借助 Ollama 和 Embeddings 构建智能知识图谱问答系统
引言
在信息爆炸的时代,如何高效地检索和利用非结构化数据成为了一个核心挑战。传统的关键词搜索往往难以理解语义,导致结果不够精准。知识图谱(Knowledge Graph)通过将实体和关系结构化,能够更直观地展示信息间的关联。然而,构建和维护知识图谱通常需要复杂的工程能力。
本文将介绍如何利用 Ollama 本地大模型能力和 Embeddings 向量技术,快速搭建一个轻量级的智能知识图谱问答系统。这套方案不仅适合个人开发者构建知识库,也适用于企业搭建内部知识检索系统。
一、核心概念解析
1. 什么是知识图谱?
知识图谱本质上是一种语义网络,由节点(实体)和边(关系)组成。例如,"乔布斯"是节点,"苹果公司"是节点,两者之间通过"创始人"这一关系连接。通过图结构,我们可以存储复杂的多跳关系,而不仅仅是扁平的文档。
2. 为什么需要 Embeddings?
自然语言查询(如"苹果公司的创始人是谁")与数据库中的结构化文本并不直接匹配。Embeddings(嵌入)技术将文本转换为高维向量空间中的点。语义相似的文本在向量空间中距离更近。通过计算查询向量与知识库向量的相似度,可以实现语义搜索,而非简单的字符串匹配。
3. Ollama 的角色
Ollama 是一个开源的大模型运行工具,支持本地部署多种模型(如 Llama3)。它提供了便捷的 API 接口,可以生成高质量的文本嵌入(Embeddings),无需依赖昂贵的云端服务,保证了数据隐私和低延迟。
二、环境准备
在开始之前,请确保您的开发环境满足以下要求:
- 操作系统:Linux, macOS 或 Windows (WSL)。
- Python 版本:建议 Python 3.8 及以上。
- 依赖库安装:
pip install numpy requests sqlite3 annoy
- Ollama 服务:
- 访问 ollama.com 下载并安装 Ollama。
- 启动服务后,拉取支持 Embedding 的模型(如
nomic-embed-text 或 llama3.1:8b 配合特定配置)。
- 验证服务:
curl http://localhost:11434/api/embed
三、系统实现步骤
1. 数据准备与数据库设计
首先,我们需要定义数据存储结构。为了演示方便,我们使用 SQLite 存储原始文本和对应的向量数据。虽然生产环境建议使用专门的向量数据库(如 Milvus, Pinecone),但 SQLite 足以支撑原型开发。
import sqlite3
import numpy as np
def create_database(db_path='knowledge_graph.db'):
"""
创建 SQLite 数据库表,用于存储文本及其 Embedding 向量。
"""
conn = sqlite3.connect(db_path)
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS embeddings
(id INTEGER PRIMARY KEY AUTOINCREMENT,
text TEXT NOT NULL,
embedding BLOB,
is_question INTEGER DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
conn.commit()
return conn
2. 生成 Embeddings
利用 Ollama 的 API 将文本转换为向量。这里假设使用 llama3.1:8b 或其他支持 Embedding 的模型。
import requests
import json
def get_embedding(text, model="llama3.1:8b", base_url="http://localhost:11434"):
"""
调用 Ollama API 获取文本的 Embedding 向量。
"""
url = f"{base_url}/api/embeddings"
payload = {
"model": model,
"prompt": text
}
headers = {'Content-Type': 'application/json'}
try:
response = requests.post(url, headers=headers, data=json.dumps(payload))
if response.status_code != 200:
raise Exception(f"API request failed with status code {response.status_code}: {response.text}")
response_data = response.json()
if 'embedding' in response_data:
return np.array(response_data['embedding'], dtype=np.float32)
elif 'embeddings' in response_data and len(response_data['embeddings']) > 0:
return np.array(response_data['embeddings'][0], dtype=np.float32)
else:
raise KeyError(f"No embedding found in API response.")
except Exception as e:
print(f"Error generating embedding: {e}")
3. 构建索引 (Annoy)
为了加速相似性搜索,我们使用 Facebook 开源的 Annoy (Approximate Nearest Neighbors Oh Yeah) 库建立索引。相比暴力遍历,Annoy 能在海量数据下提供毫秒级响应。
from annoy import AnnoyIndex
def build_annoy_index(conn, vector_size=4096, n_trees=10):
"""
从数据库中读取向量,构建 Annoy 索引。
"""
c = conn.cursor()
c.execute("SELECT id, embedding FROM embeddings")
rows = c.fetchall()
annoy_index = AnnoyIndex(vector_size, metric='angular')
for i, (row_id, embedding_blob) in enumerate(rows):
embedding = np.frombuffer(embedding_blob, dtype=np.float32)
if len(embedding) != vector_size:
print(f"Warning: Vector size mismatch at ID {row_id}. Skipping.")
continue
annoy_index.add_item(i, embedding)
print(f"Building index with {len(rows)} vectors...")
annoy_index.build(n_trees)
annoy_index.save('kg_index.ann')
print("Index saved successfully.")
return annoy_index
4. 智能查询流程
当用户发起提问时,系统将执行以下步骤:
- 将问题转换为向量。
- 在 Annoy 索引中查找最相似的 K 个向量。
- 根据 ID 从数据库获取原始文本作为答案。
def query_knowledge_base(query_text, k=5):
"""
执行智能问答查询。
"""
query_vector = get_embedding(query_text)
if query_vector is None:
return "无法生成查询向量,请检查 Ollama 服务。"
annoy_index = AnnoyIndex(len(query_vector), metric='angular')
annoy_index.load('kg_index.ann')
indices = annoy_index.get_nns_by_vector(query_vector, k, include_distances=True)
results = []
for idx, dist in zip(indices[0], indices[1]):
results.append({
"index": idx,
"distance": dist,
"text": f"(模拟返回第 {idx} 条数据内容)"
})
return results
四、优化与进阶
1. 数据更新策略
知识图谱不是一成不变的。随着新知识的产生,需要定期增量更新。
- 全量重建:数据量较小时,直接重新运行
build_annoy_index。
- 增量更新:对于大规模数据,建议引入支持动态更新的向量数据库(如 Faiss, Weaviate),避免频繁重建索引带来的性能开销。
2. 混合搜索增强
单纯依靠向量相似度可能丢失精确匹配的能力。建议结合关键词搜索(BM25)与向量搜索(Vector Search)。
- Rerank 机制:先通过向量召回 Top 50 候选,再通过重排序模型(Cross-Encoder)对结果进行精细化打分。
3. 安全与隐私
- 本地部署:本方案强调使用 Ollama 本地运行,确保敏感数据不出内网。
- 权限控制:在生产环境中,应在应用层增加用户鉴权,防止未授权访问知识库。
五、总结
通过结合 Ollama 的本地推理能力和 Embeddings 向量技术,我们可以低成本地构建具备语义理解能力的智能问答系统。这种架构特别适合中小规模的知识库场景,既避免了高昂的云服务成本,又保护了数据隐私。
未来,您可以进一步探索 LangChain 等框架,将此类系统与 RAG(检索增强生成)深度集成,实现更复杂的业务逻辑,如自动报告生成、多轮对话记忆等功能。动手实践是掌握 AI 技术的最佳途径,建议您从上述代码片段开始,逐步完善自己的知识管理系统。