ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

LangChain+RAG+AI Agent实战:从知识库问答到智能体工作流

LangChain+RAG+AI Agent实战:从知识库问答到智能体工作流 这次我们来看一套 LangChain RAG AI Agent 的完整实战路径知识库问答、工具调用、状态化工作流、接口服务化一条主线串到底。现在网上讲 LangChain 的教程非常多但真正动手时会发现几个问题版本更新太快、示例代码抄下来就跑不通、检索结果和预期差很远、一到 Agent 多轮调用就报错。所以这篇文章不做概念堆砌直接给出一条可运行、可验证、可扩展的技术主线。文章会覆盖 RAG 知识库的完整构建流程、Agent 工具调用实战、LangGraph 状态化工作流、效果评估指标、接口服务化与批量任务设计以及最常见的 8 个排查场景。不管你是想给公司内部资料做知识库问答还是想把大模型接进现有业务工具链这套流程的通用思路都可以直接复用。1. 核心能力速览能力项说明技术栈LangChain、LangGraph、Chroma、FastAPI可选 Ollama 本地模型核心功能文档加载、文本切分、向量化、检索生成、Agent 工具调用、工作流管理模型接入OpenAI 风格 API / 本地 Ollama 双通道可切换接口能力FastAPI 暴露 HTTP 接口支持单条问答和批量任务硬件门槛云端 API 模式普通开发机即可本地模型按参数量匹配合适内存或显存学习成本有 Python 基础一天内可跑通主链路适合场景知识库问答、制度文档检索、数据分析助手、业务工具编排注意边界需按实际情况验证模型授权、数据合规与内容准确性整体判断这套技术栈的入门门槛不算高真正容易出问题的是版本兼容、检索质量和工具调用编排。后面每一节都会围绕这几个痛点展开。2. LangChain、RAG、Agent 与 LangGraph 的关系很多初学者会把 LangChain、RAG、Agent 混为一谈其实它们是四个不同层次的东西。2.1 LangChain 是编排框架LangChain 本身不提供大模型也不负责训练模型。它是一个应用开发框架帮开发者把大模型、提示词、文档、向量库、外部工具串联起来。你可以把它理解为一条流水线模板定义好之后数据从一端进入经过处理从另一端输出。框架的价值在于规范化了常用组件模型封装ChatOpenAI、Ollama 等统一的聊天模型接口提示词管理ChatPromptTemplate、FewShotPromptTemplate文档处理各种 DocumentLoader、TextSplitter记忆管理对话历史、窗口记忆、摘要记忆工具调用Tool、Agent、AgentExecutor组件之间用标准接口连接所以你可以随时替换某个环节。比如今天用 OpenAI明天换成 Ollama 的 Qwen代码改动很小。2.2 RAG 是解决“模型不知道”的路径RAG全称 Retrieval-Augmented Generation检索增强生成。核心思路是模型回答之前先从知识库或文档库中检索相关内容再把检索结果作为上下文送给生成模型。为什么要这么做因为大模型的知识截止时间有限也不掌握你的私有业务资料。让它直接回答公司制度问题它只会瞎编。RAG 的做法是先用检索把答案的“候选材料”找出来模型只需要做阅读理解幻觉概率会明显下降。RAG 的典型链路文档加载 - 文本切分 - 向量化 - 向量库存储 用户提问 - 向量检索 - 拼接上下文 - 模型生成中间有一个关键点检索质量直接决定生成质量。检索不到正确答案模型怎么生成都是错的。2.3 Agent 是“让模型自己决定下一步”Agent 可以理解为一个智能体。它不仅仅是回答问题而是能根据任务目标编排步骤、调用工具、查看结果再决定下一步动作。例如用户提问“查询最近三天的订单金额并生成汇总报告”这串任务不能靠一次模型调用解决。Agent 需要先调用订单查询工具拿到原始数据再调用计算工具或报表工具最后整理成报告。LangChain 的 Agent 体系里关键组件包括Tool一个可以执行具体功能的函数比如查询数据库、调用接口Prompt告诉模型有哪些工具、什么情况下用哪个Agent根据用户输入和工具列表规划下一步动作AgentExecutor负责循环执行“思考→调用工具→观察结果→再规划”的过程2.4 LangGraph 是状态化工作流LangGraph 是 LangChain 团队推出的低层编排框架用来构建状态化的 Agent 应用。它和 LangChain 的关系不是替代而是向下延伸。LangChain 的 AgentExecutor 适合简单的循环任务。一旦业务流程复杂比如需要条件分支、人工审核节点、多 Agent 协作就需要更精确的控制。LangGraph 用图的方式定义工作流节点就是处理逻辑边就是流转条件每个节点都能读写共享状态。简单对比对比项LangChain AgentExecutorLangGraph定位高层封装开箱即用底层编排灵活可控状态管理简单适合单轮循环显式状态支持复杂分支使用场景快速验证、轻量 Agent生产级工作流、多 Agent 协作学习成本低中等我的建议是先跑通 LangChain 的 AgentExecutor理解工具调用逻辑再迁移到 LangGraph。3. 环境准备与前置条件第 3 节开始进入实操。先准备一套干净的基础环境。3.1 Python 与虚拟环境建议使用 Python 3.10 或 3.11兼容性更稳定。正式项目务必使用虚拟环境避免把依赖装进系统环境。python -m venv .venv source .venv/bin/activate # Windows 用户执行 .venv\Scripts\activate安装核心依赖pip install langchain langchain-openai langchain-community langchain-chroma chromadb pypdf fastapi uvicorn python-dotenv如果后面要测试本地模型再补装pip install ollama注意LangChain 的包拆分比较细老教程里的from langchain.llms import OpenAI在 0.3 之后已经变更。新版本统一从langchain_openai导入模型类这一点很关键。3.2 模型接入云端 API 与本地模型模型接入是第一个分叉口。如果你有 OpenAI 兼容的 API Key直接配置环境变量即可。在项目根目录创建.env文件OPENAI_API_KEY你的API_KEY OPENAI_BASE_URLhttps://api.openai.com/v1使用国内可直连的大模型服务时把OPENAI_BASE_URL换成对应的兼容地址即可代码不用改。如果想在本地跑模型可以先安装 Ollama然后拉取一个支持工具调用的模型比如 Qwen 系列ollama pull qwen2.5:7b ollama serve本地模型的好处是数据不出内网坏处是效果和速度取决于硬件。具体拉取哪个 tag以 Ollama 官方仓库当前支持的模型列表为准。4. 从 0 构建 RAG 知识库这一节用一个真实可运行的示例打通 RAG 全流程。示例默认使用云端 API本地模型接入方式在同一节末尾说明。4.1 文档加载先看文档加载。LangChain 社区提供了多种加载器常见的有TextLoader加载纯文本文件PyPDFLoader加载 PDFCSVLoader加载 CSVDirectoryLoader批量加载目录下的文档from langchain_community.document_loaders import TextLoader loader TextLoader(./data/kb.txt, encodingutf-8) docs loader.load() print(docs[0].page_content[:500])加载完成后文档变成Document对象包含page_content和metadata。如果后续要做多文档来源追踪可以在加载时给metadata添加来源字段。4.2 文本切分文档加载完成后不能直接整篇向量化。模型对输入长度有限制而且整篇文档向量化之后检索粒度太粗。常见做法是使用RecursiveCharacterTextSplitter。from langchain.text_splitter import RecursiveCharacterTextSplitter splitter RecursiveCharacterTextSplitter( chunk_size512, chunk_overlap64, separators[\n\n, \n, 。, , , , , ] ) chunks splitter.split_documents(docs) print(f切分后文档块数量: {len(chunks)})参数解释chunk_size每块最大字符数中文场景建议 300 到 800 之间chunk_overlap相邻块之间的重叠字符数用来缓解切分截断导致的语义断裂separators优先在段落、句号、分号处切分最后才按空格或字符切切分策略是 RAG 调优的第一步。块太大检索定位不准块太小上下文信息不完整。后面评估章节会专门说。4.3 向量化与向量库入库文本切分之后调用 Embedding 模型把每块文本变成向量。这里用 OpenAI 的text-embedding-3-small做演示。from langchain_openai import OpenAIEmbeddings from langchain_chroma import Chroma embeddings OpenAIEmbeddings(modeltext-embedding-3-small) vectorstore Chroma.from_documents( documentschunks, embeddingembeddings, persist_directory./db/chroma )persist_directory指定向量库的持久化目录第一次运行后向量数据会写入本地磁盘。下次启动时不需要重新加载文档直接加载向量库即可vectorstore Chroma( persist_directory./db/chroma, embedding_functionembeddings )Chroma 是一个轻量级开源向量数据库适合本地开发。生产环境如果需要更高并发可以迁移到 Elasticsearch、Milvus 或者 Qdrant接口设计理念类似。4.4 检索与生成向量库准备好之后把检索器和生成链拼起来。from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI from langchain_core.output_parsers import StrOutputParser retriever vectorstore.as_retriever(search_kwargs{k: 4}) prompt ChatPromptTemplate.from_messages([ (system, 你是知识库问答助手。请严格基于以下资料回答问题资料中没有的信息不要编造\n\n{context}), (human, {question}) ]) llm ChatOpenAI(modelgpt-4o-mini, temperature0) def ask(question: str) - str: docs retriever.invoke(question) context \n\n.join([doc.page_content for doc in docs]) chain prompt | llm | StrOutputParser() return chain.invoke({context: context, question: question}) if __name__ __main__: answer ask(这篇知识库里提到了哪些关键概念) print(answer)流程拆开看retriever.invoke(question)返回 TopK 相关文档所有文档拼接成一个context提示词要求模型只基于context回答chain.invoke完成生成这是最基础的 RAG 链路。跑通之后再考虑重排序、混合检索、记忆等增强能力。如果使用 Ollama 本地模型只需要替换两处from langchain_ollama import ChatOllama, OllamaEmbeddings embeddings OllamaEmbeddings(modelqwen2.5:7b) llm ChatOllama(modelqwen2.5:7b, temperature0)代码结构不用改。5. Agent 实战让模型学会调用工具RAG 解决的是“知识来源”问题Agent 解决的是“执行动作”问题。这一节用一个带两个工具的 Agent 示例说明原理。先定义两个工具一个查询当前时间一个做乘法计算。from datetime import datetime from langchain.tools import tool from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI tool def get_current_time() - str: 返回当前日期时间。 return datetime.now().isoformat() tool def multiply(a: int, b: int) - int: 计算两个整数的乘积。 return a * b tools [get_current_time, multiply]初始化 Agent 时提示词里需要包含input和agent_scratchpad两个变量。agent_scratchpad用来记录模型已经思考过什么、调用过哪些工具是循环执行的关键。prompt ChatPromptTemplate.from_messages([ (system, 你是一个智能助手可以在需要时调用工具解决问题。), (human, {input}), (placeholder, {agent_scratchpad}), ]) llm ChatOpenAI(modelgpt-4o-mini, temperature0) agent create_tool_calling_agent(llm, tools, prompt) executor AgentExecutor(agentagent, toolstools, verboseTrue) if __name__ __main__: result executor.invoke({ input: 现在北京时间是多少顺便计算 23 乘以 17。 }) print(result[output])执行时打开verboseTrue可以看到完整的思考轨迹模型决定先调用get_current_time工具返回时间结果模型接着调用multiply工具返回 391模型整理最终答案这里的关键认知是工具只是普通函数tool装饰器负责把函数包装成模型可识别的工具描述。工具名、参数说明、函数 docstring 都会传给模型作为模型选择工具的依据。所以工具说明必须写清楚否则模型可能不会调用。需要注意工具调用能力是模型侧支持的。OpenAI 的 GPT 系列原生支持Ollama 本地模型需要看模型是否支持 Function Calling。跑之前确认模型版本。6. RAG 效果评估与调优RAG 链路跑通后下一步是评估效果。很多初学者只关注“能不能生成答案”忽略“检索质量”这个真正的瓶颈。知识库问答的失败案例大部分问题出在检索环节。6.1 核心评估指标指标观察环节说明评估方式命中率 Hit Rate检索正确答案所需的文档是否出现在 TopK 结果中人工标注或按标准答案片段判断MRR检索排序第一个正确答案排得越靠前越好自动化计算上下文相关性检索生成检索出的内容是否与问题主题相关LLM 辅助评分忠实度 Faithfulness生成答案是否忠于检索上下文不编造信息LLM 辅助对比答案与上下文答案相关性生成答案是否直接回答用户问题而非答非所问LLM 辅助评分工程上最常用的两个指标是 Hit Rate 和 MRR。它们只考察检索结果不涉及生成方便快速迭代。可以写一个简易命中率评估脚本def hit_rate(questions, golden_docs, retriever): hits 0 for question, gold in zip(questions, golden_docs): docs retriever.invoke(question) context .join([doc.page_content for doc in docs]) if gold in context: hits 1 return hits / len(questions)更完整的评估可以借助 RAGAS 这类开源框架做 LLM 辅助评分也可以自己写一个“LLM 裁判”脚本。核心是先把问题集和标准答案准备好再跑指标避免凭感觉判断效果。6.2 重排序与混合检索基础向量检索有两个常见问题语义相近但关键词不匹配的文本召回不稳定TopK 结果里混入无关片段重排序Rerank可以在向量检索之后用 Cross-Encoder 模型对候选文档逐条打分把最相关的内容排到前面。# 伪代码先向量检索得到候选再用重排序模型精排 candidates retriever.invoke(question, k10) reranked reranker.rerank(question, candidates) final_docs reranked[:4]混合检索则是“向量检索 关键词检索”并行再把结果合并去重。Elasticsearch 同时支持 BM25 和向量检索生产场景常用它做统一检索层。如果你们系统已经在用 Elasticsearch接入 RAG 时优先考虑它而不是另起一套向量库。6.3 切分与提示词调优RAG 调优的大方向按优先级排列切分策略调整chunk_size、chunk_overlap实测 300 到 800 之间最常用检索召回数k太小可能漏答案太大可能引入噪声常见取值 4 到 10重排序候选集扩到 10 到 20精排后取前 4 到 5提示词明确要求“只基于资料回答”“资料不足时直接说明”查询改写用户问题太口语化时先让模型改写为检索表达调优时一次只改一个变量跑完评估指标再改下一个。7. 接口服务化与批量任务设计纯脚本演示只能验证逻辑真正接入业务需要把 RAG 和 Agent 封装成接口服务。7.1 FastAPI 包装 RAG用 FastAPI 包装一个/rag/query接口from fastapi import FastAPI from pydantic import BaseModel app FastAPI() class QueryBody(BaseModel): question: str k: int 4 temperature: float 0.0 app.post(/rag/query) def rag_query(body: QueryBody): docs retriever.invoke(body.question) context \n\n.join([doc.page_content for doc in docs]) chain prompt | llm | StrOutputParser() answer chain.invoke({context: context, question: body.question}) return { answer: answer, source_count: len(docs), sources: [doc.metadata.get(source, ) for doc in docs] }启动服务uvicorn main:app --host 127.0.0.1 --port 8000用 curl 验证curl -X POST http://127.0.0.1:8000/rag/query \ -H Content-Type: application/json \ -d {question: 什么是RAG, k: 4}返回结果里带上sources方便调用方核对答案来源。这个信息在调试阶段非常有用。7.2 批量任务设计接口服务适合在线问答。如果业务有批量需求比如一次性处理上百个问题不应该在上百个请求里直接并发调用接口更稳妥的做法是任务队列模式。简单实现可以用concurrent.futures控制并发import time from concurrent.futures import ThreadPoolExecutor, as_completed questions [问题1, 问题2, 问题3] def process(question): return ask(question) with ThreadPoolExecutor(max_workers4) as pool: futures {pool.submit(process, q): q for q in questions} for future in as_completed(futures): question futures[future] try: answer future.result() print(f{question}: {answer}) except Exception as e: print(f{question}: FAILED - {e})生产环境建议使用 Celery 或消息队列做异步任务任务状态、失败重试、结果落库都更完善。无论哪种方案都要注意记录每个任务的状态和日志失败任务要有重试机制建议设置重试上限控制并发数避免打爆模型服务或向量库接口服务要加访问限制避免内部接口被外部调用7.3 并发与重试策略大模型接口的延迟通常以秒计在线接口超时设置建议 60 秒以上。批量任务重试时要注意幂等性同一个问题重复处理不应该产生两份不一致的结果。简单做法是任务表里记录处理状态处理成功后标记完成。8. 资源占用与性能观察如果你的开发机性能一般需要关心整个 RAG 链路的资源占用。8.1 各环节资源消耗特征环节资源消耗类型说明文档加载与切分CPU、内存一次性操作PDF 解析较慢向量化嵌入CPU/GPU、内存批量文本越多耗时越长向量库检索内存、磁盘文本块数量越大索引占用越高LLM 生成内存/显存或云端 API本地模型时资源占用最明显重排序CPU/GPU推理耗时比向量检索高通常只对候选集执行本地嵌入模型的参数量通常在几百 MB 到几 GB 之间CPU 可以推理只是大批量嵌入时速度慢。本地 7B 量级模型通过 Ollama 运行通常需要 4GB 以上内存或显存具体取决于模型量化精度。实际占用需以本机测试为准。8.2 显存与内存观察方法Linux 下观察显存使用nvidia-smi观察内存使用free -hAPI 模式下本地资源压力主要来自向量库和文档预处理模型推理在云端。如果感觉响应变慢优先检查向量库磁盘 IO 和 API 调用频率。8.3 降低资源占用的通用手段文本块数量较大时先做嵌入缓存重复文本不重复向量化向量库索引大小影响检索耗时按业务范围拆分多个集合本地模型中优先选择 4bit 量化版本减少内存占用批量任务控制并发数避免内存暴涨定时清理日志和临时文件还有一个常见问题服务启动后端口被占用。启动前先检查端口lsof -i :8000如果有进程残留杀掉旧进程再启动新服务。9. 常见问题与排查方法实战中报错不可怕关键要知道往哪个方向查。把最常见的问题整理成一张表问题现象可能原因排查方式解决方案pip 安装依赖失败Python 版本过低或依赖冲突查看报错日志确认 Python 版本使用 Python 3.10/3.11创建新虚拟环境找不到langchain.llms模块使用了旧版导入路径检查 LangChain 版本改用langchain_openai等新包模型返回空内容或报错API Key 未配置或 Base URL 不对检查.env文件和日志确认环境变量已加载Chroma 向量库打开失败持久化目录损坏或版本不一致查看启动日志备份后删除./db/chroma重建检索结果不相关切分策略不合理或 embedding 不适配打印检索到的文档内容调整 chunk_size、k 值加重排序Agent 不调用工具工具描述不清晰或模型不支持工具调用打开 verbose 查看规划过程改写工具 docstring换支持工具调用的模型接口超时模型推理耗时较长或并发过高查看 API 日志和耗时记录加长超时时间降低并发数批量任务卡住某个任务出现异常未捕获检查任务日志和异常处理单任务 try/except设置重试上限实际排查时先看报错信息再缩小到具体环节。RAG 链路按“文档加载→切分→向量化→检索→生成”分段打日志很快能定位问题。有一个非常有用的调试技巧在检索之后打印检索到的文档内容。如果文档内容本身就不对那问题一定在检索前面的环节而不是生成模型的问题。10. 最佳实践与学习路径建议最后聊几条工程落地建议都是容易被忽视但很影响结果的事情。10.1 先小参数跑通再扩大规模第一次搭建时不要准备几百 MB 的文档先拿 3 到 5 篇文章跑通全链路。确认检索和生成都正常后再逐步扩充知识库。这样可以快速区分“代码问题”和“数据问题”。10.2 建立一套最小可运行配置把环境依赖、.env模板、启动命令记录成文档或者在项目里保留一个README.md和requirements.txt。团队协作时新成员十几分钟就能把环境跑起来而不是反复踩安装坑。10.3 评估优先于调参没有评估指标的 RAG 调优都是凭感觉。先准备一份至少覆盖常见问题的测试集再用命中率和忠实度指标做基线每次改动跑一遍结果对比。比直接调整参数更有效。10.4 合规与边界意识如果知识库涉及公司内部资料或用户隐私需要特别注意确认文档来源合法不放入未授权的版权内容系统内部接口要限制访问范围避免数据泄露涉及人脸、声音等敏感数据时必须确保有明确授权重要场景生成结果要人工复核不能直接对外发布10.5 下一步学习方向跑通基础链路后可以按这几个方向继续深入把 Agent 接进业务系统接入数据库查询、日志分析、工单处理等真实工具学习 LangGraph把多步骤流程做成带状态管理的工作流研究多路召回策略结合关键词检索、向量检索和知识图谱针对垂直领域数据做切分策略和提示词优化用 Elasticsearch 等企业级检索组件替换单机向量库支撑更高并发这套 LangChain、RAG、AI Agent 的组合在任何大模型应用项目里基本都是基础设施。把这一条主线跑通后面再学多 Agent 协作、记忆管理、工具调用增强都有清晰的地图可以参照。建议先照着文中的示例代码把 RAG 链路跑通再尝试加上一个简单工具Ag ent 和 LangGraph 的部分很快就能上手。
返回列表