恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
LangChain实战:从零构建大模型应用,打通工具调用与RAG知识库
首页
资讯中心
/
LangChain实战:从零构建大模型应用,打通工具调用与RAG知识库
LangChain实战:从零构建大模型应用,打通工具调用与RAG知识库
发布时间:2026/8/15 4:56:42
1. 从零到一为什么选择LangChain来“粘合”大模型如果你最近在捣鼓大模型应用尤其是想自己动手搭个能聊、能查、能干的智能机器人大概率会听到一个词LangChain。这玩意儿现在火得不行但第一次接触时我跟你一样懵这到底是个啥为什么大家都不用裸调API非要绕个弯子用它简单说LangChain就是个“胶水”和“脚手架”。想象一下大模型比如GPT、文心一言、通义千问是个超级聪明但有点“生活不能自理”的大脑。你问它“今天天气怎么样”它能给你编一段文采斐然的天气描写但它自己不会去查实时的天气数据。你想让它总结一篇长文档它可能因为文档太长而“消化不良”。你想让它记住之前的对话它转头就忘除非你每次都把历史对话再喂给它。LangChain要解决的就是给这个聪明大脑配上“手”工具调用、“眼睛”文档读取、“耳朵”语音识别和“记忆”对话历史管理。它把调用大模型、处理外部数据、管理对话流程这些脏活累活都封装成了标准化的组件让你能用搭积木的方式快速构建出功能复杂的AI应用而不是每次都从零开始写一堆胶水代码。我选择入坑LangChain核心就图三点标准化、模块化和生态。标准化意味着我不需要为每个不同的大模型APIOpenAI、Anthropic、国内各家写一套不同的调用和解析代码LangChain提供了统一的接口。模块化让我可以像拼乐高一样把“文档加载器”、“文本分割器”、“向量数据库”、“记忆模块”、“智能体Agent”组合起来快速实现一个具备知识库问答RAG或自主执行任务能力的机器人。生态则意味着有大量的社区示例、第三方工具集成如搜索引擎、数据库、各种API踩坑时更容易找到解决方案。当然这条路并不平坦。LangChain更新快、概念多、初期文档对新手不算友好而且由于抽象层次高一旦出问题调试起来就像在多层蛋糕里找一根针。但一旦趟过这些坑你会发现构建AI应用的效率是质的飞跃。下面我就结合自己搭建一个具备简单工具调用能力的对话机器人的全过程把那些让我熬夜的坑和最终跑通的方案掰开揉碎了讲给你听。2. 环境搭建与模型选择第一个坑往往在起点万事开头难搭建LangChain项目的第一个坑可能从你敲下pip install langchain就开始了。现在的LangChain生态已经分化核心库langchain和较新的langchain-core、langchain-community等并存如果你还看到langgraph用于构建有状态的、多步骤的工作流别慌我们先从最基础的开始。2.1 依赖安装别让版本冲突绊住脚我的建议是创建一个干净的Python虚拟环境用venv或conda然后安装一个相对稳定的基础套件。别直接pip install langchain[all]那会引入大量你可能暂时用不上的依赖增加冲突风险。# 创建一个新的虚拟环境可选但强烈推荐 python -m venv langchain-env source langchain-env/bin/activate # Linux/Mac # 或 langchain-env\Scripts\activate # Windows # 安装核心包 pip install langchain langchain-core langchain-community # 安装一个你计划使用的大模型接口包例如OpenAI pip install openai # 或者使用国内兼容OpenAI API的模型例如智谱AI、DeepSeek等通常需要其官方SDK # pip install zhipuai # 智谱GLM # pip install dashscope # 通义千问 # pip install openai # 配置base_url指向本地或兼容API # 安装可能用到的工具例如用于网页搜索的 pip install duckduckgo-search踩坑记录1langchainvslangchain-core新版本中很多核心抽象类如BaseChatModel,BaseRetriever移到了langchain-core而具体的模型实现、工具集成在langchain-community。如果你从一些老教程抄代码发现导入失败比如from langchain.llms import OpenAI报错别急这很可能是因为路径变了。现在更常见的导入方式是from langchain_openai import ChatOpenAI # 对于OpenAI # 或者从community导入其他模型 from langchain_community.llms import Tongyi # 例如通义千问安装时pip install langchain-openai这样的集成包会帮你处理好依赖。总之遇到导入错误第一反应是去查官方文档或包的__init__.py文件看最新的导入路径是什么。2.2 模型选择与配置免费、付费与本地部署的权衡选模型是战略决策直接决定成本、速度和能力。大致有三条路云端付费API如OpenAI GPT-4 Anthropic Claude能力最强效果最稳定但需要付费且有网络限制。配置简单一个API KEY就行。from langchain_openai import ChatOpenAI llm ChatOpenAI(modelgpt-3.5-turbo, api_keyyour-key, base_urlhttps://api.openai.com/v1) # 默认base_url国内云端大模型API如智谱GLM、百度文心、阿里通义合规性好中文优化可能更佳同样需要申请API KEY和付费。配置方式类似但需要安装对应的SDK并查看其LangChain集成文档。from langchain_community.chat_models import ZhipuAI ChatGLM llm ChatGLM(modelglm-4, api_keyyour-zhipu-key)本地部署大模型如通过Ollama、vLLM、FastChat部署数据隐私性最好长期成本可能更低但需要一定的硬件GPU和运维知识。这是当前很多开发者的热点选择。Ollama目前最火的本地大模型运行框架之一拉取、运行模型一条龙对新手友好。# 安装Ollama后拉取一个模型例如Llama 3 ollama pull llama3 # 运行模型服务 ollama run llama3然后在LangChain中将其视为一个兼容OpenAI API的服务进行调用from langchain_openai import ChatOpenAI llm ChatOpenAI(modelllama3, base_urlhttp://localhost:11434/v1, api_keyollama) # ollama的api_key可任意填其他本地API服务如果你用text-generation-webui或自己用FastAPI封装了模型只要它提供了兼容OpenAI的API接口都可以用上述方式连接。踩坑记录2API Base URL 与超时设置调用本地模型或某些国内镜像服务时base_url是关键。一定要确认你的模型服务提供的API端点是否完全兼容OpenAI格式特别是/v1/chat/completions。另一个巨坑是超时。本地模型或网络慢时默认超时时间可能不够导致请求失败但错误信息不明。llm ChatOpenAI( base_urlhttp://localhost:8000/v1, api_keynone, modelyour-local-model-name, timeout60.0, # 将超时时间设为60秒 max_retries2 # 增加重试次数 )踩坑记录3模型上下文长度不同模型支持的上下文长度Token数不同。如果你要做长文档处理RAG务必查清你所用模型的上下文窗口大小如GPT-3.5-turbo是16K一些本地7B模型可能只有4K。在构造提示词或进行文本分割时必须考虑这个限制否则模型会“失忆”或直接报错。3. 构建第一个对话链当简单的调用变得不简单环境好了模型通了兴冲冲地写下了第一行代码让模型做个自我介绍。这看起来是最简单的任务但LangChain的抽象在这里就给了我们一个“下马威”。3.1 理解LCELLangChain表达语言新版的LangChain大力推广LCELLangChain Expression Language。它用|操作符来连接不同的组件使链的构建像写管道一样清晰。但如果你像我一样一开始习惯性地去搜LLMChain的用法可能会发现一些老方法被标记为弃用deprecated。传统方式可能逐步淘汰from langchain.prompts import ChatPromptTemplate from langchain.chains import LLMChain prompt ChatPromptTemplate.from_template(请用{style}的风格介绍一下你自己。) chain LLMChain(llmllm, promptprompt) result chain.run(style幽默) print(result)推荐方式使用LCELfrom langchain_core.prompts import ChatPromptTemplate prompt ChatPromptTemplate.from_template(请用{style}的风格介绍一下你自己。) chain prompt | llm # 核心用 | 连接提示词模板和模型 # 调用链 response chain.invoke({style: 幽默}) print(response.content) # 注意response是一个AIMessage对象内容在.content属性里看起来更简洁了对吧但坑来了chain.invoke()返回的不是一个字符串而是一个AIMessage对象或ChatGeneration等。你需要通过.content属性来获取真正的回复文本。这是LangChain为了统一处理多轮对话、工具调用等复杂消息格式而设计的。3.2 消息历史管理让机器人记住“刚才说了啥”单轮对话太傻我们需要一个能连续聊天的机器人。这就涉及到记忆Memory。LangChain提供了几种记忆后端最简单常用的是ConversationBufferMemory。from langchain.memory import ConversationBufferMemory from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain_core.runnables import RunnablePassthrough # 1. 创建记忆用于存储对话历史 memory ConversationBufferMemory(return_messagesTrue, memory_keychat_history) # return_messagesTrue 确保存储的是消息对象而不是字符串。 # memory_keychat_history 指定在提示词中使用的变量名。 # 2. 构建提示词模板预留一个位置给历史消息 prompt ChatPromptTemplate.from_messages([ (system, 你是一个乐于助人的AI助手。), MessagesPlaceholder(variable_namechat_history), # 历史消息将插入这里 (human, {input}) ]) # 3. 构建链组合记忆加载、提示词和模型 # 这是一个稍复杂的LCEL链需要理解Runnable的概念 from langchain_core.runnables import RunnablePassthrough def load_memory(_): # 从memory中加载历史返回一个字典包含chat_history键 loaded_mem memory.load_memory_variables({}) return loaded_mem chain ( RunnablePassthrough.assign(chat_historyload_memory) # 动态加载历史 | prompt | llm )踩坑记录4记忆的加载与更新上面这个链能加载历史但聊完一句后新的对话内容并没有自动保存到记忆里这是新手最容易忽略的一点。我们需要在得到模型回复后手动将本轮的人类输入和AI输出保存到记忆对象中。# 模拟对话循环 while True: user_input input(你: ) if user_input.lower() exit: break # 调用链传入当前输入 response chain.invoke({input: user_input}) print(fAI: {response.content}) # 关键步骤手动保存本轮对话到记忆 memory.save_context({input: user_input}, {output: response.content}) # 或者如果你使用的是ChatMessageHistory可以用 add_message 方法如果你忘记save_context那么下一轮对话时模型将看不到上一轮的内容记忆功能就形同虚设。更高级的用法是将保存动作也做到链里这就需要用到RunnableLambda或自定义函数对于入门来说先理解这个手动过程至关重要。3.3 流式输出让回复“打字”出来调用大模型尤其是慢模型时干等着全量输出很煎熬。流式输出Streaming能极大提升用户体验。在LangChain中实现流式相对简单。# 配置LLM时开启流式支持如果底层模型支持 llm ChatOpenAI(streamingTrue, ...) # 注意并非所有模型/封装都支持streaming参数 # 使用流式调用 for chunk in chain.stream({input: 讲一个关于人工智能的短故事。}): if hasattr(chunk, content): print(chunk.content, end, flushTrue) # 逐块打印踩坑记录5流式响应格式不统一不同的模型和封装返回的流式chunk格式可能不同。可能是AIMessageChunk对象也可能是字典。你需要打印或调试一下chunk的结构找到包含文本内容的字段。有时内容在chunk.content有时在chunk[‘content’]或chunk.choices[0].delta.content如果直接调用原始API。务必查阅你所使用模型集成的具体文档。4. 赋予机器人“手脚”工具调用与智能体实战只会聊天的机器人是“鹦鹉”能调用工具执行任务的才是“助手”。这就是LangChain的智能体Agent和工具Tool模块大显身手的地方。智能体是一个高级抽象它根据用户指令和可用工具自主决定是直接回答还是调用某个工具或者进行多步推理。4.1 定义你的第一把工具工具本质上是一个函数加上一些描述名字、功能说明让智能体知道它能干什么。我们定义一个最简单的工具计算字符串长度。from langchain.agents import tool from langchain.tools import Tool # 方式一使用tool装饰器推荐简洁 tool def calculate_string_length(text: str) - int: 计算输入字符串的长度。 return len(text) # 方式二使用Tool.from_function手动创建 def get_word_count(text: str) - int: 计算输入字符串的单词数以空格分割。 return len(text.split()) word_count_tool Tool.from_function( funcget_word_count, nameword_counter, description计算一个英文句子中的单词数量。 ) # 将工具放入列表供智能体使用 tools [calculate_string_length, word_count_tool]踩坑记录6工具描述至关重要智能体完全依赖工具的name和description来决定是否以及如何调用它。描述必须清晰、准确。模糊的描述如“处理文本”会导致智能体无法正确理解工具用途要么乱用要么不用。好的描述应像“根据给定的城市名称查询该城市当前的天气情况。”4.2 创建智能体并运行有了工具我们需要一个“大脑”LLM来驱动智能体并选择一个“决策框架”Agent Type。最常用的是OPENAI_FUNCTIONS对应OpenAI的Function Calling能力或REACT_DOCSTORE一种经典的推理行动框架。这里我们使用与OpenAI兼容的模型和框架。from langchain.agents import create_openai_functions_agent, AgentExecutor from langchain import hub # 从LangChain Hub拉取一个预设的提示词包含如何让模型使用工具的指令 # 你也可以自己写但用现成的更稳妥 prompt hub.pull(hwchase17/openai-functions-agent) # 创建智能体它结合了LLM、提示词和工具列表 agent create_openai_functions_agent(llm, tools, prompt) # 创建代理执行器它负责运行智能体处理工具调用循环 agent_executor AgentExecutor(agentagent, toolstools, verboseTrue, handle_parsing_errorsTrue) # verboseTrue 会打印出智能体的思考过程对于调试非常重要 # handle_parsing_errorsTrue 能防止因模型输出格式偶尔解析错误而导致整个程序崩溃。 # 运行智能体 result agent_executor.invoke({input: 先计算‘Hello World’的长度再计算这个句子的单词数。}) print(result[output])当verboseTrue时你会在控制台看到类似这样的输出 Entering new AgentExecutor chain... 我需要先计算字符串“Hello World”的长度然后再计算一个句子的单词数。但用户说的“这个句子”指的是哪个句子可能指的是“Hello World”这个字符串但“Hello World”通常被视为一个短语。为了明确我应该先计算“Hello World”的长度然后计算“Hello World”这个短语的单词数。 Action: calculate_string_length Action Input: {text: Hello World} Observation: 11 Thought: 好的“Hello World”的长度是11。现在我需要计算它的单词数。“Hello World”有两个单词。 Action: word_counter Action Input: {text: Hello World} Observation: 2 Thought: 我现在有了两个结果长度是11单词数是2。我可以给出最终答案了。 Final Answer: 字符串“Hello World”的长度是11它包含2个单词。这个过程清晰地展示了智能体的“思考-行动-观察”循环ReAct模式。踩坑记录7智能体陷入死循环或错误调用这是智能体开发中最常见的问题。原因和解决方案工具描述不清或功能重叠两个工具描述相似智能体困惑。确保每个工具职责单一描述精准。LLM能力不足如果使用的本地小模型逻辑推理能力弱可能无法正确规划步骤。尝试换用更强的模型或简化任务。提示词不佳智能体的表现极度依赖系统提示词。hwchase17/openai-functions-agent是一个很好的起点但如果你的任务特殊可能需要微调提示词明确告诉智能体“在什么情况下使用什么工具”、“不要重复调用同一个工具”等。设置max_iterations防止智能体在一个问题上无限循环。AgentExecutor(max_iterations5)可以强制在5步后停止。善用handle_parsing_errorsTrue模型输出偶尔不符合工具调用的JSON格式这个参数能捕获错误并以自然语言反馈给模型让它重试而不是直接崩溃。4.3 集成真实世界工具以网页搜索为例让我们给机器人装上“搜索引擎”这个更实用的工具。这里以DuckDuckGo搜索为例。pip install duckduckgo-searchfrom langchain_community.tools import DuckDuckGoSearchRun search_tool DuckDuckGoSearchRun() tools.append(search_tool) # 加入到之前的工具列表 # 重新创建智能体和执行器因为工具列表变了 agent create_openai_functions_agent(llm, tools, prompt) agent_executor AgentExecutor(agentagent, toolstools, verboseTrue, handle_parsing_errorsTrue) # 提问一个需要实时信息的问题 result agent_executor.invoke({input: 搜索一下今天北京的最高温度是多少}) print(result[output])这时智能体可能会先调用搜索工具获取包含天气信息的网页摘要然后从中提取温度信息最后组织语言回答你。这个过程完全是自动的。踩坑记录8网络工具的不确定性网络搜索的结果是动态、非结构化的。智能体可能无法从大段文本中精准找到答案或者找到的是过时、错误的信息。这不再是LangChain的坑而是任务本身的不确定性。解决方案包括使用更专用的工具比如专门的天气API返回结构化数据。后处理Post-processing让模型对搜索工具返回的结果进行总结、提炼而不是直接引用。设计更精确的指令例如“请搜索关键词‘北京 今日 最高气温’并从结果中提取数字答案。”5. 连接专属知识库RAG架构初探与避坑指南让机器人回答通用问题很棒但真正的价值在于让它成为你私人文档的专家。这就是检索增强生成RAG的用武之地。其核心流程是文档加载 - 文本分割 - 向量化存储 - 检索 - 增强提示 - 生成答案。LangChain为每一步都提供了丰富的组件。5.1 文档加载与分割细节决定成败假设我们有一个knowledge.txt文件。from langchain_community.document_loaders import TextLoader from langchain_text_splitters import RecursiveCharacterTextSplitter # 1. 加载文档 loader TextLoader(./knowledge.txt) documents loader.load() # 2. 分割文档 text_splitter RecursiveCharacterTextSplitter( chunk_size500, # 每个块的最大字符数 chunk_overlap50, # 块之间的重叠字符数保持上下文连贯 separators[\n\n, \n, 。, , , ] # 分割符优先级 ) docs text_splitter.split_documents(documents) print(f原始文档数{len(documents)} 分割后块数{len(docs)})踩坑记录9分割策略是RAG效果的基石chunk_size太小信息碎片化模型看不到完整上下文回答可能断章取义。chunk_size太大可能超过模型上下文窗口且检索精度下降因为一个块里包含太多不相关信息。chunk_overlap是神器重叠部分能有效防止一个完整的句子或概念被拦腰截断在两个块里。一般设为chunk_size的10%-20%。separators顺序它按顺序尝试分割。把大的分隔符如段落放前面可以优先保证块的结构完整性。对于中文可能需要加入中文标点。5.2 向量化与存储选择你的“记忆宫殿”分割后的文本需要转换成向量Embedding并存入向量数据库以便后续相似度检索。from langchain_community.embeddings import OpenAIEmbeddings # 或用其他Embedding模型 from langchain_community.vectorstores import Chroma # 轻量级向量数据库 # 1. 初始化Embedding模型 embeddings_model OpenAIEmbeddings(api_keyyour_key) # 注意这会产生API调用费用 # 本地替代方案可以使用 sentence-transformers 等开源模型 # from langchain_community.embeddings import HuggingFaceEmbeddings # embeddings_model HuggingFaceEmbeddings(model_nameall-MiniLM-L6-v2) # 2. 创建向量数据库并存储文档 vectorstore Chroma.from_documents( documentsdocs, embeddingembeddings_model, persist_directory./chroma_db # 指定持久化目录 ) # 如果不指定 persist_directory数据仅保存在内存中。 # 3. 将向量库转换为检索器 retriever vectorstore.as_retriever(search_kwargs{k: 3}) # 检索最相似的3个块踩坑记录10Embedding模型的选择与成本云端Embedding API如OpenAI效果好简单但按token收费。如果你有大量文档预处理成本可能很高。本地Embedding模型如Sentence-BERT免费数据隐私好但需要本地计算资源且效果可能略逊于顶级云端模型。对于中文可以选择text2vec、m3e等优秀的中文Embedding模型。关键原则检索用的Embedding模型和生成答案的大模型最好在语义空间上对齐。用OpenAI的Embedding配GPT或用同一个开源模型家族的Embedder和LLM效果通常更稳定。5.3 构建RAG链从检索到生成现在我们将检索器集成到对话链中。from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import RunnablePassthrough from langchain_core.output_parsers import StrOutputParser # 1. 定义提示词模板其中{context}将替换为检索到的文档 template 你是一个专业的知识库助手。请严格根据以下上下文来回答问题。如果上下文没有提供足够信息请直接说“根据已知信息无法回答该问题”不要编造信息。 上下文 {context} 问题{question} 请用中文给出有帮助的答案 prompt ChatPromptTemplate.from_template(template) # 2. 构建RAG链 rag_chain ( {context: retriever, question: RunnablePassthrough()} # retriever自动获取context | prompt | llm | StrOutputParser() # 将AIMessage对象解析为字符串 ) # 3. 提问 question 我的知识库里提到了哪些关键项目 answer rag_chain.invoke(question) print(answer)踩坑记录11“幻觉”与上下文管理即使提供了上下文大模型依然可能“幻觉”胡编乱造出不存在于上下文中的内容。为了缓解提示词工程在提示词中强烈约束如“严格根据上下文”、“不要编造”、“无法回答请直接说明”。检索质量如果检索到的context不相关模型再厉害也没用。优化检索器如调整search_kwargs使用MMR搜索多样性排序是关键。引用溯源更高级的做法是让模型在回答中注明引用的来源块这需要更复杂的链设计。踩坑记录12检索器返回格式retriever返回的是一个Document对象的列表。在LCEL链中我们直接用{context: retriever, ...}LangChain会自动将多个Document的内容合并成一个字符串用分隔符如“\n\n”连接然后填入提示词的{context}占位符。如果你需要自定义连接方式可以写一个函数来处理retriever的输出。6. 部署与持久化让机器人持续服务开发调试完成后你需要让机器人能持续运行通常需要一个Web服务。FastAPI是Python生态中构建API的绝佳选择。6.1 用FastAPI封装LangChain链# main.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel from langchain_community.vectorstores import Chroma from langchain_community.embeddings import OpenAIEmbeddings from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.runnables import RunnablePassthrough from langchain_core.output_parsers import StrOutputParser # 0. 加载已持久化的向量数据库和链假设之前已经创建并保存 persist_directory ./chroma_db embeddings OpenAIEmbeddings() vectorstore Chroma(persist_directorypersist_directory, embedding_functionembeddings) retriever vectorstore.as_retriever() llm ChatOpenAI(modelgpt-3.5-turbo) prompt ChatPromptTemplate.from_template(基于以下上下文\n{context}\n\n问题{question}\n答案) rag_chain ( {context: retriever, question: RunnablePassthrough()} | prompt | llm | StrOutputParser() ) app FastAPI(title知识库问答机器人API) class QueryRequest(BaseModel): question: str app.post(/ask) async def ask_question(request: QueryRequest): try: answer rag_chain.invoke(request.question) return {answer: answer} except Exception as e: raise HTTPException(status_code500, detailf处理问题时出错{str(e)}) app.get(/health) async def health_check(): return {status: healthy}运行uvicorn main:app --reload即可启动服务。6.2 关键部署注意事项踩坑记录13链的序列化与加载上面的例子是在同一个进程中加载所有组件。但在生产环境你可能希望将训练好的链特别是包含复杂提示词和流程的序列化保存然后在服务启动时快速加载。LangChain支持使用langchain-cli或手动将链导出为JSON/YAML。但对于包含自定义函数或网络连接的复杂链序列化可能比较棘手。更常见的做法是将链的构建逻辑封装在一个函数中在服务启动时调用该函数初始化。踩坑记录14异步支持与性能LangChain的很多组件支持异步调用ainvoke,astream可以显著提升在高并发API下的性能。FastAPI本身是异步框架确保你的链也使用异步方法。app.post(/ask) async def ask_question(request: QueryRequest): answer await rag_chain.ainvoke(request.question) # 使用异步调用 return {answer: answer}在初始化LLM或Embedding模型时也要注意是否有异步客户端选项。踩坑记录15内存管理与多用户隔离记忆Memory上面的简单示例没有包含记忆。在Web服务中你需要为每个对话会话Session创建独立的记忆对象通常将会话ID与记忆存储如Redis关联。向量数据库连接确保你的向量数据库如Chroma服务是持久化且可被多个工作进程访问的。避免在每个请求中重复创建连接。资源清理长时间运行的服务注意监控内存泄漏特别是当处理大量文档或频繁创建复杂链时。7. 调试与优化当机器人不按套路出牌时即使代码跑通了机器人的行为也可能不尽如人意。以下是我积累的一些调试和优化经验。7.1 开启Verbose模式窥视黑盒这是最重要的调试手段。在初始化任何链、智能体执行器时设置verboseTrue你就能在控制台看到详细的步骤日志包括发送给模型的完整提示词。模型返回的原始响应。工具调用的参数和结果。智能体的“思考”过程。 这能帮你精准定位问题是出在提示词、工具调用解析还是模型理解上。7.2 提示词迭代与模型有效沟通大模型对提示词极其敏感。优化提示词是提升效果性价比最高的方法。角色扮演明确告诉模型“你是一个资深的XX专家”。任务分解对于复杂任务在提示词中引导模型一步步思考。格式约束要求模型以特定格式如JSON、Markdown列表输出便于后续程序解析。少样本示例Few-shot在提示词中提供一两个输入输出的例子让模型快速理解你的意图。prompt ChatPromptTemplate.from_messages([ (system, 你是一个严谨的代码审查助手。), (human, 示例问题这段Python代码有什么潜在问题\npython\ndef divide(a, b):\n return a/b\n), (ai, 潜在问题未处理除零错误ZeroDivisionError。建议添加判断 if b 0: return None 或抛出异常。), (human, {user_code}), ])7.3 评估与测试不要相信感觉为你的机器人建立简单的测试集。准备一批标准问题运行你的链人工或通过规则评估答案的准确性、相关性和安全性。当调整参数如chunk_size、search_kwargs或提示词后重新运行测试集量化比较效果变化。LangChain也提供了一些评估工具如langchain.evaluation但初期人工评估更直接有效。7.4 成本监控别让账单吓一跳如果你使用付费API成本控制必须从一开始就考虑。Token计数使用langchain.callbacks中的get_openai_callback等工具在开发阶段统计每次调用的Token消耗。缓存对重复的查询或Embedding计算结果进行缓存可以大幅节省成本和提升速度。LangChain内置了InMemoryCache、SQLiteCache等。降级策略对于非关键任务可以考虑使用更便宜的模型如GPT-3.5-turbo而非GPT-4或设置使用频率限制。回看整个搭建过程从环境配置、模型选择到对话链、智能体、RAG的构建再到最后的部署调试每一步都有其独特的“坑”。LangChain的强大在于它提供了一个高层次的抽象让我们能快速组合出强大的AI应用原型。但这种抽象的代价就是当出现问题时我们需要深入一层去理解各个组件是如何交互的。我的体会是不要试图一开始就弄懂LangChain的所有概念而是从一个具体的目标比如“做一个能查天气的机器人”出发边做边学遇到问题就针对性地去查文档、看源码、搜社区。当你成功绕过这些坑看到机器人按照你的设计流畅地工作时那种成就感绝对是值得的。