AI 学习进阶实战 · 更新于 2026年10月7日 · 15 分钟阅读

RAG 实战:从零搭建企业私有知识库

RAG 实战:从零搭建企业私有知识库
本文目录

如果你是产品经理、运营、技术支持。

大概率有过这种痛点:公司内部文档散落在 Confluence、飞书、Notion、Google Drive、邮件附件里,新人问个问题。

要么翻半天找不到答案,要么找到的答案是过时版本。

如果能让 AI 直接基于公司内部知识回答问题,效率会大幅提升。

RAG(Retrieval-Augmented Generation,检索增强生成),正是解决这个问题的核心技术。

2026 年,RAG 已经从 AI 工程领域的”前沿技术”变成”必备技能”——大多数企业 AI 应用都是 RAG 系统:智能客服、内部知识库、销售助手。

文档摘要、合同审查、HR 答疑。

本质上,90% 的”AI + 企业”项目都是 RAG。

这篇文章就是带你”从零到一”——跟着走一遍,30 分钟你能搭出一个能用的企业私有知识库问答系统。

能查你的 PDF、能查飞书文档、能查 Notion 页面,回答问题时引经据典、不胡说八道。

一、RAG 到底是什么:从名字开始讲

RAG 全称是 Retrieval-Augmented Generation,中文叫”检索增强生成”。这个名字其实已经把原理讲清楚了——三步走:三步走里,你现在走到第几步了?

  1. 检索(Retrieval):用户提问时,先从知识库里搜出最相关的几段内容
  2. 增强(Augmented):把搜出来的内容作为上下文,塞给 LLM
  3. 生成(Generation):LLM 基于这些上下文,生成最终答案

为什么需要 RAG?因为 LLM 有两个根本局限:

  • 不知道公司内部信息:LLM 是用公开数据训练的,不可能知道你们公司的产品文档、内部制度、技术方案
  • 知识有时间戳:LLM 的训练数据有截止时间,2025 年之后的事件它不知道,公司新发布的产品它也不知道

RAG 的核心思想是:LLM 不需要”记住”所有信息,只需要给它”对的资料”,它就能”现场学习”然后回答。

一个直观的比喻:RAG 就像给 LLM 配了一个”开卷考试”——LLM 本来要靠记忆答题,有了 RAG,可以让它”翻书”找答案。

然后基于找到的内容作答。

这种模式让 LLM 从”死记硬背”变成”活学活用”。

RAG vs Fine-tuning:为什么选 RAG 不是微调

你可能听说过另一种给 LLM 喂专有知识的方式——微调(Fine-tuning)。这两种方案经常被拿来对比。简明区分:

维度 RAG Fine-tuning
知识更新成本 重新摄入文档,几小时 重新训练,几天 + 几千美元
适合场景 文档常变、量大、要求可追溯 固定领域术语、风格转换
可追溯性 每条答案能追溯来源 黑盒,LLM 内部權重变化
成本 中(检索 + LLM 调用) 高(训练 + 推理)
起步门槛 低(几小时跑通) 高(需要数据 + 训练)

对多数企业内部知识库场景,RAG 是首选:文档会持续更新、知识量大、要求”每个答案有出处”。

只有少数场景(比如客服语言风格统一、特定专业术语)Fine-tuning 价值更高。

二、环境准备:5 分钟搞定

我们用 Python + LangChain + Chroma 这套成熟组合搭一个 RAG 系统。这套组合的优势是:

  • 纯 Python,跨平台
  • 不依赖云服务,本地跑通
  • 生态丰富,扩展容易

步骤 1:装依赖

mkdir my-rag && cd my-rag
python -m venv venv
source venv/bin/activate
pip install langchain langchain-community langchain-openai \
chromadb pypdf tiktoken

依赖说明:

  • langchain:RAG 编排框架
  • langchain-community:各种文档加载器(Notion、飞书、PDF 等)
  • langchain-openai:OpenAI 模型(也支持 Claude 等)
  • chromadb:本地向量数据库(免登录、纯本地)
  • pypdf:读 PDF
  • tiktoken:Token 计数

需要注意的安装踩坑:如果你在中国,OpenAI embedding API 可能在网络上是连不上的。

这种情况有两个选择:换 Sentence-Transformers 这种开源 embedding 模型(pip install sentence-transformers),或者用国内提供的云服务(阿里云 DashScope、智谱、DeepSeek 都有 embedd

ing 接口)。

本教程后文的 OpenAI 代码都可用国产模型的 embedding 接口替换。换国产接口你试过吗?

只需改一行 embeddings = HuggingFaceEmbeddings(...) 即可。

步骤 2:配 API key

建 .env 文件:

OPENAI_API_KEY=***

后面会用到 embedding 和 LLM 两个 OpenAI 接口,一个 key 搞定。

步骤 3:准备一份文档

放一个 docs/ 目录,把你公司的产品介绍、用户手册、技术文档都丢进去。RAG 系统会扫描这个目录,把所有文档处理成”知识库”。

到这里准备就绪。下面写代码。

三、最简单的 RAG:30 行核心代码

我们的第一版 RAG 系统,极简但已经能用。新建 simple_rag.py:

from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings, ChatOpenAI
from langchain_community.vectorstores import Chroma
from langchain.chains import RetrievalQA
# 1. 加载文档
loader = TextLoader(“docs/product_intro.txt”)
documents = loader.load()
# 2. 切分文档
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, chunk_overlap=50
)
chunks = text_splitter.split_documents(documents)
# 3. 向量化并存到向量数据库
embeddings = OpenAIEmbeddings(model=”text-embedding-3-small”)
vectorstore = Chroma.from_documents(chunks, embeddings)
# 4. 创建 LLM
llm = ChatOpenAI(model=”gpt-4o-mini”, temperature=0)
# 5. 创建 RAG 链
qa = RetrievalQA.from_chain_type(
llm=llm,
retriever=vectorstore.as_retriever(search_kwargs={“k”: 3}),
return_source_documents=True,
)
# 6. 提问
result = qa.invoke({“query”: “我们的产品有什么特点?”})
print(“答案:”, result[“result”])
print(“\n来源:”)
for i, doc in enumerate(result[“source_documents”]):
print(f” [{i+1}] {doc.page_content[:100]}…”)

跑一下 python simple_rag.py,你会看到:

  1. 系统读取你的 product_intro.txt
  2. 自动切分成多个段落
  3. 每段生成向量
  4. 用户提问时,先向量搜索找到最相关的 3 段
  5. 把这 3 段塞给 GPT-4o-mini
  6. LLM 生成答案

这就是 RAG 最基础的形态。整个代码 30 行,已经能做企业内部知识问答。

进阶:多文件摄入 + 增量更新

上面代码只吃一个 txt。真实场景里,你会吃整个目录下的所有文档,并且会增量更新(而非重头跑一遍)。这是企业级 RAG 的标配:

from pathlib import Path
import hashlib
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
vectorstore = Chroma(persist_directory=”./chroma”, embedding_function=OpenAIEmbeddings())
def file_hash(path: Path) -> str:
“””计算文件 hash,作为是否更新过的依据”””
return hashlib.md5(path.read_bytes()).hexdigest()
existing_meta = {m[“hash”]: m[“id”] for m in vectorstore.get()[“metadatas”] if m and “hash” in m}
for path in Path(“docs”).rglob(“*”):
if path.suffix not in [“.pdf”, “.txt”, “.md”, “.docx”]:
continue
h = file_hash(path)
if h in existing_meta:
print(f”跳过(未改动): {path}”)
continue
# 读取、切除、入库
docs = load_document(path)
vectorstore.add_documents(docs, metadatas=[{“source”: str(path), “hash”: h}])
print(f”已入库: {path}”)

第二次跑这个脚本时,改动过的文件会自动重入库,没动过的自动跳过。这是一个企业文档高频更新的常见模式。

四、加文档摄入:让 RAG 能查真实业务文档

上面的示例只能读纯文本。真实企业场景里,文档是多种格式的——PDF、Word、Notion、飞书文档。

LangChain 提供了几十种文档加载器,挑几个常用的:

加载 PDF

from langchain_community.document_loaders import PyPDFLoader
loader = PyPDFLoader(“docs/manual.pdf”)
pages = loader.load_and_split()

pages 是个列表,每个元素是一页的内容。这是 LangChain 把整本 PDF 切成多页的方式。

加载 Notion

from langchain_community.document_loaders.notion import NotionDBLoader
loader = NotionDBLoader(
integration_token=”secret_xxx”,
database_id=”你的 Notion DB ID”,
)
docs = loader.load()

需要 Notion Integration Token。

加载飞书文档

from langchain_community.document_loaders.feishu import FeishuLoader
loader = FeishuLoader(
app_id=”your_app_id”,
app_secret=”your_app_secret”,
dir_token=”文件夹 token”,
)
docs = loader.load()

批量加载多个文件

真实场景里,文档会分散在不同目录、不同格式。我们写一个 batch loader:Notion 这条路走通过吗?

from pathlib import Path
def load_directory(directory: str):
“””批量加载一个目录下所有支持的文档”””
documents = []
for file_path in Path(directory).rglob(“*”):
if file_path.suffix == “.pdf”:
loader = PyPDFLoader(str(file_path))
elif file_path.suffix in [“.txt”, “.md”]:
loader = TextLoader(str(file_path))
elif file_path.suffix == “.docx”:
from langchain_community.document_loaders import UnstructuredWordDocumentLoader
loader = UnstructuredWordDocumentLoader(str(file_path))
else:
continue
documents.extend(loader.load())
return documents
documents = load_directory(“docs/”)
print(f”加载了 {len(documents)} 个文档块”)

把这个函数封装好,以后任何目录的文档都能批量入库,不需要一行一行写加载代码。批量入库这函数你复用吗?

五、优化 RAG:从”能用”到”好用”

最基础的 RAG 系统能跑,但有 4 个常见问题:

  1. 答非所问——问 A,答 B
  2. 答得太泛——答案没针对性
  3. 检索不到——文档里有相关信息,但搜不到
  4. 重复/矛盾——不同文档说法不一致

下面 4 个优化技巧,每个都能解决其中一类问题。

优化 1:更好的文档切分策略

最简单的 RecursiveCharacterTextSplitter 是按字符硬切的,这会切断语义。更好的方式是按”语义边界”切分:

from langchain.text_splitter import MarkdownTextSplitter
# 按 Markdown 标题切分
splitter = MarkdownTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_text(markdown_text)

或者用 SemanticChunker(2026 年新出的工具),它会自动根据语义相似度切分:

from langchain_experimental.text_splitter import SemanticChunker
splitter = SemanticChunker(
embeddings,
breakpoint_threshold_type=”percentile”,
)
chunks = splitter.split_documents(documents)

这种切分不会切断句子内部结构,检索时更精准。

优化 2:混合检索(向量 + 关键词)

向量检索擅长”语义相似”,但对精确关键词、专业术语不敏感。

比如用户问”RefundPolicy.pdf 第 3 条”,纯向量检索可能搜不到,关键词检索能搜到。

from langchain.retrievers import BM25Retriever, EnsembleRetriever
# 关键词检索
bm25_retriever = BM25Retriever.from_documents(chunks)
# 向量检索
vector_retriever = vectorstore.as_retriever(search_kwargs={“k”: 5})
# 混合(70% 向量, 30% 关键词)
ensemble_retriever = EnsembleRetriever(
retrievers=[vector_retriever, bm25_retriever],
weights=[0.7, 0.3],
)
qa = RetrievalQA.from_chain_type(
llm=llm,
retriever=ensemble_retriever,
)

这种混合检索兼顾”语义理解”和”关键词精确匹配”,是企业 RAG 系统的标准做法。混合检索你用了哪种?

优化 3:重排序(Reranking)

第一轮检索可能召回了 10 个文档,但真正相关的只有前 3 个。重排序让 LLM(或专门的 rerank 模型)再过一遍,挑出最相关的:

from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import CohereRerank
# 召回 10 个文档
base_retriever = vectorstore.as_retriever(search_kwargs={“k”: 10})
# 重排到前 3
compressor = CohereRerank(top_n=3)
compression_retriever = ContextualCompressionRetriever(
base_compressor=compressor,
base_retriever=base_retriever,
)
qa = RetrievalQA.from_chain_type(
llm=llm,
retriever=compression_retriever,
)

重排序能显著提升答案的”精准度”,但会引入额外的 API 调用(成本增加)。建议在”答案质量要求高”的场景才用。

优化 4:评估与持续改进

RAG 系统上线后,你需要持续评估它的”答案质量”。最简单的方法是写一个测试集。重排序的成本你算过吗?

优化 5:Query 改写 (Query Rewriting)

用户提问往往口语化、不精准。原始查询”代理能干嘛?”对检索不友好;改成”代理软件有哪些主流使用场景”会好得多。

Query 改写用 LLM 把口语化查询重写成检索友好的形式:

from langchain.prompts import PromptTemplate
rewrite_prompt = PromptTemplate.from_template(
“将以下用户问题改写为更适合检索关键字词汇库的形式。仅输出改写后的查询,不要其他内容。\n\n原始问题: {question}\n改写后:”
)
def rewrite_query(question: str, llm) -> str:
return llm.invoke(rewrite_prompt.format(question=question)).content
# 使用
original_q = “那个能看代码的东西怎么用?”
rewritten_q = rewrite_query(original_q, llm)
print(f”原始: {original_q}”)
print(f”改写后: {rewritten_q}”)
# 可能输出: “开发者使用 AI 代码代理的方法是什么”

改写后的查询送进检索器,准确率明显提高。这个技巧特别适合”用户提问质量参差不齐”的场景(比如客服、业务答疑)。

test_cases = [
{“q”: “产品价格是多少?”, “expected_source”: “pricing.pdf”},
{“q”: “如何申请退款?”, “expected_source”: “refund_policy.pdf”},
{“q”: “客服电话?”, “expected_source”: “contact.md”},
]
def evaluate(test_cases):
correct = 0
for case in test_cases:
result = qa.invoke({“query”: case[“q”]})
sources = [doc.metadata.get(“source”) for doc in result[“source_documents”]]
if case[“expected_source”] in sources:
correct += 1
print(f”准确率: {correct}/{len(test_cases)} = {correct/len(test_cases)*100:.0f}%”)
evaluate(test_cases)

跑这个评估,你能看到 RAG 系统的”检索命中率”。如果准确率低,可以从以下方面改进:

  • 文档切分粒度(chunk_size 太大或太小)
  • embedding 模型选型
  • 加更多上下文(比如文档元数据)
  • 改写用户问题(用 LLM 把口语化问题改成更”搜索友好”的形式)

评估这件事必须做——不评估的 RAG 系统,上线后没人知道它工作得怎么样。

六、完整项目实战:做一个 HR 知识库问答

接下来我们用一个完整实例走通一遍。

这次做”HR 知识库问答”,用户可以问”年假怎么休””加班费怎么算””工资什么时候发”,系统基于公司 HR 文档回答。

项目结构

hr-rag/
├── .env
├── docs/
│ ├── 员工手册.md
│ ├── 年假政策.pdf
│ └── 薪资福利.docx
├── ingest.py # 文档摄入
├── query.py # 查询入口
└── evaluate.py # 评估

ingest.py:摄取所有文档

from pathlib import Path
from langchain_community.document_loaders import (
PyPDFLoader, TextLoader, UnstructuredWordDocumentLoader
)
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_openai import OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from dotenv import load_dotenv
load_dotenv()
def load_documents(directory: str):
docs = []
for path in Path(directory).rglob(“*”):
if path.suffix == “.pdf”:
docs.extend(PyPDFLoader(str(path)).load())
elif path.suffix in [“.txt”, “.md”]:
docs.extend(TextLoader(str(path)).load())
elif path.suffix == “.docx”:
docs.extend(UnstructuredWordDocumentLoader(str(path)).load())
return docs
def main():
documents = load_documents(“docs”)
print(f”加载 {len(documents)} 个文档”)
splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=50)
chunks = splitter.split_documents(documents)
print(f”切分成 {len(chunks)} 个 chunk”)
embeddings = OpenAIEmbeddings(model=”text-embedding-3-small”)
vectorstore = Chroma.from_documents(
chunks, embeddings, persist_directory=”./chroma”
)
vectorstore.persist()
print(f”向量库已保存到 ./chroma”)
if __name__ == “__main__”:
main()

跑 python ingest.py,HR 文档会被处理并存到本地 Chroma 数据库。这套 HR 问答你跑通了吗?

query.py:查询入口

from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import Chroma
from langchain.prompts import PromptTemplate
from langchain.chains import RetrievalQA
from dotenv import load_dotenv
load_dotenv()
embeddings = OpenAIEmbeddings(model=”text-embedding-3-small”)
vectorstore = Chroma(persist_directory=”./chroma”, embedding_function=embeddings)
llm = ChatOpenAI(model=”gpt-4o-mini”, temperature=0)
# 自定义 prompt 模板
prompt_template = “””基于以下参考资料回答问题。
参考资料:{context}
问题:{question}
答案要简洁、有依据。如果参考资料里没有答案,说”我不知道”。”””
PROMPT = PromptTemplate(
template=prompt_template,
input_variables=[“context”, “question”],
)
qa = RetrievalQA.from_chain_type(
llm=llm,
retriever=vectorstore.as_retriever(search_kwargs={“k”: 5}),
chain_type_kwargs={“prompt”: PROMPT},
return_source_documents=True,
)
def ask(question: str):
result = qa.invoke({“query”: question})
print(f”\n问: {question}”)
print(f”答: {result['result']}”)
print(f”来源: {[doc.metadata.get('source', '?') for doc in result['source_documents']]}”)
if __name__ == “__main__”:
questions = [
“年假可以休几天?”,
“加班费是怎么计算的?”,
“工资什么时候发?”,
“我刚入职,需要办理什么手续?”,
]
for q in questions:
ask(q)

跑 python query.py,你会看到一个完整的 HR 问答系统跑起来。每一个回答都会附上”来源文档路径”,让用户知道答案来自哪个文件。

评估

跑一段时间后,你需要评估这个 RAG 系统的质量。

建一个 evaluate.py,跑 50-100 个测试 case,统计准确率、命中率、用户满意度,看系统是否需要调优。

七、调试技巧:RAG 系统的常见坑

坑 1:答案”看着对”但其实不对

症状:LLM 给的答案流畅自然,但其实是”幻觉”——它没基于检索到的文档,而是基于自己的”常识”瞎编。

修复:

  • 在 prompt 里明确”如果文档里没答案,说’我不知道’,不要瞎编”
  • 把 temperature 设成 0(LLM 默认有随机性)
  • 加”返回来源文档”,让用户能验证

坑 2:检索不到”该被搜到”的内容

症状:文档里有相关信息,但搜不到。

修复:

  • 检查 chunk_size 是否合适(太大/太小都不好)
  • 试不同的 embedding 模型(text-embedding-3-large 比 -small 更准)
  • 用混合检索(向量 + 关键词)
  • 加文档元数据(标题、日期、来源)进 embedding

坑 3:速度慢

症状:问一个问题要等 5-10 秒。

修复:

  • embedding 用更快的模型
  • LLM 用更快的模型(gpt-4o-mini 比 gpt-4o 快 5 倍)
  • 用缓存:相同问题的答案不重跑
  • 优化检索(limit k 值,减少不必要检索)

坑 4:成本高

症状:每月 API 费用超出预期。

修复:

  • 监控 token 使用量
  • 用更便宜的模型处理简单问题,贵的处理复杂问题
  • 缓存高频问题的答案
  • 限制文档 chunk 数量,避免无限膨胀

八、生产化:从 demo 到能用的 3 个步骤

写完 demo 后,要把 RAG 系统用到生产里,需要做 3 件事:

步骤 1:加权限控制

生产 RAG 必须区分用户权限:

  • 普通员工:能查自己部门的文档
  • 主管:能查所有部门
  • 高管:能查机密文档

实现方式:在 retrieval 阶段先根据用户角色过滤文档 metadata。权限过滤你做了吗?

步骤 2:加审计日志

每一轮问答都要记录:

  • 用户问了什么
  • 检索到了哪些文档
  • LLM 给的答案是什么
  • 用户是否点赞(满意)

这些日志是后续优化的关键数据。

步骤 3:加监控

监控几个关键指标:

  • 响应时间
  • 检索命中率
  • 用户满意度
  • 成本

一旦异常,立即告警。

九、下一步

学完这篇,你已经能搭一个能用的 RAG 系统了。接下来的几个方向:

方向 1:上 Agent(Agentic RAG)

普通 RAG 是”先检索再生成”。Agentic RAG 让 Agent 决定”要不要检索”、”检索几次”、”用什么关键词”——更灵活,适合复杂查询。这个 Agentic RAG,你项目里用得上吗?

LangGraph 配合 LLM 决策,能搭出企业级的 Agentic RAG 系统。Agentic RAG 你搭了吗?

方向 2:接 MCP

把 Notion / 飞书 / Slack 等企业内部工具接成 MCP Server,RAG 系统就能”实时”获取最新文档,而不是靠定期 ingest。

这是 2026 年最前沿的 RAG 模式。

方向 3:多模态 RAG

现在的 RAG 主要处理文字,2026 年开始支持图片、表格、PDF 图表等多模态内容。多模态 RAG 能回答”这张图里的公式是什么意思”这种问题。

方向 4:GraphRAG

把知识图谱(Knowledge Graph)融进 RAG,系统能理解实体之间的关联,适合”问关于人/事/物之间的关系”的问题。

例如”我们公司哪个部门在 AI 项目上投入最多”——纯向量 RAG 答不好,GraphRAG 能答。

推荐学习路径

  • 想搭生产级 RAG:补充评估体系、可观测性、成本控制
  • 想理解 Agent 怎么用 RAG:看本系列《手把手搭建第一个 AI Agent:基于 LangGraph 实战》
  • 想了解 RAG 怎么跟 MCP 集成:看《MCP 实战:给 Agent 接上 GitHub / 数据库 / 浏览器》

30 分钟前你不知道 RAG 是什么,现在你能搭一个能用的企业知识库系统。但这只是起点——真正的”厉害”在于把它用到能放心交给别人的程度。

下周我会写一篇 GraphRAG 实战,讲知识图谱怎么融入 RAG,让系统回答”复杂关系类”问题。

先把今天的 demo 跑通,然后试着往里塞你公司真实文档。

30 分钟后,你的 RAG 系统会变成你最常用的”知识助手”——这种成就感,只有动手做才能体会到。

(综合 LangChain 官方文档、Chroma 文档、LangGraph 文档、Cohere Rerank 文档、企业 RAG 实战项目整理)

想搭一个只用自己那份资料的助手,可以看AI 搭个人助手这个页面,按场景分好了工具和步骤。

Avatar photo

龙主编

龙主编,AI智习室官方媒体主编。 专注 AI 行业观察与实操分享,擅长将复杂技术转化为通俗易懂的实战指南。 坚信 AI 不是取代人类,而是赋能每个人。 内容风格: 真实案例 + 详细干货 + 可操作性 使命: 让普通人也能抓住 AI 时代的红利。