传统服务出错时,可以查看状态码、日志和调用链。LLM 应用即使返回 200,也可能答非所问、成本异常或工具调用错误。
因此 LLMOps 的可观测对象不只是服务器,还包括 Prompt、模型、知识检索、工具调用、Token、费用和最终输出。Dify 将这些信息组织成 Trace,并可导出到多种观测平台。
本文介绍 AI 应用应该观测什么,以及如何避免追踪系统反过来影响主链路或泄露数据。
一、为什么普通监控不够
一次“回答质量差”可能由多种原因造成:
- Prompt 模板或变量拼装错误;
- 对话历史被错误截断;
- RAG 没有召回正确文档;
- Rerank 把相关结果排到后面;
- 模型版本或参数发生变化;
- Agent 选错工具或重复调用;
- 工具返回异常但被模型掩盖;
- 输出审核截断了最终内容。
CPU、内存和 HTTP 延迟无法解释这些问题。必须还原一次调用内部经历了什么。
1.1 三类可观测数据
| 类型 | 例子 | 主要用途 |
|---|---|---|
| Metrics | 延迟、Token、费用、失败率 | 看趋势和告警 |
| Logs | 错误、节点状态、规则命中 | 定位具体事件 |
| Traces | Workflow、Node、Model、Tool 父子关系 | 还原完整链路 |
三者互补:指标发现异常,Trace 缩小范围,日志解释细节。
二、Dify 的追踪层级
2.1 一次请求的层次
flowchart TB
Request["Conversation / API Request"] --> Workflow["Workflow Run"]
Workflow --> Node1["Knowledge Retrieval"]
Workflow --> Node2["LLM Node"]
Workflow --> Node3["Agent Node"]
Node1 --> Retrieve["Dataset Retrieval"]
Node2 --> Model["Model Invocation"]
Node3 --> Tool["Tool Invocation"]
Node3 --> Model2["Model Invocation"]
需要稳定标识:
trace_id:整条链路;span_id:某个步骤;parent_span_id:父子关系;workflow_run_id:工作流执行;node_execution_id:节点执行;conversation_id、message_id:对话上下文;tenant_id、app_id:数据归属。
没有统一 ID,数据库日志、模型日志和外部 Trace 平台就无法关联。
2.2 Trace 事件
Dify 的 TraceTask 覆盖多种对象:
- Conversation 与 Message;
- Workflow 与 Node Execution;
- LLM 与 Prompt Generation;
- Dataset Retrieval;
- Tool Invocation;
- Moderation;
- Suggested Questions。
每种事件结构不同,但最终都应转换成统一的 Trace/Span 模型。
2.3 节点数据
一个节点至少应记录:
1 | { |
输入输出帮助复现问题,但也最容易包含隐私和密钥,不能默认无限期完整保存。
三、模型调用应该记录什么
3.1 基础维度
- Provider、模型名和版本;
- 流式或非流式;
- Temperature、Top P、Max Tokens;
- 输入与输出 Token;
- 首 Token 延迟和总延迟;
- 重试次数和结束原因;
- Prompt 模板版本;
- 工具数量与结构化输出模式。
3.2 时间指标
模型调用不能只记录总耗时:
1 | 总延迟 = 排队 + DNS/连接 + 供应商处理 + 流式传输 |
关键指标:
- TTFT:从请求发出到首个 Token;
- TPOT:后续每 Token 平均时间;
- E2E Latency:从用户请求到最终响应完成;
- Queue Time:进入执行器到真正调用模型。
TTFT 变慢可能是供应商排队,E2E 变慢也可能是 RAG 或工具耗时。
3.3 费用
1 | 模型费用 = 输入 Token × 输入单价 + 输出 Token × 输出单价 |
Agent 还需要汇总每轮模型与工具费用。单次请求便宜,不代表工作流整体便宜。
价格配置应带版本和币种。供应商调价后,历史账单不能用新价格重新计算。
四、异步 Trace 导出
4.1 为什么不能同步上报
如果每个节点结束都同步请求外部平台:
- 观测平台抖动会增加用户延迟;
- 外部故障可能拖垮工作流;
- 节点多时产生大量网络请求;
- Trace 写入超时会占用业务连接。
Dify 使用 TraceQueueManager 产生任务,再由异步任务处理外部上报。
flowchart LR
Runtime["Workflow Runtime"] --> QueueManager["TraceQueueManager"]
QueueManager --> Queue["Ops Trace Queue"]
Queue --> Worker["Trace Worker"]
Worker --> Adapter["Provider Adapter"]
Adapter --> Langfuse["Langfuse"]
Adapter --> LangSmith["LangSmith"]
Adapter --> Others["Phoenix / MLflow / Opik ..."]
业务主链路只负责投递轻量事件,失败时也不应让用户请求失败。
4.2 队列设计
- Trace 任务具有明确 Schema 与版本;
- 队列设置容量,防止观测数据挤占业务资源;
- 上报失败有限重试并进入死信记录;
- 批量发送降低网络开销;
- 相同 Trace 内事件保持可重建顺序;
- Worker 水平扩展时使用幂等事件 ID;
- 积压严重时可采样或降级,而不是阻塞主流程。
4.3 Provider Adapter
Dify 通过适配器支持 Langfuse、LangSmith、Opik、Weave、Arize/Phoenix、MLflow 等平台。内部事件只定义一次,各适配器负责字段映射。
这和模型 Provider 的设计类似:核心系统依赖统一协议,第三方差异留在边界层。
五、从观测到排障
5.1 回答质量差
按链路检查:
- 用户输入是否正确进入变量池;
- Prompt 模板版本是否符合预期;
- RAG Query 是否正确;
- 召回文档、分数与 Rerank 顺序;
- 最终送入模型的消息;
- 模型、参数和结束原因;
- 输出是否被后处理或审核修改。
5.2 延迟升高
| 现象 | 可能原因 |
|---|---|
| 所有节点都慢 | Worker 排队或基础设施问题 |
| 只有 LLM TTFT 慢 | 模型供应商排队或网络问题 |
| 检索节点慢 | 向量库、Embedding 或过滤条件 |
| 工具节点慢 | 第三方 API 或沙箱冷启动 |
| 最后才变慢 | 输出审核、持久化或流式连接阻塞 |
Trace 的价值是把“请求慢”拆成具体 Span。
5.3 成本突增
常见原因:
- 对话历史没有正确裁剪;
- RAG 返回过多长文本;
- Agent 重复调用模型;
- Prompt 意外包含大变量;
- 切换到更昂贵模型;
- 失败重试重复计费。
告警应同时包含模型、应用、租户、Token 和调用轮数。
六、隐私与多租户隔离
Trace 可能包含用户问题、知识库内容、工具结果、文件地址和模型凭证,敏感度往往高于普通日志。
6.1 最小化原则
- 默认记录元数据和摘要,不默认记录全部正文;
- 对 Authorization、Cookie、API Key 和密码字段脱敏;
- 支持按应用关闭输入输出采集;
- 对个人信息做删除或哈希化;
- 设置独立保留周期;
- 导出到第三方前获得组织授权;
- 用户删除数据时同步清理相关 Trace。
6.2 租户边界
- Trace 查询必须带
tenant_id; - 外部平台的 Project 或 Dataset 按租户/环境隔离;
- Provider 配置和缓存键包含应用、租户;
- Trace SDK 实例不能错误复用其他租户的凭证;
- 后台任务携带明确身份,不能只靠全局上下文。
异步线程、全局 SDK 和缓存是最容易发生跨租户串数据的位置。
七、指标与告警建议
7.1 系统指标
- Workflow 成功率、P50/P95/P99 延迟;
- Node 各类型失败率和耗时;
- 模型 TTFT、吞吐和限流率;
- Tool 调用成功率;
- RAG 召回耗时和空结果率;
- Trace 队列长度、丢弃量和导出失败率。
7.2 业务与质量指标
- 每次会话平均 Token 与费用;
- Agent 平均迭代次数;
- 用户点赞、点踩和重新提问率;
- 引用覆盖率和无依据回答率;
- 人工转接率;
- Prompt/模型版本之间的质量差异。
可观测性告诉我们发生了什么,评测系统才判断回答是否足够好,两者不能互相替代。
八、总结
Dify 的 Trace 体系体现了以下原则:
- Trace 按请求、工作流、节点、模型和工具组织父子关系;
- 统一 ID 串联数据库记录、运行事件和外部平台;
- 模型调用同时记录质量上下文、延迟、Token 和费用;
- Trace 通过独立队列异步导出,不阻塞业务;
- Provider Adapter 屏蔽不同观测平台协议;
- 观测失败不能影响用户请求;
- 输入输出采集遵循最小化、脱敏和保留周期;
- 缓存、SDK 实例和异步任务都必须保持租户隔离;
- 指标、日志、Trace 和离线评测共同构成 LLMOps 闭环。
好的可观测性不是保存所有内容,而是在成本和隐私可控的前提下,让一次 AI 决策可以解释、定位和比较。