RAG项目总结

文章目录

1.项目目的

RAG(Retrieval-Augmented Generation,检索增强生成) 系统。核心思路是:不直接把问题丢给 AI,而是先从本地文档中检索出相关内容,再把资料+问题一起发给 AI,让 AI 基于真实资料回答,避免瞎编。

2.整体流程

读取 docs.txt → 按句号切分成句子片段 → SentenceTransformer 将每个句子转成向量(数字列表) → 向量存入 ChromaDB(向量数据库) → 用户提问 → 同样转成向量 → ChromaDB 用向量相似度搜索,找回最相关的 k 个句子 → 把找到的句子 + 用户问题 拼成提示词 → 发给 Kimi AI → 返回回答


3.Embedding 模型选择详解

这部分在代码第 49 行:

embed_model = SentenceTransformer("shibing624/text2vec-base-chinese")

3.1.什么是 Embedding 模型?

把"文字的意思"压缩成一组数字(向量)。意思相近的文字,它们在向量空间里的距离也近:

"今天天气很好" → [0.12, 0.34, 0.56, ...] "今天天气不错" → [0.13, 0.33, 0.55, ...] ← 距离近 "苹果多少钱" → [0.71, 0.22, 0.88, ...] ← 距离远

3.2.为什么选这个模型?

代码注释里提到了另一个备选:

# embed_model = SentenceTransformer("BAAI/bge-small-zh")

两个都是中文 Embedding 模型,对比:

模型 参数 向量维度 特点
shibing624/text2vec-base-chinese ~110M 768 中文语义匹配好,入门首选
BAAI/bge-small-zh ~33M 512 更小更快,但精度略低

项目最终用了 text2vec-base-chinese,它在中文句子相似度上表现更好,但代价是向量维度更高(768 vs 512),占用更多存储空间,检索也稍慢一点。

3.3.其他常见的中文 Embedding 模型

模型 维度 适用场景 说明
shibing624/text2vec-base-chinese 768 通用中文 平衡了效果和速度,本项目选用
BAAI/bge-large-zh 1024 高精度 维度高,效果最好但也最慢
BAAI/bge-small-zh 512 快速检索 轻量,适合大规模文档
moka-ai/m3e-base 768 通用中文 另一个热门的国产模型
tencent-ailab/embedding-en 768 英文专用 腾讯出品,只适合英文

3.4.选型的一般原则

  1. 中文用中文专用模型(不能用 GPT 的 text-embedding-ada-002 吗?可以,但要调 API 花钱)
  2. 维度越高精度越好,但检索越慢、占空间越大
  3. 模型大小 vs 速度的权衡bge-small 最快,text2vec-base 中等,bge-large 最慢
  4. 本地 vs API 模型:本项目的模型跑在本地(免费),也可以用 OpenAI/Kimi 的在线 Embedding API(付费但省部署)

4.LLM 模型选择

本项目选的是 Kimi(moonshot-v1-8k)

model="moonshot-v1-8k"

8k 指上下文窗口 8000 token(约 6000 个汉字)。Kimi 有更大的 moonshot-v1-32k(32000 token)。对 RAG 来说 8k 够用,因为资料已经由检索筛选过了,不需要把整篇文档塞进去。

如果想换别的 LLM,只需改 api_keybase_urlmodel 名称,代码结构不变。支持的选项:

LLM base_url model 名
Kimi https://api.moonshot.cn/v1 moonshot-v1-8k
OpenAI https://api.openai.com/v1 gpt-4o-mini
DeepSeek https://api.deepseek.com deepseek-chat
通义千问 https://dashscope.aliyuncs.com/compatible-mode/v1 qwen-plus

5.向量数据库选择

本项目用 ChromaDB (本地持久化 PersistentClient)。

常见向量数据库对比:

数据库 部署方式 适用场景
ChromaDB 嵌入式/本地 原型、小项目、个人使用(本项目选的)
FAISS Python 库 高性能、大规模向量搜索
Milvus 服务端 生产级、分布式
Qdrant 服务端 生产级、Rust 实现
PGVector PostgreSQL 插件 已有 Postgres 的项目

ChromaDB 的特点是零配置PersistentClient(path="./chroma_db") 一句代码就创建好,数据存在本地文件夹,适合学习和原型开发。


6.区分一些概念

一句话区分:

概念 一句话
HuggingFace 模型商店,下载模型的地方
SentenceTransformer 加载 Embedding 模型的 Python 工具包
Embedding 模型 把文字转成向量的模型,负责"理解语义"
LLM 模型 读懂资料并生成回答的模型,负责"写作文"
向量数据库 存向量并支持相似度搜索的数据库,负责"快速查找"

流程就是:Embedding 模型把文档变向量 → 向量数据库存起来 → 提问时转向量去搜 → LLM 根据搜到的结果写回答。HuggingFace 只是下载模型的地方,SentenceTransformer 是加载模型的工具。


7.效果图

外部资料docx.txt为

python 复制代码
Python是由Guido van Rossum于1991年首次发布的一种高级编程语言。Python的设计哲学强调代码的可读性和简洁性,使用缩进来表示代码块。Python是一种解释型语言,这意味着代码可以在不编译的情况下直接运行。Python支持多种编程范式,包括面向对象编程、函数式编程和过程式编程。

Python的标准库非常丰富,被称为"内置电池"(Batteries Included),涵盖了文件操作、网络通信、数据处理等常见功能。Python还拥有庞大的第三方库生态系统,通过pip包管理器可以轻松安装。常用的第三方库包括用于数值计算的NumPy、数据处理的Pandas、机器学习的Scikit-learn和深度学习的PyTorch。

Python的应用领域非常广泛。在Web开发方面,有Django和Flask等流行框架。在数据科学和人工智能领域,Python已经成为最主流的语言。在自动化运维和脚本编写方面,Python也因其简洁易用而广受欢迎。此外,Python在科学计算、金融分析和教育领域也有大量应用。

Python在数据科学领域的地位尤其突出。Pandas库提供了DataFrame数据结构,使得数据处理变得简单高效。Matplotlib和Seaborn等库可以生成高质量的统计图表。Scikit-learn提供了统一的机器学习API,让分类、回归、聚类等任务变得标准化。这些工具的组合使Python成为数据科学家的首选语言。

Python的版本演进也非常活跃。Python 2于2000年发布,2020年正式停止维护。Python 3于2008年发布,是目前主要使用的版本。最新的Python 3.12引入了许多新特性,包括更清晰的错误信息、性能优化和新的语言特性。Python社区采用PEP(Python Enhancement Proposal)流程来讨论和决定语言的变化。

效果图如下

由于实现代码中没有加入上下文,因此每次对话都是独立的,没有对话记忆,如下图。如果需要对话记忆功能,需要把对话历史也发给向量数据库。

8.完整代码

python 复制代码
import chromadb
import os

# HuggingFace 镜像(国内网络加速)
os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"

from sentence_transformers import SentenceTransformer
from openai import OpenAI
from chromadb import Collection as ChromaCollection

# =========================
# 1. KIMI API 配置
# =========================
KIMI_API_KEY = "sk-xxxxxxxxxxxx"
KIMI_BASE_URL = "https://api.moonshot.cn/v1"  # 例如 https://api.moonshot.cn/v1

# client = OpenAI(
#         api_key=os.environ.get("OPENAI_API_KEY"),
#         base_url=os.environ.get("OPENAI_BASE_URL"),
#     )

client = OpenAI(
    api_key=KIMI_API_KEY,
    base_url=KIMI_BASE_URL
)

# =========================
# 2. 读取文档
# =========================
BASE_DIR = os.path.dirname(__file__) # 获取当前脚本所在目录,包含rag.py 和 docs.txt
DOC_PATH = os.path.join(BASE_DIR, "docs.txt")

with open(DOC_PATH, "r", encoding="utf-8") as f:
    text = f.read()

# 文本切分:split() 按句号切分,并去除空白;strip() 去除前后空白;if c.strip() 过滤掉空字符串
chunks = [c.strip() for c in text.split("。") if c.strip()]

# =========================
# 3. Embedding模型(本地,在 main 中延迟加载)
# =========================

embed_model = None

def embed(texts): # 输入是一个文本列表List<Str>,输出是一个向量列表List<List<Float>>
    global embed_model
    if embed_model is None:
        print("正在加载 Embedding 模型...")
        embed_model = SentenceTransformer("shibing624/text2vec-base-chinese")
    return embed_model.encode(texts).tolist() # encode() 返回 numpy 数组,tolist() 转换为 Python 列表,方便存储到 ChromaDB 中

# =========================
# 4. 初始化Chroma
# =========================
client_db = None
collection: ChromaCollection | None = None

def init_chroma():
    global client_db, collection
    print("正在初始化 ChromaDB...")
    client_db = chromadb.PersistentClient(path="./chroma_db")
    collection = client_db.get_or_create_collection(
        name="kimi_rag"
    )

# =========================
# 5. 初始化向量库(只执行一次)
# =========================
def init_db():
    if collection.count() > 0:
        return

    embeddings = embed(chunks)
    # chunks 和 embeddings 的长度应该一致,每个 chunk 对应一个 embedding 向量
    for i, chunk in enumerate(chunks):
        collection.add(
            ids=[str(i)], # ChromaDB 需要每个文档一个唯一ID,这里用字符串形式的索引作为ID
            documents=[chunk], 
            embeddings=[embeddings[i]] 
        ) 

# =========================
# 6. 检索
# =========================
def retrieve(q, k=3):
    q_vec = embed([q])[0] # embed() 返回一个列表,里面是一个向量,所以取 [0] 获取这个向量

    # 进行向量检索,返回最相似的 k 个文档
    results = collection.query(
        query_embeddings=[q_vec],#支持批量查询[q_vec1, q_vec2, ...]
        n_results=k 
    ) # query() 返回一个字典,包含 "ids", "documents", "embeddings" 等字段,这里我们只需要 "documents"

    return results["documents"][0] # results["documents"] 是一个列表,里面是一个列表(因为我们只查询了一个向量),所以取 [0] 获取这个文档列表,即最相似的 k 个文档

# =========================
# 7. 调用Kimi LLM
# =========================
def ask_llm(prompt):
    response = client.chat.completions.create(
        model="moonshot-v1-8k",  # Kimi模型
        messages=[
            {"role": "user", "content": prompt}
        ],
        temperature=0.3 # 控制生成文本的随机程度,0.3 表示较为保守,适合需要准确回答的场景
    )

    return response.choices[0].message.content

# =========================
# 8. RAG主流程
# =========================
def ask(query):
    context = retrieve(query)

    prompt = f"""
你是一个企业知识助手,请严格根据资料回答问题,不允许编造。

【资料】
{chr(10).join(context)}

【问题】
{query}
"""

    return ask_llm(prompt)

# =========================
# 9. 主程序
# =========================
if __name__ == "__main__":
    # 初始化 ChromaDB(必须在 init_db 之前)
    init_chroma()

    print("开始初始化数据库")
    init_db()
    print("数据库初始化完成")

    print("RAG系统已启动(Chroma + Kimi)")

    while True:
        q = input("\n请输入问题:")
        print("\n回答:\n", ask(q))
相关推荐
大模型真好玩1 小时前
LangChain DeepAgents 速通指南(八)—— DeepAgents流式输出详解
人工智能·langchain·agent
码上掘金1 小时前
基于 YOLO 的小麦麦穗检测系统的设计与实现
人工智能·yolo·语言模型
沪漂阿龙1 小时前
AI Agent爆火,但你真的懂LangChain吗?——大模型智能体开发完全指南
人工智能·langchain
可爱の小公举1 小时前
Java 后端程序员转 AI Agent 工程师:一条可执行学习路线
java·人工智能·学习
华盛AI1 小时前
DeepSeek新一代大模型DeepSeek V4深度调研分析
人工智能
Cx330❀1 小时前
深度解析:从原理到实战,一文吃透 Linux 信号机制(上)
大数据·linux·运维·服务器·人工智能·elasticsearch
smallyoung2 小时前
RAG质量评估全攻略:RAGAS四维指标 + 生产级监控实战
人工智能·后端
code_pgf2 小时前
openclaw的gateway详解
人工智能·gateway
生成论实验室2 小时前
《事件关系阴阳博弈动力学:识势应势之道》第十一篇:双脑协同——WOLM与大模型的共生智能
人工智能·算法·语言模型·架构·创业创新