
现在我们做大模型应用,有个最基础、最直观的体会:写好Prompt、调通API只是项目的起点。本地测试效果看着很不错,一旦上线之后各种问题接踵而至。同样的输入,大模型时而回答精准,时而幻觉频发;不同Prompt版本效果好坏靠主观感觉判断,没有量化数据;线上用户真实问题无法回流,模型迭代全凭开发人员猜问题出在哪里;出现故障时,很难定位是Prompt问题、检索上下文问题、还是LLM本身输出不稳定。
早期开发原型阶段,我们可以手动跑样例、肉眼看结果。但当业务走向生产环境,面向真实用户流量,就必须一套完整体系:可观测追踪、Prompt 实验能力、自动化评测、人工标注、线上反馈闭环。市面上LangSmith、Langfuse已经成为主流大模型追踪工具,OpenTelemetry提供通用可观测标准,Prompt A/B测试用来对比不同提示词版本优劣,自动化评测集保证迭代不退化,人工标注和用户反馈补齐自动化评测覆盖不到的场景。
如果没有完整的体系概念和思路,很容易会把这些组件当成独立工具使用:只拿LangSmith打日志,只单独写评测脚本,各个模块互相割裂,无法形成闭环。真正工程化落地,不是简单堆砌工具,而是把追踪、实验、评测、标注、线上反馈串联起来,形成完整迭代链路。

传统软件可观测包含日志、指标、链路追踪三大支柱。但大模型应用属于生成式 AI,它和普通接口服务有本质区别。普通接口输入固定,输出确定性强;大模型同样输入,输出具备随机性。传统监控只能看到接口报错、耗时、QPS,看不到Prompt完整内容、模型返回文本、中间思考步骤、RAG 检索出来的文档、工具调用参数、幻觉现象。
大模型场景下的可观测,核心要回答这几类问题:
大模型可观测分为两大路线,两者不是互斥关系,可以互相配合使用:
在没深入深入了解前,很容易混淆彼此,LangSmith、Langfuse不是简单日志打印工具。它们专门针对LLM调用链做抽象,会区分不同Span类型:LLM调用、Retrieval检索、Tool工具调用、Prompt模板渲染、Agent 思考步骤,把大模型应用复杂执行过程完整还原。
传统日志库只能打印字符串文本,无法结构化保存Prompt变量、输入输出、token消耗、嵌套 Agent调用层级。如果我们自己手写日志,要处理大量结构化字段,工作量巨大,还很容易遗漏关键字段。这就是专用LLM追踪工具存在的价值。
LangSmith是LangChain官方配套产品,Langfuse是开源可观测平台,二者能力高度重合,但设计定位有差异。
LangSmith 核心特点
Langfuse核心特点
两者共同能力:
简单总结选型参考:
OpenTelemetry是一套通用可观测标准,简称OTel,不属于大模型专属工具。它定义统一 Trace、Metrics、Logs数据格式,可以把链路数据输出到Jaeger、Zipkin、Prometheus、Elasticsearch各类后端。
为什么大模型项目需要OTel? LangSmith、Langfuse有自己的数据存储与UI。企业内部往往已经有一套成熟监控体系。直接把所有可观测数据全部丢给第三方SaaS平台,存在数据合规、数据出境、权限管控问题。OTel可以作为中间标准层:把 LLM 调用链路输出标准OTel Span,一份数据,既可以推送到Langfuse做AI业务分析,同时推送到企业内部现有监控平台做运维监控。
目前社区已经有LLM语义约定,在OTel Span中约定LLM相关属性:模型名称、prompt内容、completion输出、token输入输出数量、temperature参数等。
示例:Python OpenAI + Langfuse OpenTelemetry桥接片段
from openai import OpenAI
from langfuse.openai import langfuse_context
import opentelemetry
client = OpenAI()
# 开启追踪,Langfuse同时支持输出OTel标准span
langfuse_context.configure(
public_key="pk-xxx",
secret_key="sk-xxx",
host="http://localhost:3000",
otel_exporter_enabled=True
)
completion = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role":"user","content":"解释什么是大模型可观测"}]
)
print(completion.choices[0].message.content)上面示例执行完成后,一次大模型调用会生成两份数据:
可观测上线最容易出现的问题,这里做几点实践提醒:
开发大模型应用,Prompt是核心资产。同样业务需求,可以写出多版Prompt。
在多版Prompt情况下,我们该如何确定哪一个 Prompt 版本线上效果更好?通常我们的做法,通过本地跑10几个样例,主观感觉v3效果不错,直接上线。这种方式风险很高,本地少量样例不代表真实用户分布。部分Prompt在测试样例表现优秀,遇到真实用户五花八门输入就翻车。
Prompt A/B测试,就是解决这个问题:线上流量做分流,一部分流量走Prompt A版本,一部分流量走Prompt B版本,基于真实业务数据,量化对比两个版本各项指标,用数据决定哪个版本上线,而不是靠开发者主观感受。
Prompt A/B不等同于简单离线对比。离线评测使用固定评测集;A/B测试使用真实线上用户流量,能够捕捉到离线测试覆盖不到的真实输入分布。
一套完整 Prompt A/B 测试体系,必须包含下面几个组件:
示例:Prompt 分流逻辑
以下示例实现稳定分流,30%用户流量走到v2新版本Prompt,70%继续使用基线v1。每条Trace绑定prompt_id,后续平台就可以按prompt版本分组统计用户反馈、自动化评测分数。
import hashlib
def get_prompt_version(user_id: str, traffic_ratio_b: float=0.3):
# 根据user_id哈希稳定分流
hash_val = int(hashlib.md5(user_id.encode()).hexdigest(),16) % 100
if hash_val < traffic_ratio_b * 100:
# B组:新版本Prompt
return {
"prompt_id":"prompt_summary_v2",
"template":"你是专业摘要助手,输出精简摘要,控制在100字以内:{input_text}"
}
else:
# A组:基线旧版本
return {
"prompt_id":"prompt_summary_v1",
"template":"对下面文本做摘要:{input_text}"
}
# 业务调用
user_id = "user_123456"
prompt_info = get_prompt_version(user_id, traffic_ratio_b=0.3)
# trace记录prompt_id,用于后续统计
langfuse_context.update_current_trace(
prompt_id=prompt_info["prompt_id"],
user_id=user_id
)不建议直接把未经离线验证的Prompt直接丢线上A/B测试。正确流程:

离线评测过滤掉明显劣化版本,线上A/B验证真实用户场景表现,两者互相补充。
Prompt迭代、模型版本升级、RAG检索逻辑改动,每次修改之后,如何确认没有把原有能力改坏?如果全部靠人工一条条审核,成本极高,迭代速度会被严重拖慢。自动化评测集的价值,就是充当回归测试用例。每次代码、Prompt改动,自动批量跑一遍评测集,输出量化分数,快速发现能力退化。
首先消除一个对评测存在的误解:自动化评测不是用来100%替代人工。自动化擅长大规模回归、快速筛明显问题;复杂、高风险业务场景仍然需要人工标注兜底。自动化评测集核心组成:评测样本数据集 + 评测器。
评测数据集有4个主要来源,实际项目一般混合使用:
数据集需要分类管理,划分不同场景:通用问答、摘要、RAG 问答、工具 Agent 等。同时数据集要持续迭代,不是一次性建好就永久不变。随着业务变化,持续新增样本,淘汰过时样本。
3.1 基于规则评测器
简单字符串匹配,关键词检测。
3.2 LLM-as-Judge 大模型充当裁判评测器
把query、模型输出、参考标准答案交给另一个能力更强LLM,让裁判模型打分,输出1‑5分或者布尔判断(是否幻觉、是否回答准确)。 这是现在工业界最主流评测手段。 常用评判维度:
LLM as Judge 简单示例:
LLM‑as‑Judge存在固有偏差,裁判模型本身也会犯错。实践技巧:temperature设置为0;prompt写清楚评判标准;高风险场景可以多个裁判投票。
def llm_judge(query:str, model_output:str, reference_answer:str):
judge_prompt = f"""
你是评测专家,请评判模型回答质量。
用户问题:{query}
参考标准答案:{reference_answer}
模型输出:{model_output}
请输出JSON,包含两个字段:
score:1‑5分,5分最好,1分最差;
reason:简短打分理由。
"""
resp = client.chat.completions.create(
model="gpt‑4o‑mini",
messages=[{"role":"user","content":judge_prompt}],
temperature=0
)
return resp.choices[0].message.content3.3 嵌入相似度评测
计算模型输出文本和标准答案向量相似度。
3.4 专用指标
完整自动化评测工作流:

实践中碰到的问题记录总结:
自动化评测强大,但存在天花板:
所以我们需要两条输入:用户线上原始反馈 + 人工标注工作台,形成闭环:线上真实 Trace 收集用户反馈 → 人工审核标注 → 优质/坏样例沉淀到评测数据集 → 使用评测集迭代 Prompt、业务逻辑 → 上线之后继续收集线上Trace与反馈。这个循环就是大模型迭代飞轮。

线上反馈是第一手原始信号。产品侧在应用界面增加简单反馈按钮:满意/不满意,还可以允许用户填写简短反馈文本。
关键工程点: 用户反馈事件,必须和后端的Trace ID做关联。前端点击点赞/点踩,上报 trace_id,后端调用Langfuse/LangSmith接口,把用户打分附着在对应Trace记录上。
示例:接收前端用户反馈
# 接收前端上报:trace_id、用户评分、用户反馈文本
def user_feedback_callback(trace_id:str, user_score:int, user_comment:str=None):
from langfuse import Langfuse
lf = Langfuse()
lf.score(
trace_id=trace_id,
name="user_feedback",
value=user_score, # 1差评,5好评
comment=user_comment
)
lf.flush()这样在Langfuse平台,我们就可以筛选所有用户打低分Trace,集中查看哪些场景用户不满意。
收集完海量Trace,需要人工介入标注工作。Langfuse内置标注工作台,可以筛选出:用户差评Trace、自动化评测低分Trace、高优先级业务Trace,推给标注人员。
人工标注可以自定义标签体系,举例RAG问答业务标签:
标注完成之后,可以一键把这条Trace的query、理想修正答案导出,新增到自动化评测数据集。做到线上真实问题回流进评测集。
完整闭环全链路,整个流程构建了“采集→标注→评测→迭代→灰度→上线”的完整闭环:线上Trace与用户反馈经人工标注后沉淀为评测数据集,CI自动评测保障迭代不退化,候选版本经离线过滤与A/B灰度验证后全量上线,并持续采集反馈进入下一轮,形成数据驱动的持续优化飞轮。

流程细节说明:
这样最需要的注意的是,很多场景如果只做到第一步记录Trace,后面2‑8步没有打通,工具就沦为单纯日志工具,无法产生迭代价值。闭环的核心不是工具,是数据流转流程,让线上真实问题持续回流到开发评测环节。
工程落地会遇到现实约束,需要权衡取舍:

我们把全部技术点做一次汇总梳理,理清各自职责边界,避免混淆:
它们不是相互替代关系,是一套互补组合。缺少任意一环,整个迭代链条就会断裂。
不要期望一次性搭建完整庞大体系,可以分阶段实施:
阶段一(最小可用):
阶段二(自动化回归)
阶段三(Prompt 实验)
阶段四(完整闭环)
大模型应用开发,原型调试只是起点,真正难点在于上线之后持续迭代优化。传统软件依靠单元测试、线上监控保障质量;大模型应用因为生成结果存在不确定性,我们需要一套全新质量保障体系。LangSmith、Langfuse负责记录每一次大模型运行完整过程;OpenTelemetry对接企业运维体系;Prompt A/B测试用真实流量客观对比提示词版本好坏;自动化评测集充当回归测试,防止迭代过程能力退化;人工标注和线上用户反馈闭环把真实用户遇到的问题源源不断回流到开发环节。
整套体系核心思想就是减少主观判断,用数据驱动Prompt与业务逻辑迭代。不再靠开发人员感觉判断Prompt好不好,而是结合Trace记录、用户反馈、自动化评测分数、A/B实验指标综合决策。
对于应用实践来说,不必追求一步做到完美完备。可以按照分阶段路径,从小版本逐步搭建。先把Trace追踪和用户反馈落地,再补齐自动化评测,之后逐步完善A/B测试与标注闭环。当真正运转起来之后,大模型应用就可以持续吸收真实业务输入,稳步迭代质量,而不是停留在一次性调 Prompt 的原型阶段。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。