您部署了一个 AI 代理。它调用工具,读取结果,再调用更多工具,给出答案。大多数时候它能正常工作。然后用户报告出了问题,您打开追踪,发现了它:charge_card 工具返回了 402,而代理只是……继续前进,并告诉客户他们的订单已发货。
这不是指“编造事实”意义上的幻觉。这是运行中的一个 结构性 缺陷——被忽略的工具错误。而关于结构性缺陷的关键在于:您不需要另一个 LLM 来发现它们。 通过查看追踪可以判定它们。
这就是 tracelint 的全部前提:它是代理运行的 linter。它读取执行追踪——代理 实际做了什么——并以确定性的方式标记结构性错误,以确切的追踪行作为证据并返回 CI 退出码。它在运行之后、在追踪上运行,而不是在您的代码上运行。永不需要第二个模型来判断它。
因为对于这类错误,评判器是错误的工具。已发表的追踪错误基准显示,LLM 评判器的定位准确率较低——它们只会告诉您“似乎有问题”,而不会可靠地指出是 哪一步 出错。它们还具有非确定性、每条追踪会产生费用,并且无法用于 CI 阻塞(您会因为一次掷硬币而让构建失败吗?)。
与此同时,一类代理错误是 可结构性判定的:
这些都不需要模型。它们需要追踪和验证器。这就是 tracelint 所做的。
pip install tracelint
tracelint demo --html demo.html
demo 运行无密钥验证套件 — — 每种缺陷植入一个实例,加上干净的对照 — — 并生成 HTML 报告。无需 API 密钥,无需下载模型。
要在真实追踪上对 CI 进行门禁:
tracelint check ./trace.json --tools ./tools.json # exit 2 on a structural defect
退出码:0 干净,2 结构上可证明的缺陷,3 输入错误。启发式发现不会自行导致 CI 失败。
这是分布洞察。您可能已经在为您的代理添加仪器 — 与 OpenInference (OpenTelemetry 语义约定,用于 AI),向 Arize Phoenix、Langfuse 或 OTel 收集器提供数据。tracelint 直接读取该遥测数据。您不需要学习新的追踪格式;您只需将其指向您已有的跨度。
tracelint check spans.json --format openinference # Phoenix, OTLP, TRAIL
tracelint check trace.json --format langfuse
tracelint check messages.json --format openai
或者直接从正在运行的 Phoenix 实例中,在 Python 中:
import phoenix as px
from tracelint import lint_otel_trace
spans = px.Client().get_spans_dataframe().to_dict("records")
report = lint_otel_trace(spans)
print(report.exit_code) # 0 or 2
for f in report.active_findings:
print(f.rule, f.tier.value, f.summary)
我根据真实的 OpenInference 导出进行了验证,而不仅仅是手工构建的 fixtures — 一个真实的 Phoenix trace,一个 OTel-SDK span 导出,以及 Phoenix dataframe 的形状。在一个真实的 Phoenix trace 上,tracelint 的确定性地定位到了一个真实的工具故障:
[hard_event] R2a tool_error_event (step 9)
'add_spans_to_dataset' returned an error (GraphQL query 'exampleMutation' ... 'an unexpected error occurred')
循环中没有模型。只是:此 TOOL span 具有 ERROR 状态,恰好在此步骤,这里是消息。
| 规则 | 发现 |
|---|---|
| R1 | 模式违规 — 参数未通过工具的 JSON Schema |
| R2 | 工具返回了错误 / 后来的副作用调用重用了一个出错的值 |
| R3 | 幻觉参数 — 值无法从任何观察到的东西推导出来 |
| R4 | 循环 — N 次完全相同且无进展的调用 |
| R5 | 冗余调用 — 完全相同的调用 + 完全相同的结果,中间没有变化 |
| R6 | 参数格式错误 — 工具调用的参数不是有效的 JSON |
| R7 | 未知工具 — 对未在声明的工具集中出现的工具的调用 |
这是通过 OpenInference 适配器运行的卡住循环示例:
[candidate] R4 loop (step 2,4,6)
'search' called 3 times in a row with identical arguments and no change in result state (ok)
[candidate] R5 redundant_call (step 2,6)
'search' repeats an earlier identical call with no mutating call in between
1. 候选,而非裁决。 只有结构上可证明的事项(模式违规,格式错误的 JSON)是导致 CI 失败的硬性缺陷。启发式信号 — 循环,冗余调用,可疑参数 — 会被显示为 带有证据的候选项,供人工审查,从不被断定为真理,并且它们自身不会导致你的构建失败。重试循环和卡住的循环在结构上看起来相似;tracelint 会向你展示证据并让你决定,而不是假装它知道。
2. 它告诉你它不能检查什么。 这是我最关心的一点。如果追踪中缺少规则所需的字段 — — 没有工具模式,也没有结果负载 — — 该规则不会静默通过。它给出理由并抑制,在报告中打印出来:
suppressed (2) — not checked, not a clean pass:
R1 schema_violation: no tool schema available for any called tool
R7 unknown_tool: no tool registry supplied — cannot know which tools were declared
一个看似干净却隐藏漏洞的报告比没有报告更糟——这是虚假的自信。tracelint 拒绝给你这种感觉。
pip install tracelint
tracelint demo --html demo.html
它是开源的(MIT),依赖轻量(jsonschema + 标准库),支持 Python 3.10–3.12,整个测试套件是离线且确定性的。
如果您正在收集代理追踪并希望对其进行确定性检查,我真的很想知道您的实际导出中会出现什么问题——这就是最近三个真实世界形状修复发生的方式。欢迎提交问题和追踪。
——
一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。