不一致性主张
关于 LLM agent 的一个反复出现的抱怨是它们不稳定:同一个请求输入两次,会产生两个不同的决策。这种说法几乎总是同一套框架——模型不稳定、采样温度太高、prompt 太脆弱。CTGT 的 Concordance 工作之所以有用,恰恰是因为它拒绝这套框架。它追踪 agent 得出结论的路径,并追问两次运行为何出现分歧,而不是断言它们确实分歧了。答案往往在于:这两次运行从来就不是同一次运行。
在工具链的另一端,DeepEval 风格的测试框架已经让输出打分在大规模场景下变得常规化。你可以运行一套用例、挂上指标、得到一个通过率。这些框架自身无法做到的,是定位失败的成因:某个用例得分为零只能告诉你答案是错的,而不能告诉你轨迹中哪一步引入了错误。Concordance 式追踪与 DeepEval 式打分之间的差距,不是指标设计上的差距,而是上下文捕获上的差距。追踪工具能解释分歧,是因为它持有输入;打分框架只能报告分歧,是因为它丢弃了输入。
隐藏方差的来源
agent 的决策远不止是用户消息的函数。在两次从外部看完全相同的运行之间,以下各项都可能不同:

- 检索到的上下文。 向量搜索返回的排序集合会随索引更新、embedding 模型版本和并列打破规则而变化。两次运行可能检索到有重叠但不完全相同的文档,而模型会基于它实际拿到的内容进行推理。
- 工具响应。 天气 API、数据库查询、搜索调用——每一个都返回实时数据。工具载荷中的一个时间戳、一个分页游标,或一个重新排序的结果集,就足以改变下一步。
- 顺序与时间戳。 长对话中的消息顺序、注入系统 prompt 的挂钟时间,以及并行工具调用的解析顺序,都会进入 prompt。
- 采样参数。 temperature、top-p、seed 和 max tokens 常常按环境设置,却很少与依赖它们的 prompt 一起做版本标记。
- prompt 组装漂移。 系统 prompt 由模板、few-shot 示例和注入的上下文组装而成。一次只改动一个片段的部署,会改变每个请求的有效输入,而输出得分中没有任何东西记录这一变化。
令人不安的结论是:一旦检查测试框架,许多“看起来相同的输入”其实并不相同。agent 在给定其输入的情况下是确定性地行动的;只是这些输入没有被保持不变、没有被记录、也没有被比较。近期关于 agent 评估的报道不断回到这一点——有趣的方差存在于模型周围的流水线中,而不只在模型本身——其实际含义是:仅靠输出打分只会持续错误归因。
重放契约
解决办法是一份契约:每个决策都记录足够的上下文,以便被精确重放。具体而言,一条 trace 记录应当携带:
{
"run_id": "...",
"model": { "name": "...", "version": "...", "params": { "temperature": 0.0, "top_p": 1.0, "seed": 42 } },
"prompt": { "template_hash": "...", "assembled": "...", "fragments": ["..."] },
"retrieval": [
{ "doc_id": "...", "content_hash": "...", "score": 0.81, "rank": 1 }
],
"steps": [
{
"index": 0,
"tool": "search",
"args": { "query": "..." },
"response": { "...": "..." },
"response_hash": "..."
}
],
"output": "..."
}
组装后的 prompt 与其各片段的哈希一起被逐字存储,因此模板变更无需 diff 数兆字节的文本即可被检测到。检索集合携带文档哈希,因此索引偏移是可见的,而不是靠推断。工具参数和响应在每一步都被捕获,这使轨迹成为一个可重放的序列,而不是一个终端字符串。

有了这条记录,重放就变成了一项受控实验。冻结输入——相同的 prompt、相同的检索集合、相同的工具响应、相同的模型版本——任何残余的分歧都是模型方差。一次只解冻一个维度,你就能把分歧归因于检索、某个工具或某次部署。打分也随之从终端答案转向轨迹:每一步都被比较,第一个分歧点就是调查的起点。这就是知道某个用例失败与知道哪个决策失败之间的区别。
权衡是真实存在的。完整上下文捕获是存储密集型的,它会拖慢写入路径,并且会迫使目前把 prompt 和检索配置当作环境变量的团队建立纪律。捕获工具响应还可能捕获敏感载荷,这要求在写入时而非分析时进行脱敏。这些都不是免费的,采用重放的团队应当预期在见到回报之前先投入留存策略和 schema 治理。另一种选择——对你无法复现的输出打分——每次运行更便宜,每个 bug 更昂贵。
这给运营者带来了什么
失败的用例变得可复现。运营者不再只有一张截图和对所问内容的模糊记忆,而是拥有一条能重放到同样错误答案的 trace,以及一份显示哪一步引入了该错误的 diff。可复现性是修复的前提;没有它,调试就是猜测。
评估成本变得可归因。针对冻结输入的重放运行会检验决策逻辑,而无需重新获取实时数据或重新运行探索性检索。这使回归套件运行成本更低、更易于推理,因为每次运行只测试一件事,而不是整条流水线。全新的探索性运行仍然有价值,但它们不再是唯一的选择。
一致性成为一个可度量、有基线的属性。运营者不再把稳定性当作轶事——“昨天还好好的”——而是可以跨部署追踪每一步的分歧率,并观察 prompt 变更或模型升级是否改变了它们。这正是 Concordance 与 DeepEval 两条线索共同指向的转变:追踪上下文,在受控条件下重放它,并对轨迹打分。模型很少是谜团所在。缺失的输入才是。
