首页 / 资讯中心 / 文章详情

LangChain实战:从提示词到RAG与Agent的完整落地指南

LangChain实战:从提示词到RAG与Agent的完整落地指南 ★ FEATURED ARTICLE
简介一套面向大模型开发者的完整LangChain实战教程由黑马程序员推出聚焦检索增强生成RAG与智能体Agent两大主题从提示词工程讲到可落地的完整项目并结合Cursor、Devin、VSCode Agent等AI编程工具帮助开发者把大模型能力融入实际业务。资源包共235个文件大小约22.96MB主要包含121个Python脚本功能模块与案例代码、25个txt提示词库、16个log运行日志、13个xml配置、8个yml环境配置以及6个sqlite3数据库等目录结构清晰便于按主题检索。已有377人浏览学习。教程中不仅提供中文编写规则与精选提示词库还详细演示了知识库构建、任务拆解与编排、外部工具集成等关键场景通过源码、日志和配置文件的配合学习者可以完整复现RAG问答流程与Agent自动执行流程并掌握常见问题的排查思路。它兼顾原理讲解与工程实现适合希望系统掌握LangChain、快速交付AI应用的初中级及进阶开发者。1. 大模型RAG与Agent实战为什么从LangChain切入最稳很多人拿到一套大模型RAG与Agent项目教程第一反应是先去翻代码包结果被几十个文件淹没了。这条学习路径真正的起点不是模型也不是向量库而是提示词。基于LangChain技术把“提示词 → RAG检索 → Agent决策”串成一条可调试的链路是当前企业落地私有大模型最主流的工程范式RAG负责把外部知识变成模型“看得见”的上下文Agent负责把模型变成“会调用工具做事”的执行者。适合正在做企业知识库、客服问答、内部自动化助手的后端和算法工程师。先说结论这套实战教程值得跟但别照着读完就以为会了坑几乎都藏在数据切分和工具调用细节里。2. 提示词到大模型调用先跑通LangChain最小链路再谈RAG2.1 提示词工程在RAG与Agent中到底管什么提示词不是“把话说清楚”那么简单。在RAG里提示词决定模型是老实复述检索片段还是脑补一段不存在的知识在Agent里提示词决定模型在什么条件下调用工具、调用完怎么解读返回结果。很多做RAG的朋友第一个翻车点就在这里检索结果明明是对的但提示词写得像开放作文模型一口气编了三条理由。提示词工程在大模型应用里的角色是“约束边界”不是“激发灵感”。常见的做法是把提示词拆成四段角色定义、任务目标、输入输出约束、反面提示。角色定义锚定模型的行为基线任务目标把问题限定到“只回答与检索片段相关的内容”输入输出约束明确格式“只返回JSON”“不要解释”反面提示补一句“如果片段中没有答案回答不知道”。这套模板放RAG和Agent场景都能复用而且LangChain里用PromptTemplate管理比在代码里拼f-string干净得多。2.2 用LangChain封装大模型的最小调用代码这条路径上第一段能跑的代码是用LangChain把任意兼容OpenAI接口的大模型包装成一条链。不管后面接RAG还是Agent这个最小链路都是地基。from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate from langchain_core.output_parsers import StrOutputParser # 兼容大多数国产大模型厂商的OpenAI风格接口 llm ChatOpenAI( base_urlhttps://api.your-provider.com/v1, api_keyyour-api-key, modelyour-model-name, temperature0.3, max_tokens1024, ) prompt ChatPromptTemplate.from_messages([ (system, 你是企业知识库助手只能依据提供的上下文回答不知道就说不知道。), (human, 上下文{context}\n\n问题{question}), ]) chain prompt | llm | StrOutputParser() answer chain.invoke({ context: LangChain是一个用于构建大模型应用的开发框架。, question: LangChain是什么 }) print(answer)这段代码的核心是把三个组件串成一条链prompt负责把变量渲染成消息序列llm负责生成StrOutputParser负责把响应里的Content解析成纯字符串。LangChain里用管道符“|”组合组件管道模型好就好在每一步输入输出都是标准格式方便中间插入检索器或工具。参数说明temperature在知识问答场景推荐0.1到0.3数值越高模型越“敢编”RAG场景最不能要的就是编造max_tokens按回答长度设问答类1024够用代码生成类要调到2048以上。base_url指向厂商的OpenAI兼容端点这条路径的好处是模型供应商可替换——一开始用免费大模型API做原型验证生产环境再换成企业采购的私有化接口代码逻辑不用动。2.3 提示词模板的三个必调参数与长尾写法模板里最容易被忽视的是两个变量context和question的比例。常见的错误是把context塞成一大段question只占最后一句模型会迷失在长文本里。更稳的写法是让question在前context作为“参考资料”跟在后面并在system消息里明确“上下文仅供参考”。第二个必调参数是输出格式约束长度。只要业务需要结构化结果比如给下游系统返回字段就不要靠提示词“拜托”模型遵守JSON格式而是用LangChain的with_structured_output配合Pydantic模型做强约束。提示词设计到这个程度才谈得上可测试可回归。第三个参数是few-shot示例的条数。文本分类类问题一到两条示例足够多了浪费token还会把模型带偏工具调用类问题反而要多给失败的负例比如“当工具返回错误时不要重试同一参数”。这一条在后续Agent章节会反复用到。3. RAG知识库落地加载、切分、向量化与检索的四步工程3.1 RAG为什么能解决“模型不知道”的问题RAG的全称是检索增强生成核心逻辑是先检索再回答。大模型训练完参数就固定了新知识、私有文档它一律不知道硬问就会产生幻觉RAG把外部文档切片后转成向量存进向量库提问时先召回最相关的几个片段再连同问题一起交给模型生成答案。说白了就是把“背不出来”变成“开卷考试”。但这套方案有一个瓶颈也是大家都在讨论的“rag瓶颈”检索质量的上限决定了回答质量的上限。检索召回错片段提示词写得再好也白搭。瓶颈主要出现在两个环节文本切分破坏了语义完整性以及Embedding模型和语料不匹配。这两个问题会在第5章具体展开这里先记住一个原则RAG工程的核心是控制信息损耗而不是堆模型参数。数据结构上还要区分一个概念rag知识库和结构知识库的适用场景完全不同。结构知识库指的是关系型数据库、知识图谱这类强schema的数据适合精确查询和统计聚合RAG知识库适合非结构化文本比如PDF合同、产品手册、对话记录。常见做法是两者结合能用SQL查的走结构化接口查不到的模糊问题再走RAG不会有人把整个数据库导出成文本塞进向量库那样既不经济也难维护。3.2 文档加载与切分chunk_size和overlap怎么设先看加载端。LangChain里DocumentLoader负责把不同格式的文件统一成Document对象Document包含page_content和metadata两个主要字段。PDF用PyPDFLoaderMarkdown用TextLoaderCSV用CSVLoader。metadata非常关键后面做过滤和溯源都靠它建议在加载阶段就把来源文件名、页码、章节标题写进去。from langchain_community.document_loaders import PyPDFLoader from langchain_text_splitters import RecursiveCharacterTextSplitter loader PyPDFLoader(product_manual.pdf) docs loader.load() splitter RecursiveCharacterTextSplitter( chunk_size512, chunk_overlap64, separators[\n\n, \n, 。, , , ., !, ?, , ], ) chunks splitter.split_documents(docs) print(f原始文档数: {len(docs)}, 切分后片段数: {len(chunks)})参数说明是这一段的重头戏。chunk_size512表示每个片段最长512个字符这个值在中文场景下大约对应300到400个汉字足够表达一个完整论点又不会超出主流Embedding模型的输入上限。chunk_overlap64让相邻片段有部分重叠避免一个完整句子恰好被拦腰截断。separators里的分隔符列表决定了优先从哪个层级切分先按双换行切段落再按单换行再按句号问号叹号切句子最后才按空格和字符硬切。中文语料一定要把“。”加进去否则英文默认分隔符会把中文句子切得稀碎。这里顺带回答一个高频问题rag知识库能存储图片嘛。纯文本RAG管道存不了图片内容但工程上有成熟做法图片单独存对象存储向量库里存图片的标题、OCR文本和object路径命中片段后由前端渲染图片缩略图。多模态Embedding模型可以做到图文互相检索但部署复杂且效果对硬件敏感第一版系统不建议上。3.3 Embedding与向量库选型开源模型优先还是商用优先Embedding模型负责把文本映射成高维向量。中文场景第一梯队是BGE系列和M3E英文场景OpenAI的text-embedding-3-small很常用。选型的判断标准不是榜单分数而是三个实际问题是否支持中文分词粒度、向量维度对存储成本的影响、是否允许私有化部署。企业数据不出内网是硬需求这时候开源Embedding模型几乎是唯一选择配合CPU推理也能跑只是慢一些。向量存储方面不同阶段用不同工具。FAISS是内存级向量索引适合单机原型和千万元素以下的中小知识库Chroma是嵌入式向量库支持持久化和metadata过滤小团队做产品原型最顺手Milvus这类分布式向量数据库适合生产环境支持水平扩展和混合检索。选型不要太激进第一版用FAISS跑通等数据量到百万级再引入Milvus不迟。3.4 检索链路完整代码从文档到带分数的相似度召回from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import FAISS # 本地开源Embedding模型离线可用 embeddings HuggingFaceEmbeddings( model_nameBAAI/bge-base-zh-v1.5, encode_kwargs{normalize_embeddings: True}, ) # 用切好的chunks构建向量库向量库会保存到本地目录 vectorstore FAISS.from_documents(chunks, embeddings) vectorstore.save_local(faiss_index) # 检索时读取向量库返回最相似的top_k片段 db FAISS.load_local( faiss_index, embeddings, allow_dangerous_deserializationTrue, ) results db.similarity_search_with_score(产品保修期是多久, k4) for doc, score in results: print(fscore: {score:.4f}, 来源: {doc.metadata.get(source, unknown)}) print(doc.page_content[:120]) print(---)代码逻辑分三段构建、持久化、检索。构建阶段把chunks逐条Embedding后写入FAISS索引normalize_embeddingsTrue表示向量归一化这样后续计算余弦相似度时分数范围更稳定。save_local和load_local实现了向量库落盘避免每次都重新Embedding这是做增量更新的基础。检索阶段返回的score是相似度距离不同模型分数分布差异很大不要死记硬背“0.7才算相关”先打印一批真实查询的score分布再定阈值。metadata在检索中的作用容易被忽略。建议在写入前给每个chunk的metadata加上产品线、版本号、生效日期这些字段检索时用FAISS的filter参数先缩小候选集再算相似度。这类过滤对“老版本文档和新版本文档同时存在”的场景特别有效属于低成本高收益的做法。如果想进一步引入知识图谱领域里讨论的ontology rag方向是针对有强层级关系的知识做结构化约束属于进阶路线第一版可以不做。4. Agent智能体实战从ReAct循环到LangChain工具调用4.1 Agent和RAG的分工边界在哪里RAG解决的是“模型不知道”的问题Agent解决的是“模型不会做”的问题。同一个大模型接上工具调用能力后就能完成查天气、发邮件、查库存这类外部动作。Agent与RAG的分工很清晰RAG输入输出都是文本Agent则把文本指令变成真实的系统操作。两者经常配合出现——先RAG检索得到事实再Agent调用工具执行动作比如“根据这份合同模板生成一份会议纪要并发给参会人”。Agent的核心是用大模型做决策而不是硬编码if-else。经典范式是ReAct即推理与行动交替执行模型先观察当前状态思考下一步该做什么调用一个工具观察工具返回再决定继续还是结束。这套循环听起来简单但工程落地时的难点全在“终止条件”和“错误恢复”上下一节会给出对应参数。4.2 用LangChain实现一个带工具调用的最小Agent先定义一个工具再构建Agent再执行。这是LangChain里最直接的三步走。工具用装饰器注册函数的docstring会被当作工具描述喂给模型模型靠这段描述决定何时调用、传什么参数所以docstring要写清楚用途和参数类型这是很多新手意识不到的细节。from langchain_openai import ChatOpenAI from langchain.agents import create_react_agent, AgentExecutor from langchain_core.tools import tool from langchain_core.prompts import PromptTemplate tool def query_stock(product_id: str) - str: 查询指定产品ID的实时库存。参数product_id是产品编码例如P10086。 # 实际项目里这里会走库存系统API inventory {P10086: 32, P10088: 0} count inventory.get(product_id, -1) if count 0: return {status: error, message: unknown product_id} return f{{status: ok, stock: {count}}} llm ChatOpenAI( base_urlhttps://api.your-provider.com/v1, api_keyyour-api-key, modelyour-model-name, temperature0.2, ) prompt PromptTemplate.from_template( 你是一个库存助手可以查询库存。请严格根据工具返回结果作答。\n 尽可能使用工具查询数据不要猜答案。\n 工具信息{tools}\n 工具名{tool_names}\n 用户问题{input}\n 思考过程{agent_scratchpad} ) agent create_react_agent(llmllm, tools[query_stock], promptprompt) executor AgentExecutor( agentagent, tools[query_stock], max_iterations5, early_stopping_methodgenerate, verboseTrue, ) resp executor.invoke({input: P10088有货吗}) print(resp[output])代码里最关键的两个参数是max_iterations和early_stopping_method。max_iterations5限制Agent最多执行5轮思考-行动循环防止模型在工具调用里死循环烧钱early_stopping_methodgenerate表示达到迭代上限后让模型不调用工具、直接生成一个最终答复给用户而不是干巴巴报错。工具返回值那段JSON字符串是有讲究的status字段区分ok和error这样模型能识别工具是否成功。如果不做这个设计模型会在工具返回报错后反复用相同参数重试直到撞上max_iterations。把工具返回结构化是Agent开发里最值得抄的工程习惯之一。4.3 agent框架选型LangChain、Dify、CrewAI哪个更适合你所有新手都会卡在框架选型上。LangChain是开发框架适合要自己控制流程、深度定制逻辑的研发团队学习曲线陡但灵活度最高Dify是可视化平台编排RAG和Agent像搭积木适合业务人员快速做原型也能部署到私有环境但复杂逻辑会被平台的能力边界卡住CrewAI专注于多智能体协作适合让多个角色分工完成任务的场景。选哪个核心看团队构成只有开发没有产品落地经验的选LangChain纯业务团队要做验证Dify上手最快多角色流程协作CrewAI省事。还有一个概念容易混harness和agent区别。harness指的是承载Agent运行的外壳负责循环调度、记录中间步骤、控制终止agent本身是决策大脑。很多框架里你写的业务代码其实是在定义agent的思考方式而框架内置的harness负责让这个思考循环起来。理解这一点调试时就能分清问题是出在“大脑没想对”还是“循环没跑对”。Agent安全也要提前设防。工具调用本质上是把系统的执行力交到了大模型手里所以工具必须做白名单准入不能让模型直接拼shell命令所有外部输入进工具之前要做参数校验敏感操作比如转账、删除必须有二次确认机制。agent安全这个方向会越来越重要第一版系统至少要保住“工具只能读不能写”的底线。5. RAG与Agent调试避坑手册5条现象、原因与修复记录5.1 中文检索结果全是碎片答非所问现象知识库文档是中文产品手册切分后检索“保修期多久”拿回来的片段只有半句话答案拼都拼不出来。原因RecursiveCharacterTextSplitter的默认分隔符是为英文设计的英文按空格和换行切不会破坏句子中文没有空格词边界默认设置会把一个完整句子拦腰截断。解决把中文句号、问号、感叹号、分号加进separators列表并放在空格之前同时把chunk_overlap从默认的0调整到64以上给跨片段被截断的内容留出冗余。改完后重新生成向量库别只改切分器不动索引那是白改。5.2 中文语料用英文Embedding模型score分布离谱现象检索结果看着相关但score全部集中在0.8到0.9之间阈值怎么调都分不出好坏有时排名第一的片段反而是废话。原因部分英文Embedding模型在中文上映射到相近区域区分度不足相似度分数整体偏高丧失了排序能力。解决换成中文预训练模型比如bge-base-zh-v1.5。替换后先打印一段真实查询的score分布正常情况下相关片段和不相关片段的分数差会拉开到0.1以上。如果分数差距仍不明显检查是否忘记开启normalize_embeddings。5.3 Agent卡死在同一步反复调用同一个工具现象Agent调用库存工具返回“库存为0”模型不换方案继续传同一个product_id重试直到max_iterations耗尽。原因工具返回值里没有携带“业务失败”和“系统错误”的区别模型以为调用失败于是不断重试。解决把工具返回值格式化成JSON明确status字段ok表示业务成功参数错误返回error并附message业务上“库存为0”也是ok只是value等于0。同时把docstring里补充一句“库存为0是正常业务结果不需要重试”。这样模型就知道换个参数或者换思路。5.4 新旧文档版本混在同一个向量库答案自相矛盾现象同一产品的PDF手册更新了三版旧版说保修1年新版说保修3年检索时两个片段都被召回模型有时答1年有时答3年。原因构建向量库时没有对文本片段做版本过滤新旧内容处于公平竞争地位相似度相近时随机排序答案自然不稳定。解决文档加载阶段往metadata里写版本号和生效日期检索时先用filter按版本范围缩小候选集再算相似度或者写入时只保留最新版本旧版本进归档库需要时才单独查询。这个坑在存量文档多、更新频繁的企业场景几乎必踩越早处理代价越小。5.5 检索结果太多塞爆上下文模型被噪声带偏现象top_k调到10每段512字光上下文就5000多字回答变得又长又啰嗦还经常引用不相关的内容。原因不是所有检索结果都有用把低分片段硬塞给模型模型分不清哪些是核心论据只能全盘接收噪声被当成事实。解决第一版top_k设3到4不要超过5再按score做一次硬过滤低于阈值的片段不进入提示词。同时把提示词改成“只依据第一条和第二条上下文回答”给模型明确的优先级。上下文质量优先于数量这条经验适用于所有RAG项目。6. 进阶技巧本地私有化部署大模型后的RAG验证与调优RAG与Agent方案在企业内落地时经常卡在“模型不能出内网”这个硬性要求上。常见做法是用Ollama这类工具在本地拉起开源大模型再让LangChain连接本地的OpenAI兼容端点实现全链路私有化部署。具体配置很简单from langchain_openai import ChatOpenAI llm ChatOpenAI( base_urlhttp://localhost:11434/v1, api_keyollama, modelqwen2.5:7b, temperature0.2, )本地模型部署完成后最值得做的一件事是建立RAG回归测试集。准备20到50条“问题-标准答案”对写一个小脚本对每个问题检索top_k片段把片段拼进提示词让模型作答然后人工或让更强模型判断答案是否覆盖标准答案要点统计命中率。调优时坚持单变量固定Prompt和Embedding不变只改chunk_size用同一份测试集跑三轮取稳定值再固定chunk_size去换Embedding模型。变量混着调只会得到一堆无法解释的结果最后全靠玄学调参。这条调优路线的血泪经验是早期我把大量时间花在换Embedding模型上后来发现chunk_size、overlap、top_k这三个参数对回答质量的影响远大于模型换品牌。本地模型生成速度慢7B级别量化模型在CPU上单请求要好几秒所以测试集规模不要贪大先跑通流程再扩量。希望你在这条路上少交学费多做能复现的回归实验希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站