Skip to content

Agent 为什么经常“不听话”:从 Context、Tool 到结果验证 ​

Agent Demo 往往很好看:演示的人知道该问什么,路径短,Tool 少,旁边还有人盯着。真正丢进业务系统里,常见体验是:不调工具、乱调工具、绕圈、一本正经地胡说、偶尔还干出越权的事。

这篇不讲模型原理。我想回答的是:

Demo 为什么很好看,真正用起来为什么经常不稳定?

背景仍是我自己:多年 Java / 企业系统,正在把 Agent 往真实业务场景里推。踩过的坑,和以后会优先防的坑,都记在这里。结论可以先说:

Agent「不听话」,多数时候不是性格问题,是约束不够。


1. Demo 能跑,不代表 Agent 能用 ​

两边差别很大:

text
Demo:
单任务 · 短 Context · 少 Tool · 人工观察 · 路径可预期

真实应用:
复杂任务 · 长 Context · 多个 Tool · 异常与重试
权限 · 成本 · 并发 · 结果验证 · 脏数据

Demo 里「看起来智能」,常常是场景被裁剪过了。真实系统里,用户一句话可能含糊、数据可能过期、接口可能超时、权限可能不够。模型还是那个模型,环境变了,表现就崩。

所以我评估 Agent,不看演示流畅度,看:异常怎么处理、错了能不能拦住、日志能不能复盘、失败时用户看到什么。能演示和能值班,是两件事。企业系统里,值班能力比 Demo 分数重要得多。


2. Context 问题 ​

最常见的几类:

信息缺失
没给设备号、时间范围、业务规则,却指望模型「自己懂现场」。模型会补全——补出来的往往是幻觉。用户听起来很完整,系统里却对不上号。

信息过多
把整份制度、半年工单、全部会话历史塞进去。噪声变大,关键信号被淹没,Token 和延迟一起涨。模型开始抓次要细节,主线反而丢了。

历史污染
上一轮任务的中间假设还留在对话里,下一轮任务被带偏。尤其是多轮「分析—追问」之后,旧结论会像事实一样继续流传。

上下文冲突
系统提示说「只查询不修改」,用户又说「直接帮我改掉」,业务规则又禁止某状态变更。模型夹在中间,表现就会飘:有时服从用户,有时服从系统,你很难预测。

我的处理思路:

text
需要什么给什么
长期信息与当前任务分离
历史过长就摘要,不原文堆叠
Tool 结果结构化,少塞散文
冲突规则写死在程序侧,不交给模型仲裁

Context 工程做不好,后面怎么换模型都像「不听话」。换模型是最后一招,不是第一招。做后端的人换个说法:给下游的 payload 裁不好,调用方再聪明也会翻车。


3. Tool 问题 ​

真实故障里,很大一部分其实是 Tool 设计问题:

  • 该调不调:描述含糊、触发条件不清
  • 调错 Tool:名字相近、职责重叠
  • 参数错误:类型不对、缺必填、时间格式乱
  • 返回值模型看不懂:一大段 HTML、无字段说明、错误时仍返回 200 + 空对象
  • Tool 失败却被当成成功:超时后模型继续「分析」

核心观点:

很多 Agent 问题并不是模型能力问题,而是 Tool 设计得不像一个好的工程接口。

用 Java 后端的标准想:如果你给同事一个 queryEquipment(String id),文档不写清返回字段、失败怎么表示,对方调用也会一团糟。模型比同事更依赖清晰契约——它不会来问你「这个 null 是什么意思」。

我会要求 Tool:

  • 名称表达单一职责
  • 参数有类型与校验
  • 成功 / 失败结构固定
  • 错误信息机器可读、人也读得懂
  • 写操作与读操作严格分开
  • 对「无数据」和「调用失败」做出区分,避免模型把空结果编成故事

举个反例:接口超时返回空对象,模型读成「当前无异常」,再据此写一份很自信的分析报告。根因不在模型,在契约。Tool 像好 API,Agent 才有机会像好调用方;Tool 像垃圾桶,Agent 再强也只是高级乱调用。


4. Agent 无限循环 ​

典型形态:

text
判断 → Tool → 判断 → Tool → 判断 → …

原因可能是:终止条件不清、Tool 结果不足以推进、模型反复「再查一下」、验证失败却没有退出策略。有时用户问题本身就含糊,模型用更多调用假装在努力。

我会在编排层硬约束:

  • 最大执行步数(例如 8~12 步,按场景定)
  • Timeout(整次任务与单次 Tool)
  • Retry 上限(按错误类型区分可重试 / 不可重试)
  • 状态机:明确「进行中 / 待确认 / 成功 / 失败 / 需追问」
  • 终止条件:目标达成、信息不足需问用户、权限不足、步数耗尽

没有这些,Agent 不是「更努力」,是在烧钱和打接口。循环本身不可怕,可怕的是没有人规定它何时必须停。这和消息消费里的重试风暴是一类工程问题,只是中间多了一个会即兴发挥的决策者。


5. 输出看起来正确,但实际上错误 ​

这是我认为最危险的一类。

例如:

text
模型:「设备 A 当前存在异常。」

实际上:设备状态接口返回的是昨天缓存的数据。

或者:

text
模型:「维修工单已创建。」

实际上:createWorkOrder 因权限失败,返回了错误码,模型没读懂。

所以:

text
模型输出 ≠ 事实

正确链路更接近:

text
事实数据(接口 / 数据库)
 ↓
程序验证
 ↓
模型解释(基于已验证事实)

而不是让模型自己生成事实。

企业系统里,用户对「说得像真的」很敏感。一次自信的错误,会比十次「我不确定」更伤信任。Agent 应用里,宁可少说,也不要无依据地断言。

我会要求分析类输出尽量带「依据来源」:哪次查询、哪个字段、哪个时间点。对不上来源的句子,编排层可以直接删掉或改成追问,而不是原样展示。如果让我给 MES 分析类 Agent 定验收标准,第一条就会是:结论必须能回溯到 Tool 结果。


6. 权限问题 ​

Agent 接进真实系统之后,权限必须由程序控制,不能交给模型「自己判断能不能做」。

text
查询 ≠ 修改 ≠ 删除 ≠ 执行生产操作

尤其是 MES / ERP:

Agent 可以建议执行什么,但不应该天然拥有执行一切操作的能力。

我会把动作分成至少三档:

  1. 只读查询:在用户权限内可自动执行
  2. 低风险写操作:如草稿、备注 → 可自动或轻确认
  3. 高风险写操作:改关键状态、触发生产、对外发送 → 强制人工确认 + 审计日志

模型可以说「建议创建工单」;真正 INSERT 发生在确认之后,由业务服务执行。这和传统系统的权限模型一致,只是前面多了一层 Agent 编排。

还有一点:Agent 使用的服务账号,权限应小于等于当前用户,而不是「万能运维账号」。否则一次 Prompt 注入或一次误判,影响面会大得离谱。企业系统里这是基本功,接到 Agent 上不能松。


7. 成本问题 ​

不稳定往往伴随着贵:

  • Context 越堆越长
  • Tool 无效调用多
  • 本来用小模型够用,却全程上大模型
  • 失败无限重试
  • 不必要的多轮 Loop
  • 同一只读查询在一轮任务里被反复打

Agent 成本控制本质上也是工程问题:裁 Context、限步数、按任务选模型、缓存只读查询、失败快速失败、把「解释」和「决策」拆开(决策用强模型,格式化用弱模型)。

我不会先问「换个更强的模型能不能好」,而会先问「这次任务有多少步是无效的」。成本失控的 Agent,短期还能靠演示撑着,长期一定会被业务方关掉——不是因为不智能,是因为账单和对账都过不去。


8. 稳定性问题 ​

一套我会默认带上的工程能力:

text
Timeout
Retry(有上限、可分类)
Fallback(降级到普通 AI 调用或人工)
Logging
Tracing(一次任务一条链路)
Validation
Human-in-the-loop

没有日志和追踪,出了「不听话」你只能猜。有了链路,你才能看到:是 Context 缺了、Tool 错了,还是验证没拦住。

稳定性不是调一次 Prompt 得到的,是约束、观测和回滚能力堆出来的。传统后端里的超时、熔断、降级、审计,原样搬到 Agent 编排层,通常比再写十段「请你务必准确」更有效。我会把这些当成 Agent 上线的默认清单,而不是「以后再补」。


9. 我现在认为 Agent 最重要的能力 ​

不是:

「让模型更聪明。」

而是:

「让一个不确定的模型输出,被一套确定性的工程系统约束起来。」

模型负责理解与选择;程序负责边界、权限、验证、终止与审计。谁主谁辅搞反了,Demo 越炫,线上越难收场。

这也是为什么我从业务系统背景看 Agent,会本能地强调:接口契约、状态机、权限、校验、人工确认——这些在传统后端里早就是常识,换到 Agent 里同样成立。差别只是:中间多了一个会即兴发挥的组件,所以约束要写得更硬,而不是更软。


10. 如果重新做 ​

我会把自己按回这几句:

text
少一点自由,多一点约束
少一点自动执行,多一点验证
少一点复杂 Agent,多一点确定性工程

具体一点:

  • 先把 Tool 做成好 API
  • 先把验证和权限做成硬门槛
  • 先把步数和超时做成硬限制
  • 先把日志做成能复盘的链路
  • 再谈更复杂的多 Agent、长记忆、全自动

Agent「不听话」,多数时候不是性格问题,是系统设计没有把不确定的部分关进笼子里。把笼子设计好,它才配进真实业务。