这篇文章帮你搞定 LangGraph 分布式追踪的底层原理,从 Trace/Span 到全链路可观测

阅读提示

  • 适合谁看:有 LangGraph 或 LLM 应用开发经验,正在做生产级可观测性的工程师
  • 看完能做什么:能设计可追踪、可调试、可监控的分布式追踪系统
  • 不适合谁:还没理解 LangGraph State/Graph 基础概念的纯新手

先给结论

  • 追踪不是“打印日志”,而是结构化的 Trace/Span 数据
  • 每个节点执行都是一个 Span,Span 之间通过 TraceID 关联
  • 生产级追踪必须考虑:采样策略、上下文传播、 exporter 选型

很多人做 LangGraph 时,demo 阶段跑得很顺,一上生产就发现 Agent 执行链是“黑盒”:

  • 不知道哪个节点耗时最长
  • 出错时不知道哪个节点出问题
  • 性能瓶颈无法定位

看起来是日志问题,本质上是分布式追踪没设计好

01 分布式追踪的本质:Trace 与 Span

分布式追踪的核心思想是Trace 与 Span

  • Trace:一次完整的执行链,包含所有 Span
  • Span:执行链中的一个步骤,包含开始时间、结束时间、状态
  • TraceID:Trace 的唯一标识,所有 Span 共享
  • SpanID:Span 的唯一标识,用于关联父子关系

这意味着:

  • 每个节点执行都是一个 Span
  • Span 之间通过 TraceID 关联
  • 父子 Span 通过 ParentSpanID 关联
为什么不能用日志代替?
# 误区:用日志记录执行链def execute_node(state):    print(f"Node started: {node_name}")    result = process(state)    print(f"Node finished: {node_name}")    return result

这种写法的问题在于:

  1. 日志是文本,无法结构化查询
  2. 无法关联父子关系
  3. 无法计算耗时
  4. 无法做采样和聚合

LangGraph 的解法是把追踪变成Trace + Span + Exporter

  • Trace:一次完整的执行链
  • Span:执行链中的一个步骤
  • Exporter:把 Span 数据导出到 Jaeger/Zipkin
场景代码示例:分布式追踪配置
from opentelemetry import tracefrom opentelemetry.sdk.trace import TracerProviderfrom opentelemetry.sdk.trace.export import BatchSpanProcessorfrom opentelemetry.exporter.jaeger.thrift import JaegerExporter# 1) 初始化 Tracerprovider = TracerProvider()jaeger_exporter = JaegerExporter(    agent_host_name="localhost",    agent_port=6831,)provider.add_span_processor(BatchSpanProcessor(jaeger_exporter))trace.set_tracer_provider(provider)tracer = trace.get_tracer("langgraph-agent")# 2) 运行入口:验证配置是否成功if __name__ == "__main__":    print("Tracer configured:", tracer)

02 Span 的底层原理:执行步骤的结构化记录

图 2|Span 执行流程

Span 的核心是执行步骤的结构化记录

  • 开始时间:Span 开始的时间戳
  • 结束时间:Span 结束的时间戳
  • 状态:Span 的执行状态(OK/ERROR)
  • 属性:Span 的附加信息(key-value)

这意味着:

  • Span 不是“日志行”,而是“结构化数据”
  • Span 可以嵌套,形成父子关系
  • Span 可以导出到外部系统,做可视化和分析
场景代码示例:Span 的使用方式
from opentelemetry import tracetracer = trace.get_tracer("langgraph-agent")def execute_node(state):    # 创建 Span    with tracer.start_as_current_span("execute_node") as span:        # 设置属性        span.set_attribute("node_name", "my_node")        span.set_attribute("input", str(state))        # 执行逻辑        result = process(state)        # 设置状态        span.set_status(trace.StatusCode.OK)        span.set_attribute("output", str(result))        return result# 最小验证if __name__ == "__main__":    print("execute_node ready")

03 上下文传播:跨节点的 Trace 关联

图 3|上下文传播机制

上下文传播是分布式追踪的关键:

  • TraceContext:携带 TraceID 和 SpanID
  • 传播方式:通过 HTTP Header 或 gRPC Metadata
  • 自动传播:OpenTelemetry 自动注入和提取

这意味着:

  • 跨节点调用时,TraceContext 自动传播
  • 子节点自动继承父节点的 TraceID
  • 无需手动传递 TraceID
场景代码示例:上下文传播配置
from opentelemetry import tracefrom opentelemetry.propagate import set_global_textmapfrom opentelemetry.propagators.composite import CompositePropagatorfrom opentelemetry.propagators.tracecontext import TraceContextTextMapPropagator# 1) 配置传播器set_global_textmap(    CompositePropagator([TraceContextTextMapPropagator()]))# 2) 运行入口:验证传播器配置if __name__ == "__main__":    print("Propagator configured")

04 最小实验:观察追踪如何工作

实验条件

  • 环境:LangGraph latest,Python 3.10+,Jaeger
  • 输入:一个简单任务,包含两个节点
  • 预期观察:Jaeger 中看到两个 Span,通过 TraceID 关联
  • 先准备什么:启动 Jaeger,配置 OpenTelemetry
  • 先跑什么:执行任务,观察 Jaeger 中的 Span
  • 你应该看到什么:两个 Span,通过 TraceID 关联

代码 1

from opentelemetry import tracefrom opentelemetry.sdk.trace import TracerProviderfrom opentelemetry.sdk.trace.export import BatchSpanProcessorfrom opentelemetry.exporter.jaeger.thrift import JaegerExporter# 配置 Tracerprovider = TracerProvider()jaeger_exporter = JaegerExporter(    agent_host_name="localhost",    agent_port=6831,)provider.add_span_processor(BatchSpanProcessor(jaeger_exporter))trace.set_tracer_provider(provider)tracer = trace.get_tracer("langgraph-agent")def node_a(state):    with tracer.start_as_current_span("node_a") as span:        span.set_attribute("input", str(state))        return {"result": "a"}def node_b(state):    with tracer.start_as_current_span("node_b") as span:        span.set_attribute("input", str(state))        return {"result": "b"}# 测试# with tracer.start_as_current_span("root") as root_span:#     result_a = node_a({"task": "test"})#     result_b = node_b(result_a)#     root_span.set_attribute("output", str(result_b))

如果结果不符合预期,先看哪里

  • Jaeger 是否正常连接
  • TraceID 是否正确传播
  • Span 是否正确创建
  • Exporter 是否正确导出

05 跑出来不对时,先看这几件事

  • 现象 1:Jaeger 中看不到 Span → 可能 Exporter 配置错误,先检查连接
  • 现象 2:Span 之间没有关联 → 可能上下文传播未生效,先检查 Propagator
  • 现象 3:Span 耗时不准确 → 可能时间戳错误,先检查时区
  • 现象 4:采样率太低 → 可能采样策略配置错误,先检查 Sampler

06 什么时候该用,什么时候别急着上

  • 更适合:复杂 Agent 执行链、生产级可观测性、性能分析
  • 不适合:简单任务、原型验证、低并发场景
  • 成本会突然变高的点:Span 存储、采样策略、Exporter 选型

3 问判断法

  1. 你的 Agent 是否包含多个节点?
  2. 是否需要定位性能瓶颈?
  3. 是否需要生产级可观测性?

如果 3 个问题大多是否定,先不要上复杂方案。

07 小结:从“日志”到“结构化追踪”

分布式追踪的底层原理可以总结成三句话:

  • Trace 是核心:一次完整的执行链,包含所有 Span
  • Span 是关键:执行步骤的结构化记录,支持嵌套和关联
  • 上下文是保障:TraceContext 自动传播,跨节点关联

当你把追踪从“日志”升级为“结构化追踪”,系统才真正具备可调试性、可监控性和可优化性。

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

在这里插入图片描述

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

在这里插入图片描述

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐