用 Trace、事件和测试定位故障

每一步都可追踪

本章目标

让每次运行都能回答:走了哪条路径、状态如何变化、外部调用为何失败、成本是否超限。

启用 LangSmith

export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY='在本机设置,不要写入代码'
export LANGSMITH_PROJECT=langgraph-support-tutorial

不要使用旧教程中的 LANGCHAIN_TRACING_V2LANGCHAIN_API_KEY 作为新项目主配置。

运行配置中加入可过滤元数据:

config = {
    "configurable": {"thread_id": "tenant-a:T-100"},
    "tags": ["support", "refund"],
    "metadata": {"tenant_id": "tenant-a", "ticket_id": "T-100"},
}

Trace 和日志不得记录密钥、完整个人信息、支付凭证或不必要的原始对话。

排查顺序

一次运行如何排查

  1. 检查节点路径与条件边选择。
  2. 检查每个节点返回的局部更新。
  3. 检查模型、工具和数据库耗时及重试次数。
  4. 检查 token、步骤数和费用预算。
  5. 检查中断前是否发生非幂等副作用。

本地读取状态:

snapshot = await graph.aget_state(config)
print(snapshot.values)
print(snapshot.next)

history = [item async for item in graph.aget_state_history(config)]

不伪造观测数据

教程不提供虚构的“耗时 0.823 秒、Token 158”作为运行证据。实际数据依赖模型、网络、节点实现和追踪环境,应从自己的 Trace 中读取,并注明测试环境。

测试、日志和 Trace 各自解决不同问题:

三类证据各有职责

  • 测试防止行为回归。
  • 日志记录业务事件和异常。
  • Trace 解释一次运行内部的调用树和状态流。

统一关联标识

一次请求可能经过网关、API、图节点、模型和多个工具。至少贯穿以下标识:

request_id, run_id, thread_id, tenant_id, ticket_id,
checkpoint_id, node_name, idempotency_key

日志使用结构化字段,不要把它们拼进一段难以检索的消息:

logger.info(
    "order_lookup_finished",
    extra={
        "thread_id": thread_id,
        "ticket_id": ticket_id,
        "node_name": "query_order",
        "duration_ms": duration_ms,
        "outcome": "success",
    },
)

tenant_id 可以用于授权和过滤,但日志平台仍需租户级访问控制。问题全文、模型提示词和工具返回默认不进入日志;确需保留时进行字段级脱敏、加密和保留期审批。

用一次故障走完整排查链

以“订单查询先超时一次后成功”为例:

  1. API 日志确认 request_idthread_id 和调用入口。
  2. Trace 显示 query_kb 一次成功,query_orderTimeoutError 重试两次。
  3. 节点更新证明技术重试没有增加业务字段 attempts
  4. 工具指标显示订单 API 首次超时、第二次成功及总延迟。
  5. 最终状态停在审批点,证明没有因为技术故障提前执行退款。

仓库测试 test_order_lookup_technical_retry_recovers 提供确定性故障源;接入 LangSmith 后应在自己的环境中保存对应 Trace 链接或截图,而不是在教程里伪造数值。

指标、SLO 与告警

至少采集:

类型指标示例
流量每租户运行数、节点调用数、SSE 连接数
延迟运行端到端、节点、模型和工具 P50/P95/P99
错误永久失败率、重试率、人工接管率、恢复失败率
资源PostgreSQL 连接池、队列深度、Worker 并发
成本输入/输出 token、模型调用数、单工单费用
业务安全重复副作用拦截数、未知执行结果数、超时审批数

告警必须对应可执行 Runbook。例如“Checkpoint 写入失败率持续五分钟超过阈值”应指导值班人员检查数据库连接池、磁盘、锁等待和最近发布,并明确是否暂停新运行。

故障注入清单

  • 让一个工具返回 429、503、永久 400 和畸形 JSON。
  • interrupt() 后、退款前重启进程。
  • 在退款成功后、状态写回前终止 Worker。
  • 断开 PostgreSQL,验证 readiness 和恢复行为。
  • 让客户端缓慢读取或中断 SSE。
  • 提交相同审批和相同运行请求。

每次实验都应给出预期路径、告警、最终状态和禁止发生的副作用。

本章验收

  • 能通过一个关联标识从 API 日志追到 Trace、工具调用和业务记录。
  • 能从真实 Trace 解释一次重试和一次中断恢复。
  • 已定义延迟、错误、成本和业务安全指标及告警阈值。
  • 日志与 Trace 有字段白名单、脱敏规则和保留期。