上回说到
理论部分咱们都盘完了。

切分、向量库、混合检索、Prompt,零件都齐了。
今天,咱们把它们组装起来,搓一台能跑的车!

本篇包含完整代码,建议收藏后对着敲。


🏗️ 架构设计

在写代码之前,先理清流程。
一个最简可用的企业知识助手(MVP),长这样:

用户上传文档 (PDF/MD) 
  ↓
后台:读取 -> 切分 -> 向量化 -> 存入 Chroma
  ↓
用户提问
  ↓
后台:问题向量化 -> 检索相关段落 -> 组装 Prompt -> 请求大模型
  ↓
返回答案

技术栈选择:

  • 后端:Python + FastAPI(轻量、快、原生支持异步)
  • 向量库:Chroma(本地部署,零成本)
  • 大模型接口:Ollama(调用本地 Gemma 4 或 Llama 3)

💻 核心代码实现

项目结构:

rag-bot/
├── app.py           # 核心逻辑
├── utils.py         # 工具函数
└── requirements.txt # 依赖

第一步:环境准备

# 1. 创建虚拟环境
python -m venv venv
source venv/bin/activate  # Windows: venv/Scripts/activate

# 2. 安装依赖
pip install fastapi uvicorn chromadb langchain-text-splitters ollama python-multipart

💡 注意:

  • python-multipart 是 FastAPI 处理文件上传必须的依赖。
  • 确保本地已经安装并运行了 Ollama,且下载了 gemma2:9b 模型:ollama pull gemma2:9b

第二步:编写文档处理模块 (utils.py)

负责把文本切碎存起来。

# utils.py
import chromadb
from langchain_text_splitters import RecursiveCharacterTextSplitter

# 初始化 Chroma 客户端(数据存在 ./chroma_db 目录)
# PersistentClient 会自动创建目录并持久化数据
client = chromadb.PersistentClient(path="./chroma_db")
collection = client.get_or_create_collection(name="knowledge_base")

def add_document(text: str, doc_id: str) -> str:
    """添加文档到知识库"""
    
    # 1. 切分
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=500, 
        chunk_overlap=50
    )
    chunks = splitter.split_text(text)
    
    if not chunks:
        return "文档为空,未添加任何内容。"
    
    # 2. 生成 ID
    # Chroma 需要每个 chunk 有唯一 ID,这里用 doc_id + 序号
    ids = [f"{doc_id}_{i}" for i in range(len(chunks))]
    
    # 3. 存入(Chroma 默认会自动调用内置 Embedding 模型)
    # 注意:生产环境建议用专业的 Embedding API,这里为了简单用默认的
    collection.add(
        documents=chunks,
        ids=ids,
        metadatas=[{"source": doc_id} for _ in chunks]
    )
    
    return f"成功添加 {len(chunks)} 个片段"

def search_documents(query: str, n_results: int = 3) -> list:
    """检索相关文档"""
    results = collection.query(
        query_texts=[query],
        n_results=n_results
    )
    # results["documents"] 是二维列表,取第一个 query 的结果
    return results["documents"][0]

第三步:编写后端 API (app.py)

负责提供上传和问答接口。

# app.py
from fastapi import FastAPI, UploadFile, File
from pydantic import BaseModel
import ollama
from utils import add_document, search_documents

app = FastAPI(title="企业知识助手")

class Question(BaseModel):
    query: str

@app.post("/upload")
async def upload_file(file: UploadFile = File(...)):
    """上传文件并索引"""
    try:
        content = await file.read()
        # 尝试 utf-8 解码,失败则用 latin-1 兜底
        try:
            text = content.decode("utf-8")
        except UnicodeDecodeError:
            text = content.decode("latin-1")
            
        msg = add_document(text, doc_id=file.filename)
        return {"message": msg}
    except Exception as e:
        return {"error": str(e)}

@app.post("/ask")
async def ask_question(q: Question):
    """提问接口"""
    
    # 1. 检索资料
    docs = search_documents(q.query)
    if not docs:
        return {"answer": "抱歉,知识库中未找到相关信息。"}
    
    # 2. 拼接 Prompt
    context = "/n".join(docs)
    prompt = f"""请根据以下资料回答问题。如果资料不足,请回答“不知道”。
    
【参考资料】
{context}

【问题】
{q.query}
"""
    
    # 3. 调用 Ollama (假设你本地跑着 Ollama,模型是 gemma2:9b)
    # 如果你用的是 OpenAI 兼容接口,这里换成 httpx 请求即可
    try:
        response = ollama.chat(
            model='gemma2:9b', 
            messages=[{'role': 'user', 'content': prompt}]
        )
        answer = response['message']['content']
    except Exception as e:
        answer = f"模型调用失败:{str(e)}"
        
    return {"answer": answer, "sources": docs}

第四步:运行与测试

# 启动服务
uvicorn app:app --reload

打开浏览器访问 http://localhost:8000/docs,你会看到 Swagger UI 界面。

测试流程:

  1. 1. 在 /upload 接口上传一个 txt 文件(里面写上你的公司制度)。

  2. 2. 在 /ask 接口输入问题:“年假怎么休?”

  3. 3. 看!系统返回了基于文档的精准答案!


📦 怎么部署上线?

代码跑通了,怎么给同事用?

  1. 1. 局域网部署:

找一台有显卡(或内存够大)的服务器。

uvicorn app:app --host 0.0.0.0 --port 8000

同事访问 http://你的 IP:8000/docs 就能用了。

  1. 2. 前端界面:

Swagger 界面太丑?你可以写一个简单的 HTML 页面,用 fetch 调用 /ask 接口。
或者直接用 Open WebUI,它支持接入 OpenAI 兼容接口,你把这个 FastAPI 包装成 OpenAI 格式就能无缝对接。

  1. 3. 容器化:

写个 Dockerfile,打包成镜像,丢到 Docker-compose 里一键启动。


📝 总结一下

看,RAG 系统其实没想象中那么复杂。
核心就是:存数据 -> 查数据 -> 喂模型。

  • utils.py 负责“存”和“查”。
  • app.py 负责“喂”和“返回”。
  • Chroma 是记忆,Ollama 是大脑。

这就搭好了最基础的版本。
当然,生产环境还要考虑并发、权限控制、日志监控等等。
但作为起步,这个 MVP 已经足够你向老板演示“我们的 AI 知识库”了!

下一篇,作为系列的收官之作,咱们聊聊 RAG 评测:回答准确率怎么量化?怎么知道你的 RAG 好不好?


觉得这篇代码实战对你有帮助?点个 ,下一篇教你如何量化 RAG 效果!

这里给大家精心整理了一份全面的AI大模型学习资源包括:AI大模型全套学习路线图(从入门到实战)、精品AI大模型学习书籍手册、视频教程、实战学习、面试题等,资料免费分享

👇👇扫码免费领取全部内容👇👇
在这里插入图片描述

1. 成长路线图&学习规划

要学习一门新的技术,作为新手一定要先学习成长路线图方向不对,努力白费

这里,我们为新手和想要进一步提升的专业人士准备了一份详细的学习成长路线图和规划。可以说是最科学最系统的学习成长路线。
在这里插入图片描述

2. 大模型经典PDF书籍

书籍和学习文档资料是学习大模型过程中必不可少的,我们精选了一系列深入探讨大模型技术的书籍和学习文档,它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础(书籍含电子版PDF)

在这里插入图片描述

3. 大模型视频教程

对于很多自学或者没有基础的同学来说,书籍这些纯文字类的学习教材会觉得比较晦涩难以理解,因此,我们提供了丰富的大模型视频教程,以动态、形象的方式展示技术概念,帮助你更快、更轻松地掌握核心知识

在这里插入图片描述

4. 2026行业报告

行业分析主要包括对不同行业的现状、趋势、问题、机会等进行系统地调研和评估,以了解哪些行业更适合引入大模型的技术和应用,以及在哪些方面可以发挥大模型的优势。

5. 大模型项目实战

学以致用 ,当你的理论知识积累到一定程度,就需要通过项目实战,在实际操作中检验和巩固你所学到的知识,同时为你找工作和职业发展打下坚实的基础。

在这里插入图片描述

6. 大模型面试题

面试不仅是技术的较量,更需要充分的准备。

在你已经掌握了大模型技术之后,就需要开始准备面试,我们将提供精心整理的大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。

在这里插入图片描述

7. 资料领取:全套内容免费抱走,学 AI 不用再找第二份

不管你是 0 基础想入门 AI 大模型,还是有基础想冲刺大厂、了解行业趋势,这份资料都能满足你!
现在只需按照提示操作,就能免费领取:

👇👇扫码免费领取全部内容👇👇
在这里插入图片描述

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐