LangChain+RAG+AI Agent实战:从知识库问答到智能体工作流
2026/9/1 2:16:26 网站建设 项目流程

这次我们来看一套 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_URL=https://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:加载 PDF
  • CSVLoader:加载 CSV
  • DirectoryLoader:批量加载目录下的文档
from langchain_community.document_loaders import TextLoader loader = TextLoader("./data/kb.txt", encoding="utf-8") docs = loader.load() print(docs[0].page_content[:500])

加载完成后,文档变成Document对象,包含page_contentmetadata。如果后续要做多文档来源追踪,可以在加载时给metadata添加来源字段。

4.2 文本切分

文档加载完成后,不能直接整篇向量化。模型对输入长度有限制,而且整篇文档向量化之后检索粒度太粗。常见做法是使用RecursiveCharacterTextSplitter

from langchain.text_splitter import RecursiveCharacterTextSplitter splitter = RecursiveCharacterTextSplitter( chunk_size=512, chunk_overlap=64, 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(model="text-embedding-3-small") vectorstore = Chroma.from_documents( documents=chunks, embedding=embeddings, persist_directory="./db/chroma" )

persist_directory指定向量库的持久化目录,第一次运行后,向量数据会写入本地磁盘。下次启动时,不需要重新加载文档,直接加载向量库即可:

vectorstore = Chroma( persist_directory="./db/chroma", embedding_function=embeddings )

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(model="gpt-4o-mini", temperature=0) 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(model="qwen2.5:7b") llm = ChatOllama(model="qwen2.5:7b", temperature=0)

代码结构不用改。

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 时,提示词里需要包含inputagent_scratchpad两个变量。agent_scratchpad用来记录模型已经思考过什么、调用过哪些工具,是循环执行的关键。

prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个智能助手,可以在需要时调用工具解决问题。"), ("human", "{input}"), ("placeholder", "{agent_scratchpad}"), ]) llm = ChatOpenAI(model="gpt-4o-mini", temperature=0) agent = create_tool_calling_agent(llm, tools, prompt) executor = AgentExecutor(agent=agent, tools=tools, verbose=True) if __name__ == "__main__": result = executor.invoke({ "input": "现在北京时间是多少?顺便计算 23 乘以 17。" }) print(result["output"])

执行时打开verbose=True,可以看到完整的思考轨迹:

  • 模型决定先调用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, k=10) reranked = reranker.rerank(question, candidates) final_docs = reranked[:4]

混合检索则是“向量检索 + 关键词检索”并行,再把结果合并去重。Elasticsearch 同时支持 BM25 和向量检索,生产场景常用它做统一检索层。如果你们系统已经在用 Elasticsearch,接入 RAG 时优先考虑它,而不是另起一套向量库。

6.3 切分与提示词调优

RAG 调优的大方向,按优先级排列:

  1. 切分策略:调整chunk_sizechunk_overlap,实测 300 到 800 之间最常用
  2. 检索召回数:k太小可能漏答案,太大可能引入噪声,常见取值 4 到 10
  3. 重排序:候选集扩到 10 到 20,精排后取前 4 到 5
  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_workers=4) 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 -h

API 模式下,本地资源压力主要来自向量库和文档预处理,模型推理在云端。如果感觉响应变慢,优先检查向量库磁盘 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.mdrequirements.txt。团队协作时,新成员十几分钟就能把环境跑起来,而不是反复踩安装坑。

10.3 评估优先于调参

没有评估指标的 RAG 调优都是凭感觉。先准备一份至少覆盖常见问题的测试集,再用命中率和忠实度指标做基线,每次改动跑一遍结果对比。比直接调整参数更有效。

10.4 合规与边界意识

如果知识库涉及公司内部资料或用户隐私,需要特别注意:

  • 确认文档来源合法,不放入未授权的版权内容
  • 系统内部接口要限制访问范围,避免数据泄露
  • 涉及人脸、声音等敏感数据时,必须确保有明确授权
  • 重要场景生成结果要人工复核,不能直接对外发布

10.5 下一步学习方向

跑通基础链路后,可以按这几个方向继续深入:

  1. 把 Agent 接进业务系统,接入数据库查询、日志分析、工单处理等真实工具
  2. 学习 LangGraph,把多步骤流程做成带状态管理的工作流
  3. 研究多路召回策略,结合关键词检索、向量检索和知识图谱
  4. 针对垂直领域数据做切分策略和提示词优化
  5. 用 Elasticsearch 等企业级检索组件替换单机向量库,支撑更高并发

这套 LangChain、RAG、AI Agent 的组合在任何大模型应用项目里基本都是基础设施。把这一条主线跑通,后面再学多 Agent 协作、记忆管理、工具调用增强,都有清晰的地图可以参照。建议先照着文中的示例代码把 RAG 链路跑通,再尝试加上一个简单工具,Ag ent 和 LangGraph 的部分很快就能上手。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询