LangChain、LangGraph与LangSmith:构建可控AI智能体的三大核心框架
最近在尝试将大语言模型(LLM)应用到具体的业务场景中,比如医疗问诊、金融客服,发现单纯调用一个模型 API 往往力不从心。模型不知道如何获取最新知识,无法执行多步骤任务,更缺乏对复杂流程的控制。这时, LangChain、LangGraph 和 LangSmith 这三个工具就进入了视野。它们分别解决了 LLM 应用开发中的工具链、流程编排和监控调试三大核心难题。本文将以一个 医疗问诊智能体(Agent) 的构建过程为主线,手把手带你理解这三个框架的核心概念、区别与协作方式,并提供一个可运行的代码示例。无论你是刚接触 AI 应用开发的新手,还是希望系统化工程化的开发者,都能从中获得清晰的路径。
1. 背景与核心概念:为什么需要它们?
在深入代码之前,我们必须先理清这三个工具各自扮演的角色,以及它们如何协同工作。这就像组建一个现代化的医院。
1.1 LangChain:医生的“工具箱”
LangChain 是一个用于开发由语言模型驱动的应用程序的框架。你可以把它想象成一位全能医生随身携带的 工具箱 。
- 它是什么 :一套标准化的接口和组件,用于连接 LLM、外部数据源(如数据库、搜索引擎)、记忆存储以及各种工具(如计算器、API)。
- 解决什么问题 :解决了 LLM 的“孤立”问题。LLM 本身是一个强大的“大脑”,但缺乏“手”(执行工具)、“眼睛”(读取数据)和“记忆”(记住对话)。LangChain 通过
Chains、Agents、Retrieval等模块,将这些能力有机地组合起来。 - 核心组件 :
- Models : 封装各种 LLM(OpenAI, Anthropic, 本地模型等)和 Embedding 模型。
- Prompts : 管理提示词模板,实现动态提示生成。
- Indexes : 用于文档加载、分割、向量化存储和检索(即 RAG 的核心)。
- Chains : 将多个组件按顺序链接起来,执行一个固定流程。
- Agents : 让 LLM 根据当前情况,自主决定调用哪个工具(来自
Tools)来完成任务。这是实现“智能”的关键。 - Memory : 在对话或交互中持久化状态信息。
简单来说,LangChain 让你能方便地告诉 LLM:“这是计算器(工具),这是病历数据库(检索器),你用它们来帮病人诊断。”
1.2 LangGraph:医院的“就诊流程图”
当问诊流程变得复杂,比如需要分诊、多科室会诊、检查、开药等环节循环时,简单的链(Chain)或基础的智能体(Agent)就难以清晰表达这种带有 循环、分支、并行 的状态逻辑。
LangGraph 是建立在 LangChain 之上的一个库,用于构建具有 状态和循环 的复杂、有状态的应用程序。
- 它是什么 :一个基于图(Graph)的工作流编排框架。它用节点(Node)和边(Edge)来定义应用程序的执行流程。
- 解决什么问题 :解决了复杂、多步骤、有状态任务的流程控制问题。它让 Agent 的行为不再是“一次思考-行动”,而是可以像流程图一样,在不同的状态间流转,直到满足终止条件。
- 核心概念 :
- State : 定义整个工作流共享的数据结构(如病人信息、当前症状、已做检查、诊断结果)。
- Nodes : 图中的节点,代表一个执行步骤(如“分诊”、“问诊”、“开检查单”)。每个节点是一个函数,接收 State,修改 State,并返回结果。
- Edges : 连接节点的边,决定下一个执行哪个节点。可以是条件边(根据 State 内容决定),也可以是固定边。
- Checkpointer : 支持持久化状态,实现长时运行工作流的暂停与恢复。
用医院比喻,LangGraph 就是那张清晰的“就诊流程图”,规定了病人从挂号到离院的每一步路径和规则。
1.3 LangSmith:医院的“监控与质控中心”
开发调试一个 LLM 应用非常痛苦:提示词效果不好、链调用出错、Agent 决策诡异、成本不可控。
LangSmith 是一个用于调试、测试、评估和监控 LLM 应用程序的开发平台。
- 它是什么 :一个云服务平台(也有本地部署方案),为 LangChain/LangGraph 应用提供全生命周期的可观测性。
- 解决什么问题 :解决了 LLM 应用开发中的“黑盒”问题,提供了追踪、评估、版本管理能力。
- 核心功能 :
- Tracing : 自动记录每次 Chain、Agent、LLM 调用的输入、输出、耗时、token 消耗和内部步骤,形成可视化链路。
- Testing & Evaluation : 创建数据集,批量测试应用,并利用 LLM 或规则自动评估输出质量。
- Prompt Management : 版本化管理提示词,方便对比不同提示词的效果。
- Monitoring : 监控生产环境应用的性能、成本和异常。
它就像医院的监控中心,记录每一次诊疗过程,评估医生(Agent)的表现,并不断优化诊疗规范(Prompt)。
1.4 三者关系总结
- LangChain 提供砖瓦和水泥 (Models, Tools, Memory等基础组件)。
- LangGraph 提供建筑设计图和施工流程 (用图来编排这些组件,构建复杂应用)。
- LangSmith 提供工程监理和质量检测体系 (确保建筑过程可控,结果可靠)。
接下来,我们将用它们构建一个简化的医疗问诊 Agent。
2. 环境准备与版本说明
我们将使用 Python 进行开发。请确保你的环境满足以下要求:
- 操作系统 : Windows 10/11, macOS 或 Linux (Ubuntu 20.04+)
- Python : 版本 3.10 或 3.11(推荐 3.11,兼容性最好)
- 包管理工具 : pip
首先,创建一个新的项目目录并安装必要的依赖。我们主要使用 langchain , langgraph , langsmith 的客户端,以及 OpenAI 的 LLM(你也可以替换为其他兼容 API 的模型,如 Anthropic、通义千问等)。
# 创建项目目录
mkdir medical-agent-tutorial && cd medical-agent-tutorial
# 创建虚拟环境 (可选但推荐)
python -m venv venv
# Windows: venv\Scripts\activate
# macOS/Linux: source venv/bin/activate
# 安装核心依赖
pip install langchain langgraph langsmith openai
# 安装其他可能用到的工具库
pip install python-dotenv # 用于管理环境变量
版本说明 : 本文示例基于以下主要库版本编写,不同版本间 API 可能有细微差异,请以官方文档为准。
langchain==0.1.0及以上langgraph==0.0.40及以上langsmith==0.0.85及以上openai==1.0.0及以上
重要 :你需要一个 OpenAI API Key 来运行示例。请将其保存在项目根目录的 .env 文件中,不要硬编码在代码里。
# .env 文件内容
OPENAI_API_KEY=sk-your-actual-api-key-here
LANGCHAIN_API_KEY=ls-your-langsmith-api-key-here # 可选,如果使用LangSmith
LANGCHAIN_TRACING_V2=true # 可选,启用LangSmith追踪
LANGCHAIN_PROJECT=Medical-Agent-Tutorial # 可选,指定LangSmith项目名
3. 核心组件拆解:构建问诊 Agent 的基石
在画流程图(LangGraph)之前,我们需要先用 LangChain 准备好“工具箱”里的工具。
3.1 定义工具:医生的“听诊器”和“检查单”
我们的问诊 Agent 需要一些基础工具。这里模拟三个工具:
- 症状查询工具 :模拟一个医学知识库,根据症状关键词返回可能的疾病信息。
- 检查建议工具 :根据当前怀疑的疾病,建议需要做的检查项目。
- 药品查询工具 :根据疾病和患者过敏史,推荐安全药品。
# tools.py
from langchain.tools import tool
from typing import Optional
@tool
def query_symptom_knowledge(symptom: str) -> str:
"""
根据症状关键词查询医学知识库,返回可能的疾病信息。
Args:
symptom: 症状描述,如“发烧咳嗽”、“腹痛腹泻”。
Returns:
可能的疾病列表和简要说明。
"""
# 这里模拟一个简单的知识库,真实场景应连接向量数据库或专业API
knowledge_base = {
"发烧咳嗽": "可能疾病:1. 普通感冒:上呼吸道感染,通常伴有鼻塞、流涕。\n2. 流感:起病急,高热、全身酸痛、乏力明显。\n3. 肺炎:可能伴有胸痛、咳脓痰、呼吸困难。",
"腹痛腹泻": "可能疾病:1. 急性胃肠炎:多由不洁饮食引起,常伴恶心、呕吐。\n2. 细菌性痢疾:里急后重,便中带脓血。\n3. 肠易激综合征:慢性病程,与情绪、饮食相关。",
"头痛头晕": "可能疾病:1. 偏头痛:单侧搏动性头痛,可能畏光畏声。\n2. 紧张性头痛:双侧压迫感或紧箍感。\n3. 高血压:需测量血压确认。"
}
return knowledge_base.get(symptom, f"知识库中未找到关于'{symptom}'的典型疾病信息。建议提供更详细症状。")
@tool
def suggest_examination(disease_suspicion: str) -> str:
"""
根据怀疑的疾病,建议需要做的检查项目。
Args:
disease_suspicion: 怀疑的疾病名称,如“肺炎”、“急性胃肠炎”。
Returns:
建议的检查项目列表。
"""
examination_map = {
"肺炎": "建议检查:1. 血常规 2. C反应蛋白(CRP) 3. 胸部X光或CT 4. 痰培养",
"急性胃肠炎": "建议检查:1. 血常规 2. 粪便常规+潜血 3. 电解质检查(若脱水严重)",
"流感": "建议检查:1. 血常规 2. 流感病毒抗原检测(咽拭子)",
"高血压": "建议检查:1. 血压监测(动态/家庭) 2. 心电图 3. 肾功能、尿常规 4. 眼底检查"
}
return examination_map.get(disease_suspicion, f"对于疾病'{disease_suspicion}',建议咨询专科医生确定具体检查。")
@tool
def recommend_medication(disease: str, allergy_history: Optional[str] = None) -> str:
"""
根据疾病和患者过敏史,推荐安全药品。
Args:
disease: 确诊或高度怀疑的疾病名称。
allergy_history: 患者过敏史,如“青霉素过敏”、“磺胺过敏”。
Returns:
药品推荐及注意事项。
"""
medication_guide = {
"普通感冒": "推荐:1. 对症治疗:布洛芬(退烧止痛)。2. 复方感冒药(如酚麻美敏)。\n注意:多休息,多喝水。",
"细菌性肺炎": "推荐:1. 抗生素:阿莫西林克拉维酸钾(若无青霉素过敏)。若青霉素过敏,可用左氧氟沙星或阿奇霉素。\n2. 止咳化痰药:氨溴索。",
"高血压": "推荐:1. 一线药物:氨氯地平(钙通道阻滞剂)或厄贝沙坦(ARB类)。\n需在医生指导下长期规律服用,定期监测血压。"
}
recommendation = medication_guide.get(disease, f"疾病'{disease}'的常规用药建议请咨询药师或医生。")
if allergy_history:
if "青霉素" in allergy_history and "阿莫西林" in recommendation:
recommendation += f"\n【重要警告】患者有{allergy_history},禁止使用青霉素类抗生素(如阿莫西林),请更换其他类别抗生素。"
if "磺胺" in allergy_history and "复方" in recommendation:
recommendation += f"\n【注意】部分复方感冒药含磺胺成分,有过敏史者慎用。"
return recommendation
3.2 创建智能体(Agent):赋予 LLM 使用工具的能力
我们将使用 LangChain 的 create_react_agent 来创建一个 ReAct 模式的智能体。这种模式的 Agent 会进行“思考(Reason)”和“行动(Act)”的循环。
# agent_basic.py
from langchain_openai import ChatOpenAI
from langchain.agents import create_react_agent, AgentExecutor
from langchain.prompts import PromptTemplate
from tools import query_symptom_knowledge, suggest_examination, recommend_medication
import os
from dotenv import load_dotenv
load_dotenv() # 加载 .env 文件中的环境变量
# 1. 初始化大语言模型
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0, api_key=os.getenv("OPENAI_API_KEY"))
# 2. 准备工具列表
tools = [query_symptom_knowledge, suggest_examination, recommend_medication]
# 3. 定义ReAct代理的提示词模板
# 这个模板告诉LLM如何思考、如何使用工具、如何格式化输出
react_prompt_template = """
你是一个专业的医疗问诊助手。请根据患者的描述,使用提供的工具来逐步分析病情,并提供最终建议。
你有权使用以下工具:
{tools}
使用工具时,请严格按照以下格式:
Thought: 我需要思考当前应该做什么
Action: 使用的工具名
Action Input: 工具的输入(必须是一个字符串)
Observation: 工具返回的结果
当你有了最终答案时,必须使用以下格式:
Thought: 我现在知道了最终答案
Final Answer: 给患者的最终建议,应清晰、全面、包含诊断思路、检查建议和用药提醒(如有)。
开始!
患者主诉:{input}
{agent_scratchpad}""" # agent_scratchpad 会自动填充之前的思考和行动历史
prompt = PromptTemplate.from_template(react_prompt_template)
# 4. 创建ReAct Agent 和 执行器
agent = create_react_agent(llm, tools, prompt)
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True)
# 5. 运行一个简单示例
if __name__ == "__main__":
patient_input = "我发烧,还咳嗽,浑身没力气。"
print(f"患者: {patient_input}")
print("-" * 50)
result = agent_executor.invoke({"input": patient_input})
print("\n" + "="*50)
print("助手最终回答:\n", result["output"])
运行 python agent_basic.py ,你会看到 Agent 的思考过程(因为 verbose=True ):
- Thought : 患者有发烧、咳嗽、乏力症状,我需要先查询可能的疾病。
- Action :
query_symptom_knowledge - Action Input :
发烧咳嗽 - Observation : 得到可能疾病列表(感冒、流感、肺炎)。
- Thought : 需要区分是感冒、流感还是肺炎,建议做检查来明确。
- Action :
suggest_examination - Action Input :
肺炎(它可能根据严重程度选择先排查肺炎) - ... 如此循环,直到它认为可以给出最终建议。
这个基础的 Agent 已经能完成多步任务,但它的流程是隐式的,由 LLM 每次临时决定。对于更复杂、更需要严格控制的流程,我们就需要 LangGraph 。
4. 完整实战:用 LangGraph 构建结构化问诊工作流
现在,我们来用 LangGraph 设计一个更贴近真实场景的、有状态的问诊流程图。流程包括: 分诊 -> 详细问诊 -> 检查建议 -> 初步诊断与用药建议 -> 结束 。
4.1 定义状态:患者的“病历本”
首先,我们定义整个工作流共享的状态(State)。这就像一份电子病历,记录问诊过程中的所有信息。
# graph_state.py
from typing import TypedDict, List, Optional, Annotated
import operator
class GraphState(TypedDict):
"""
定义LangGraph工作流的状态。
所有节点都读取和修改这个状态字典。
"""
# 患者输入
patient_input: str
# 从症状中提取的关键信息
extracted_symptoms: List[str]
# 知识库查询结果
possible_diseases: Optional[str]
# 建议的检查项目
suggested_exams: Optional[str]
# 患者过敏史(在问诊中获取)
allergy_history: Optional[str]
# 初步诊断
preliminary_diagnosis: Optional[str]
# 用药建议
medication_recommendation: Optional[str]
# 最终输出给患者的信息
final_advice: Optional[str]
# 控制流程的标记,决定下一步去哪
next_step: str # 例如: "triage", "inquire", "suggest_exam", "diagnose", "end"
4.2 构建图:定义节点和边
我们将创建五个节点函数,并定义它们之间的流转逻辑。
# medical_graph.py
from langgraph.graph import StateGraph, END
from graph_state import GraphState
from tools import query_symptom_knowledge, suggest_examination, recommend_medication
from langchain_openai import ChatOpenAI
import os
from dotenv import load_dotenv
load_dotenv()
llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
# ---------- 节点1: 分诊 (Triage) ----------
def triage_node(state: GraphState) -> GraphState:
"""
初步分诊节点。
分析患者主诉,提取关键症状,并决定下一步是直接查询知识库还是进入详细问诊。
"""
print("[节点] 进入分诊环节...")
symptoms = state["patient_input"]
# 这里可以用一个简单的LLM调用或规则来提取症状关键词
# 为了简化,我们假设输入就是症状描述
state["extracted_symptoms"] = [symptoms]
# 简单规则:如果症状描述简单(如“发烧咳嗽”),直接查知识库;否则进入详细问诊
if len(symptoms) < 20: # 简单判断
state["next_step"] = "query_knowledge"
else:
state["next_step"] = "inquire"
return state
# ---------- 节点2: 详细问诊 (Inquire) ----------
def inquire_node(state: GraphState) -> GraphState:
"""
详细问诊节点。
模拟医生进一步询问病史、过敏史等。
"""
print("[节点] 进入详细问诊环节...")
# 在实际应用中,这里可以是一个复杂的LLM对话,动态生成问题。
# 本例中我们模拟一个固定询问。
print("助手:请问您是否有已知的药物过敏史?(例如:青霉素、磺胺等)")
# 假设我们从状态或外部输入获取答案,这里模拟一个答案
simulated_allergy = "没有青霉素过敏史" # 实际应从交互中获取
state["allergy_history"] = simulated_allergy
state["next_step"] = "query_knowledge" # 问诊后去查询知识库
return state
# ---------- 节点3: 查询知识库 (Query Knowledge) ----------
def query_knowledge_node(state: GraphState) -> GraphState:
"""
使用工具查询症状对应的可能疾病。
"""
print("[节点] 查询医学知识库...")
symptom = state["extracted_symptoms"][0] if state["extracted_symptoms"] else state["patient_input"]
knowledge = query_symptom_knowledge.invoke(symptom)
state["possible_diseases"] = knowledge
print(f"知识库查询结果: {knowledge[:100]}...") # 打印部分结果
state["next_step"] = "suggest_exam"
return state
# ---------- 节点4: 建议检查 (Suggest Examination) ----------
def suggest_exam_node(state: GraphState) -> GraphState:
"""
根据可能的疾病,建议检查项目。
"""
print("[节点] 生成检查建议...")
# 从知识库结果中,让LLM提取一个最可能的疾病用于建议检查(简化处理)
# 实际应用中可能需要更复杂的逻辑
diseases_text = state["possible_diseases"]
# 简单提取第一行提到的疾病
first_line = diseases_text.split('\n')[0] if diseases_text else ""
target_disease = "肺炎" if "肺炎" in first_line else "急性胃肠炎" if "胃肠炎" in first_line else "感冒"
exams = suggest_examination.invoke(target_disease)
state["suggested_exams"] = exams
state["preliminary_diagnosis"] = f"考虑{target_disease}可能性大,需进一步检查明确。"
state["next_step"] = "diagnose"
return state
# ---------- 节点5: 诊断与建议 (Diagnose) ----------
def diagnose_node(state: GraphState) -> GraphState:
"""
综合信息,给出初步诊断和用药建议,形成最终输出。
"""
print("[节点] 生成最终诊断与建议...")
diagnosis = state["preliminary_diagnosis"]
allergy = state["allergy_history"]
# 同样,简化处理,从初步诊断中提取疾病名
disease_for_med = "肺炎" if "肺炎" in diagnosis else "普通感冒"
meds = recommend_medication.invoke(disease_for_med, allergy)
state["medication_recommendation"] = meds
# 组装最终建议
final_advice = f"""
【问诊总结】
患者主诉:{state['patient_input']}
【初步分析】
{state['possible_diseases']}
【检查建议】
{state['suggested_exams']}
【初步诊断】
{diagnosis}
【用药提醒】
{meds}
【重要提示】
以上为AI辅助分析,仅供参考,不能替代执业医师诊断。请尽快携带相关资料前往医院就诊,由医生进行最终诊断和治疗。
"""
state["final_advice"] = final_advice
state["next_step"] = "end"
return state
# ---------- 构建图 ----------
def create_medical_graph():
"""创建并返回编译好的问诊工作流图"""
workflow = StateGraph(GraphState)
# 添加节点
workflow.add_node("triage", triage_node)
workflow.add_node("inquire", inquire_node)
workflow.add_node("query_knowledge", query_knowledge_node)
workflow.add_node("suggest_exam", suggest_exam_node)
workflow.add_node("diagnose", diagnose_node)
# 设置入口点
workflow.set_entry_point("triage")
# 定义边(根据 state[“next_step”] 的值决定流向)
# 从 triage 出发
workflow.add_conditional_edges(
"triage",
# 这是一个路由函数,根据state决定下一个节点
lambda state: state["next_step"],
{
"query_knowledge": "query_knowledge",
"inquire": "inquire",
}
)
# inquire 之后固定去 query_knowledge
workflow.add_edge("inquire", "query_knowledge")
# 后续流程是固定的
workflow.add_edge("query_knowledge", "suggest_exam")
workflow.add_edge("suggest_exam", "diagnose")
# diagnose 之后结束
workflow.add_edge("diagnose", END)
# 编译图
graph = workflow.compile()
return graph
if __name__ == "__main__":
# 创建图实例
medical_graph = create_medical_graph()
# 定义初始状态
initial_state: GraphState = {
"patient_input": "我发烧,咳嗽比较厉害,感觉胸口有点闷。",
"extracted_symptoms": [],
"possible_diseases": None,
"suggested_exams": None,
"allergy_history": None,
"preliminary_diagnosis": None,
"medication_recommendation": None,
"final_advice": None,
"next_step": "triage", # 从分诊开始
}
print("开始执行医疗问诊工作流...")
print("="*60)
# 运行图
final_state = medical_graph.invoke(initial_state)
print("\n" + "="*60)
print("工作流执行完毕!")
print("\n【最终给患者的建议】")
print(final_state["final_advice"])
运行 python medical_graph.py ,你将看到一个清晰的、按步骤执行的问诊流程。每个节点的执行和状态转换一目了然。这就是 LangGraph 带来的价值: 显式、可控、可调试的复杂流程 。
4.3 集成 LangSmith:监控与调试工作流
要让这个工作流更健壮,我们需要观察其内部运行情况。LangSmith 可以无缝集成。
首先,确保你已设置好 LANGCHAIN_API_KEY 等环境变量(见第2节)。LangChain/LangGraph 的调用会自动被追踪。
我们修改 medical_graph.py 中的工具调用部分,使其使用 @tool 装饰器的工具能被 LangSmith 更好地追踪。实际上,只要你用 langchain 的 tool 装饰器或 Tool 类创建工具,并在有 LangSmith 配置的环境下运行,追踪就会自动发生。
为了更明显,我们可以在主执行代码中增加一个简单的 LangSmith 追踪示例:
# 在 medical_graph.py 的 __main__ 部分稍作修改
if __name__ == "__main__":
import langsmith
# 初始化客户端(环境变量已配置则自动进行)
client = langsmith.Client()
print(f"LangSmith 追踪已启用,项目: {os.getenv('LANGCHAIN_PROJECT', 'default')}")
medical_graph = create_medical_graph()
initial_state: GraphState = {...} # 同上
print("开始执行医疗问诊工作流(追踪中)...")
# invoke 方法会自动将本次运行记录到 LangSmith
final_state = medical_graph.invoke(initial_state)
# ... 其余输出不变
运行后,打开 LangSmith 官网 ,在你的项目中就能看到这次 invoke 的完整追踪记录(Trace)。你可以点击查看:
- 整个 Graph 的调用链路。
- 每个节点(函数)的输入输出。
- 每个工具调用的详细输入、输出和耗时。
- LLM 内部调用的提示词和补全结果。
这对于调试 Agent 的决策过程、优化提示词、分析性能瓶颈至关重要。
5. 常见问题与排查思路
在开发 LangChain/LangGraph 应用时,你可能会遇到以下典型问题:
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
ModuleNotFoundError: No module named ‘langchain’ |
依赖未正确安装或虚拟环境未激活。 | 1. 确认在项目目录下。 2. 激活虚拟环境: source venv/bin/activate (Linux/Mac) 或 venv\Scripts\activate (Windows)。 3. 重新安装: pip install -r requirements.txt 。 |
AuthenticationError / Invalid API Key |
OpenAI API Key 错误或未设置。 | 1. 检查 .env 文件中的 OPENAI_API_KEY 是否正确。 2. 确认代码中通过 os.getenv(“OPENAI_API_KEY”) 读取。 3. 确保 Key 有余额且未过期。 |
| Agent 陷入循环,不停调用工具 | ReAct 提示词未明确终止条件,或 LLM 无法理解任务已完成。 | 1. 检查提示词模板中的 Final Answer 格式是否明确。 2. 在 AgentExecutor 中设置 max_iterations 参数(如 max_iterations=5 )强制限制循环次数。 3. 使用 handle_parsing_errors=True 避免解析错误导致循环。 |
| LangGraph 节点状态未更新 | 节点函数修改了局部变量,但未正确更新并返回 state 字典。 |
确保每个节点函数都接收 state ,修改它,并返回修改后的 state 。LangGraph 依赖返回值来更新全局状态。 |
| 工具调用失败,参数类型错误 | @tool 装饰器函数的参数类型提示与 LLM 生成的 Action Input 不匹配。 |
1. 确保工具函数有清晰的 Args 文档字符串,LLM 依赖这个来生成输入。 2. 工具函数的参数尽量使用简单类型( str , int ),避免复杂对象。 3. 使用 AgentExecutor(..., handle_parsing_errors=True) 捕获错误并让 Agent 重试。 |
| LangSmith 看不到追踪记录 | 环境变量未正确配置或网络问题。 | 1. 确认 .env 文件中 LANGCHAIN_TRACING_V2=true 和 LANGCHAIN_API_KEY 已设置。 2. 重启终端或 IDE 使环境变量生效。 3. 访问 LangSmith 网站,确认 API Key 有效,且项目名称正确。 |
| Graph 编译错误 | StateGraph 的节点或边定义有误,比如节点名拼写错误、条件边映射的键不存在。 |
1. 仔细检查 add_node 和 add_edge / add_conditional_edges 中使用的节点名称字符串是否完全一致。 2. 条件边的路由函数返回值必须在提供的映射字典的键中。 |
6. 最佳实践与工程建议
将原型应用到生产环境,需要考虑更多工程化因素。
6.1 提示词工程
- 结构化与明确性 :给 Agent 和 Graph 中 LLM 节点的提示词必须清晰定义角色、任务、步骤和输出格式。使用
PromptTemplate进行管理。 - 少样本学习 :在提示词中提供 1-2 个高质量的示例(Few-shot),能显著提升复杂任务的表现。
- 版本控制 :使用 LangSmith 的 Prompt Management 功能管理不同版本的提示词,便于对比和回滚。
6.2 工具设计
- 单一职责 :每个工具应只做一件事,并且做好。避免创建功能混杂的“巨无霸”工具。
- 健壮性 :工具函数内部要有充分的错误处理(try-except),返回明确的错误信息,帮助 Agent 理解失败原因。
- 安全性 :任何执行写操作、访问外部系统或敏感数据的工具,必须加入权限验证和操作确认机制。
6.3 工作流(LangGraph)设计
- 状态设计精简 :
State应只包含流程必需的数据。避免将中间计算的大量临时数据放入状态。 - 节点粒度适中 :一个节点完成一个逻辑上相对独立的步骤。太粗则不易调试,太细则增加复杂度。
- 善用条件边 :
add_conditional_edges是实现动态流程的关键。确保路由函数逻辑清晰,覆盖所有可能的分支。 - 持久化检查点 :对于长时运行或需要中断恢复的工作流,使用
Checkpointer保存状态。
6.4 可观测性与监控(LangSmith)
- 全面启用追踪 :在开发、测试和生产环境都启用 LangSmith 追踪,这是调试和优化的基石。
- 创建评估数据集 :针对核心场景,构建一批高质量的输入-输出对,定期运行评估,监控应用效果是否下降。
- 设置告警 :关注 LangSmith 中的耗时、Token 消耗和错误率指标,设置阈值告警。
6.5 性能与成本
- 缓存 :对频繁且结果不变的 LLM 调用或工具查询(如知识库检索)实施缓存,减少重复计算和 API 调用。
- 限制与降级 :在
AgentExecutor和 Graph 中设置max_iterations、max_execution_time,防止失控循环产生高额费用。 - 模型选择 :非核心推理步骤可考虑使用更小、更快的模型(如
gpt-3.5-turbo),关键总结或诊断步骤再用大模型(如gpt-4)。
6.6 安全与合规(尤其对于医疗场景)
- 免责声明 :任何医疗建议输出必须包含明确的免责声明,指出其辅助性,不能替代专业医疗诊断。
- 数据脱敏 :处理患者输入时,需注意隐私保护,避免在日志、追踪信息中记录个人身份信息(PII)。
- 审核机制 :对于高风险建议(如用药),应设计人工审核环节,或将其限制在“建议咨询医生”的范围内。
通过本文的拆解,你应该对 LangChain、LangGraph 和 LangSmith 在构建一个复杂 AI Agent 应用中的角色和协作方式有了直观的理解。从 LangChain 的工具组装,到 LangGraph 的流程编排,再到 LangSmith 的全链路观测,它们共同构成了开发现代化、可维护、可调试的 LLM 应用的坚实基础。下一步,你可以尝试用更复杂的工具(如真实数据库、API)、更精细的 Graph 状态和条件逻辑,来构建属于你自己的智能体应用。
更多推荐


所有评论(0)