RAG检索
你将学会: 文档切块 → 放入向量库 → 检索 → 交给模型回答。
前置: L01、L02。
模型训练截止日期之后的公司文档,它不会「知道」。RAG = 回答前先检索你提供的文本。

先跑假向量把管道跑通(不需要百炼 key)。语义真正准,再换成 embedding API。
1. 只切分(不需要 API key)
from langchain_core.documents import Document
from langchain_text_splitters import RecursiveCharacterTextSplitter
raw = """LangChain 的入口是 create_agent,负责模型加工具循环。
LangGraph 用 StateGraph 编排节点和边,支持 checkpoint。
Deep Agents 预装虚拟文件系统和子代理,适合长任务。
"""
docs = [Document(page_content=raw, metadata={"source": "notes.txt"})]
splitter = RecursiveCharacterTextSplitter(chunk_size=40, chunk_overlap=8, add_start_index=True)
for i, c in enumerate(splitter.split_documents(docs)):
print(i, c.metadata.get("start_index"), repr(c.page_content))
2. 检索 + 生成(需要 DeepSeek)
FakeEmbeddings 不是语义检索,只验证形状。问「checkpoint」不一定命中 LangGraph 那句。换真 embedding 后才会按意思找。
from dotenv import load_dotenv
load_dotenv()
from langchain.chat_models import init_chat_model
from langchain_core.documents import Document
from langchain_core.embeddings import FakeEmbeddings
from langchain_core.vectorstores import InMemoryVectorStore
from langchain_text_splitters import RecursiveCharacterTextSplitter
model = init_chat_model(
"deepseek:deepseek-chat",
temperature=0.5,
max_tokens=2500,
timeout=300,
max_retries=6,
)
docs = [
Document(page_content="请假流程:提前在 OA 提交,直属领导审批,HR 备案。"),
Document(page_content="报销需要电子发票,金额超过 1000 元要总监加签。"),
Document(page_content="笔记本电脑每 3 年可申请更换,找 IT 工单。"),
]
chunks = RecursiveCharacterTextSplitter(chunk_size=80, chunk_overlap=0).split_documents(docs)
store = InMemoryVectorStore(embedding=FakeEmbeddings(size=64))
store.add_documents(chunks)
question = "报销一千块以上要找谁?"
hits = store.similarity_search(question, k=2)
context = "\n".join(h.page_content for h in hits)
print("检索到 =>", [h.page_content for h in hits])
print("回答 =>", model.invoke(
f"只根据资料回答,资料没有就说不知道。\n资料:\n{context}\n\n问题:{question}"
).content)
真语义搜索:仓库 05-RAG与检索/Document-pipeline文档管道.py(BAILIAN_API_KEY)。
上面是 2-Step RAG:你规定「先检索再生成」。生产里更常见的是 Agentic RAG:把检索做成工具,让 agent 自己决定何时查。
3. 检索挂成工具(需要 DeepSeek)
from dotenv import load_dotenv
load_dotenv()
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.tools import tool
from langchain_core.documents import Document
from langchain_core.embeddings import FakeEmbeddings
from langchain_core.vectorstores import InMemoryVectorStore
model = init_chat_model(
"deepseek:deepseek-chat",
temperature=0.5,
max_tokens=2500,
timeout=300,
max_retries=6,
)
store = InMemoryVectorStore(embedding=FakeEmbeddings(size=64))
store.add_documents([
Document(page_content="请假流程:提前在 OA 提交,直属领导审批,HR 备案。"),
Document(page_content="报销需要电子发票,金额超过 1000 元要总监加签。"),
Document(page_content="笔记本电脑每 3 年可申请更换,找 IT 工单。"),
])
@tool
def search_notes(query: str) -> str:
"""在公司制度里检索。问请假、报销、换电脑时必须调用。"""
print(f"[检索] {query}", flush=True)
hits = store.similarity_search(query, k=3)
return "\n".join(h.page_content for h in hits) or "没有检索到。"
agent = create_agent(
model=model,
tools=[search_notes],
system_prompt="制度问题必须先 search_notes。资料没有就说不知道。不要编造。",
)
print(agent.invoke({
"messages": [{"role": "user", "content": "报销超过一千要找谁?"}]
})["messages"][-1].content)
终端应出现 [检索] ...。L13 综合项目就是在这一段上加记忆和测试。
练习
- 把三句资料改成你自己的笔记,问一个只有笔记里才有的问题。
- 问一个资料里没有的问题,确认模型按提示说「不知道」(系统提示已经写了)。
本章验收
- 能画出 Loader → Splitter → Embedding → VectorStore → LLM
- 亲手跑通「检索到的片段进 prompt」
- 能把检索挂成
@tool,并在日志里看到它被调用 - 知道 FakeEmbeddings 不能当生产检索
对照仓库:05-RAG与检索/Retrieval检索.py、Document-pipeline文档管道.py
下一课:中间件与护栏
JavaWeb
Spring
MyBatis
linux
消息队列
JavaSE
工具
片段
AI
搜索
dy