从零构建 DeepSeek 私有知识库系统:基于 Ollama 的本地 RAG 大模型

78 阅读11分钟

💡 本地部署 DeepSeek AI 助手:从零开始的完整指南

本教程带你从零搭建一个本地 AI 助手系统,实现让 DeepSeek 模型“读取文档 + 回答问题”的智能问答功能。 适合:没有编程基础的初学者 / 想在本地运行大模型的人。


🧩 步骤 1:安装 Ollama(如已安装可跳过)

1.1 下载并安装

curl -fsSL https://ollama.com/install.sh | sh

命令解释:

  • curl:命令行下载工具(就像浏览器下载文件)
  • -fsSL:下载参数,保证下载过程稳定
  • | sh:下载完成后直接执行安装脚本

👉 Windows 用户可前往 Ollama 官网 下载安装程序。


1.2 验证安装

ollama --version

看到类似 ollama version 0.1.29 的输出,就说明安装成功。


🤖 步骤 2:下载 DeepSeek 模型

2.1 模型选择对照表

模型名称大小内存需求速度智能程度推荐
deepseek-r1:1.5b1GB4GB很快一般❌ 太弱
deepseek-r1:7b4GB8GB较快不错✅ 推荐(需16GB内存)
deepseek-r1:14b8GB12GB较慢很好⚠️ 16GB勉强可用
deepseek-r1:32b18GB20GB+最强❌ 普通电脑跑不动

2.2 下载模型

ollama pull deepseek-r1:7b

解释:

  • ollama pull:下载模型
  • deepseek-r1:7b:模型名称 + 参数量(7B = 70亿参数)

💬 步骤 3:测试模型是否能正常运行

ollama run deepseek-r1:7b

输入:

你好,请介绍一下你自己

模型能回复说明运行成功。 退出方式:输入 /bye 或按下 Ctrl + C


📄 步骤 4:准备资料

4.1 安装文档处理库

pip3 install pypdf2 python-docx

说明:

  • pip3 install:安装 Python 工具包
  • pypdf2:读取和解析 PDF 文件
  • python-docx:读取 Word 文件(.docx)

4.2 创建项目文件夹

cd ~/Desktop
mkdir my-ai-assistant
cd my-ai-assistant

mkdir documents    # 原始PDF和Word文件
mkdir processed    # 转换后的纯文本
mkdir scripts      # Python脚本

结构示意:

my-ai-assistant/
├── documents/     ← 存放原始资料
├── processed/     ← 转换后的文本
└── scripts/       ← 程序脚本

4.3 创建文档转换脚本

创建一个名为 convert_docs.py 的文件,代码如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
文档转换脚本 - 把PDF和Word文档转成纯文本
"""

import os
from pathlib import Path

# 导入文档处理库
try:
    from PyPDF2 import PdfReader  # 处理PDF
    from docx import Document  # 处理Word
except ImportError:
    print("❌ 缺少必要的库,请运行:")
    print("pip3 install pypdf2 python-docx --break-system-packages")
    exit(1)


def convert_pdf_to_text(pdf_path):
    """
    把PDF文件转换成文本
    参数:pdf_path - PDF文件的路径
    返回:提取的文本内容
    """
    try:
        # 打开PDF文件
        reader = PdfReader(pdf_path)
        text = ""
        
        # 逐页提取文字
        for page_num, page in enumerate(reader.pages, 1):
            print(f"  正在处理第 {page_num}/{len(reader.pages)} 页...")
            text += page.extract_text() + "\n\n"
        
        return text
    except Exception as e:
        print(f"❌ 处理PDF失败:{e}")
        return ""


def convert_docx_to_text(docx_path):
    """
    把Word文档转换成文本
    参数:docx_path - Word文件的路径
    返回:提取的文本内容
    """
    try:
        # 打开Word文档
        doc = Document(docx_path)
        text = ""
        
        # 逐段提取文字
        for para_num, paragraph in enumerate(doc.paragraphs, 1):
            if para_num % 10 == 0:  # 每处理10段显示一次进度
                print(f"  正在处理第 {para_num} 段...")
            text += paragraph.text + "\n"
        
        return text
    except Exception as e:
        print(f"❌ 处理Word失败:{e}")
        return ""


def main():
    """
    主程序:扫描documents文件夹,转换所有PDF和Word文档
    """
    print("=" * 50)
    print("📄 文档转换工具")
    print("=" * 50)
    
    # 设置文件夹路径
    documents_dir = Path("documents")
    processed_dir = Path("processed")
    
    # 检查文件夹是否存在
    if not documents_dir.exists():
        print(f"❌ 找不到 {documents_dir} 文件夹")
        print("请先创建这个文件夹,并把PDF和Word文档放进去")
        return
    
    # 创建输出文件夹
    processed_dir.mkdir(exist_ok=True)
    
    # 获取所有文档文件
    pdf_files = list(documents_dir.glob("*.pdf"))
    docx_files = list(documents_dir.glob("*.docx"))
    
    total_files = len(pdf_files) + len(docx_files)
    
    if total_files == 0:
        print(f"❌ {documents_dir} 文件夹里没有找到PDF或Word文档")
        print("支持的格式:.pdf, .docx")
        return
    
    print(f"\n找到 {len(pdf_files)} 个PDF文件,{len(docx_files)} 个Word文档")
    print(f"总共需要处理 {total_files} 个文件\n")
    
    processed_count = 0
    failed_count = 0
    
    # 处理PDF文件
    for i, pdf_file in enumerate(pdf_files, 1):
        print(f"[{i}/{len(pdf_files)}] 正在转换PDF:{pdf_file.name}")
        text = convert_pdf_to_text(pdf_file)
        
        if text.strip():  # 如果提取到了内容
            # 保存为文本文件
            output_file = processed_dir / f"{pdf_file.stem}.txt"
            output_file.write_text(text, encoding='utf-8')
            print(f"  ✅ 已保存到:{output_file}")
            processed_count += 1
        else:
            print(f"  ⚠️  没有提取到内容,可能是扫描版PDF")
            failed_count += 1
        print()
    
    # 处理Word文档
    for i, docx_file in enumerate(docx_files, 1):
        print(f"[{i}/{len(docx_files)}] 正在转换Word:{docx_file.name}")
        text = convert_docx_to_text(docx_file)
        
        if text.strip():
            output_file = processed_dir / f"{docx_file.stem}.txt"
            output_file.write_text(text, encoding='utf-8')
            print(f"  ✅ 已保存到:{output_file}")
            processed_count += 1
        else:
            print(f"  ⚠️  没有提取到内容")
            failed_count += 1
        print()
    
    # 显示统计结果
    print("=" * 50)
    print(f"✅ 转换完成!")
    print(f"成功:{processed_count} 个")
    print(f"失败:{failed_count} 个")
    print(f"所有文本文件已保存到:{processed_dir}/")
    print("=" * 50)


if __name__ == "__main__":
    main()

4.4 运行转换脚本

cd ~/Desktop/my-ai-assistant
python3 scripts/convert_docs.py

结果:

  • 看到每个文件的转换日志
  • 转换后的 .txt 文件会出现在 processed 文件夹

🧠 步骤 5:构建知识库(RAG 系统)

让 AI 能“阅读”你的资料并基于内容回答问题。


5.1 安装 RAG 相关库

pip3 install chromadb sentence-transformers langchain

关键组件说明:

名称作用
RAG(Retrieval-Augmented Generation)让 AI 先“查资料”再生成答案,减少“胡编乱造”
ChromaDB轻量级的向量数据库,用于存储文本的数字表示
sentence-transformers将文字转为“向量”(机器能理解的数字形式)
langchainAI 应用开发框架,用于连接模型、工具、数据库等组件

📘 简单理解: sentece-transformers 是“翻译文字成数字”的工具, langchain 是“把模型和知识库粘在一起”的胶水。


5.2 创建知识库脚本

scripts 文件夹中创建build_knowledge_base.py,代码如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
知识库构建脚本 - 把你的文档导入向量数据库
这样AI就能快速找到相关资料来回答问题
"""

import os
from pathlib import Path

try:
    import chromadb
    from chromadb.utils import embedding_functions
    from sentence_transformers import SentenceTransformer
except ImportError:
    print("❌ 缺少必要的库,请运行:")
    print("pip3 install chromadb sentence-transformers --break-system-packages")
    exit(1)


def split_text_into_chunks(text, chunk_size=500, overlap=50):
    """
    把长文本切成小块(因为AI一次处理有限制)
    
    参数:
        text: 要切分的文本
        chunk_size: 每块的字数(默认500字)
        overlap: 块之间重叠的字数(避免切断重要信息)
    
    返回:文本块的列表
    """
    chunks = []
    start = 0
    text_length = len(text)
    
    while start < text_length:
        # 切出一块文本
        end = start + chunk_size
        chunk = text[start:end]
        
        # 如果不是最后一块,尝试在标点符号处切断
        if end < text_length:
            # 往回找最近的句号、问号或换行
            for i in range(len(chunk) - 1, max(0, len(chunk) - 100), -1):
                if chunk[i] in ['。', '!', '?', '\n', '.', '!', '?']:
                    chunk = chunk[:i + 1]
                    end = start + i + 1
                    break
        
        if chunk.strip():  # 如果这块不是空的
            chunks.append(chunk.strip())
        
        # 下一块从重叠位置开始
        start = end - overlap
    
    return chunks


def build_knowledge_base():
    """
    主程序:读取所有文本文件,构建知识库
    """
    print("=" * 60)
    print("🔨 正在构建知识库...")
    print("=" * 60)
    
    # 设置路径
    processed_dir = Path("processed")
    db_dir = Path("knowledge_db")
    
    # 检查文件夹
    if not processed_dir.exists() or not list(processed_dir.glob("*.txt")):
        print(f"❌ {processed_dir} 文件夹里没有找到文本文件")
        print("请先运行 convert_docs.py 转换文档")
        return
    
    # 获取所有文本文件
    text_files = list(processed_dir.glob("*.txt"))
    print(f"\n找到 {len(text_files)} 个文本文件\n")
    
    # 初始化向量数据库
    print("📦 正在初始化数据库...")
    client = chromadb.PersistentClient(path=str(db_dir))
    
    # 删除旧的集合(如果存在)
    try:
        client.delete_collection("company_docs")
    except:
        pass
    
    # 创建新集合
    # 使用中文向量模型
    print("📥 正在加载中文向量模型(第一次会下载,需要几分钟)...")
    
    collection = client.create_collection(
        name="company_docs",
        metadata={"description": "公司文档知识库"}
    )
    
    # 处理每个文件
    all_chunks = []
    all_metadatas = []
    all_ids = []
    chunk_id = 0
    
    for file_num, text_file in enumerate(text_files, 1):
        print(f"\n[{file_num}/{len(text_files)}] 正在处理:{text_file.name}")
        
        # 读取文件内容
        text = text_file.read_text(encoding='utf-8')
        print(f"  文件大小:{len(text)} 字")
        
        # 切分成小块
        chunks = split_text_into_chunks(text)
        print(f"  切分为:{len(chunks)} 块")
        
        # 为每块准备元数据(记录来源)
        for chunk in chunks:
            all_chunks.append(chunk)
            all_metadatas.append({
                "source": text_file.name,
                "chunk_id": chunk_id
            })
            all_ids.append(f"doc_{chunk_id}")
            chunk_id += 1
        
        print(f"  ✅ 完成")
    
    # 批量导入数据库
    print(f"\n💾 正在将 {len(all_chunks)} 个文本块导入数据库...")
    print("   (这一步会比较慢,请耐心等待)")
    
    # 分批处理(避免内存溢出)
    batch_size = 100
    for i in range(0, len(all_chunks), batch_size):
        batch_end = min(i + batch_size, len(all_chunks))
        print(f"   进度:{batch_end}/{len(all_chunks)} ({batch_end*100//len(all_chunks)}%)")
        
        collection.add(
            documents=all_chunks[i:batch_end],
            metadatas=all_metadatas[i:batch_end],
            ids=all_ids[i:batch_end]
        )
    
    print("\n" + "=" * 60)
    print("✅ 知识库构建完成!")
    print(f"总共导入:{len(all_chunks)} 个文本块")
    print(f"数据库位置:{db_dir}/")
    print("=" * 60)
    print("\n💡 下一步:运行 ai_assistant.py 开始使用AI助手")


if __name__ == "__main__":
    build_knowledge_base()

该脚本会:

  1. 读取 processed 文件夹的文本
  2. 分块处理(每500字一块)
  3. 向量化后存入 ChromaDB

5.3 构建知识库

cd ~/Desktop/my-ai-assistant
python3 scripts/build_knowledge_base.py

完成后,你的本地知识库就准备好了 🎉


🧩 步骤 6:创建 AI 助手程序

scripts 文件夹中创建 ai_assistant.py,代码如下:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
AI助手主程序 - 你的专属领域智能助手
基于DeepSeek模型和公司文档知识库
"""

import chromadb
import requests
import json
from pathlib import Path


class AIAssistant:
    """AI助手类"""
    
    def __init__(self):
        """初始化AI助手"""
        print("🤖 正在启动AI助手...")
        
        # 连接知识库
        db_dir = Path("knowledge_db")
        if not db_dir.exists():
            print("❌ 找不到知识库!")
            print("请先运行 build_knowledge_base.py 构建知识库")
            exit(1)
        
        self.client = chromadb.PersistentClient(path=str(db_dir))
        self.collection = self.client.get_collection("company_docs")
        
        # Ollama API设置
        self.ollama_url = "http://localhost:11434/api/generate"
        self.model_name = "deepseek-r1:7b"
        
        print("✅ AI助手已就绪!\n")
    
    def search_knowledge(self, question, top_k=3):
        """
        在知识库中搜索相关内容
        
        参数:
            question: 用户的问题
            top_k: 返回最相关的几条结果(默认3条)
        
        返回:相关文档的列表
        """
        results = self.collection.query(
            query_texts=[question],
            n_results=top_k
        )
        
        return results['documents'][0] if results['documents'] else []
    
    def ask(self, question):
        """
        回答用户问题
        
        流程:
        1. 在知识库中搜索相关资料
        2. 把资料和问题一起发给AI
        3. AI基于资料生成答案
        """
        print(f"\n💭 问题:{question}")
        print("\n🔍 正在搜索相关资料...")
        
        # 搜索相关文档
        relevant_docs = self.search_knowledge(question, top_k=3)
        
        if not relevant_docs:
            print("⚠️  没有找到相关资料,AI将基于通用知识回答\n")
            context = ""
        else:
            print(f"✅ 找到 {len(relevant_docs)} 条相关资料\n")
            context = "\n\n".join(relevant_docs)
        
        # 构建提示词(告诉AI如何回答)
        prompt = f"""你是一个专业的AI助手,请基于以下公司内部资料回答用户的问题。

【相关资料】
{context}

【用户问题】
{question}

【回答要求】
1. 如果资料中有相关信息,请基于资料详细回答
2. 如果资料中没有相关信息,请明确告知,不要编造
3. 回答要专业、准确、易懂
4. 适当引用资料中的关键信息

请开始回答:"""
        
        # 调用DeepSeek模型
        print("🤖 AI正在思考...\n")
        print("-" * 60)
        
        try:
            response = requests.post(
                self.ollama_url,
                json={
                    "model": self.model_name,
                    "prompt": prompt,
                    "stream": True  # 流式输出(像打字一样逐字显示)
                },
                stream=True
            )
            
            full_response = ""
            for line in response.iter_lines():
                if line:
                    try:
                        data = json.loads(line)
                        if 'response' in data:
                            text = data['response']
                            print(text, end='', flush=True)
                            full_response += text
                    except:
                        pass
            
            print("\n" + "-" * 60)
            return full_response
            
        except Exception as e:
            print(f"\n❌ 调用AI失败:{e}")
            print("请确保Ollama正在运行:ollama serve")
            return None
    
    def interactive_mode(self):
        """
        交互模式:持续对话
        """
        print("=" * 60)
        print("🎉 欢迎使用专属AI助手!")
        print("=" * 60)
        print("\n💡 使用说明:")
        print("  - 直接输入问题,按回车提交")
        print("  - 输入 'quit' 或 'exit' 退出")
        print("  - 输入 'clear' 清屏")
        print("\n" + "=" * 60 + "\n")
        
        while True:
            try:
                # 获取用户输入
                question = input("👤 你:").strip()
                
                if not question:
                    continue
                
                # 处理特殊命令
                if question.lower() in ['quit', 'exit', '退出']:
                    print("\n👋 再见!")
                    break
                
                if question.lower() in ['clear', '清屏']:
                    import os
                    os.system('clear')
                    continue
                
                # 回答问题
                self.ask(question)
                print("\n" + "=" * 60 + "\n")
                
            except KeyboardInterrupt:
                print("\n\n👋 再见!")
                break
            except Exception as e:
                print(f"\n❌ 出错了:{e}\n")


def main():
    """主程序入口"""
    # 创建AI助手实例
    assistant = AIAssistant()
    
    # 启动交互模式
    assistant.interactive_mode()


if __name__ == "__main__":
    main()

该程序实现问答功能:

  • 用户输入问题
  • 系统在知识库中检索相关内容
  • 把结果交给 DeepSeek 模型生成回答

🚀 步骤 7:启动与测试

7.1 启动 Ollama 服务

ollama serve

保持该窗口运行。


7.2 启动 AI 助手

cd ~/Desktop/my-ai-assistant
python3 scripts/ai_assistant.py

7.3 测试提问

我们公司有哪些产品?

模型将基于你资料中的内容生成回答。


🔧 常见问题 FAQ

Q1. 如何更新知识库?

# 放入新文档
python3 scripts/convert_docs.py
python3 scripts/build_knowledge_base.py

Q2. 回答不准确?

  • 确认资料清晰、无错别字
  • 增加相关内容
  • 尝试更大模型(14B)

Q3. 太慢?

  • 换小模型(如 7B)
  • 优化检索参数(top_k=2
  • 使用 GPU 加速

📚 参考资料


✅ 总结

组件作用说明
Ollama本地运行大模型类似“离线版 ChatGPT”
DeepSeekAI 模型理解和生成自然语言
RAG检索增强生成让 AI “先查资料再回答”
ChromaDB向量数据库存储文本向量
Sentence-transformers文本转向量让机器理解语义
LangChain框架让模型、数据库协同工作