背景:为什么需要 RAG

说实话,大模型刚火那会儿,我也觉得直接问 ChatGPT 就完事了。但真到了实际项目里,一个现实问题摆在眼前:大模型不知道你公司的内部数据。

你说”帮我查一下上季度销售数据“,GPT 只能一脸懵——它训练的时候根本没看过你们公司的 Excel 啊。

RAG(检索增强生成)就是来解决这个问题的。简单说就是:先搜再答——从你的知识库里检索相关内容,然后把检索结果”喂“给大模型,让它基于你的数据回答。

这玩意儿不是什么高深理论,但落地的时候坑是真不少。今天就从零开始,手把手搭一个能用的 RAG 系统。

RAG 系统架构图

环境准备

安装 Ollama(本地大模型)

curl -fsSL https://ollama.com/install.sh | sh

装完后拉一个模型:

ollama pull qwen2.5:7b
ollama pull nomic-embed-text

安装 Python 依赖

pip install langchain langchain-community chromadb fastapi uvicorn

分步实现

第一步:文档加载与分割

原始文档不能直接丢给大模型,得先切块。切太小语义不完整,切太大超出上下文窗口。

from langchain_community.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter

loader = DirectoryLoader("./docs/", glob="**/*.txt")
documents = loader.load()

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,
    chunk_overlap=100
)
chunks = text_splitter.split_documents(documents)
print(f"文档被切分为 {len(chunks)} 个块")

这里有个坑:chunk_size 不是越大越好。500 字左右比较合适,既能保留语义,又不会让检索结果太模糊。

文档切分示意图

第二步:向量化与存储

from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.vectorstores import Chroma

embeddings = OllamaEmbeddings(model="nomic-embed-text")

vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db"
)
print("向量数据库已创建,共", vectorstore._collection.count(), "个向量")

第三步:构建检索链

from langchain.chains import RetrievalQA
from langchain_community.llms import Ollama

llm = Ollama(model="qwen2.5:7b", temperature=0.1)

qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff",
    retriever=vectorstore.as_retriever(search_kwargs={"k": 3})
)

query = "公司的服务器维护流程是什么?"
result = qa_chain.invoke({"query": query})
print(result["result"])

第四步:封装成 API

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Query(BaseModel):
    question: str

@app.post("/ask")
async def ask(query: Query):
    result = qa_chain.invoke({"query": query.question})
    return {"answer": result["result"]}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

API 部署架构图

常见问题 Q&A

Q:为什么不用 OpenAI 的 embedding?
A:可以用,但考虑到数据隐私和成本,很多企业选择本地部署。Ollama 的 nomic-embed-text 效果够用。

Q:chunk_size 怎么调?
A:一般 300-1000 之间。小文档用 300,大文档用 500-800。overlap 要设,不然切在句子中间时上下文断了。

Q:检索结果不准确怎么办?
A:1. 检查 chunk 质量 2. 调大 k 值 3. 试试 Hybrid Search

Q:支持 PDF 吗?
A:需要装 PyMuPDF,用 PyMuPDFLoader 加载。

总结

说实话,RAG 的入门门槛真的很低,几行代码就能跑起来。但生产环境要考虑的事挺多:文档更新策略、检索质量评估、延迟优化、多轮对话上下文管理……

不过别被吓到。先跑通 Demo,再一步步优化,这才是正经的工程落地路径。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐