学习笔记 · Obsidian
SDK 追踪上下文与分布式链路
最稳妥的接入顺序是:优先原生框架集成,其次 Provider wrapper,再用 <code>traceable</code> 补业务节点;只有 SDK 不可用时才直接调用 REST。所有路径最终都必须维护同一个父子上下文、project 和 flush 生命周期。
一、接入层级
| 优先级 | 方式 | 适用场景 | 主要风险 |
|---|---|---|---|
| 1 | LangChain/LangGraph/Deep Agents 原生 tracing | 已使用对应框架 | 配置继承和版本差异 |
| 2 | Provider/框架 wrapper | OpenAI、Anthropic 等直接 SDK | 多重 instrument 造成重复 trace |
| 3 | <code>traceable</code> / <code>@traceable</code> | 自定义业务、tool、retriever | run type 和 I/O 语义需自己保证 |
| 4 | <code>trace</code> / RunTree | 需要手动控制生命周期 | 漏 patch、异常路径、层级错误 |
| 5 | REST API | SDK 无法运行的语言/环境 | 同步开销、批量协议、幂等和顺序 |
二、环境与程序化配置
常用变量:
- <code>LANGSMITH_TRACING=true</code>:启用全局 tracing。
- <code>LANGSMITH_API_KEY</code>:密钥。
- <code>LANGSMITH_ENDPOINT</code>:区域或自托管 API;区域 URL 不要带尾斜杠。
- <code>LANGSMITH_WORKSPACE_ID</code>:一个 key 关联多 workspace 时消歧。
- <code>LANGSMITH_PROJECT</code>:默认 project。
无法设置环境变量时,创建显式 Client,并在 tracing context 或 tracer 中注入 client、project 和 enabled。不要把密钥硬编码到源码。
LangSmith 的 RunTree API 有一个容易忽略的特性:显式创建 RunTree 可绕过 <code>LANGSMITH_TRACING</code> 开关。它适合主动 tracing,不适合作为“全局关停”唯一控制点。
三、业务函数的自动追踪
<code>traceable</code> 会自动:
- 建立 run、记录输入输出和异常。
- 从当前异步/线程上下文取得父 run。
- 将内部已 instrument 的 LLM、LangChain 或 tool 嵌套为子 run。
- 支持 name、run type、tags、metadata、client 和 project。
Generator/async generator 只有在迭代完成、关闭或抛错后才能结束 run;调用函数但不消费生成器不会产生完整 trace。流式服务要覆盖客户端断连和取消路径。
读取当前 span:
- 用 current run tree/span API 取得 ID、trace ID 或增加 metadata。
- 读取可能返回空,代码必须允许 tracing 被禁用。
- 不建议遍历整个 current RunTree 来推导所有子节点;异步子节点可能尚未提交。
四、嵌套与上下文传播
同进程内,traceable 和受支持 wrapper 通常自动继承上下文。跨服务必须:
- 从当前 run 生成 tracing headers。
- 随业务请求发送。
- 下游在 tracing context 中把 headers 设为 parent。
- 下游业务节点在该 context 内创建。
传播的是追踪身份,不是认证。下游仍需使用自己的 LangSmith 凭据;不要把上游 API key 放入 tracing headers。
异步队列要把父上下文写入消息 envelope,并定义过期策略。若队列任务可能在父 trace 保留窗口后执行,可改为新 trace,并用业务 correlation ID 关联,避免伪造一棵长期未闭合的树。
五、动态路由到 project 和 workspace
静态路由使用环境变量;动态路由使用 tracing context 或显式 client。
多目的地复制支持:
- array 形式可表达多个 endpoint/workspace/API key。
- primary 与 replica 使用确定性 run ID,便于对账。
- replica 发送失败不影响 primary,也不应阻断业务。
- Python 可用 OTel、LangSmith 或 hybrid 模式;文档当前说明 hybrid 只支持 Python。
文档中的 object 形式多 endpoint 示例使用了重复 JSON key;标准 JSON 无法保存两个同名 key。生产配置应使用数组形式,不要复制该 object 示例。
六、LangChain
设置环境变量后,Runnable 默认自动 tracing。重要行为:
- Python 可用 <code>tracing_context</code> 选择性启停;JS/TS 可传 <code>LangChainTracer</code> callback。
- tags 和 metadata 会从父 Runnable 继承给子 run;直接挂在某一模型实例上的配置只作用于该分支。
- <code>run_name</code> 只重命名被调用的 Runnable,不自动改内部 LLM run 名。
- 自定义 root <code>run_id</code> 会成为 trace ID,但当前不能直接给 LLM 对象指定该能力。
- Python 用 <code>wait_for_all_tracers</code>;JS 用 <code>awaitAllCallbacks</code> 等待提交。
- JS 非 serverless 可后台发送降低延迟;serverless 应关闭后台回调或显式等待。
LangChain JS 与 traceable 的互操作仍有边界:从 RunnableLambda 取到的 RunTree 不宜修改/遍历,极端并发下 execution order 可能相同,应依赖 start time 和真实层级。
七、LangGraph 与 Deep Agents
LangGraph:
- 使用 LangChain 模型/工具时,只需原生 tracing 配置。
- 使用裸 SDK 或自定义函数时,模型用 provider wrapper,工具用 traceable,才能正确嵌套。
- <code>configurable.thread_id</code> 是图持久化/会话标识的重要来源,但仍应在最终 trace 中验证 thread metadata。
Deep Agents:
- 基于 LangGraph,设置 LangSmith 环境变量即可自动 tracing;仅做自动 tracing 不要求单独安装 langsmith。
- 需要选择性 tracing、查询或自定义 metadata 时再安装 SDK。
- 子 Agent 产生的 run 使用 <code>lc_agent_name</code>,可在 Runs 视图或 SDK filter 中隔离。
- 一次 invoke 通常包含规划 LLM、tool、子 Agent 和最终响应;不要拆成多个无关 trace。
Claude Agent SDK:
- Python 使用 <code>configure_claude_agent_sdk</code>,JS/TS 使用 <code>wrapClaudeAgentSDK</code>。
- 会自动捕获 query、模型交互、tool 与 MCP 操作。
- 该页没有列出最低版本、脱敏和 flush 细节;生产采用前须以包 release/reference 补齐。
八、Human-in-the-loop 与后台任务
动态 interrupt/resume 适合生产人审:运行在明确节点暂停,收到批准/编辑/拒绝后以同一 checkpoint 恢复。
静态 breakpoint 更适合调试测试,不建议作为生产审批工作流,因为它与代码位置强绑定、状态语义较弱。
后台 run 必须在实际工作完成时结束,而不是在任务入队时结束。建议:
- 入队节点记录 task ID。
- worker 通过分布式父上下文创建子 run。
- 取消、超时、重试和死信都写入明确状态。
- 重试要有 attempt metadata,避免把多个尝试伪装成一个无错误 run。
九、直接 REST API
简单模式:
- <code>POST /runs</code> 创建,<code>PATCH /runs/{id}</code> 结束。
- 子 run 传 <code>parent_run_id</code>;服务端生成 trace ID 和 dotted order。
- 简单但慢、限额更低,且同步调用会影响业务。
高吞吐模式:
- <code>POST /runs/multipart</code> 批量 post/patch。
- 调用方必须生成 UUIDv7、trace ID 和 dotted order。
- multipart 每个 run 的主体、inputs、outputs、events 分 part。
- 需要连接池、批次上限、退避重试、幂等 ID、超时和丢弃策略。
官方示例偏教学:直接 requests 调用没有完整超时、重试、响应检查、批量队列和熔断;<code>serialize_run</code> 还会原地移除 inputs/outputs/events。生产实现应优先复用 SDK batching,不能直接照搬。
十、提交与关停
异步 tracing 的底线:
- CLI/短进程:finally 中等待所有 tracer。
- serverless:关闭后台发送或调用 SDK 的 pending batches/flush。
- worker:优雅关停先停止接单,再等待 tracing 队列,最后关闭 exporter。
- 非关键 tracing 失败通常不应让用户请求失败,但必须有丢弃计数、队列水位和错误日志。