Trace

Trace 是 Agent 执行过程的完整记录,包含每次 LLM 调用、工具执行、状态转换的详细信息。它是调试、监控和评估 Agent 的基础数据。

#type / concept #status / evergreen #tech / ai #tech / ops

[!info] related notes

Trace

一句话定义

Trace 是 Agent 一次 Run 执行过程的完整记录,包含每个 Step 的 LLM 调用(输入/输出/延迟/token)、工具执行(名称/参数/结果/耗时)和状态转换。它是调试 Agent “为什么做出这个决策”的核心数据。

它解决什么问题

Agent 是非确定性的:同样的输入可能产生不同的执行路径。出了问题时你需要知道:

  • Agent 为什么选择了这个工具而不是那个?
  • 工具返回了什么结果?
  • LLM 的 Prompt 里到底塞了什么内容?
  • 哪一步花了最多时间?
  • token 消耗在哪里?

没有 Trace,Agent 就是一个黑盒。

核心原理

Trace 的数据结构

Trace (一次 Run 的完整记录)
├── Span 1: LLM Call
│   ├── input: system prompt + messages + tools
│   ├── output: tool_call / text
│   ├── tokens: {input: 1200, output: 350}
│   ├── latency_ms: 2300
│   └── model: gpt-4

├── Span 2: Tool Execution
│   ├── tool_name: search_knowledge
│   ├── arguments: {query: "..."}
│   ├── result: [...]
│   ├── latency_ms: 450
│   └── status: success

├── Span 3: LLM Call
│   ├── input: ... + tool_result
│   ├── output: final answer
│   ├── tokens: {input: 1800, output: 500}
│   └── latency_ms: 3100

└── Summary
    ├── total_tokens: 3850
    ├── total_latency_ms: 5850
    ├── tool_calls: 1
    └── steps: 2

Trace 与 OpenTelemetry

Trace 遵足 OpenTelemetry 的分布式追踪模型:

  • Trace: 一次完整的请求链路
  • Span: 链路中的一个操作单元
  • Span Context: 跨服务传递的上下文(trace_id, span_id)
Trace (trace_id: abc123)
├── Span: Agent Run (span_id: 001)
│   ├── Span: LLM Call (span_id: 002)
│   ├── Span: Tool Execution (span_id: 003)
│   └── Span: LLM Call (span_id: 004)

Trace vs Log vs Metric

TraceLogMetric
关注点请求链路离散事件聚合数值
粒度一次请求一条记录统计值
用途调试、性能分析错误排查监控告警
例子一次 Agent Run 的完整过程”Tool X 调用失败""平均延迟 2.3s”

典型工程实现

Trace 记录器

class AgentTracer:
    def __init__(self, run_id: str):
        self.run_id = run_id
        self.spans: list[Span] = []
        self.current_span: Optional[Span] = None

    def start_span(self, name: str, attributes: dict = None) -> Span:
        span = Span(
            trace_id=self.run_id,
            span_id=generate_id(),
            name=name,
            start_time=datetime.now(),
            attributes=attributes or {},
            parent_id=self.current_span.span_id if self.current_span else None,
        )
        self.spans.append(span)
        self.current_span = span
        return span

    def end_span(self, span: Span, status: str = "ok"):
        span.end_time = datetime.now()
        span.duration_ms = (span.end_time - span.start_time).total_seconds() * 1000
        span.status = status

    def record_llm_call(self, input_tokens, output_tokens, model, latency_ms):
        span = self.start_span("llm_call", {"model": model})
        span.attributes["input_tokens"] = input_tokens
        span.attributes["output_tokens"] = output_tokens
        self.end_span(span)

    def record_tool_call(self, tool_name, arguments, result, latency_ms, status):
        span = self.start_span("tool_call", {"tool_name": tool_name})
        span.attributes["arguments"] = arguments
        span.attributes["result"] = result
        self.end_span(span, status)

Trace 查询

# 查询某个 Run 的所有 Span
trace = tracer.get_trace(run_id="run_001")

# 查询所有慢 LLM 调用
slow_calls = tracer.query(
    filter="span.name = 'llm_call' AND span.duration_ms > 5000"
)

# 查询工具调用失败率
fail_rate = tracer.query(
    filter="span.name = 'tool_call'",
    aggregate="COUNT(*) WHERE status = 'error' / COUNT(*)"
)

常见设计模式

1. 自动 Trace

Agent Runtime 自动记录所有 LLM 调用和工具执行,不需要手动埋点。

2. 采样 Trace

生产环境中只记录部分 Trace(如 10%),减少存储开销。

3. 错误 Trace

出错时自动记录完整 Trace,正常时只记录摘要。

常见坑

  1. 不记录 LLM 输入: 只记录输出,无法复现问题
  2. Trace 数据太大: 完整记录所有内容,存储成本高
  3. 不做采样: 生产环境全量记录,性能影响大
  4. Trace 和 Log 分离: 同一个请求的 Trace 和 Log 对不上
  5. 不记录 token 消耗: 无法分析成本

和其他概念的关系

  • vs Run: Run 是执行单元,Trace 是 Run 的记录
  • vs Checkpoint: Checkpoint 用于恢复,Trace 用于回溯
  • vs OpenTelemetry: OTel 是 Trace 的标准框架
  • vs Trace Viewer: Viewer 是 Trace 的可视化工具

总结

Trace 是 Agent 的黑盒记录器。没有 Trace,你无法知道 Agent 为什么做出某个决策,也无法优化它的行为。

参考资料

创建于 2026/6/30 更新于 2026/7/15