☰
大模型应用开发实战:RAG、LangChain与Agent工具调用全解析
2026/10/28 13:56:59 网站建设 项目流程

“怎么让大模型回答我自己的资料?”“Agent 到底怎么调用工具?”“RAG、LangChain、Embedding、向量数据库这些词一次出现,我该按什么顺序学?”

这篇就是围绕这些问题写的。标题里那一串名词——Agent 智能体、LangChain、RAG 检索增强、提示词工程、向量数据库、Embedding、工具调用——不是七门独立的课,而是一条完整的大模型应用项目链路。文章会把这条链路拆开,按“先跑通、再优化、最后接业务”的顺序讲清楚,并给出可复制的代码模板和一套通用验证流程。

先给结论:这篇文章适合正在从“会调 API”走向“能独立搭一个 AI 应用”的开发者。你会搞清楚每个名词实际解决什么问题、它们的调用顺序是什么、如何最小化地搭一个 RAG 知识库、如何给 Agent 加工具调用,以及踩到显存不足、接口超时、检索质量差这类问题时从哪里入手排查。

1. 核心能力速览

先把整条技术栈和本文覆盖范围放在一张表里,方便你判断哪些内容可以直接拿走用:

能力项说明
技术栈范围Prompt 工程、Embedding、向量数据库、RAG、LangChain/LangGraph、Agent、工具调用、API 服务
核心价值让大模型使用私有知识、自主决定调用工具、提供可复用的应用接口
运行环境Python 3.9+,本地或服务器部署均可;CPU 可跑 Embedding 与小型模型,GPU 决定生成模型和向量化速度
关键依赖langchain、langchain-openai / langchain-community、chromadb、fastapi、sentence-transformers 等,具体版本需按项目锁定
是否支持 API 服务支持,可用 FastAPI 或 LangServe 封装统一接口
是否支持批量任务支持,建议用目录批量导入文档、队列化检索请求、加入失败重试
是否支持一键启动可以写一个启动脚本统一加载向量库和 Web/API 服务,但不如整合包一键启动,需要简单配置
适合场景企业知识库问答、文档阅读理解、Agent 自动化工单、代码审查辅助、内容生产
不适合场景对实时性和精度要求极高的生产系统、需要强多轮状态管理的复杂业务(需引入 LangGraph 等状态机方案)

从材料看,这篇讨论的是一个偏“全链路方法论”的东西,不是某个固定开源仓库。所以本文会用通用开源组件(LangChain、ChromaDB、FastAPI 等)搭一条可运行链路,并标明哪些地方需要按你的项目替换。

2. 这条技术栈到底解决什么问题

很多新手容易被名词淹没。先把每个词对应到实际问题上。

2.1 Embedding 与向量数据库:让机器比对“语义”

大模型本身不知道你的私有文档内容。要让模型回答“我们公司报销制度是什么”,第一步是把文档切成片段,转成向量(Embedding),存进向量数据库。查询时也把问题转成向量,用相似度检索出最相关的文档片段。

这里的关键事实:Embedding 模型决定了检索质量上限。同一个项目里,用通用 Embedding 模型和用针对领域微调的 Embedding 模型,检索结果会有明显差异。如果材料里涉及“qwen embedding”“deepseek embedding ragflow”这类热词,说明当前常见的做法是优先尝试国产开源 Embedding 模型,或者 RagFlow、Dify 这类平台内置的向量化链路。

2.2 RAG:把检索结果塞进提示词

RAG 的全称是 Retrieval-Augmented Generation,检索增强生成。它做的事很朴素:把向量数据库检索到的文本片段拼进 Prompt,再让大模型基于这些片段回答。

RAG 的价值是“不重新训练模型,就能让模型用到私有知识”。缺点是引入了一个新的故障点:检索不准,回答就不准。所以后面第 5 节会专门讲“如何判断 RAG 质量”。

2.3 Agent 与工具调用:让模型自己决定下一步

Agent 的思路是给模型一些“工具”,让它根据任务自动决定调用哪个。常见工具包括:搜索引擎、计算器、数据库查询接口、内部 API、代码执行器。

材料里热词提到“LangGraph 和 LangChain 的区别”。简单理解:LangChain 提供组件库,能快速搭简单链式调用;LangGraph 提供更精细的图状态管理,适合复杂 Agent 流程。先跑通 LangChain 的 Agent,再根据需求考虑是否切到 LangGraph。

2.4 LangChain:不是运行时,是胶水层

LangChain 不是一个独立的大模型引擎,它更像是把 Prompt、LLM、Embedding、向量库、工具、Agent 串起来的框架。它解决的问题不是“模型能力”,而是“工程集成速度”。如果项目规模到一定程度,也可以只用手写 Python 组装,但不是从 0 到 1 最省力的路径。

3. 环境准备与前置条件

在写代码前,先把环境准备好。建议第一次跑通不要追最新版本,用稳定组合。以下是通用检查清单,实际版本号需要以你使用的模型和框架为准。

3.1 基础环境检查

# 查看 Python 版本,建议 3.9 以上 python --version # 查看 pip 版本 pip --version # 查看 CUDA 是否可用(有 NVIDIA 显卡时) nvidia-smi

如果你在本地没有 NVIDIA 显卡,也可以纯 CPU 跑完整条链路。Embedding 模型和小规模文本生成的推理在 CPU 上只是慢,不是不能跑。如果你的业务要求吞吐量,再考虑 GPU。

3.2 安装核心依赖

pip install langchain langchain-community langchain-openai chromadb sentence-transformers fastapi uvicorn python-dotenv

如果你的 LLM 调用走 OpenAI 兼容接口,就装langchain-openai;如果直接调用本地模型,通常需要配合 Ollama 或 vLLM 提供的 OpenAI 兼容服务,配置好base_url即可。

3.3 模型准备

整条链路需要两类模型:

模型类型作用可选方案
Embedding 模型文本转向量sentence-transformers 系列、BAAI/bge 系列、开源 Qwen Embedding 等
LLM生成答案OpenAI 兼容 API、本地 Ollama 中的 Qwen/Llama/DeepSeek 等

需要特别注意:Embedding 模型和 LLM 是独立的。你可以用本地 Embedding 模型 + 远程 LLM API 的组合,也可以用远程 Embedding + 本地 LLM。如果机器显存有限,最省显存的做法是 Embedding 用小模型,生成模型用 API。

如果你所在环境是特定的国产加速卡或服务器环境,例如热门词里提到的昇腾 910B 等,vLLM 启动 embedding 模型时可能遇到兼容性问题。从通用实践看,vLLM 的推理后端对 embedding 模型支持并不像一个标准的 chat 模型那样通用,遇到这类情况优先查阅对应版本的官方文档,确认该版本是否支持 embedding 模型,必要时换用 sentence-transformers 或独立部署 embedding 服务。

4. 动手拆解:Embedding + 向量数据库 + RAG

4.1 数据准备:如何加载文档并切分

RAG 链路的第一步是文档加载。常见做法是读取本地目录里的 txt、md、pdf 等文件。

from langchain_community.document_loaders import DirectoryLoader, TextLoader from langchain.text_splitter import RecursiveCharacterTextSplitter loader = DirectoryLoader( "./docs", glob="**/*.md", loader_cls=TextLoader, loader_kwargs={"encoding": "utf-8"} ) documents = loader.load() splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50 ) chunks = splitter.split_documents(documents) print(f"文档块数量: {len(chunks)}")

这段代码里chunk_size和chunk_overlap是 RAG 效果的重要参数。块太小会丢失上下文,块太大检索噪声高。一般来说,500 到 800 字是常见起点,具体要看你的文档类型。如果涉及 3GPP 协议、法律合同这类专业长文档,建议用更结构化的切分策略,先按章节标题切,再按段落切。

4.2 向量化并写入向量数据库

材料里出现了 ChromaDB、Milvus、Qdrant、PGVector 等多个向量数据库热词。从 0 到 1 最省事的是 ChromaDB,单机嵌入式,不需要额外起服务。

from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_community.vectorstores import Chroma embedding_model = HuggingFaceEmbeddings( model_name="BAAI/bge-small-zh-v1.5", model_kwargs={"device": "cpu"} ) vectorstore = Chroma.from_documents( documents=chunks, embedding=embedding_model, persist_directory="./chroma_db" ) print("向量库写入完成")

这里 model_name 需要替换成你实际能下载到的模型。bge-small-zh-v1.5是一个常见中文 Embedding 模型,但模型版本会更新,实际使用时以你拉取到的模型为准。如果你打算用 Milvus、Qdrant 或 PGVector,思路一样:初始化向量库客户端,替换Chroma为对应类即可。

4.3 检索测试:看召回是否合理

不要急着写回答生成,先单独测试检索。这一步能帮你尽早发现知识库问题。

question = "报销流程是什么?" results = vectorstore.similarity_search_with_score(question, k=5) for doc, score in results: print(f"相似度: {score:.4f}") print(doc.page_content) print("---")

判断标准很简单:检索出来的片段是否真的和问题相关。如果相关片段排在最前面,说明 Embedding 和切分策略基本可用;如果完全不相关,问题可能出在模型选型、数据切分或文档噪音上。

4.4 组装 RAG 回答链路

检索没问题之后,再让 LLM 基于检索结果生成回答。

from langchain_openai import ChatOpenAI from langchain.prompts import ChatPromptTemplate from langchain_core.runnables import RunnablePassthrough llm = ChatOpenAI( model="qwen2.5:7b", # 按你实际用的模型服务调整 base_url="http://127.0.0.1:11434/v1", # Ollama 默认 OpenAI 兼容地址 api_key="EMPTY", temperature=0.2 ) retriever = vectorstore.as_retriever(search_kwargs={"k": 5}) prompt = ChatPromptTemplate.from_messages([ ("system", "你是一个基于知识库回答问题的助手。只使用下面检索到的内容回答,如果内容不足以回答,请如实说明。"), ("human", "检索片段:\n{context}\n\n问题:{question}") ]) rag_chain = ( {"context": retriever, "question": RunnablePassthrough()} | prompt | llm ) answer = rag_chain.invoke("报销流程是什么?") print(answer.content)

注意base_url和api_key需要按你的模型服务调整。Ollama 是常见本地模型启动方式之一,它提供的接口兼容 OpenAI 格式,所以ChatOpenAI可以接入;如果用 vLLM 启动模型,同理替换为 vLLM 服务的地址。

5. 如何判断 RAG 质量:别只看“答得对不对”

热门词里有一个问题:“RAG 知识库指标有哪些,如何理解各指标”。这部分内容比较核心,单独提出来讲。

RAG 的质量可以拆成两段:检索质量和生成质量。

5.1 检索质量指标

指标含义怎么理解
Recall@K前 K 个检索结果中,相关文档占全部相关文档的比例越高越好,说明没漏掉关键内容
Precision@K前 K 个检索结果中,相关文档的比例越高越好,说明检索噪声低
MRR第一个相关结果出现的位置越高越好,说明用户最快看到正确答案
Hit Rate是否有相关结果出现在前 K 个评估用户是否能检索到正确答案

5.2 生成质量指标

生成质量不能用单一数字衡量。常见做法是:构建一个测试集(问题、标准答案、参考来源),用 LLM 作为裁判进行评估,或者人工抽检。

指标含义
忠实度回答是否完全基于检索片段,避免幻觉
相关性回答是否直接回应了用户问题
完整性关键信息是否都覆盖
引用正确性回答引用的来源是否真的支撑了对应内容

5.3 提高 RAG 质量的实操顺序

  1. 先看检索结果,再做生成优化。检索不对,Prompt 写得再好也没用。
  2. 优化文档切分。按文档结构切比固定字数切通常更有效。
  3. 换个 Embedding 模型试试。不用迷信大模型,Embedding 模型对检索影响很大。
  4. 加入查询改写。用户问题太口语化时,先让 LLM 把问题改写成更利于检索的表述。
  5. 建立测试集。每次改动之后跑一遍测试集,用指标看是变好还是变差。

6. Agent 与工具调用:让模型不只“会聊天”

跑通 RAG 之后,再来看 Agent。Agent 解决的是“模型需要外部动作才能完成任务”的场景,比如查数据库、查天气、调用内部 API、执行代码。

6.1 React Agent 的最小实现

LangChain 里 Agent 的最小写法通常包含:LLM、工具列表、Agent 执行器。

from langchain.agents import create_tool_calling_agent, AgentExecutor from langchain.tools import tool from langchain_core.prompts import ChatPromptTemplate @tool def get_service_status(service_name: str) -> str: """查询指定服务的当前状态,例如 'auth-service'。""" # 这里替换成真实的内部 API 调用或数据库查询 return f"{service_name} 状态正常,最近 5 分钟无错误日志。" tools = [get_service_status] prompt = ChatPromptTemplate.from_messages([ ("system", "你是自动化运维助手。根据需要调用工具。"), ("human", "{input}"), ("placeholder", "{agent_scratchpad}") ]) agent = create_tool_calling_agent(llm, tools, prompt) agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) result = agent_executor.invoke({"input": "帮我查一下 auth-service 的状态"}) print(result["output"])

这段代码是关键模式:@tool装饰器把普通函数变成 Agent 可调用的工具。工具的描述信息很重要,模型靠描述决定什么时候调用哪个工具。描述不清晰,工具就不会被正确调用。

6.2 工具设计原则

  • 工具描述要写清楚“什么时候用”和“返回什么”。
  • 工具参数越少越好,减少模型填错参数的概率。
  • 工具内部要做好异常处理,返回给模型的必须是可读的结果,不是堆栈。
  • 敏感操作要加确认步骤,不要直接把删除、写库、支付之类的动作暴露给模型。

6.3 LangChain 还是 LangGraph

热词里频繁出现的“langgraph 和 langchain 的区别”,从选型角度给你一个判断依据:

  • 如果你的流程是“用户提问 -> 检索 -> 生成”,用 LangChain 的链式调用就够。
  • 如果你的流程包含循环、多分支、定时重试、人工审批,用 LangGraph 更合适。
  • Agent 流程复杂之后,状态管理会变成痛点,LangGraph 能把每一步的状态和流转显式表达出来。
  • 第一次做 Agent 项目,先用 LangChain 快速验证,不要一上来就引入图框架。

顺带回应另一个热词:“langchain 过时了吗”。从社区活跃度和生态看,LangChain 仍然是文档最全、资料最多的框架之一。它适合做快速原型和标准链路。真正“过时”的说法主要来自复杂生产项目对性能和状态管理的高要求,那是 LangGraph 或其他更轻量框架的适用场景,不代表 LangChain 没有价值。

7. 接口 API 与批量任务

从 0 到 1 的项目,最终都要面对“怎么给别人用”。建议把 RAG 和 Agent 都封装成 FastAPI 接口,再批量处理文档。

7.1 FastAPI 封装

from fastapi import FastAPI from pydantic import BaseModel app = FastAPI(title="RAG Service") class QueryRequest(BaseModel): question: str top_k: int = 5 class QueryResponse(BaseModel): answer: str sources: list[str] @app.post("/rag/query", response_model=QueryResponse) def rag_query(req: QueryRequest): docs = retriever.get_relevant_documents(req.question) answer = rag_chain.invoke(req.question) return QueryResponse( answer=answer.content, sources=[doc.page_content for doc in docs] ) @app.get("/health") def health(): return {"status": "ok"}

启动服务:

uvicorn app:app --host 0.0.0.0 --port 8000

7.2 用 Python 调用接口做批量测试

批量任务的核心是控制并发和记录日志。不要一次性把几千个请求全部打进去,先小批量测试。

import requests import time import json url = "http://127.0.0.1:8000/rag/query" questions = [ "报销流程是什么?", "如何申请假期?", "渠道合作邮件怎么写?" ] results = [] for q in questions: try: resp = requests.post(url, json={"question": q}, timeout=60) result = resp.json() results.append({"question": q, "answer": result["answer"]}) print(f"成功: {q}") except Exception as e: results.append({"question": q, "error": str(e)}) print(f"失败: {q}, 错误: {e}") time.sleep(0.5) with open("batch_results.json", "w", encoding="utf-8") as f: json.dump(results, f, ensure_ascii=False, indent=2)

7.3 批量文档导入

生产环境常见做法是用任务队列(如 Celery)处理文档导入:接收文件 -> 切分 -> 向量化 -> 写入向量库 -> 更新索引。小项目可以简单点,用目录扫描加日志记录:

# 伪代码示例,实际路径需按项目调整 python ingest.py --input ./documents --output ./chroma_db --chunk-size 500

建议每个文档写入后记录对应doc_id,这样后续可以按文档维度更新或删除向量,避免“只能加不能删”的尴尬。

8. 资源占用与性能观察

这一节重点讲怎么看资源占用,而不是给你一个固定的显存数字。因为实际占用取决于 Embedding 模型、LLM 大小、量化方式、并发数等,必须落到你的具体环境上看。

8.1 观察方法

# 查看 GPU 显存占用 nvidia-smi -l 1 # 查看 CPU 和内存 htop # Python 进程内存 ps aux | grep python

8.2 性能影响因子

因素影响方向
Embedding 模型尺寸越大越准,但向量化速度变慢,CPU 上更明显
LLM 参数量和量化位宽直接影响显存占用和推理速度
chunk_size越大上下文信息越多,但检索和生成 token 开销增加
top_k越大召回越多,但 Prompt 变长,首 token 延迟增加
并发请求影响吞吐量,但可能触发显存溢出或排队超时

8.3 降低资源占用的思路

  • 如果 Embedding 和 LLM 都在本机 GPU 上跑,显存容易紧张。可以把 Embedding 放到 CPU,推理放在 GPU。
  • LLM 优先选 4-bit 量化版本,用 Ollama 或 vLLM 加载时指定量化参数。
  • 批量向量化时用 batch size 控制峰值显存。
  • 接口服务设置超时和并发上限,避免资源被个别慢请求占满。

8.4 关于 vLLM 与 Embedding 的常见限制

热词里出现了“通过 vLLM 启动 embedding 向量和 reranker 模型”的疑问。这里补充一个通用认知:vLLM 的服务目标主要面向生成模型,对 embedding 和 reranker 模型的支持不是它最核心的能力。在不同硬件、不同版本下,能不能用 vLLM 启动 embedding 模型,表现不一致。如果你在某个服务器上遇到这类问题,更稳妥的方案是:

  • Embedding 模型单独用 sentence-transformers 启动,提供 HTTP 接口。
  • Reranker 模型同样单独部署服务,或直接跳过。
  • 生成模型继续用 vLLM,两者互不干扰。

这样能避免一个框架承载所有模型类型的兼容性风险。

9. 常见问题与排查方法

问题现象可能原因排查方式解决方案
依赖安装失败Python 版本过老或新、包名变更查看完整错误堆栈,确认是网络问题还是版本冲突升级 Python 到 3.9+;换用国内镜像源;锁定版本
向量库写入后检索结果为空Embedding 模型加载失败或切分后文档块为空打印 chunks 数量和向量库统计检查文档读取路径和编码;确认文档不是空文件
检索结果相关度差Embedding 模型选型不当或 chunk_size 不合适单独跑相似度检索,人工检查召回换 Embedding 模型;调整切分参数
接口调用超时LLM 推理慢或请求队列堆积在日志里看单次推理耗时降低并发;换更小的模型;启用流式输出
显存不足模型过大或并发过高观察 nvidia-smi 峰值换量化模型;降低 batch 并发;Embedding 放 CPU
Agent 不调用工具工具描述不清晰或模型不支持工具调用检查 verbose 日志中模型输出改写工具描述;换支持 function call 的模型
批量任务卡住单个请求无超时或循环逻辑里依赖失败加日志,定位卡在哪一步所有请求加 timeout;任务加失败重试和死信标记
回答产生幻觉检索片段不完整或 Prompt 约束不足把实际 Prompt 打出来检查加强 Prompt 限制;提高 top_k;增加引用来源
端口被占用上次服务未退出或其他进程占用端口lsof -i:8000或netstat -ano查看换端口或清理旧进程
模型服务地址不对导致 401/404base_url 或 api_key 配错先用 curl 直接请求模型服务测试核对模型服务文档;测试后再接 LangChain

10. 最佳实践与使用建议

  • 第一个版本用最小配置跑通。先不用管性能和多轮对话,把“文档 -> 向量库 -> 检索 -> 回答 -> 接口”这条链路完整走一遍。
  • 统一目录结构。模型下载目录、文档目录、向量库目录、日志目录分开管理,后续更新和排查会省很多时间。
  • 每次修改都建立基线测试集。无论是调 Prompt、换 Embedding 还是改切分参数,都用同一组问题跑结果,对比之后再上线。
  • 批次任务一定要加日志和失败重试机制。没有日志的批处理任务出问题时,定位成本会翻倍。
  • 接口服务不要直接暴露到公网。有公网访问需求时,务必加鉴权、限流和来源 IP 限制。
  • 涉及私有数据、用户信息、公司制度文档时,确认数据使用范围和合规边界。不能确认来源的文档不要进入知识库。
  • 涉及人脸、声音、姓名等个人敏感信息的内容,在采集、存储、生成、分发前必须确认授权,遵守当地法规和平台规则。
  • 商用发布前,对 Agent 的自动动作做权限最小化设计。不要给模型调用删除、支付、发布等高危操作的能力。
  • 上线后持续抽检真实问题。RAG 不是一次配置就永久有效的系统,文档更新、用户问题分布变化都会影响效果。

11. 总结与下一步

从 0 到 1 搭建大模型应用项目,真正的难点不是某个算法,而是把 Embedding、向量数据库、RAG、LangChain、Agent 工具调用这条链路串起来之后,还能稳定、可排查、可迭代。

这篇文章最值得你记住的路线是:先跑通文档加载和切分,再验证向量检索召回,再组装 RAG 回答链路,最后封装 API 和批量任务。Agent 放在 RAG 之后做,因为工具调用的前提是模型对一个领域有足够理解,而 RAG 正好能给它提供这种理解。

最先应该验证的功能,不是一段华丽的多轮对话,而是“检索出的内容是否足够回答问题”。这一步能帮你提前排除 Embedding 选型、切分策略和文档清洗的问题。

最容易踩的坑有三类:一是 Embedding 模型和 LLM 混为一谈,用同一个模型服务启动所有功能;二是不做检索质量评估,直接调 Prompt,效果反复横跳;三是一上来就追 LangGraph 和复杂 Agent 架构,流程还没跑通就把自己绕进去。

后续可以继续扩展的方向包括:用 LangGraph 处理有状态的多智能体协作、引入 Reranker 提升检索精度、用评估框架给 RAG 建立自动化测试集、针对专业领域(如协议文档、法律文书)做结构化切分和知识抽取。

建议你先照着第 4 节的代码,拿自己手头的文档跑一遍最小链路。跑通之后,再回头决定要加 Agent、换向量库还是接入生产环境。这套链路只要起过一次,后面扩展都是增量工作。

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

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

立即咨询