RAG上线一周,用户反馈"答得不准"。我看了一眼代码:
ini
response = chain.invoke({"question": query})
一个黑盒。 question进去了,answer出来了,中间发生了什么?检索到哪些chunk?LLM收到了什么prompt?Token用了多少?------全不知道。
这感觉就像Java应用没有日志,线上出bug只能猜。以前写Spring Boot,起码有log4j、有skywalking、有APM,哪行报错一清二楚。AI应用呢?裸奔。
直到我用了LangSmith,才终于给AI应用装上了"监控面板"。
先说结论
| 功能 | 没有LangSmith | 有LangSmith |
|---|---|---|
| 追踪每次调用 | 只能看到最终输出 | 完整链路:检索→Prompt→生成 |
| 定位问题环节 | 猜,逐个打log | 点开trace一看就知 |
| Token成本统计 | 手动算API账单 | 自动统计,按链路分解 |
| Prompt版本管理 | Git提交代码 | 每次变更可对比效果 |
| 测试回归 | 手动问几遍 | 自动跑评估集 |
Java人的理解:LangSmith ≈ Skywalking/Zipkin。 分布式追踪给微服务装了眼睛,LangSmith给AI应用装了眼睛。
坑1:以为LangSmith只是个日志面板
翻车现场
一开始我把LangSmith当成普通的日志工具,只在最外层加了追踪:
ini
import langsmith
# 只在最外层包了一下
with langsmith.trace("rag_query", run_type="chain") as run:
response = chain.invoke({"question": query})
run.end(outputs={"answer": response})
结果: LangSmith里只看到一条trace,知道"调了一次RAG",但中间发生了什么------检索了多少chunk?LLM输入是什么?------全不知道。
正确做法:自动追踪------LangChain原生集成,零代码改造
LangChain从0.1版本开始原生支持LangSmith,只需要设环境变量,不需要改任何代码:
lua
import os
# 只需要这3行环境变量
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_API_KEY"] = "lsv2_sk_xxx"
os.environ["LANGCHAIN_PROJECT"] = "my-rag-app"
# 原有代码完全不用改
response = chain.invoke({"question": "退货政策是什么?"})
LangSmith自动记录整个调用链:
scss
rag_query (Chain)
├── retriever (Retriever) → 检索到3个chunk
├── prompt (ChatPromptTemplate) → 组装后的完整prompt
└── llm (ChatModel) → 生成回答,耗时2.3s,token=428
每个环节的输入、输出、耗时、token数,全部自动记录。 不用你手动打log。
坑2:检索效果差,不知道是chunk的问题还是LLM的问题
翻车现场
用户问"退货要多久",AI回答"建议您联系客服"。
是检索没找到退货相关chunk?还是LLM收到正确的chunk但回答跑偏了?不知道。
以前的做法:在每个环节手动print,然后翻终端日志。效率极低,而且线上环境根本没有终端可看。
正确做法:用LangSmith的Trace视图逐环节排查
打开LangSmith的trace详情页,看到这样的链路:
ini
retriever → 输出3个chunk:
[1] "退货政策:未拆封7天内..." (similarity=0.82)
[2] "退款流程:提交申请后..." (similarity=0.71)
[3] "常见问题:Q1 如何退货..." (similarity=0.68)
prompt → 组装后的完整prompt:
"根据以下文档回答问题:\n[1] 退货政策:未拆封7天内...\n问题:退货要多久"
llm → 输出: "建议您联系客服确认退货时间"
一眼看出: 检索没问题(3个chunk都和退货相关),是LLM回答跑偏了。问题出在prompt------没有明确要求"必须根据文档回答,不要让用户联系客服"。
修复prompt后:
swift
prompt = ChatPromptTemplate.from_messages([
("system", "根据提供的文档内容直接回答问题。如果文档中有明确答案,直接给出,不要说'请联系客服'。"),
("human", "文档内容:\n{context}\n\n问题:{question}")
])
再跑一遍,AI回答:"未拆封商品7天内可退货,3个工作日处理。"
如果没有LangSmith,这种排查可能要半小时。有了它,30秒定位问题。
坑3:上线后成本失控,不知道哪条链路最费token
翻车现场
月API账单从50涨到200,不知道是哪个功能吃掉的。
RAG问答?文档摘要?Agent工具调用?每种功能都调LLM,但不知道哪个是成本大头。
正确做法:LangSmith的成本分析------按链路、按模型拆分
LangSmith自动统计每次调用的token消耗和成本:
ini
项目:my-rag-app(最近7天)
按链路类型:
RAG问答: 1,234次 token=528,000 估算$12.5
文档摘要: 456次 token=312,000 估算$8.2
Agent工具调用: 89次 token=187,000 估算$4.1
按模型:
qwen-plus: token=820,000 $15.2
qwen-turbo: token=207,000 $1.6
异常调用(token>2000):
6月12日 14:23 RAG问答 token=4,280 ⚠️
那个token=4,280的异常调用,点进去一看: 检索到12个chunk全塞进prompt了。正常应该只塞3-5个,是retriever的k值设错了。
ini
# 修复前
retriever = vectorstore.as_retriever(search_kwargs={"k": 12}) # 传太多了
# 修复后
retriever = vectorstore.as_retriever(search_kwargs={"k": 4}) # 合理数量
修复后,RAG问答的平均token从428降到210,成本直接砍半。
坑4:改了prompt不知道效果变好还是变差
翻车现场
优化prompt是AI应用的日常操作,但改完prompt全靠手动问几遍来判断效果。
问题:
- 今天改了,下周又改,不知道哪个版本效果最好
- 手动测试3-5个问题,不代表整体效果
- 没法量化"变好了多少"
正确做法:LangSmith的评估+数据集功能
第1步:创建评估数据集
ini
from langsmith import Client
client = Client()
# 创建一个评估数据集
dataset = client.create_dataset("rag-qa-eval")
# 添加测试用例
examples = [
{"question": "退货要多久?", "expected": "未拆封7天内,3个工作日"},
{"question": "支持什么支付方式?", "expected": "支付宝、微信支付、银行卡"},
{"question": "配送范围有哪些?", "expected": "全国大部分地区,偏远地区需加运费"},
]
for ex in examples:
client.create_example(
inputs={"question": ex["question"]},
outputs={"expected": ex["expected"]},
dataset_id=dataset.id
)
第2步:跑评估
ini
from langsmith.evaluation import evaluate
def target_fn(inputs: dict) -> dict:
response = chain.invoke({"question": inputs["question"]})
return {"answer": response}
results = evaluate(
target_fn,
data="rag-qa-eval",
evaluators=[
# 评估答案和期望的相似度
langsmith.evaluation.evaluators.EmbeddingDistance(),
],
)
第3步:对比不同版本
改了prompt后,再跑一次评估。LangSmith自动对比:
java
版本对比:
v1 (6月10日): 平均相似度 0.72, 平均耗时 2.1s
v2 (6月12日): 平均相似度 0.81, 平均耗时 1.8s ← 当前最优
v3 (6月14日): 平均相似度 0.76, 平均耗时 2.3s
现在优化prompt有了量化依据,不再是"感觉好一点"。
LangSmith的免费额度够用吗?
| 免费版 | 限制 |
|---|---|
| 每月trace数 | 5,000条 |
| 团队成员 | 1人 |
| 数据保留 | 14天 |
个人项目和刚上线的小应用完全够用。 日请求量<200的RAG,一个月大概3000-4000条trace。
如果trace超过5000条,两个选择:
- 只追踪关键链路(设置采样率)
- 自部署LangSmith开源版(Docker一键启动)
bash
# 设置采样率,只追踪10%的调用
os.environ["LANGCHAIN_SAMPLING_RATE"] = "0.1"
回头看
| 坑 | 一句话总结 |
|---|---|
| 只当日志面板用 | LangChain原生集成,设环境变量就自动追踪全链路 |
| 不知道问题出在哪个环节 | Trace视图逐环节排查,30秒定位 |
| 成本失控不知道谁吃的 | 按链路/模型拆分token统计,一眼看清 |
| 改prompt不知道变好变差 | 评估数据集+自动对比,量化优化效果 |
AI应用没有可观测性,就像生产环境没有监控------能跑,但出问题就是瞎子。 LangSmith是目前最方便的AI应用监控工具,和LangChain无缝集成,推荐第一时间配上。