首页 › AI Agent › Agent100道面试题 › 评估 -evaluation › Trace 和 Span:Agent 执行的可观测性

Trace 和 Span:Agent 执行的可观测性

难度:中级 分类:Evaluation​

简短回答​

Trace 和 Span 是分布式追踪(Distributed Tracing)的核心概念,被引入 LLM/Agent 系统用于实现执行可观测性——理解 Agent "做了什么、花了多久、哪里出了问题"。Trace 代表一次完整的 Agent 执行(从接收任务到返回结果),Span 代表 Trace 中的一个操作单元(如一次 LLM 调用、一次工具调用、一次检索)。Span 之间有父子关系,形成树形结构,清晰展示 Agent 的决策链。OpenTelemetry (OTel) 是 LLM 可观测性的主流方向——OTel GenAI Special Interest Group 维护的 Semantic Conventions for Generative AI 截至 2026-05 仍处于 Development 阶段(尚未 Stable),定义了 GenAI 相关的语义约定(gen_ai.system、gen_ai.request.model 等属性)。主流工具(Langfuse、LangSmith 2026-01 起 end-to-end native OTel、Arize Phoenix)都已支持,但 API 名字可能在 GA 前微调,生产接入建议固定到具体语义版本。​

详细解析​

Trace 和 Span 的结构​

​

飞书文档 - 图片

​

一个 Trace 就是一棵 Span 树:每次 LLM / 工具调用都是可独立计时、可标错的子节点。​

OpenTelemetry 集成​

​

代码块​

Python

from opentelemetry import trace​

from opentelemetry.sdk.trace import TracerProvider​

from opentelemetry.sdk.trace.export import BatchSpanProcessor​

​

# 初始化 OTel​

provider = TracerProvider()​

provider.add_span_processor(​

BatchSpanProcessor(OTLPSpanExporter(endpoint="http://collector:4318"))​

)​

trace.set_tracer_provider(provider)​

tracer = trace.get_tracer("agent-service")​

​

class ObservableAgent:​

"""带完整可观测性的 Agent"""​

​

async def execute(self, task: str):​

# 创建 Trace(顶层 Span)​

with tracer.start_as_current_span("agent_execution") as root_span:​

root_span.set_attribute("task", task)​

root_span.set_attribute("agent.name", "research-agent")​

​

# Step 1: 规划​

plan = await self.plan(task)​

​

# Step 2: 执行每个步骤​

results = []​

for step in plan.steps:​

result = await self.execute_step(step)​

results.append(result)​

​

# 记录总体指标​

root_span.set_attribute("total_steps", len(results))​

root_span.set_attribute("task_success", True)​

​

return self.synthesize(results)​

​

async def plan(self, task):​

with tracer.start_as_current_span("llm_call") as span:​

span.set_attribute("gen_ai.system", "openai")​

span.set_attribute("gen_ai.request.model", "gpt-4o")​

span.set_attribute("gen_ai.operation.name", "planning")​

​

response = await self.llm.invoke(task)​

​

# 记录 token 使用​

span.set_attribute("gen_ai.usage.input_tokens", response.usage.prompt_tokens)​

span.set_attribute("gen_ai.usage.output_tokens", response.usage.completion_tokens)​

​

return response​

​

async def execute_step(self, step):​

with tracer.start_as_current_span("agent_step") as span:​

span.set_attribute("step.name", step.name)​

​

if step.requires_tool:​

# 工具调用子 Span​

with tracer.start_as_current_span("tool_call") as tool_span:​

tool_span.set_attribute("tool.name", step.tool_name)​

tool_span.set_attribute("tool.input", str(step.tool_params))​

​

result = await self.call_tool(step.tool_name, step.tool_params)​

​

tool_span.set_attribute("tool.output_size", len(str(result)))​

if result.error:​

tool_span.set_status(trace.Status(trace.StatusCode.ERROR))​

tool_span.record_exception(result.error)​

​

return result​

​

GenAI 语义约定(OTel 标准)​

​

代码块​

Python

# OTel 为 GenAI 定义的标准属性​

otel_genai_attributes = {​

# 系统信息​

"gen_ai.system": "openai / anthropic / google",​

"gen_ai.request.model": "gpt-4o / claude-sonnet-4-5",​

​

# 请求参数​

"gen_ai.request.temperature": 0.7,​

"gen_ai.request.max_tokens": 4096,​

"gen_ai.request.top_p": 1.0,​

​

可观测性的三大支柱在 Agent 中的应用​

​

代码块​

JSON

observability_pillars = {​

"Traces(追踪)": {​

​

实际调试场景​

​

代码块​

Python

# 场景:Agent 在某个任务上失败了,如何用 Trace 定位问题?​

​

debug_workflow = """​

1. 找到失败的 Trace​

→ 根据 request_id 或 error 状态筛选​

​

2. 查看 Span 树结构​

→ 定位哪个 Span 出错(红色标记)​

​

3. 检查出错 Span 的详情​

→ LLM 调用:看输入 Prompt 和输出​

→ 工具调用:看参数和返回值​

→ 错误信息:看异常类型和堆栈​

​

4. 分析上下文​

→ 前序 Span 的输出是否正常​

​

主流工具对比​

​

​

常见误区 / 面试追问​

误区:"有日志就不需要 Trace" — 日志是离散的事件记录,Trace 是结构化的因果链。日志告诉你"发生了什么",Trace 告诉你"为什么发生"以及"事件之间的关系"。在多步 Agent 中,没有 Trace 几乎无法定位问题。​

误区:"Trace 只在出问题时有用" — Trace 在日常监控中同样重要:发现性能瓶颈(哪个 Span 最慢)、优化成本(哪个 LLM 调用 token 消耗最多)、理解用户行为(Agent 通常走什么路径)。​

追问:"如何控制 Trace 数据的存储成本?" — (1) 采样——不是每个请求都记录完整 Trace(如 10% 采样率);(2) 按需详细度——正常请求只记录关键 Span,错误请求记录全部细节;(3) 数据保留策略——Trace 数据保留 7-30 天。​

追问:"OpenTelemetry 的优势是什么?" — 供应商无关性。用 OTel 标准化的数据可以发送到任何后端(Jaeger、Datadog、Langfuse)。换监控工具不需要改代码,只改 exporter 配置。这避免了供应商锁定。​