打开网易新闻 查看精彩图片

你花了三周搭观测系统。链路追踪进Jaeger,指标进Grafana,告警进Slack。模型说了什么、耗时多久、花了多少钱,一清二楚。

然后你改了提示词。

模型变好了?变坏了?哪些输入出问题?你不知道。你的链路追踪是只写的——数据进去了,再也没出来过。生产数据躺在Jaeger里,从没变成测试用例。

我们搭了座桥,把追踪转成测试。跑自己数据时发现,一半链路片段是空的——因为recordContent默认关闭。专门用来提取测试数据的工具,什么都提取不到。

修好了。以下是完整工作流。

每个LLM团队都有的死循环

每个LLM团队都有的死循环

部署提示词v2,盯几小时仪表盘,"看起来正常,延迟差不多,没报错",继续干活。

"看起来正常"不是评估。你在检查系统健康——延迟、错误、成本——但没检查输出质量。模型可能返回明显更差的答案,你却不知道,因为你没有基于真实生产数据的回归测试。

做得好的团队有另一套循环:收集生产输入输出(追踪)→从真实流量提取测试用例→用新提示词跑这些输入→打分:v2比v1好吗?→放心部署。

第2到4步是评估框架做的事。问题是从第1步到第2步。你的追踪在Jaeger里,评估框架要YAML数据集。没人搭这座桥。

一条命令把Jaeger追踪变成测试集

一条命令把Jaeger追踪变成测试集

npx toad-eye export-trace abc123def456

输出:✅ Exported trace abc123def456 → ./trace-abc123de.eval.yaml

生成的YAML长这样:

name: exported-trace-abc123de

source: toad-eye-export

metadata:

trace_id: abc123def456

打开网易新闻 查看精彩图片

exported_at: "2026-03-15T14:22:00.000Z"

model: gpt-4o

provider: openai

cases:

- id: production-case-1

variables:

input: "What are the side effects of ibuprofen?"

assertions:

- type: max_length

value: 1500

- type: not_contains

value: "i cannot"

- id: production-case-2

variables:

input: '{"action": "summarize", "text": "..."}'

assertions:

- type: max_length

value: 800

打开网易新闻 查看精彩图片

- type: is_json

value: true

一条追踪,多次LLM调用,每次变成一个测试用例。断言(assertions)是根据生产模型实际返回的内容自动生成的。

保守基线:抓退化,不抓优化

保守基线:抓退化,不抓优化

导出不只是复制输入输出。它分析生产响应,创建基线断言:

max_length:生产响应的长度。新响应更长?可能啰嗦了,触发警报。

not_contains:生产响应里没有的短语。新响应出现了?可能是拒绝回答或格式错乱。

is_json / contains:结构约束。生产输出是JSON?新输出也得是。

这些是保守基线——它们捕捉退化,不捕捉改进。v2可能好得多,但只要没破坏现有行为,测试就通过。这是故意的:先防止搞砸,再谈优化。

运行评估:npx toad-eye eval ./trace-abc123de.eval.yaml --prompt ./prompt-v2.txt

输出对比表:哪些用例通过、哪些失败、失败的具体差异。生产输入"ibuprofen副作用"在v1返回1500字,v2返回1800字,触发max_length断言。你需要决定:这是退化,还是更好的详细回答?

我们踩过的3个坑

我们踩过的3个坑

坑1:recordContent默认关闭。Jaeger只存元数据,不存实际输入输出。工具设计来提取测试数据,结果提取到一堆空壳。修复:开recordContent,或者换能存内容的追踪后端。

坑2:生产数据有噪声。用户输入"asdfgh",模型返回"我不理解"。这种用例进测试集没意义。修复:加过滤规则,只导出有明确意图的交互。

坑3:断言太松漏掉真问题,太严误报。修复:从保守开始,人工审核失败案例,逐步收紧。

从"看起来正常"到"知道正常"

从"看起来正常"到"知道正常"

这套工作流的核心是缩小"能观测"和"能评估"的 gap。大多数团队卡在中间:看得见,但不敢改。

我们内部跑了一个月。提示词迭代从"改完祈祷"变成"改完跑测试"。一次v3版本,测试显示15%的生产用例触发not_contains断言——新提示词在某些边缘问题上开始说"我无法回答"。回滚,修提示词,重跑,通过,部署。

没这套工具,这15%的问题可能几周后才被用户投诉发现。