Agent 架构与工具调用
LLM 单独使用时,它只能"根据输入直接生成输出",不会查资料、不会算账、不会执行代码。Agent 的核心思想是给模型加上一个能力:在生成过程中调用外部工具,把工具返回的结果再喂回上下文,继续推理。这样模型擅长的事情(理解、规划、生成)由它做,它不擅长的事情(精确计算、检索、查询接口)交给确定性代码。
ReAct:思考—行动—观察的循环
大多数 Agent 都遵循 ReAct 模式,即"推理(Reason)+ 行动(Act)"交替进行:
text
思考: 用户要查上个月的销冠,我需要先查询销售数据库。
行动: 调用 querySales(month="上月", sort="desc", limit=1)
观察: { "name": "张三", "amount": 128000 }
思考: 拿到了结果,可以回答用户了。
回答: 上个月销冠是张三,销售额 12.8 万。这个循环由三个部分组成:
| 环节 | 谁来做 | 内容 |
|---|---|---|
| 思考 | 模型 | 决定下一步做什么、调用哪个工具 |
| 行动 | 框架/代码 | 执行模型选定的工具,拿到结果 |
| 观察 | 框架/代码 | 把工具结果放进上下文,交还模型 |
循环需要一个终止条件:模型判断"已经能回答了"就输出最终答案;或者达到最大步数上限,强制停止。没有步数上限的 Agent 可能陷入无限循环,持续消耗 Token。
工具定义:函数调用
工具本质是一个有明确入参和返回值的函数,模型不需要看它的实现,只需要看它的"说明书":名字、用途、参数 schema。主流模型都支持结构化的函数调用(function calling),模型按 schema 输出参数,框架负责真正执行。
json
{
"name": "queryOrder",
"description": "按订单号查询订单状态和金额",
"parameters": {
"type": "object",
"properties": {
"orderId": { "type": "string", "description": "订单编号,如 ORD12345" }
},
"required": ["orderId"]
}
}定义工具有几个实践要点:
- description 要写给模型看:说清什么时候该用、什么时候不该用。模型是根据 description 决定是否调用的,写不清楚就会乱调或漏调。
- 参数要简单且可校验:能用枚举就用枚举,尽量让模型少出错。
- 返回结构要稳定:工具返回的 JSON 结构要固定,方便模型解读,也方便程序兜底。
- 工具要够少:给模型几十个工具,它选错的概率会上升。按场景拆分工具集,而不是一次全塞给它。
记忆与上下文管理
Agent 跑起来后,上下文会不断增长:系统指令、历史对话、每一次思考、每一次工具调用结果,全都会累积。一旦超出窗口,就会丢失关键信息或直接报错。
常见的处理策略:
| 策略 | 做法 | 适用 |
|---|---|---|
| 滑动窗口 | 只保留最近 N 轮 | 短对话、无状态任务 |
| 摘要压缩 | 把早期对话总结成摘要 | 长对话、需要保留主旨 |
| 外部记忆 | 把历史存到数据库,按需检索 | 需要长期记忆的助手 |
不要把"全量历史"无脑塞进上下文。很多任务只需要当前这一步的相关信息,过多的历史反而让模型分心,还增加成本。
何时该用、何时不该用 Agent
Agent 不是万能的,它的代价是:不可控、慢、贵、难调试。判断标准是——这个任务是否真的需要"动态决定下一步做什么"。
| 适合 Agent | 不适合 Agent |
|---|---|
| 步骤无法预先确定,要根据中间结果分支 | 步骤固定,只是串起来执行 |
| 需要理解自然语言意图再选工具 | 输入结构固定,分支明确 |
| 任务开放式,可能需要多轮探索 | 简单的数据提取或转换 |
很多看起来"需要 Agent"的场景,其实用一个固定流水线(先检索 → 再让模型总结)就够了。固定流水线可控、可测、便宜;Agent 应该作为"当流水线不够用时"的升级,而不是默认选择。
失败模式
Agent 会以几种典型方式失败,设计时要提前考虑:
- 循环调用:反复调用同一个工具却拿不到想要的结果,空转直到步数上限。需要检测重复调用并强制终止。
- 幻觉工具调用:模型编造一个不存在的工具,或给真实工具填了不合法的参数。框架必须校验工具名和参数,校验失败要反馈给模型而不是直接报错。
- 过度行动:本该先确认就执行了有副作用的操作(发邮件、删数据)。有副作用的动作必须有人工确认或独立权限层。
- 上下文污染:工具返回的结果里夹带了注入指令,影响模型后续判断。工具返回也应当作不可信数据处理。
务实的设计清单
- 是否设定了最大步数和重复调用检测?
- 每个工具的 description 是否说清了使用时机?
- 有副作用的工具是否有人工确认或权限校验?
- 上下文是否会无限增长,有没有压缩或清理策略?
- 这个任务是否真的需要 Agent,还是固定流水线就够?
Agent 的价值在于把模型的"理解与规划"能力和外部系统的"确定性执行"能力组合起来。把它用在真正需要灵活性的地方,其余地方用更简单可控的方式,整体系统才会稳。