logo

实战二:RAG 知识库助手

很多 Agent 项目到最后都绕不开 RAG。原因很直接:模型再强,也不会天然知道你公司的制度、项目文档、会议纪要和内部流程。

如果你不把这些知识接进来,Agent 很容易表现得“很会说”,但一问到具体业务细节就开始泛化回答,甚至直接编。

这一节我们做一个简化版 HR 助手。它不追求花哨,只追求把最基础的 RAG 闭环看清楚。

[PROMPT_LAB_BANNER]


1. 先理解这件事到底在解决什么

RAG 本质上不是“让模型更聪明”,而是给模型补一个受控的外部知识层。

它解决的是下面这类问题:

  • 回答必须基于公司内部文档
  • 内容会变,不能只靠预训练知识
  • 用户问的是具体政策,不允许随口发挥

一个最小 RAG 流程大概是这样:

sequenceDiagram
    participant User
    participant Agent (Chain)
    participant Retriever
    participant VectorDB
    participant LLM
    
    User->>Agent: "能报销请客吃饭吗?"
    Agent->>Retriever: Invoke
    Retriever->>VectorDB: 语义搜索 (Similarity Search)
    VectorDB-->>Retriever: 返回文档片段 (Context)
    Retriever-->>Agent: Context
    Agent->>LLM: Prompt + Context + Question
    LLM-->>Agent: "根据规定,上限 $50..."
    Agent-->>User: 最终回答

2. 技术栈

  • LangChain:用来快速把检索和生成接起来
  • ChromaDB:本地向量数据库,适合实验和原型
  • 任意支持 embeddings + chat 的模型:用于向量化和最终生成
pip install langchain langchain-chroma langchain-openai

3. 准备知识库(Indexing)

假设我们有一个很小的 handbook.txt

公司规定:

  1. 年假:入职满一年有 10 天年假。
  2. 病假:需提供医生证明,全薪。
  3. 报销:餐饮报销上限为每人每餐 $50,需发票。
from langchain_community.document_loaders import TextLoader
from langchain_text_splitters import CharacterTextSplitter
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings

# 1. 加载文档
loader = TextLoader("./handbook.txt")
documents = loader.load()

# 2. 切分 (Chunking)
text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0)
docs = text_splitter.split_documents(documents)

# 3. 存入向量数据库
db = Chroma.from_documents(docs, OpenAIEmbeddings())

4. 构建检索链(Retrieval Chain)

入库之后,下一步才是让系统“会查”。

这里有个关键点经常被忽略:RAG 并不是把知识塞给模型就结束了,而是要在回答前先判断“应该查什么、查回来哪些片段、这些片段够不够回答当前问题”。

from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

llm = ChatOpenAI(model="gpt-4o")

# 定义 Prompt,明确要求基于 Context 回答
prompt = ChatPromptTemplate.from_template("""
你是一个 HR 助手。请基于下面的 Context 回答用户问题。
如果你不知道,就说不知道。

Context:
{context}

Question:
{input}
""")

# 创建 "文档合并链" (把检索到的片段塞进 Prompt)
combine_docs_chain = create_stuff_documents_chain(llm, prompt)

# 创建 "检索链" (连接 DB 和 LLM)
retriever = db.as_retriever()
rag_chain = create_retrieval_chain(retriever, combine_docs_chain)

这段示例能跑,但你在真实项目里最好再多做两件事:

  1. 明确要求“找不到就说不知道”,不要自由发挥。
  2. 让模型尽量引用或转述检索结果,而不是脱离 context 自己补完整答案。

5. 运行与测试

response = rag_chain.invoke({"input": "我刚入职,请朋友吃饭花了 80 块,能报销吗?"})
print(response["answer"])

预期回答

不能全额报销。根据公司规定,餐饮报销上限为每人每餐 $50。

这个例子看起来简单,但已经足够暴露出 RAG 最关键的判断点:

  • 检索有没有真的把“餐饮报销上限 $50”这段找出来
  • 模型有没有基于这段回答
  • 模型会不会看到“80 块”之后又开始自己发挥解释

如果你线上发现回答不稳定,优先拆这三层看,不要一上来就改 prompt。


6. 进阶:把 RAG 变成一个 Tool

上面的 rag_chain 还只是一个知识问答组件。如果你想把它放进更完整的 Agent 里,比如:

  • 先查政策
  • 再给用户总结
  • 必要时帮用户生成申请邮件

那你就不能把 RAG 只当成一个页面功能,而要把它包装成一个可调用的工具。

from langchain.tools.retriever import create_retriever_tool

retriever_tool = create_retriever_tool(
    retriever,
    "search_company_policy",
    "搜素公司关于请假、报销等行政规定的政策文档"
)

# 现在这个 tool 可以和其他 tool 一起给 Agent 使用了
tools = [retriever_tool, send_email_tool, ...]

一旦走到这一步,RAG 就从“一个知识库功能”变成了“Agent 的一项能力”。


7. 真实项目里 RAG 最容易出问题的地方

Chunk 切分不合理

切得太大,召回准确但浪费上下文;切得太碎,模型拿到一堆零散句子,难以理解完整含义。

这通常不是理论问题,而是非常实际的效果问题。很多“RAG 不准”,最后都是 chunk 策略有问题。

Embedding 和文档更新不同步

文档改了,但索引没更新,Agent 就会把旧制度当新制度回答。

这在内部知识库系统里特别危险,因为回答看起来很像真的。

检索到了,但没用对

有些系统明明把正确片段找回来了,结果模型回答时还是带上了自己的常识补充。你最后看到的表象是“RAG 查到了但回答还是不准”。

这时候要看的是:

  • prompt 约束够不够
  • 上下文是不是太长,正确片段被淹没了
  • 模型是否被要求区分“已知”和“推测”

权限没做好

这是最不能忽视的一点。

如果你把所有文档一股脑都向量化,检索时又不做权限过滤,普通员工就可能问到本不该看到的内容。RAG 的权限控制必须做在检索层,而不是只靠最终回答层来“自觉克制”。


8. 一个更像生产环境的升级方向

如果你准备把这个实验继续做深,可以按这个顺序升级:

  1. 换成真实的多文档知识库,而不是单个 handbook.txt
  2. 增加 metadata,比如文档类型、部门、更新时间、权限级别
  3. 在检索前做 query rewrite,让用户问题更适合搜索
  4. 加 rerank,把召回结果重新排序
  5. 给最终回答加引用来源,方便核对

做到这里,RAG 才会慢慢从 demo 走向可用系统。


小结

RAG 最值得掌握的,不是那几个术语,而是整条链路怎么拆开看:

  • Indexing:知识怎么入库
  • Retrieval:该找哪段内容
  • Generation:回答是否真的基于检索结果
  • Toolification:怎么把检索能力接进更大的 Agent 系统

只要你把这四层分清楚,很多“RAG 不准”的问题其实都能定位。

AI Agent 开发实战手册
AI Engineer

AI Agent 开发实战手册

从 0 到 1 掌握 AI Agent 开发:涵盖自主计划、工具调用、MCP 协议与多智能体编排实战。

AI Agent 开发实战手册实战二:RAG 知识库助手

实战二:RAG 知识库助手

很多 Agent 项目到最后都绕不开 RAG。原因很直接:模型再强,也不会天然知道你公司的制度、项目文档、会议纪要和内部流程。

如果你不把这些知识接进来,Agent 很容易表现得“很会说”,但一问到具体业务细节就开始泛化回答,甚至直接编。

这一节我们做一个简化版 HR 助手。它不追求花哨,只追求把最基础的 RAG 闭环看清楚。

Prompt Lab

把这章的知识,直接变成实战能力

进入交互式实验室,用真实任务练 Prompt,10 分钟快速上手。

进入 Prompt Lab →

#1. 先理解这件事到底在解决什么

RAG 本质上不是“让模型更聪明”,而是给模型补一个受控的外部知识层。

它解决的是下面这类问题:

  • 回答必须基于公司内部文档
  • 内容会变,不能只靠预训练知识
  • 用户问的是具体政策,不允许随口发挥

一个最小 RAG 流程大概是这样:

sequenceDiagram participant User participant Agent (Chain) participant Retriever participant VectorDB participant LLM User->>Agent: "能报销请客吃饭吗?" Agent->>Retriever: Invoke Retriever->>VectorDB: 语义搜索 (Similarity Search) VectorDB-->>Retriever: 返回文档片段 (Context) Retriever-->>Agent: Context Agent->>LLM: Prompt + Context + Question LLM-->>Agent: "根据规定,上限 $50..." Agent-->>User: 最终回答

#2. 技术栈

  • LangChain:用来快速把检索和生成接起来
  • ChromaDB:本地向量数据库,适合实验和原型
  • 任意支持 embeddings + chat 的模型:用于向量化和最终生成
bash
pip install langchain langchain-chroma langchain-openai

#3. 准备知识库(Indexing)

假设我们有一个很小的 handbook.txt

公司规定:

  1. 年假:入职满一年有 10 天年假。
  2. 病假:需提供医生证明,全薪。
  3. 报销:餐饮报销上限为每人每餐 $50,需发票。
python
from langchain_community.document_loaders import TextLoader from langchain_text_splitters import CharacterTextSplitter from langchain_chroma import Chroma from langchain_openai import OpenAIEmbeddings # 1. 加载文档 loader = TextLoader("./handbook.txt") documents = loader.load() # 2. 切分 (Chunking) text_splitter = CharacterTextSplitter(chunk_size=100, chunk_overlap=0) docs = text_splitter.split_documents(documents) # 3. 存入向量数据库 db = Chroma.from_documents(docs, OpenAIEmbeddings())

#4. 构建检索链(Retrieval Chain)

入库之后,下一步才是让系统“会查”。

这里有个关键点经常被忽略:RAG 并不是把知识塞给模型就结束了,而是要在回答前先判断“应该查什么、查回来哪些片段、这些片段够不够回答当前问题”。

python
from langchain.chains import create_retrieval_chain from langchain.chains.combine_documents import create_stuff_documents_chain from langchain_core.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI llm = ChatOpenAI(model="gpt-4o") # 定义 Prompt,明确要求基于 Context 回答 prompt = ChatPromptTemplate.from_template(""" 你是一个 HR 助手。请基于下面的 Context 回答用户问题。 如果你不知道,就说不知道。 Context: {context} Question: {input} """) # 创建 "文档合并链" (把检索到的片段塞进 Prompt) combine_docs_chain = create_stuff_documents_chain(llm, prompt) # 创建 "检索链" (连接 DB 和 LLM) retriever = db.as_retriever() rag_chain = create_retrieval_chain(retriever, combine_docs_chain)

这段示例能跑,但你在真实项目里最好再多做两件事:

  1. 明确要求“找不到就说不知道”,不要自由发挥。
  2. 让模型尽量引用或转述检索结果,而不是脱离 context 自己补完整答案。

#5. 运行与测试

python
response = rag_chain.invoke({"input": "我刚入职,请朋友吃饭花了 80 块,能报销吗?"}) print(response["answer"])

预期回答

不能全额报销。根据公司规定,餐饮报销上限为每人每餐 $50。

这个例子看起来简单,但已经足够暴露出 RAG 最关键的判断点:

  • 检索有没有真的把“餐饮报销上限 $50”这段找出来
  • 模型有没有基于这段回答
  • 模型会不会看到“80 块”之后又开始自己发挥解释

如果你线上发现回答不稳定,优先拆这三层看,不要一上来就改 prompt。


#6. 进阶:把 RAG 变成一个 Tool

上面的 rag_chain 还只是一个知识问答组件。如果你想把它放进更完整的 Agent 里,比如:

  • 先查政策
  • 再给用户总结
  • 必要时帮用户生成申请邮件

那你就不能把 RAG 只当成一个页面功能,而要把它包装成一个可调用的工具。

python
from langchain.tools.retriever import create_retriever_tool retriever_tool = create_retriever_tool( retriever, "search_company_policy", "搜素公司关于请假、报销等行政规定的政策文档" ) # 现在这个 tool 可以和其他 tool 一起给 Agent 使用了 tools = [retriever_tool, send_email_tool, ...]

一旦走到这一步,RAG 就从“一个知识库功能”变成了“Agent 的一项能力”。


#7. 真实项目里 RAG 最容易出问题的地方

#Chunk 切分不合理

切得太大,召回准确但浪费上下文;切得太碎,模型拿到一堆零散句子,难以理解完整含义。

这通常不是理论问题,而是非常实际的效果问题。很多“RAG 不准”,最后都是 chunk 策略有问题。

#Embedding 和文档更新不同步

文档改了,但索引没更新,Agent 就会把旧制度当新制度回答。

这在内部知识库系统里特别危险,因为回答看起来很像真的。

#检索到了,但没用对

有些系统明明把正确片段找回来了,结果模型回答时还是带上了自己的常识补充。你最后看到的表象是“RAG 查到了但回答还是不准”。

这时候要看的是:

  • prompt 约束够不够
  • 上下文是不是太长,正确片段被淹没了
  • 模型是否被要求区分“已知”和“推测”

#权限没做好

这是最不能忽视的一点。

如果你把所有文档一股脑都向量化,检索时又不做权限过滤,普通员工就可能问到本不该看到的内容。RAG 的权限控制必须做在检索层,而不是只靠最终回答层来“自觉克制”。


#8. 一个更像生产环境的升级方向

如果你准备把这个实验继续做深,可以按这个顺序升级:

  1. 换成真实的多文档知识库,而不是单个 handbook.txt
  2. 增加 metadata,比如文档类型、部门、更新时间、权限级别
  3. 在检索前做 query rewrite,让用户问题更适合搜索
  4. 加 rerank,把召回结果重新排序
  5. 给最终回答加引用来源,方便核对

做到这里,RAG 才会慢慢从 demo 走向可用系统。


#小结

RAG 最值得掌握的,不是那几个术语,而是整条链路怎么拆开看:

  • Indexing:知识怎么入库
  • Retrieval:该找哪段内容
  • Generation:回答是否真的基于检索结果
  • Toolification:怎么把检索能力接进更大的 Agent 系统

只要你把这四层分清楚,很多“RAG 不准”的问题其实都能定位。

常见问题

开发 AI Agent 需要掌握哪些编程语言?
首选 Python 或 TypeScript。Python 是 AI 生态的基石,而 TypeScript 在开发 MCP Server 和网页端交互时效率极高。借助 Cursor 等 AI 原生编辑器,编程门槛已大幅降低。
MCP 协议目前支持哪些模型?
MCP 是开放协议,目前对 Claude 3.5 系列支持最完美。通过 MCP Proxy,GPT-4o 和 Gemini 也可以间接访问 MCP Server 数据源。
AI Agent 会导致程序员失业吗?
不会,但会改变程序员的工作内容。未来的开发者将从“写代码”转向“管理 Agent 团队”,重点在于系统架构设计、复杂逻辑校验和 Agent 的提示词优化。