Ollama 本地知识库:用 ChromaDB 实现文档向量化与语义检索Ollama

1. 准备环境:安装 Ollama 与 ChromaDB

本地知识库的核心是 向量数据库 ,用于存储文档的语义向量。ChromaDB 轻量、易用,适合个人开发者。首先确保已安装 Ollama,并拉取一个嵌入模型(如 nomic-embed-text),该模型将文档转为向量。

复制代码
# 安装 ChromaDB
pip install chromadb

# 拉取嵌入模型
ollama pull nomic-embed-text

原因:嵌入模型负责将文本转化为数值向量,向量数据库根据向量相似度检索文档。没有向量化,语义搜索就无从谈起。

2. 加载文档并生成向量

假设你有一个 Markdown 文件 knowledge.md,内容为技术问答。首先读取文件,分割为段落(chunks),并利用 Ollama 生成每个段落的向量。

复制代码
import chromadb
from chromadb.utils import embedding_functions

# 初始化 ChromaDB 客户端
client = chromadb.PersistentClient(path='./kb_chroma')

# 使用 Ollama 嵌入函数
ollama_ef = embedding_functions.OllamaEmbeddingFunction(
    model_name="nomic-embed-text",
    url="http://localhost:11434/api/embeddings"
)

# 创建或获取集合
collection = client.get_or_create_collection(
    name="my_kb",
    embedding_function=ollama_ef
)

# 加载文档并添加
with open('knowledge.md', 'r') as f:
    text = f.read()

# 简单分段(每段200字符)
chunks = [text[i:i+200] for i in range(0, len(text), 200)]
ids = [f"chunk_{i}" for i in range(len(chunks))]

collection.add(
    documents=chunks,
    ids=ids
)
print(f"已添加 {len(chunks)} 个文档块")

原因OllamaEmbeddingFunction 封装了调用 Ollama API 的逻辑,避免了手动构造请求。分段是为了让每个向量对应一个语义连贯的片段,提升检索精度。

3. 实现语义检索

当用户提问时,将问题向量化后在 ChromaDB 中搜索最相似的文档块。以下示例查询"如何配置 Ollama 模型?"。

复制代码
query = "如何配置 Ollama 模型?"

# 执行查询(返回前3个结果)
results = collection.query(
    query_texts=[query],
    n_results=3
)

print("检索结果:")
for doc, dist in zip(results['documents'][0], results['distances'][0]):
    print(f"距离 {dist:.4f}: {doc[:50]}...")

原因 :ChromaDB 会自动调用 OllamaEmbeddingFunction 对查询文本进行向量化,然后计算余弦距离。距离越小,语义越相似。

4. 最佳实践清单

  1. 选择合适的嵌入模型nomic-embed-text 适合通用场景,若涉及代码,可选用 mistralllama3 的嵌入版本。
    原因:不同嵌入模型对领域语义的理解能力不同。
  2. 合理分段文档 :推荐 200-500 字符一段,段与段之间保留上下文重叠。
    示例 :使用 RecursiveCharacterTextSplitter 实现智能分割。
  3. 持久化存储 :使用 PersistentClient 而非临时内存,避免每次重启重新构建知识库。
    原因:ChromaDB 会将向量数据写入磁盘,重启后自动加载。
  4. 元数据过滤 :为每个文档块添加元数据(如来源文件、章节),在查询时可按条件过滤。
    示例collection.add(documents=..., ids=..., metadatas=[{"source": "knowledge.md"}])
  5. 调整返回数量 :根据场景设置 n_results,一般 3-5 个足够,避免信息过载。

5. 集成到 Ollama 对话

将检索到的文档块作为上下文,结合用户问题发送给 Ollama 模型生成回答,实现 RAG(检索增强生成)。

复制代码
import requests

# 取检索结果的前 1000 字作为上下文
context = "\n".join(results['documents'][0])[:1000]
prompt = f"基于以下知识回答:\n{context}\n\n问题:{query}"

response = requests.post("http://localhost:11434/api/generate",
    json={"model": "llama3.2", "prompt": prompt, "stream": False})

print(response.json()['response'])

原因:仅靠大模型自身知识可能过时或缺失,本地知识库提供最新、私有的信息,大幅提升回答准确度。

通过以上步骤,你已成功搭建本地知识库,并实现语义检索与 RAG 对话。后续可以扩展为支持 PDF、Word 等多格式文档,或集成到前端聊天界面。

相关推荐
jianpeng的工程笔记7 小时前
WeKnora 搭建研发 EDA 知识库:Docker 部署、RAG 与 Wiki 实践
docker·知识库·eda·rag
ZGi.ai8 小时前
开源 AI Agent Runtime:培训题生成
知识库·工作流·ai智能体·zgi·agentruntime·培训资料
AI闲人1 天前
Agent 平台的两种哲学:从 WeKnora 和 Molio 聊起
人工智能·知识库·企业ai落地
53AI2 天前
多模态知识库实践:音频、表格、PDF混合文档如何变成可检索的知识资产
知识库·企业知识库·ai知识库·ai落地
慧都小妮子4 天前
Word/Excel/PPT 如何稳定导出 Markdown?文档 SDK 三线能力拆解
.net·markdown·知识库·aspose·rag·文档转换·文档互操作
yxlalm5 天前
SpringAI+RAG-检索文档变知识:从上传到精准检索的完整链路
spring·知识库·rag
我有满天星辰6 天前
一次性读取整个 Obsidian:自动把我的 Markdown 变成 AI 知识库
llm·知识库
ZGi.ai7 天前
知识库权限变了,怎样避免答错?
agent·权限管理·知识库·工作流·zgi·客服运营