大模型对话接口本质上是”文本进、文本出”。用户问天气,模型只能给出一段看起来像天气信息的文字,它并不能真的去看一眼气象数据。Agent 想解决的就是这个断层:让模型不仅会说,还会做——查数据库、调接口、读文件、执行脚本,把结果拿回来继续推理。
从”会聊天”到”会做事”,中间隔着的不是模型能力的跃迁,而是一套工程结构。这套结构好不好,决定了 Agent 是稳定工具还是不稳定玩具。
一、Agent 的四个基本构成
一个最小可用的 Agent 循环,通常由四块组成:
┌──────────┐
│ LLM │ ← 核心推理引擎
└────┬─────┘
│ 决定下一步
┌─────────┼─────────┐
▼ ▼ ▼
规划 工具 记忆
(拆解任务) (执行动作) (跨轮状态)
- LLM:负责理解任务、决定下一步做什么、把中间结果组织成结论。
- 规划(planning):把一个大目标拆成可执行的步骤序列。可以是模型隐式规划(在推理里自然展开),也可以显式要求它先输出计划再执行。
- 工具(tools):模型能调用的外部能力,比如搜索、计算、API 调用、代码执行。工具是 Agent 与真实世界交互的唯一通道。
- 记忆(memory):短期是对话历史,长期可以是向量化的笔记、任务状态、用户偏好。没有记忆的 Agent 每次对话都从零开始。
这四块里,真正决定 Agent 可靠性的是工具层和约束层,而不是模型有多聪明。模型再强,工具描述写得含糊、权限放得过宽,系统照样会出问题。
二、ReAct 式循环:思考、行动、观察
目前最广泛使用的 Agent 执行模式是 ReAct(Reason + Act)循环,每一轮包含三个动作:
Thought: 我需要先查一下上周的订单量,才能回答这个问题。
Action: query_orders(start="2026-10-13", end="2026-10-19")
Observation: {"total": 1284, "amount": 392011}
Thought: 数据拿到了。现在回答用户的问题,需要把订单量和金额都列出来。
Answer: 上周订单总量 1284 笔,金额约 39.2 万。
这个循环的好处是可观测:每一步”想做什么、做了什么、拿到什么”都留痕,出问题时能定位是哪一步断掉。对比”一口气把答案吐出来”的单步模式,ReAct 的调试友好度高出一大截。
工程实现上有两个细节:
- 循环要有边界。设定最大步数(比如 5~10 步),超过就强制让模型输出当前已知的结论或失败原因。没有边界的循环是 Agent 失控的常见入口。
- Observation 要控制长度。工具返回的原始数据可能很大(比如整张表),要截断或摘要后再塞回上下文,否则几个来回就把窗口吃满了。
三、工具调用的协议要点
Function calling(工具调用)已经形成了大同小异的接口约定:模型在回答里输出一个”要调用哪个工具、参数是什么”的结构化请求,宿主程序执行后把结果以工具消息的形式返回,模型基于结果继续推理。
一套好用的工具定义,关键在三处:
{
"name": "query_orders",
"description": "查询订单列表。时间范围必填,最长跨度不超过 90 天。返回订单数与总金额。",
"parameters": {
"type": "object",
"properties": {
"start": { "type": "string", "description": "起始日期,格式 YYYY-MM-DD" },
"end": { "type": "string", "description": "结束日期,格式 YYYY-MM-DD" }
},
"required": ["start", "end"]
}
}
- description 写给模型看,不是写给程序员看。要写清”什么时候该用、什么时候不该用、边界是什么”,而不是复述函数名。
- 参数尽量少而明确。参数越多,模型填错的概率越高。能用默认值的参数就别让它填。
- 返回值要可读。工具返回给模型的也是文本,压缩成模型容易消化的结构(字段少、有明确语义、错误信息可读),比返回原始 JSON dump 有效得多。
工具返回的错误也要认真设计。”参数错误”这种信息对模型没有帮助,”end 日期不能早于 start 日期,请检查”才能让模型自己纠正。错误信息是 Agent 自我修复能力的重要输入。
四、护栏与权限控制
Agent 会”动手”,就意味着它可能”做错事”。护栏不是可选项,是把 Agent 放进生产环境的前提。常见手段按严格程度递增:
- 白名单。只允许调用明确列出的工具,其他一律不暴露。比”把所有 API 都注册上去,靠提示词约束”安全一个数量级。
- 参数约束。限制可操作的资源范围(只读某个目录、只操作某个项目的数据),在工具实现层校验,而不是依赖模型自觉。
- 确认机制。对高危操作(删除、发送、支付、对外发布)设置人工确认点。Agent 提议、人来批准,这个模式在多数业务里是合理的默认值。
- 审计日志。每次工具调用记录:时间、工具名、参数、结果、触发该调用的对话上下文摘要。出问题时能回溯,也方便分析 Agent 的行为模式。
- 速率与预算限制。限制单次任务的工具调用总次数、总 Token 消耗、总执行时间。失控的循环会在烧完预算之前先烧掉你的耐心。
一个实用的分类法:读操作可以放开一些,写操作收紧,不可逆操作(删除、对外发送)必须人工确认。按这个梯度设计权限,比一刀切全放开或全锁死都更实用。
五、常见失败模式
Agent 的失败不是”随机出错”,模式相当集中:
| 失败模式 | 表现 | 应对 |
|---|---|---|
| 循环打转 | 反复调用同一个工具、反复得到同样的错误 | 最大步数限制 + 重复调用检测 |
| 幻觉工具 | 调用不存在的工具名、编造参数 | 白名单 + 参数 Schema 校验 |
| 权限过大 | 一次操作影响了不该影响的数据 | 参数约束 + 确认机制 |
| 上下文溢出 | 工具结果太大,早期任务目标被挤出窗口 | 结果截断/摘要 + 目标重申 |
| 过度自信 | 中间结果错了但没检查,一路推到结论 | 关键步骤插入校验点 |
| 提示注入 | 工具返回内容里藏有指令,带偏 Agent 行为 | 工具返回内容与指令分离、敏感操作确认 |
其中提示注入是 Agent 时代特有的风险:工具返回的数据里如果含有”请调用删除接口”这类文本,模型可能把它当成指令执行。对策是把”数据”和”指令”在结构上分开(比如工具结果用明确的分隔标签包裹、对工具返回内容做净化),并且永远不要让工具返回内容直接触发高危操作。
六、渐进落地:从确定性脚本到半自主
一口气做”全自主 Agent”是多数项目翻车的原因。更稳的路径是按自主度分级:
- 级别 0:纯脚本。流程完全确定,LLM 只负责某个环节(比如从文本里抽取字段)。这一步价值已经很实在。
- 级别 1:受限工具调用。模型可以在白名单里选工具,但每一步的执行流程由代码编排(orchestration),模型只做单步决策。
- 级别 2:半自主。模型自己决定调用顺序,但关键节点有人工确认、有步数上限、有预算上限。
- 级别 3:全自主。模型自主规划并执行完整任务。这一步的收益和风险都最大,只在失败代价可控的场景里尝试。
每一级升级的前提是:上一级的失败模式已经被监控和处理。没有监控的升级,只是把问题藏得更深。
从对话到自主调用工具,距离不在模型智商,而在于工程上愿不愿意把工具定义、权限边界、失败处理这些”枯燥的部分”做扎实。Agent 是一个系统工程问题,模型只是其中的一个组件——想清楚这一点,落地就会稳很多。
Comments (4)
之前一直半懂不懂,现在清楚多了。
想问下这个方案对小团队来说会不会太重。
文中举的例子很贴近实际工作。
补充一点:文档里这块其实有说明,容易被忽略。
Please Sign in to join the discussion.