在传统客服领域工作过的朋友一定对这几个场景不陌生用户问了一个稍微复杂点的问题系统要么答非所问要么需要等待好几秒才能给出一个干巴巴的、可能已经过时的答案。更头疼的是当产品知识库更新后客服机器人往往需要重新训练整个模型费时费力。今天我们就来聊聊如何用LangGraph和RAG技术亲手搭建一个既快又准、还能“与时俱进”的智能客服系统实测下来响应速度的提升非常可观。1. 为什么是 LangGraph RAG在深入代码之前我们先理清思路。传统客服机器人的核心痛点有三个响应慢尤其是涉及多步查询或逻辑判断时流程是串行的一步卡住步步等待。知识旧基于固定语料训练的模型无法实时获取最新的产品文档、公告或用户手册。对话笨很难进行连贯的多轮对话经常忘记上文说了什么或者无法处理用户指代比如“上面说的那个功能怎么用”。RAG完美解决了第二个问题。它把用户的问题拿去向量数据库里搜一圈把最相关的文档片段找出来和问题一起塞给大语言模型去生成答案。这样答案的“素材”始终是最新的我们只需要更新向量数据库就行。但 RAG 本身还是一个“单步”操作。一个复杂的客服查询可能先要判断意图再决定是查知识库、查订单、还是转人工中间可能还需要多次追问用户获取必要信息。这就是LangGraph的用武之地。它让我们可以用图的方式编排这些步骤哪些可以并行跑哪些需要按条件分支管理起来清清楚楚效率自然就上去了。2. 技术选型为什么不是 Airflow 或 Prefect你可能会问工作流引擎不是有 Airflow、Prefect 这些成熟方案吗它们和 LangGraph 定位不同。Airflow/Prefect更像是“宏观调度器”擅长管理以天、小时为周期的批处理任务比如每天凌晨的数据ETL。它们的任务节点通常是独立的脚本或任务节点间传递的是任务成功/失败的状态和有限的数据不适合做毫秒级、需要复杂内存状态共享的实时对话交互。LangGraph是“微观编排器”专为AI应用设计。它的节点是函数边定义了函数执行的顺序和条件整个图的状态也就是对话的上下文在内存中流动延迟极低。它原生支持循环多轮对话、并行、条件分支这些正是智能对话系统需要的。所以对于需要低延迟、有状态、多步骤的AI智能体应用LangGraph是目前更趁手的工具。3. 核心实现三步走我们的智能客服核心流程可以抽象为三个主要模块用 LangGraph 串联起来。3.1 第一步用 LangGraph 绘制客服“思维导图”我们把一次客服交互看作一个图。这个图至少包含以下几个节点路由节点判断用户意图。是普通问答查询订单还是投诉建议检索节点对于问答类意图调用 RAG 检索器去向量数据库找资料。生成节点将检索到的资料和用户问题结合生成友好、准确的回答。外部查询节点对于订单查询等调用内部API获取数据。状态管理节点负责维护和更新对话历史。LangGraph 的强大在于定义这些节点之间的流转逻辑非常直观。比如路由节点之后可以同时指向检索节点和外部查询节点但通过条件边每次只执行其中一个分支。from langgraph.graph import StateGraph, END from typing import TypedDict, Annotated from langchain_core.messages import AnyMessage, HumanMessage, AIMessage import operator # 1. 定义图的状态这是贯穿整个流程的“记忆体” class AgentState(TypedDict): messages: Annotated[list[AnyMessage], operator.add] # 对话消息历史 user_intent: str # 路由识别的用户意图 retrieved_context: list[str] # RAG检索到的上下文 final_answer: str # 最终生成的答案 # 2. 初始化图 workflow StateGraph(AgentState) # 3. 定义各个节点函数 def router_node(state: AgentState) - AgentState: 根据最新一条用户消息判断意图 last_message state[“messages”][-1].content # 这里可以用一个简单的分类器或者调用一个小型LLM来判断 if “订单” in last_message or “物流” in last_message: intent “query_order” elif “投诉” in last_message or “建议” in last_message: intent “human_transfer” else: intent “qa” return {“user_intent”: intent} def retrieval_node(state: AgentState) - AgentState: 只有意图为qa时才执行检索 if state[“user_intent”] ! “qa”: return {“retrieved_context”: []} query state[“messages”][-1].content # 调用RAG检索器具体实现见下一节 contexts rag_retriever.invoke(query) return {“retrieved_context”: contexts} def generation_node(state: AgentState) - AgentState: 生成最终答案 if state[“user_intent”] “qa”: # 结合检索到的上下文生成 prompt f“””基于以下信息回答问题。如果信息不足请如实告知。 信息{‘\n’.join(state[‘retrieved_context’])} 问题{state[‘messages’][-1].content} 答案“”” answer llm.invoke(prompt) elif state[“user_intent”] “query_order”: # 调用订单查询API answer f“已为您查询订单状态是{query_order_api(state[‘messages’][-1].content)}” else: answer “您的问题需要人工客服协助正在为您转接...” # 将AI的回答添加到消息历史中这是实现多轮对话的关键 new_ai_message AIMessage(contentanswer) return {“final_answer”: answer, “messages”: [new_ai_message]} # 4. 将节点添加到图中 workflow.add_node(“router”, router_node) workflow.add_node(“retriever”, retrieval_node) workflow.add_node(“generator”, generation_node) # 5. 设置边定义执行流程 workflow.set_entry_point(“router”) # router之后流程一定会走到retriever workflow.add_edge(“router”, “retriever”) # retriever之后流程一定会走到generator workflow.add_edge(“retriever”, “generator”) # generator是终点 workflow.add_edge(“generator”, END) # 6. 编译图得到一个可执行对象 app workflow.compile()3.2 第二步打造高效的RAG核心RAG模块的核心是检索器。我们选用轻量级的Chroma作为向量数据库OpenAI的text-embedding-3-small模型做嵌入。from langchain_chroma import Chroma from langchain_openai import OpenAIEmbeddings, ChatOpenAI from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain_community.document_loaders import TextLoader # 初始化组件 embeddings OpenAIEmbeddings(model“text-embedding-3-small”) llm ChatOpenAI(model“gpt-3.5-turbo”) text_splitter RecursiveCharacterTextSplitter(chunk_size500, chunk_overlap50) class RAGRetriever: def __init__(self, persist_directory“./chroma_db”): # 持久化存储避免每次冷启动 self.vectorstore Chroma( embedding_functionembeddings, persist_directorypersist_directory ) self.retriever self.vectorstore.as_retriever(search_kwargs{“k”: 3}) # 返回最相关的3个片段 def add_documents(self, file_path): 向知识库添加新文档 loader TextLoader(file_path) documents loader.load() chunks text_splitter.split_documents(documents) self.vectorstore.add_documents(chunks) print(f“已成功添加 {len(chunks)} 个文本块到知识库。”) def invoke(self, query: str) - list[str]: 检索与查询最相关的文本 docs self.retriever.invoke(query) return [doc.page_content for doc in docs] # 初始化RAG检索器 rag_retriever RAGRetriever() # 首次运行或更新知识时调用 # rag_retriever.add_documents(“./product_manual.txt”)关键点chunk_size文本块大小和k检索数量是影响精度和速度的关键参数。块太大信息可能不聚焦块太小可能丢失上下文。k值太大会拖慢生成速度k值太小可能漏掉关键信息。需要根据你的知识库特点进行调试。3.3 第三步对话状态管理——系统的“记忆”从上面的代码可以看到AgentState中的messages字段记录了完整的对话历史。这是实现多轮对话的基础。每次用户发起新的一轮我们都将整个历史包括之前的问答传递给路由和生成节点。这样LLM 就能理解上下文中的指代关系。但是这里有一个常见的坑无限制地增长历史会导致两个问题1) 超过LLM的上下文窗口长度2) 不必要的token消耗增加成本和延迟。解决方案是使用“对话摘要”或“滑动窗口”对话摘要在对话轮次较多时用一个单独的节点将冗长的历史总结成一段简短的摘要然后用摘要最近几轮对话作为新的历史。滑动窗口只保留最近N轮对话例如最近10轮丢弃更早的。我们在generation_node之后可以增加一个summarize_node来实现摘要功能或者简单地在状态更新逻辑里截断messages列表。4. 性能优化与避坑指南系统搭起来了但要用于生产还得过性能这一关。4.1 负载测试与缓存策略用locust或pytest-benchmark模拟并发用户请求重点关注两个指标P95响应时间和每秒查询数。优化手段检索结果缓存对于高频、通用问题如“营业时间”、“退货政策”其检索结果在短时间内是稳定的。可以用functools.lru_cache或Redis缓存(query, k)对应的文档ID列表避免重复进行向量相似度计算。from functools import lru_cache lru_cache(maxsize1024) def cached_retrieve(query: str, k: int) - list[str]: return rag_retriever.vectorstore.similarity_search(query, kk)LLM响应缓存对于完全相同的输入提示词输出是确定的。可以缓存(prompt_hash, model_name)到对应的答案。但要注意如果提示词中包含了随时间变化的信息如“今天的订单”就不能缓存。4.2 冷启动优化第一次启动服务时加载嵌入模型和连接向量数据库可能较慢。预热在服务启动后立即用几个标准查询如“你好”、“介绍一下产品”触发一次完整的检索和生成流程让相关组件完成初始化。持久化连接池确保数据库连接、Embedding模型客户端等是长连接或池化管理的。4.3 RAG检索偏差修正有时候检索到的文档片段Top1未必是最相关的这会导致“答偏”。重排序先使用向量检索召回较多的候选文档比如k10再用一个更精细的交叉编码器模型对候选文档进行重排序选出Top3。虽然多了一步但精度提升显著。元数据过滤在存储文档时为其添加元数据如“部门售后”、“版本v2.0”。检索时可以先根据对话历史推测用户可能关心的元数据范围进行初步过滤提升检索精度。4.4 LangGraph任务编排最佳实践节点职责单一每个节点只做一件事路由、检索、生成、调用API。这样图结构清晰便于调试和单元测试。善用条件边不是所有流程都是线性的。利用add_conditional_edges可以根据节点输出动态决定下一步走向实现复杂的业务流程。状态精简AgentState里只放必要的数据。传递过大的状态对象会影响序列化/反序列化效率。5. 总结与延伸通过 LangGraph 的流程编排和 RAG 的动态知识获取我们构建的智能客服系统不仅响应更快得益于并行和精准检索而且维护更简单更新知识库只需增删文档。实测中对于知识库内的标准问题端到端响应时间能从传统方案的2-3秒降低到800毫秒以内提升超过300%。这个框架还有很大的扩展空间多语言支持为不同语种的知识库建立独立的向量存储在路由节点识别用户语言后选择对应的RAG检索器和生成模型。多模态交互用户可能上传图片询问产品。可以在图里增加一个“视觉理解”节点使用多模态大模型如GPT-4V解析图片内容将其转换为文本描述再流入后续的检索和生成流程。复杂事务处理将处理退换货、修改订单等需要多步交互的事务流程用 LangGraph 的子图功能封装起来使主图更加简洁。搭建的过程就像搭积木LangGraph 提供了稳固的连接件RAG 提供了丰富的知识积木而我们的业务逻辑则是搭建的图纸。希望这篇笔记能帮你理清图纸动手搭建出属于你自己的、高效智能的客服助手。