使用 Ollama + LangChain + Chroma 构建本地 RAG 应用完整指南

背景介绍

大语言模型(LLM)现在应用很广,但直接用它有一些问题:知识库是固定的、专业知识不够、偶尔会胡扯。检索增强生成(RAG)技术把检索和生成结合起来,先从知识库里找相关信息,再把这些内容喂给 LLM,这样生成的答案更靠谱。以前的 RAG 方案基本都调用 OpenAI API,得花钱,还有数据隐私的破事。

这两年开源出了不少能在本地跑的方案。Ollama 能在自己机器上跑各种开源大模型,LangChain 打包了 RAG 开发的全套工具,Chroma 是轻量级向量数据库。这三个凑一起,就能在本地搭一个 RAG 系统,不用联网,数据全存自己电脑上。

问题描述

很多人会遇到这种情况:基于公司内部文档做个问答系统,数据不想传到云上,就想全放本地。这种需求下,本地 RAG 系统就很合适。

这篇讲清楚怎么从零开始,用 Ollama 跑开源模型(Llama 3、Qwen 什么的),配合 LangChain 的 RAG 组件和 Chroma 向量数据库,搭一个本地问答系统。整个过程不需要互联网,满足企业数据安全的要求。

详细步骤

环境准备

先装必要的 Python 包。Python 3.10 或更高版本。建个虚拟环境,然后装依赖:

pip install langchain langchain-community langchain-chroma ollama chromadb beautifulsoup4 requests

安装并启动 Ollama

Ollama 支持 macOS、Linux 和 Windows。Linux 上用一键脚本安装:

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

装完下模型。推荐 qwen2.5 或 llama3,还有 nomic-embed-text 用来做文本嵌入:

ollama pull qwen2.5:7b
ollama pull nomic-embed-text

启动服务:

ollama serve

准备知识文档

搞几个文本文件放到目录里当知识库。Markdown、TXT、HTML 都行。每个文件算一个知识主题。

构建 RAG 应用

流程是这样的:

  1. 加载文档 — 用 LangChain 的文档加载器读本地文件
  2. 分割 — 把文档切成小块,方便后面检索
  3. 向量化 — 用嵌入模型把文本块变成向量,存到 Chroma
  4. 检索 — 把用户问题转成向量,从数据库找最相似的文本块
  5. 生成 — 把检索到的内容和问题一起发给 LLM,拿答案

完整代码示例

#!/usr/bin/env python3
"""
本地 RAG 问答系统
使用 Ollama + LangChain + Chroma
"""

import os
from pathlib import Path
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.embeddings import OllamaEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_community.llms import Ollama
from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain import hub

# 配置参数
DOCS_DIR = "./docs"  # 知识文档目录
VECTORSTORE_DIR = "./vectorstore"  # 向量数据库存储路径
LLM_MODEL = "qwen2.5:7b"  # 使用的 LLM 模型
EMBED_MODEL = "nomic-embed-text"  # 嵌入模型

def load_documents(docs_dir: str):
    """加载目录中的所有文档"""
    documents = []
    docs_path = Path(docs_dir)
    
    if not docs_path.exists():
        raise FileNotFoundError(f"文档目录不存在: {docs_dir}")
    
    # 支持多种文本格式
    for ext in ["*.txt", "*.md", "*.html"]:
        for file_path in docs_path.glob(ext):
            loader = TextLoader(str(file_path), encoding="utf-8")
            docs = loader.load()
            documents.extend(docs)
    
    print(f"已加载 {len(documents)} 个文档")
    return documents

def split_documents(documents):
    """将文档分割成小块"""
    text_splitter = RecursiveCharacterTextSplitter(
        chunk_size=500,
        chunk_overlap=50,
        length_function=len,
    )
    chunks = text_splitter.split_documents(documents)
    print(f"文档分割完成,共 {len(chunks)} 个文本块")
    return chunks

def create_vectorstore(chunks, persist_dir: str):
    """创建向量数据库"""
    # 使用 Ollama 的嵌入模型
    embeddings = OllamaEmbeddings(
        model=EMBED_MODEL,
        base_url="http://localhost:11434"
    )
    
    # 如果向量数据库已存在,直接加载
    if os.path.exists(persist_dir):
        print("加载已存在的向量数据库...")
        vectorstore = Chroma(
            persist_directory=persist_dir,
            embedding_function=embeddings
        )
    else:
        print("创建新的向量数据库...")
        vectorstore = Chroma.from_documents(
            documents=chunks,
            embedding=embeddings,
            persist_directory=persist_dir
        )
    
    return vectorstore

def setup_qa_chain(vectorstore):
    """设置问答链"""
    # 使用 Ollama 运行 LLM
    llm = Ollama(
        model=LLM_MODEL,
        base_url="http://localhost:11434",
        temperature=0.7
    )
    
    # 从 LangChain Hub 获取检索增强生成提示模板
    retrieval_qa_prompt = hub.pull("langchain-ai/retrieval-qa-string-template")
    
    # 创建文档组合链
    combine_docs_chain = create_stuff_documents_chain(
        llm,
        retrieval_qa_prompt
    )
    
    # 创建检索链
    retrieval_chain = create_retrieval_chain(
        vectorstore.as_retriever(),
        combine_docs_chain
    )
    
    return retrieval_chain

def main():
    """主函数"""
    print("=" * 50)
    print("本地 RAG 问答系统")
    print("=" * 50)
    
    # 步骤 1: 加载文档
    print("\n[1/4] 加载文档...")
    documents = load_documents(DOCS_DIR)
    
    # 步骤 2: 分割文档
    print("\n[2/4] 分割文档...")
    chunks = split_documents(documents)
    
    # 步骤 3: 创建向量数据库
    print("\n[3/4] 创建向量数据库...")
    vectorstore = create_vectorstore(chunks, VECTORSTORE_DIR)
    
    # 步骤 4: 设置问答系统
    print("\n[4/4] 初始化问答系统...")
    qa_chain = setup_qa_chain(vectorstore)
    
    # 交互式问答
    print("\n" + "=" * 50)
    print("问答系统已就绪!输入问题开始咨询,输入 quit 退出")
    print("=" * 50)
    
    while True:
        question = input("\n问题: ").strip()
        if question.lower() in ["quit", "exit", "q"]:
            print("再见!")
            break
        
        if not question:
            continue
        
        print("\n思考中...")
        response = qa_chain.invoke({"input": question})
        
        print("\n" + "-" * 50)
        print("回答:")
        print(response["answer"])
        print("-" * 50)
        
        # 显示参考来源
        if "context" in response:
            print("\n参考来源:")
            for i, doc in enumerate(response["context"], 1):
                source = doc.metadata.get("source", "未知")
                print(f"  {i}. {source}")

if __name__ == "__main__":
    main()

准备测试文档

docs 目录下建个 about.txt

# 公司介绍

我们的公司成立于 2020 年,专注于人工智能技术的研发和应用。

# 产品服务

我们提供以下核心产品:
1. 智能客服系统 - 基于大语言模型的客户服务解决方案
2. 数据分析平台 - 企业级数据分析工具
3. 自动化测试框架 - 软件质量保障工具

# 联系方式

邮箱: contact@example.com
电话: 400-123-4567
地址: 北京市海淀区科技园区

运行结果

跑起来之后,系统会按顺序执行:

==================================================
本地 RAG 问答系统
==================================================

[1/4] 加载文档...
已加载 1 个文档

[2/4] 分割文档...
文档分割完成,共 8 个文本块

[3/4] 创建向量数据库...
创建新的向量数据库...

[4/4] 初始化问答系统...
==================================================
问答系统已就绪!输入问题开始咨询,输入 quit 退出
==================================================

问题: 你们公司提供什么产品?
思考中...

--------------------------------------------------
回答:
根据提供的信息,我们公司提供以下核心产品:

1. 智能客服系统 - 基于大语言模型的客户服务解决方案
2. 数据分析平台 - 企业级数据分析工具  
3. 自动化测试框架 - 软件质量保障工具

这些产品覆盖了 AI 应用、数据分析和软件质量保障等领域。
--------------------------------------------------

参考来源:
  1. docs/about.txt

可以看到,系统正常回答了关于公司产品的问题,而且准确引用了知识来源。

总结

这篇文章演示了怎么用 Ollama、LangChain 和 Chroma 搭本地 RAG。几个好处:

  • 数据全在本地,不用传到云上,企业隐私有保障
  • 不依赖外部 API,断网也能跑
  • 开源模型随便选,根据自己机器配置挑

后续可以捣鼓的方向:换更大更专业的模型改善回答质量;调一调文本分割策略提高检索准度;加上对话历史支持多轮问答;包装成 API 给其他服务调用。

这个本地 RAG 方案给企业和开发者提供了一个安全、私有的 AI 知识管理选择。

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇