📚 RAG:给AI装上"图书馆"

"世界上有一种知识,AI本来不知道。但你给它一座图书馆,它就能装得像个博学家。这,就是RAG。"

📖 定义:什么是RAG?

RAG(Retrieval-Augmented Generation,检索增强生成)是一种让AI在回答问题之前,先从外部知识库中检索相关信息的技术。

想象一下考试:

💡 一句话理解:RAG = AI的图书馆系统。它让AI先查资料再回答,告别"一本正经地胡说八道"。

⚙️ 为什么需要RAG?

LLM的三大痛点

RAG的解决方案

🏗️ RAG架构:两大阶段

阶段一:Indexing(索引构建)

把知识装进"图书馆":

┌─────────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
│  原始文档   │ → │  分块    │ → │ Embedding│ → │ 向量数据库│
│ (PDF/Word/ │    │ (Chunk)  │    │ (向量化) │    │(存储)    │
│  Web/...)  │    └──────────┘    └──────────┘    └──────────┘
└─────────────┘

1. 文档加载(Load)

从各种来源加载文档:

from langchain.document_loaders import (
    PyPDFLoader,      # PDF文件
    TextLoader,       # 文本文件  
    WebBaseLoader,    # 网页
    NotionLoader      # Notion文档
)

# 加载PDF
docs = PyPDFLoader("manual.pdf").load()

# 加载网页
docs = WebBaseLoader("https://docs.openclaw.ai").load()

2. 文档分块(Split)

把长文档切成适合处理的小块:

from langchain.text_splitter import RecursiveCharacterTextSplitter

splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,      # 每块1000字符
    chunk_overlap=200     # 重叠200字符(保持上下文)
)

chunks = splitter.split_documents(docs)

3. 向量化(Embed)

把文本变成向量(数字表示语义):

from langchain.embeddings import OpenAIEmbeddings

embeddings = OpenAIEmbeddings()

# "猫" → [0.12, -0.34, 0.56, ...]  # 1536维向量
# "狗" → [0.15, -0.31, 0.52, ...]  # 相似的向量

4. 存储(Store)

存入向量数据库:

from langchain.vectorstores import Chroma, FAISS, Pinecone

# 使用Chroma本地存储
vectorstore = Chroma.from_documents(
    documents=chunks,
    embedding=embeddings,
    persist_directory="./chroma_db"
)

阶段二:Retrieval(检索生成)

用户提问时的处理流程:

用户提问 → Embedding → 向量检索 → 取Top-K → 组装Prompt → LLM生成答案
            (向量化)    (相似度搜索)  (相关文档)  (增强上下文)

完整流程

# 1. 用户提问
question = "OpenClaw怎么配置多Agent?"

# 2. 向量化查询
query_vector = embeddings.embed_query(question)

# 3. 检索相似文档
relevant_docs = vectorstore.similarity_search(
    query=question,
    k=4  # 取最相似的4个文档块
)

# 4. 组装增强Prompt
context = "\n\n".join([doc.page_content for doc in relevant_docs])

augmented_prompt = f"""基于以下参考资料回答问题:

参考资料:
{context}

用户问题:{question}

请基于以上资料回答。如果资料中没有相关信息,请明确说明。"""

# 5. LLM生成答案
answer = llm.generate(augmented_prompt)

🚀 OpenClaw实战:RAG集成

场景:企业内部知识库助手

搭建一个能理解公司文档的AI助手:

Step 1:准备知识库

# 目录结构
knowledge_base/
├── products/           # 产品文档
│   ├── openclaw_guide.pdf
│   └── feature_list.md
├── faqs/              # 常见问题
│   └── common_issues.md
└── policies/          # 公司政策
    └── refund_policy.pdf

Step 2:构建RAG Pipeline

# rag_builder.py
from langchain.document_loaders import DirectoryLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import Chroma

class KnowledgeBase:
    def __init__(self, docs_path="./knowledge_base"):
        self.embeddings = OpenAIEmbeddings()
        self.vectorstore = None
        self.docs_path = docs_path
    
    def build(self):
        """构建知识库索引"""
        # 1. 加载文档
        loader = DirectoryLoader(
            self.docs_path,
            glob="**/*.{pdf,md,txt}",
            loader_cls=TextLoader
        )
        docs = loader.load()
        
        # 2. 分块
        splitter = RecursiveCharacterTextSplitter(
            chunk_size=1000,
            chunk_overlap=200
        )
        chunks = splitter.split_documents(docs)
        
        # 3. 存入向量库
        self.vectorstore = Chroma.from_documents(
            chunks,
            self.embeddings,
            persist_directory="./kb_index"
        )
        self.vectorstore.persist()
        
        print(f"✅ 知识库构建完成!共索引 {len(chunks)} 个文档块")
    
    def query(self, question, k=4):
        """查询知识库"""
        if not self.vectorstore:
            self.vectorstore = Chroma(
                persist_directory="./kb_index",
                embedding_function=self.embeddings
            )
        
        results = self.vectorstore.similarity_search(question, k=k)
        return results

# 使用
kb = KnowledgeBase()
kb.build()  # 首次运行构建索引

Step 3:OpenClaw Agent配置

agents:
  list:
    - name: knowledge_assistant
      system_prompt: |
        你是公司的知识库助手。你会基于提供的参考资料回答用户问题。
        
        回答规则:
        1. 严格基于提供的参考资料回答
        2. 如果资料中没有答案,明确说明"根据现有资料,我无法确定..."
        3. 回答时标注信息来源
        4. 保持专业、友好的语气
      skills:
        - rag_query  # 自定义RAG查询技能

skills:
  rag_query:
    description: "查询知识库"
    handler: |
      from rag_builder import KnowledgeBase
      kb = KnowledgeBase()
      results = kb.query(query)
      return format_results(results)

Step 4:使用示例

用户:"OpenClaw怎么配置MCP?"

Agent处理:
1. 调用 rag_query("OpenClaw怎么配置MCP")
2. 检索到相关文档片段
3. 组装Prompt并生成答案:

"根据《OpenClaw MCP集成指南》,配置MCP需要以下步骤:

1. 在config.yaml中添加mcp.servers配置...
2. 指定command和args参数...
3. 在Agent中启用mcp_servers...

[来源: openclaw_guide.pdf, 第12页]"

💡 高级RAG技巧

1. Hybrid Search(混合检索)

向量检索 + 关键词检索结合:

# 向量检索(语义相似)
vector_results = vectorstore.similarity_search(query, k=10)

# 关键词检索(精确匹配)
keyword_results = bm25_retriever.retrieve(query, k=10)

# 融合排序
final_results = reciprocal_rank_fusion(
    vector_results, 
    keyword_results
)

2. Query重写

优化用户查询以提高检索质量:

# 原始查询:"它怎么配置?"
# 重写后:"OpenClaw MCP Server怎么配置?"

rewritten_query = llm.generate(f"""
将以下查询重写为更具体的搜索查询:
上下文:用户在问OpenClaw相关问题
查询:{query}
""")

3. 上下文压缩

检索到的文档太长,提取关键信息:

from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor

compressor = LLMChainExtractor.from_llm(llm)
compression_retriever = ContextualCompressionRetriever(
    base_compressor=compressor,
    base_retriever=vectorstore.as_retriever()
)

4. 多跳检索

复杂问题需要多步检索:

# 问题:"OpenClaw MCP支持哪些数据库?"
# Step 1: 检索MCP相关信息
# Step 2: 基于Step 1结果,检索数据库支持信息

🎯 RAG优化 checklist

"RAG的本质不是让AI变聪明,而是让AI知道'自己不知道什么',并学会查资料。这才是真正的智慧。"

📚 延伸阅读