基于LangGraph构建生产级AI Agent:从客服工单处理实战到部署优化

基于LangGraph构建生产级AI Agent:从客服工单处理实战到部署优化 1. 项目概述为什么“生产级”是AI Agent的分水岭最近和不少同行交流发现大家聊起AI Agent已经从“这东西挺酷”变成了“这东西怎么才能用起来”。确实从去年开始各种Agent框架和平台如雨后春笋般冒出来LangChain、LangGraph、Dify、Claude Agent SDK……名字都听麻了。但当你真的想动手把一个Demo级别的Agent变成能稳定运行、处理真实业务的生产级应用时会发现这中间隔着一道巨大的鸿沟。Demo可以只关心“能不能跑通”而生产级则要面对稳定性、性能、成本、可观测性等一系列现实拷问。今天我就以一个过来人的身份结合我最近用LangGraph搭建的一个客服工单自动分类与路由Agent的实战经历手把手带你走完从技术选型到最终上线的完整流程。这个项目不大但麻雀虽小五脏俱全它要求Agent能理解用户提交的工单内容自动判断问题类型如“账号问题”、“支付故障”、“产品咨询”并分派给对应的处理队列同时还要能处理用户的追问维护简单的对话状态。我们不会停留在“Hello World”而是会深入到部署、监控、优化这些真正决定项目成败的环节。无论你是刚入门想找个靠谱的起点还是已经踩过一些坑想系统化提升这篇指南应该都能给你一些直接的参考。2. 核心需求解析与方案选型在动手写第一行代码之前我们必须把需求掰开揉碎了看。我那个客服工单Agent的需求听起来简单但拆解后会发现不少隐藏的挑战。2.1 需求拆解从业务场景到技术清单首先业务需求是用户通过一个Web界面提交文字工单Agent需要自动完成分类和路由。这引申出几个核心功能点意图识别与分类准确理解用户工单的核心诉求归到预设的类别。状态管理与多轮对话用户可能会追问“我刚才提交的支付问题处理到哪一步了”Agent需要能关联上下文。工具调用与外部集成分类后需要调用内部API将工单数据写入对应的业务系统队列。稳定性与可观测性作为生产服务必须保证高可用并且能清晰地看到每一次请求的链路、耗时、LLM调用详情方便排查问题。基于这些我们的技术选型清单就清晰了需要一个能编排复杂工作流、管理状态、方便集成工具、且具备良好可观测性基础的框架。2.2 框架横评LangChain、LangGraph、Dify与Claude SDK市面上主流的选项就那几个我们来逐一分析看哪个最适合这个“生产级”场景。LangChain这无疑是生态最繁荣的“瑞士军刀”。它的链Chain和代理Agent抽象非常经典社区工具和集成多如牛毛。但是对于需要复杂状态循环和精细控制流的应用原生的Agent抽象有时会显得力不从心。它的执行过程更像一个黑盒调试和追踪每一步的中间状态比较麻烦。对于我们的多轮对话和严格的工作流它可能不是最优雅的解决方案。LangGraph你可以把它理解为LangChain的“工作流引擎”升级版。它引入了图Graph的概念将Agent的执行过程明确定义为由节点Node和边Edge组成的有向图。这带来了几个巨大优势显式状态管理整个Agent的运行状态State是一个贯穿始终的、可自定义的Pydantic模型状态变化一目了然。清晰的控制流通过边条件判断来控制下一个执行节点循环、分支、并行等逻辑变得极其直观。强大的可观测性由于执行路径是确定的图配合LangSmith等工具可以非常清晰地可视化每一步的执行过程、输入输出和耗时这对生产调试至关重要。子图Subgraph支持可以将复杂流程模块化比如把“用户身份验证”抽成一个子图多处复用保持代码整洁。 对于我们的工单Agent分类、路由、状态更新、等待用户输入正好可以建模成一个清晰的图结构。因此LangGraph是我们的核心框架选择。Dify这是一个优秀的低代码/无代码AI应用平台。它通过可视化工作流编排大大降低了构建AI应用的门槛。如果你追求极致的开发速度且业务逻辑不涉及大量自定义代码和复杂集成Dify是很好的选择。但是它的缺点也在于“平台化”自定义能力受限于平台提供的节点深度集成内部系统可能需要绕弯子部署和运维依赖平台方对于需要极致性能调优和复杂控制逻辑的场景可能会遇到天花板。我们的项目需要紧密耦合内部工单API且对可控性要求高因此Dify更适合作为前期原型验证工具而非最终生产框架。Claude Agent SDK这是Anthropic为其Claude模型量身打造的Agent框架。如果你坚定地使用Claude系列模型并且希望获得与模型特性深度优化的开发体验它是一个不错的选择。但其生态和灵活性目前与LangChain/LangGraph还有差距且将你绑定在了特定的模型提供商上。从生产级的长期维护和灵活性考虑我们暂时不将其作为主选。结论我们选择LangGraph作为核心编排框架利用其强大的状态管理和可视化工作流能力。同时我们会利用LangChain生态中丰富的工具集成如计算器、搜索引擎封装等作为补充。底层LLM为了平衡效果、成本和速度生产环境可以选择GPT-4o或Claude 3 Haiku开发调试阶段可以用DeepSeek或通义千问等性价比较高的模型。3. 环境搭建与核心概念初始化工欲善其事必先利其器。生产级项目的第一步就是建立一个稳定、可复现的工程环境。3.1 工程化环境配置别再只用pip install了生产环境需要精确的依赖管理。# 创建项目目录 mkdir production-ai-agent cd production-ai-agent # 创建虚拟环境推荐使用uv或conda这里用uv示例速度极快 uv venv source .venv/bin/activate # On Windows: .venv\Scripts\activate # 使用 uv 初始化项目并安装核心依赖 uv init uv add langgraph langchain-openai langchain-community pydantic python-dotenv uv add fastapi uvicorn httpx # 用于构建API服务 uv add langsmith # 用于可观测性强烈推荐 uv add pytest pytest-asyncio # 用于测试 # 生成 requirements.txt 以备部署 uv pip compile pyproject.toml -o requirements.txt关键依赖说明langgraph核心工作流引擎。langchain-openaiOpenAI模型集成。langchain-community包含大量社区工具。pydantic用于定义强类型的State模型这是LangGraph的基石。langsmithLangChain官方出的可观测性平台能记录每次链、Agent的调用轨迹对调试和生产监控不可或缺。它有免费额度。接下来创建项目结构production-ai-agent/ ├── .env # 环境变量API Keys等 ├── .gitignore ├── pyproject.toml # 项目依赖声明 ├── src/ │ ├── __init__.py │ ├── agent/ # Agent核心逻辑 │ │ ├── __init__.py │ │ ├── state.py # 定义State │ │ ├── nodes.py # 定义各个节点函数 │ │ ├── graph.py # 构建并编译Graph │ │ └── tools.py # 自定义工具 │ ├── api/ # FastAPI应用 │ │ ├── __init__.py │ │ └── main.py │ └── config.py # 配置管理 ├── tests/ # 测试用例 └── scripts/ # 部署或辅助脚本3.2 理解LangGraph的核心State与Graph这是LangGraph最精髓的两个概念必须吃透。State它定义了你的Agent在整个工作流中需要记住和传递的所有信息。它必须是一个PydanticBaseModel。对于我们的工单AgentState可能长这样# src/agent/state.py from typing import Annotated, Literal, Optional from typing_extensions import TypedDict import operator from pydantic import BaseModel, Field from datetime import datetime class AgentState(BaseModel): Agent的完整状态贯穿工作流始终。 # 用户输入 user_input: str Field(description用户当前轮次的输入内容) # 对话历史简化版生产环境可能需要更复杂的结构 conversation_history: Annotated[list, operator.add] Field( default_factorylist, description对话历史记录每轮为一个字典包含角色和内容 ) # Agent的分析结果 intent: Optional[str] Field(defaultNone, description识别的用户意图类别) confidence: Optional[float] Field(defaultNone, description意图识别的置信度) # 系统执行结果 ticket_id: Optional[str] Field(defaultNone, description创建的工单ID) assigned_queue: Optional[str] Field(defaultNone, description分配的工单队列) # 控制流标志 requires_human: bool Field(defaultFalse, description是否需要人工介入) error_message: Optional[str] Field(defaultNone, description错误信息) # 元数据 created_at: datetime Field(default_factorydatetime.now)注意conversation_history字段的Annotated[list, operator.add]这是LangGraph的归约器Reducer它告诉框架在每次循环中如何更新这个列表这里是追加。这是实现多轮对话记忆的关键。Graph与NodeGraph是由Node节点和Edge边组成的。Node是一个普通的Python函数或异步函数它接收当前的State执行一些操作如调用LLM、调用工具然后返回一个State的更新字典。Edge决定了基于更新后的State下一个该执行哪个Node。4. 构建生产级工单处理Agent现在我们开始用代码将设计落地。4.1 定义工具ToolsAgent的手和脚工具是Agent与外部世界交互的方式。我们先定义两个核心工具一个用于调用内部工单系统API一个用于查询知识库模拟。# src/agent/tools.py import httpx from typing import Dict, Any from langchain.tools import tool from langchain_core.tools import ToolException import logging logger logging.getLogger(__name__) class InternalTicketSystem: 模拟内部工单系统客户端。生产环境需替换为真实SDK或API调用。 def __init__(self, base_url: str, api_key: str): self.client httpx.AsyncClient(base_urlbase_url, headers{X-API-Key: api_key}) async def create_ticket(self, title: str, description: str, category: str, user_info: Dict) - Dict[str, Any]: 在内部系统创建工单。 payload { title: title, description: description, category: category, submitter: user_info } try: resp await self.client.post(/api/v1/tickets, jsonpayload, timeout30.0) resp.raise_for_status() data resp.json() logger.info(f工单创建成功: ID{data.get(id)}) return {success: True, ticket_id: data.get(id), queue: data.get(assignedQueue)} except httpx.HTTPStatusError as e: logger.error(f创建工单HTTP错误: {e}) raise ToolException(f工单系统创建失败: {e.response.text}) except Exception as e: logger.error(f创建工单未知错误: {e}) raise ToolException(f工单系统请求异常: {str(e)}) async def close(self): await self.client.aclose() # 使用LangChain的tool装饰器将其暴露给Agent tool async def create_service_ticket(ticket_title: str, ticket_description: str, problem_category: str) - str: 在内部工单系统中创建一个新的服务请求工单。 请确保problem_category是以下之一[billing, technical, account, general_inquiry]。 Args: ticket_title: 工单的简短标题。 ticket_description: 问题的详细描述。 problem_category: 问题分类。 # 这里简化处理实际应从State或上下文中获取用户信息 user_info {user_id: extracted_from_context} # 初始化客户端生产环境应从依赖注入或全局配置获取 # 此处为示例直接模拟返回 # async with InternalTicketSystem(https://internal.example.com, key) as its: # result await its.create_ticket(ticket_title, ticket_description, problem_category, user_info) # return f工单创建成功工单号{result[ticket_id]}已分配至{result[queue]}队列。 return f[模拟]工单创建成功标题{ticket_title}分类{problem_category}工单号T-20240527-001。 tool async def search_knowledge_base(query: str) - str: 在公司内部知识库中搜索相关解决方案或文档。 # 模拟搜索过程 simulated_results [ f找到关于{query}的文档如何重置账户密码。, f相关文章{query}常见问题解答。 ] return \n.join(simulated_results[:2]) # 返回前两条注意工具函数的文档字符串Docstring至关重要LLM尤其是GPT-4依赖这些描述来决定何时以及如何调用工具。描述要清晰、准确并说明参数格式。4.2 实现节点Nodes工作流中的每一步节点是工作流中的具体执行单元。我们将工单处理流程分解为几个节点。# src/agent/nodes.py from typing import Dict, Any from langgraph.graph import StateGraph, START, END from .state import AgentState from .tools import create_service_ticket, search_knowledge_base from langchain_openai import ChatOpenAI from langchain_core.messages import HumanMessage, SystemMessage, AIMessage import logging import json logger logging.getLogger(__name__) # 初始化LLM。生产环境应从配置读取模型名和API Key。 llm ChatOpenAI(modelgpt-4o-mini, temperature0.1, streamingFalse) async def classify_intent_node(state: AgentState) - Dict[str, Any]: 节点1分析用户输入识别意图和分类。 logger.info(f开始意图分类用户输入: {state.user_input[:100]}...) # 构建系统提示词这是影响效果的关键 system_prompt SystemMessage(content你是一个专业的客服工单分类助手。请严格根据用户输入判断其意图属于以下哪一类 1. report_issue - 用户报告一个具体的问题或故障如无法登录、支付失败、页面错误。 2. ask_question - 用户提出一个咨询类问题如如何操作、资费说明、功能咨询。 3. request_service - 用户明确请求一项服务如开通权限、重置密码、注销账户。 4. other - 不属于以上任何一类。 同时如果属于report_issue或request_service请进一步判断问题类别 - billing (账单/支付) - technical (技术/故障) - account (账户/登录) - general_inquiry (普通咨询) 请以纯JSON格式回复包含两个字段intent (意图) 和 category (类别仅当意图为1或3时提供否则为null)。不要有任何额外解释。) user_message HumanMessage(contentstate.user_input) try: response await llm.ainvoke([system_prompt, user_message]) result_text response.content.strip() # 安全地解析JSON result json.loads(result_text) intent result.get(intent, other) category result.get(category) logger.info(f意图分类结果: intent{intent}, category{category}) # 更新状态 update { intent: intent, assigned_queue: category # 这里简单映射实际可能更复杂 } # 将本轮交互加入历史 new_history_entry {role: user, content: state.user_input} new_ai_entry {role: assistant, content: f分析意图: {intent}, 类别: {category}} return {conversation_history: [new_history_entry, new_ai_entry], **update} except json.JSONDecodeError as e: logger.error(fLLM返回的JSON解析失败: {result_text}, 错误: {e}) return {intent: other, error_message: f意图分析失败: {e}} except Exception as e: logger.error(f意图分类节点执行异常: {e}) return {intent: other, error_message: str(e), requires_human: True} async def handle_question_node(state: AgentState) - Dict[str, Any]: 节点2处理咨询类问题尝试从知识库寻找答案。 if state.intent ! ask_question: # 如果不是咨询类直接传递状态不执行操作 return {} logger.info(f处理咨询问题: {state.user_input}) # 调用知识库搜索工具 kb_result await search_knowledge_base(state.user_input) # 让LLM基于知识库结果生成友好回复 prompt f用户问题{state.user_input} 从知识库中找到的相关信息 {kb_result} 请根据以上信息用友好、专业的口吻直接回答用户的问题。如果知识库信息不足请如实告知并建议其提交工单。 ai_response await llm.ainvoke([HumanMessage(contentprompt)]) reply_content ai_response.content update { conversation_history: [{role: assistant, content: reply_content}] } return update async def create_ticket_node(state: AgentState) - Dict[str, Any]: 节点3对于需要创建工单的意图调用工具创建工单。 if state.intent not in [report_issue, request_service]: return {} if not state.assigned_queue: return {error_message: 无法确定工单类别, requires_human: True} logger.info(f开始创建工单类别: {state.assigned_queue}) # 这里可以构建更详细的工单描述例如结合对话历史 ticket_title f{state.intent}: {state.user_input[:50]}... ticket_description f用户描述{state.user_input}\n\n分析意图{state.intent}\n分配队列{state.assigned_queue} try: # 调用工具 tool_result await create_service_ticket.ainvoke({ ticket_title: ticket_title, ticket_description: ticket_description, problem_category: state.assigned_queue }) update { ticket_id: T-SIMULATED-001, # 应从工具返回结果中提取 conversation_history: [{role: assistant, content: tool_result}] } return update except Exception as e: logger.error(f创建工单失败: {e}) return {error_message: f创建工单时出错: {e}, requires_human: True} async def finalize_response_node(state: AgentState) - Dict[str, Any]: 节点4整理最终回复给用户。 # 这里可以根据state中的ticket_id, assigned_queue等信息生成最终总结性消息 if state.ticket_id: final_msg f您的问题已处理完毕。工单号{state.ticket_id}已转至{state.assigned_queue}团队跟进。您可以通过工单号查询进度。 elif state.error_message: final_msg f处理过程中遇到问题{state.error_message}。已为您转接人工客服。 # 更新状态标志需要人工介入 return {conversation_history: [{role: assistant, content: final_msg}], requires_human: True} else: # 对于咨询类回复已在handle_question_node生成这里可能不需要额外动作 # 或者可以生成一个结束语 final_msg 请问还有其他可以帮您的吗 return {conversation_history: [{role: assistant, content: final_msg}]}4.3 组装工作流图Graph编排节点与边这是LangGraph最直观的部分像画流程图一样把节点连接起来。# src/agent/graph.py from langgraph.graph import StateGraph, START, END from .state import AgentState from .nodes import classify_intent_node, handle_question_node, create_ticket_node, finalize_response_node import logging logger logging.getLogger(__name__) def route_after_classify(state: AgentState) - str: 路由函数根据意图分类结果决定下一个节点。 intent state.intent if intent ask_question: return handle_question elif intent in [report_issue, request_service]: return create_ticket else: return finalize_response # 其他意图或分类失败直接结束 def check_for_human_intervention(state: AgentState) - str: 路由函数检查是否需要人工介入。 if state.requires_human: logger.warning(流程标记为需要人工介入。) return END # 直接结束或跳转到人工交接节点 return __end__ # 继续默认流程 def create_agent_graph() - StateGraph: 创建并编译工单处理Agent的工作流图。 # 1. 创建图构建器并指定状态模式 workflow StateGraph(AgentState) # 2. 添加节点 workflow.add_node(classify_intent, classify_intent_node) workflow.add_node(handle_question, handle_question_node) workflow.add_node(create_ticket, create_ticket_node) workflow.add_node(finalize_response, finalize_response_node) # 3. 添加边定义控制流 workflow.add_edge(START, classify_intent) # 从 classify_intent 出来根据路由函数决定去向 workflow.add_conditional_edges( classify_intent, route_after_classify, { handle_question: handle_question, create_ticket: create_ticket, finalize_response: finalize_response, } ) # handle_question 和 create_ticket 节点执行后都走向 finalize_response workflow.add_edge(handle_question, finalize_response) workflow.add_edge(create_ticket, finalize_response) # 在最终响应前检查是否需要人工介入 workflow.add_conditional_edges( finalize_response, check_for_human_intervention, {END: END, __end__: END} # 这里简化实际可能有人工节点 ) # 设置最终节点 workflow.add_edge(finalize_response, END) # 4. 编译图 compiled_graph workflow.compile() logger.info(工单处理Agent图编译完成。) return compiled_graph # 全局可用的图实例 agent_graph create_agent_graph()现在一个具备完整工作流的Agent就构建好了。你可以通过agent_graph.invoke({user_input: 我的账户登录不上了提示密码错误})来测试它。它会自动执行分类-创建工单-生成回复的流程。5. 部署、监控与性能优化一个能在本地运行的Agent离“生产级”还差得远。接下来是关键环节让它成为一个可靠的服务。5.1 使用FastAPI构建RESTful API我们需要一个标准接口供前端或其他服务调用。# src/api/main.py from fastapi import FastAPI, HTTPException, Depends from pydantic import BaseModel from contextlib import asynccontextmanager import logging from src.agent.graph import agent_graph from src.agent.state import AgentState import os from langsmith import Client from dotenv import load_dotenv load_dotenv() # 配置LangSmith追踪非必须但强烈推荐 os.environ[LANGCHAIN_TRACING_V2] true os.environ[LANGCHAIN_ENDPOINT] https://api.smith.langchain.com os.environ[LANGCHAIN_API_KEY] os.getenv(LANGCHAIN_API_KEY) os.environ[LANGCHAIN_PROJECT] production-ticket-agent # 你的项目名 logger logging.getLogger(__name__) class ChatRequest(BaseModel): message: str session_id: str | None None # 用于支持多轮对话会话 class ChatResponse(BaseModel): reply: str session_id: str requires_human: bool ticket_id: str | None None # 简单的内存会话存储生产环境请使用Redis、数据库等 session_store {} asynccontextmanager async def lifespan(app: FastAPI): # 启动逻辑如初始化数据库连接池 logger.info(AI Agent API 启动中...) yield # 关闭逻辑 logger.info(AI Agent API 关闭中...) # 如有需要可关闭工具中的HTTP客户端等 app FastAPI(title工单处理AI Agent API, lifespanlifespan) app.post(/chat, response_modelChatResponse) async def chat_with_agent(request: ChatRequest): 与工单处理Agent对话的主端点。 try: # 1. 获取或初始化会话状态 session_id request.session_id or fsess_{os.urandom(4).hex()} current_state session_store.get(session_id, AgentState(user_input)) # 2. 更新状态中的用户输入 inputs {user_input: request.message} # 可以在这里合并历史状态LangGraph的invoke会处理Reducer # 为了简单演示我们每次重新初始化生产环境需持久化完整State # 更佳实践是将整个State序列化后存入session_store # 3. 调用编译好的图执行工作流 config {configurable: {thread_id: session_id}} # 用于LangSmith追踪 final_state await agent_graph.ainvoke(inputs, configconfig) # 4. 从最终状态提取回复 # 取对话历史中最后一条AI回复 history final_state.get(conversation_history, []) last_ai_msg next( (msg[content] for msg in reversed(history) if msg[role] assistant), 抱歉我未能生成回复。 ) # 5. 更新会话存储简化处理实际应存储整个State session_store[session_id] final_state # 6. 返回响应 return ChatResponse( replylast_ai_msg, session_idsession_id, requires_humanfinal_state.get(requires_human, False), ticket_idfinal_state.get(ticket_id) ) except Exception as e: logger.exception(f处理聊天请求时发生未预期错误: {e}) raise HTTPException(status_code500, detail内部服务器错误) app.get(/health) async def health_check(): 健康检查端点。 return {status: healthy}使用Uvicorn运行uvicorn src.api.main:app --host 0.0.0.0 --port 8000 --reload5.2 集成可观测性LangSmith实战没有可观测性的AI应用就是“盲人摸象”。LangSmith能记录每一次LLM调用、工具调用和图的执行路径。注册并获取API Key前往 LangSmith官网 注册。配置环境变量如上文代码所示设置LANGCHAIN_TRACING_V2、LANGCHAIN_API_KEY等。查看追踪启动你的Agent并发送请求后在LangSmith控制台即可看到详细的追踪记录。你可以看到每个节点的输入输出。LLM调用的具体提示词Prompt和补全Completion。工具调用的参数和结果。整个工作流的耗时瀑布图。这对于调试“为什么Agent做出了这个决策”和性能优化至关重要。5.3 性能优化与成本控制要点生产环境必须关注这两点。缓存对LLM结果进行缓存可以大幅减少重复调用和成本。使用langchain.cache如SQLiteCache,RedisCache。from langchain.globals import set_llm_cache from langchain.cache import SQLiteCache set_llm_cache(SQLiteCache(database_path.langchain.db))超时与重试为LLM和工具调用设置合理的超时和重试策略避免单个慢请求拖垮整个服务。langchain-openai和httpx都支持配置。模型降级非关键路径或简单任务使用更小、更快的模型如gpt-4o-minivsgpt-4o。异步化确保你的节点函数、工具调用都是异步的async/await并使用异步HTTP客户端如httpx.AsyncClient以支持高并发。批量处理如果场景允许将多个用户请求聚合后批量调用LLM需要模型支持能显著降低成本。6. 测试、迭代与常见问题排查6.1 编写自动化测试测试AI应用有其特殊性因为输出是非确定性的。我们的策略是单元测试节点函数Mock掉LLM和工具测试业务逻辑。集成测试工作流使用固定的测试用例和Mock的LLM响应验证整个图的执行路径是否符合预期。评估测试Evaluation使用LangSmith的评估功能针对一批真实或构造的测试用例评估Agent输出的相关性、准确性和安全性。# tests/test_agent.py import pytest from unittest.mock import AsyncMock, patch from src.agent.nodes import classify_intent_node from src.agent.state import AgentState pytest.mark.asyncio async def test_classify_intent_node_report_issue(): 测试分类节点对报障类输入的处理。 # 模拟LLM返回固定的JSON mock_response AsyncMock() mock_response.content {intent: report_issue, category: technical} with patch(src.agent.nodes.llm.ainvoke, return_valuemock_response): initial_state AgentState(user_input网站突然打不开了显示500错误。) result await classify_intent_node(initial_state) assert result[intent] report_issue assert result[assigned_queue] technical assert len(result[conversation_history]) 26.2 常见问题与排查清单在实际开发和运维中你肯定会遇到下面这些问题问题1Agent总是调用错误的工具或参数不对。排查首先去LangSmith查看LLM接收到工具定义tool.description的提示词部分是否清晰。检查工具的描述文档是否准确描述了功能和参数。尝试在系统提示词中更明确地指导LLM何时使用工具。技巧给工具起一个清晰、动词开头的名字如search_knowledge_base而非kb_search。在工具描述中明确写出调用示例。问题2图执行陷入循环或停在某个节点不动。排查检查add_conditional_edges中的路由函数。确保所有可能的状态分支都有对应的目标节点。在路由函数中增加详细的日志打印出判断条件。技巧使用workflow.get_graph().draw_mermaid()输出图的Mermaid代码在线渲染成流程图直观检查逻辑。问题3多轮对话中状态如对话历史混乱或丢失。排查确认State中用于存储历史的字段是否正确使用了Annotated[list, operator.add]。检查每次invoke时是否正确地传递和恢复了完整的上一轮State。会话存储如session_store的实现是否正确。技巧在开发初期可以将完整的State在API响应中也返回给前端调试用便于观察状态变化。问题4性能瓶颈API响应慢。排查利用LangSmith的追踪时间线找出耗时最长的节点。通常是LLM调用或外部工具调用如网络请求。优化为LLM调用启用缓存。优化工具调用的网络连接使用连接池、设置超时。考虑将非必要的同步操作改为异步。问题5LLM输出格式不符合要求无法解析。排查这是提示词工程问题。在系统提示词中严格要求输出格式如“请以纯JSON格式回复包含xx字段”。使用response_format参数如果模型支持如OpenAI的JSON模式。在代码中添加更健壮的解析逻辑和fallback机制。构建生产级AI Agent是一个系统工程它远不止是调用API。从清晰的架构设计LangGraph到工程化的环境与部署再到不可或缺的可观测性LangSmith和测试评估每一步都关乎最终应用的稳定性和可用性。这套以LangGraph为核心的方案提供了所需的控制力、透明度和扩展性。希望这个从零到一的实战指南能帮你避开我当初踩过的那些坑更顺畅地将你的AI想法落地为真正可用的服务。