ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

LangGraph实战指南:构建有状态AI工作流与全链路优化

LangGraph实战指南:构建有状态AI工作流与全链路优化 大家好我是专注于AI应用开发的技术博主。在构建复杂的AI工作流时你是否遇到过这样的困扰多个LLM调用、工具执行和状态管理逻辑混杂在一起代码像“意大利面条”一样难以维护和调试传统的LangChain虽然强大但在处理有状态、多步骤的循环或条件流程时显得力不从心。这正是LangGraph要解决的核心问题。本文将为你带来LangGraph从零到一的完整实战指南。我们不仅会深入讲解LangGraph的核心概念、状态设计和编程模型还会结合Langfuse实现全链路追踪与评估并探讨如何将训练好的模型通过量化感知训练QAT进行优化最后使用SFTTrainer进行监督微调。无论你是想入门LangGraph的新手还是希望构建更健壮、可观测AI系统的进阶开发者这篇文章都能提供一套可落地的闭环方案。1. LangGraph 核心概念与架构解析在深入代码之前我们必须理解LangGraph的设计哲学和它要解决的问题。这将帮助我们更好地运用它而不是仅仅套用模板。1.1 什么是LangGraph与LangChain有何区别LangGraph是LangChain框架的一个扩展库它专门用于构建有状态、多参与者的图Graph结构工作流。你可以把它想象成一个功能强大的流程图引擎其中每个节点是一个处理单元如调用LLM、执行工具边则定义了节点之间的流转逻辑。核心区别在于“状态”和“循环”LangChain的核心是“链”Chain它通常是线性的、无状态的。一个输入经过一系列处理得到一个输出链就结束了。虽然也有Agent但其内部的循环和状态管理相对隐晦和固定。LangGraph的核心是“图”Graph和“状态”State。它显式地管理一个共享的状态对象节点可以读取和修改这个状态。图可以包含循环比如让Agent反复思考直到满意、条件分支根据结果走不同路径以及并行执行。这使其特别适合构建复杂的、多轮的智能体Agent或工作流。简单来说LangChain擅长组装工具链而LangGraph擅长编排有状态的、可能循环的工作流。LangGraph不是替代LangChain而是对其能力的增强和补充。1.2 关键组件State、Node、Edge理解这三个概念是掌握LangGraph的关键。State状态 这是一个贯穿整个工作流执行周期的共享数据容器通常是一个Pydantic模型或TypedDict。它定义了工作流中需要传递和更新的所有数据。例如在一个聊天Agent中State可能包含messages对话历史、next指示下一步做什么等字段。Node节点 节点是工作流中的基本执行单元。一个节点就是一个函数它接收当前的State作为输入执行一些操作如调用LLM、查询数据库并返回一个更新后的State或包含更新部分的字典。每个节点都有一个唯一的名字。Edge边 边定义了节点之间的流转逻辑。分为两种起始边Start Edge定义工作流从哪个节点开始。普通边Regular Edge根据当前State的内容决定下一个要执行的节点是谁。这通常通过一个路由函数conditional_edge来实现条件分支。1.3 静态循环与动态结束这是LangGraph一个非常强大的特性。静态循环通过将一个节点指向它自身或一个循环子图可以实现迭代。例如一个“思考”节点可以反复运行直到State中的某个条件满足。动态结束工作流不会无限循环下去。通过将一个边指向一个特殊的END节点可以终止整个工作流。你可以在路由逻辑中判断如果任务完成则前往END否则继续循环。这种“循环-判断-结束”的模式正是构建自主Agent如ReAct模式的基石。2. 环境准备与项目初始化接下来我们搭建一个可实战的环境。本文将使用Python作为开发语言。2.1 创建虚拟环境与安装依赖强烈建议使用虚拟环境来管理依赖避免包冲突。# 1. 创建并进入项目目录 mkdir langgraph-tutorial cd langgraph-tutorial # 2. 创建Python虚拟环境以Python 3.10为例 python3.10 -m venv venv # 3. 激活虚拟环境 # Linux/macOS source venv/bin/activate # Windows # venv\Scripts\activate # 4. 安装核心依赖 pip install langgraph langchain langchain-openai # 5. 安装可选但重要的工具链 # Langfuse用于追踪和评估后续会用到 pip install langfuse # 用于示例的额外工具包 pip install wikipedia requests2.2 配置API密钥我们需要配置OpenAI的API密钥。出于安全考虑永远不要将密钥硬编码在代码中。# Linux/macOS export OPENAI_API_KEYyour-openai-api-key-here # Windows (PowerShell) # $env:OPENAI_API_KEYyour-openai-api-key-here你也可以使用.env文件配合python-dotenv来管理# 安装 dotenv # pip install python-dotenv # 在项目根目录创建 .env 文件内容如下 # OPENAI_API_KEYsk-...然后在代码开头加载from dotenv import load_dotenv load_dotenv() # 现在 os.getenv(‘OPENAI_API_KEY’) 可以获取到密钥2.3 初始化Langfuse可选但推荐Langfuse是一个开源的LLM应用观测平台可以详细记录每次工作流的执行轨迹、输入输出、耗时和Token使用情况对于调试和优化至关重要。from langfuse import Langfuse # 初始化Langfuse你需要从Langfuse Cloud或自部署实例获取密钥 # 你可以先在 https://cloud.langfuse.com 注册获取 langfuse Langfuse( secret_keyyour-langfuse-secret-key, public_keyyour-langfuse-public-key, hosthttps://cloud.langfuse.com # 或你的自部署地址 ) # 测试连接 try: langfuse.auth_check() print(Langfuse连接成功) except Exception as e: print(fLangfuse连接失败: {e})3. 构建你的第一个LangGraph聊天助手我们从最简单的线性图开始创建一个能进行多轮对话的聊天助手。3.1 定义状态State状态是工作流的“记忆”。我们使用TypedDict来定义。from typing import TypedDict, List from langchain_core.messages import BaseMessage class AgentState(TypedDict): 定义Agent工作流的状态。 # 消息列表存储整个对话历史 messages: List[BaseMessage] # 一个可选的字段指示用户想做什么 user_intent: str3.2 创建节点Nodes节点是执行具体任务的函数。我们创建两个节点一个处理用户输入一个调用LLM生成回复。from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, AIMessage from langgraph.graph import END # 初始化LLM llm ChatOpenAI(modelgpt-3.5-turbo) def process_input(state: AgentState) - dict: 处理用户输入的节点。 # 从状态中获取最新的用户消息假设最后一条是用户输入 last_message state[‘messages’][-1] # 这里可以做一些预处理例如提取意图 # 为了简单我们假设用户意图就是消息内容 user_intent last_message.content if isinstance(last_message, HumanMessage) else “” # 返回要更新到状态中的字段 return {“user_intent”: user_intent} def call_llm(state: AgentState) - dict: 调用LLM生成回复的节点。 # 1. 准备对话历史 conversation_history state[‘messages’] # 2. 调用LLM传入整个历史 response llm.invoke(conversation_history) # 3. 将AI的回复添加到消息列表中 updated_messages state[‘messages’] [response] # 4. 返回更新后的状态 return {“messages”: updated_messages}3.3 构建图Graph并编译现在我们将节点和边组装起来。from langgraph.graph import StateGraph, START # 1. 创建一个图并指定状态的结构 workflow StateGraph(AgentState) # 2. 添加节点 workflow.add_node(“process_input”, process_input) workflow.add_node(“call_llm”, call_llm) # 3. 添加边定义执行流程 workflow.add_edge(START, “process_input”) # 从开始到处理输入 workflow.add_edge(“process_input”, “call_llm”) # 处理完输入后调用LLM workflow.add_edge(“call_llm”, END) # LLM回复后结束 # 4. 编译图得到一个可执行的对象 app workflow.compile()3.4 运行与测试编译好的app就是一个可以调用的函数其输入和输出都是State。# 初始化状态用户说“你好” initial_state: AgentState { “messages”: [HumanMessage(content“你好”)], “user_intent”: “” } # 运行图 final_state app.invoke(initial_state) # 查看结果 print(“最终的消息历史”) for msg in final_state[“messages”]: print(f”{msg.type}: {msg.content}“)运行上述代码你会看到LLM对“你好”的回复。这实现了一个单轮对话。但我们的图是线性的对话一次就结束了。如何实现多轮这就需要引入循环。4. 进阶实战构建具有循环能力的ReAct AgentReActReasoning Acting是一种经典的Agent模式它让Agent能够“思考-行动-观察”循环直到解决问题。我们用LangGraph来实现它。4.1 设计ReAct Agent的状态状态需要包含更多信息来支持循环决策。from typing import Optional, Literal from pydantic import BaseModel, Field from langchain_core.messages import BaseMessage class ReActState(BaseModel): ReAct Agent的状态使用Pydantic便于验证。 # 输入的问题 input: str # 完整的消息历史思考、行动、观察 messages: List[BaseMessage] Field(default_factorylist) # 当前步骤的“思考”内容 thought: Optional[str] None # 当前步骤要执行的“行动”工具名 action: Optional[str] None # 行动的“输入” action_input: Optional[str] None # 工具执行的“观察”结果 observation: Optional[str] None # 最终答案当找到时 final_answer: Optional[str] None4.2 创建工具ToolsAgent需要工具来与环境交互。我们创建两个简单的工具。from langchain.tools import tool import wikipedia import requests tool def search_wikipedia(query: str) - str: 在维基百科中搜索一个主题。 try: # 设置语言为中文 wikipedia.set_lang(“zh”) # 获取摘要 summary wikipedia.summary(query, sentences2) return summary except wikipedia.exceptions.DisambiguationError as e: return f”歧义项请更具体: {e.options}“ except wikipedia.exceptions.PageError: return “未找到相关页面。” except Exception as e: return f”搜索出错: {str(e)}“ tool def get_weather(city: str) - str: 获取一个城市的天气模拟工具。 # 这是一个模拟工具实际中你会调用真正的天气API weather_data { “北京”: “晴25°C”, “上海”: “多云23°C”, “广州”: “阵雨28°C”, } return weather_data.get(city, f”未找到{city}的天气信息。”) # 将工具包装成LangChain可用的格式 from langchain.tools import Tool tools [Tool.from_function(search_wikipedia), Tool.from_function(get_weather)]4.3 构建ReAct图的节点我们需要三个核心节点reason思考/规划、act执行工具、observe整合观察结果。from langchain_core.prompts import ChatPromptTemplate from langchain.agents import create_react_agent # 1. 创建ReAct代理的提示词模板 prompt ChatPromptTemplate.from_messages([ (“system”, “你是一个有帮助的助手可以使用工具。请遵循以下格式\n\n思考你需要对问题进行分析\n行动要使用的工具名\n行动输入工具的输入\n观察工具返回的结果\n...这个循环可以重复多次\n思考我现在知道最终答案了\n最终答案对原始问题的最终回答”), (“placeholder”, “{chat_history}”), (“human”, “{input}”), ]) # 2. 使用LangChain的便捷函数创建ReAct Agent其核心是LLM react_agent create_react_agent(llm, tools, prompt) def reason_node(state: ReActState) - dict: 思考节点分析问题决定下一步是使用工具还是给出答案。 # 准备Agent的输入 agent_input { “input”: state.input, “chat_history”: state.messages } # 调用ReAct AgentLLM进行思考 response react_agent.invoke(agent_input) # 解析LLM的响应提取“思考”、“行动”等信息 # 这里简化处理实际需要更复杂的解析逻辑来匹配ReAct格式 response_text response[“output”] if isinstance(response, dict) else response.content # 示例性解析在实际项目中你需要一个更稳健的解析器 lines response_text.split(‘\n’) thought “” action None action_input None for line in lines: if line.startswith(‘思考’): thought line.replace(‘思考’, ‘’).strip() elif line.startswith(‘行动’): action line.replace(‘行动’, ‘’).strip() elif line.startswith(‘行动输入’): action_input line.replace(‘行动输入’, ‘’).strip() elif line.startswith(‘最终答案’): # 如果找到最终答案更新状态并结束 final_answer line.replace(‘最终答案’, ‘’).strip() return { “thought”: thought, “final_answer”: final_answer } # 如果没有最终答案说明需要执行工具 return { “thought”: thought, “action”: action, “action_input”: action_input, “messages”: state.messages [AIMessage(contentresponse_text)] # 记录AI的思考 } def act_node(state: ReActState) - dict: 行动节点根据思考结果执行对应的工具。 if not state.action: return {“observation”: “未指定行动。”} # 根据工具名找到对应的工具 selected_tool next((t for t in tools if t.name state.action), None) if not selected_tool: return {“observation”: f”未知工具: {state.action}“} # 执行工具 try: observation selected_tool.invoke(state.action_input) except Exception as e: observation f”工具执行出错: {str(e)}“ return { “observation”: observation, “messages”: state.messages [AIMessage(contentf”行动 {state.action} 完成。”)] } def observe_node(state: ReActState) - dict: 观察节点将工具执行的结果整合到消息历史中。 observation_msg f”观察{state.observation}“ updated_messages state.messages [AIMessage(contentobservation_msg)] return {“messages”: updated_messages}4.4 定义条件边与循环逻辑这是LangGraph最精彩的部分根据State的内容动态决定下一步是继续“思考-行动”循环还是结束。from langgraph.graph import END def should_continue(state: ReActState) - Literal[“reason”, “end”]: 判断下一步应该去‘思考’节点还是结束。 # 如果已经得到了最终答案就结束 if state.final_answer is not None: return “end” # 否则继续思考可能进行下一轮行动 return “reason” # 构建图 react_workflow StateGraph(ReActState) # 添加节点 react_workflow.add_node(“reason”, reason_node) react_workflow.add_node(“act”, act_node) react_workflow.add_node(“observe”, observe_node) # 设置起始节点 react_workflow.set_entry_point(“reason”) # 添加条件边 # 从 reason 节点出来后根据 should_continue 函数决定去向 react_workflow.add_conditional_edges( “reason”, should_continue, { “reason”: “act”, # 如果需要继续就去执行行动 “end”: END # 如果结束就直接终止 } ) # 添加固定边 react_workflow.add_edge(“act”, “observe”) react_workflow.add_edge(“observe”, “reason”) # 观察完后回到思考节点形成循环 # 编译图 react_app react_workflow.compile()4.5 运行ReAct Agent现在让我们运行这个强大的Agent来回答一个需要查资料的问题。# 初始化状态 initial_react_state ReActState(input“北京今天的天气怎么样然后再告诉我爱因斯坦的主要贡献。”) # 运行图 final_state react_app.invoke(initial_react_state) print(“\n ReAct Agent 执行结果 ”) print(f”问题: {final_state.input}“) if final_state.final_answer: print(f”最终答案: {final_state.final_answer}“) else: print(“未得出最终答案。”) print(“\n执行轨迹:”) for msg in final_state.messages: print(f”- {msg.content}“)这个Agent会先思考需要调用天气工具执行后得到观察结果“晴25°C”然后继续思考下一个问题调用维基百科工具最终整合信息给出答案。整个“思考-行动-观察”的循环被LangGraph清晰地管理起来。5. 集成Langfuse实现全链路追踪与评估构建复杂的图工作流后调试和优化变得困难。Langfuse可以完美解决这个问题它像飞机的“黑匣子”记录每一次执行的完整轨迹。5.1 使用Langfuse Decorator进行自动插桩最简单的方式是使用Langfuse的langfuse.decorator来装饰你的图或节点函数。from langfuse.decorators import observe, langfuse_context import asyncio observe() # 使用装饰器自动追踪该函数 def run_agent_with_tracing(question: str): 一个包装函数用于运行Agent并自动被Langfuse追踪。 state ReActState(inputquestion) result react_app.invoke(state) return result # 运行并追踪 langfuse_context.update_current_trace( name“ReAct-Agent-Demo”, user_id“test_user_001”, metadata{“project”: “langgraph-tutorial”} ) final_result run_agent_with_tracing(“珠穆朗玛峰的高度是多少”) # 在Langfuse控制台你现在可以看到一次完整的Trace # 里面包含了图的结构、每个节点的输入输出、耗时和Token使用情况。5.2 手动集成以获得更细粒度控制如果你需要自定义Trace和Span的名称、标签或元数据可以手动集成。from langfuse import Langfuse langfuse Langfuse() # 假设已通过环境变量配置 def traced_reason_node(state: ReActState) - dict: # 为这个节点的执行创建一个Span with langfuse.span( name“reason_node”, inputstate.dict(), metadata{“step”: “reasoning”} ) as span: # 原有的reason_node逻辑 result reason_node(state) # 记录输出 span.output result return result # 类似地可以装饰act_node和observe_node # 然后使用这些被装饰的函数重新构建图5.3 在Langfuse控制台进行分析执行几次调用后打开Langfuse控制台Cloud或本地你可以查看Trace列表每次调用都是一条Trace。深入Trace详情可以看到完整的图执行流程每个节点是一个Span。分析性能查看每个节点的耗时找出瓶颈。检查输入输出验证每个步骤是否正确处理了数据。评估质量可以手动或通过集成API对结果进行评分Score用于后续优化模型或提示词。6. 模型优化量化感知训练QAT与SFTTrainer当我们有了一个运行良好的Agent工作流后下一步可能就是部署。为了提升推理速度、降低资源消耗对模型进行量化是常见手段。而量化感知训练QAT可以在训练阶段就模拟量化过程让模型适应低精度计算从而在真正量化后精度损失最小。6.1 量化感知训练QAT概念QAT的核心思想是“模拟量化训练补偿”在训练前向传播时插入“假量化”Fake Quantization操作模拟将权重和激活值从浮点数转换为低精度整数如INT8的过程。在反向传播时使用直通估计器Straight-Through Estimator, STE来近似量化操作的梯度使得模型可以正常更新。这样训练出的模型其参数已经习惯了量化带来的噪声和信息损失因此在后续进行真正的静态量化Post-Training Quantization, PTQ时性能下降会显著减少。适用场景当你计划将模型部署到资源受限的边缘设备如Jetson系列或需要极致推理速度时QAT是保证精度的关键步骤。6.2 使用Hugging Facetransformers进行QAT以下是一个使用transformers和torch.ao.quantization进行QAT的简化示例。假设我们已经有一个微调过的语言模型。import torch import torch.nn as nn from transformers import AutoModelForCausalLM, AutoTokenizer from torch.ao.quantization import QuantStub, DeQuantStub, prepare_qat, convert # 1. 加载预训练模型和分词器 model_name “microsoft/phi-2” # 示例模型请替换为你的模型 tokenizer AutoTokenizer.from_pretrained(model_name) model AutoModelForCausalLM.from_pretrained(model_name) # 2. 定义需要量化的模型包装类 class QuantizableLM(nn.Module): def __init__(self, original_model): super().__init__() self.model original_model self.quant QuantStub() # 量化入口 self.dequant DeQuantStub() # 反量化出口 def forward(self, input_ids, attention_maskNone): # 模拟量化输入先经过量化-反量化 x self.quant(input_ids) x self.dequant(x) # 原始模型前向传播 outputs self.model(input_idsx, attention_maskattention_mask) return outputs # 3. 包装模型 quantizable_model QuantizableLM(model) # 4. 配置QAT quantizable_model.qconfig torch.ao.quantization.get_default_qat_qconfig(‘fbgemm’) # 针对服务器CPU # 如果是移动端或ARM可使用 ‘qnnpack’ # 5. 准备QAT插入假量化节点 torch.ao.quantization.prepare_qat(quantizable_model, inplaceTrue) # 6. 进行量化感知训练这里仅展示训练循环结构 def qat_training_loop(model, train_dataloader, optimizer, epochs3): model.train() for epoch in range(epochs): for batch in train_dataloader: optimizer.zero_grad() input_ids batch[‘input_ids’] attention_mask batch[‘attention_mask’] labels batch[‘labels’] outputs model(input_idsinput_ids, attention_maskattention_mask) loss outputs.loss if hasattr(outputs, ‘loss’) else nn.CrossEntropyLoss()(outputs.logits.view(-1, outputs.logits.size(-1)), labels.view(-1)) loss.backward() optimizer.step() print(f”Epoch {epoch1} completed.”) # 训练结束后转换为真正的量化模型 quantized_model torch.ao.quantization.convert(model.eval(), inplaceFalse) return quantized_model # 注意实际训练需要准备数据加载器、优化器等此处省略。6.3 使用SFTTrainer进行监督微调在QAT之前或之后我们通常需要使用特定数据对模型进行监督微调SFT。trl库提供的SFTTrainer极大地简化了这个过程。from datasets import Dataset from transformers import AutoTokenizer, TrainingArguments from trl import SFTTrainer # 1. 准备训练数据示例 train_data [ {“text”: “用户你好\n助手你好我是AI助手有什么可以帮您”}, {“text”: “用户推荐一部科幻电影\n助手我推荐《星际穿越》它探讨了虫洞和时间膨胀非常震撼。”}, # ... 更多对话数据 ] dataset Dataset.from_list(train_data) # 2. 加载模型和分词器这里用原始模型也可以是QAT准备后的模型 model_name “microsoft/phi-2” tokenizer AutoTokenizer.from_pretrained(model_name) tokenizer.pad_token tokenizer.eos_token # 设置填充令牌 model AutoModelForCausalLM.from_pretrained(model_name) # 3. 定义训练参数 training_args TrainingArguments( output_dir“./sft_results”, num_train_epochs3, per_device_train_batch_size4, gradient_accumulation_steps4, logging_steps10, save_steps100, learning_rate2e-5, fp16True, # 混合精度训练节省显存 remove_unused_columnsFalse, ) # 4. 创建SFTTrainer trainer SFTTrainer( modelmodel, argstraining_args, train_datasetdataset, tokenizertokenizer, dataset_text_field“text”, # 数据集中文本字段的名称 max_seq_length512, # 最大序列长度 packingTrue, # 是否打包样本以提高效率 ) # 5. 开始训练 trainer.train() # 6. 保存微调后的模型 trainer.save_model(“./my_sft_model”) tokenizer.save_pretrained(“./my_sft_model”)结合QAT与SFT的流程建议方案A先SFT后QAT使用高质量数据对基础模型进行SFT得到一个任务专用的高质量模型。然后对这个SFT模型进行QAT使其获得量化鲁棒性最后导出为量化模型部署。这是最常用的流程。方案BQAT-aware SFT如果资源充足且追求极致量化后精度可以在QAT模拟环境下进行SFT。即先对基础模型做prepare_qat然后使用SFTTrainer在这个模型上进行训练。这样训练出的模型从一开始就适应了量化噪声。7. 常见问题与排查思路在开发LangGraph应用时你可能会遇到以下典型问题。问题现象可能原因排查思路与解决方案State更新不生效节点函数返回的字典键名与State定义的字段名不匹配。检查节点函数return的字典键名必须与StateTypedDict或Pydantic Model的字段名完全一致。使用print(state)调试。图陷入无限循环条件边conditional_edge的逻辑有误始终无法满足结束条件。检查should_continue或类似的路由函数。确保在完成任务后能正确返回指向END的值。在状态中设置最大循环次数作为安全阀。Langfuse看不到追踪数据1. API密钥或主机地址配置错误。2. 代码没有实际执行到被装饰的函数。3. 异步调用未完成。1. 检查环境变量LANGFUSE_SECRET_KEY等是否正确。2. 在代码中增加print语句确认函数被调用。3. 如果是异步确保使用了asyncio.run()或正确等待。检查Langfuse控制台的项目选择是否正确。工具Tool执行失败1. 工具输入格式不对。2. 工具本身有bug或依赖未安装。3. 网络问题。1. 打印state.action和state.action_input检查是否与工具期望的参数匹配。2. 单独测试工具函数。3. 为工具调用添加try-except并在observation中返回错误信息让Agent能处理失败。SFTTrainer训练时OOM内存不足1.per_device_train_batch_size太大。2.max_seq_length太长。3. 模型太大。1. 减小batch_size增加gradient_accumulation_steps来补偿。2. 减小max_seq_length或使用动态填充。3. 启用梯度检查点gradient_checkpointingTrue、混合精度训练fp16True或使用LoRA等参数高效微调方法。量化后模型精度损失严重1. QAT训练不充分或数据不匹配。2. 量化配置如对称/非对称、量化位宽不合适。3. 模型本身对量化敏感。1. 确保QAT训练轮次足够并使用代表性校准数据。2. 尝试不同的qconfig如从fbgemm换为qnnpack。3. 考虑只对部分层量化如仅量化注意力层的KV缓存。在部署前务必在验证集上评估量化模型的精度。8. 最佳实践与工程建议根据项目经验遵循以下实践能让你构建出更稳健、可维护的LangGraph应用。状态设计要精简而充分精简只把需要在节点间传递的数据放入State。避免将整个对话历史这样的庞大数据直接作为状态可以考虑只存储摘要或最近N条消息。充分确保状态包含所有决策所需的信息。例如在ReAct Agent中thought、action、observation都是驱动循环的关键。节点功能保持单一职责一个节点只做一件事。例如call_llm节点只负责与LLM交互search_database节点只负责查询数据库。这提高了代码的可测试性和可复用性。为图添加可视化与调试支持LangGraph内置了可视化方法。使用app.get_graph().draw_mermaid_png()可以生成流程图帮助你理解工作流。在开发阶段可以在每个节点内打印关键状态或使用Langfuse进行可视化追踪。实现超时与错误处理机制在invoke调用外部服务如LLM API、数据库时务必设置超时。对于可能失败的节点使用try-except捕获异常并将错误信息作为observation返回状态让图能够根据错误决定下一步如重试或终止。版本化你的图配置随着业务变化图的结构节点、边可能会调整。将图的构建逻辑State定义、节点函数、边设置封装在清晰的模块中并使用版本控制工具如Git进行管理。考虑将编译好的图对象序列化保存便于回滚和部署。区分开发与生产环境开发环境使用Langfuse进行详细追踪使用成本较低的LLM如gpt-3.5-turbo进行测试。生产环境关闭不必要的详细日志可能切换到性能更高或成本更优的LLM如gpt-4-turbo或Claude。确保所有API密钥和配置通过环境变量或安全的配置中心管理。对SFT和QAT的数据质量严格把关SFT数据质量远胜于数量。确保指令清晰、回答准确、格式一致。清洗掉含有偏见、错误或无关信息的数据。QAT校准数据应来自模型实际应用场景的分布。不要用训练数据做校准以免引入偏见。通常准备几百个样本即可。建立完整的评估体系不要只依赖人工检查。为你的LangGraph应用建立自动化评估管道功能正确性针对核心流程编写单元测试和集成测试。性能指标监控平均响应时间、Token消耗、循环次数等。效果评估使用Langfuse的评分功能结合人工评估或模型评估如使用GPT-4作为裁判对最终输出进行质量打分。定期分析评估结果指导迭代优化。本文从LangGraph的核心概念讲起带你一步步构建了从简单聊天助手到复杂ReAct Agent的工作流并集成了Langfuse实现可观测性最后探讨了通过QAT和SFT来优化与定制模型。这套组合拳涵盖了AI应用从开发、调试到优化部署的关键环节。真正的掌握源于动手实践。建议你从本文的示例代码出发尝试修改状态结构、增加新的工具如计算器、搜索引擎API、或者构建一个属于自己的多Agent协作系统。在遇到问题时多利用Langfuse的追踪功能进行调试它会让你清晰地看到数据在图中是如何流动和变化的。
返回列表