AI Agent 开发教程:用工具调用与记忆模块构建自主任务执行系统
从一次工具调用开始理解 Agent 的本质
很多人第一次接触 AI Agent 开发教程,脑子里想的是"让模型自己干活"。这个直觉没错,但跳过基础直接上多 Agent 编排,几乎必然在状态管理上翻车。
最简单的起点是一个单步工具调用(Function Calling / Tool Use)。以 Claude Opus 4.8 或 GPT-5.4 为例,你在系统提示里声明一组工具 schema,模型在回复中返回结构化的工具调用请求,你的代码执行这个调用并把结果塞回对话,模型再生成最终答案。整个过程是一个同步的 request → execute → respond 循环,延迟通常在 1~3 秒之间。
这一步看起来平淡,但它确立了 agent 的核心机制:模型负责推理与决策,宿主程序负责执行与环境交互。模型永远不"真正执行"任何东西,它只是在表达意图。
一个最小可运行的工具调用结构长这样(以 OpenAI 兼容接口为例):
tools = [
{
"type": "function",
"function": {
"name": "search_web",
"description": "Search the web for up-to-date information",
"parameters": {
"type": "object",
"properties": {
"query": {"type": "string"}
},
"required": ["query"]
}
}
}
]
response = client.chat.completions.create(
model="gpt-5.4",
messages=messages,
tools=tools,
tool_choice="auto"
)
tool_choice="auto" 让模型自己判断是否需要调用工具。设成 "required" 则强制调用,适合需要保证结构化输出的场景。
多步规划:ReAct 循环与 token 预算控制
单步工具调用解决不了复杂任务。真实的 agent 任务往往需要 4~12 步决策才能完成,比如"帮我调研竞品定价并生成报告"这类需要搜索、提取、汇总三个阶段的工作。
主流实现是 ReAct(Reason + Act) 循环:模型先输出 Thought(推理),再输出 Action(工具调用),执行后得到 Observation,继续推理。这个循环持续到模型判断任务完成或触发终止条件。
用代码表达这个循环,核心是一个 while 驱动的消息追加机制:
MAX_STEPS = 15
step = 0
while step < MAX_STEPS:
response = client.chat.completions.create(
model="claude-opus-4-8", # 或 gpt-5.4
messages=messages,
tools=tools,
max_tokens=4096
)
msg = response.choices[0].message
# 模型决定停止
if msg.tool_calls is None:
break
# 执行工具并追加结果
for tool_call in msg.tool_calls:
result = dispatch_tool(tool_call)
messages.append({
"role": "tool",
"tool_call_id": tool_call.id,
"content": result
})
step += 1
MAX_STEPS 设 15 是实践中比较稳健的上限。太低会导致任务中途截断,太高则在模型发生"幻觉循环"时会烧掉大量 token——Claude Opus 4.8 的输出 token 单价约为 Haiku 4.5 的 15 倍,循环失控的成本不可忽视。
另一个容易忽略的点是 context window 预算。GPT-5.4 支持 128K context,但当 messages 列表增长到 60K+ tokens 时,模型的注意力开始稀释,早期的工具结果会被"遗忘"。常见的解法是在每轮循环后对历史消息做摘要压缩,保留最近 N 条原始消息 + 一条汇总。
记忆模块:短期上下文、长期存储与向量检索
记忆是让 agent 真正"自主"的关键。没有记忆的 agent 每次任务都从零开始,无法跨会话积累知识,也无法在长任务中维护中间状态。
实践中通常区分三层记忆:
| 层级 | 存储位置 | 典型容量 | 适用场景 |
|---|---|---|---|
| 工作记忆(Working Memory) | messages 列表(in-context) | 8K~32K tokens | 当前任务的推理状态 |
| 情节记忆(Episodic Memory) | 向量数据库(如 Chroma、Qdrant) | 百万级 chunk | 历史任务结果、用户偏好 |
| 语义记忆(Semantic Memory) | 结构化 DB 或 KV 存储 | 无上限 | 领域知识、规则、配置 |
工作记忆直接在 context window 里,读写成本最低。情节记忆通过 embedding 检索,典型流程是:把历史工具执行结果切成 512 token 的 chunk,用 text-embedding-3 或 gemini-embedding-exp 生成向量存入 Qdrant,每轮循环开始前做 top-k 检索(k=5 是常用起点),把相关结果注入 system prompt。
语义记忆更接近传统数据库,用 SQLite 或 Redis 存结构化状态,比如任务进度、用户确认过的偏好、上次执行到哪一步。这部分不走向量检索,直接 key-value 读取。
状态管理与异常恢复:让 Agent 在生产环境跑得住
原型阶段的 agent 往往脆弱:工具调用超时、模型返回格式不符预期、外部 API 限流——任何一个都能让整个任务链断掉。生产级 agent 必须显式处理这三类问题。
工具执行层 要有超时 + 重试 + fallback:
import tenacity
@tenacity.retry(
stop=tenacity.stop_after_attempt(3),
wait=tenacity.wait_exponential(multiplier=1, min=2, max=10),
retry=tenacity.retry_if_exception_type(TimeoutError)
)
def call_tool_with_retry(tool_name: str, args: dict):
return tool_registry[tool_name](**args)
3 次重试、指数退避、最长等待 10 秒——这个配置覆盖了绝大多数偶发性网络抖动。
模型输出解析层 要处理格式异常。即便是 GPT-5.5 或 Claude Opus 4.8,在 context 很长时偶尔也会返回非标准 JSON。推荐在工具调用 schema 之外单独加一个 parse_response 步骤,用 json.loads + try/except 包裹,失败时把原始输出当成文本工具结果传回,让模型自己修正。
任务级状态持久化 是最容易被忽视的:把每一步的 {step, tool_name, args, result, status} 序列化存到数据库,任务中断后可以从断点续跑,而不是从头开始。这在需要 30+ 步才能完成的长任务里能节省 60%~80% 的重跑成本。
Codex、Claude Code、Gemini CLI 这类编码 CLI 工具本质上也是按这套架构工作的:它们维护文件系统状态作为外部记忆,用工具调用执行 shell 命令和文件读写,并在每次执行后把结果注回 context 继续推理。理解了上面这套基础,读它们的源码或自己扩展工具集会顺手很多。
如果你在搭建这套 agent 系统时需要同时调用 GPT-5.4、Claude Opus 4.8、DeepSeek V3 等多个模型做能力对比或成本优化,我一直在用 XycAi 词元平台——一个 OpenAI 兼容接口接入 200+ 全球模型,Claude Code、Codex、Gemini CLI 都可以一键切换接入,不用改代码。主流旗舰模型低至官方价 1.4 折,节点 CN2 直连延迟低,企业合规也没问题,搭原型和跑生产都够用。
一个 API 接入 200+ 全球 AI 模型
GPT · Claude · Gemini 官方模型低至 1.4 折起,持大模型算法备案号,CN2 直连低至 5ms,可开全球合规发票。
立即体验 XycAi →