LangSmith的Trace和Span是什么

📅 发布时间:2026/8/6 4:07:02
LangSmith的Trace和Span是什么
Span跨度在LLM可观测 / OpenTelemetry / LangSmith / LangFuse 领域Trace一次完整请求的整条链路一条大树干SpanTrace里面的每一小段操作树上的每一个节点/树枝1条Trace 1次完整会话/一次Agent执行。一条Trace由多个Span组成Span之间有父子嵌套关系形成树。举个Agent例子Trace: 用户提问帮我查北京天气 ├─ Span【Agent主chain】(总耗时 2.2s) ├─ Span【调用工具 search天气】(耗时0.8s) └─ Span【LLM生成回答】(耗时1.3s)每一个方块就是一个Span。Span里面记录什么信息每个Span一定有span_id自己唯一IDparent_span_id父Span的id顶层Span父idNone开始时间、结束时间 → 计算耗时operation name操作名字llm.invoke、tool.search、graph_node:call_tool输入 inputs输出 outputs状态成功 / error / cancelled被取消元数据token消耗、模型名称、异常堆栈LangSmith里面叫RunRun Span概念等价。LangSmith术语Trace是根Run下面所有子Run就是子Span。产品整条链路单元片段LangSmithTrace根RunRun等价SpanLangFuseTraceObservation(Obs)等价SpanOpenTelemetryTraceSpanLangSmith内部Run对象就是Span_CURRENT_RUNcontextvar存的就是当前正在执行的Span对象。父子Span是怎么形成的结合前面contextvars创建父Span根Run把它存入ContextVar。执行子函数traceable/ callback 读取context拿到父Span。创建子Span把子Span的parent_span_id 父span_id。子Span执行完成上报。不需要手动传参靠上下文隐式拿到父ID自动嵌套。三种Span结束状态✅正常结束拿到end回调记录结束时间完整上报。❌异常报错触发on_xxx_error回调标记span状态为error记录异常栈。⚠️被取消前端停止生成task.cancel()协程抛出CancelledError。不会走到end回调也不会走到error回调Span只有start没有endUI看到一条“截断、未完成”的trace。区分容易混淆名词Trace完整的一次业务请求链路根Span链路中每一个独立操作片段子节点ContextVar用来隐式传递当前span对象方便自动设置parent_span_idCallback事件钩子在业务节点执行的前后触发创建/结束Span极简伪代码模拟Span模型dataclassclassSpan:span_id:strparent_span_id:str|Nonename:strstart_time:floatend_time:float|Nonestatus:str# ok / error / cancelledinputs:dictoutputs:dict|None# 上下文变量保存当前正在运行的spancurrent_span:ContextVar[Span|None]ContextVar(current_span)defstart_span(name):parentcurrent_span.get()spanSpan(span_idstr(uuid.uuid4()),parent_span_idparent.span_idifparentelseNone,namename,start_timetime.time(),end_timeNone,statusok,inputs{},outputsNone)tokencurrent_span.set(span)returnspan,tokendefend_span(span,token):span.end_timetime.time()report_span(span)# 上报到LangSmith/LangFusecurrent_span.reset(token)回到Agent业务用户发消息跑LangGraph新建Trace根Span存入contextvar执行graph节点回调触发新建子Spanparent指向根节点内部调用LLM再新建LLM子Span用户点停止task.cancel代码直接中断。end_span()不会执行。→ 所有已经start但是没有end的Span在平台上展示为残缺链路。对比LangFuseLangFuse Observation就是Span但不依赖contextvars你必须手动传入父trace/observation_id或者依赖OTel的上下文。所以不会出现隐式上下文带来的断链但埋点代码写得更多。一句话总结Trace是一整条请求Span就是这条请求里面每一步操作的记录单元。LangSmith的Run就是Span。