返回博客列表

ATIF 与 OpenTelemetry:Agent 轨迹的两种打开方式

2026-10-08T09:30:00+08:00
AI AgentOpenTelemetryObservabilityHarborLLM

想复现一次 Agent 的失败现场,你会先翻什么?终端里滚走的输出、Agent 自己那份格式私有 .jsonl 会话文件、还是某个平台后台里的 trace 列表?在评测场景里这个问题更尖锐:换一个 Agent 跑同一批任务,日志格式就换一套方言,可视化、训练管线、故障排查全部要重写解析器。

Harbor Framework——一个在容器化环境里评测和优化 Agent 与模型的开源框架——给出的答案是两件套:一份标准化的轨迹文件 ATIF,加一条通往 OpenTelemetry 的官方转换管道。一个负责"完整记录",一个负责"接入生态"。这篇文章把这两块拼图拆开看。

本文大纲:

  1. ATIF 是什么:给 Agent 轨迹立的 JSON 标准
  2. 走读 trajectory.json:从字段到版本演进
  3. 原生轨迹 vs ATIF:可移植性的分界线
  4. atif2otel:把轨迹变成 OpenTelemetry spans
  5. 生态汇流:NVIDIA 的三步棋
  6. 分工,而不是取代

ATIF 是什么:给 Agent 轨迹立的 JSON 标准

ATIF(Agent Trajectory Interchange Format)是 Harbor 的 RFC 0001 定义的一套 JSON 规范,用来记录一个 Agent 的完整交互历史:用户消息、Agent 的推理、工具调用、环境观察结果,以及每一步和整趟的 metrics。

它的动机写在 RFC 开头:现有的 Agent 日志各说各话——对话式日志、显式动作序列(如 MiniSweAgent 的做法)、可回放的数据结构(如 OpenHands 的做法)——每一条下游链路(查看器、数据集、SFT/RL 训练管线)都得为每种 Agent 写一个解析器。ATIF 想要的是一个稳定表示,让采集下来的数据立刻可用于调试、可视化、监督微调和强化学习。

在 Harbor 的运行结果里,这份文件通常就叫 trajectory.json,落在试验结果的 agent/ 目录下。声明了 capabilities.atif = true 的 Agent 会自动往自己的日志目录写它,Harbor 用它做两件事:渲染——本地结果查看器的 Trajectory 标签页直接读它展示每一步;加载——用它去 seed 一个新会话。

走读 trajectory.json:从字段到版本演进

一份最小但完整的 ATIF 轨迹长这样(当前格式 ATIF-v1.7):

{
  "schema_version": "ATIF-v1.7",
  "session_id": "session-123",
  "agent": {
    "name": "my-agent",
    "version": "1.0.0",
    "model_name": "openai/gpt-5.6-sol"
  },
  "steps": [
    {
      "step_id": 1,
      "source": "user",
      "message": "Create hello.txt."
    },
    {
      "step_id": 2,
      "source": "agent",
      "message": "I'll create it.",
      "tool_calls": [
        {
          "tool_call_id": "call-1",
          "function_name": "write_file",
          "arguments": {"path": "hello.txt", "content": "Hello"}
        }
      ],
      "observation": {
        "results": [
          {"source_call_id": "call-1", "content": "File created"}
        ]
      }
    }
  ]
}

根级字段里,agent 描述产生轨迹的系统(名称、版本、默认模型,可选带上完整的 tool_definitions);steps 是按序交互,step_id 从 1 开始严格连续;Agent 步骤里的 tool_calls 与 observation.results 通过 source_call_id 配对;可选的 final_metrics 汇总全程的 token、成本和步数;subagent_trajectories 则能把子 Agent 的完整轨迹嵌进同一个文件。

几个版本演进的节点很能说明这套格式的野心:

版本 增加了什么 为谁服务
v1.3 / v1.4 completion_token_ids / prompt_token_ids RL 训练:存下真实送进 LLM 的 token,避免重分词漂移
v1.5 tool_definitions SFT:让训练管线拿到完整的函数签名与文档
v1.6 图片多模态内容 多模态轨迹
v1.7 子轨迹嵌入、trajectory_id、llm_call_count 多 Agent 工作流单文件存档
v1.8(RFC) 音频 ContentPart 语音输入型轨迹

注意 v1.7 的子 Agent 语义是 NVIDIA 工程师贡献的——这个伏笔在第五节会再次出现。Harbor 为格式配了 Pydantic 模型(harbor.models.trajectories)和一个校验器,检查 schema、step ID 连续性、tool-call 引用、时间戳甚至引用的本地图片文件:

uv run python -m harbor.utils.trajectory_validator path/to/trajectory.json

原生轨迹 vs ATIF:可移植性的分界线

Harbor 支持两种轨迹加载,分界线很清晰:

  • 原生轨迹是 Agent 私有的会话文件——claude-code 的在 agent/sessions/projects/-app/<session-id>.jsonl,codex 的在按日期组织的 rollout-*.jsonl。加载无损,但只能喂回同一个 Agent。
  • ATIF 轨迹是可移植的中间格式。加载时 Harbor 把它转换成目标 Agent 的原生格式,保留消息、工具调用和工具结果——意味着 claude-code 跑出来的轨迹可以拿来 seed 一次 codex 会话。转换不承诺无损,Agent 特有的细节、系统消息和非文本内容可能被省略。

两种能力分开声明:写 ATIF 是 capabilities.atif,加载原生和加载 ATIF 各有独立的 capability 开关。目前 claude-code 和 codex 已同时支持两种加载。这套设计的实际价值在于:评测基建终于可以把"轨迹"当作一等公民来搬运、对比、复用,而不是被某个 Agent 的私有格式绑死。

atif2otel:把轨迹变成 OpenTelemetry spans

到这里为止,ATIF 解决的是记录与交换。但轨迹文件躺在磁盘上,终究不在观测生态的查询路径里。Harbor 的解法是官方插件之一:atif2otel(另一个官方插件是同步 LangSmith 的),把每个 Agent 的 ATIF trajectory 转换成 OpenTelemetry spans——model 调用、tool 调用、subagent 各自成为 span,父子关系天然对应轨迹的嵌套结构。

uv tool install --with harbor-atif2otel harbor

# 流式导出:OTLP endpoint 直传 MLflow
export OPENAI_API_KEY="..."
export MLFLOW_TRACKING_TOKEN="..."
harbor run \
  -t hello-world/hello-world \
  -a codex -m openai/gpt-5.6-sol \
  --plugin atif2otel \
  --pk endpoint=https://mlflow.example.com \
  --pk experiment_name=harbor-evals

它有两种输出模式,由 mode=auto 自动决定:设了 endpoint(即 OTEL_EXPORTER_OTLP_ENDPOINT)就流式上报,设了 output_dir 就把 OTLP JSON 写成文件,两个都设就两条路都走。内置的上传器把每次试验导到一个 MLflow server——而 MLflow 的 tracing 功能本身就是用 OpenTelemetry 构建的,等于 OTLP 一出,Collector 后面的所有观测后端(Jaeger、Tempo、各类商业平台)理论上都能接。

这一步转换的意义值得说透:轨迹文档面向"人和训练管线",优化的是完整性与可回放性;span 流面向"查询与关联",优化的是实时性与生态兼容。atif2otel 没有让谁取代谁,而是在两者之间架了一座单向桥。

flowchart LR
    A["Agent trial in container"] --> B["agent/trajectory.json (ATIF)"]
    A --> C["Native session .jsonl"]
    B --> D["Results viewer
Trajectory tab"] B --> E["Cross-agent seeding
claude-code to codex"] B --> F["SFT / RL datasets
token_ids, tool_definitions"] B --> G["atif2otel plugin"] G --> H["OTel spans
model / tool / subagent calls"] H --> I["OTLP endpoint"] I --> J["MLflow / Collector / trace backends"] C -->|"lossless, same agent only"| K["Resume in same agent"]

生态汇流:NVIDIA 的三步棋

ATIF 与 OTel 的合流不是 Harbor 单方面的设想,NVIDIA 已经用三步把它变成了现实:

  1. 贡献格式演进。ATIF v1.7 的子轨迹嵌入、trajectory_id 体系由 NVIDIA 工程师 Bryan Bednarski 和 Anuradha Karuppiah 贡献——多 Agent 场景正是推理服务厂商最关心的地方。
  2. 标识符对齐。NVIDIA 的推理服务框架 Dynamo 不输出 ATIF,它输出 serving 导向的 dynamo.agent.trace.v1(请求时延、token、cache 命中、队列深度、worker 位置)。但它的身份字段刻意与 ATIF 同名——通过在每次 LLM 请求里附带 nvext.agent_context(session_id / trajectory_id / parent_trajectory_id),serving 侧 trace 与 harness 侧的 ATIF 文件"无需改名即可 join"。官方文档的原话是 "the two formats are complementary and join cleanly because identifier names match"。
  3. 双格式摄入。NVIDIA NeMo Platform 的 Intake 服务同时接受两条摄入路径: instrumented Agent 通过 OpenTelemetry / OpenInference exporter 发来的 OTLP spans,以及直接 POST 的 ATIF 轨迹(/ingest/atif 端点),两者被归一化成同一套可查询的 spans 和 traces。

三步合起来,图景已经很完整:一端是完整轨迹文档,一端是运行时遥测流,两边开始共享同一套身份体系。

分工,而不是取代

把两条线放在一起看,各自的定位其实非常清楚:

  • OpenTelemetry 回答"此刻系统里发生了什么"——实时、低开销、面向运维和告警,span 是事件的切片。
  • ATIF 回答"这个 Agent 完整经历了什么"——完整、可回放、面向评测与训练。SFT 需要的 tool_definitions、RL 需要的 prompt_token_ids / completion_token_ids、多 Agent 需要的 subagent_trajectories,这些信息在 span 模型里根本没有位置。

观测性领域的历史正在重演:先是方言林立,然后出现翻译层(atif2otel 这样的桥),最后身份对齐、双格式汇入同一个后端。当年 OpenTelemetry 用一套 API/SDK 统一了 metrics、logs、traces 的采集端,如今 Agent 生态在轨迹这一层走的是同一条路——只是这一次,"完整回放"和"实时观测"两种需求从一开始就注定要用两种载体。

如果你在搭自己的评测或观测链路,比较务实的路径是:评测跑在 Harbor 里,轨迹以 ATIF-v1.7 落盘(让 Pydantic 模型和校验器守住 schema 底线);要看板就挂 atif2otel 或 LangSmith 插件;自研 Agent 与 serving 层对接时,把 session_id / trajectory_id 这套命名当公共语言——将来无论往哪个后端汇,都不用再改名。


作者: itech001 来源: 公众号:AI人工智能时代(the-ai-era) 网站: https://www.theaiera.top/ 关注每日最新AI新闻和技术博客,主页有更多的文章的AI 技术参考:https://www.theaiera.top

本文首发于 AI人工智能时代,转载请注明出处。

分享给朋友