公司动态

LangChain实战指南:从零构建RAG与智能体应用

📅 2026/8/11 9:42:52
LangChain实战指南:从零构建RAG与智能体应用
1. 项目概述为什么我们需要LangChain如果你最近在捣鼓AI应用开发尤其是想用上那些强大的大语言模型LLM那你大概率听过“LangChain”这个名字。它就像一个“胶水”或者“脚手架”把大模型、你的数据、各种工具和外部系统粘合在一起让你能快速构建出功能复杂的AI应用。简单来说LangChain解决的核心痛点是大模型本身很强大但它是个“黑盒”不知道怎么直接读取你的数据库、调用你的API、或者处理你的一大堆文档。你需要一个框架来编排这些流程而LangChain就是目前最流行的选择之一。我刚开始接触时觉得直接调用OpenAI的API不就完了但当你真的想做一个能回答你公司内部知识库问题的聊天机器人或者一个能自动分析报表并生成总结的智能助手时你会发现事情远没那么简单。你需要处理文档加载、文本分割、向量化存储、检索、对话历史管理、工具调用等一系列繁琐的步骤。LangChain把这些都模块化了提供了标准化的组件和清晰的抽象让你能像搭积木一样构建应用而不是从零开始造轮子。这对于开发者尤其是那些希望快速验证想法、构建原型的团队来说价值巨大。2. LangChain核心架构与核心组件拆解理解LangChain首先要理解它的几个核心抽象。它不是一个大而全的单一工具而是一个由多个松散耦合的组件构成的生态系统。2.1 核心六边形Model I/O, Retrieval, Chains, Agents, Memory, CallbacksLangChain的官方文档将核心概念分为六大块这构成了其基本架构。Model I/O这是最基础的一层负责与大模型对话。它抽象了不同模型提供商如OpenAI、Anthropic、本地部署的Llama等的接口差异。你通过PromptTemplate来构造输入提示词通过LLM或ChatModel对象来调用模型然后得到一个结构化的输出LLMResult。这里的核心是“标准化”让你换模型时只需改一行配置代码。Retrieval检索这是实现“基于知识的问答”或RAG检索增强生成的核心。它处理从外部数据源获取相关信息并注入给大模型的整个过程。流程通常是加载文档 - 文本分割成块 - 将文本块转换为向量嵌入 - 存入向量数据库 - 用户提问时将问题也转换为向量在向量库中搜索最相关的文本块 - 将这些文本块作为上下文和问题一起送给模型。LangChain提供了数十种文档加载器DocumentLoader、文本分割器TextSplitter、向量存储VectorStore和检索器Retriever你可以灵活组合。Chains链这是LangChain的灵魂。链将多个组件或多个其他链按顺序组合在一起形成一个完整的处理流程。最简单的链是LLMChain它组合了一个提示词模板和一个LLM。但链的强大之处在于可以构建复杂的、有分支的逻辑比如SequentialChain顺序链、RouterChain路由链。你可以把一个链想象成一个函数它接收输入经过一系列处理可能调用LLM、检索数据、处理文本最后产生输出。Agents智能体这是让AI应用变得“智能”和“主动”的关键。智能体的核心思想是赋予大模型使用工具Tools的能力。你给智能体一套工具比如搜索网络、查询数据库、执行计算和一个目标智能体中的“大脑”通常是LLM会自主决定下一步该做什么、使用哪个工具、如何解析工具的返回结果并最终达成目标。这突破了单一问答的模式能够处理需要多步骤推理和外部交互的复杂任务。Memory记忆为了让对话或交互具有连续性你需要记忆。LangChain提供了多种记忆组件从简单的缓存上一次对话的ConversationBufferMemory到只保留关键实体信息的ConversationEntityMemory再到能总结历史对话的ConversationSummaryMemory。记忆本质上是在链或智能体的多次调用之间持久化和管理状态信息。Callbacks回调这提供了在链执行过程中插入自定义逻辑的钩子用于日志记录、监控、流式传输输出等。对于生产环境的应用调试和性能观测至关重要。2.2 新星LangGraph 与 LangChain 的区别这是最近社区讨论的热点。简单来说LangChain 是用于构建链Chains和智能体Agents的框架而 LangGraph 是用于构建有状态、多参与者工作流的框架。你可以把传统的LangChain链看作是一个线性的、确定性的流程虽然也可以有分支。而LangGraph引入了“图”的概念节点Node可以是任何函数或LangChain可运行对象边Edge定义了节点之间的流转条件。这特别适合构建复杂的、有循环的、需要协调多个“参与者”可以是不同的LLM、工具、甚至人工审核节点的智能体应用。例如一个研究型智能体的工作流可能是先让一个“规划”节点LLM制定研究大纲然后让一个“搜索”节点调用工具搜集资料再让一个“写作”节点根据资料起草报告最后让一个“评审”节点检查报告质量如果质量不合格则循环回“写作”或“搜索”节点。这种带循环和条件判断的复杂流程用传统的链式结构会非常别扭而用LangGraph的图结构来描述就非常直观和强大。所以LangGraph不是替代LangChain而是它的一个超集或高级扩展。对于大多数简单的线性任务用LangChain的Chain就够了。当你需要构建具有复杂状态和循环逻辑的、更强大的智能体系统时LangGraph是更合适的选择。很多新的高级Agent框架如CrewAI底层也借鉴或集成了图的思想。3. 从零开始手动配置并调用你的第一个大模型理论说了这么多我们直接上手。这里我以使用OpenAI的GPT模型为例但流程对于配置其他模型如通过Ollama本地运行的Llama是类似的。3.1 环境准备与安装首先确保你有一个Python环境建议3.8以上。创建一个新的虚拟环境是个好习惯。# 创建虚拟环境可选 python -m venv langchain-env source langchain-env/bin/activate # Linux/Mac # langchain-env\Scripts\activate # Windows # 安装LangChain核心包和OpenAI SDK pip install langchain langchain-openailangchain是核心框架langchain-openai是LangChain官方维护的OpenAI集成包它包含了调用GPT模型所需的所有组件。注意现在官方推荐使用这种按提供商拆分的包如langchain-anthropic,langchain-community而不是一个庞大的langchain包包含所有集成。3.2 配置模型与发起第一次对话你需要一个OpenAI的API密钥。获取后不要硬编码在代码里最好设置为环境变量。# 在终端中设置环境变量 export OPENAI_API_KEYyour-api-key-here然后编写你的第一个脚本# 导入必要的模块 from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser # 1. 创建模型实例 # model_name可以是 gpt-4, gpt-3.5-turbo 等 # temperature控制创造性0.0更确定1.0更随机 llm ChatOpenAI(modelgpt-3.5-turbo, temperature0.7) # 2. 创建提示词模板 prompt_template ChatPromptTemplate.from_messages([ (system, 你是一个乐于助人的助手擅长用简洁易懂的方式回答问题。), (user, {input}) ]) # 3. 创建输出解析器这里简单地将输出转为字符串 output_parser StrOutputParser() # 4. 组合成链 chain prompt_template | llm | output_parser # 5. 调用链 response chain.invoke({input: 请用一句话解释什么是机器学习}) print(response)代码解读与注意事项ChatOpenAI 这是用于对话模型如GPT-3.5/4的类。如果你使用纯文本补全模型已较少使用对应的是OpenAI类。temperature参数是关键对于需要确定答案的任务如代码生成、数据提取可以设低0.1-0.3对于创意写作可以设高0.7-0.9。ChatPromptTemplate 这是构建对话式提示词的模板。from_messages方法接受一个消息列表每条消息是一个元组如(“role”, “content”)。这里我们定义了一个系统消息来设定AI的角色一个用户消息模板{input}作为占位符。StrOutputParser 模型返回的是一个复杂的AIMessage对象这个解析器帮我们提取出其中的文本内容。LangChain提供了多种输出解析器用于将模型输出解析为结构化数据如JSON、列表。链的组装 (|操作符) 这是LangChain新版0.1.0推荐的LCELLangChain Expression Language语法。prompt_template | llm | output_parser创建了一个可运行的链它清晰地表示了数据流用户输入 - 填充提示词 - 调用LLM - 解析输出。这比旧版的LLMChain更灵活和直观。invoke方法 这是同步调用链的方法。对于流式响应可以使用stream方法。实操心得一开始你可能会对ChatPromptTemplate和PromptTemplate感到困惑。简单区分ChatPromptTemplate用于对话模型接收消息列表PromptTemplate用于文本补全模型接收单个字符串。现在绝大多数场景都用对话模型所以优先使用ChatPromptTemplate。4. 构建实用链实现一个简单的检索增强生成RAG问答系统单纯调用模型意义有限。我们结合Retrieval构建一个能基于自定义文档回答问题的系统。这里我们用一个文本文件作为知识库。4.1 文档加载、分割与向量化假设我们有一个knowledge.txt文件里面包含一些公司产品介绍。from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter from langchain_openai import OpenAIEmbeddings from langchain_community.vectorstores import Chroma import os # 1. 加载文档 loader TextLoader(./knowledge.txt, encodingutf-8) documents loader.load() # 2. 分割文本 # 大模型有上下文长度限制必须把长文档切分成块。 text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每个块的最大字符数 chunk_overlap50, # 块之间的重叠字符防止上下文断裂 separators[\n\n, \n, 。, , , , , ] # 分割符优先级 ) docs text_splitter.split_documents(documents) print(f原始文档被分割成了 {len(docs)} 个块) # 3. 创建嵌入模型用于将文本转换为向量 embeddings OpenAIEmbeddings(modeltext-embedding-3-small) # 使用OpenAI的嵌入模型 # 4. 创建向量数据库并存储向量 # 这里使用Chroma一个轻量级、易用的向量数据库可以持久化到磁盘。 persist_directory ./chroma_db vectordb Chroma.from_documents( documentsdocs, embeddingembeddings, persist_directorypersist_directory ) vectordb.persist() # 持久化到磁盘 print(向量数据库已创建并持久化。)关键参数解析与避坑指南chunk_size 这是最重要的参数。太小会丢失上下文信息太大会超出模型上下文窗口且检索不精准。一般根据你使用的模型上下文长度和文档特点来定。对于GPT-3.5/4上下文通常4K-128K500-1000是个不错的起点。切记这个大小是字符数不是Token数中文一个汉字通常算1-2个Token需要预留余量。chunk_overlap 重叠是为了避免一个完整的句子或概念被硬生生切成两半导致检索时信息不完整。通常设为chunk_size的10%-20%。嵌入模型OpenAIEmbeddings会产生API调用费用。对于本地或离线应用可以考虑开源的嵌入模型如langchain.embeddings.HuggingFaceEmbeddings但需要自己下载模型并可能有性能损耗。向量数据库选择Chroma适合快速原型开发。生产环境可能会考虑Pinecone云服务、Weaviate开源、Qdrant开源高性能或PGVector基于PostgreSQL。选择时需考虑规模、性能、过滤能力、成本等因素。4.2 构建检索链并提问现在我们已经有了向量知识库可以构建一个完整的问答链了。from langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain from langchain_core.prompts import ChatPromptTemplate # 1. 从磁盘加载已存在的向量数据库 vectordb Chroma( persist_directorypersist_directory, embedding_functionembeddings ) # 2. 创建检索器 retriever vectordb.as_retriever( search_typesimilarity, # 相似度搜索还有 mmr最大边际相关性可兼顾相关性与多样性 search_kwargs{k: 3} # 返回最相关的3个文档块 ) # 3. 创建用于回答的提示词模板 # 注意这里的 context 占位符它将被检索到的文档填充 qa_prompt ChatPromptTemplate.from_template( 请根据以下上下文信息回答问题。如果你不知道答案就老实说不知道不要编造答案。 上下文信息 {context} 问题{input} 请根据上下文提供答案) # 4. 创建“组合文档”链它负责将检索到的文档和问题组合成最终提示词并调用LLM combine_docs_chain create_stuff_documents_chain(llm, qa_prompt) # 5. 创建最终的检索链它将检索器和组合文档链连接起来 qa_chain create_retrieval_chain(retriever, combine_docs_chain) # 6. 提问 question 你们公司的主打产品是什么有什么特点 result qa_chain.invoke({input: question}) print(问题, question) print(答案, result[answer]) # 你可以查看检索到的源文档 print(\n参考来源) for i, doc in enumerate(result[context]): print(f[片段{i1}]: {doc.page_content[:200]}...) # 打印前200字符这个流程就是RAG的核心用户提问 - 将问题转换为向量 - 在向量库中搜索相似文本块 - 将检索到的文本块作为“上下文”和原始问题一起组装成新的提示词 - 发送给大模型生成答案。实操心得提示词工程是关键。上面qa_prompt中的指令“根据以下上下文信息回答问题...不要编造答案”对于减少模型“幻觉”胡编乱造至关重要。你可以根据任务调整这个系统提示例如“请用中文回答”、“答案请分点列出”等。检索到的文档质量直接决定最终答案的质量如果检索不到相关文档再好的提示词也白搭。5. 进阶实战打造一个能使用工具的智能体Agent让我们创建一个能使用搜索引擎和计算器的智能体让它解决需要实时信息或复杂计算的问题。5.1 定义工具首先我们需要定义智能体可以使用的工具。这里我们用两个模拟工具一个搜索工具一个计算工具。from langchain.agents import tool from langchain.tools import Tool import math # 使用 tool 装饰器定义工具 tool def search_web(query: str) - str: 当需要获取最新的、实时的信息如新闻、天气、股价或未知领域知识时使用此工具进行网络搜索。 # 这里为了演示我们模拟一个搜索结果。 # 实际应用中你可以集成SerpAPI、Google Search API等真实搜索工具。 print(f[模拟搜索] 搜索关键词: {query}) # 模拟返回搜索结果 mock_results { 今天天气: 北京2024年5月15日晴气温18-28摄氏度南风2级。, 苹果股价: 截至美东时间昨日收盘苹果公司(AAPL)股价为182.52美元上涨0.86%。, Python是什么: Python是一种高级、通用、解释型的编程语言以其清晰的语法和代码可读性而闻名。 } return mock_results.get(query, f未找到关于 {query} 的明确信息。) tool def calculator(expression: str) - str: 当需要进行数学计算如算术、平方根、对数时使用此工具。输入应为合法的数学表达式字符串。 print(f[计算器] 计算表达式: {expression}) try: # 警告使用eval有安全风险仅用于演示。生产环境应用用ast.literal_eval或专用数学库。 # 这里进行安全限制仅允许数学表达式中的常见字符 allowed_chars set(0123456789-*/(). sqrt log pi e ) if not all(c in allowed_chars for c in expression): return 错误表达式包含不安全字符。 # 替换一些数学常量 expression expression.replace(pi, str(math.pi)).replace(e, str(math.e)) # 简单处理sqrt函数 if sqrt in expression: import re def sqrt_eval(match): return str(math.sqrt(float(match.group(1)))) expression re.sub(rsqrt\(([^)])\), sqrt_eval, expression) result eval(expression, {__builtins__: {}}, math.__dict__) return str(result) except Exception as e: return f计算错误: {e} # 将工具放入列表供智能体使用 tools [search_web, calculator]工具定义要点tool装饰器 这是定义LangChain工具最简洁的方式。它会自动根据函数名、参数和文档字符串来生成工具的描述。文档字符串Docstring极其重要智能体中的LLM就是靠这个描述来决定在什么情况下使用哪个工具。描述要清晰、具体说明工具的用途和适用场景。输入输出 工具函数通常接收字符串输入返回字符串输出。这符合LLM处理文本的特性。5.2 创建智能体并运行我们将使用OpenAI的函数调用Function Calling能力来创建智能体这是目前最稳定和高效的方式。from langchain_openai import ChatOpenAI from langchain.agents import create_openai_functions_agent, AgentExecutor from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder # 1. 创建更强大的模型建议使用GPT-4或最新版GPT-3.5-turbo它们对函数调用支持更好 agent_llm ChatOpenAI(modelgpt-3.5-turbo-1106, temperature0) # temperature设为0使决策更稳定 # 2. 创建智能体提示词 # 提示词需要定义角色、目标并预留对话历史和代理思考过程的位置。 prompt ChatPromptTemplate.from_messages([ (system, 你是一个强大的助手可以调用工具来回答问题。请严格按照以下规则行事\n 1. 对于需要最新信息或未知知识的问题使用搜索工具。\n 2. 对于数学计算问题使用计算器工具。\n 3. 在给出最终答案前你必须先调用工具获取必要信息。\n 4. 每次只调用一个最必要的工具。根据工具返回结果再决定下一步。\n 5. 最终答案应清晰、完整并引用工具获取的信息。), MessagesPlaceholder(variable_namechat_history), # 预留历史消息位置 (user, {input}), MessagesPlaceholder(variable_nameagent_scratchpad), # 预留代理思考过程位置 ]) # 3. 创建智能体 agent create_openai_functions_agent(llmagent_llm, toolstools, promptprompt) # 4. 创建代理执行器负责运行智能体管理工具调用循环 agent_executor AgentExecutor( agentagent, toolstools, verboseTrue, # 开启详细日志可以看到智能体的思考过程和工具调用 handle_parsing_errorsTrue, # 处理解析错误避免因格式问题崩溃 max_iterations5, # 限制最大迭代次数防止死循环 early_stopping_methodgenerate # 当智能体认为可以给出最终答案时停止 ) # 5. 运行智能体 result agent_executor.invoke({ input: 请先搜索一下北京今天的天气然后计算一下如果气温从中午的28度下降到晚上的18度温差是多少 }) print(\n--- 最终答案 ---) print(result[output])运行过程解析当verboseTrue时你会看到类似下面的输出这揭示了智能体的内部工作流程 Entering new AgentExecutor chain... 思考用户问了两个问题1. 北京今天的天气2. 计算温差。我需要先获取天气信息然后提取温度进行计算。 行动调用 search_web 工具。 行动输入{query: 北京今天天气} 观察[模拟搜索] 搜索关键词: 北京今天天气 观察北京2024年5月15日晴气温18-28摄氏度南风2级。 思考我已经获取了天气信息最高温28度最低温18度。现在需要计算温差。 行动调用 calculator 工具。 行动输入{expression: 28 - 18} 观察[计算器] 计算表达式: 28 - 18 观察10 思考我得到了温差是10度。现在可以结合天气信息给出最终答案。 最终答案根据搜索到的信息北京今天2024年5月15日天气晴朗气温在18到28摄氏度之间。中午最高气温28度晚上最低气温18度两者温差为10摄氏度。 Finished chain. --- 最终答案 --- 根据搜索到的信息北京今天2024年5月15日天气晴朗气温在18到28摄氏度之间。中午最高气温28度晚上最低气温18度两者温差为10摄氏度。避坑指南与高级技巧模型选择 智能体的表现严重依赖底层LLM的推理和规划能力。GPT-4通常比GPT-3.5-turbo表现好得多尤其是在复杂任务中。如果使用开源模型需要确保其经过足够的函数调用/工具使用微调。提示词工程 系统提示词是指引智能体行为的关键。清晰的规则如“每次只调用一个工具”能有效减少智能体的混乱行为。你可以通过反复测试来优化提示词。max_iterations必须设置防止智能体陷入“思考-调用-再思考”的死循环消耗大量Token。handle_parsing_errors 设为True是个好习惯因为模型偶尔会输出不符合工具调用格式的内容导致解析失败。这个参数能让执行器尝试修复或继续。工具设计 工具应尽量单一职责输入输出明确。复杂的工具会让智能体难以正确使用。如果工具返回错误智能体应该能处理并尝试其他方案。6. 生产环境考量部署、监控与成本优化当你开发完一个基于LangChain的应用原型后如何将它变得健壮、可维护并推向生产6.1 应用部署与API服务化LangChain应用本身是Python代码部署方式与其他Python Web应用类似。一个常见的模式是使用FastAPI或Flask将其包装成REST API服务。# 示例使用FastAPI包装之前的RAG问答链 from fastapi import FastAPI, HTTPException from pydantic import BaseModel from langchain_openai import ChatOpenAI, OpenAIEmbeddings from langchain_community.vectorstores import Chroma from langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain from langchain_core.prompts import ChatPromptTemplate app FastAPI(title知识库问答API) # 在启动时加载模型和向量库避免每次请求都加载 embeddings OpenAIEmbeddings() vectordb Chroma(persist_directory./chroma_db, embedding_functionembeddings) retriever vectordb.as_retriever(search_kwargs{k: 3}) llm ChatOpenAI(modelgpt-3.5-turbo, temperature0) qa_prompt ChatPromptTemplate.from_template(...) # 同前的提示词 combine_docs_chain create_stuff_documents_chain(llm, qa_prompt) qa_chain create_retrieval_chain(retriever, combine_docs_chain) class QuestionRequest(BaseModel): question: str class AnswerResponse(BaseModel): answer: str sources: list[str] # 可以返回来源片段 app.post(/ask, response_modelAnswerResponse) async def ask_question(request: QuestionRequest): try: result qa_chain.invoke({input: request.question}) sources [doc.page_content[:500] for doc in result.get(context, [])] return AnswerResponse(answerresult[answer], sourcessources) except Exception as e: raise HTTPException(status_code500, detailf处理问题时出错: {str(e)}) # 使用 uvicorn 运行: uvicorn main:app --host 0.0.0.0 --port 8000部署注意事项资源初始化 像嵌入模型、LLM客户端、向量数据库连接这类重量级对象应该在服务启动时初始化并复用单例而不是在每个请求中创建这能极大提升性能。异步支持 LangChain的很多组件支持异步调用ainvoke,astream。如果你的应用并发量高考虑使用异步框架如FastAPI并调用异步方法可以提高吞吐量。环境变量与配置 API密钥、模型名称等配置项务必通过环境变量或配置文件管理不要写在代码里。容器化 使用Docker容器化你的应用确保环境一致性便于在云服务器或Kubernetes上部署。6.2 监控、日志与可观测性生产系统必须可观测。你需要知道应用是否健康、性能如何、成本多少。LangSmith 这是LangChain官方推出的监控和调试平台。它就像大模型应用的“New Relic”或“Datadog”。你只需要设置一个环境变量它就能自动追踪所有链、智能体、工具调用的详细信息包括输入、输出、耗时、Token使用量、成本等。对于调试复杂链的流程、分析性能瓶颈、审计模型行为至关重要。强烈建议在开发和生产中使用。export LANGCHAIN_TRACING_V2true export LANGCHAIN_API_KEYyour-langsmith-api-key export LANGCHAIN_PROJECTyour-project-name自定义日志 在关键节点如工具调用开始/结束、检索完成、最终答案生成添加结构化日志便于排查问题。性能指标 监控API响应时间、Token消耗速率、向量数据库查询延迟等。设置警报当延迟或错误率超过阈值时通知。6.3 成本优化与性能调优策略大模型API调用是主要成本。以下是一些优化策略缓存 对频繁出现的相同或相似查询的结果进行缓存。LangChain内置了InMemoryCache、RedisCache等。对于检索环节可以考虑缓存嵌入向量的计算结果。优化提示词 精简系统提示词和上下文移除不必要的指令。让模型“少说废话”。控制上下文长度精炼检索结果 不要盲目返回大量文档块。通过search_kwargs控制返回数量(k)或使用MMR搜索在相关性和多样性间取得平衡。摘要长文档 对于检索到的长文档块可以先用一个快速的、便宜的模型如GPT-3.5-turbo对其进行摘要再将摘要作为上下文送入主模型。模型阶梯使用对于简单的分类、提取任务使用小模型或专用模型。对于需要复杂推理、创意生成的任务再使用GPT-4等大模型。这就是所谓的“MoE混合专家”思想在应用层的体现。异步与批处理 如果有多条独立的数据需要处理如批量总结多篇文章可以使用异步调用或将请求批量发送给支持批处理的API以减少网络开销。本地模型部署 对于数据敏感或长期成本考量可以部署开源模型如Llama 3, Qwen, DeepSeek在本地或私有云。使用Ollama、vLLM、TGI等工具可以方便地部署和调用。虽然前期硬件投入大但长期来看可能更经济。你需要权衡开发效率、性能、成本和控制权。7. 常见问题排查与实战心得在开发和运维LangChain应用的过程中我踩过不少坑。这里总结一些典型问题和解决方法。7.1 连接与配置问题问题调用OpenAI API时超时或报错APIConnectionError。排查网络问题 确保你的服务器或本地网络能稳定访问OpenAI的API端点。可以尝试用curl或ping测试连通性。代理配置 如果你在公司网络或需要代理需要在代码中或环境变量里设置。对于openai库可以通过openai.proxy设置或者设置HTTP_PROXY/HTTPS_PROXY环境变量。API密钥与基地 检查OPENAI_API_KEY环境变量是否正确。如果你使用的是Azure OpenAI或其他兼容API需要配置openai.api_base和openai.api_type等参数。在LangChain中创建ChatOpenAI对象时可以通过base_url和api_key参数指定。7.2 模型响应问题问题模型输出不符合预期比如不遵循指令、胡编乱造幻觉。解决检查提示词 这是最常见的原因。确保你的系统提示词清晰、明确地定义了角色和任务约束。对于RAG一定要在提示词中强调“仅根据提供的上下文回答”。调整温度temperature和top_p 对于需要确定答案的任务将temperature调低如0.1。top_p核采样也可以配合调整降低其值会使输出更集中。使用更强大的模型 GPT-3.5-turbo在复杂指令遵循和减少幻觉方面不如GPT-4。如果任务关键升级模型是最直接有效的方法。后处理与验证 对于关键输出可以增加一个验证步骤。例如让另一个LLM或规则系统检查答案是否与提供的上下文矛盾。7.3 检索效果不佳问题RAG系统检索不到相关文档或者检索到的文档不精准。优化文本分割策略 尝试不同的chunk_size和chunk_overlap。对于技术文档按章节或标题分割可能比按固定字符数分割更好。可以尝试MarkdownHeaderTextSplitter。嵌入模型 不同的嵌入模型对语义的理解能力不同。OpenAI的text-embedding-3系列通常效果很好。开源模型如BGE、SentenceTransformers的模型也不错但可能需要针对你的领域微调。检索方法相似度搜索similarity 最常用返回最相似的k个片段。最大边际相关性MMR 在保证相关性的同时增加结果的多样性避免返回内容重复的片段。通过search_type“mmr”和fetch_k参数先获取更多候选再筛选来使用。自查询Self-Query 如果文档有元数据如作者、日期可以让LLM从问题中提取过滤条件再进行向量搜索提高精度。重排序Re-ranking 在向量检索出Top K个结果后使用一个更精细但更慢的交叉编码器模型如bge-reranker对结果进行重新排序将最相关的一两个提到最前面。这是提升RAG效果的高级技巧会牺牲一些速度。7.4 智能体Agent失控问题智能体陷入循环、调用错误工具、或产生无意义动作。调试开启详细日志AgentExecutor(verboseTrue)是第一步观察它的思考过程。简化任务 将复杂任务拆解成子任务分别测试智能体对每个子任务的处理能力。优化工具描述 确保每个工具的文档字符串docstring准确描述了其功能和适用场景。这是LLM选择工具的主要依据。限制迭代次数 务必设置max_iterations如5-10次这是安全绳。使用ReAct模式或更高级的框架 基础的函数调用智能体可能不够稳定。可以尝试使用明确要求模型输出“Thought:”, “Action:”, “Observation:”的ReAct提示模板。对于极其复杂的任务考虑使用LangGraph来构建有明确状态和循环控制的工作流。7.5 性能瓶颈问题应用响应慢。分析** profiling工具** 使用Python的cProfile或py-spy找出耗时最长的函数。主要瓶颈通常在于LLM API调用 网络延迟模型推理时间。考虑使用流式响应stream让用户先看到部分结果或优化提示词减少输出长度。嵌入计算 如果使用本地嵌入模型首次加载和计算可能很慢。可以预计算并存储文档嵌入。向量数据库检索 当向量库非常大时百万级以上检索可能变慢。确保对向量索引做了优化如HNSW并考虑在内存中缓存热门查询。工具调用 如果工具涉及外部API如网络搜索、数据库查询其延迟会直接影响智能体。为工具设置超时并考虑并行调用可能独立的工具。最后保持耐心和实验精神。LangChain生态在快速演进最佳实践也在不断更新。多关注官方文档和社区如GitHub、Discord从简单的链开始逐步构建复杂的应用在过程中持续测试、监控和迭代是掌握这门技术的不二法门。