从RAG到智能体:LangChain与LangGraph构建AI应用工作流实战 在实际 AI 大模型应用开发领域从简单的 API 调用到构建具备自主决策和复杂工作流的智能体技术栈的深度和广度都在快速扩展。对于准备面试或希望系统掌握核心技术的开发者而言常常面临知识碎片化、概念混淆、缺乏实战串联的困境。Agent、RAG、LangChain、LangGraph 这些关键词代表了当前构建高级 AI 应用的核心组件理解它们各自的作用、相互关系以及如何组合使用是区分普通调用者与资深架构师的关键。本文将围绕这四个核心概念构建一条从理论到实践的学习路径。我们不会停留在概念介绍而是深入其工作机制通过对比分析厘清 LangChain 与 LangGraph 的设计哲学差异并构建一个融合了 RAG 知识库查询与多步骤决策的智能体案例。目标是让你不仅能回答面试中的深度问题更能具备设计和实现一个完整 AI 应用工作流的能力。1. 核心概念解析Agent、RAG、LangChain 与 LangGraph 的角色定位在开始编码之前必须清晰理解每个技术组件解决的核心问题及其在应用架构中的位置。混淆概念会导致技术选型错误和架构设计混乱。1.1 Agent从工具执行者到自主决策者Agent智能体的本质是一个能够感知环境、进行决策并执行行动以达到目标的系统。在大模型语境下Agent 通常指一个以大语言模型为核心“大脑”能够调用外部工具如搜索引擎、计算器、数据库、API来完成复杂任务的程序。通俗理解如果把大模型看作一个知识渊博但“手无缚鸡之力”的顾问那么 Agent 就是为这位顾问配备了手工具、眼感知和脚执行能力使其能够真正动手解决问题。例如一个“数据分析 Agent”可以理解用户问题“分析上个月销售趋势”决定需要调用数据库查询工具和图表生成工具然后按顺序执行这些操作最终给出带图表的报告。技术定义一个典型的 Agent 框架包含几个关键部分规划Planning拆解任务、工具调用Tool Use选择并执行工具、记忆Memory记住对话历史和工具执行结果。其工作流是循环的思考 - 行动 - 观察结果 - 再思考直到任务完成或无法继续。面试常见问题“Agent 和简单的 Chain 有什么区别” Chain 是预定义的、线性的执行流程而 Agent 引入了决策点其执行路径会根据模型对当前状态的判断动态变化因此能处理更开放、更复杂的任务。1.2 RAG为大模型注入精准的领域知识RAG 代表检索增强生成。其核心要解决的问题是大模型的幻觉问题与知识滞后性。通用大模型可能对特定领域、私有数据或最新信息一无所知或产生错误回答。通俗理解想象你要写一篇关于公司最新产品的报告但你手头只有产品的公开简介。RAG 的作用就是先帮你从公司内部文档库知识库里快速找到所有相关的技术文档、市场报告和用户反馈检索然后你结合这些找到的资料和你自己的写作能力生成完成一份内容准确、细节丰富的报告。技术流程索引将私有或领域文档分割成片段转换为向量嵌入存入向量数据库。检索当用户提问时将问题也转换为向量在向量数据库中搜索最相关的文本片段。增强将检索到的相关片段作为上下文与用户问题一起拼接成提示词Prompt提交给大模型。生成大模型基于提供的上下文生成最终答案。关键价值答案更具事实依据可追溯来源检索到的片段且无需重新训练模型即可更新知识更新向量数据库即可。1.3 LangChainAI 应用的“脚手架”和“粘合剂”LangChain 是一个用于开发由大语言模型驱动的应用程序的框架。它本身不是一个 Agent 或 RAG 的实现而是一个提供了大量标准化组件的工具箱。核心功能模型抽象统一不同厂商OpenAI Anthropic 本地模型等的调用接口。提示词管理提供模板、示例选择器方便构建和复用 Prompt。链将多个对大模型的调用、工具调用、数据处理步骤串联起来形成固定流水线。记忆提供多种记忆后端管理对话历史。代理提供了实现 Agent 所需的基础设施如工具定义、代理执行器。检索集成了与向量数据库交互的接口是构建 RAG 系统的重要部分。定位LangChain 降低了构建复杂 AI 应用的门槛开发者无需从零开始处理模型集成、上下文管理、工具编排等繁琐问题。你可以把它看作乐高积木提供了各种标准化零件。1.4 LangGraph基于状态图的复杂工作流编排引擎LangGraph 是建立在 LangChain 之上的一个库专门用于构建有状态的、多参与者的工作流。它引入了图计算的思想来编排 Agent 或 Chain。核心概念状态和边。整个系统被建模为一个图节点是执行单元如调用 LLM、运行工具边定义了状态如何在不同节点间流转的条件。与 LangChain Agent 的区别这是面试高频点。LangChain 标准 Agent通常采用AgentExecutor其循环是LLM 决定下一步行动 - 执行工具 - 将结果返回给 LLM 进行下一轮思考。这个循环相对固定适合单代理、任务明确的场景。LangGraph可以构建任意复杂的拓扑结构。例如你可以创建多个专属 Agent一个负责检索一个负责分析一个负责格式化并定义它们之间的协作规则。可以轻松实现循环、分支、并行、人工审核节点等复杂逻辑。它显式地管理一个全局的状态对象所有节点都读写这个状态。适用场景当你的工作流不仅仅是“思考-行动”循环而是需要多个智能体协作、有严格步骤顺序、包含条件判断或需要持久化中间状态时LangGraph 是更强大的选择。为了更直观地区分可以参考下表特性LangChain (Chain/Agent)LangGraph编排范式线性链或简单循环Agent有向图支持循环、分支、并行状态管理隐式通过输入输出传递显式集中式的State对象复杂度适合中低复杂度、单代理任务适合高复杂度、多代理协作、长工作流控制流有限主要由 LLM 决策驱动完全可编程可以精确控制流程典型用例问答链、简单工具调用Agent多专家协作、审批流程、游戏模拟、复杂决策系统2. 环境准备与项目初始化我们将构建一个融合 RAG 和 Agent 的案例一个“技术文档分析助手”。它能根据用户关于某个技术如“Kubernetes”的问题先通过 RAG 从本地文档库检索相关信息再根据问题复杂度决定是直接回答还是需要调用代码解释工具或网络搜索工具进一步处理。2.1 环境与依赖配置首先确保你的 Python 环境建议 3.10并安装核心库。我们将使用 OpenAI 的 GPT 模型作为 LLM 核心Chroma 作为向量数据库LangChain 和 LangGraph 作为框架。# 创建并进入项目目录 mkdir tech_doc_agent cd tech_doc_agent python -m venv venv # Windows: venv\Scripts\activate # Linux/Mac: source venv/bin/activate # 安装核心依赖 pip install langchain langchain-openai langchain-chroma langgraph # 安装文档加载和文本分割工具 pip install pypdf tiktoken # 安装用于网页搜索的工具示例使用 Tavily需注册获取API Key pip install langchain-tavily注意langchain-openai和langchain-chroma是 LangChain 官方维护的集成包替代了旧版langchain包中对应的部分依赖管理更清晰。2.2 密钥与配置管理在项目根目录创建.env文件来管理敏感信息永远不要将密钥硬编码在代码中。# .env OPENAI_API_KEYsk-your-openai-api-key-here TAVILY_API_KEYyour-tavily-api-key-here然后在代码中通过dotenv加载。同时我们创建一个config.py文件来集中管理配置。# config.py import os from dotenv import load_dotenv load_dotenv() # 加载 .env 文件中的环境变量 class Config: OPENAI_API_KEY os.getenv(OPENAI_API_KEY) TAVILY_API_KEY os.getenv(TAVILY_API_KEY) # 向量数据库持久化路径 PERSIST_DIRECTORY ./chroma_db # 使用的嵌入模型 EMBEDDING_MODEL text-embedding-3-small # 使用的LLM模型 LLM_MODEL gpt-4o-mini # 或 gpt-4-turbo根据实际情况选择 # 快速检查关键配置是否已加载 if not Config.OPENAI_API_KEY: raise ValueError(请在 .env 文件中设置 OPENAI_API_KEY)3. 构建 RAG 知识库子系统在智能体工作流中RAG 将作为第一个关键节点负责提供精准的领域知识上下文。3.1 文档加载与处理假设我们有一个docs/文件夹里面存放了若干 PDF 格式的技术文档。我们编写一个函数来加载并处理它们。# rag_core.py from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings from langchain_chroma import Chroma from config import Config import os def create_vector_store_from_docs(docs_dir: str ./docs): 从指定目录加载PDF文档分割文本创建向量存储。 documents [] for filename in os.listdir(docs_dir): if filename.endswith(.pdf): file_path os.path.join(docs_dir, filename) print(f正在加载: {file_path}) loader PyPDFLoader(file_path) docs loader.load() documents.extend(docs) if not documents: raise ValueError(f在 {docs_dir} 目录下未找到PDF文档。) # 文本分割将长文档切分为适合检索的片段 text_splitter RecursiveCharacterTextSplitter( chunk_size1000, # 每个片段约1000字符 chunk_overlap200, # 片段间重叠200字符保持上下文连贯 separators[\n\n, \n, 。, , , , , , ] ) splits text_splitter.split_documents(documents) print(f共加载 {len(documents)} 个文档分割为 {len(splits)} 个文本块。) # 初始化嵌入模型 embeddings OpenAIEmbeddings( modelConfig.EMBEDDING_MODEL, api_keyConfig.OPENAI_API_KEY ) # 创建并持久化向量数据库 vectorstore Chroma.from_documents( documentssplits, embeddingembeddings, persist_directoryConfig.PERSIST_DIRECTORY ) print(f向量数据库已创建并保存至: {Config.PERSIST_DIRECTORY}) return vectorstore # 如果首次运行执行此函数来构建知识库 # vectorstore create_vector_store_from_docs()3.2 构建检索器知识库构建好后我们需要一个检索器来查询它。为了提高检索质量我们可以使用“重排序”技术。# rag_core.py (续) from langchain.retrievers import ContextualCompressionRetriever from langchain.retrievers.document_compressors import LLMChainExtractor from langchain_openai import ChatOpenAI def get_enhanced_retriever(vectorstore): 创建一个带重排序功能的增强检索器。 先进行向量相似度检索再用LLM对结果进行精炼和重排。 # 基础向量检索器 base_retriever vectorstore.as_retriever( search_typesimilarity, search_kwargs{k: 10} # 初步检索10个片段 ) # 使用LLM对检索结果进行压缩和重排序可选提升精度但增加延迟和成本 llm ChatOpenAI( modelConfig.LLM_MODEL, api_keyConfig.OPENAI_API_KEY, temperature0 ) compressor LLMChainExtractor.from_llm(llm) # 组合成压缩检索器 compression_retriever ContextualCompressionRetriever( base_compressorcompressor, base_retrieverbase_retriever ) return compression_retriever # 后续使用加载已存在的向量数据库并获取检索器 def load_existing_retriever(): embeddings OpenAIEmbeddings( modelConfig.EMBEDDING_MODEL, api_keyConfig.OPENAI_API_KEY ) vectorstore Chroma( persist_directoryConfig.PERSIST_DIRECTORY, embedding_functionembeddings ) # 为了演示这里先使用基础检索器生产环境可考虑增强版 retriever vectorstore.as_retriever(search_kwargs{k: 5}) return retriever4. 定义智能体工具与 LangGraph 状态我们的智能体需要多种工具。我们将使用 LangGraph 来编排一个包含 RAG 检索节点和工具调用决策节点的工作流。4.1 定义工具我们定义三个工具1. RAG 检索工具核心2. 代码解释工具3. 网络搜索工具。# agent_tools.py from langchain.tools import tool from langchain_community.tools.tavily_search import TavilySearchResults from langchain_openai import ChatOpenAI from config import Config from rag_core import load_existing_retriever import json # 工具1: RAG检索工具 tool def retrieve_tech_docs(query: str) - str: 从内部技术文档库中检索与问题最相关的信息。 当用户询问特定技术细节、概念或内部知识时使用此工具。 retriever load_existing_retriever() docs retriever.invoke(query) # 将检索到的文档内容拼接成字符串 context \n\n---\n\n.join([doc.page_content for doc in docs]) return f从知识库中检索到以下相关信息\n\n{context} # 工具2: 代码解释工具模拟 tool def explain_code(code_snippet: str) - str: 解释一段代码的功能、逻辑或潜在问题。 输入应是一段清晰的代码字符串。 llm ChatOpenAI(modelConfig.LLM_MODEL, api_keyConfig.OPENAI_API_KEY) prompt f请解释以下代码 {code_snippet} 请分点说明其主要功能、关键步骤和可能的注意事项。 response llm.invoke(prompt) return response.content # 工具3: 网络搜索工具需要TAVILY_API_KEY def get_web_search_tool(): return TavilySearchResults( api_keyConfig.TAVILY_API_KEY, max_results3, # 控制搜索结果数量 search_depthadvanced ) # 将所有工具打包成一个列表 def get_all_tools(): tools [retrieve_tech_docs, explain_code] if Config.TAVILY_API_KEY: tools.append(get_web_search_tool()) else: print(警告未配置 TAVILY_API_KEY网络搜索工具不可用。) return tools4.2 定义 LangGraph 状态LangGraph 的核心是状态管理。我们定义一个状态类描述在整个工作流中传递的数据结构。# graph_state.py from typing import TypedDict, List, Annotated import operator class GraphState(TypedDict): 定义LangGraph工作流的状态。 # 用户原始问题 question: str # 从知识库检索到的上下文 context: str # 模型生成的初步分析或答案草稿 generation: str # 工作流执行步骤的历史记录用于调试 steps: Annotated[List[str], operator.add] # 标志位指示下一步应该进入哪个节点 next_step: str关键字段说明question: 用户输入贯穿始终。context: 由retrieve_tech_docs工具填充作为生成答案的依据。generation: 存储LLM的最终输出。steps: 一个列表自动累积每个节点执行后的描述方便追踪流程。next_step: 控制流的关键。节点可以根据逻辑设置这个值决定工作流下一步走向哪个节点。5. 构建 LangGraph 工作流我们将工作流设计为三个主要节点1. 检索节点2. 决策节点3. 生成节点。此外还需要一个路由逻辑来控制流程。5.1 实现各个节点函数每个节点都是一个函数接收当前state修改后返回新的state。# workflow_nodes.py from langchain_openai import ChatOpenAI from config import Config from graph_state import GraphState from agent_tools import get_all_tools from langchain.agents import create_react_agent, AgentExecutor from langchain import hub def retrieve_node(state: GraphState) - GraphState: 节点1检索节点。调用RAG工具获取相关知识。 print(---进入检索节点---) question state[question] tools get_all_tools() # 这里我们直接调用之前定义的RAG工具 rag_tool [t for t in tools if t.name retrieve_tech_docs][0] context rag_tool.invoke({query: question}) # 更新状态 state[context] context state[steps].append(f已从知识库检索到相关信息。) # 检索完成后进入决策节点 state[next_step] decision return state def decision_node(state: GraphState) - GraphState: 节点2决策节点。分析问题和已有上下文决定下一步行动。 print(---进入决策节点---) question state[question] context state[context] llm ChatOpenAI(modelConfig.LLM_MODEL, api_keyConfig.OPENAI_API_KEY, temperature0) # 构建决策Prompt decision_prompt f 你是一个工作流调度器。请根据用户问题和已检索到的上下文决定下一步操作。 用户问题{question} 已检索到的上下文{context[:1000]}... # 截断部分上下文 请从以下选项中选择唯一一个下一步动作 A) 【直接回答】如果上下文已足够清晰、完整地回答用户问题。 B) 【需要代码解释】如果用户问题涉及代码理解或上下文中有需要解释的代码片段。 C) 【需要网络搜索】如果上下文信息不足、过时或问题涉及最新动态、外部事件。 D) 【无法回答】如果上下文完全不相关且问题超出能力范围。 只输出选项字母不要有任何其他解释。 decision llm.invoke(decision_prompt).content.strip() state[steps].append(f决策节点分析结果选择 [{decision}]) # 根据决策结果设置下一步路由 if decision A: state[next_step] generate elif decision B: state[next_step] code_agent elif decision C: state[next_step] web_agent else: state[next_step] end # 无法回答结束流程 return state def generate_node(state: GraphState) - GraphState: 节点3生成节点。基于检索到的上下文生成最终答案。 print(---进入生成节点---) question state[question] context state[context] llm ChatOpenAI(modelConfig.LLM_MODEL, api_keyConfig.OPENAI_API_KEY) generation_prompt f 请基于以下提供的上下文信息专业、准确地回答用户问题。 如果上下文信息不足以完全回答问题请基于已知信息回答并说明局限性。 不要提及“根据上下文”这类字眼将信息自然整合到答案中。 上下文信息 {context} 用户问题{question} 最终答案 answer llm.invoke(generation_prompt) state[generation] answer.content state[steps].append(已基于上下文生成最终答案。) state[next_step] end return state5.2 实现工具调用节点Agent节点决策节点可能将工作流导向两个 Agent 节点代码解释 Agent 或网络搜索 Agent。这里我们实现代码解释 Agent 节点。# workflow_nodes.py (续) def code_agent_node(state: GraphState) - GraphState: 节点4代码解释Agent节点。使用ReAct模式调用解释代码的工具。 print(---进入代码解释Agent节点---) question state[question] context state[context] llm ChatOpenAI(modelConfig.LLM_MODEL, api_keyConfig.OPENAI_API_KEY, temperature0) tools get_all_tools() # 获取特定的代码解释工具 code_tool [t for t in tools if t.name explain_code][0] # 使用LangChain的ReAct Agent模式 prompt hub.pull(hwchase17/react) # 一个标准的ReAct提示模板 agent create_react_agent(llm, [code_tool], prompt) agent_executor AgentExecutor(agentagent, tools[code_tool], verboseTrue) # 将用户问题和上下文结合作为Agent的输入 agent_input f 用户原始问题{question} 相关技术背景供参考{context[:500]} 请专注于解释或分析与问题相关的代码部分。 # 执行Agent result agent_executor.invoke({input: agent_input}) state[generation] result[output] state[steps].append(代码解释Agent已完成工作。) state[next_step] end return state # 类似地可以实现 web_agent_node使用网络搜索工具。 # 为了简化示例我们用一个占位函数。 def web_agent_node(state: GraphState) - GraphState: print(---进入网络搜索Agent节点示例---) state[generation] 此处应调用网络搜索工具获取最新信息并整合回答 state[steps].append(网络搜索Agent节点被触发。) state[next_step] end return state def end_node(state: GraphState) - GraphState: 终点节点。 print(---工作流结束---) return state5.3 组合成完整工作流图现在我们将所有节点和路由逻辑组合起来。# build_graph.py from langgraph.graph import StateGraph, END from workflow_nodes import * from graph_state import GraphState def create_workflow_graph(): # 1. 创建状态图 workflow StateGraph(GraphState) # 2. 添加节点 workflow.add_node(retrieve, retrieve_node) workflow.add_node(decision, decision_node) workflow.add_node(generate, generate_node) workflow.add_node(code_agent, code_agent_node) workflow.add_node(web_agent, web_agent_node) workflow.add_node(end, end_node) # 3. 设置入口点 workflow.set_entry_point(retrieve) # 4. 定义边路由逻辑 # 从检索节点到决策节点 workflow.add_edge(retrieve, decision) # 从决策节点到不同分支 workflow.add_conditional_edges( decision, # 路由函数根据 state[“next_step”] 决定下一个节点 lambda state: state[next_step], { generate: generate, code_agent: code_agent, web_agent: web_agent, end: end } ) # 从生成节点、Agent节点到结束节点 workflow.add_edge(generate, end) workflow.add_edge(code_agent, end) workflow.add_edge(web_agent, end) # 5. 编译图 app workflow.compile() return app # 创建图应用实例 graph_app create_workflow_graph()6. 运行验证与结果分析现在我们可以运行这个集成了 RAG 和 Agent 的智能工作流了。6.1 编写主程序并测试# main.py from build_graph import graph_app from graph_state import GraphState def run_agent(question: str): 运行智能体工作流处理用户问题。 # 初始化状态 initial_state: GraphState { question: question, context: , generation: , steps: [], next_step: retrieve # 初始指向检索节点 } print(f\n{*50}) print(f处理问题: {question}) print(f{*50}) # 执行图 final_state graph_app.invoke(initial_state) print(f\n{*50}) print(工作流执行步骤:) for i, step in enumerate(final_state[steps], 1): print(f{i}. {step}) print(f{*50}) print(\n最终答案) print(final_state[generation]) print(f{*50}) return final_state if __name__ __main__: # 测试用例 test_questions [ Kubernetes中的Deployment和StatefulSet有什么区别, # 应触发 RAG - 决策A - 生成 请解释这段YAML配置apiVersion: apps/v1\nkind: Deployment, # 应触发 RAG - 决策B - 代码Agent 最近Kubernetes 1.30版本有什么新特性, # 应触发 RAG - 决策C - 网络Agent (如果配置了) 如何做一道红烧肉, # 可能触发 RAG - 决策D - 结束 ] for q in test_questions[:1]: # 先测试第一个问题 run_agent(q) input(\n按Enter键继续下一个问题...)6.2 预期输出与流程解析运行python main.py对于第一个测试问题你可能会看到类似以下的输出具体内容取决于你的知识库 处理问题: Kubernetes中的Deployment和StatefulSet有什么区别 ---进入检索节点--- ---进入决策节点--- ---进入生成节点--- 工作流执行步骤: 1. 已从知识库检索到相关信息。 2. 决策节点分析结果选择 [A] 3. 已基于上下文生成最终答案。 最终答案 Deployment 和 StatefulSet 都是 Kubernetes 中用于部署和管理 Pod 的工作负载资源但设计目标不同。 1. **Deployment**适用于无状态应用。它确保指定数量的 Pod 副本持续运行并支持滚动更新和回滚。Pod 名称是随机的没有持久化存储标识关联可以随意创建和销毁。 2. **StatefulSet**适用于有状态应用如数据库。它为每个 Pod 提供唯一、稳定的网络标识符主机名和持久化存储卷。Pod 是按顺序创建、更新和删除的保证了拓扑状态和存储状态的稳定性。 简单来说如果你的应用需要稳定的网络标识、有序部署或持久化存储用 StatefulSet否则用 Deployment 更简单高效。 流程解析检索节点将问题转换为向量在 Chroma 数据库中搜索关于 Kubernetes Deployment 和 StatefulSet 的文档片段并将结果存入state[“context”]。决策节点LLM 判断检索到的上下文足够回答问题因此设置next_step为”generate”。生成节点LLM 结合上下文和问题生成结构化的最终答案。结束工作流完成。7. 常见问题排查与优化实践在实际开发和面试中理解并解决以下问题至关重要。7.1 核心问题排查清单问题现象可能原因检查点与解决方案RAG 检索结果不相关1. 文档分割策略不当块太大/太小。2. 嵌入模型不匹配或质量差。3. 检索参数k设置不当。4. 向量数据库未正确持久化或加载。1. 调整chunk_size和chunk_overlap尝试不同分割器。2. 评估嵌入模型在不同领域的表现考虑微调或更换模型。3. 调整search_kwargs{“k”: n}尝试相似度搜索 (similarity) 或最大边际相关性搜索 (mmr)。4. 检查persist_directory路径确认from_documents和Chroma()加载使用的是同一路径。Agent 陷入循环或调用错误工具1. Prompt 指令不清晰导致 LLM 无法正确决策。2. 工具描述不够准确。3. ReAct Agent 的max_iterations设置过小或过大。1. 在决策节点的 Prompt 中明确选项和输出格式限制如“只输出字母”。2. 完善工具函数的docstring这是 LLM 理解工具用途的主要依据。3. 在AgentExecutor中设置max_iterations10,handle_parsing_errorsTrue来限制循环并处理解析错误。LangGraph 工作流状态混乱1. 状态 (State) 结构定义不清晰节点间读写冲突。2. 条件边 (conditional_edges) 的路由函数逻辑有误。3. 节点函数修改了不应修改的状态字段。1. 使用TypedDict明确定义状态结构。使用Annotated标注列表的合并方式如operator.add。2. 在路由函数中打印state[“next_step”]的值进行调试。3. 确保每个节点只修改它应该负责的字段遵循单一职责原则。整体响应速度慢1. LLM API 调用延迟。2. RAG 检索阶段处理大量文档。3. 工作流节点串行过多。1. 考虑使用更快的模型如gpt-4o-mini或引入缓存机制。2. 对知识库建立更高效的索引如 HNSW或进行预过滤。3. 分析工作流将无依赖的节点改为并行执行LangGraph 支持。生成答案出现幻觉1. RAG 检索到的上下文本身有误或不足。2. LLM 在生成时忽略了上下文。3. Prompt 未强制模型基于上下文回答。1. 确保知识库文档质量。增加检索数量k或使用重排序技术。2. 在生成节点的 Prompt 中使用强指令如“必须基于以下上下文回答如果上下文没有提到请明确说‘根据已有信息无法回答’。”3. 在最终答案后要求模型引用来源片段。7.2 生产环境最佳实践配置管理永远使用环境变量或配置中心管理 API Key、模型参数、数据库连接等敏感信息。.env文件仅用于开发。错误处理与重试在所有外部调用LLM API、工具调用、数据库查询周围添加健壮的错误处理、重试逻辑和超时设置。LangChain 提供了retry装饰器和tenacity库集成。日志与监控为每个节点和工作流执行记录详细的日志包括输入、输出、耗时和错误。将state[“steps”]列表的内容持久化便于事后分析和调试。集成像 Prometheus、LangSmith 这样的监控工具。性能优化缓存对频繁相同的检索查询或 LLM 提示词结果进行缓存。异步对于 I/O 密集型操作如多个并行的工具调用使用 LangChain 的异步接口。流式输出对于生成节点考虑使用 LLM 的流式响应以提升用户体验。评估与迭代建立评估体系使用准确率、相关性、幻觉率等指标评估 RAG 和 Agent 的效果。定期用新数据更新知识库并优化 Prompt 和工具设计。8. 扩展方向与面试思考掌握以上基础后你可以从以下几个方向深化这些也是高级面试中常探讨的话题更复杂的 Agent 架构实现ReAct、Plan-and-Execute、Multi-Agent Collaboration等模式。研究 AutoGen、CrewAI 等多智能体框架。RAG 高级技巧查询转换在检索前对用户问题进行重写、扩展或分解。混合检索结合向量搜索和关键词搜索如 BM25。Reranking使用更精细的交叉编码器模型对初步检索结果进行重排序。图数据库增强将知识存入图数据库利用关系进行检索。LangGraph 高级特性人工介入节点在关键决策点引入人工审核。子图将复杂节点封装为可复用的子工作流。持久化检查点保存工作流状态支持从断点恢复。模型微调针对特定领域任务微调嵌入模型或小语言模型以提升检索和生成质量。工程化与部署将整个系统容器化使用 FastAPI 或 Gradio 提供 API 或 Web 界面并考虑负载均衡和弹性伸缩。在面试中当被问到“LangChain 和 LangGraph 区别”时你可以结合本项目的架构回答LangChain 提供了构建 Agent 所需的工具、链和记忆等基础组件而 LangGraph 则是在此之上当你需要编排一个包含复杂状态流转、多角色协作、条件分支和循环的确定性工作流时的更优选择。我们的“技术文档分析助手”就利用 LangGraph 清晰地定义了“检索 - 决策 - (生成/代码解释/搜索) - 结束”这一可控流程这是单纯使用 LangChain Agent 难以优雅实现的。