第5课:LangSmith 快速入门实战【第一个LangSmith链路追踪项目从零搭建】

文章目录
一、开篇导读
经过前四节课的学习,你已经完成了一系列重要准备:理解了LangSmith是什么,完成了账号注册和配额评估,搭建好了Python开发环境,还深入掌握了Trace、Run、Project、Session、Tag等核心概念。现在,到了真正动手的时候了。
本节课我们要做一个完整的实战项目——从零搭建一个带有 LangSmith 链路追踪功能的智能客服原型。这将是你在 LangSmith 技能树上的第一个里程碑。
你可能会想:不就是链式调用一下LLM,然后打印几行日志吗?
不是这么简单。真正的企业级大模型应用需要处理多轮对话、工具调用、RAG检索、流式输出、错误重试等复杂场景。如果一个请求出现问题,你得知道是Prompt写得不对、模型参数没调好、还是中间某个工具返回了脏数据。这些都是大模型应用开发中非常棘手的问题。LangSmith能够清晰地呈现应用的一次完整执行过程,并关联多轮对话上下文,这是传统print埋点完全无法匹敌的。
本节课你将收获:
- 亲手搭建一个从零开始的完整 LangSmith 项目
- 掌握
@traceable装饰器、wrap_openai客户端、trace上下文管理器三种追踪方式 - 学会在调用树中定位性能瓶颈和错误根源
- 掌握通过 Thread ID 串联多轮对话的高阶用法
- 写一个带工具调用和 RAG 检索的企业级客服 Agent
- 学会查看 LangSmith 控制台中的各种分析视图
- 收获一套生产级的最佳实践配置模板
二、知识前置铺垫
2.1 为什么大模型应用比传统程序更需要追踪
传统 Web 应用(如电商网站)的逻辑是确定性的。一个 HTTP 请求进来,后端代码执行几个函数,查一下数据库,把结果渲染成 HTML 返回。如果出错了,堆栈信息会抛出来,你可以清晰地定位到是哪一行代码、哪个函数出了问题。
大模型应用完全不同。复杂的大模型应用往往牵涉到多个 LLM 调用、工具调用、输出解析等环节。当用户问“帮我查一下明天的天气”,你的应用可能会:
- 先调用一个意图识别模型(第1次LLM调用)
- 根据意图触发
get_weather工具调用 - 根据工具返回的结果,再次调用模型生成最终回答(第2次LLM调用)
如果最终答案错了,你很难判断是意图识别错了,还是 get_weather 返回了错误数据,还是最后的生成模型没有正确理解工具返回的内容。这就像一架波音客机有数十万个零件,要排查一个故障,工程师需要看到每个零件的“黑匣子”数据。
LangSmith 通过 Project、Trace、Run 三层结构记录大模型应用的全流程,帮助开发者追踪复杂链路、定位问题瓶颈。
2.2 Trace、Run、Thread 三层结构的回顾
在开始实战之前,我们先快速回顾一下 LangSmith 的数据模型。LangSmith 将数据组织为三层层级结构:
Projects 是所有追踪数据的逻辑容器。一个项目对应一个应用或一个功能模块,不同项目之间互不干扰。在真实项目中,你会按环境划分项目,比如 myapp-dev、myapp-staging、myapp-prod。
Traces 是一次完整的用户请求过程。当用户发起一次请求(如问一句话、运行一次RAG),LangSmith就会生成一条Trace。每个Trace有一个唯一的Trace ID。
Runs 是Trace内部的单次步骤调用。比如用户问“LangSmith能做什么”,系统执行 RAG:先检索文档,再生成回答。那么“检索文档”是一个Run,“生成回答”是另一个Run。Run 之间通过 parent_run_id 形成树形结构。完整理解这一点,对后面读懂调用树非常有帮助。
Threads 是Traces的序列,代表一次完整的对话。在多轮对话中,每一轮是一个独立的Trace,但通过 session_id、thread_id 或 conversation_id 将这些Trace串联成一个对话线程。
2.3 追踪的三种实现方式对比
LangSmith 提供了三种灵活的实现方式,你可以根据代码特征选择合适的方案:
| 方式 | 使用方法 | 适用场景 | 优势 |
|---|---|---|---|
| @traceable 装饰器 | 在函数上方添加 @traceable |
自定义业务逻辑、需要精细控制的函数 | 自动处理嵌套调用,自动捕获输入输出,代码侵入最小 |
| wrap_openai 客户端 | 对原始 OpenAI SDK 一层包装即可 | 直接使用 OpenAI/Anthropic 原生 SDK 的场景 | 无需改动现有调用代码,自动捕获所有 API 请求 |
| trace 上下文管理器 | with trace("操作名"): |
需要对某个代码块进行单独追踪 | 可以在代码块级别的粒度上灵活控制 |
| 手动 RunTree | 直接调用 RunTree API |
非 LangChain 框架的高度定制场景 | 最底层、最灵活的控制能力 |
对于本节课,我们将使用 LangChain 框架,因此 toggle 环境变量的方式会自动追踪大部分 LangChain 调用。同时我们也会展示 @traceable 装饰器的高级用法。
三、核心概念精讲
3.1 从零开始追踪自动生效的原理
LangChain 内部实现了标准的回调系统。如果你在 LangChain 1.0 中设置环境变量 LANGCHAIN_TRACING_V2="true",LangSmith 回调处理器会在 LangChain 初始化时自动注册。当你调用 chain.invoke() 时,LangChain 会在各个生命周期节点(on_chain_start、on_llm_start、on_chain_end 等)触发回调。LangSmith 的回调处理器会拦截这些事件,组装成 Run 对象,并通过异步队列上报到 LangSmith 云端。
这个机制的存在,意味着你不需要在代码中显式地写任何埋点代码。这对于已有 LangChain 项目的改造尤其方便——加上环境变量就可以获得完整的链路追踪能力,不需要大规模重构代码。
3.2 RunnableConfig 传参的作用
在使用 LCEL 时,你可以通过 RunnableConfig 传递额外的配置信息。LangChain 的 Runnable 对象会在执行时自动从 config 中提取 tags 和 metadata,并将其附加到对应的 Run 上。
from langchain_core.runnables import RunnableConfig
config = RunnableConfig(
tags=["production", "v2.0"], # 用于分类筛选
metadata={"user_id": "12345", "session_id": "sess_abc"} # 用于调试和会话关联
)
chain.invoke(input_data, config=config)
这个机制为我们提供了在运行时动态向 Trace 注入业务维度的能力,让开发者在不修改业务逻辑的前提下完成精细化的数据标注。
3.3 Thread ID 的下发方式
对于需要关联多轮对话的场景,核心思路是生成一个全局唯一的 thread_id,并在每次调用时通过 metadata 传递下去。LangSmith 会在后端自动识别 session_id、thread_id 或 conversation_id 这个特殊的 metadata 键,并将其作为 Thread 的分组依据。
当 Thread ID 固定下来后,LangSmith 会将该会话下所有的 Trace 串在一条时间线里,而不是像默认情况那样把每一轮对话当成孤立的片段。
四、原理底层剖析
4.1 Run 的创建与生命周期
当一个 Trace 开始时,LangSmith SDK 首先创建一个根 Run,它的 parent_run_id 为 null。当程序执行过程中调用一个被 @traceable 装饰的函数时,SDK 会将当前线程的上下文栈顶 Run 的 ID 作为新 Run 的 parent_run_id,从而形成嵌套关系。
嵌套 Run 的实现依赖于 Python 的上下文变量机制,能够在线程边界内无感传播 Trace 信息,确保子调用能够找到正确的父调用。
4.2 数据上报的异步机制
LangSmith 采用异步上报模式,Run 对象先被放入一个内存队列,后台守护线程持续消费队列,通过 HTTP POST 批量发送到 LangSmith API。这种设计确保了即使 LangSmith 云端服务出现短暂不可用或网络抖动,上报重试逻辑也不会阻塞主业务线程,对业务性能几乎没有影响。
4.3 从 Thread 到 Trace 的关联映射
当你在 metadata 中传入 session_id 或 thread_id 时,LangSmith 后端会解析这个特殊的 property,并在数据库的 trace 表中为该字段增加索引。在 UI 的 Threads 视图中,LangSmith 会基于该字段将多个 Trace 进行聚合展示,形成一个完整的对话链路图。
五、环境配置手把手实战
由于第四节课已经完整搭建了开发环境,这里只做快速验证。
5.1 环境快速验证
在项目根目录下创建 .env 文件:
# .env 配置
LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=lsv2_pt_你的Key
LANGCHAIN_PROJECT=langsmith-quickstart # 这节课专门用的项目
OPENAI_API_KEY=sk-你的Key
⚠️ 关键点:如果你的 LANGCHAIN_PROJECT 没有被指定,那么所有的 Trace 会发送到名为 default 的项目当中。后面要在 UI 找到它们会比较麻烦,所以强烈建议一开始就养成给项目命名的习惯。
编写以下验证脚本 verify_env.py:
import os
from dotenv import load_dotenv
load_dotenv()
def verify():
required = ["LANGCHAIN_API_KEY", "OPENAI_API_KEY"]
for var in required:
if not os.getenv(var):
print(f"❌ {var} not set")
return False
print(f"✅ LANGCHAIN_PROJECT={os.getenv('LANGCHAIN_PROJECT', 'default')}")
print(f"✅ LANGCHAIN_TRACING_V2={os.getenv('LANGCHAIN_TRACING_V2')}")
return True
if __name__ == "__main__":
verify()
5.2 安装依赖
pip install langchain langchain-openai langsmith python-dotenv
六、完整可运行代码案例
6.1 第一个 Trace——最简链追踪入门
通过一个最简单的 LCEL 链,让你第一次在控制台中亲眼看到 Trace 和 Runs。
# 文件名: first_trace.py
# 说明: 第一个带有 LangSmith 追踪的可运行链
import os
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
load_dotenv()
# 显式指定项目
os.environ["LANGCHAIN_PROJECT"] = "langsmith-quickstart"
print("=" * 60)
print("第一步:启动第一个 LangSmith 追踪项目")
print("=" * 60)
# 构建简单的 LLM 调用链
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)
prompt = ChatPromptTemplate.from_messages([
("system", "你是一名资深的 AI 布道师,语气轻松热情。"),
("human", "请用一句话介绍什么是 {topic}。")
])
output_parser = StrOutputParser()
chain = prompt | llm | output_parser
# 执行链并观察追踪
result = chain.invoke({"topic": "LangSmith"})
print(f"\n返回结果:\n{result}")
print("\n✅ 代码执行完毕,登录 LangSmith 控制台查看 Trace。")
当你运行这段代码并打开 LangSmith 控制台,你会看到一个名为 langsmith-quickstart 的项目。点进去之后,应该看到一条 Trace,里面嵌套了 3 个 Runs:ChatPromptTemplate 负责格式化、ChatOpenAI 负责模型调用、StrOutputParser 负责结果解析。LangSmith 展示的调用树和耗时,提供了基础的性能可观测能力。
6.2 嵌套函数追踪——使用 @traceable 装饰器
当程序逻辑被拆分为多个自定义函数时,使用 @traceable 可以获得更清晰的嵌套关系。
# 文件名: nested_trace_demo.py
import os
from dotenv import load_dotenv
from langsmith import traceable
from langchain_openai import ChatOpenAI
load_dotenv()
os.environ["LANGCHAIN_PROJECT"] = "langsmith-quickstart"
llm = ChatOpenAI(model="gpt-3.5-turbo")
@traceable(run_type="chain", name="商品推荐AI")
def recommend_product(user_profile: str, budget: int) -> str:
"""根据用户画像和预算生成推荐"""
product = find_suitable_product(user_profile, budget)
return generate_recommendation(product)
@traceable(run_type="tool", name="商品检索")
def find_suitable_product(profile: str, budget: int) -> dict:
"""模拟从数据库/API 检索商品"""
candidates = [
{"name": "智能手环", "price": 299, "suitable_for": "运动爱好者"},
{"name": "无线耳机", "price": 899, "suitable_for": "音乐爱好者"},
{"name": "AI学习机", "price": 1999, "suitable_for": "学生群体"}
]
for item in candidates:
if item["price"] <= budget:
return item
return {"name": "基础款手环", "price": 99, "suitable_for": "通用"}
@traceable(run_type="llm", name="推荐文案生成")
def generate_recommendation(product: dict) -> str:
"""调用大模型生成推荐文案"""
response = llm.invoke(f"根据产品 {product['name']}({product['price']}元) 生成推荐理由。")
return f"推荐 {product['name']}:{response.content}"
if __name__ == "__main__":
result = recommend_product("喜欢运动的大学生", 500)
print(f"\n最终输出:{result}")
在 LangSmith 控制台中,你会看到一条主 Trace,其子 Run 分别对应 商品检索(tool) 和 推荐文案生成(llm)。这种精确的耗时归因能力是传统 print 调试完全无法匹敌的。
6.3 企业级智能客服 Agent(工具调用 + RAG + 多轮对话)
这是一个综合性实战项目,包含工具调用、RAG 检索、多轮对话 Thread 关联等功能。
# 文件名: advanced_customer_support.py
# 说明: 一个带工具调用、RAG 和多轮对话的企业级客服 Agent
import os
import uuid
from dotenv import load_dotenv
from langsmith import traceable
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableConfig
from typing import Annotated, Literal
load_dotenv()
os.environ["LANGCHAIN_PROJECT"] = "langsmith-quickstart"
# --- 模拟的知识库检索 (RAG) ---
@traceable(run_type="retriever", name="知识库检索")
def search_knowledge_base(query: str) -> str:
"""根据用户问题从知识库中查找相关信息"""
knowledge_base = {
"退款": "退款申请可在订单详情页发起,我们会在 3 个工作日内处理,款项原路退回。",
"退货": "支持 7 天无理由退货,只要商品不影响二次销售即可。",
"物流": "订单发货后可在我的订单中查看物流信息,通常 3-5 天送达。",
"会员": "会员等级是根据近 12 个月的消费金额计算的,不同等级享有不同权益。"
}
for key, value in knowledge_base.items():
if key in query:
return value
return "抱歉,我暂时没有找到相关信息,请联系人工客服。"
# --- 工具:查订单状态 ---
@traceable(run_type="tool", name="查询订单状态")
def check_order_status(order_id: str) -> str:
"""根据订单号查询订单当前状态"""
status_map = {
"ORD001": "已发货,预计 12 月 20 日送达",
"ORD002": "待支付,请尽快完成支付",
"ORD003": "已完成,感谢您的购买"
}
return status_map.get(order_id, "未找到该订单,请核对订单号")
# --- 工具:计算退款金额 ---
@traceable(run_type="tool", name="退款金额计算器")
def calculate_refund(original_price: float, days_used: int = 0) -> float:
"""根据原价和使用天数计算退款金额"""
if days_used <= 7:
return original_price
elif days_used <= 15:
return original_price * 0.7
else:
return original_price * 0.5
# --- 工具选择器 (决策哪个工具被调用) ---
@traceable(run_type="chain", name="意图识别与工具调用")
def call_tool(intent: Literal["退货退款", "查订单", "查物流", "会员咨询"], **kwargs) -> str:
"""根据识别到的用户意图,路由到不同的工具函数"""
if intent == "退货退款":
price = kwargs.get("price", 0)
days = kwargs.get("days", 0)
refund = calculate_refund(price, days)
return f"根据您的情况,预计可退款 {refund} 元。"
elif intent == "查订单":
order_id = kwargs.get("order_id", "")
return check_order_status(order_id)
elif intent == "查物流" or intent == "会员咨询":
return search_knowledge_base(intent)
else:
return "请提供更详细的信息,我可以帮您查询订单、处理退款或解答会员问题。"
# --- 主客服 Agent ---
@traceable(run_type="chain", name="智能客服 Agent")
def customer_support_agent(user_input: str, thread_id: str = None) -> str:
"""
客服 Agent 主入口
Args:
user_input: 用户输入的自然语言问题
thread_id: 会话线程 ID (用于多轮对话关联)
"""
# 步骤 1:借助大模型做意图识别 (简单的 zero-shot 分类)
intent_prompt = ChatPromptTemplate.from_template("""
将用户的请求分类为以下四类之一:'退货退款', '查订单', '查物流', '会员咨询'。
只输出分类,不要输出其他内容。
用户说:{input}
""")
intent_chain = intent_prompt | ChatOpenAI(model="gpt-3.5-turbo", temperature=0) | (lambda x: x.content.strip())
intent = intent_chain.invoke({"input": user_input})
# 步骤 2:调用对应的工具
result = call_tool(intent=intent, **extract_params(user_input))
# 步骤 3:让大模型生成自然语言回复
final_prompt = ChatPromptTemplate.from_template("""
你是客服助手。用户提问:{input}
根据以下信息回复用户:{info}
回复要友好得体,不要编造信息。
""")
final_chain = final_prompt | ChatOpenAI(model="gpt-3.5-turbo", temperature=0.7)
response = final_chain.invoke({"input": user_input, "info": result})
return response.content
# 辅助函数:从自然语言中简单提取参数 (这里仅做演示)
def extract_params(user_input: str) -> dict:
params = {}
import re
order_match = re.search(r"ORD\d{3}", user_input)
if order_match:
params["order_id"] = order_match.group()
price_match = re.search(r"(\d+(?:\.\d+)?)元", user_input)
if price_match:
params["price"] = float(price_match.group(1))
return params
# --- 对话循环 ---
def chat_loop():
"""多轮对话循环,自动生成统一的 thread_id"""
thread_id = f"thread_{uuid.uuid4().hex[:8]}"
print(f"会话 ID: {thread_id}")
print("智能客服已上线,输入 quit 退出\n")
while True:
user_input = input("用户: ").strip()
if user_input.lower() == "quit":
break
# 关键:通过 metadata 传递 thread_id
config = RunnableConfig(metadata={"thread_id": thread_id})
reply = customer_support_agent(user_input, thread_id=thread_id)
print(f"客服: {reply}\n")
if __name__ == "__main__":
chat_loop()
这个企业级 Agent 将所有关键节点都加了 @traceable,并在每次执行时通过 metadata 传入了 thread_id。打开 LangSmith 界面,左侧导航栏可以看到 Threads 视图,在这里你能将所有多轮对话聚合在一个线程内,看到完整的客服交互全过程。
七、代码逐行详解
7.1 环境配置和项目初始化
from dotenv import load_dotenv
load_dotenv()
os.environ["LANGCHAIN_PROJECT"] = "langsmith-quickstart"
load_dotenv() 必须位于代码最顶部,优先级高于所有其他模块导入。如果在导入 LangChain 之后才调用 load_dotenv(),LangSmith 的回调系统可能已经在没有 API Key 的情况下完成初始化,导致追踪失效。这是一个资深工程师踩坑多次后总结出的最干净的写法。
os.environ["LANGCHAIN_PROJECT"] = ... 是在运行时动态覆写项目名称。这样既保留了 .env 文件的兜底值,又给了代码更大的灵活性——比如可以在代码中根据环境变量 APP_ENV 动态切换 dev/staging/prod 项目。
7.2 @traceable 装饰器的参数
@traceable(run_type="chain", name="商品推荐AI")
run_type决定了 LangSmith UI 中该 Run 的图标样式和默认展示字段:chain会显示 Link/Chain 图标,tool展示扳手图标,llm展示机器人图标,retriever展示文件夹图标。明确设置run_type能让 UI 一目了然。name是在界面中展示的可读名称,建议采用中文或英文业务命名,便于团队理解。
7.3 RunnableConfig 传参
在客服 Agent 的例子中,我们用到了 RunnableConfig:
config = RunnableConfig(metadata={"thread_id": thread_id})
reply = customer_support_agent(user_input, thread_id=thread_id)
在实际实现中,customer_support_agent 内部需要将 config 透传给 Chain,LangChain 才会自动将 metadata 附加到 Root Run 上。上面的简化版本展示了 metadata 透传的关键思路。
八、常见坑点与避坑指南
8.1 环境变量 LANGCHAIN_PROJECT 不生效
典型症状:明明在代码中或者 .env 里设置了 LANGCHAIN_PROJECT,但在 UI 侧仍然看到所有数据流向 default 项目。
根本原因:Python 多线程/异步环境下的 LangSmith 上下文初始化时机问题。某些情况下环境变量的变更未能及时被回调系统感知。
最佳实践:在 Python 脚本最初几行就放置 load_dotenv(),紧接着显式覆写 os.environ。如果发现仍然无效,在启动 Python 脚本前用命令行 export 做兜底验证。
8.2 thread_id 始终无法聚合对话
根本原因:LangSmith 对 thread_id / session_id 的识别依赖 metadata 字段。如果错误地放到了 tags 里面,LangSmith 不会对其进行 Thread 聚合。
解决方案:始终将 thread_id 放在 RunnableConfig 的 metadata 字典中。可在 UI 中查看 Trace 详情,确认 metadata 字段是否包含 thread_id。
8.3 SDK 版本过旧导致字段不识别
LangSmith 的创新速度很快,部分新特性(如 thread_id 自动聚合)需要较新的 SDK 版本。建议定期升级:
pip install --upgrade langsmith langchain langchain-openai
升级前务必检查 Release Note 以避免 breaking changes。
8.4 免费版配额超限
开发调试阶段频繁运行代码,很容易在一个星期内用完全部配额。在不需要追踪的场景下,设置采样率是一个好习惯:
import random
os.environ["LANGCHAIN_TRACING_V2"] = "true" if random.random() < 0.1 else "false"
8.5 追踪数据延迟出现
LangSmith 使用异步批量上报机制,Trace 提交后需要等待几秒到几十秒才呈现在 UI 中。如果测试完成后立即去控制台刷新没看到数据,请稍等片刻再刷新。
8.6 traceable 装饰器导致函数签名改变
当你使用 @traceable 装饰器时,被装饰函数的原始签名会被包装。如果后续代码依赖函数的原始签名(例如通过 inspect.signature 反射),可能会出现问题。在这种情况下,可以考虑使用 functools.wraps 元装饰器,或者改用 RunnableConfig 传递追踪信息。
九、企业级落地最佳实践
9.1 环境与项目隔离
针对开发、测试、生产环境分别创建独立的 Project 是一个强有力的隔离手段。在 CI/CD 流水线中,可以根据环境变量自动完成映射:
if: github.ref == 'refs/heads/main'
env:
LANGCHAIN_PROJECT: "myapp-prod"
if: github.ref == 'refs/heads/develop'
env:
LANGCHAIN_PROJECT: "myapp-dev"
9.2 Tags 和 Metadata 的标准化
建立一套标准的 Tag 命名规则,便于后期筛选和分析:
config = RunnableConfig(
tags=[f"env:{ENV}", f"version:{APP_VERSION}", f"user_tier:{user_tier}"],
metadata={
"request_id": str(uuid4()),
"user_id": user_id,
"ab_test_bucket": bucket
}
)
9.3 Thread 的多租户设计
在多租户系统中,可以用复合 thread_id 来隔离数据:
thread_id = f"tenant_{tenant_id}:user_{user_id}:session_{session_token}"
LangSmith 会将这个字符串直接作为全局唯一的 Thread 标识,你也可以方便地在所有相关调用中传递它。
9.4 生产环境采样策略
在万亿级日志规模下,全量追踪的成本难以承受。可以实现动态采样逻辑:
def should_trace(user_id: str) -> bool:
# 特定 VIP 用户 100% 捕获
if user_id in VIP_USERS:
return True
# 按用户 ID 取模得到确定性采样
return int(hashlib.md5(user_id.encode()).hexdigest()[:2], 16) < SAMPLE_RATE
9.5 敏感信息脱敏
对于包含个人身份信息的输入或输出,在发送给 LangSmith 之前必须做脱敏处理。可以在全局层面注册回调钩子,或者在 @traceable 装饰器中处理:
@traceable(capture_input=False) # 完全不记录输入
def process_user_data(user_info):
# 处理逻辑
pass
也可以在 Middleware 中统一脱敏,确保 Trace 数据不会泄露用户隐私。
9.6 Dashboard 和监控
当项目已经持续运行并且有了稳定流量之后,可以在 LangSmith 的 Monitor 选项卡中观察 Token 用量、请求耗时、错误率等核心指标。对于企业级应用,建议每小时自动导出指标到内部监控系统,并设置核心指标阈值告警。
十、本节知识点总结
经过这一节课的系统实战,你可以全面、有层次地回顾以下核心技能:
| 知识点类别 | 具体内容 |
|---|---|
| 环境搭建 | .env 配置、Project 命名、环境变量验证脚本 |
| 最简追踪 | 通过 LangChain + LCEL 获得第一个 Trace |
| 嵌套追踪 | 使用 @traceable 记录多层级函数调用、设置 run_type |
| Threads 会话 | 通过 metadata 中的 thread_id 关联多轮对话 |
| 企业级 Agent | 结合意图识别、工具调用、RAG 检索的完整客服系统 |
| 避坑实操 | thread_id 归属 metadata、project 隔离、配额超限处理 |
| 企业规范 | 标准化 Tag、环境隔离、生产采样、数据脱敏 |
十一、课后思考练习题
练习题1:理论理解(简答题)
1.1 请用 200 字以内的篇幅解释 Trace、Run、Thread 的关系。
1.2 如果我在调用链中既想追踪大模型的输入输出,又想追踪自定义的数值计算环节,用 @traceable 装饰器需要注意什么?
1.3 @traceable 与 wrap_openai 的区别有哪些?什么时候更适合用 wrap_openai?
练习题2:动手实践(编码题)
2.1 改造 first_trace.py,实现一个 translate 函数:接收一个英文句子,先调用 LLM 将其翻译成中文,再统计翻译结果的字符数(统计字符数也需出现在 Trace 的子 Run 中)。最终在 LangSmith UI 中确认字符数统计的 Run 是否依附于翻译父 Run 下。
2.2 从你工作的实际业务场景或开源数据集中抽取 3 条真实的客服 Case,修改 advanced_customer_support.py,增加一个对应的 Thread 并在 UI 中观察对话历史。
练习题3:场景设计(分析题)
3.1 假设你维护的客服 Agent 支持 10 种工具。某一天你发现一个用户的追问总是得到错误答案,但其他用户都正常。请设计一套基于 LangSmith 的排查流程:如何过滤该用户的 Trace、如何定位偏离发生在哪一轮对话、如何确定是哪个工具调用错误。
3.2 公司要求对所有生产环境的 Trace 做 7 天实时监控,但同时开发者希望对高优先级用户的互动做永久留痕。请设计一个技术方案,确保高优先级数据不被自动清理。
练习题4:生产级扩展(选做)
4.1 基于 advanced_customer_support.py 增加一个完整的 prompt 版本管理流程:利用 LangSmith 的 dataset + evaluation 功能,对比 prompt v1 和 prompt v2 在该客服场景上的准确率,并用 Evaluation 面板展示结果。
4.2 部署一个简单的 FastAPI Web 服务,暴露 /chat 接口,背后调用客服 Agent。利用中间件自动为每个请求生成 thread_id 并透传 metadata(包括 client_ip、user_agent)。这样你可以在生产流量中实时看到每条 API 调用对应的 Trace。
下节课预告:
第 6 节课我们深入环境变量与密钥配置,学会在多环境(dev/prod)之间安全切换密钥,并用加密手段规避 KEY 被硬编码或提交到 Git 仓库的泄露风险。这部分内容对生产级应用尤其重要。
下一节课见!
🔗《20节课 LangSmith 从入门到精通》系列课程导航
🌟 感谢您耐心阅读到这里!
💡 如果本文对您有所启发欢迎:
👍 点赞📌 收藏 📤 分享给更多需要的伙伴。
🗣️ 期待在评论区看到您的想法, 共同进步。
🔔 关注我,持续获取更多干货内容~
🤗 我们下篇文章见~
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)