专栏系列第 7 篇 · 智能体纪元
引言:AI Agent开发的范式变革
在大型语言模型(LLM)技术爆发的今天,AI Agent已从简单的问答工具演变为具备复杂认知能力的智能系统。这种进化对开发工具提出了全新要求:如何追踪智能体的思考过程?如何编排多步骤工作流?如何确保系统的可靠性和可观测性?LangSmith与LangGraph作为LangChain生态的核心组件,正是为解决这些问题而生。本文将深入解析这两个组件的设计哲学、技术架构与应用实践。
在理解LangSmith与LangGraph之前,需要明确它们在LangChain生态中的定位。假设读者已具备以下基础概念:
- Agent:能调用工具自主完成任务的智能体(如通过
AgentExecutor实现) - Chain:将LLM与其他组件串联的基础执行单元
- Tool:Agent可调用的功能扩展(如计算器、搜索引擎)
LangSmith与LangGraph并非独立存在,而是对LangChain核心能力的增强:
- LangSmith → 观测性增强
- LangGraph → 流程控制增强
本文将通过对比演示,展现这两个组件如何将基础Agent进化为工业级智能系统。
一、LangSmith:AI Agent的可观测性中枢
1. 设计理念:让AI开发透明可见
LangSmith源于一个简单却深刻的认知:黑箱化是AI系统不可靠的根源。传统LLM应用开发中,开发者往往面临三大痛点:
- 无法追踪模型调用链
- 难以定位逻辑错误
- 缺乏性能评估基准
开发者面临的核心痛点:
- 盲盒调试:不知道哪步工具调用出错
- 性能黑洞:不清楚API调用耗时分布
- 迭代失控:无法量化版本升级的影响
LangSmith通过全链路追踪和可视化分析,将AI Agent的"思维过程"转化为可解释的数据图谱,实现了开发范式的根本转变。
1.1 只需添加几行配置即获得全维度观测能力
pip install langchain_openai langchain_core
export LANGCHAIN_TRACING_V2=true
export LANGSMITH_API_KEY=<your-api-key>
# This example uses OpenAI, but you can use any LLM provider of choice
export OPENAI_API_KEY=<your-openai-api-key>
1.2 无需额外代码即可将Trace(痕迹)记录到 LangSmith
import os
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
# os.environ['LANGSMITH_TRACING'] = "True"
os.environ['LANGCHAIN_TRACING_V2'] = 'true'
prompt = ChatPromptTemplate.from_messages([
("system", "您是一位得力的智能助手。请仅根据给定的上下文,使用合适的语言响应用户的请求。"),
("user", "问题: {question}\n上下文: {context}")
])
model = ChatOpenAI(
model='deepseek-chat',
openai_api_key=os.getenv('DEEPSEEK_API_KEY'),
openai_api_base='https://api.deepseek.com/v1',
temperature=0
)
output_parser = StrOutputParser()
chain = prompt | model | output_parser
question = "你能总结一下今天上午的会议吗?"
context = "在今天上午的会议上,我们解决了世界上所有的冲突。"
result = chain.invoke({"question": question, "context": context})
print(result)
1.3 查看Trace
smith.langchain.com/o/9015dba0-…
上面展示了如何通过设置单个环境变量来跟踪应用程序中 LangChain 可运行对象的所有调用。虽然这是一种便捷的入门方法,但你可能只想跟踪应用程序的特定调用或部分内容。
1.4 手动传入LangChainTracer实例作为回调来跟踪
from langchain.callbacks.tracers import LangChainTracer
# 取消设置 LANGSMITH_TRACING
# os.environ['LANGCHAIN_TRACING_V2'] = 'true'
# 可以设置LANGSMITH_PROJECT环境变量,为整个应用程序运行配置自定义项目名称
os.environ['LANGSMITH_PROJECT'] = 'default'
tracer = LangChainTracer()
chain.invoke({"question": "我是否正在使用回调?", "context": "我正在使用回调。"}, config={"callbacks": [tracer]})
1.5 使用tracing_v2_enabled上下文管理器来跟踪
from langchain_core.tracers.context import tracing_v2_enabled
with tracing_v2_enabled():
chain.invoke({"question": "我是否正在使用上下文管理器?", "context": "我正在使用上下文管理器。"})
1.6 单独设置项目名称参数
from langchain.callbacks.tracers import LangChainTracer
tracer = LangChainTracer(project_name='default')
chain.invoke({"question": "我是否正在使用回调?", "context": "我正在使用回调。"}, config={"callbacks": [tracer]})
from langchain_core.tracers.context import tracing_v2_enabled
with tracing_v2_enabled(project_name='default'):
chain.invoke({"question": "我是否正在使用上下文管理器?", "context": "我正在使用上下文管理器。"})
1.7 在Config中提供任意元数据和标签,从而为跟踪添加注释
这有助于将其他信息与跟踪关联起来,例如跟踪的执行环境或发起跟踪的用户。
import os
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
os.environ['LANGCHAIN_TRACING_V2'] = 'true'
prompt = ChatPromptTemplate.from_messages([
("system", "你是一个乐于助人的人工智能。"),
("user", "{input}")
])
# 标签“model-tag”和元数据 {“model-key”:“model-value”} 将仅附加到 ChatOpenAI 运行
chat_model = ChatOpenAI(
model='deepseek-chat',
openai_api_key=os.getenv('DEEPSEEK_API_KEY'),
openai_api_base='https://api.deepseek.com/v1',
temperature=0
).with_config({"tags": ["model-tag"], "metadata": {"model-key": "model-value"}})
output_parser = StrOutputParser()
# 可以使用 RunnableConfig 配置标签和元数据
chain = (prompt | chat_model | output_parser).with_config(
{"tags": ["config-tag"], "metadata": {"config-key": "config-value"}})
# 标签和元数据也可以在运行时传递
chain.invoke({"input": "生命的意义是什么?"},
{"tags": ["invoke-tag"], "metadata": {"invoke-key": "invoke-value"}})
1.8 通过在Config中提供名称来自定义给定运行的名称
# 在 LangChain 内跟踪时,运行名称默认为被跟踪对象的类名(例如,“ChatOpenAI”)。
configured_chain = chain.with_config({"run_name": "MyCustomChain"})
configured_chain.invoke({"input": "生命的意义是什么?"})
# 您还可以在调用时配置运行名称,如下所示
chain.invoke({"input": "生命的意义是什么?"}, {"run_name": "MyCustomChain"})
1.9 通过在Config中提供 ID 来自定义特定运行的 ID
import uuid
my_uuid = uuid.uuid4()
# You can configure the run ID at invocation time:
chain.invoke({"input": "What is the meaning of life?"}, {"run_id": my_uuid})
2. 核心功能全景
在LangSmith控制台中可分析:
| 功能模块 | 技术实现 | 应用场景 |
|---|---|---|
| 调用链追踪 | 异步日志采集系统 | 调试复杂Agent逻辑 |
| 性能监控 | 时序数据库+指标计算引擎 | 成本优化与资源调配 |
| 数据标注 | 人工反馈集成接口 | 构建高质量微调数据集 |
| 回归测试 | 版本对比+差异分析 | 保障系统迭代稳定性 |
3. 深度集成实践
(1) 全链路追踪配置
import os
from langsmith import RunTree
from langchain_openai import ChatOpenAI
# ------------------ 环境变量配置 ------------------
# 确保在环境变量或 .env 文件中配置了以下内容:
# LANGCHAIN_API_KEY: LangSmith 的 API Key
# DEEPSEEK_API_KEY: deepseek 模型的 API Key
os.environ["LANGCHAIN_ENDPOINT"] = os.getenv("LANGCHAIN_ENDPOINT", "https://api.smith.langchain.com")
# ------------------ 初始化 LLM ------------------
llm = ChatOpenAI(
model="deepseek-chat",
openai_api_key=os.getenv("DEEPSEEK_API_KEY"),
openai_api_base="https://api.deepseek.com/v1",
temperature=0,
)
# ------------------ 用户输入 ------------------
user_query = "我忘记了登录密码,怎么才能尽快重新设置?"
# ------------------ 顶层追踪节点 ------------------
run_tree = RunTree(
name="customer_service_agent_trace",
inputs={"user_query": user_query},
tags=["langsmith-demo", "run_tree", "full_trace"]
)
try:
# ------------------ 子任务 1:调用 LLM 生成回复 ------------------
prompt = (
"请为用户生成一段简洁友好的密码重置指引,"
"说明操作步骤,并提醒用户注意账户安全。"
)
llm_child = RunTree(
name="llm_inference",
inputs={"prompt": prompt},
parent_id=run_tree.id # 👈 建立层级
)
response = llm.invoke(prompt)
llm_child.add_outputs({"response": response})
llm_child.post() # 👈 上传子节点
# ------------------ 子任务 2:格式化输出 ------------------
format_child = RunTree(
name="format_response",
inputs={"raw_response": response},
parent_id=run_tree.id
)
formatted = f"您好,{response} 如有疑问请联系人工客服协助处理。"
format_child.add_outputs({"formatted_response": formatted})
format_child.post()
# ------------------ 顶层输出 ------------------
run_tree.add_outputs({"final_response": formatted})
except Exception as e:
run_tree.add_outputs({"error": str(e)})
raise
finally:
run_tree.post() # 👈 上传主节点到 LangSmith 平台
# 控制台展示最终结果
print(formatted)
这个示例展示了如何使用 LangChain 与 LangSmith 搭建一个“客服智能体”的原型,并通过 RunTree 工具对整个执行过程进行结构化的全链路追踪。追踪的内容不仅包括最终结果,还详细记录了每一步中 LLM 的调用和响应处理。
当你在网站上向客服机器人提问,比如“我忘记密码了怎么办?”,背后其实是一个小程序在帮你处理:
- 它会把你的问题转化成一句清晰的“提示语”,比如:“请生成密码重置流程的说明”;
- 然后它调用一个智能模型来写出这段说明;
- 最后它把这段说明稍微润色一下,再发给你。
为了让开发者能“看清楚”这个机器人到底每一步做了什么,我们用 LangSmith 提供的“追踪系统”记录了整个过程——就像一张“处理流程图”,可以在平台上回放每一步的输入和输出。
在LangSmith控制台中,开发者可直观看到:
- 每个工具(Tools)的调用耗时
- 各步骤的Token消耗占比
- 异常调用的堆栈追踪
二、LangGraph:复杂认知工作流的编排引擎
1. 架构哲学:从链式到图式
传统LangChain的链式(Chain)结构在处理以下场景时显露局限:
- 带循环的对话状态管理
- 多Agent协同决策
- 动态路径选择
LangGraph引入 有向无环图(DAG) 模型,通过三大创新突破限制:
- 状态持久化:支持长时间运行的智能体会话
- 条件分支:实现基于上下文的动态路由
- 并行执行:提升复杂任务的完成效率
当客服Agent需要处理以下场景时,传统链式架构遇到瓶颈:
# 传统线性处理
response = agent.run("我要退货,上周买的鞋子尺寸不对")
# 隐含需求:1.验证订单 2.检查退货政策 3.生成退货码 4.通知物流
痛点呈现:
- 僵化流程:无法动态调整处理步骤
- 状态丢失:多轮交互后无法回溯上下文
- 资源争用:无法并行执行独立任务
2. 核心抽象模型
graph TD
Start --> Preprocessor
Preprocessor --> |普通问题| QA_Agent
Preprocessor --> |技术问题| Tech_Support
Preprocessor --> |投诉建议| CRM_System
QA_Agent --> Response_Generator
Tech_Support --> Knowledge_Base
CRM_System --> Ticket_System
Response_Generator --> End
Knowledge_Base --> Response_Generator
Ticket_System --> Response_Generator
3. 企业级应用案例
客户服务自动化系统
import os
import sqlite3
from typing import TypedDict, Literal, Optional
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.tracers import LangChainTracer
from langchain_openai import ChatOpenAI
from langchain_core.output_parsers import StrOutputParser
from langgraph.checkpoint.sqlite import SqliteSaver
from langgraph.graph import StateGraph, END
# LangSmith配置
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = "default"
tracing_handler = LangChainTracer()
class AgentState(TypedDict):
"""代理状态类型定义
Attributes:
user_input: str 用户输入文本
intent: Optional[Literal["普通问题", "技术问题", "投诉问题"]] 问题分类结果
response: Optional[str] 生成的响应内容
"""
user_input: str
intent: Optional[Literal["普通问题", "技术问题", "投诉问题"]]
response: Optional[str]
# 初始化大语言模型
llm = ChatOpenAI(
model='deepseek-chat',
openai_api_key=os.getenv('DEEPSEEK_API_KEY'), # 从环境变量获取API密钥
openai_api_base='https://api.deepseek.com/v1', # DeepSeek API端点
temperature=0, # 控制生成结果的随机性
callbacks=[tracing_handler] # 集成 LangSmith
)
output_parser = StrOutputParser() # 用于解析LLM输出的纯文本结果
def safe_set_intent(value: str) -> Optional[Literal["普通问题", "技术问题", "投诉问题"]]:
"""安全设置问题分类
Args:
value: 待验证的分类字符串
Returns:
当输入为有效分类时返回原值,否则返回None
"""
return value if value in ("普通问题", "技术问题", "投诉问题") else None
def classify_intent(state: AgentState) -> AgentState:
"""问题分类节点
Args:
state: 当前对话状态
Returns:
更新后的状态(包含分类结果)
"""
prompt = ChatPromptTemplate.from_template(
"请判断用户问题类型,只返回普通问题/技术问题/投诉问题,不要包含任何格式符号或额外文字。问题内容:{input}"
)
chain = prompt | llm | output_parser # 构建处理链
intent = chain.invoke({"input": state["user_input"]}).strip()
return {
"user_input": state["user_input"],
"intent": safe_set_intent(intent), # 安全设置分类
"response": None
}
def handle_general(state: AgentState) -> AgentState:
"""普通问题处理节点"""
prompt = ChatPromptTemplate.from_template(
"你是一个客服助手,请用纯文本回答以下普通问题,不要包含任何格式符号或标记。问题:{input}"
)
chain = prompt | llm | output_parser
response = chain.invoke({"input": state["user_input"]})
return {
"user_input": state["user_input"],
"intent": state.get("intent"),
"response": response
}
def handle_tech(state: AgentState) -> AgentState:
"""技术问题处理节点"""
prompt = ChatPromptTemplate.from_template(
"你是一名技术支持工程师,请用纯文本回答以下技术问题,不要包含任何格式符号或标记。技术问题:{input}"
)
chain = prompt | llm | output_parser
response = chain.invoke({"input": state["user_input"]})
return {
"user_input": state["user_input"],
"intent": state.get("intent"),
"response": response
}
def handle_complaint(state: AgentState) -> AgentState:
"""投诉问题处理节点"""
prompt = ChatPromptTemplate.from_template(
"你是一名投诉处理专员,请用纯文本回答以下投诉,不要包含任何格式符号或标记。投诉内容:{input}"
)
chain = prompt | llm | output_parser
response = chain.invoke({"input": state["user_input"]})
return {
"user_input": state["user_input"],
"intent": state.get("intent"),
"response": response
}
def decide_next_step(state: AgentState) -> str:
"""路由决策函数
Args:
state: 当前对话状态
Returns:
下一节点的名称
"""
return state.get("intent", "普通问题") # 默认路由到普通问题
# 构建工作流
workflow = StateGraph(AgentState)
# 注册节点
workflow.add_node("classify", classify_intent) # 分类节点
workflow.add_node("普通问题", handle_general) # 注意:节点名称改为中文
workflow.add_node("技术问题", handle_tech)
workflow.add_node("投诉问题", handle_complaint)
# 设置条件路由(修正后的映射关系)
workflow.add_conditional_edges(
"classify",
decide_next_step,
{
"普通问题": "普通问题", # 键值统一使用中文
"技术问题": "技术问题",
"投诉问题": "投诉问题"
}
)
# 设置终止边
workflow.add_edge("普通问题", END)
workflow.add_edge("技术问题", END)
workflow.add_edge("投诉问题", END)
# 设置入口点
workflow.set_entry_point("classify")
# 编译时启用检查点
conn = sqlite3.connect("checkpoints.sqlite", check_same_thread=False)
memory = SqliteSaver(conn)
app = workflow.compile(checkpointer=memory)
if __name__ == "__main__":
# 测试用例
test_cases = [
("user_001", "你们的工作时间是几点?"),
("user_002", "我的账号无法登录"),
("user_003", "我要投诉你们的服务态度")
]
for user_id, query in test_cases:
print(f"\n[会话 {user_id}] 用户提问: {query}")
# 执行工作流(关键修正)
result = app.invoke(
{"user_input": query},
config={"configurable": {"thread_id": user_id}}
)
print(f"问题类型: {result.get('intent')}")
print(f"系统回复: {result.get('response')}")
# 验证检查点
checkpoint = memory.get_tuple({"configurable": {"thread_id": user_id}})
print(f"检查点状态: {checkpoint}")
输出:
LangSmith监控:
该工作流实现:
- 智能会话状态管理
- 基于意图的动态路由
- 断点续话能力
4. 核心概念解析
1. 状态流(State Flow)
核心概念:
LangGraph 的核心是基于状态流转的图计算模型,通过 StateGraph 定义数据流。状态是一个类型化的字典(TypedDict),在节点间传递和修改。
代码体现:
class AgentState(TypedDict): # 定义状态结构
user_input: str
intent: Optional[Literal["普通问题", "技术问题", "投诉问题"]]
response: Optional[str]
workflow = StateGraph(AgentState) # 声明状态流
2. 节点(Nodes)
核心概念:
节点是纯函数,接收当前状态,返回更新后的状态。LangGraph 不限制节点内部逻辑(可调用LLM、工具、API等)。
代码体现:
def classify_intent(state: AgentState) -> AgentState:
# 调用LLM进行分类
return {"intent": "技术问题"} # 只更新部分状态
workflow.add_node("classify", classify_intent) # 注册节点
3. 边(Edges)
核心概念:
边定义节点间的流转路径,分为两种:
- 固定边:
add_edge("node1", "node2") - 条件边:基于状态动态路由
代码体现:
# 条件边(根据intent值路由)
workflow.add_conditional_edges(
"classify",
decide_next_step, # 路由决策函数
{"技术问题": "tech_node", ...}
)
# 固定边(直接跳转)
workflow.add_edge("tech_node", END)
4. 检查点(Checkpoints)
核心概念:
检查点(Checkpoint)是在任务或流程执行过程中自动保存中间状态的一种机制,旨在实现容错恢复、状态追踪和重复计算避免。在 LangGraph 等流程编排框架中,检查点用于持久化每个节点执行后的状态,使得在流程中断或异常退出后,可以从最近的检查点恢复继续执行,而无需重头开始。检查点既可保存在内存中(如 MemorySaver),也可持久化到本地数据库(如 SqliteSaver)或远程存储(如 RedisSaver),以适应不同的开发与部署场景。
代码体现:
import sqlite3
from langgraph.checkpoint.sqlite import SqliteSaver
conn = sqlite3.connect("checkpoints.sqlite", check_same_thread=False)
memory = SqliteSaver(conn)
app = workflow.compile(checkpointer=memory)
5. 执行模型
核心概念:
LangGraph 采用异步有向图执行模型:
- 从
entry_point开始 - 按边条件流转
- 直到到达
END
代码体现:
workflow.set_entry_point("classify") # 设置起点
app.invoke({"user_input": "问题内容"}) # 执行流式
与上面代码的映射
| 概念 | 代码示例 | 设计目的 |
|---|---|---|
| 状态 | AgentState | 定义数据流动的规范格式 |
| 节点 | handle_tech/classify_intent | 模块化业务逻辑 |
| 条件路由 | decide_next_step 函数 | 实现动态流程控制 |
| 持久化 | SqliteSaver | 支持长周期对话状态管理 |
架构优势对比
| 能力项 | 传统Agent | LangGraph Agent |
|---|---|---|
| 流程动态性 | 固定顺序 | 基于上下文的条件分支 |
| 状态管理 | 短期记忆 | 持久化检查点(Checkpoint) |
| 执行模式 | 串行 | 支持并行与异步 |
| 错误恢复 | 整体失败 | 局部重试与补偿机制 |
三、LangChain生态的协同进化
1. 技术定位关系
graph LR
LangChain_Core --> Models
LangChain_Core --> Tools
LangChain_Core --> Memory
LangSmith --> Monitoring
LangGraph --> Workflow
Models --> LangSmith
Tools --> LangGraph
Memory --> LangSmith
2. 协同开发模式
-
开发阶段:
- 使用LangGraph设计工作流拓扑
- 通过LangSmith调试单个节点
-
测试阶段:
- 在LangSmith中创建黄金数据集
- 执行自动化回归测试
-
运维阶段:
- 实时监控生产环境指标
- 通过检查点回放定位问题
3. 性能基准对比
| 任务类型 | 纯LangChain | LangChain+LangGraph | 提升幅度 |
|---|---|---|---|
| 多步骤推理 | 12.4s | 8.7s | 30% |
| 带循环的对话 | 失败率32% | 失败率4% | 87% |
| 资源消耗 | 38GB内存 | 22GB内存 | 42% |
四、未来愿景:通向AGI的开发范式
1. LangSmith的演进方向
- 智能根因分析:自动定位异常调用的逻辑链路
- 预测性缩放:基于流量模式的自动资源调配
- 合规审计:满足GDPR等法规的数据溯源需求
2. LangGraph的长期目标
- 分布式Agent网络:支持跨物理节点的智能体协作
- 强化学习集成:实现工作流的自主优化
- 量子计算就绪:为新型计算架构预留接口
3. 开发者体验升级
- 可视化编程界面:拖拽式工作流设计器
- 智能代码生成:自然语言转LangGraph配置
- 元宇宙调试环境:3D空间中的Agent思维可视化
结语:重新定义AI工程边界
LangSmith与LangGraph不仅代表着技术工具的进步,更预示着一个新纪元的开启:当AI系统的开发过程变得完全透明可控,当复杂认知任务的编排如同搭积木般简单,人类终于站在了构建可靠智能系统的门槛之上。这两个组件的演化轨迹,正勾勒出未来AGI开发平台的雏形——在这里,每个开发者都能像指挥交响乐团般,优雅地驾驭智能的洪流。