为什么 Agent Testing 失效
Source: Dev.to
(未提供需要翻译的正文内容。如需翻译,请粘贴完整的文本。)
为什么代理测试已失效
以及该如何应对。
软件测试已经解决了数十年。你写一个函数,断言它的输出,CI 变绿,你就发布。契约很明确:相同输入,总是相同输出,永远如此。
LLM 代理彻底打破了这份契约——而大多数团队还没有注意到。
- 今天让你的代理“总结一下这份合同”,它会给出一个不错的回复。
- 明天在模型更新、提示词微调或上下文窗口变化后再问一次,它会给出略有不同的答案。并不是完全错误,只是…不同。差异足以让下游系统在凌晨 2 点悄然解析失败。
这并非假设,而是正在生产环境中发生的真实情况,发生在那些以为自己交付的是稳定系统的公司里。
为什么这种失败模式隐蔽
- 没有异常 – 代理总会响应。它总是响应。响应甚至看起来合情合理。失败是语义层面的,而非语法层面的。
- 无法按需复现 – 你不能
git bisect出模型行为的漂移。模型本身没有变化——是你的提示词变了,或者模型从 API 提供商那里悄然更新,亦或是你注入的上下文发生了偏移。 - 现有测试捕捉不到 – 单元测试会完整地 mock LLM。集成测试只检查 API 调用是否完成。两者都没有验证响应内容是否仍满足下游的期望。
- 没有认知回归套件 – 你在盲目飞行。
传统软件是确定性的。LLM 是在语言的学习表征上进行运算的随机系统。更新模型时,你并不是在修补一个函数——而是在移动一个分布。
Claude‑3.5 与 Claude‑4 在法律摘要提示上的 3 % 差异,可能在人工审查中不易察觉,却会在期待每个输出都出现 “termination”(终止)一词的流水线中导致灾难性后果。
业界的回应是增加更多评估——精细的人类偏好数据集、MMLU 基准、红队套件。这些对模型构建者很有价值,但对应用开发者几乎没有帮助。
应用开发者真正需要的不是 “这个模型总体上能干吗?” 而是 “在我的特定提示、特定上下文下,这个模型仍然能产生我的系统可以依赖的输出吗?”
这个问题今天没有好的答案。
在交付 LLM 应用的团队中常见的真实模式
| 月份 | 事件 |
|---|---|
| 1 | 团队编写提示词,发布代理,手动验证输出看起来不错。 |
| 2 | 有人“稍微”微调系统提示以改善语气。三个下游解析器开始间歇性失效。 |
| 3 | 模型提供商在同一 API 端点后端悄然更新模型。响应格式漂移了 15 %。代理在演示中仍能工作。 |
| 4 | 客户报告摘要合同缺少责任条款。事后分析发现问题起始于第 2 个月。由于没有行为测试,没人注意到。 |
这是一种常态,而非例外。
重新思考代理输出的方式
停止将代理输出视为函数返回值。将它们视为 由具有行为契约的概率过程生成的文档。
契约: 对于此类输入,输出必须满足以下结构和语义属性。
测试该契约需要
- 基线捕获 – 将你的场景在已知良好的系统版本上运行并记录输出。这就是你的 行为指纹。
- 包含性检查 – 定义每个输出必须出现的内容。不是精确的文本(那在每次运行时都会失败),而是语义锚点:关键术语、必需章节、结构元素。
- 漂移检测 – 将新输出与基线进行比较。当相似度低于你的容忍阈值时,使构建失败。让工程师决定该变化是否是有意的。
- CI 集成 – 在每次推送、每次模型版本更改、每次提示编辑时都运行此检查。方式与运行单元测试相同。
这并不复杂,只是没有人去做而已。
工具缺口
现有的评估框架(RAGAS、LangSmith 等)要么:
- 与特定框架耦合(LangChain 等)
- 侧重于 RAG 质量指标,而非行为回归
- 需要托管基础设施和账户
- 过于复杂,无法在一个下午内加入 CI 流水线
市场需要的是一个针对代理的 pytest:轻量、可组合、在本地运行、零基础设施、行为异常时返回代码 1。
最小可行接口示例
# scenarios/summarize_contract.yaml
name: summarize_contract
input: |
Summarize this contract clause in 5 bullet points:
"...The Contractor shall indemnify...termination upon 30 days notice..."
expected_contains:
- liability
- termination
max_tokens: 512
# Run against real model, compare to baseline
agentprobe run scenarios/ \
--backend anthropic \
--baseline baseline.json \
--tolerance 0.8
✓ PASS summarize_contract
✗ FAIL extract_parties
Drift detected: similarity 0.61
代理测试之所以失效,是因为还没有人构建合适的工具。这是一个可以解决的问题。