☰
Tracelane 拆解:AI Agent 轨迹的防篡改账本如何做到离线验真
2026/10/2 6:50:06 网站建设 项目流程

审计员要的那份证据

审计员在银行里问的不是 Agent 跑没跑,而是记录能不能被改。

一份普通日志满足不了这个问题,因为它可以随时被覆盖。

SOC2 审计要的是 tamper-evident,也就是动过手就看得出来。

Tracelane 把自己定位成 AI Agent 的飞行记录器。

它蹲在 Agent 和模型供应商之间,所有流量都过它这一道。

每条事件按租户串成哈希链,再批量锚定到一份公开透明日志。

验真可以用 tlane verify 完全离线重跑,不回调 Tracelane。

这正是审计员愿意签字的那一类证据。

它的作者是 Sanjeev,一个人做了六个多月。

他之前在 BFSI 干过,见过审计员要 tamper-evident 而不是日志。

所以这条产品的骨头,是从证据可信往回倒推工程。

这一点决定了它和 LiteLLM、Portkey 这类网关的取舍不同。

后者优先做路由和成本,它优先做可验真。

Apache 2.0 开源,仓库在 github.com/tracelane/tracelane。

下面拆它怎么把离线可验真做成一个能落地的工程。

重点不是功能清单,而是几处能看出取舍的设计。

先看账本本身,再看它老实写下的边界。

然后是护栏的观察优先,和 2 毫秒热路径。

最后是一段可跑的验真代码。

合规场景里,日志和证据是两个词。

日志告诉你发生了什么,但不保证没被改。

证据要求任何篡改都能被发现,哪怕改的人是管理员。

Tracelane 的账本设计就是冲着这条来的。

它不依赖你信任它的服务器,信任建立在哈希链上。

这是密码学担保,不是服务条款担保。

所以哪怕你自托管,验真逻辑也跑在你自己机器上。

这一点是它和托管观测平台最硬的区别。

后者要你相信它不会改后台数据,这里不用信。

代价是你得自己管好导出的链文件。

哈希链与透明日志的咬合

账本的核心是前一条的哈希喂给下一条。

这样任意一处改动,会让后面所有哈希对不上。

这是区块链以外很老的技术,叫哈希链。

Tracelane 按租户分链,每个租户有自己的序号序列。

事件落库时算哈希,存进 ClickHouse 的 audit_log 表。

托管版把权威账本放在 Postgres,再复制一份到 ClickHouse。

这是为了兼顾事务一致性和分析查询的吞吐。

但光有哈希链还不够,因为它只能证明内部没断。

一个能改库的管理员仍可以在重写时把整条链重算。

要防这一手,得把链头定期锚定到外部不可改的地方。

这就是批量锚定到公开透明日志的那一步。

锚定后,哪怕管理员重算内部链,也对不上外部锚点。

这是从 Merkle tree 到 Certificate Transparency 的老套路。

Tracelane 把它接到 Agent 轨迹上,是工程拼装不是新密码学。

验真器叫 tlane verify,从导出文件就能重算整条链。

它不向 Tracelane 发任何请求,纯本地校验。

这是审计员能把它带走、离线复核的关键。

最妙的工程是验真器被实现了三遍。

Rust 一份,Python 一份,TypeScript 一份。

三份都对着同一组 8 个一致性测试向量跑。

这 8 个向量里有故意伪造的,也有边界数值的。

CI 里跑 10 个 Rust、14 个 Python、19 个 TypeScript 测试。

还有一个 round-trip 任务,断言三份实现结果一致。

这种多语言对照,防的是单份实现的 bug 骗过审计。

因为验真器是审计员唯一信任的代码,它不能有暗坑。

仓库 evals 目录里另有 20 个一致性评测。

10 个容错、7 个网关正确性,加 ingest-schema、脱敏、注入各一。

作者还老实说,有些内部测试针对私有 ADR,没放进仓库。

test 脚本会直接告诉你这一点,而不是假装全绿。

这种诚实本身就是审计可信度的一部分。

账本的强度,等于它愿意公开的弱点。

下一节就看它公开了哪些边界。

老实写下的边界

自托管的人最该先读的一段,是账本的边界。

自托管不带 Postgres 控制面,只有 ClickHouse 里的链。

它能在一次网关生命周期内验真,这是测过的。

作者实测四次聊天请求,产出八条链接行,零断链。

但重启之后,链头本来是从 Postgres 控制面恢复的。

自托管没有 Postgres,所以重启后序号从 genesis 重新开始。

结果会出现重复的 seq 值,离线验真器跨不过这个边界。

换句话说,自托管的账本是按段可验真,不是跨重启连续可验真。

要跨重启一条连续可验真的链,今天只能上 Tracelane Cloud。

作者把这条写成正文,而不是等你自己在验真器输出里发现。

这是这种产品最值钱的态度。

还有几条同样写在前面的边界。

它没有 SOC2 报告,没有可配置的数据驻留。

没有 HIPAA 或 BAA,没有文档化的 SAML 单点登录。

没有合同级 SLA,也没有文档化的 Slack、PagerDuty 告警集成。

这些都列为还没有,不是被你挖出来的缺口。

预测层的几个能力也老实标了今天不开火。

浏览器卡死循环预测、A2UI 目录一致性门禁,都还没触发。

因为它们要的字段,/v1/chat/completions 请求里根本不带。

蒸馏出来的 SLM 判官也没启用,因为没有训练好的模型随仓库发。

所以这些预测护栏今天对 LLM 流量零影响。

作者把没开火和为什么没开火一起讲清楚。

这避免了你把它当防御层用,结果发现它根本没拦。

crates/policy 里有个 Cedar 策略引擎的脚手架,V1 没接上。

这也是写明的,不是藏着的。

仓库本身有个透明声明,它是从另一棵开发树发布出来的。

main 上的提交是压缩发布,没有分支保护,没有可审查的评审历史。

作者的忠告是,判代码和发版,别判提交图。

对一个要审计可信的产品,这种坦白反而加分。

护栏为什么先观察再说话

Tracelane 的护栏默认是观察优先,不是拦截优先。

成本、schema、提示注入这三条护栏都在请求里跑。

但它们的默认动作是记录加标记,而不是把请求挡回去。

原因是误报拦截会直接打断一次合法的 Agent 运行。

对一个跑长任务的 Agent,一次误杀可能毁掉几十步。

所以先观察、积累、回头复盘,比先拦更稳。

这是和安全网关必须拦很不一样的设计观。

它的潜台词是,护栏是给运维看的信号,不是死锁。

需要拦的时候,你自己加规则,它把数据备好。

两条最有意思的护栏,是 MCP 工具定义锁定和致命三角检测。

这两条免费给所有档位,包括 OSS 自托管。

工具定义锁定,把你批准过的工具定义算一个哈希存下。

运行时拿实时定义和这个哈希比,不一致就标记。

防的是工具定义被悄悄改了,Agent 还在用旧授权跑。

这种漂移在 MCP 生态里是真实风险,不是理论风险。

致命三角检测,盯的是三个条件同时出现。

非可信输入,加上私有数据,再加上外传路径。

三个凑齐,才标记为高风险组合。

单看任何一个都不一定有问题,凑齐才是问题。

这比单条规则拦更准,因为它看的是组合。

这两条护栏也都遵守观察优先,先标不先拦。

ML 集成在路线图上,今天跑的是启发式。

启发式的好处是可解释、可审计、没有模型幻觉。

坏处是抓不到复杂模式,所以才要补 ML。

但作者没把没训好的模型塞进来充数。

这和上一节的没开火就说没开火,是一致的态度。

PII 脱敏器接在审计和护栏两条路径上。

所以落库的轨迹里,敏感字段在写盘前就脱了。

这降低了账本本身成为合规负债的风险。

crates/policy 里还有个 Cedar 策略引擎脚手架。

V1 没接,留给你按自己的策略补。

2 毫秒热路径是怎么省出来的

可验真和护栏都得过一道关,网关本身不能慢。

加一层代理就意味着每条请求多一段延迟。

Tracelane 把热路径用 Rust 写,框架是 Axum 加 tokio。

它做 BYOK 路由,把请求转发到你带 key 的191家供应商。

0% 加价,你的 key 就是你的成本。

在 LiteLLM 的 AIGatewayBench 上实测,加了2 毫秒 p50。

p95 是 4 毫秒,p99 是 5 毫秒,采集开着。

测试条件是 4 vCPU,跑了两轮,公平对比。

同场测的 LiteLLM Python 代理是 14 到 15 毫秒。

Portkey 同场是 3 到 4 毫秒。

Langfuse 和 LangSmith 没有网关,不进这张表。

Rust 热路径是它压低延迟的主因,不是魔法。

采集默认全保真,不需要你去关采样。

这是它和很多观测平台不一样的地方。

后者默认采样,你得手动调高才看得到全貌。

它反过来,默认全收,再加单条轨迹上限兜底。

上限是一万 spans 或 64 兆,环境变量可调。

超出只裁这一条轨迹,不伤你其余的轨迹。

这防的是一个失控 Agent 撑爆你的存储。

采集后走 NATS JetStream 传给 ingest worker。

worker 批量写 ClickHouse 热层。

冷层是 Cloudflare R2,还在路线图上。

托管的权威账本在 Postgres,再复制到 ClickHouse。

自托管只有 ClickHouse 链,上一节讲过它的边界。

架构图很直白,Agent 到网关,网关到 NATS,NATS 到 ingest。

ingest 分两路写 ClickHouse 和将来的 R2。

没有仪表盘容器,自托管是 headless 的。

Web UI 今天只有托管版有。

这是它在自托管完整度上最显眼的一刀。

对照表能看出它和同类各自的取舍:

维度TracelaneLiteLLMPortkeyLangfuse
网关 p50 开销2 ms部分(14-15 ms)3-4 ms无网关
Rust 热路径有无无无
BYOK 零加价有有有无
防篡改账本离线验真有无无无
MCP traces 服务有无无无
自托管单 compose有有有有
许可证Apache 2.0MITMITMIT

这张表里 Tracelane 唯一独占的,是离线可验真的账本。

LiteLLM 路由和成本更强,它可验真更强。

选哪个,取决于你要解决的是哪一头的问题。

它不是要替掉谁,而是补上一块别人没有的板。

一段可跑的验真

说再多不如跑一次,给一段能直接跑的。

先是托管的接法,三行就能让 Agent 发 spans。

init 指定网关地址和 key,key 要有 ingest 权限。

然后包一下你的 Anthropic 客户端就行。

它不 monkey-patch,得显式包每个客户端。

这点有人嫌烦,但它换来了没有隐式副作用。

TypeScript 端是对称的 instrumentOpenAI。

# 托管:三行让 Agent 发 OTel spans export TRACELANE_API_KEY=tlane_... export TRACELANE_GATEWAY_URL=https://gateway.tracelane.dev
from tracelane import init, instrument_anthropic from anthropic import Anthropic init(endpoint="https://gateway.tracelane.dev", api_key="tlane_...") client = Anthropic() instrument_anthropic(client) # 现在 messages.create() 会向网关发出 spans
# 自托管:一把起整套,再离线验真 docker compose -f infra/self-host/docker-compose.yml up -d set -a; source infra/self-host/.env; set +a export TRACELANE_GATEWAY_URL=http://localhost:8080 export TRACELANE_API_KEY="$TRACELANE_MASTER_KEY" tlane verify # 从导出的链文件本地重算,不回调任何远端

自托管的话,compose 一把起整套。

infra/self-host/docker-compose.yml up 就行。

两个 key 必须在 .env 里设好。

一个是 TRACELANE_MASTER_KEY,用 openssl rand 生成。

一个是供应商 key,比如 ANTHROPIC_API_KEY。

不设供应商 key,网关能起,但每个请求都 401。

还有个坑,.env 里设的变量不会自动进 shell。

得 set -a 加 source 加 set +a 才能带进去。

否则你以为设了,其实 shell 里是空,第一个请求就 401。

这是文档里专门写出来的坑,照抄能少踩。

网关在 :8080,把 TRACELANE_GATEWAY_URL 指过去。

验真用 tlane verify,喂它导出的链文件。

它本地重算,不回调任何远端。

网关是 OpenAI 路径兼容的,打 /v1/chat/completions。

请求体用 Anthropic 的工具 schema。

两种工具形状它都接,归一成一个内部表示,不改写请求。

从 LiteLLM 迁移有现成导入器,一行转配置。

从 Helicone 迁移改 base URL 和 auth 头,不用重导轨迹。

发版是 cosign 签的,keyless OIDC,可验 provenance。

每个版本带 CycloneDX SBOM,CI 用 Grype 加 Syft 加 OSV-Scanner。

作者说,判这东西,看代码和发版,别看提交图。

这是给审计员的最后一句忠告。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询