青雲的博客

Article

Agent 从 Demo 到真实业务,差的不是模型,而是工程秩序

· 15 分钟阅读

最近经常看到一个问题:

Agent 的 Demo 能跑,但一接真实业务就开始乱。

该调工具的时候不调,不该调的时候乱调。RAG 检索看起来有结果,但回答一细问就露馅。工具失败以后不知道该重试、降级,还是交给人。上下文一长,模型前后状态开始漂。跑一段时间以后,效果有没有变好说不清,成本倒是肉眼可见地涨。

这个问题很典型。

我现在越来越觉得,Agent 从 Demo 到真实业务,中间差的不是一个更强的模型,也不是换一个更流行的框架,而是一整套工程秩序。

Demo 阶段你看到的是:

模型理解需求 -> 调工具 -> 给结果

真实业务里你遇到的是:

需求不完整
检索不稳定
工具会失败
状态会丢
上下文会胀
成本会炸
结果还要能解释

所以 Agent 的核心经验可以先压成一句话:

Agent 的上限由模型决定,但下限由工程决定。

下限没托住,模型再聪明,也只是一个不稳定的实习生。

不要先问用什么框架,先问什么叫完成

很多 Agent 项目一开始就选框架。

LangGraph、CrewAI、AutoGen、Dify、各种自研 runtime,都能把流程串起来。但如果任务本身没定义清楚,框架只是把混乱重新包装了一遍。

真实业务里,最先要定义的是任务契约。

这个任务的输入是什么?

是用户一句话、一个表单、一份文件、一个工单,还是一个代码仓库?

这个任务的输出是什么?

是文本建议、结构化 JSON、数据库记录、PR、报表,还是一个可访问的页面?

什么叫成功?

用户满意不满意当然重要,但系统层面还要更具体:测试是否通过、知识库证据是否命中、字段是否完整、工具是否执行成功、是否需要人工确认。

什么叫失败?

工具失败、检索为空、权限不足、参数不合法、置信度不够、预算耗尽,这些都不应该混成一个模糊的“执行失败”。

很多 Agent 看起来“会思考”,但一接业务就乱,本质是系统没有定义什么叫完成。

没有完成标准,Agent 就只能靠语言自嗨。

我非常不喜欢 Agent 只说“任务已完成”。真正可靠的 Agent 应该能交出证据:

  • 调了哪些工具;
  • 用了哪些资料;
  • 中间失败过什么;
  • 为什么重试;
  • 最终结果怎么验证;
  • 哪些地方仍然不确定。

这才是工程系统,不是聊天机器人。

RAG 不准,通常不是向量库一个人的锅

很多人一遇到 RAG 不准,就开始换 embedding、换向量数据库、调 topK。

这些当然有用,但经常不是第一问题。

RAG 真正的问题一般在更前面:文档有没有被正确解析,chunk 有没有保留语义边界,检索有没有带结构化条件,上下文拼接有没有控制噪声。

比如一个合同文档,如果你把标题、条款编号、表格、附件关系全打散,只剩一堆固定长度的文本块,那后面再好的向量模型也很难救。

我现在更愿意把 RAG 当成 Agent 的眼睛,而不是一个简单搜索框。

稍微可靠一点的 RAG,至少要有这几层:

  • 文档解析:PDF、网页、表格、代码、Markdown 不能一刀切;
  • Chunk 策略:按标题、段落、语义、代码块切,而不是只按长度切;
  • Metadata:文档类型、时间、业务线、权限、章节路径;
  • Hybrid Search:关键词和向量一起用,不要迷信纯向量;
  • Rerank:第一轮召回负责“广”,第二轮排序负责“准”;
  • 引用证据:回答要能指回原文片段;
  • 空结果策略:找不到就说找不到,不要硬编。

RAG 最大的坑不是没搜到。

更麻烦的是:搜到一点相似的东西,然后模型很自信地胡说。

所以 RAG 不是为了让 Agent 看起来知道更多,而是为了让它知道自己知道什么、不知道什么。

Tool Calling 不是接几个 API,而是能力治理

Demo 里的工具经常长这样:

searchWeb(query)
sendEmail(to, content)
createOrder(payload)

看起来很清爽。

但真实业务里的工具不是函数列表,而是权限边界。

一个工具至少要回答这些问题:

  • 当前用户有没有权限调用;
  • 信息是否足够,需不需要先追问;
  • 调用后有没有副作用;
  • 调错了能不能撤销;
  • 失败以后是重试、降级,还是交给人;
  • 返回结果怎么验证。

我一般会先把工具按风险分层。

只读工具,比如查询订单、搜索知识库,可以比较放心地自动调用。

低风险写工具,比如创建草稿、生成计划、写临时文件,可以自动执行,但要留日志。

高风险写工具,比如发邮件、提交代码、修改订单、扣款,就不能让模型一句话直接干。该确认就确认,该审批就审批。

不可逆工具更不用说,默认就应该非常保守。

Agent 最容易翻车的地方,不是不会调工具,而是它不知道工具的副作用。

所以 Tool Calling 的本质不是模型会不会调用函数,而是系统如何治理能力。

Loop 里一定要有 verifier

一个最小可用的 Agent Loop,不应该只有:

Plan -> Act -> Answer

更合理的是:

Goal       目标是什么
Planner    下一步怎么选
Actor      执行动作
Observer   观察结果
State      记录状态
Verifier   判断有没有变好
Policy     权限、成本、重试、审批约束
Exit       成功、失败、预算、人类接管

这里最关键的是 verifier。

没有 verifier 的 Agent,像一个只会汇报进度的人:

我已经分析完成了。
我已经修复问题了。
我已经生成方案了。

但你问它证据是什么,它拿不出来。

真实业务里,verifier 可以很朴素:

  • 单元测试是否通过;
  • SQL 查询是否有结果;
  • 返回 JSON 是否符合 schema;
  • 文档引用是否真的存在;
  • 工具执行是否成功;
  • 关键字段是否完整;
  • 成本是否超预算;
  • 是否需要人类确认。

如果是 Coding Agent,verifier 可以是 pnpm testcargo testgit diff --check

如果是客服 Agent,verifier 可以是“答案是否引用知识库”“是否命中敏感政策”“是否需要升级人工”。

如果是数据分析 Agent,verifier 可以是“SQL 是否执行成功”“样本量是否足够”“图表字段是否对应”。

不要让模型自己一句“我觉得可以”就结束。

Agent 真正开始可靠,是从它愿意接受外部验证开始的。

上下文不是越长越好,要分层管理

上下文一长就乱,很正常。

因为很多系统把所有东西都塞进一个 prompt:

  • 用户历史;
  • 当前任务;
  • 工具结果;
  • RAG 文档;
  • 错误日志;
  • 系统规则;
  • 示例;
  • 旧状态。

最后模型不是没能力,而是被噪声淹没了。

我建议至少分三层。

Context 是当前这一轮必须看的内容,要短、准、直接影响输出。

State 是任务进行到哪里了,可以更新,也可以恢复。

Memory 是长期偏好和历史经验,慎用,需要检索。

不要把 Memory 当垃圾桶。

很多所谓记忆系统,只是把历史对话越塞越多。这样做的结果不是智能增强,而是缓存污染。

更好的方式是:

  • 当前任务状态结构化保存;
  • 工具结果只保留摘要和引用;
  • 长文档通过 RAG 动态取;
  • 失败记录进入 state,不要一直留在 prompt;
  • 每轮只给模型当前决策所需的信息。

上下文管理的目标不是让模型看见一切,而是让它只看见该看的东西。

工具失败要有语义

真实业务里,工具一定会失败。

网络超时、权限不足、参数错误、数据不存在、第三方限流、返回格式变了,都很正常。

问题不在失败,而在失败有没有语义。

同样是失败,下面这些对 Agent 来说完全不一样:

timeout
permission_denied
not_found
validation_error
rate_limited
side_effect_uncertain

timeout 可以重试。

permission_denied 应该停止并提示用户授权。

not_found 可能要换检索条件。

validation_error 应该修参数。

rate_limited 应该等待或降级。

side_effect_uncertain 必须人工确认。

如果工具只返回一个 Error: failed,Agent 就只能瞎猜。

所以工具层不要只封装成功结果,也要封装失败语义。

Agent 的可靠性,很大一部分来自它知道失败以后该怎么办。

成本控制不要最后再做

很多项目 Demo 阶段不看成本,等接业务才发现一次任务要跑十几轮模型调用、几十次检索、几次 rerank,还要调用大模型做验证。

效果是有了,账单也有了。

成本控制应该一开始就进入设计。

简单做法包括:

  • 模型路由:简单分类、小决策用便宜模型,关键生成用强模型;
  • 缓存:相同检索、相同工具结果、稳定系统 prompt 尽量缓存;
  • 预算:每个任务设置最大轮数、最大 token、最大工具调用次数;
  • 提前退出:已经满足 verifier,就不要继续想;
  • 分级 RAG:先轻量召回,不够再 rerank,不要上来全套;
  • 日志统计:记录每类任务平均成本和失败成本。

不要让 Agent 无限制“再想一想”。

人类工程师加班会累,Agent 不会累,但账单会。

没有评估集,优化就会变成玄学

Agent 项目最容易出现一种错觉:

今天感觉比昨天好了。

但感觉不是评估。

你至少要有一套固定任务集:

  • 常见问题;
  • 边界问题;
  • 工具失败场景;
  • RAG 检索困难样本;
  • 长上下文任务;
  • 需要人工确认的高风险操作。

每次改 prompt、换模型、改 chunk、加工具,都跑一遍。

指标也不要只看回答好不好,最好拆开看:

  • 任务有没有完成;
  • 有没有引用正确资料;
  • 该不该调工具、调没调、调对没调;
  • 工具失败后有没有合理兜底;
  • 平均 token、调用次数、耗时;
  • 出问题后能不能追溯;
  • 哪些任务必须交给人。

没有评估,Agent 优化就会变成玄学调参。

如果 Demo 能跑,但真实业务一接就乱

我会按这个顺序补:

先定义任务契约:输入、输出、成功、失败、验收。

然后给工具加 schema、权限、副作用等级、失败语义。

再给 RAG 加 metadata、rerank、引用证据和空结果策略。

接着把 Agent Loop 补成 Goal / Actor / Observer / Verifier / State。

再做上下文分层,不要把所有历史都塞进 prompt。

同时加预算:最大轮数、最大 token、最大工具次数。

最后做固定评估集,每次改动都跑。

很多人会反过来:先换框架,先上多 Agent,先搞复杂编排。

但真实经验是,单 Agent 都没有工具治理、状态记录、失败恢复和 verifier,多 Agent 只会把混乱放大。

Agent Demo 解决的是能不能跑。

真实业务解决的是出问题时还能不能保持秩序。

前者靠模型能力,后者靠工程系统。

Keep Reading

相关文章

评论