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 适合通用场景,若涉及代码,可选用 mistral 或 llama3 的嵌入版本。
    原因:不同嵌入模型对领域语义的理解能力不同。
  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 等多格式文档,或集成到前端聊天界面。

相关推荐
第404块砖头7 小时前
Spring Boot 4.1 + Spring AI 2.0:我如何用 Java 微服务把 RAG、知识图谱和 MCP 协议串成一个 Agent 平台
知识图谱·知识库·graph·rag·mcp·spring boot 4.1·spring ai 2.0
AI闲人2 天前
Hermes:把学习写进文件,把知识变成技能
人工智能·知识库·ai 编程·企业ai落地
死磕音视频4 天前
Dify 入门:用 Docker 自部署并搭建知识库问答助手
docker·知识库·dify·大模型应用
code2cat5 天前
【随笔】RAG语义缓存:问题很相似,答案就能直接复用吗
java·缓存·知识库·rag
code2cat6 天前
【随笔】RAG检索缓存:复用证据之前,先把权限和版本放进缓存键
java·人工智能·缓存·知识库·rag
坐吃山猪8 天前
ChromaDB09-数据库操作
数据库·chromadb
java_logo8 天前
Docker 部署 MaxKB:轻松搭建企业级智能体平台
运维·docker·容器·知识库·智能体·maxkb·轩辕镜像
code2cat9 天前
【随笔】RAG遇到冲突证据:先对齐范围,再判断来源
人工智能·知识库·rag
昔我往昔16 天前
chromadb 这个query_texts 查询的是基于分词还是基于向量查询的
python·chromadb
爱写代码的倒霉蛋19 天前
我用book-to-skill把尹圣雨的《TCP/IP网络编程》做成了知识库(适合快速入门网络编程)
网络·网络编程·知识库