AI CXYKK AI 教程
OB 安全治理篇:观测、Trace 和日志
安全治理篇 · AI 质量课程

观测、Trace 和日志

Agent 跑错了,你知道错在哪吗?不知道的话,下次还会再错。观测、Trace 和日志的作用,就是让每一次执行都有迹可循,出了问题能复盘,能审计,能找到根因,然后避免再犯。

要能看到全貌 一次请求经过了哪些步骤、调用了哪些工具、花了多长时间,都得有记录。
要能追溯细节 出了问题,能顺着 Trace 一路查下去,看到底是哪一步出了岔子。
要能复盘分析 不是只看到错误就完了,得分析为什么出错,怎么避免下次再出错。
要能持续改进 把失败案例沉淀下来,变成规则和测试,让系统越跑越稳。
trace-view span / log / error / replay
Trace 一次完整请求的执行轨迹,从入口到出口。
Span Trace 里的每个步骤,比如调用 LLM、查数据库、调工具。
Log 每个 Span 里的详细日志,记录输入输出和状态。
Trace
追踪
Span
步骤
Log
日志
Replay
复盘
01 · 为什么要做观测

没有观测,Agent 出错就是黑盒

你不知道它为什么这么回答,不知道它调了哪些工具,不知道它在哪里卡住了。出了问题,只能靠猜。

没有观测

靠猜排查问题

Agent 回答错了,你不知道它走了什么路径、看了什么资料、做了什么判断。只能重新跑一遍,指望能复现。

有观测

靠数据排查问题

Agent 回答错了,你能直接看 Trace,看到它第 3 步调用了错误的工具,第 5 步的 LLM 输入缺少关键上下文。

一句话面试版 可直接背

观测是让 Agent 系统可调试、可审计、可改进的基础。通过 Trace 记录执行轨迹,通过 Log 记录每一步的输入输出,出了问题能复盘根因,能把失败案例沉淀成规则,形成持续改进的闭环。

02 · 核心概念

Trace、Span 和 Log,三个概念要分清楚

这三个词经常混着用,但其实各有各的用处。搞清楚它们的关系,排查问题时才不会乱。

Trace

一次请求的完整轨迹

从用户发起请求开始,到最终返回结果结束,中间经过的所有步骤都串在一起。每个 Trace 有个唯一 ID,方便追踪。

Span

Trace 里的一个步骤

比如"调用 LLM"是一个 Span,"查询数据库"是另一个 Span。每个 Span 记录开始时间、结束时间、输入输出和状态。

Log

Span 里的详细记录

Span 是结构化的,Log 更灵活。可以记录调试信息、错误堆栈、业务状态等。Log 要带上 Trace ID 和 Span ID,才能关联起来。

Trace 数据结构示例 trace-example.json
{
  "traceId": "abc-123-def",
  "spans": [
    {
      "spanId": "span-1",
      "name": "receive_request",
      "startTime": "2026-06-12T10:00:00Z",
      "endTime": "2026-06-12T10:00:01Z",
      "status": "ok"
    },
    {
      "spanId": "span-2",
      "parentId": "span-1",
      "name": "call_llm",
      "startTime": "2026-06-12T10:00:01Z",
      "endTime": "2026-06-12T10:00:05Z",
      "status": "ok",
      "input": {"prompt": "..."},
      "output": {"text": "..."}
    },
    {
      "spanId": "span-3",
      "parentId": "span-1",
      "name": "query_database",
      "startTime": "2026-06-12T10:00:05Z",
      "endTime": "2026-06-12T10:00:06Z",
      "status": "error",
      "error": "connection timeout"
    }
  ]
}
03 · 层级结构

Trace 是一棵树,不是一条线

一次请求可能并行调用多个工具,每个工具又可能调用子工具。Trace 的层级结构能反映出这种父子关系。

Root Span 接收用户请求,整个 Trace 的起点。
Child Spans 调用 LLM、查询知识库、调用工具 A、调用工具 B...
并行执行 多个 Child Span 可以同时执行,互不阻塞。
嵌套调用 工具 A 内部又调用了子工具 A1、A2,形成更深的层级。
为什么要关心层级?
排查问题时,你要能快速定位到出问题的子 Span。如果只看顶层,根本看不出是哪个子步骤出了问题。层级结构让你能从上往下钻取,一步步接近根因。
04 · 日志分类

日志不是随便写,要分清楚类型和用途

不同类型的日志,记录的东西不一样,给谁看的也不一样。混在一起写,排查问题时很难过滤。

日志类型 记录什么 谁看 例子
业务日志 业务流程的关键节点 产品经理、运营 用户发起了退款请求,订单号 xxx
调试日志 开发调试信息 开发人员 LLM 输入 prompt 长度: 1234 tokens
错误日志 异常和错误堆栈 开发人员、运维 数据库连接超时,重试 3 次失败
审计日志 敏感操作记录 安全团队、合规 用户 xxx 删除了订单 yyy
性能日志 耗时和性能指标 运维、开发 LLM 调用耗时 3.2s,tokens 消耗 500
日志要带什么信息 必选
  • 1Trace ID 和 Span ID,用来关联上下文。
  • 2时间戳,精确到毫秒。
  • 3日志级别:DEBUG、INFO、WARN、ERROR。
  • 4日志内容,尽量结构化(JSON 格式)。
  • 5用户 ID、请求 ID 等业务标识。
结构化日志示例 structured-log.json
{
  "timestamp": "2026-06-12T10:00:05.123Z",
  "level": "INFO",
  "traceId": "abc-123-def",
  "spanId": "span-2",
  "userId": "user-456",
  "requestId": "req-789",
  "message": "call_llm",
  "metadata": {
    "model": "gpt-4",
    "promptTokens": 1234,
    "completionTokens": 567,
    "latencyMs": 3200
  }
}
05 · 如何实现

可观测性不是事后补丁,要从设计时就考虑

等你把系统写完了再想怎么加观测,通常会发现到处都要改。不如一开始就把 Trace 和 Log 的设计考虑进去。

1 选技术栈 OpenTelemetry、Jaeger、Zipkin,或者云厂商的方案。
2 埋点 在关键节点插入 Trace 和 Log 的埋点代码。
3 传递上下文 确保 Trace ID 和 Span ID 在整个调用链里传递。
4 收集和存储 把 Trace 和 Log 收集起来,存到可查询的系统里。
5 可视化和告警 提供查询界面,配置关键指标的告警。
OpenTelemetry 埋点示例 otel-example.py
from opentelemetry import trace

tracer = trace.get_tracer(__name__)

@tracer.start_as_current_span("call_llm")
def call_llm(prompt: str) -> str:
    span = trace.get_current_span()
    span.set_attribute("prompt.length", len(prompt))

    # 调用 LLM
    result = llm_client.complete(prompt)

    span.set_attribute("result.length", len(result))
    span.set_attribute("model", "gpt-4")
    return result
别忘了 LLM 的输入输出
传统系统的观测主要看性能和错误。Agent 系统不一样,LLM 的输入输出才是核心。要把 prompt 和 completion 都记录下来(注意脱敏),不然出了问题根本不知道 LLM 看到了什么、回答了啥。
06 · 错误复盘

出了问题,怎么快速定位根因

有观测不代表能自动找到问题。你得知道怎么查,从哪开始查,查到什么程度算够了。

复盘五步法 Method
  • 1复现问题:拿到用户反馈的错误现象和 Trace ID。
  • 2看全貌:打开 Trace,看整个执行流程,定位到出问题的 Span。
  • 3看细节:进入出问题的 Span,看它的输入输出和日志。
  • 4找根因:分析为什么出错,是数据问题、逻辑问题还是外部依赖问题。
  • 5沉淀改进:把根因记录下来,修复问题,更新规则和测试用例。
常见问题分类 Root Cause
  • 1上下文不足:LLM 没看到足够的信息,回答不准确。
  • 2工具调用错误:调了错误的工具,或者工具参数传错了。
  • 3检索失败:知识库没查到,或者查到了错误的内容。
  • 4逻辑错误:Agent 的推理过程有问题,做了错误的判断。
  • 5外部依赖:调用的 API 超时、返回错误、或者返回了意外的数据。
复盘报告模板 post-mortem.md
# 错误复盘报告

## 问题现象
用户在查询订单状态时,Agent 返回了错误的订单信息。

## Trace 分析
- Trace ID: abc-123-def
- 问题 Span: query_order (span-3)
- 错误类型: 查询参数错误

## 根因
Agent 在提取订单号时,把用户输入的"订单 12345"解析成了"1234",漏掉了最后一位。
原因是 prompt 里对订单号格式的描述不够明确。

## 修复措施
1. 更新 prompt,明确订单号是 5 位数字
2. 增加参数校验,不符合格式的要追问用户
3. 把这类错误加入测试集,防止复发

## 跟进
- 负责人: @张三
- 完成时间: 2026-06-15
07 · 审计追踪

不只是调试,还要能审计

审计是给合规、安全、法务看的。他们不关心技术细节,只关心谁在什么时候做了什么,有没有越权,有没有违规。

操作审计

谁做了什么

记录用户的每一个操作,特别是敏感操作,比如删除、修改权限、导出数据。

权限审计

有没有越权

记录 Agent 调用了哪些工具,访问了哪些数据,有没有超出权限范围。

合规审计

有没有违规

记录 Agent 的输出有没有违反合规要求,比如泄露敏感信息、承诺不该承诺的事。

审计项 记录什么 保留多久 谁来看
用户操作 用户发起的请求、上传的文件、修改的配置 至少 1 年 安全团队、客服
Agent 决策 Agent 选择了什么工具、传了什么参数、给了什么回答 至少 1 年 安全团队、产品
工具调用 调用了哪些外部 API、访问了哪些数据、修改了什么 至少 3 年 安全团队、合规
敏感数据 Agent 有没有接触到敏感数据、有没有泄露 至少 5 年 合规、法务
审计日志不能被篡改
审计日志一旦被写入,就不能被修改或删除。不然出了问题,日志被改了,就没法追溯了。要用追加写入的方式存储,或者用区块链之类不可篡改的技术。
08 · 持续改进

复盘不是终点,改进才是

找到根因、修复问题还不够。要把失败案例沉淀下来,变成规则和测试,让系统越跑越稳,避免同样的问题再出现。

改进闭环 Loop
  • 1发现问题:从用户反馈、监控告警、审计日志里发现异常。
  • 2复盘根因:用 Trace 和 Log 定位问题根因,写复盘报告。
  • 3修复问题:改 prompt、改逻辑、改工具、改护栏。
  • 4沉淀案例:把失败案例加入测试集,防止复发。
  • 5更新规则:把新发现的风险模式加入护栏和审计规则。
  • 6回归测试:每次改动都跑一遍测试集,确保没有引入新问题。
改进记录示例 improvement-log.json
{
  "issueId": "INC-2026-0612",
  "discoveredAt": "2026-06-12T10:00:00Z",
  "discoveredBy": "用户反馈",
  "traceId": "abc-123-def",

  "rootCause": "prompt 对订单号格式描述不明确",
  "impact": "返回错误的订单信息",

  "actions": [
    {
      "type": "prompt_update",
      "description": "明确订单号是 5 位数字",
      "completedAt": "2026-06-12T15:00:00Z"
    },
    {
      "type": "test_case_added",
      "description": "加入订单号解析错误的测试用例",
      "completedAt": "2026-06-12T16:00:00Z"
    },
    {
      "type": "validation_added",
      "description": "增加订单号格式校验",
      "completedAt": "2026-06-13T10:00:00Z"
    }
  ],

  "status": "resolved",
  "verifiedAt": "2026-06-14T09:00:00Z"
}
关键指标 Metrics
错误率

每 1000 次请求里有多少次出错。改进后应该持续下降。

复发率

同样的问题再出现的比例。沉淀案例后应该趋近于 0。

平均修复时间

从发现问题到修复完成的平均耗时。流程成熟后应该越来越短。

测试覆盖率

测试集覆盖的场景比例。每次失败后都应该提升。

09 · 工具选型

市面上有很多工具,但思路是通用的

不用纠结用哪个工具,重要的是理解核心概念。换工具的时候,思路能迁移。

OpenTelemetry

开源标准

CNCF 的开源项目,支持多种语言和框架。可以对接 Jaeger、Zipkin、Prometheus 等后端。

LangSmith

LangChain 官方

专为 LLM 应用设计的观测平台,能自动记录 LangChain 的调用链,支持调试和评估。

Datadog

云厂商方案

功能全面的可观测性平台,支持 Trace、Log、Metrics 的统一视图,适合企业级应用。

Jaeger

分布式追踪

Uber 开源的分布式追踪系统,适合微服务架构,能可视化调用链。

ELK Stack

日志分析

Elasticsearch + Logstash + Kibana,经典的日志分析和可视化方案。

Grafana

监控告警

数据可视化和告警平台,支持多种数据源,能展示 Trace、Log 和 Metrics。

选型考虑 问什么 为什么重要
语言支持 支持你的技术栈吗? 不支持的话,接入成本很高。
LLM 集成 能自动记录 LLM 调用吗? Agent 系统的核心是 LLM,这部分必须能观测到。
查询性能 查询速度快吗?支持复杂查询吗? 排查问题时,查询慢会严重影响效率。
存储成本 存储费用怎么算?数据保留多久? Trace 和 Log 的数据量很大,成本要控制好。
合规性 符合你们的合规要求吗? 有些行业对数据存储和访问有严格要求。
10 · 完整案例

从发现问题到持续改进,完整走一遍

用一个真实的案例,把前面讲的内容串起来。看看观测、Trace 和日志是怎么在实际工作中发挥作用的。

01
发现问题 客服反馈:用户问"我的订单到哪了",Agent 回答"您的订单已发货",但实际还没发货。
02
定位 Trace 拿到 Trace ID: abc-123-def,打开 Trace 视图,看到 Agent 调用了 query_order_status 工具。
03
查看细节 进入 query_order_status Span,看到返回结果是 {status: "shipped"},但这个状态是旧的缓存数据。
04
分析根因 根因:订单状态更新后,缓存没有及时刷新。Agent 读到了过期数据,给出了错误回答。
05
修复问题 1. 修复缓存刷新逻辑
2. Agent 回答前检查数据新鲜度
3. 增加"数据可能延迟"的提示
06
沉淀改进 1. 把这类问题加入测试集
2. 增加缓存过期监控
3. 更新审计规则:Agent 必须标注数据来源和时效
复盘报告 post-mortem-report.md
# 订单状态查询错误复盘

## 问题
用户询问订单状态,Agent 返回"已发货",实际未发货。

## Trace 分析
Trace ID: abc-123-def
问题 Span: query_order_status
错误原因: 读取了过期的缓存数据

## 根因
1. 订单状态更新后,缓存未在 5 分钟内刷新
2. Agent 没有检查数据时效性
3. 缺少"数据可能延迟"的提示

## 修复
1. 修复缓存刷新机制,状态变更后 1 分钟内刷新
2. Agent 回答前检查 last_updated 字段
3. 超过 5 分钟的数据,回答时标注"数据可能延迟"

## 改进
1. 测试集新增:缓存过期场景的测试用例
2. 监控新增:缓存延迟超过 1 分钟告警
3. 审计规则:Agent 必须标注数据来源和时效

## 跟进
- 负责人: @李四
- 完成时间: 2026-06-15
- 验证时间: 2026-06-16
- 结果: 回归测试通过,监控运行正常
11 · 面试问答

面试官问观测,怎么回答才显得有经验

不是背概念,而是要体现出你真正做过、踩过坑、有方法论。下面这些问题,都是面试官常问的。

问题 1:为什么 Agent 系统需要观测?

传统系统出错,看代码基本能猜到原因。Agent 系统不一样,它的行为是非确定性的,同样的输入可能走出完全不同的路径。没有 Trace 和 Log,出了问题根本不知道它走了什么路径、看了什么资料、做了什么判断。观测是调试、审计和改进的基础。

问题 2:Trace 和 Log 有什么区别?

Trace 是结构化的,记录的是一次请求的完整执行流程,有层级关系,能看到每一步的耗时和状态。Log 更灵活,记录的是具体的调试信息、业务事件、错误堆栈。Trace 像地图,能让你快速定位问题在哪个环节;Log 像放大镜,能让你看清楚那个环节到底发生了什么。

问题 3:你们怎么排查问题的?

我们有一套标准流程:拿到用户反馈和 Trace ID 后,先看 Trace 全貌,定位到出问题的 Span;然后进入那个 Span,看它的输入输出和日志;分析根因,是数据问题、逻辑问题还是外部依赖问题;最后写复盘报告,把失败案例加入测试集,更新规则和护栏,防止复发。

问题 4:审计日志和普通日志有什么区别?

审计日志是给合规、安全、法务看的,记录的是敏感操作和关键决策,比如用户删了什么数据、Agent 调了什么工具、访问了什么敏感信息。审计日志不能被篡改,要长期保留,通常至少 1 年,有些要 3 年甚至 5 年。普通日志主要是给开发调试用的,保留时间短一些。

问题 5:怎么保证观测系统本身不影响性能?

几个措施:采样,不是每个请求都记录,可以按比例采样或者只对关键路径全量记录;异步写入,Trace 和 Log 先写到本地缓冲区,后台异步发送到存储系统;批量发送,不要每条日志都发一次网络请求,攒一批再发;过滤,低级别的日志可以过滤掉,只记录有价值的信息。

问题 6:你们怎么把观测和改进闭环起来的?

每次发现问题,都会写复盘报告,把根因和修复措施记录下来。然后把失败案例加入测试集,更新护栏规则和审计规则。每次改动都跑回归测试,确保没有引入新问题。我们还有几个关键指标:错误率、复发率、平均修复时间、测试覆盖率。这些指标持续跟踪,能看到改进效果。

12 · 练习和速查

记住这条主线:能看到、能追溯、能复盘、能改进

学完这节,你应该能把"Agent 出错了"变成"Agent 出错了,我通过 Trace 定位到第 3 步的 LLM 调用缺少上下文,已经修复并加入测试集"。

练习任务 Practice
  • 1为你的 Agent 系统设计 Trace 结构,定义主要的 Span 类型。
  • 2设计日志规范:不同类型日志的格式、级别、必选字段。
  • 3模拟一个错误场景,写出完整的复盘报告。
  • 4列出你们的审计需求:哪些操作需要审计、保留多久。
  • 5设计改进闭环:发现问题后,怎么沉淀案例、更新规则。
  • 6选择合适的观测工具,说明选型理由。
一页速查卡 Cheatsheet
  • Trace一次请求的完整执行轨迹,用 Trace ID 串联。
  • SpanTrace 里的一个步骤,记录输入输出和状态。
  • LogSpan 里的详细记录,要带上 Trace ID 和 Span ID。
  • 复盘复现 → 定位 → 分析 → 修复 → 沉淀。
  • 审计记录敏感操作,不可篡改,长期保留。
  • 改进把失败案例变成规则和测试,持续优化。
面试项目表达模板 interview-script.md
我把 Agent 的可观测性设计成四层:

第一层是追踪层,用 Trace 记录每次请求的完整执行流程,从入口到出口,每个步骤都是一个 Span,记录输入输出和状态。

第二层是日志层,在 Span 里记录详细的业务日志、调试日志、错误日志和审计日志。所有日志都带上 Trace ID 和 Span ID,方便关联查询。

第三层是复盘层,出了问题,通过 Trace 快速定位到出问题的 Span,看它的输入输出,分析根因。写复盘报告,把失败案例加入测试集,更新规则和护栏。

第四层是审计层,记录所有敏感操作和关键决策,不可篡改,长期保留,满足合规要求。

这样做的目的是让 Agent 系统可调试、可审计、可改进。出了问题能复盘根因,能沉淀经验,能持续优化,而不是每次都靠猜。