AI 应用上线后怎么排查问题?日志与可观测性应该这样设计

上一篇文章讨论了 Memory。

Memory 让 AI 应用可以在可控范围内延续上下文。

但当一个 AI 应用真的上线后,仅仅能记住上下文还不够。

它还必须能被排查、被追踪、被复盘。

因为线上问题一定会出现。

模型可能回答异常。

Prompt 可能被错误拼接。

RAG 可能检索不到正确内容。

Tool 可能调用失败。

Workflow 可能卡在某个节点。

Agent 可能重复执行无效步骤。

Token 成本可能突然升高。

用户输入可能触发边界情况。

如果没有日志和可观测性,开发者只能靠猜。

而 AI 应用最怕的就是靠猜排查问题。

所以,从 Demo 走向工程化,日志与可观测性是必须补上的一层能力。

一、AI 应用的问题不只是代码报错

传统后端系统排查问题,通常关注:

  • 接口是否报错。
  • 数据库是否异常。
  • 响应时间是否过长。
  • 服务器资源是否不足。
  • 异常栈在哪里。

这些在 AI 应用里仍然重要。

但 AI 应用的问题更多。

例如:

模型没有报错,但回答质量很差。

接口返回 200,但用户觉得结果不对。

Tool 调用成功了,但用了错误参数。

RAG 检索返回了内容,但不是用户真正需要的内容。

Agent 执行完了,但路径明显绕远了。

Workflow 没有崩溃,但某个节点输出不合理。

Token 消耗没有报警,但单次请求成本比预期高很多。

这些问题不是普通异常栈能解释的。

它们需要更细的链路记录。

也需要专门面向 AI 应用的观测指标。

二、为什么 print 日志不够

很多 Demo 项目会这样写日志:

python 复制代码
print("start workflow")
print("call llm")
print("result:", result)

这在本地调试阶段还可以。

但上线后远远不够。

首先,print 没有结构。

你很难按用户、请求、模型、任务、错误类型去检索。

其次,print 很难串联链路。

一次用户请求可能包含多次模型调用、多次 Tool 调用、多次检索和多个 Workflow 节点。

如果没有统一 trace_id,很难知道这些日志属于同一次请求。

第三,print 容易泄露敏感信息。

开发阶段随手打印 Prompt、用户输入、接口参数,线上可能就会把隐私或密钥打进日志。

第四,print 不适合统计。

你很难从一堆文本中稳定统计模型耗时、Token 成本、失败率和工具调用次数。

所以,AI 应用需要结构化日志。

不是多打几行 print。

三、一次 AI 请求应该有 trace_id

AI 应用的调用链通常比较长。

例如一次问答请求可能是:

text 复制代码
用户请求
  ↓
解析输入
  ↓
加载 Memory
  ↓
RAG 检索
  ↓
构造 Prompt
  ↓
调用 LLM
  ↓
判断是否调用 Tool
  ↓
执行 Tool
  ↓
再次调用 LLM
  ↓
返回结果

如果每一步日志没有关联,排查问题会非常痛苦。

所以每次请求都应该生成一个 trace_id。

例如:

text 复制代码
trace_id = "req_20260711_100001_xxxx"

后续所有日志都带上这个 trace_id:

json 复制代码
{
  "trace_id": "req_20260711_100001_xxxx",
  "event": "llm_call_start",
  "model": "deepseek-chat",
  "workflow": "rag_workflow"
}

这样排查问题时,就能把一次请求下的所有事件串起来。

trace_id 是可观测性的基础。

没有 trace_id,日志只是散落的碎片。

四、请求日志应该记录什么

请求日志是入口层日志。

它回答的是:

谁在什么时候发起了什么类型的请求,最终结果如何。

请求日志可以记录:

text 复制代码
trace_id:请求链路 ID。
user_id:用户 ID 或匿名 ID。
endpoint:接口路径或入口名称。
method:请求方法。
request_type:请求类型。
status:成功或失败。
latency_ms:总耗时。
created_at:请求时间。
error_code:错误码。

例如:

json 复制代码
{
  "trace_id": "req_001",
  "event": "request_finished",
  "endpoint": "/chat",
  "status": "success",
  "latency_ms": 3420
}

请求日志不一定要记录完整用户输入。

很多时候只需要记录输入长度、类型、是否命中某类规则。

如果必须记录输入,也要做脱敏和权限控制。

五、模型调用日志应该记录什么

模型调用是 AI 应用最核心、也最容易出问题的地方。

模型调用日志应该至少记录:

text 复制代码
trace_id:请求链路 ID。
provider:模型供应商。
model:模型名称。
prompt_version:Prompt 版本。
input_tokens:输入 token。
output_tokens:输出 token。
total_tokens:总 token。
latency_ms:模型耗时。
status:成功或失败。
error_type:错误类型。
retry_count:重试次数。

例如:

json 复制代码
{
  "trace_id": "req_001",
  "event": "llm_call_finished",
  "provider": "openai",
  "model": "gpt-4.1",
  "prompt_version": "qa_v3",
  "input_tokens": 1200,
  "output_tokens": 360,
  "latency_ms": 2100,
  "status": "success"
}

这里有一个重点:

不要默认把完整 Prompt 和完整 Response 全部写进普通日志。

因为里面可能包含用户隐私、业务数据或敏感上下文。

更合理的做法是:

  • 默认记录结构化元数据。
  • 必要时记录脱敏后的摘要。
  • 调试环境可以打开详细日志。
  • 生产环境详细日志需要权限和保留周期。

六、Token 成本必须可观测

AI 应用和传统后端最大的不同之一,是模型调用有直接成本。

一次请求消耗多少 token,可能直接影响账单。

如果没有 Token 统计,很难发现成本异常。

需要观察的指标包括:

  • 单次请求平均 token。
  • 单个用户 token 消耗。
  • 单个 Workflow token 消耗。
  • 单个模型 token 消耗。
  • 每日总 token。
  • 输入 token 和输出 token 比例。
  • 重试导致的额外 token。

例如某个 Workflow 改版后,平均输入 token 从 1000 增加到 8000。

接口仍然正常。

用户也可能没有马上反馈。

但成本已经明显异常。

所以 Token 不是附属信息。

它应该是 AI 应用的核心指标。

七、Tool 调用日志应该记录什么

Tool 调用让 Agent 具备行动能力。

但 Tool 也是风险点。

每一次 Tool 调用都应该可追踪。

Tool 调用日志可以记录:

text 复制代码
trace_id:请求链路 ID。
tool_name:工具名称。
tool_version:工具版本。
permission_level:权限级别。
arguments_schema:参数结构。
latency_ms:执行耗时。
status:成功或失败。
error_type:错误类型。
result_size:结果大小。

例如:

json 复制代码
{
  "trace_id": "req_001",
  "event": "tool_call_finished",
  "tool_name": "search_docs",
  "permission_level": "read_only",
  "latency_ms": 320,
  "status": "success"
}

注意,不要随意记录完整参数。

比如文件路径、用户输入、业务 ID、接口返回,都可能包含敏感信息。

更稳妥的做法是记录参数结构和脱敏后的关键字段。

Tool 日志的目标不是把所有内容打出来。

而是让开发者能知道工具有没有被调用、调用是否成功、耗时多少、失败在哪里。

八、RAG 检索也需要日志

RAG 系统里,模型回答不好,问题不一定在模型。

很可能是检索阶段出了问题。

例如:

  • 没有检索到内容。
  • 检索到了错误文档。
  • top_k 设置不合理。
  • 相似度分数太低。
  • 文档切片质量差。
  • 过滤条件写错。

所以 RAG 检索也需要日志。

可以记录:

text 复制代码
trace_id:请求链路 ID。
query_length:查询长度。
collection:知识库名称。
top_k:召回数量。
hit_count:命中数量。
score_range:相似度范围。
latency_ms:检索耗时。
rerank_used:是否使用重排。

例如:

json 复制代码
{
  "trace_id": "req_001",
  "event": "retrieval_finished",
  "collection": "product_docs",
  "top_k": 5,
  "hit_count": 5,
  "latency_ms": 180
}

如果需要记录命中文档,也建议记录文档 ID、chunk ID 和分数。

不要默认记录完整原文内容。

九、Workflow 节点状态要能追踪

复杂 AI 应用通常不是一次模型调用。

它可能包含多个 Workflow 节点。

例如:

text 复制代码
load_memory
retrieve_docs
build_prompt
call_llm
parse_answer
call_tool
finalize_response

每个节点都应该有开始、结束、失败日志。

例如:

json 复制代码
{
  "trace_id": "req_001",
  "event": "workflow_node_finished",
  "workflow": "rag_workflow",
  "node": "retrieve_docs",
  "status": "success",
  "latency_ms": 210
}

这样当用户说结果慢时,可以看到慢在检索、模型、Tool,还是最终处理。

当结果错误时,也可以看是哪个节点开始偏离。

Workflow 可观测性的关键,是把黑盒流程拆成可追踪节点。

十、Agent step 也要能复盘

Agent 的问题往往更难排查。

因为 Agent 不是固定流程。

它可能根据上下文动态决定下一步。

所以 Agent step 需要记录。

可以记录:

text 复制代码
trace_id:请求链路 ID。
agent_name:Agent 名称。
step_index:步骤序号。
thought_type:步骤类型。
selected_tool:选择的工具。
decision_status:决策状态。
latency_ms:步骤耗时。

例如:

json 复制代码
{
  "trace_id": "req_001",
  "event": "agent_step",
  "agent_name": "research_agent",
  "step_index": 3,
  "selected_tool": "search_docs",
  "decision_status": "tool_call"
}

这里要注意:

不一定要记录完整推理过程。

很多场景只需要记录可审计的决策摘要。

例如选择了哪个 Tool、为什么进入某个分支、当前步骤是否成功。

这样既能复盘,又能降低敏感信息和冗余日志风险。

十一、错误日志要分层

AI 应用错误不能只分成成功和失败。

更合理的做法是分层。

例如:

text 复制代码
config_error:配置错误。
llm_error:模型调用错误。
retrieval_error:检索错误。
tool_error:工具调用错误。
workflow_error:流程错误。
validation_error:参数校验错误。
permission_error:权限错误。
rate_limit_error:限流错误。
timeout_error:超时错误。

这样做的好处是:

报警更准确。

统计更清楚。

排查路径更短。

例如都是失败,但模型限流和 Tool 参数错误完全是两类问题。

前者可能要调整重试、降级或额度。

后者可能要修 schema、Prompt 或参数校验。

错误日志越清晰,线上恢复越快。

十二、日志必须脱敏

日志不是越详细越好。

尤其是 AI 应用,输入输出里很容易包含敏感信息。

不能直接记录的内容包括:

  • API Key。
  • Token。
  • 密码。
  • 验证码。
  • 身份证号。
  • 手机号。
  • 邮箱。
  • 支付信息。
  • 用户隐私内容。
  • 原始大文件全文。

所以需要 Redactor,也就是脱敏模块。

例如:

python 复制代码
class Redactor:
    def redact(self, text: str) -> str:
        text = self.mask_api_keys(text)
        text = self.mask_phone_numbers(text)
        text = self.mask_emails(text)
        return text

在写日志之前先脱敏。

在保存 Prompt 或 Response 之前也要脱敏。

日志系统不能成为隐私泄露的入口。

十三、AI Scaffold 里的可观测性模块

在 AI Scaffold 中,可以把可观测性作为独立模块。

项目结构可以这样设计:

text 复制代码
app/
├── observability/
│   ├── __init__.py
│   ├── logger.py
│   ├── tracing.py
│   ├── metrics.py
│   ├── events.py
│   ├── redactor.py
│   └── exporters.py
├── llm/
│   └── client.py
├── tools/
│   └── registry.py
├── workflows/
│   └── rag_workflow.py
├── agents/
│   └── assistant_agent.py
└── config/
    └── settings.py

其中:

logger.py 负责结构化日志。

tracing.py 负责 trace_id 和链路追踪。

metrics.py 负责统计指标。

events.py 定义 AI 应用里的事件类型。

redactor.py 负责敏感信息脱敏。

exporters.py 负责对接外部日志平台或监控系统。

LLM、Tool、Workflow、Agent 都不应该各写一套日志逻辑。

它们应该统一发事件。

由 observability 模块负责记录、脱敏和导出。

十四、总结

AI 应用上线后,排查问题不能只靠 print。

因为 AI 应用的问题可能来自模型、Prompt、RAG、Tool、Workflow、Agent、Memory、配置、权限和用户输入。

一个合理的日志与可观测性设计,至少应该做到:

  • 每次请求有 trace_id。
  • 请求日志结构化。
  • 模型调用记录 provider、model、耗时和 token。
  • Token 成本可统计。
  • Tool 调用可追踪。
  • RAG 检索可复盘。
  • Workflow 节点状态可观察。
  • Agent step 可以审计。
  • 错误类型要分层。
  • 日志写入前必须脱敏。
  • 生产环境不要默认记录完整 Prompt 和 Response。
  • 可观测性模块要统一,而不是散落在各个业务模块里。

对于 AI Scaffold 来说,可观测性不是上线后的附加功能。

它应该从项目结构阶段就被考虑进去。

因为 AI 应用越复杂,越需要知道每一次结果是怎么来的。

能跑只是第一步。

能解释、能排查、能复盘,才是工程化系统真正可维护的开始。

下一篇文章可以继续讨论安全治理:

当 Agent 能调用 Tool、读取 Memory、访问外部系统时,如何设计权限边界、审计机制和 Prompt Injection 防护。

相关推荐
在世修行1 小时前
第17篇:晶粒尺寸统计算法 — 从像素到微米的转换
人工智能·计算机视觉·像素转换
万点科技码农1 小时前
2025年7月11日行业热点解读:定制软件开发与AI工作流重构一体化趋势
大数据·人工智能·重构
JL151 小时前
Agent工程-为什么Agent必须有观测和Tracing
服务器·网络·人工智能·安全
用户6954977099492 小时前
第 8 章 vLLM/LMDeploy/Triton 适配 DeepSeek 源码改造
人工智能
波动几何2 小时前
角色生成器character-builder
人工智能
dayuOK63072 小时前
AI Agent市场爆发:从“试一试”到“离不开”,只用了不到一年
大数据·人工智能·ai作画·新媒体运营·aigc·ai写作
茶马古道的搬运工2 小时前
AI 深度技能之-解读Hermes Agent(四)- Hermes Kanban 多 Agent 流水线
人工智能
海外数字观察家2 小时前
马来西亚商贸数字化落地指南:跨境批发、连锁零售首选ERP方案(品未云)
大数据·人工智能·马来西亚进销存系统·马来西亚收银系统·马来西亚erp系统·马来西亚仓库管理系统
珠海西格电力2 小时前
数据采集与治理:零碳园区管理系统的 “生命线”
大数据·人工智能·算法·架构·能源