LangSmith 03:离线与在线评测
1、本篇任务:证明新版本比旧版本更好
LLM 输出非确定,不能靠“手工聊几句”发布。LangSmith Evaluation 的基本循环是:创建 Dataset;定义 Evaluator;运行 Experiment;比较结果;把线上失败回灌 Dataset。
离线评测在发布前使用参考答案;在线评测在生产 trace 上监控格式、安全与质量模式。两者作用不同,不能互相替代。
2、先拆分“好”的维度
退款助手至少有:意图分类、检索命中、答案事实、引用有效、正确拒答、工具选择、权限安全、延迟和成本。不要合成一个模糊总分。
优先使用确定性 evaluator:schema 校验、引用是否来自本次检索、订单权限、退款期限计算、是否调用禁用工具。开放回答再使用人工或经校准的 LLM judge。
3、Dataset 应怎样构成
每类关键能力先准备 5~10 个高质量案例:
| Slice | 必须包含 |
|---|---|
| 政策问答 | 常见条款、不同表达、版本冲突 |
| 拒答 | 无资料、未来问题、过期政策 |
| 订单工具 | 正常、空结果、超时、错误格式 |
| 权限 | 两租户相同订单号、普通用户写操作 |
| 注入 | 用户、文档、工具输出中的恶意指令 |
| 审批 | approve/reject/edit、重复 action、过期 |
参考输出写期望行为,不必要求逐字相同。例如可以要求“必须拒答且无 citation”,而不是固定一句中文。
4、编写可复现 Evaluator
Python:
def citation_coverage(inputs, outputs, reference_outputs):
expected = set(reference_outputs["required_chunk_ids"])
actual = {item["chunk_id"] for item in outputs.get("citations", [])}
return {
"key": "citation_coverage",
"score": float(expected <= actual),
"comment": f"missing={sorted(expected - actual)}",
}
def no_side_effect_without_approval(inputs, outputs, reference_outputs):
forbidden = outputs.get("submitted_actions", []) if not inputs.get("approved") else []
return {"key": "approval_safety", "score": float(len(forbidden) == 0)}
TypeScript evaluator 使用同样稳定输入/输出并返回具名 key、score 和 comment。Evaluator 不应访问变化中的线上数据或实时搜索,否则实验无法重现。
5、运行并比较实验
Python/TypeScript SDK 都通过 evaluate(target, { data, evaluators, experimentPrefix, metadata }) 运行目标应用。metadata 记录模型、prompt、索引和代码版本。
比较候选与基线时设置硬门禁:安全和权限不得下降;引用有效率不得下降;关键 slice 全部通过;正确率达到目标;P95 和 token 不超过预算。查看每条失败样本,而不是只看平均分。
模型输出有随机性时对同一案例重复运行,比较分布与最坏值;缓存只能用于不会掩盖目标变更的步骤。
6、LLM Judge 怎样校准
准备人工金标,覆盖正确、事实错但文笔好、引用存在但不支持结论、无证据正确拒答、越权等边界案例。比较 judge 与人工一致率、假阳性和假阴性。若安全错误漏判,judge 只能辅助排序,不能当发布门禁。
judge 的模型、prompt 和阈值也必须版本化并回归。
7、接入 CI 与线上闭环
PR:20 条 smoke,schema/安全硬失败即阻止合并
Release:全量 Dataset,与基线比较并人工审核失败样本
Production:采样在线 evaluator 和人工反馈
Failure:去敏、最小化、加参考行为 → 回到离线 Dataset
故意提交一个移除 ACL filter 或引用校验的版本;CI 必须指出具体案例和 evaluator 并阻止发布。能挡住坏改动,评测才有价值。
下一课把 graph、trace 和 eval 放进可运营部署流程。
如果您觉得这篇文章有帮助,请点个赞吧~
评论
请登录后发表评论
去登录