Skip to content

LLM应用架构与可观测性

从架构认知到技术栈拆解,再到可观测性落地 · 测试人员的必备视角

这篇怎么学

本讲是全课程最"偏开发"的一讲,但目标不是让你写代码,而是让你看得懂架构、读得懂链路、找得到问题。建议按"认知 → 技术栈 → 可观测性 → 实操"四层递进学习,先建立全局视图,再深入每个技术栈的测试关注点。

第1章:为什么测试人员要懂应用架构

1.1 不懂架构只能做黑盒

传统软件测试里,不懂架构也能写用例、点页面、发请求。但在 LLM 应用中,一个用户问题的回答可能经过了检索、重排、Prompt 拼接、模型推理、后处理五个以上环节。如果你不知道这些环节的存在,当回答出错时,你只能说"回答不对",却说不清到底是哪一层出了问题。

不懂架构的测试人员:不懂架构的测试人员 只能报告"回答不准确" 无法判断是检索问题还是生成问题 写的 Bug 描述让开发无法定位 测试策略只有"问一遍看结果" 懂架构的测试人员:懂架构的测试人员 能定位到"检索层返回了无关文档" 能区分 Prompt 模板问题和模型能力问题 能按分层设计针对性测试用例 能和开发用同一套语言沟通

1.2 懂架构能做分层定位

LLM 应用的问题定位本质上是一个链路分层排查的过程。以 RAG 应用为例:

错误现象可能的问题层定位方式
回答内容完全编造检索层未命中 / Prompt 未注入上下文查看检索结果是否为空
回答引用了错误文档检索层 / Rerank 层对比召回文档与预期文档
回答内容正确但格式混乱Prompt 模板 / 后处理层检查 Prompt 中的格式指令
回答速度极慢模型推理层 / 向量检索层查看各环节延迟分布
回答中出现敏感内容内容审核层 / 模型本身检查是否有审核过滤器

1.3 测试人员需要懂到什么程度

测试人员的架构认知三层

  1. 知道有什么:知道链路上有哪些组件,各自负责什么
  2. 知道怎么连:知道数据从用户输入到最终输出流经了哪些节点
  3. 知道哪里可能出错:知道每个节点的典型失败模式和可测试点 你不需要能写 LangChain 代码,但你需要知道 Chain 的执行顺序;你不需要能部署 Milvus,但你需要知道向量检索的 Top-K 和阈值会影响回答质量。

第2章:LLM应用架构全景图

2.1 典型架构六层模型

一个完整的 LLM 应用从用户输入到最终输出,通常经过以下六层: 👤 用户 ↓ 前端 (Web / App / API) ↓ API 网关 (鉴权 / 限流 / 路由) ↓ 应用层 (LangChain / Dify / 自研) ↓ 大模型 API (GPT / Claude / 文心 / 通义) ↕ 应用层还会调用以下外部资源 🔧 工具 / 插件 📚 知识库 / 向量DB 🗄️ 业务数据库

2.2 每一层的测试关注点

层级核心职责测试关注点
前端层用户交互、消息收发、流式渲染输入长度限制、流式渲染中断、Markdown 渲染
API 网关鉴权、限流、路由转发Token 过期、并发限流、超时配置
应用层Prompt 编排、Chain 编排、RAG、Agent 调度Prompt 注入、Chain 中断、上下文截断
模型层文本生成、推理幻觉、一致性、安全过滤、Token 消耗
工具/插件搜索、计算、API 调用工具选择正确性、参数传递、超时
知识库文档存储、向量检索召回率、相关性、索引更新延迟
数据库会话记录、用户数据数据一致性、历史记录准确性

关键认知

LLM 应用的架构和传统 Web 应用最大的区别在于:模型层是非确定性的。同样的输入可能产生不同的输出,这意味着测试策略不能只靠"断言精确值",还需要引入语义评估和统计方法。

第3章:LangChain / LlamaIndex

3.1 是什么、解决什么问题

LangChain 和 LlamaIndex 是目前最流行的两个 LLM 应用开发框架。它们的核心价值是把"调用大模型"这件事从一次 API 调用,扩展为可编排、可扩展、可追溯的应用链路

框架定位核心优势适用场景
LangChain通用 LLM 应用编排框架Chain/Agent/Tool 编排灵活对话系统、Agent、复杂工作流
LlamaIndex数据索引与检索增强框架数据连接和检索能力强知识库问答、文档检索、RAG

3.2 LangChain 核心概念

概念作用类比
Chain将多个步骤串联成一条执行链流水线上的工序
Agent让 LLM 自主决定调用哪些工具自主决策的调度员
Memory管理多轮对话的上下文记忆对话的"短期记忆"
Retriever从知识库中检索相关文档图书馆管理员
ToolAgent 可调用的外部能力工具箱里的具体工具
Prompt Template结构化管理提示词模板填空题的模板

3.3 LangChain 模块关系图

LangChain 核心模块关系 用户输入 ↓ Prompt Template(模板渲染) ↓ Chain / Agent(编排 & 决策) ↓ LLM 调用 Retriever 检索 Tool 工具调用 ↓ Memory(上下文管理) ↓ 输出给用户

3.4 测试人员要关注什么

LangChain/LlamaIndex 的关键测试点

  • Chain 的步骤执行顺序:是否按预期顺序执行,中间步骤是否可追溯
  • Prompt 模板变量注入:变量是否正确填充,特殊字符是否转义
  • Memory 的上下文管理:多轮对话是否正确保持上下文,上下文窗口截断策略
  • Agent 的工具选择:是否选择了正确的工具,工具调用参数是否正确
  • 异常处理:某个步骤失败后整条 Chain 的行为

第4章:Dify / Coze 等低代码平台

4.1 低代码平台的架构模式

Dify、Coze、FastGPT 等低代码平台的核心思路是:把 LangChain 那套代码逻辑,变成可视化的拖拽配置。开发者不需要写 Python 代码,就能搭建出一个完整的 LLM 应用。

可视化画布 → 工作流引擎 → 节点执行器 → LLM / 工具 / 知识库 → 结果输出

4.2 工作流/Agent 的运行机制

模式运行方式适用场景
工作流模式按预定义节点顺序依次执行流程固定的业务(客服、报告生成)
Agent 模式LLM 自主决策执行路径需要灵活决策的场景(研究助手)
混合模式固定流程中嵌入 Agent 决策节点兼顾可控性和灵活性

4.3 和代码开发的区别

代码开发(LangChain):代码开发(LangChain) 完全掌控每一行逻辑 调试靠日志和断点 版本管理靠 Git 测试用 pytest + 单元测试 灵活但门槛高 低代码平台(Dify/Coze):低代码平台(Dify/Coze) 通过可视化配置搭建流程 调试靠平台内置日志面板 版本管理靠平台快照 测试靠平台预览 + 手动验证 上手快但灵活度受限

4.4 测试策略差异

维度代码开发低代码平台
单元测试可针对每个函数写测试只能测试单个节点的输入输出
集成测试Mock 依赖服务依赖平台的预览功能
回归测试CI/CD 自动化需导出配置 + 用 API 回归
链路追踪集成 LangFuse 等工具使用平台内置日志
版本对比Git diff平台快照对比(能力有限)

低代码平台测试的最大风险

低代码平台上线速度快,但测试手段少。最常见的问题是:配置改了一个小参数(比如 Temperature 从 0.3 改成 0.7),没有任何测试覆盖,直接上线后发现回答质量下降。建议对关键工作流建立 API 级别的自动化回归。

第5章:RAG 系统技术栈详解

5.1 完整技术栈

组件职责主流选型测试关注
文档加载器读取各种格式文档LangChain Loader、UnstructuredPDF/Word/Excel 解析准确性
文本切分器把文档切成适合检索的片段RecursiveCharacterSplitter、TokenSplitter切分粒度、上下文丢失
Embedding 模型将文本转成向量表示OpenAI Ada、BGE、M3E、Cohere语义相似度、多语言支持
向量数据库存储和检索向量Milvus、Pinecone、Qdrant、Weaviate查询延迟、召回率、索引更新
Rerank 模型对初步召回结果精排Cohere Rerank、BGE Reranker、JinaAI排序准确性、延迟开销
Prompt 拼接将检索结果注入提示词LangChain PromptTemplate上下文截断、格式正确性
LLM 生成基于上下文生成回答GPT-4o、Claude、文心、通义幻觉、忠实度、安全性

5.2 向量数据库选型对比

数据库部署方式核心特点适合场景
Milvus自部署 / Zilliz Cloud高性能、分布式、生态好大规模生产环境
Pinecone全托管 SaaS零运维、开箱即用快速上线、不想维护基础设施
Qdrant自部署 / CloudRust 编写、性能优异中小规模高性能场景
Weaviate自部署 / Cloud支持混合搜索(向量+关键词)需要混合检索策略
Chroma嵌入式 / 自部署轻量、开发友好原型验证、小规模项目

5.3 数据入库流程

RAG 数据入库流程(Indexing Pipeline) 原始文档 PDF / Word / HTML ↓ 文档加载器 解析 & 提取文本 ↓ 文本切分器 按策略切分为 Chunk ↓ Embedding 模型 文本 → 向量 ↓ 向量数据库 存储向量 + 元数据

5.4 查询流程

用户提问 → Query Embedding → 向量检索 Top-K → Rerank 精排 → Prompt 拼接 → LLM 生成 → 输出回答

5.5 测试人员要关注哪些组件

RAG 系统测试的五个关键卡口

  1. 文档解析准确性:表格、图片、特殊格式是否被正确提取
  2. 切分质量:切分后的片段是否保持了语义完整性
  3. 检索召回率:相关文档是否被检索到,Top-K 设置是否合理
  4. Rerank 排序:最相关的文档是否排在最前面
  5. 生成忠实度:回答是否忠于检索到的上下文,而非编造

第6章:Agent 框架运行机制

6.1 主流 Agent 范式

范式运行方式优势典型风险
ReAct思考 → 行动 → 观察 → 循环推理过程可追溯循环次数过多、死循环
Plan-and-Execute先制定计划,再逐步执行适合复杂多步任务计划不合理、执行偏离
Multi-Agent多个 Agent 协作完成任务可分工协作协调开销大、职责模糊

6.2 ReAct 执行循环

ReAct 循环:Thought → Action → Observation

🤔 Thought LLM 推理思考 → 🔧 Action 调用工具/API → 👁️ Observation 获取执行结果 ↩

循环直到 LLM 认为可以给出最终回答

6.3 LangGraph 的状态图模型

LangGraph 是 LangChain 团队推出的 Agent 编排框架,核心思想是用**有限状态机(FSM)**来管理 Agent 的执行流程。每个节点是一个处理步骤,边上带有条件判断。

概念含义测试关注
State图中流转的数据状态状态字段是否正确更新
Node一个处理步骤(LLM 调用/工具调用/逻辑判断)节点输入输出是否正确
Edge节点之间的连接条件分支是否走对
Conditional Edge基于状态决定下一步走哪个节点边界条件下路由是否正确
Checkpoint状态快照,支持回溯和恢复中断恢复后状态是否一致

6.4 工具注册与调用机制

Agent 的能力边界由它可以调用的工具决定。工具注册通常包含三个要素:

# LangChain 工具定义示例
from langchain.tools import tool

@tool
def search_knowledge_base(query: str) -> str:
    """在知识库中搜索与用户问题相关的文档。
    
    Args:
        query: 用户的搜索关键词
    
    Returns:
        与查询最相关的文档片段
    """
    results = vector_store.similarity_search(query, k=5)
    return "\n".join([doc.page_content for doc in results])

Agent 测试的关键链路

  1. 工具选择:面对具体问题,Agent 是否选了正确的工具
  2. 参数构造:传给工具的参数是否合理、完整
  3. 结果解读:工具返回结果后,Agent 是否正确理解并继续
  4. 循环控制:是否存在无限循环,最大步数限制是否生效
  5. 错误恢复:工具调用失败后,Agent 是否能换一种策略

第7章:什么是 LLM 可观测性

7.1 传统 APM vs LLM 可观测性

传统 APM(Application Performance Monitoring):传统 APM(Application Performance Monitoring) 关注:延迟、错误率、吞吐量 输入/输出是确定性的 监控指标明确、阈值清晰 工具:Datadog、New Relic、Prometheus LLM 可观测性(LLM Observability):LLM 可观测性(LLM Observability) 关注:延迟 + Token 成本 + 回答质量 输入/输出是非确定性的 需要追踪 Prompt → 检索 → 生成全链路 工具:LangFuse、LangSmith、Phoenix

7.2 核心概念

概念含义类比
Trace一次完整的请求处理过程一个完整的订单从下单到完成
SpanTrace 中的一个步骤订单中的某个处理环节
Generation一次 LLM 调用(特殊的 Span)Chef 做菜的那个环节
示例

一次 RAG 请求在可观测性系统中的 Trace 结构:

Trace: "用户提问:公司的退款政策是什么?"
├── Span: Query 预处理 (12ms)
├── Span: Embedding 生成 (45ms)
├── Span: 向量检索 Top-5 (23ms)
├── Span: Rerank (67ms)
├── Generation: GPT-4o 调用 (1,340ms)
│   ├── Input tokens: 1,520
│   ├── Output tokens: 380
│   └── Cost: $0.034
└── Span: 后处理 & 返回 (5ms)
总耗时: 1,492ms | 总 Token: 1,900 | 总费用: $0.034

7.3 为什么 LLM 应用更需要可观测性

特性传统应用LLM 应用可观测性需求
确定性同输入同输出同输入不同输出极高 需要追踪每次输出
链路长度通常 3-5 层可能 10+ 步骤高 需要细粒度 Span
成本边际成本低每次调用都有 Token 费用高 需要成本监控
质量评估断言即可需要语义级评估中高 需要质量打分
调试难度看日志定位Prompt + 模型行为交织极高 需要完整上下文回放

第8章:可观测性要看什么

8.1 十个关键监控指标

#指标含义告警阈值参考
1请求量每分钟/小时的 LLM 调用次数突增 >200% 或骤降 >50%
2延迟分布P50/P90/P99 响应时间P99 > 10s
3Token 消耗Input/Output Token 使用量单次请求 > 8K tokens
4费用按时间/用户/功能的费用统计日费用超预算 150%
5错误率LLM 调用失败、超时、限流的比例> 5%
6幻觉率回答中包含编造内容的比例> 10%(采样评估)
7用户满意度点赞/点踩比例点踩率 > 20%
8模型版本当前使用的模型和版本模型切换后质量下降
9Prompt 版本当前使用的 Prompt 模板版本Prompt 变更后回归测试
10检索命中率RAG 查询中检索到相关文档的比例命中率 < 60%

8.2 告警规则设计

告警级别触发条件处理方式
P0 严重LLM API 全部超时或不可用立即切换备用模型,通知 on-call
P0 严重日费用超预算 300%限流或暂停服务,排查异常调用
P1 重要错误率 > 10% 持续 5 分钟排查模型状态和网络问题
P1 重要P99 延迟 > 15s 持续 10 分钟检查模型负载和排队情况
P2 一般检索命中率下降 > 20%检查知识库索引状态
P2 一般用户点踩率上升 > 10%采样分析 Bad Case

8.3 线上质量持续监控策略

三道防线

  1. 实时监控:请求量、延迟、错误率、Token 消耗 → Grafana / 云监控
  2. 每日采样评估:随机抽取 N 条对话,用评估模型或人工打分 → LangFuse Annotation
  3. 周度回归测试:用标准测试集跑一遍,检查质量是否有回退 → CI/CD Pipeline

第9章:用户反馈转化为测试用例

9.1 反馈收集机制

反馈方式信息量实现成本处理方式
👍 / 👎 按钮低(只知道好坏)极低统计比例,筛选 Bad Case
多维评分(准确性/有用性/流畅性)按维度分析薄弱环节
文字反馈NLP 分类 + 人工审核
"正确答案"提交极高直接作为 Ground Truth

9.2 从 Bad Case 到测试用例的转化流程

收集用户反馈 → 筛选 Bad Case → 分析根因 → 生成测试用例 → 加入回归集 → 持续监控

示例

转化案例: 用户反馈:"问'上季度销售额是多少',系统编造了一个数字。"

  • 根因分析:知识库中没有最新季度的销售数据,RAG 未检索到相关文档,LLM 自行编造
  • 测试用例:当知识库中不存在相关信息时,系统应回答"暂无该数据"而非编造
  • 检查点:① 检索结果是否为空;② Prompt 中是否有"无信息时不要编造"的指令;③ 回答是否承认信息不足

9.3 持续改进闭环

反馈 → 测试 → 优化 闭环

用户反馈 → Bad Case 库 → 回归测试集 → 优化 Prompt/RAG → 上线验证

↻ 持续循环

关键原则

每一个线上 Bad Case 都应该变成一条回归测试用例。如果同类问题反复出现,说明根因没有被修复。回归测试集的增长速度反映了系统质量治理的力度。

第10章:LangFuse 实操

10.1 LangFuse 是什么

LangFuse 是目前最流行的开源 LLM 可观测性平台,功能覆盖 Trace 追踪、Prompt 管理、评估打分、成本统计。

能力说明
Trace 追踪记录每次请求的完整链路(Span + Generation)
Prompt 管理版本化管理 Prompt 模板,支持 A/B 测试
评估打分支持人工标注和模型自动评分
成本统计按模型/用户/时间维度统计 Token 和费用
数据集管理管理测试用例集,支持批量评估

10.2 安装部署

# Docker 自部署(推荐用于内网环境)
git clone https://github.com/langfuse/langfuse.git
cd langfuse

# 启动 LangFuse(包含 PostgreSQL)
docker compose up -d

# 访问 http://localhost:3000
# 默认无预设账号,首次访问需注册

10.3 Python 集成

# 安装 SDK
# pip install langfuse openai

from langfuse import Langfuse
from langfuse.decorators import observe, langfuse_context
from openai import OpenAI

langfuse = Langfuse(
    public_key="pk-lf-xxx",
    secret_key="sk-lf-xxx",
    host="http://localhost:3000"
)
client = OpenAI()

@observe()
def retrieve_documents(query: str) -> list:
    """检索相关文档"""
    langfuse_context.update_current_span(
        metadata={"query": query, "top_k": 5}
    )
    results = vector_store.similarity_search(query, k=5)
    return results

@observe()
def generate_answer(query: str, context: str) -> str:
    """调用 LLM 生成回答"""
    response = client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {"role": "system", "content": f"基于以下上下文回答问题:\n{context}"},
            {"role": "user", "content": query}
        ]
    )
    return response.choices[0].message.content

@observe()
def rag_pipeline(query: str) -> str:
    """完整的 RAG 管道"""
    docs = retrieve_documents(query)
    context = "\n".join([doc.page_content for doc in docs])
    answer = generate_answer(query, context)
    
    langfuse_context.update_current_trace(
        user_id="user_123",
        tags=["rag", "production"]
    )
    return answer

10.4 追踪一次 RAG 请求的完整链路

集成完成后,每次调用 rag_pipeline() 都会在 LangFuse 中生成一条完整的 Trace。你可以在 LangFuse 界面中看到:

LangFuse 界面 - Trace 详情视图

左侧面板展示 Trace 的时间轴,可以看到每个 Span 的执行顺序和耗时:

  • rag_pipeline(总耗时 1,523ms)
  • ├── retrieve_documents(68ms)— 输入:query,输出:5条文档
  • └── generate_answer(1,440ms)— Generation 类型
  • ├── Model: gpt-4o
  • ├── Input tokens: 1,520 | Output tokens: 380
  • ├── Cost: $0.034
  • └── 完整的 Prompt 和 Response 文本 右侧面板展示选中 Span 的详细信息,包括输入输出、元数据、耗时分布。

10.5 评估与标注

在 LangFuse 界面中,你可以对每条 Trace 进行人工打分:

  • 准确性(Accuracy):回答内容是否正确
  • 忠实度(Faithfulness):是否忠于检索到的上下文
  • 有用性(Helpfulness):回答对用户是否有帮助
  • 安全性(Safety):是否包含不当内容

第11章:成本监控实操

11.1 Token 消耗统计脚本

# 使用 LangFuse API 统计 Token 消耗
import requests
from datetime import datetime, timedelta

LANGFUSE_HOST = "http://localhost:3000"
LANGFUSE_PUBLIC_KEY = "pk-lf-xxx"
LANGFUSE_SECRET_KEY = "sk-lf-xxx"

def get_token_usage(days=7):
    """获取最近 N 天的 Token 消耗"""
    end = datetime.utcnow()
    start = end - timedelta(days=days)
    
    response = requests.get(
        f"{LANGFUSE_HOST}/api/public/metrics/daily",
        auth=(LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY),
        params={
            "traceName": "rag_pipeline",
            "fromTimestamp": start.isoformat(),
            "toTimestamp": end.isoformat()
        }
    )
    
    data = response.json()
    total_input = sum(d.get("inputTokens", 0) for d in data)
    total_output = sum(d.get("outputTokens", 0) for d in data)
    total_cost = sum(d.get("totalCost", 0) for d in data)
    
    print(f"时间范围: {start.date()} ~ {end.date()}")
    print(f"Input Tokens:  {total_input:,}")
    print(f"Output Tokens: {total_output:,}")
    print(f"总费用: ${total_cost:.2f}")
    return data

get_token_usage(7)

11.2 多维度成本统计

统计维度价值实现方式
按用户找出异常高消耗用户Trace 中记录 user_id
按功能哪些功能最费钱Trace 中记录 tags (如 rag / chat / summary)
按模型不同模型的性价比Generation 中自动记录 model
按时间发现费用趋势和异常按日/周/月聚合

11.3 异常消耗告警

# 异常消耗检测 & 告警
import statistics

def check_cost_anomaly(daily_costs: list, threshold_sigma=2):
    """基于统计方法检测费用异常"""
    if len(daily_costs) < 7:
        return False, "数据不足"
    
    mean = statistics.mean(daily_costs)
    stdev = statistics.stdev(daily_costs)
    latest = daily_costs[-1]
    
    upper_bound = mean + threshold_sigma * stdev
    
    if latest > upper_bound:
        alert_msg = (
            f"⚠️ 费用异常告警\n"
            f"今日费用: ${latest:.2f}\n"
            f"历史均值: ${mean:.2f}\n"
            f"告警阈值: ${upper_bound:.2f}\n"
            f"偏离程度: {(latest - mean) / stdev:.1f} σ"
        )
        send_alert(alert_msg)  # 发送到钉钉/Slack/飞书
        return True, alert_msg
    
    return False, "正常"

第12章:案例 — 为一个 RAG 系统搭建可观测性

12.1 系统描述

案例背景

某公司内部知识库问答系统,基于 LangChain + Milvus + GPT-4o 构建。用户可以提问公司制度、产品手册、技术文档等内容。上线后收到大量"回答不准确"的反馈,但团队无法定位具体问题。

12.2 LangFuse 集成过程

步骤操作耗时
1Docker 部署 LangFuse30 分钟
2在 RAG 管道中集成 @observe() 装饰器2 小时
3为每个 Trace 添加 user_id 和 tags30 分钟
4配置 Grafana 看板(接 LangFuse 的 Prometheus Exporter)1 小时
5建立每日采样评估流程2 小时

12.3 上线后发现的问题

通过 LangFuse 的 Trace 追踪,团队在一周内定位了三个关键问题:

问题发现方式根因修复方案
30% 的问题检索不到相关文档检索 Span 返回结果为空文档切分粒度太大(2000 字/块),语义匹配不上调整切分策略为 500 字/块 + 50 字重叠
部分回答包含已过时的制度信息Trace 中检索到的文档是 2023 版新版文档上传后未删除旧版向量建立文档版本管理和向量更新流程
某个用户 Token 消耗是平均值的 50 倍成本统计按用户维度排序该用户在用脚本批量调用接口做数据抓取增加用户级别的调用频率限制

12.4 优化效果

优化前:优化前 检索命中率:65% 用户满意度:58% 日均费用:$120 P99 延迟:8.5s 优化后(2 周):优化后(2 周) 检索命中率:89% +24% 用户满意度:82% +24% 日均费用:$75 -37% P99 延迟:4.2s -50%

案例总结

可观测性不仅仅是"看日志",它是**让问题从"感觉回答不好"变成"知道哪里出了问题、为什么出问题、怎么修"**的关键基础设施。没有可观测性的 LLM 应用,就像没有仪表盘的汽车——能开,但出问题时你不知道发动机温度是多少。

第13章:课堂练习

课堂练习

练习一:架构分层分析 你所在的团队正在开发一个"智能客服"系统,使用 Dify 搭建工作流,接入了 GPT-4o 和企业知识库。请回答:

  1. 画出这个系统的完整架构图(参考第2章的六层模型)
  2. 列出每一层至少 3 个测试关注点
  3. 如果用户反馈"客服回答了一个完全不相关的内容",你会按什么顺序排查哪些层?

课堂练习

练习二:可观测性指标设计 为上述智能客服系统设计可观测性方案:

  1. 从第8章的 10 个指标中,选出对这个系统最重要的 5 个,并说明理由
  2. 为每个指标设计告警阈值和告警级别
  3. 设计一个"每日质量报告"的模板,包含哪些内容

课堂练习

练习三:LangFuse 实操(需要环境)

  1. 用 Docker 部署一个 LangFuse 实例
  2. 编写一个简单的 RAG Pipeline(可以用 Mock 数据),集成 LangFuse 追踪
  3. 在 LangFuse 界面中查看 Trace,回答以下问题:
    • 整条链路中最耗时的环节是哪个?
    • 一次请求消耗了多少 Token?
    • 如果检索结果为空,Trace 中能看出来吗?

补充:OpenTelemetry 与 GenAI 语义约定

为什么需要 OpenTelemetry

LangFuse 等专用工具解决了 LLM 层面的可观测性,但企业级系统还需要把 LLM 调用放到整个请求链路(Web → API → LLM → 数据库)中统一追踪。OpenTelemetry(OTel)是云原生可观测性的事实标准,2025 年开始正式定义了 GenAI 语义约定,让 LLM 调用的 Trace/Span 能和传统服务的 Span 统一串联。

GenAI 语义约定核心字段

Span 属性说明示例值
gen_ai.system模型提供方openai
gen_ai.request.model请求的模型名gpt-4o
gen_ai.response.model实际使用的模型gpt-4o-2024-08-06
gen_ai.request.max_tokens最大生成 token 数1000
gen_ai.request.temperature温度参数0.7
gen_ai.usage.input_tokens输入 token 数150
gen_ai.usage.output_tokens输出 token 数320
gen_ai.response.finish_reasons结束原因["stop"]

Python 集成示例

# pip install opentelemetry-api opentelemetry-sdk opentelemetry-instrumentation-openai
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import ConsoleSpanExporter, SimpleSpanProcessor

provider = TracerProvider()
provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
trace.set_tracer_provider(provider)

# 自动 instrument OpenAI 客户端
from opentelemetry.instrumentation.openai import OpenAIInstrumentor
OpenAIInstrumentor().instrument()

# 之后所有 OpenAI 调用自动生成带 gen_ai.* 属性的 Span
from openai import OpenAI
client = OpenAI()
resp = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "你好"}]
)
# 控制台会输出包含 gen_ai.usage.input_tokens 等字段的 Span

与 LangFuse 的关系

维度OpenTelemetryLangFuse
定位通用可观测性标准,覆盖全链路LLM 专用追踪平台
Span 类型HTTP、DB、消息队列、LLM 全覆盖专注 Generation、Trace、Score
生态Jaeger / Grafana Tempo / Datadog 等自有 Dashboard + API
适用场景企业级全链路追踪LLM 应用开发和调试
建议两者互补:OTel 做全链路,LangFuse 做 LLM 精细化分析

测试人员关注的 OTel 检查点

  • Span 完整性:每次 LLM 调用是否生成了 Span,gen_ai.* 字段是否齐全
  • 链路串联:LLM Span 是否正确挂在父 Span(如 HTTP 请求)下
  • Token 准确性:OTel 记录的 token 数是否与 API 响应一致
  • 错误标记:LLM 调用失败时 Span 的 status 是否设为 ERROR
  • 敏感数据:Span 中是否无意间记录了用户 Prompt 或 API Key

课堂练习

  1. 用 OpenTelemetry 的 ConsoleExporter 跑一次 OpenAI 调用,观察输出的 Span 包含哪些 gen_ai.* 属性。
  2. 对比 OTel 记录的 token 数和 API 响应中 usage 的 token 数是否一致。

补充参考答案要点

  • 练习一的架构分层至少要拆到输入层、编排层、模型层、工具/检索层和观测层,问题必须能落到具体一层。
  • 练习二的指标设计不能只看最终分数,还要同时覆盖流量、延迟、错误类型、成本和人工反馈。
  • 练习三做 LangFuse 或同类平台时,核心不是“把日志接进去”,而是保证 trace、prompt、模型输出和评价结果能串起来看。

上次更新: