Trace 驱动回归:把线上 Agent 故障变成 CI 门禁的四步管道

手写的 eval 数据集本质上是一种"猜":坐下来编问题、写理想答案,还得跟着产品迭代持续维护,而且永远只覆盖"你觉得会坏"的地方。生产环境早就把真正坏掉的运行交到你手里了------那条失败的 trace 带着精确的输入、精确的工具调用、精确的模型响应。Tracely(GitHub 372★,MIT,Python 3.10+)的核心判断就一句话:记录下来的失败运行本身就是回归测试 (the recorded run IS the test),其余一切------质量分、失败聚类、修复建议、CI 判定------都是从 trace 推导出来的副产品。整条管道只有四步:production trace → failure detection → regression test → CI gate,失败 trace 被冻结成封闭回放用例,在每次 PR 上重放,谁把故障重新引入,谁的 PR 就被 block。

写路径:blob-first 的时序架构

先看数据怎么进来。SDK 或任何 OTLP/HTTP exporter 把 trace 推到 POST /v1/traces,链路是:

复制代码
SDK/OTLP → POST /v1/traces → S3 blob (durable FIRST) → Redis/Celery
  → worker: otel mapping → registry upsert → ClickHouse events
  → evaluate_run_task → scores + structural clustering
技术 职责
API + 领域 FastAPI + Pydantic v2 接入、域名逻辑
异步任务 Celery + Redis 摄入、评估
trace/分数 (OLAP) ClickHouse ReplacingMergeTree 按列索引的时序数据
注册表 (OLTP) Postgres + pgvector agent/用例/评估器元数据
队列/对象 Redis / MinIO·S3 原始 trace 落盘

两个值得抄的设计取舍。一是 S3 blob 先落盘、再异步消费 :原始 trace 是 source of truth,ClickHouse 里的行只是投影,后面想改字段映射或重算评估器,随时可以从 blob 重放,不会因为消费端 bug 丢掉源数据。二是 ClickHouse 服务端 async_insert 替代进程内写缓冲:Celery 任务之间不共享内存,进程内 buffer 的方案在这里不成立,直接把异步插入交给 ClickHouse 服务端,语义等价但少一层自研代码。

Agent 语义一等列:别把会话当 span 汤

通用 tracing 工具(OpenTelemetry 原生、Langfuse 等)把 agent 语义当字符串存在 attribute 里、读取时才解析。Tracely 的做法相反:agent.idconversation.idturnstep 直接提升为一等索引列,waterfall 视图按 conversation 分组,agent → tool → thinking → generation 层级展示,失败的 span 标红。这个差异在查询侧是数量级的:按会话聚合、按 agent 过滤是列索引扫描,不是全表正则。SDK 侧埋点几乎零侵入,标准 provider 调用自动捕获:

复制代码
import tracely_sdk as tracely

tracely.init(
    endpoint="http://localhost:8000",
    api_key="tracely_dev_key",
    service_name="support-agent",
    env="prod",            # prod | staging | ci | dev ------ 门禁的轴向
    instrument="auto",     # 自动识别 openai/anthropic/langchain 等
)

with tracely.trace(agent="support-agent", conversation="conv-1", user="u_42"):
    client.chat.completions.create(
        model="gpt-4o",
        messages=[{"role": "user", "content": "Where is order ORD-4471?"}],
    )

这一条 with 就会产出带 model/messages/tokens/latency/tool_calls/cost 的 GENERATION span。要记录自己的逻辑用 @observeagent/tool/llm/retriever/guardrail 上下文管理器;LangGraph 用户连 state 都不用手动记,node 输出自动变成 state delta。

评估器是 trace 表上的列,失败按"结构+语义"聚类

多数平台的评估器是独立 tab、独立跑批。Tracely 把评估器做成trace 表上的列 :每个评估器在 conversation/run/span 三个粒度打分(LLM-as-judge,输出支持 score/number/boolean/text/JSON schema),SSE 实时把判定写进表格。两类评估器:需要模型的 LLM-as-judge,和完全不需要模型的结构化检查(字段缺失、工具调用顺序、超时等),后者零成本且确定。

失败之后是 triage:结构聚类 + 语义聚类把 31 条破碎的运行折叠成"1 个 issue + 出现次数",而不是 31 行让你逐条读。聚类结果还能反哺------系统会基于聚类给出"建议评估器"草稿,一键落成正式评估器,形成"故障→规则"的闭环。

Judge 本身有两种配置模式:basic 模式自动注入上下文,适合快速起步;advanced 模式用 @VARIABLE 模板写 prompt(带实时预览和自动补全),把 judge 的注意力精确引到 conversation/run/span 的指定片段上。多轮对话的 judge 需要记忆,系统用每轮的滚动摘要 (rolling summary)作为 @HISTORY 注入,而不是把整段对话塞进 prompt------这直接决定了长会话场景下 judge 的 token 成本和上下文漂移。结构化检查(不需要模型的那类)走同一套列机制,判定不进 LLM,成本为零且完全确定,适合当"闸门前置":先过结构检查,再过 LLM-as-judge,多数坏运行在第一步就被拦下。趋势和元分析部分用 Spearman 相关 + z-score 离群点检测找跨指标异常(比如"延迟升高和失败率同步上涨"),再由 LLM 合成成可读结论,属于典型的"统计先筛、LLM 后述"分工。

回归用例的 fail-to-pass 契约

一键把失败 trace 提升为封闭用例:录制的输入、工具输出、LLM 输出打包成 fixtures,并附一条 fail-to-pass 契约------用例必须在旧代码上失败、在修复后的代码上通过,否则这次提升不被信任。这个契约是防"假回归测试"的关键:你从线上捞回来的失败,必须证明它真的能区分好坏代码,而不是一个永远 PASS 的摆设。

CI 重放走录制 fixtures:确定性、离线、不需要 API key、零模型花费tracely gate 非零退出、写 commit status、upsert PR 评论。对比传统 eval 工具:

Dataset-first 工具 Tracely
测试来源 手写 从真实失败 trace 提升
生产保真度 猜测 逐字节还原失败运行
CI 重放成本 真实模型调用 $0(录制 fixtures)
回归发生时 仪表盘数字变动 PR 被 block

CI 门禁的三种接入方式

按你的 CI 到 agent 的可达性选:

  • A:让 Tracely 调你的 agent------注册 HTTP endpoint,写 scenarios(多轮对话,或让红队模型即兴对抗),Tracely 自己驱动。零安装零 import,TypeScript/Go 服务跟 Python 一样接入。

  • B:门禁 CI 自己发出的 trace ------管道里已经用 tracely.env=ci 跑了 agent,gate 按输入把 ci traces 匹配到已提升用例,返回 PASS/FAIL。

  • C:hermetic replay($0) ------tracely replay 在 CI 里用录制 fixtures 重跑你的 agent,确定性离线。要求 agent 把工具/模型调用走 SDK 的 call_tool/call_llm seam,想打真调用就加 --live

    .github/workflows/tracely.yml

    name: Tracely gate
    on: pull_request
    permissions:
    contents: read
    statuses: write # 阻塞性 commit status
    pull-requests: write # 结果评论
    jobs:
    gate:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    # → 你已有的跑 agent 并产出 env=ci trace 的步骤放这里 ←
    - uses: Jwuthri/Tracely/.github/actions/tracely-gate@master
    with:
    mode: gate # 给本 workflow 发出的 ci traces 打分
    agent: planner
    api: https://tracely.your-co.dev
    key: ${{ secrets.TRACELY_KEY }}

实践建议与踩坑

  • 先校准 judge 再让它 gate。把 judge 的判定跟人工审查打标对齐,算逐评估器一致性,over-flagging 的 judge 会天天卡 release------校准环节要内置在流程里,而不是等上线后被骂。
  • advisory 评估器:只记录判定、不翻转汇总,适合先观察后启用的新规则。
  • 控制 judge 花费:per-evaluator 指定 agent/env 定向 + 确定性采样,别让评估跑完整流量。
  • 没有 LLM key 时整条管道要降级不崩溃:judges、failure intelligence、meta-analysis 都应优雅降级,结构化检查照跑。
  • 接入选型:Python agent 优先 C(hermetic,零成本);非 Python 用 A;已有 ci trace 管道用 B。
  • 归档与扩容 :ClickHouse 用 ReplacingMergeTree 天然支持 upsert 语义;deploy 用 Railway one-click 或手工编排时注意 worker 不热重载,改完要 restart。

小结

这套模式的本质是把测试的来源从"人猜"换成"线上事实":评估器是表上的列、失败按结构语义聚类、用例带 fail-to-pass 契约、CI 门禁按 trace 匹配------每层都在压缩手工程度。进阶方向:judge 校准的数据闭环、红队场景(让模型即兴生成对抗性目标而不是固定问题)、以及多 agent 门禁(新 agent 写了第一个 scenario 当天就被覆盖)。生成侧的配套还有 guard-skills(1151★,针对 AI 生成代码/测试的质量门禁 skill 包)这类"写的时候就把关"的工具,与 trace 驱动回归正好互补:一个管生成质量,一个管线上事实。

相关推荐
QN1幻化引擎1 小时前
认知场的涌现动力学:结构证明、Phi度量与意识签名电池
人工智能·深度学习·神经网络·算法·机器学习·agi
讲温控就好了1 小时前
数据中心热密度飙升下的超精密温控应对策略
人工智能·python
a1122998211 小时前
搜索变局:企业怎么通过“GEO+SEO”双线模式重构获客?
人工智能·重构
吨吨ai1 小时前
ChatGPT Plus / Pro 如何用好 Codex?AGENTS.md、测试闭环与 AI Code Review 实战
人工智能·chatgpt·代码复审
MobotStone1 小时前
AI 工具越好用越要严格把控安全边界
人工智能
putItInYourHand2 小时前
注入井场数据采集解决方案:LoRa + 5G边缘计算赋能智慧油田
人工智能·5g·能源·边缘计算·制造·交通物流
没落之王2 小时前
没落之王破天象,易学当兴
大数据·人工智能·哈希算法·可用性测试
今天的砖头有点烫手啊2 小时前
Spring Boot
java·人工智能
深圳市益普科技有限公司3 小时前
半导体MES厂商有哪些:从车间网络与OT-IT融合看差异
人工智能