Week 7-8:RAG(检索增强生成)
🎯 本周目标:给 Agent 加上"外挂硬盘"——让它能根据你的项目文档、历史交易数据来回答问题,而不是瞎编。
1. 为什么需要 RAG?
LLM 有两个致命缺点:
| 问题 | 表现 | 解决方案 |
|---|---|---|
| 知识截止日期 | LLM 只知道训练数据里的内容 | 给它外挂最新数据 |
| 幻觉 | 一本正经地瞎编不存在的事实 | 让它先查资料再回答 |
RAG(Retrieval-Augmented Generation) = 检索 + 增强 + 生成
传统 LLM: 用户问题 → LLM → 直接回答(可能瞎编)
RAG: 用户问题 → 检索相关文档 → 把文档塞给 LLM → LLM 基于文档回答
RAG Pipeline 全景
flowchart LR
A[文档] --> B[分块 Chunking]
B --> C[向量化 Embedding]
C --> D[存入向量数据库]
E[用户问题] --> F[向量化 Embedding]
F --> G[向量数据库检索 Top-K]
G --> H[相关文档块]
H --> I[组装 Prompt]
I --> J[LLM 生成回答]
2. 核心概念对照
Embedding(嵌入)
把一段文字转换成一个数字向量(比如 768 维的数组),语义相近的文字,向量也相似。
# 例子:用 Embedding 模型把文字转成向量
"BTC 价格突破 10 万" → [0.12, -0.34, 0.56, ..., 0.78] # 768 维
"比特币创下历史新高" → [0.11, -0.32, 0.55, ..., 0.76] # 向量很接近 ✨
"今天吃了一碗牛肉面" → [0.01, 0.02, -0.10, ..., 0.05] # 向量完全不同
向量数据库
存 Embedding 向量的数据库,能快速找到和查询向量最相似的 Top-K 条。
| 向量数据库 | 特点 | 适合场景 |
|---|---|---|
| ChromaDB(推荐初学者) | 轻量、本地、Python 原生、API 友好 | 个人项目 / 原型 |
| FAISS | Meta 开源,性能最强但 API 老 | 大量向量 / 生产环境 |
| Milvus | 分布式、企业级 | 大规模生产 |
| Pinecone | 云服务,免运维 | 不想自己管的生产环境 |
💡 初学者选 ChromaDB
ChromaDB 不需要启动服务,直接 persist_directory="本地文件夹" 就能用,就像 SQLite 之于关系型数据库。
TS 对照
| RAG 组件 | 前端类比 |
|---|---|
| 文档分块 Chunking | 把大文件做 code-splitting,分成多个 chunk |
| Embedding | 给每个 chunk 生成一个"语义指纹" |
| 向量检索 | 按"指纹相似度"找到最相关的 chunk |
| Prompt 组装 | 把检索到的 chunk 塞进 LLM 的 context window |
3. 动手:本地 RAG 实战
安装依赖
.venv\Scripts\python -m pip install chromadb langchain-chroma langchain-huggingface sentence-transformers
sentence-transformers是本地运行的 Embedding 模型,支持中文。
完整代码
# app/rag/rag_pipeline.py
"""
RAG Pipeline 示例:
把 electric-trading-ai 项目的文档喂进向量库,然后问问题
"""
from pathlib import Path
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import TextLoader, DirectoryLoader
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_chroma import Chroma
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
# ===== 配置 =====
PERSIST_DIR = "./chroma_db" # 向量数据库持久化目录
DOCS_DIR = Path("e:/wf_work/wf_ai/electric-trading-ai") # 你的项目根目录
# ===== 1. 加载和分块文档 =====
def load_and_split_docs(docs_dir: Path):
"""加载项目里的文档,然后分块"""
# 加载 Markdown、txt、py 文件(选择性排除)
loader = DirectoryLoader(
str(docs_dir),
glob=["**/*.md", "**/*.txt"],
recursive=True,
use_multithreading=True,
)
docs = loader.load()
print(f"加载了 {len(docs)} 个文档")
# 分块:长文档切成小段落
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=500, # 每块大约 500 字符
chunk_overlap=50, # 相邻块有 50 字符重叠,避免切断语义
length_function=len,
)
splits = text_splitter.split_documents(docs)
print(f"切分成了 {len(splits)} 个块")
return splits
# ===== 2. Embedding + 存进 ChromaDB =====
def build_vector_store(splits):
"""用 Embedding 模型向量化并存入 ChromaDB"""
# 本地 Embedding 模型(支持中文,首次会自动下载约 400MB)
embeddings = HuggingFaceEmbeddings(
model_name="shibing624/text2vec-base-chinese", # 中文效果好
model_kwargs={'device': 'cpu'},
encode_kwargs={'normalize_embeddings': True},
)
# 创建/加载 ChromaDB
vectorstore = Chroma.from_documents(
documents=splits,
embedding=embeddings,
persist_directory=PERSIST_DIR,
collection_name="trading_docs",
)
print(f"向量数据库已就绪,持久化到 {PERSIST_DIR}")
return vectorstore
# ===== 3. 构建 RAG Chain =====
def build_rag_chain(vectorstore):
"""构建 RAG 问答链"""
# 检索器:根据问题找 Top-4 最相关的文档块
retriever = vectorstore.as_retriever(
search_type="similarity",
search_kwargs={"k": 4},
)
# LLM
llm = ChatOpenAI(
model="Qwen/Qwen2.5-7B-Instruct",
base_url="https://api.siliconflow.cn/v1",
api_key="your-api-key-here",
temperature=0.3, # RAG 场景要低温度,减少发散
)
# Prompt 模板
prompt = ChatPromptTemplate.from_template("""
你是一个 AI Agent 学习助手。请严格基于以下上下文回答用户的问题。
如果上下文中没有相关信息,请说"抱歉,我在你的文档里没有找到相关内容",不要瞎编。
上下文:
{context}
用户问题:{question}
""")
# LangChain LCEL Chain 组装
rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
return rag_chain
def format_docs(docs) -> str:
"""把检索到的文档块拼成一个字符串"""
return "\n\n".join(doc.page_content for doc in docs)
# ===== 4. 运行 =====
async def main():
# Step 1-2: 构建向量库(第一次跑会慢,之后向量库持久化了就快)
splits = load_and_split_docs(DOCS_DIR)
vectorstore = build_vector_store(splits)
# Step 3: 构建 RAG Chain
rag_chain = build_rag_chain(vectorstore)
# Step 4: 问答
questions = [
"这个 electric-trading-ai 项目有哪些依赖?",
"项目用的什么框架?",
"Python 版本要求是多少?",
"你好", # 测试无关问题
]
for q in questions:
print(f"\n{'='*50}")
print(f"Q: {q}")
answer = await rag_chain.ainvoke(q)
print(f"A: {answer}")
if __name__ == "__main__":
import asyncio
asyncio.run(main())
运行
.venv\Scripts\python app\rag\rag_pipeline.py
预期输出
加载了 5 个文档
切分成了 23 个块
向量数据库已就绪,持久化到 ./chroma_db
==================================================
Q: 这个 electric-trading-ai 项目有哪些依赖?
A: 根据项目配置文件,依赖包括 fastapi 等。
==================================================
Q: 项目用的什么框架?
A: 项目使用 FastAPI 作为 Web 框架。
==================================================
Q: Python 版本要求是多少?
A: 项目要求 Python 版本 >= 3.11。
==================================================
Q: 你好
A: 抱歉,我在你的文档里没有找到相关内容。
🎉 恭喜!你的 Agent 现在会查资料了! 不会再瞎编了。
4. 进阶:把 RAG 集成到 LangGraph Agent
把 RAG 作为 LangGraph 的一个 Tool,Agent 自己决定什么时候查:
from langchain_core.tools import tool
# 把 RAG 检索器包装成一个 Tool
@tool
def query_project_docs(question: str) -> str:
"""当用户问到关于本项目的技术问题时,用这个工具去查项目文档。"""
# 这里的 vectorstore 就是上一节构建的
retriever = vectorstore.as_retriever(search_kwargs={"k": 3})
docs = retriever.invoke(question)
context = "\n\n".join(d.page_content for d in docs)
return f"检索到以下相关内容:\n{context}"
# 然后把 query_project_docs 加进 Month 2 Week 5 的 TOOLS 列表
# Agent 就会自动在需要的时候调用它!
完整的增强后 Agent 图
flowchart TD
A[START] --> B[analyze_intent]
B --> C{意图分类}
C -->|交易查询| D[use_trading_tools]
C -->|项目技术问题| E[query_project_docs<br/>RAG Tool]
C -->|闲聊| F[direct_chat]
D --> G[summarize]
E --> G
G --> H[END]
F --> H
5. RAG 效果调优
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 检索不到相关内容 | chunk 太大或太小 | 调整 chunk_size,一般 300-800 |
| 检索到的内容不相关 | Embedding 模型不匹配 | 中文内容用中文 Embedding 模型 |
| LLM 还是瞎编 | Prompt 约束不够 | 加 "如果没有相关信息就说不知道" |
| 回答太冗长 | 检索到的 chunk 太多 | 减少 k 值,或加 reranker 重排 |
| 中文效果差 | 用了英文 Embedding 模型 | 用 shibing624/text2vec-base-chinese 等中文模型 |
进阶调优方向(以后学)
- Hybrid Search:关键词搜索 + 向量搜索结合
- Reranker:检索后用 Cross-Encoder 重新排序
- Query Rewriter:用户问题改写后再检索
- Agentic RAG:Agent 自主决定要不要拆问题、查几次
6. 本周作业
| # | 任务 | 验收标准 |
|---|---|---|
| 1 | 跑通上面的 RAG Pipeline | 能正确回答项目文档里的问题 |
| 2 | 试试把你的 .env.example、README.md 也加进向量库 | 覆盖更多知识 |
| 3 | 把 RAG 包装成 LangGraph 的 Tool,集成到交易 Agent | Agent 能自主决定何时查文档 |
| 4 | 对比调不同的 chunk_size(200/500/800)看效果 | 体会 chunking 策略的影响 |
| 5 | 读 LangChain RAG Tutorial(官方) | 理解完整 RAG 流程 |
7. Month 2 总结
到这里你已经完成了:
- ✅ LangGraph StateGraph 编排 Agent 行为流
- ✅ Function Calling 让 Agent 调用真实 Python 函数
- ✅ RAG 让 Agent 能查资料不瞎编
- ✅ 把 Agent + RAG 集成到 FastAPI 后端
你现在已经能搭出一个有真实业务能力的 AI Agent 应用了! 进入 Month 3,我们会把所有东西串起来做一个完整项目、部署上线。🚀