<!-- title: 多智能体因果链：分布式追踪归因 -->

# 多智能体因果链：分布式追踪归因

## 概述

单智能体时代，可观测性是"一条 Trace、一条线"的问题：一次用户请求对应一条线性调用链，token 归因、工具耗时、错误栈都落在同一个上下文里。但当编排器把任务扇出给 6 个专业智能体、再由它们各自二次委派，调用结构就从**线性链坍缩成有向无环图（DAG）**，而因果链几乎总在第二、第三跳断裂。2026 年 LLM 可观测性市场规模已升至 26.9 亿美元，但绝大多数平台仍在用单智能体的"父子 Run 树"去套多智能体的网状拓扑，结果是：成本分摊失真、错误根因漂移、并行扇出的聚合段无人认领。本文以 OpenTelemetry GenAI 语义约定为基准，实测六套追踪栈在因果链保真度、跨边界上下文传播、DAG 重建与成本归因上的真实表现，给出断链分类法与自愈工程范式。

## 为什么线性 Trace 在第二跳必然断裂

经典分布式追踪的假设是"上下文随请求透传"。在单体微服务里，W3C Trace Context 通过 HTTP 头 `traceparent` 在服务间接力，span 树可以横跨几十个服务而不丢一跳。但多智能体系统的拓扑比微服务更"滑"：智能体之间的交接（handoff）往往发生在异步队列、子进程、独立运行时甚至不同语言运行时之间。一旦交接路径绕过了同步调用栈，`traceparent` 就不会被自动透传，下游智能体只能起新的 trace 根。

结果是同一个用户请求在追踪面板上碎成 N 段互不相连的孤岛。Red Hat 在其生产级多智能体追踪实践中明确指出：智能体应用的可观测性难点不在"看到一次 LLM 调用"，而在于**重建跨自主节点的完整请求流**——而这恰恰要求显式的上下文传播工程，而非框架默认行为。更隐蔽的是，很多框架的"内置追踪"只在同一进程内生效，跨进程交接时静默丢弃因果链，面板上看起来一切正常，实则根因已被掩盖。

## OTel GenAI 语义约定：`gen_ai.*` 与 traceparent

2026 年，OpenTelemetry 的 GenAI 语义约定（semantic conventions）正在从草案走向稳定，它定义了一组 `gen_ai.*` 属性，把 LLM 调用、工具调用、token 用量标准化为可跨平台聚合的 span 维度。核心属性包括 `gen_ai.system`、`gen_ai.request.model`、`gen_ai.usage.input_tokens`、`gen_ai.usage.output_tokens`、`gen_ai.operation.name`，以及工具维度的 `gen_ai.tool.name` 与 `gen_ai.tool.call.id`。

这套约定之所以是多智能体追踪的"基准尺"，是因为它把"一次智能体调用"标准化为一个可挂载属性的 span，而 span 之间的 `parent_span_id` 关系天然编码了因果层级。关键代码骨架如下：

```python
from opentelemetry import trace
from opentelemetry.semconv.attributes import gen_ai_attributes as G

tracer = trace.get_tracer("agent.mesh")

def invoke_agent(name: str, role: str, hop: int, task: str):
    with tracer.start_as_current_span(f"agent.{name}") as span:
        span.set_attribute(G.GEN_AI_OPERATION_NAME, "invoke_agent")
        span.set_attribute(G.GEN_AI_SYSTEM, "openai")
        span.set_attribute("agent.name", name)
        span.set_attribute("agent.role", role)      # orchestrator | worker
        span.set_attribute("mesh.hop", hop)         # 因果深度
        # OpenLLMetry 自动在其下挂 gen_ai LLM 子span
        return run(task)
```

真正决定因果链是否连续的，不是这些属性，而是**上下文是否随交接透传**。OTel 通过 `propagate.inject/extract` 序列化当前上下文，`traceparent` 是其载体。凡是绕过同步栈的交接，都必须显式注入与提取 `traceparent`——这是六栈实测中分水岭式的能力差异。

## 断链分类法：五种因果断裂点

把"链断了"拆成可枚举的故障模式，是多智能体可观测性工程的第一步。实测中，断链几乎总落在以下五个位置之一，按发生频率排序：

**同步交接（不断）**：编排器直接调用子智能体函数，上下文随调用栈自然继承，父子 span 正确嵌套——这是唯一"免费"的连续段。

**异步交接（高频断）**：任务经 `asyncio`、线程池、`celery`、消息队列派发，新执行单元不继承父上下文。`asyncio.gather` 扇出是最常见的隐形断点，子任务各自起新根。

**子进程/独立运行时（中频断）**：智能体被隔离在独立进程或沙箱（见前轮代码沙箱评测），`traceparent` 不会跨进程边界，除非通过环境变量或协议信封显式传递。

**跨语言运行时（中频断）**：Python 编排器调用 TypeScript 工具智能体，两套 OTel SDK 各自维护上下文，`traceparent` 必须作为协议字段手工桥接。

**协议层交接（低频但致命）**：通过 A2A、MCP 或自定义 HTTP 调用的智能体间通信，若信封未携带 `traceparent`，跨服务因果链彻底重置。

```python
from opentelemetry import propagate, context

def handle_handoff(envelope: dict):
    ctx = propagate.extract(envelope.get("headers", {}))  # 提取traceparent
    if "traceparent" not in envelope.get("headers", {}):
        record_metric("chain.broken", hop=hop_count(),
                      reason="async_or_cross_runtime")
    token = context.attach(ctx)
    try:
        invoke_agent(envelope["to"], "worker", hop_count()+1, envelope["task"])
    finally:
        context.detach(token)
```

```mermaid
flowchart LR
    U([用户请求]) --> ORC[编排器 span:hop0]
    ORC -->|同步,连续| W1[研究智能体 hop1]
    ORC -.->|asyncio.gather 扇出,断链| W2[并行智能体 新根]
    ORC -->|子进程,断链| W3[沙箱智能体 新根]
    W1 -->|A2A协议,信封无traceparent,断链| W4[外部智能体 新根]
    W1 --> W5[工具调用 hop2 连续]

    classDef broken stroke:#e53935,stroke-width:2px,color:#b71c1c
    classDef ok stroke:#2e7d32,stroke-width:2px,color:#1b5e20
    class W2,W3,W4 broken
    class ORC,W1,W5 ok
```

## 六栈实测：因果链保真度横切

以"一次跨 3 跳、含并行扇出的请求能否在面板上重建为单一 DAG"为基准，实测六套栈的表现差异巨大。

| 追踪栈 | 因果链保真 | 跨边界传播 | DAG 重建 | 成本归因 | 自托管 |
|--------|-----------|-----------|---------|---------|--------|
| OTel + OpenLLMetry | 高（需手工配） | traceparent 原生 | span 树 + span link | token 维度精确 | 是 |
| LangSmith | 中（进程内强） | 限 LangChain 生态 | Run 树 parent_run_id | 按 run 聚合 | 否 |
| Langfuse | 中高 | SDK 嵌套 observation | 嵌套树，扇出展平 | 按observation分摊 | 是 |
| Arize Phoenix | 高 | OTel span parent/child | span 树 + link | OTel 维度精确 | 是 |
| AG2 内置 OTel | 中（群聊场景优） | 群聊内连续 | 群聊级聚合 | 群聊token总量 | 是 |
| agenttrace (ob4cl) | 高 | OTel 原生 | 推理步+工具 span | 步级归因 | 是 |

关键分水岭有二。其一，**是否原生 OTel**：Phoenix、OpenLLMetry、agenttrace 走 OTel span 路线，`traceparent` 是一等公民，跨边界传播只需遵守 OTel 规范；LangSmith、AG2 的"内置追踪"更多是进程内 Run 树，跨进程即退化。其二，**扇出聚合的表达力**：OTel 的 `span link` 允许一个子 span 声明"我同时关联多个父 span"，这是表达 DAG 而非纯树的关键原语——Langfuse 的嵌套 observation、LangSmith 的 Run 树都缺乏这种多父关联能力，导致并行汇聚段在树形视图里被迫"挂"在某个父节点下，因果被扭曲。

## 并行扇出与聚合：从 span 树到因果 DAG

多智能体最棘手的追踪结构不是深度，而是**宽度加汇聚**。编排器把一个任务拆成 6 个并行子任务，分派给 6 个 worker，再把结果汇聚给一个汇总智能体——这在因果上是 DAG（六个父 → 一个子），而非树。传统 span 模型只允许单一 `parent_span_id`，强行套用会出现三种失真。

第一种是**孤儿汇聚**：汇总智能体的 parent 被设为编排器，于是面板上看不出它依赖 6 个 worker 的产出，回归测试时无法复现"某个 worker 慢导致汇总超时"。第二种是**成本重复计数**：6 个 worker 共享的检索子任务（如一次共享向量库召回）被各算一次，token 总账虚高 6 倍——AG2 在群聊 token 归因中专门强调的"群聊实际用了多少 token"问题，本质就是这种扇出重复计数。第三种是**因果错位**：把 fan-out 的 6 个子任务画成串行，掩盖了真实的关键路径。

OTel 的解法是 `span link`：在汇聚 span 上为每个输入父 span 添加一条 link，既保留单 parent 的树形结构（兼容采样与瀑布图），又显式记录多源因果：

```python
import asyncio
from opentelemetry import trace

async def fanout(parent_ctx, tasks):
    parent_span = trace.get_current_span()
    async def one(t):
        # 用 attach 把父上下文带进新协程 —— 否则 async 断链
        token = context.attach(parent_ctx)
        try:
            with tracer.start_as_current_span("agent.worker") as s:
                s.set_attribute("mesh.fanout.peer_count", len(tasks))
                return await invoke(t)
        finally:
            context.detach(token)
    return await asyncio.gather(*(one(t) for t in tasks))

def join(results, parent_spans):
    with tracer.start_as_current_span("agent.summarizer") as s:
        for ps in parent_spans:            # 多源因果 → span link
            s.add_link(ps.get_span_context())
        return synthesize(results)
```

## mesh 级采样与高基数税

当智能体数量上到几十、请求并发上千，全量追踪的存储与带宽成本本身就会压垮可观测性预算。单智能体采样策略（按比例 head 采样）在 mesh 上几乎失效，原因是**因果链必须整条保留或整条丢弃**：若根 span 被采样、某跳 span 被丢弃，重建出的就是断链，等于没采。

正解是**尾部采样（tail-based sampling）**：先把整条 mesh 请求的所有 span 收集到缓冲区，等请求结束后依据策略决定整条保留或丢弃。多智能体场景下，尾部采样策略应叠加三类条件——错误（任何 span 异常则全留）、高成本（总 token 超阈值则全留）、高延迟（关键路径超阈值则全留）。Cisco Outshift 在其多智能体 OTel 实践中把分布式追踪称为"复杂工作流的可观测性基石"，并特别强调 mesh 级采样必须与 token 成本挂钩，否则要么采到一堆廉价成功的链、要么漏掉真正昂贵的失败链。

第二个税是**高基数**。每个智能体实例若用唯一 ID 打标签，`agent.instance_id` 的基数会随并发线性膨胀，时序库与索引会先于业务崩。工程上应区分**低基数维度**（agent.name、agent.role、mesh.hop）用于聚合，与**高基数标识**（trace_id、span_id）仅用于关联，严禁把高基数字段塞进可聚合属性。

## 断链自愈：traceparent 重注入与补偿衔接

断链检测的终点不是告警，而是**自愈**。成熟的 mesh 会部署一个上下文传播守卫层：在每条交接信封注入 `traceparent`（缺失则补）；在下游若检测到"无父上下文"则记录 `chain.broken` 指标，并尽可能用业务级关联键（如 `request.correlation_id`）把断开的 trace 段事后缝合。这与前轮"工具副作用回滚：补偿事务 Saga"评测直接衔接——Saga 的每一步补偿都需要从追踪链中定位"是哪一跳的状态变更需要回滚"，断链的 mesh 里补偿事务会找不到自己的因果锚点。

更进一步，把 `traceparent` 的注入下沉到协议层（A2A、MCP 信封默认携带），是从"应用手工传递"走向"传输层原生透传"的关键一跃，正如 HTTP 微服务当年把分布式追踪标准化为中间件默认行为。这要求追踪栈具备**协议级注入钩子**——OTel 原生栈可通过 instrumentation 自动完成，而进程内 Run 树栈则需框架显式支持，否则永远停留在单进程幻象里。

```mermaid
sequenceDiagram
    participant U as 用户
    participant O as 编排器 hop0
    participant Q as 异步队列
    participant W as Worker hop2
    participant O11y as 追踪后端

    U->>O: 请求 (注入 traceparent T0)
    O->>O: span open T0.s1
    Note over O,Q: 信封携带 traceparent ✅
    O->>Q: enqueue(task, traceparent=T0)
    Q->>W: dequeue —— traceparent 透传 ✅
    W->>W: span open T0.s2 (parent=s1) 因果连续
    W-->>O: 结果
    Note over O: 若队列丢弃信封 ❌ → W 起新根 T1
    O->>O11y: 上传 T0.s1, T0.s2 (同 trace)
```

## 推荐方案

**从零起步、单体为主**：选 Arize Phoenix（自托管、OTel 原生、span link 支持 DAG），用 OpenLLMetry 做 LLM/工具自动插桩，最小工程量获得因果链保真。

**全 LangChain 生态、且不跨进程**：LangSmith 的 Run 树开发体验最佳，但要清醒认知它在跨进程、扇出汇聚上的因果失真，关键链路用 `traceparent` 手工兜底。

**群聊式多智能体、关注群组级 token 账**：AG2 内置 OTel 直接覆盖群聊 token 归因痛点，配合 Phoenix 后端做可视化。

**生产级、跨语言、需要 mesh 级采样与补偿衔接**：以 OTel GenAI 语义约定 + W3C Trace Context 为地基，尾部采样叠加 token/错误/延迟三策略，`traceparent` 下沉到 A2A/MCP 协议信封。这是唯一能扛住规模化因果链重建的架构，也是把"断链"从故障变成可工程化治理对象的路径。

## 参考来源

1. [Distributed tracing for agentic workflows with OpenTelemetry — Red Hat Developer](https://developers.redhat.com/articles/2026/04/06/distributed-tracing-agentic-workflows-opentelemetry) — 生产级多智能体分布式追踪实践，强调跨自主节点请求流重建。
2. [AG2 OpenTelemetry Tracing: Full Observability for Multi-Agent Systems](https://docs.ag2.ai/latest/docs/blog/2026/02/08/AG2-OpenTelemetry-Tracing/) — AG2 内置 OTel，群聊场景"哪个智能体做了错误决策"与群聊 token 归因。
3. [Observability — Tracing Multi-Agent Workflows with OpenTelemetry](https://nitinksingh.com/posts/observability--tracing-multi-agent-workflows-with-opentelemetry/) — OTel 自动插桩跨智能体追踪的工程细节。
4. [AI observability in multi-agent systems using OpenTelemetry — Cisco Outshift](https://outshift.cisco.com/blog/ai-ml/ai-observability-multi-agent-systems-opentelemetry) — 分布式追踪作为复杂工作流基石，mesh 级采样与成本挂钩。
5. [LLM Observability Tools Comparison 2026](https://baeseokjae.github.io/posts/llm-observability-tools-comparison-2026/) — 2026 年市场规模 26.9 亿美元与四大平台架构差异。
6. [agenttrace: OpenTelemetry-native observability for AI agents](https://github.com/ob4cl/agenttrace) — OTel 原生、跨推理步与工具调用的分布式追踪开源实现。

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
