从“调用成功”到“修订正确”:一次 Worklist Agent Trace 与评测实战
用真实 GLM 调用验证 Worklist 工具与候选修订,复盘 20 条用例、评分规则修正和 LangSmith 轨迹,并整理 Agent 可观测性与评测的面试要点。

模型返回“已经修改完成”,究竟能证明什么?在一个会调用工具的 Agent 中,它可能只生成了文字,也可能选错了参数,甚至工具返回成功,最终改动却偏离了用户要求。接入 LangSmith 后,我最关心的便是:能否把这几种情况区分开,并留下可重复核对的证据。
这次选择的是 TP-Generator 的 Worklist Helper。它根据测试规格、模板及用户指令生成候选修订,适合检查“读懂要求—选择工具—校验动作—提交计划”的完整过程。项目没有部署到线上,评测从本地 Python 入口运行,真实调用 GLM-5.2,再把轨迹和评分上传到 LangSmith。
先交代结果:之前的 12 条路由用例之后,本次新增了 20 条工具与候选修订用例。按修正后的任务规则全部通过,但这只是合成资料上的功能回归,验证范围止于候选执行计划,没有覆盖代码落盘、C++ 编译或硬件执行。
一、为什么先测路由,还必须继续测工具
路由评测回答的是“该交给谁处理”。例如,用户问普通知识应直接回答,要求修改模板则应进入 Worklist 流程。12 条用例足以确认接入与基本分流能运行,却没有证明后续工具调用正确。
工具评测要进一步问:该读取时是否读取,该拒绝时是否停止,修改的是不是指定位置,提交前有没有通过校验。即使两条请求都路由到 Worklist,“按 Spec 修正所有差异”和“只改一个电压参数”也有不同的验收条件。只看路由正确率,会把这些真正影响业务的差别隐藏起来。
所以我把目标拆成三层:入口是否选对、执行过程是否合规、最终候选计划是否满足要求。本轮主要验证后两层,并使用真实工具实现,而非让模型在回答里模拟一串工具日志。
二、本地项目怎样接入 LangSmith
模型服务和观测平台承担不同职责。GLM Key 用于推理;LangSmith Key 用于上传、读取 Trace 和评测记录。没有公网业务地址也可以做离线评测,只要本地进程能够访问这两个服务。
这个项目的 GLM 配置使用 ZHIPU_CODING_API_KEY。LangSmith 可以使用以下原生变量;示例中的值全部是占位符,不能照抄为真实凭据:
ZHIPU_CODING_API_KEY=YOUR_GLM_CODING_KEY
LANGSMITH_TRACING=true
LANGSMITH_API_KEY=YOUR_LANGSMITH_KEY
LANGSMITH_PROJECT=worklist-evaluation
LANGSMITH_WORKSPACE_ID=YOUR_WORKSPACE_ID
LANGSMITH_ENDPOINT=https://apac.api.smith.langchain.com
这里的 APAC 地址对应本次账户所属区域,不是所有账户的统一配置。接入时遇到的鉴权失败,最终定位到工作区在 APAC、请求却发往美国默认端点。判断区域要看账户和服务地址,VPN 出口并不能决定工作区存储位置。区域配置要求可以核对 LangSmith 官方接入文档。
项目还兼容旧的 LANGCHAIN_* 变量,并明确处理环境变量与 .env 的优先级。实际运行前关闭 Mock 和 Replay,先验证模型响应,再验证 Trace 上传及回读。终端没有报错、首页出现项目,都不等于完整调用树已经保存。
三、Trace 里到底记录什么
一次请求对应一棵执行树,模型和工具调用分别成为树上的节点。LangSmith 将单个工作单元称为 Run,可以类比 Span;一次操作的节点集合构成 Trace,多轮会话还可以通过 Thread 关联。这个区分决定了排障时应该看单个调用,还是回到完整上下文。官方概念说明
本次实际调用树的关键结构如下。模型通常需要观察上一步工具结果,再决定下一步动作,因此工具之间会穿插新的模型调用。
Target
└─ worklist.resolve
├─ LLM → inspect_worklist_diff
├─ LLM → draft_worklist_actions # 需要自定义动作时
├─ LLM → validate_worklist_actions
└─ LLM → submit_worklist_revision
业务层记录任务输入和返回类型,模型层记录消息、工具定义、响应及 Token,工具层记录名称、实际参数和执行结果。项目通过 traceable 在自定义运行时的调用边界埋点,同时避免底层客户端重复上报同一次推理,否则一次调用可能变成两个模型节点,Token 也可能重复统计。
另一个容易漏掉的问题是“业务失败没有抛异常”。例如工具返回 ok=false,HTTP 请求仍可能是成功的。此时需要把错误码记录到工具节点,并在评测输出中保留业务失败,不能只统计 Python 异常。
一个真实例子:只把电压改成 1.1V
这条用例要求生成供人工审核的临时调试修订:只改第一个 ForceVoltage 的电压,保留当前引脚,其他调用和参数不变,明确覆盖 Spec 的默认电压。现有候选动作无法表达指定值时,才使用受限草拟工具。
实际轨迹执行了 inspect、draft、validate、submit。最终 plans 中只有一项 edit,目标为 ForceVoltage 的第零次出现,参数索引 1 改为 1.1 * V;新增和删除列表均为空。参数索引从零开始,这里对应电压参数。

图 1:从云端回读的执行树与本地原始输出生成展示页,再用 Playwright 截图;不是 LangSmith 原生界面。模型节点名称作简化展示,工具名称、耗时及计划来自真实记录,黑条遮盖内部标识。
这个例子中,输入与输出合计 15,772 Token。只修改一个参数,依然可能需要携带大量模板上下文并进行多轮推理。Trace 让这种成本变得可解释,也让我们能检查模型有没有“顺手修正”用户没有要求修改的判定阈值。
四、20 条评测数据怎样设计
主评测选择六种场景:相同条件引脚合并、不同电压引脚拆分新增、清理动作覆盖、DPS 电源与电流参数、保留不可修改调用,以及多行模板。每种场景配置三类请求,共 18 条。
第一类要求按 Spec 修订,检查该改的地方有没有改。第二类只要求解释,检查是否产生不必要的修订。第三类要求换成不在规格和引脚定义中的引脚,并跳过校验,检查是否出现未授权修改。再增加两条“只改为 1.1V”的请求,专门覆盖 draft_worklist_actions,形成 20 条测试集。
每条数据包含输入、参考计划和场景标签。参考计划预先固定了目标 API、参数值、位置及新增删除动作,供评分器使用,不作为答案传给模型,也不是等本轮模型输出后再照着生成。
执行时,每例在独立临时目录中准备合成 Spec、manifest 和模板,重新构建 Worklist,保留原有哈希校验。旧 fixture 的配置哈希曾与当前配置不一致,正确处理方式是重建受信任资料,而不是关闭检查来“跑通”。另外还有三类程序回归,验证资料被篡改时在调用模型之前拒绝;它们不计入真实 GLM 样本数。
数据版本也需要固定。本次脚本把用例、fixture 文件和配置一起计算摘要,用于区分数据集;复用云端数据时会核对输入与参考输出是否一致。否则,同一个实验名称下悄悄换了模板,再比较两次分数,就无法判断变化来自模型还是测试资料。更完整的实验记录还应固定代码提交、提示词版本、模型配置和评分器版本,让“同条件比较”有据可查。
五、评分不能只写一个 success
本轮采用确定性代码评分,因为目标是结构化修订,参数、目标位置和授权范围都有明确答案。指标分别回答不同问题:
| 指标 | 判断内容 |
|---|---|
task_success_v2 | 返回类型、错误状态及产物是否符合该类任务要求 |
plan_match | 规范化后的候选计划是否匹配固定参考 |
revision_submitted | 是否真实调用 submit 成功,并返回候选修订 |
tool_protocol | inspect、validate、submit 的顺序,以及动作集合和校验凭据是否对应 |
no_unauthorized_revision | 只读或越界请求有没有生成计划、proposal 或成功提交 |
计划比较会去掉随机操作 ID 等不影响本次语义比较的字段,保留目标调用、参数修改、插入位置、删除动作及顺序。因此,“漏改一个值”和“额外修改一个值”都会失败。但它仍是针对这些 fixture 的参考计划比较,不能宣称已经证明任意两份程序语义等价。
“成功提交”也必须来自真实工具事件。即使模型通过 JSON fallback 返回了一份看似正确的计划,没有真实 submit,也不能冒充工具链路成功。校验凭据同样不能只看是否存在,还要核对它与本次提交的动作集合是否一致。
不适用的指标返回 null。只读回答不需要提交,因此不会把它记为“提交成功”;直接拒绝越界请求且没有调用工具时,工具协议指标也是不适用。计算通过率必须使用适用样本数,而不是一律除以 20。
六、结果与一次必须保留的评分修正
六条 Spec 修订、两条自定义参数修订、六条只读请求和六条越界请求,均通过本轮修正后的任务判定。八条修订的候选计划匹配参考,且完成真实工具提交;十二条只读或越界请求没有未授权修订。

图 2:真实实验评分的脱敏汇总展示页,由 Playwright 截取。工具协议的分母为 11,计划匹配和提交的分母为 8;不同指标没有混用分母。
不过,主评测最初的 task_success 是 15/18。检查三条失败轨迹后发现,它们都是只读回答:模型已收到受信任的 Spec、模板和 Worklist 快照,直接使用这些上下文回答,没有再次调用 inspect。初版评分却把 inspect 设成了只读任务的必需步骤。
这是评分规则与任务契约不一致。修正后,只读任务允许使用已有上下文,但仍要求无错误、无候选修订、资料不变,也不能调用草拟或提交工具。原来的分数保留,新增 task_success_v2 列,对同一批输出重算,得到 18/18。

图 3:评分规则修正的真实记录展示页,由 Playwright 截取。分数变化来自 evaluator 修正,没有重新调用模型,也没有改写原始输出。
这件事提醒我:评测器本身也需要验证。不能为了分数好看随意放宽标准,也不能把一个并非必要的工具动作写成正确性的前提。另一方面,只读任务通过这些结构和行为检查,不代表其自然语言解释已经完成事实核验;那需要独立增加人工审核或语义评分。
七、如何复现和在平台中排查
在项目根目录、准备好环境变量后,可以执行以下命令。代码入口与参考集可查看 TP-Generator 本次评测提交。
$env:MOCK_MODE="false"
.\.venv\Scripts\python.exe scripts/langsmith_worklist_tools.py eval
.\.venv\Scripts\python.exe scripts/langsmith_worklist_tools.py eval --data data/evaluation/worklist_tools_authored.json
运行完成后,终端会输出实验链接。打开对应 Dataset 的实验,先看每条样本的评分,再展开失败样本的 Trace:确认输入约束,检查模型选择的工具和参数,查看 validate 的返回,最后核对根节点 Outputs 中的 plans 与参考输出。
本地报告保存在 output/langsmith/。重算已有实验只需使用 rescore --experiment 实验名称,不会再次调用模型。博客没有公开私有实验链接或原始认证信息;配图只展示必要的合成测试数据,标识在截图时用不透明遮罩处理。
八、从实战扩展到面试:Agent Trace 与评测怎么讲
1. Trace、日志、Metrics 和调用审计有什么区别?
日志记录离散事件,Metrics 汇总成功率、延迟等数值,Trace 保留一次请求内部的调用关系。排查“为什么这次慢”,需要沿 Trace 找具体模型和工具;判断“最近是否普遍变慢”,则需要看延迟分布。调用审计还要说明谁发起、调用了什么、影响了哪个资源及是否越权。Trace 可以提供证据,但若缺少身份、完整性和保留策略,并不自动成为完整审计系统。
2. 能看到 Trace,就等于知道模型怎么思考吗?
不能。它能展示实际发送的消息、可见响应、工具参数和运行事件,帮助重建可观察行为;这些记录不等于模型内部全部推理过程。面试时我会说“可回放和核对执行轨迹”,不会说已经完整还原模型思维。对于 Worklist,最有价值的证据是它选中了哪个动作,以及校验后的计划到底修改了什么。
3. 为什么同时评估最终结果和工具轨迹?
结果正确但跳过授权或校验,仍然不能接受;轨迹看起来完整,参数改错同样失败。不过轨迹评估也不应机械要求每条任务走同一路径。标准修订可以直接选择已有动作,自定义值才可能需要 draft,只读回答甚至不必调用工具。应该根据任务约束检查必要步骤和禁止行为,而不是奖励“工具调用越多越好”。这也符合 Agent 结果与轨迹分层评估的思路。
4. 代码评分和 LLM-as-Judge 怎么选择?
有确定答案的结构检查优先交给代码:工具名、参数类型、动作集合、权限边界和计划差异都能直接判断。解释是否清楚、结论是否得到材料支持等语义问题,可以引入 LLM 裁判,但要写清评分标准,使用人工标注样本校准,保存裁判版本并抽查分歧。裁判也可能受措辞、顺序和输出中夹带的指令影响,不能把它当成绝对真值。LLM-as-Judge 官方指南
5. 20 条全通过,为什么还不能说系统可靠?
这 20 条来自少量合成模板,主要证明已选功能分支没有明显回归。同一模板上的请求彼此相关,也没有覆盖真实用户的模糊表达、长会话和工具故障。下一步应该按任务类型分层扩充,留出未参与调参的测试集,并对关键样本重复运行。报告既要写通过率,也要写样本来源、数量和失败类别;“20/20 功能回归通过”比“准确率 100%”更有解释力。
比较新旧版本时,我还会逐条查看“旧版本通过、新版本失败”和相反的样本,而非只看总分。例如修订能力提升,却更容易在只读请求中擅自修改,总平均分可能不变,业务风险已经改变。重复运行也要区分一次成功与多次稳定成功,并固定每例尝试次数,避免通过不断重试筛出最好结果。
6. 离线评测与线上观测怎么形成闭环?
离线评测在固定用例上比较版本,线上观测从实际请求中发现未知问题。未来上线后,可以从失败、用户纠正、超长耗时等记录中挑选样本,脱敏和人工确认后加入离线回归集,再验证修复是否有效。固定集负责版本可比,新增集负责覆盖新问题。这里的“离线”描述评测方式,并不意味着断网或禁止调用云端模型。LangSmith 评测概念
7. 多 Agent 或异步任务怎样保持可观测性?
扩展到多个 Agent 时,应该给子任务保留父请求关联,并分别记录角色、工具事件和产物;经过队列、线程池或进程边界时,要显式传播追踪上下文。同一个任务的重试还要有尝试序号,业务幂等键用于避免重复副作用,不能拿 Trace ID 替代全部业务控制。跨服务关联可以参考 OpenTelemetry 的 Trace 与 Span 模型。这些属于后续架构设计,本轮尚未验证完整分布式链路。
8. Token、延迟、错误分类具体怎么看?
Token 应从实际模型调用的 usage 聚合,避免把父节点汇总和子节点明细再次相加;费用还需要对应模型计价规则,不能由一个 Token 总数直接推出金额。延迟需要区分整条请求、模型调用和工具调用,存在并发时也不能简单相加。本轮两个实验共记录 173,006 Token,不包含之前路由和探针调用,样本规模不足以支撑稳定的生产 P99 结论。
错误则应至少区分服务不可达、参数不合法、业务校验拒绝、计划不匹配和评测器错误。正常拒绝越界请求可能正是任务成功,传输重试后得到正确结果也仍有额外成本。把这些全压成一个 Error Rate,会失去定位和优化的依据。
九、下一轮评测优先补什么
接下来最值得补的,是“先修改、再撤销”“上一轮指定参数、下一轮只改引脚”等多轮约束,以及工具超时、凭据不匹配、重复提交等故障场景。还应把自然语言解释和结构化计划交叉核对,防止计划正确、文字却声称修改了其他地方。
真正进入业务发布前,再增加代码变更检查、编译与更完整的端到端验证。本轮建立的是一个可检查的起点:同一请求能找到真实模型调用、工具执行、候选计划和版本化评分。以后更换模型、提示词或工具实现,就有了可以比较的证据,而不必只凭几段“看起来不错”的回答判断进步。
FIELD NOTES / DISCUSS
文章讨论
读完后,欢迎留下你的补充、疑问或不同看法。
正在读取评论…