Agent 浪潮观察:从单次问答到自主执行任务的范式转变
上周有个做电商客服系统的朋友找我吐槽:他把一个”自动处理退款申请”的 Agent 接上线,跑了三天,退款金额对不上账。查日志才发现,Agent 在第二步查订单失败后,自己”脑补”了一个订单号继续走后面的流程——模型没有报错,流程也顺利跑完了,只是结果是错的。这类问题不会出现在单轮问答里,但只要你的系统开始”自主执行多步任务”,它就一定会出现。这就是 Agent 和普通对话应用的分水岭:多了自主性,也多了一整套新的失败模式要兜底。
大模型从”回答问题”到”完成任务”的跨越,是当前 AI 应用演进最核心的主题之一。Agent(智能体)不再只是被动响应 Prompt,而是主动调用工具、分解子任务、迭代执行,直到完成用户的目标。这一范式转变既带来了巨大的应用可能,也引入了新的工程复杂度。
一、Agent 的核心架构要素
一个典型的 AI Agent 由以下要素构成:
| 要素 | 说明 |
|---|---|
| 语言模型(大脑) | 负责规划、推理、决策下一步行动 |
| 工具集(手脚) | 可调用的函数:搜索、代码执行、数据库查询、API 调用等 |
| 记忆系统 | 短期记忆(当前上下文)+ 长期记忆(向量数据库/外部存储) |
| 规划机制 | ReAct / Plan-and-Execute / 反思循环等策略 |
| 执行环境 | 能运行代码、浏览器操作、文件读写的沙箱 |
这些要素的组合方式决定了 Agent 的能力边界和可靠性。这里拆开讲讲每一项在真实项目里踩过的坑,光看表格是感受不到的。
语言模型这一层,你要先想清楚”每一步该用多贵的模型”。 很多团队一上来就用最贵的旗舰模型跑全部步骤,账单立刻起飞。实际上 Agent 里的步骤是有轻重之分的:任务分解、最终总结这种需要强推理的环节,放旗舰模型;中间的工具参数拼接、格式转换这类机械步骤,换成一个便宜的小模型甚至规则代码就能做,没必要每一步都烧大模型的 Token。
工具集不是越多越好,这条表格里写了但值得展开。 我见过一个团队给 Agent 挂了 30 多个工具,结果模型经常”选错工具”——比如该查订单表却调用了查库存表,因为两个工具的描述里都有”查询”两个字,模型分不清边界。工具描述要写清楚”什么时候该用、什么时候不该用”,最好在描述里加一句反例,比如”仅用于查询已支付订单的物流状态,不要用于查询库存或价格”。
记忆系统这块最容易被低估的是”检索质量”而不是”存不存”。 很多人一上来就接向量数据库做长期记忆,结果发现 Agent 该记住的没记住,不该翻出来的旧对话反而被塞进上下文干扰了判断。根源往往不是向量库选错了(Pinecone、Milvus、pgvector 效果差异没有你想的那么大),而是 embedding 的切片粒度和相似度阈值没调好。如果你的场景对话轮次不多(几十轮以内),先老老实实把完整历史塞进上下文窗口,比接一套检索系统更省心也更准;等上下文明显放不下了,再考虑做摘要压缩或检索式记忆。
规划机制里 ReAct 是目前最实用的默认选项,不是因为它最先进,而是因为它最好调试。 ReAct 的核心循环是”思考(Thought)→ 行动(Action)→ 观察(Observation)“,每一步模型都要先把”我为什么要这么做”写出来再执行。这行”思考”文本看起来啰嗦,但排查问题时全靠它——出了幻觉工具调用,你翻思考记录基本能一眼看出模型是在哪一步”想岔了”。Plan-and-Execute 模式(先整体规划再顺序执行)在任务步骤固定、不需要中途调整时效率更高,但一旦中途情况有变化,重新规划的成本比 ReAct 边想边做要高不少。拿不准选哪个的时候,先上 ReAct,把日志跑顺了,再考虑要不要换。
二、Agent 能做什么:当前能力地图
已经可靠商用的场景:
- 代码辅助 Agent:在限定代码库范围内自动修 Bug、写单测、生成文档
- 数据分析 Agent:连接数据库,自动生成 SQL、执行查询、输出报告
- 客服 & 知识问答 Agent:结合 RAG 和工具调用,处理有明确边界的问答任务
- 文档处理流水线:读取→提取→结构化→写回,适合批量离线任务
仍在探索、可靠性有限的场景:
- 需要长时间(数小时)自主执行的复杂任务
- 跨多个外部系统的高风险操作(如自动付款、合同签署)
- 需要创造性判断而非规则执行的开放性任务
判断一个场景现在能不能上 Agent,我一般用三个问题过一遍,比空谈”能不能落地”实在:
- 单步操作是否可验证? 比如”生成 SQL 并执行”,执行结果(返回的行数、报错信息)能立刻验证对错;但”写一份市场分析报告”就很难在中间步骤验证对错,只能等最后交付时人工判断。可验证的任务,Agent 的自主执行才有意义——因为出错了系统自己能发现并重试。
- 单次出错的代价有多大? 客服 Agent 答错一句话,用户顶多再问一遍;自动付款 Agent 走错一步,钱就真的转出去了。代价越大,越需要在关键节点加人工确认,而不是追求全自动。
- 任务边界能不能提前枚举? “在这 12 张表里查数据” 边界清楚;“帮我处理这个客户的所有诉求” 边界模糊,模型很容易在模糊边界里发挥过度。边界越清楚,Agent 的可靠性上限越高。
三个问题里只要有一个答案是”否”,我都建议先做成”Agent 生成建议 + 人工点一下确认”的半自动流程,等积累了足够多的真实运行日志、摸清了失败模式的分布,再逐步放开人工确认的比例。这比一上来就搭全自动系统更稳,出问题的返工成本也小得多。
三、Function Calling 是 Agent 的关键基础设施
现代主流模型都支持 Function Calling(工具调用)——模型输出结构化的工具调用指令,由宿主程序执行后将结果返回给模型,形成闭环。这是 Agent 能”做事”的基础。
关键工程点:
- 工具描述要精准:模型根据工具描述决定何时调用、怎么调用,描述模糊会导致错误调用
- 工具数量不宜过多:工具太多会稀释模型的注意力,建议每个 Agent 专注 5-10 个核心工具
- 错误处理必须完整:工具执行失败时需要有明确的重试或降级策略,否则 Agent 会陷入死循环
详细实现参考Function Calling 完整接入指南,这里补几个接入指南里没细说、但真实项目里必然会遇到的坑。
第一个坑:模型吐出来的参数不一定合法,你的代码要当它随时会出错来写。 比如工具定义要求 amount 是数字,模型偶尔会吐出 "amount": "一百" 这种字符串,或者干脆漏了必填字段。下面是一个最基础的执行封装,把参数校验和异常兜底放在工具执行之前,而不是让异常直接冒穿到最外层:
import json
from jsonschema import validate, ValidationError
def safe_execute_tool(tool_name, arguments_json, tool_registry):
tool = tool_registry.get(tool_name)
if tool is None:
return {"error": f"工具 {tool_name} 不存在,请检查工具名是否拼写正确"}
try:
args = json.loads(arguments_json)
validate(instance=args, schema=tool.schema)
except (json.JSONDecodeError, ValidationError) as e:
# 把校验失败的具体原因回传给模型,而不是直接报错终止
return {"error": f"参数格式不合法:{str(e)},请重新生成符合 schema 的参数"}
try:
return tool.run(**args)
except Exception as e:
return {"error": f"工具执行失败:{str(e)}"}
这里的关键设计是:校验失败和执行失败都不要让程序崩溃,而是把错误信息原样打包成一条”工具结果”回传给模型。模型看到”参数格式不合法:‘amount’ is not of type ‘number‘“这种具体报错,下一轮通常能自己纠正过来重新生成参数——这比你自己写规则去”猜”模型哪里错了要省事得多,也是 Agent 系统里自愈能力的核心来源。
第二个坑:接口层面的 429(限流)和超时,光靠”重试一次”不够用。 高并发场景下你会在日志里频繁看到类似 RateLimitError: Rate limit reached for requests 或者请求卡在 30 秒后超时的情况,直接重试大概率还是撞限流。稳妥的做法是指数退避加抖动:
import time
import random
def call_with_backoff(fn, max_retries=5, base_delay=1):
for attempt in range(max_retries):
try:
return fn()
except RateLimitError:
if attempt == max_retries - 1:
raise
# 指数增长的等待时间 + 随机抖动,避免多个请求同时重试再次撞车
delay = base_delay * (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)
注意退避策略只应该用来兜底”限流、网络抖动、超时”这类瞬时性错误,像”参数不合法""工具不存在”这种确定性错误重试多少次结果都一样,应该直接把错误信息返回给模型走纠正逻辑,不要浪费重试次数和 Token。这两类错误处理方式在代码里最好分开写,混在一起是很多线上 Agent 无谓消耗 Token 的常见原因。
四、多 Agent 协作:分工与通信
单个 Agent 的能力有限,复杂任务往往需要多个 Agent 协作——一个 Orchestrator Agent 负责任务分解和调度,多个 Worker Agent 各司其职。
多 Agent 系统的主要挑战:
- 上下文同步:各 Agent 之间如何共享状态,避免信息孤岛
- 错误传播:某一 Agent 的错误如何被检测并避免影响全局
- 成本控制:多 Agent 并行调用模型,Token 消耗呈倍数增长
上下文同步这件事,我见过两种做法,取舍完全不同。 一种是”共享黑板”模式:所有 Agent 读写同一份状态(可以简单到一个 Redis Hash 或者一张数据库表),Orchestrator 每次调度前先读一遍最新状态。好处是实现简单、调试直观,缺点是状态一大,每次同步的开销和一致性维护成本会上去。另一种是”消息传递”模式:Agent 之间不共享状态,只通过 Orchestrator 转发的消息交换必要信息,类似微服务里的事件驱动。好处是各 Agent 之间解耦彻底,缺点是信息传递链路变长,调试时得追好几跳消息才能定位问题出在哪。团队规模小、Agent 数量在 5 个以内时,我倾向直接用共享黑板,能少踩很多分布式一致性的坑;Agent 数量上来了或者需要独立扩缩容时,再考虑消息传递。
成本这块建议你上线前就拿真实数据估算一遍,而不是等账单出来才知道贵。 简单估算公式:单次任务总 Token 消耗 ≈ Orchestrator 的规划 Token + 每个 Worker Agent 的(输入上下文 + 输出)Token × 参与的 Worker 数量。举个例子帮你建立量级感:假设 Orchestrator 规划一次消耗 2000 Token,3 个 Worker Agent 每个平均消耗 5000 Token(含上下文),那么单次多 Agent 任务大约消耗 17000 Token,是单 Agent 直接处理同类任务的 3-5 倍并不奇怪。这笔账在设计阶段就该算清楚:如果单任务预算卡得很紧,优先考虑能不能把部分 Worker 换成更便宜的模型,或者干脆用规则代码替代,而不是每个 Worker 都用同一档模型顶格配置。
| 场景 | 单 Agent 直接处理 | 多 Agent 协作 |
|---|---|---|
| 任务边界单一、步骤少 | 优先选,延迟低、成本低、易调试 | 没必要,纯增加协调开销 |
| 需要多领域专业知识(如法务+财务+技术) | 单 Agent 容易在专业细节上出错 | 优先选,每个 Worker 聚焦单一领域更准 |
| 需要并行处理多个独立子任务 | 只能串行,总耗时是各步骤之和 | 并行执行,总耗时接近最慢的那个子任务 |
| 对总成本极度敏感 | 优先选 | 需要精算 Token 消耗,谨慎评估 |
五、可靠性是 Agent 落地的最大瓶颈
当前 Agent 的失败模式主要有三类:
- 幻觉工具调用:调用了不存在的工具参数,或伪造了执行结果
- 任务漂移:多步执行后偏离原始目标,走向无关子任务
- 循环卡死:在错误中反复重试,消耗大量 Token 和时间
应对策略:设置最大步数硬限制、关键操作要人工确认、全链路日志可观测。这三条策略具体怎么落地,展开说说。
最大步数硬限制不是拍脑袋定一个数字,而是要给死循环和正常长任务留出区分空间。 我一开始的做法是简单粗暴地”超过 10 步就强制终止”,结果发现有些正常任务(比如多表联合查询加数据校验)本来就需要 12-15 步,被误杀了。后来改成两层限制:一层是硬上限(比如 30 步,超过就无条件终止,防止彻底失控),另一层是”相似度检测”——如果连续 3 步的工具调用参数几乎一样(比如反复查询同一个不存在的订单号),提前判定为卡死并终止,不用等跑满硬上限再退出:
def should_terminate(history, max_steps=30, similarity_window=3):
if len(history) >= max_steps:
return True, "达到最大步数硬限制"
if len(history) >= similarity_window:
recent = history[-similarity_window:]
# 简化示例:比较最近几步的工具名+参数是否完全相同
calls = [(h["tool"], h["args"]) for h in recent]
if len(set(calls)) == 1:
return True, "检测到重复调用,判定为循环卡死"
return False, None
关键操作的人工确认,边界怎么划最省心? 我的经验是按”能不能撤销”来划分,而不是按操作类型划分:能撤销的操作(生成草稿、发起查询、写临时表)放开自动执行;不能撤销或代价高的操作(真实付款、删除数据、对外发送邮件、签署合同)一律加人工确认这一步,哪怕它在业务上看起来很简单。这条线划清楚之后,团队内部对”哪些地方要不要加确认”的争论基本就没了。
全链路日志这块,最容易被忽视的是要把模型的”思考过程”也存下来,不只是存最终结果。 前面提到的那个退款 Agent 出问题案例,事后排查全靠翻 ReAct 的 Thought 记录才找到”模型在查询失败后自己编了订单号”这一步——如果日志只存了”调用了查询工具”和”最终结果”,中间这段”模型自己在想什么”就永远丢失了,出问题基本无从查起。建议至少记录三样东西:每一步的完整 Prompt(含工具结果)、模型原始输出(含思考文本)、以及执行工具的实际返回值,三者都要能按任务 ID 串起来查,事后复盘才有据可查。
常见问题
Agent 和普通 Chatbot 有什么本质区别? Chatbot 每轮独立响应,Agent 能跨多步维持目标、调用外部工具、记住中间状态。Agent 更像一个”执行者”,而不只是”回答者”。
构建 Agent 需要用专门的框架吗? LangChain、LlamaIndex、AutoGen 等框架可以加速开发,但也引入了额外的抽象层和学习成本。简单场景下直接用模型的原生 Function Calling 接口更清晰可控。
Agent 适合替代哪些人工岗位的工作? 当前阶段最适合替代”规则明确、步骤可预测、结果可验证”的重复性操作。高判断力、高创意、高风险的决策仍应保留人工确认环节。
延伸阅读:怎么追踪大模型动态与看懂评测 · Function Calling 接入指南 · RAG 应用构建实践 · 返回 AI 资讯中心 · 了解国产大模型专题