🧠 图解记忆:Trace 上下文既要穿过同步 HTTP,也要随消息元数据跨越异步边界;点击图片可查看原图。
💡 答案要点
核心挑战:
单 Agent:TraceID 在单个进程内传递
多 Agent:TraceID 跨越多个进程/服务,需要手动传播
问题:Agent A 调用 Agent B,trace_id 断了吗?传播机制对比:
| 方式 | 原理 | 适用场景 | 局限性 |
|---|---|---|---|
| HTTP Header | traceparent 自动传播 | HTTP 调用 | 需要所有服务支持 OTEL |
| 消息队列 | 手动注入 baggage | 异步消息 | 需要修改消息格式 |
| 共享内存 | Redis 存储上下文 | 同机器多进程 | 延迟增加 |
| 数据库 | Task 表存储 trace_id | 持久化任务 | 需要事务支持 |
生产级实现(HTTP + 消息队列双模式):
展开 Python 代码示例(58 行)
python
from opentelemetry import propagate, trace
from opentelemetry.propagate import inject, extract
from opentelemetry.trace.propagation.tracecontext import TraceContextTextMapPropagator
class MultiAgentTracer:
def __init__(self):
self.propagator = TraceContextTextMapPropagator()
# 模式1:HTTP 调用(自动传播)
async def call_agent_http(self, agent_name: str, task: dict, url: str):
headers = {}
inject(headers) # 自动从当前 context 注入 traceparent
response = await httpx.AsyncClient().post(
url,
json=task,
headers={**headers, "X-Agent-Name": agent_name}
)
span_context = extract(response.headers).get(
trace_span_context_key, None
)
return response.json()
# 模式2:消息队列调用(手动传播)
async def call_agent_mq(self, agent_name: str, task: dict, mq_client):
current_span = trace.get_current_span()
span_context = current_span.get_span_context()
traceparent = f"00-{span_context.trace_id:032x}-{span_context.span_id:016x}-01"
message = {
**task,
"_trace_context": {
"traceparent": traceparent,
"tracestate": current_span.get_span_context().trace_state,
"agent_name": agent_name,
"parent_span_id": span_context.span_id
}
}
await mq_client.publish(
exchange="agent_exchange",
routing_key=agent_name,
body=json.dumps(message)
)
# 跨 Agent 轨迹聚合查询
async def get_full_trace(task_id: str):
"""获取同一任务的所有 Agent 轨迹"""
trace_id = await redis.hget(f"task:{task_id}", "trace_id")
spans = await jaeger_client.query(
service=["agent-orchestrator", "agent-search", "agent-executor"],
trace_id=trace_id
)
return sorted(spans, key=lambda s: s.start_time)数据库 Schema 设计:
sql
-- 任务表存储 trace_id 关联
CREATE TABLE agent_tasks (
id UUID PRIMARY KEY,
trace_id VARCHAR(64) NOT NULL,
parent_span_id VARCHAR(32) NOT NULL,
status VARCHAR(20),
created_at TIMESTAMP,
completed_at TIMESTAMP,
INDEX idx_trace_id (trace_id),
INDEX idx_status (status)
);
-- 子 Agent 任务关联表
CREATE TABLE agent_task_children (
parent_task_id UUID REFERENCES agent_tasks(id),
child_agent_name VARCHAR(50),
child_trace_id VARCHAR(64),
child_span_id VARCHAR(32),
status VARCHAR(20),
PRIMARY KEY (parent_task_id, child_agent_name)
);面试话术:
"多Agent追踪的核心是trace_id的传播方式。HTTP调用自动传播(OTel标准),消息队列需要手动注入traceparent到消息体。生产中我用过两种模式:同步HTTP用自动传播,异步MQ用手工传播(把traceparent放消息头)。每个任务在数据库存trace_id,调试时用Jaeger按trace_id查询,能看到OrchestratorAgent→SearchAgent→ExecutorAgent的完整时序。"
