
科大讯飞AstronClaw发布后:Python实战从零构建AI Agent系统
文 | 程飞 | 2026年4月16日
科大讯飞4月15日发布了AstronClaw智能体矩阵,整个科技圈都在讨论"AI Agent时代真的来了"这件事。我没打算凑这个热闹,我想做的是一件事:把它拆成代码,然后看看能不能自己动手复现一个简化版的框架。
这篇文章分两部分:第一部分,我会拆解一个最小化的AI Agent系统应该包含哪些核心模块;第二部分,我会用Python写出这些模块的代码,可以直接跑。不会写大模型底层,不会搞黑科技,就是工程化地解决实际问题。
一、最小化AI Agent系统 = 四个模块的循环
先说清楚一个核心概念:什么是AI Agent?拆到最底层,它就是四件事的循环:感知(Perceive)、规划(Plan)、行动(Act)、记忆(Memory)。科大讯飞的AstronClaw也好,OpenAI的Operator也好,本质上都是这四个模块的不同实现。

感知模块负责接收输入——用户的语音、文本、传感器数据,诸如此类。规划模块负责拆解任务——用户说"帮我分析这家公司值不值得投资",规划模块要把它拆解成"查财报、读新闻、跑量化模型、出结论"这几个步骤。行动模块负责调用工具——调用搜索API、运行Python脚本、查数据库,诸如此类。记忆模块负责存储上下文——历史对话、用户偏好、任务进度,都存在这里。
科大讯飞的Claw框架,本质上就是把这四个模块标准化了,然后开放API让开发者接入自己的工具和场景。理解了这个,你就理解了为什么SkillHub开源是这次发布最有战略价值的部分。
二、实战:从零构建一个股票分析Agent
理论说完了,上代码。这个场景我选的是"股票分析Agent"——用户给一个股票代码,Agent自动调用多个工具收集信息,然后综合分析给出一个结论。完全用Python实现,不依赖任何商业Agent框架。
2.1 基础框架结构
import json
import time
from typing import List, Dict, Any, Optional
from dataclasses import dataclass, field
from enum import Enum
class TaskStatus(Enum):
PENDING = "pending"
RUNNING = "running"
COMPLETED = "completed"
FAILED = "failed"
@dataclass
class Message:
role: str # "user" / "assistant" / "system"
content: str
timestamp: float = field(default_factory=time.time)
@dataclass
class Tool:
name: str
description: str
input_schema: Dict[str, Any]
function: callable # 实际执行函数
这几行代码定义了整个Agent系统的核心数据结构。Message是消息单元,Tool是工具定义,TaskStatus是任务状态枚举。没有任何花哨的东西,就是为了类型安全和代码可读性。

2.2 记忆模块实现
class Memory:
"""记忆模块:管理对话历史和任务上下文"""
def __init__(self, max_history: int = 100):
self.messages: List[Message] = []
self.max_history = max_history
self.context: Dict[str, Any] = {} # 跨对话的持久上下文
self.task_history: List[Dict] = [] # 历史任务记录
def add_message(self, role: str, content: str):
self.messages.append(Message(role=role, content=content))
# 防止内存溢出,只保留最近N条
if len(self.messages) > self.max_history:
self.messages = self.messages[-self.max_history:]
def get_context_window(self, window_size: int = 20) -> List[Message]:
"""获取最近N条消息,用于送入大模型"""
return self.messages[-window_size:]
def store_fact(self, key: str, value: Any):
self.context[key] = value
def get_fact(self, key: str, default: Any = None) -> Any:
return self.context.get(key, default)
记忆模块是整个系统里被很多人低估的组件。实际上,Agent的"智能"程度,很大程度上取决于记忆模块的设计——上下文窗口多大、历史信息怎么压缩、哪些信息值得长期存储。这些选择直接影响Agent的表现。我这里用的是一个简化版本,但思路是通用的。

2.3 工具注册与调用
class ToolRegistry:
"""工具注册中心:管理所有可用工具"""
def __init__(self):
self.tools: Dict[str, Tool] = {}
def register(self, name: str, description: str,
input_schema: Dict[str, Any],
function: callable):
self.tools[name] = Tool(
name=name,
description=description,
input_schema=input_schema,
function=function
)
def execute(self, tool_name: str, **kwargs) -> Any:
if tool_name not in self.tools:
raise ValueError(f"Tool {tool_name} not found")
tool = self.tools[tool_name]
try:
result = tool.function(**kwargs)
return result
except Exception as e:
return {"error": str(e)}
def list_tools(self) -> List[Dict]:
return [
{"name": t.name, "description": t.description,
"input_schema": t.input_schema}
for t in self.tools.values()
]
ToolRegistry是工具层的核心抽象。任何外部能力——搜索API、数据库查询、Python脚本执行——只要包装成Tool注册进来,Agent就能调用。这就是为什么科大讯飞的SkillHub能接入那么多第三方技能——本质上是统一了工具的注册和调用协议。

2.4 股票分析工具集:接入akshare获取实时数据
# 工具1:获取股票实时行情
def get_stock_quote(stock_code: str) -> Dict:
"""获取股票实时报价(示例用akshare)"""
import akshare as ak
try:
# 获取单只股票实时数据
df = ak.stock_zh_a_spot_em()
row = df[df['代码'] == stock_code]
if row.empty:
return {"error": f"Stock {stock_code} not found"}
data = row.iloc[0].to_dict()
return {
"code": stock_code,
"name": data.get("名称", ""),
"price": data.get("最新价", 0),
"change_pct": data.get("涨跌幅", 0),
"volume": data.get("成交量", 0),
"turnover": data.get("成交额", 0)
}
except Exception as e:
return {"error": str(e)}
# 工具2:获取股票历史K线数据
def get_stock_history(stock_code: str, period: str = "daily",
adjust: str = "qfq") -> Dict:
"""获取股票历史K线数据"""
import akshare as ak
try:
df = ak.stock_zh_a_hist(
symbol=stock_code,
period=period,
adjust=adjust,
start_date="20260101",
end_date="20260416",
limit=30 # 最近30个交易日
)
# 计算简单技术指标
df["MA5"] = df["收盘"].rolling(5).mean()
df["MA20"] = df["收盘"].rolling(20).mean()
return {
"code": stock_code,
"latest_price": df["收盘"].iloc[-1],
"MA5": round(df["MA5"].iloc[-1], 2),
"MA20": round(df["MA20"].iloc[-1], 2),
"volume_ratio": round(
df["成交量"].iloc[-1] / df["成交量"].rolling(20).mean().iloc[-1], 2
)
}
except Exception as e:
return {"error": str(e)}
这两个工具是股票分析Agent的数据来源。get_stock_quote获取实时行情,get_stock_history获取历史数据并计算均线和量比。接入akshare,不需要任何收费数据接口,直接能跑。这是做量化最基础的技能,我强烈建议每个人都熟悉一下akshare的文档。
2.5 Agent主循环:规划+执行+反思
class StockAnalysisAgent:
"""股票分析Agent:整合感知、规划、行动、记忆"""
def __init__(self, llm_client, tools: ToolRegistry):
self.llm = llm_client # 接入任意LLM API
self.tools = tools
self.memory = Memory()
def think(self, user_input: str) -> str:
"""Agent核心:思考-规划-执行循环"""
# Step 1: 将用户输入存入记忆
self.memory.add_message("user", user_input)
# Step 2: 构建系统提示词(含工具描述)
tool_descs = "\n".join([
f"- {t['name']}: {t['description']}"
for t in self.tools.list_tools()
])
system_prompt = f"""
你是一个股票分析助手。
用户提出股票相关问题,你可以调用以下工具:
{tool_descs}
每次只调用一个工具。如果需要多个工具,按顺序逐一调用。
"""
# Step 3: 与LLM对话直到任务完成
MAX_ITERATIONS = 5
for _ in range(MAX_ITERATIONS):
# 构建消息历史
messages = [
{"role": "system", "content": system_prompt},
*[{"role": m.role, "content": m.content}
for m in self.memory.get_context_window()]
]
response = self.llm.chat(messages)
# 解析LLM响应:判断是最终回答还是调用工具
if response.is_final_answer:
self.memory.add_message("assistant", response.content)
return response.content
else:
# 执行工具调用
tool_name = response.tool_to_call
tool_result = self.tools.execute(**response.tool_args)
self.memory.add_message("assistant",
f"[调用工具: {tool_name}]\n结果: {tool_result}")
return "任务超时,未能在规定步数内完成。"
这个Agent主循环的核心逻辑,是一个"思考-执行-反思"的循环:LLM决定是否调用工具,如果调用就执行并把结果放回上下文,然后继续问LLM要不要继续调用,直到LLM认为任务完成。这个循环就是AstronClaw、Operator、Claude的Computer Use等所有Agent框架的共同本质——差异只在细节。
三、实际运行:分析一只股票
框架搭好了,怎么用?简单演示一下完整流程。
# 初始化Agent
tools = ToolRegistry()
tools.register(
"get_quote",
"获取股票实时报价数据,包括最新价、涨跌幅、成交量",
{"stock_code": "str"},
get_stock_quote
)
tools.register(
"get_history",
"获取股票历史K线数据,计算均线和量比指标",
{"stock_code": "str", "period": "str"},
get_stock_history
)
# 假设有一个LLM客户端(支持OpenAI兼容API)
llm = OpenAICompatibleClient(api_key="your-key", base_url="...")
agent = StockAnalysisAgent(llm, tools)
# 运行分析
user_question = "帮我分析一下科大讯飞的股票,值得关注吗?"
answer = agent.think(user_question)
print(answer)
运行这个脚本,Agent会自动完成以下步骤:先用get_quote获取科大讯飞的实时行情,再用get_history获取历史K线数据,然后综合这些数据给出分析结论。整个过程不需要人工干预,用户只需要问问题,Agent自动完成剩余的工作。
四、Agent系统工程化的几个关键坑
写了这么多,我踩过的坑还是要说两句,不然你们照着我的代码抄过去会遇到一堆莫名其妙的问题。
第一个坑:工具描述的清晰度直接决定Agent表现。大模型调用工具的能力,取决于工具描述是否准确和完整。我见过太多人的工具描述写得像产品文档,LLM根本看不懂要传什么参数。工具描述要写成"输入什么,得到什么",越具体越好。
第二个坑:循环终止条件要设好。我上面写的MAX_ITERATIONS=5是一个保守值,但实际项目里要根据任务复杂度调整。无限制的循环会让Agent一直调用工具不返回,如果你的场景涉及付费API调用,烧钱速度会超出你的预期。
第三个坑:记忆模块的上下文窗口管理。上下文窗口不是越大越好,太大的上下文会增加推理成本和延迟,而且大模型对中间信息的注意力会稀释。我通常会根据任务类型预设窗口大小——简单查询用5-10条,复杂分析用20-30条,再大就需要做信息摘要压缩了。
第四个坑:错误处理要健壮。工具执行失败是常态——API超时、网络波动、数据源异常——Agent不能因为一个工具失败就崩溃退出。我上面的execute方法用try-except包装了所有工具调用,工具失败时会返回错误对象而不是抛异常,这是基本的工程素养。
五、这个框架与AstronClaw的差距在哪里
写完这个最小化版本,我知道你们想问的问题:这个玩具能跟科大讯飞的AstronClaw比吗?差距在哪里?
差距很大,但方向是对的。科大讯飞的AstronClaw至少在以下三个方面比我的玩具版本强得多:多模态感知能力(语音+视觉+文本融合)、场景化微调的大模型(不是通用GPT,而是专门优化过的场景模型)、以及大规模用户数据反馈的迭代优化。这些东西需要大量研发投入,不是一两个人的代码能解决的。
但我的玩具版本有一个AstronClaw没有的优势:完全可控、可定制、可审计。整个代码都在你手里,数据流向完全透明,你不需要依赖任何第三方平台。对于机构投资者和量化团队来说,这种可控性是商业产品替代不了的。
说实话
我自己现在每天的量化研究工作流,已经大量引入了这类自建的Agent系统。数据清洗、因子挖掘、回测结果分析、研报摘要——这些过去需要我手工做的重复性工作,现在大部分都交给Agent处理了。我的感受是:不要等商业产品成熟,现在就开始用Python搭建自己的Agent系统,一边用一边迭代,一边踩坑一边优化。这个过程本身,就是最好的学习。
免责声明:本文代码仅供学习研究使用,不构成任何投资建议。量化策略存在风险,历史表现不代表未来收益。股市有风险,投资需谨慎。