构建智能问答系统:ollama-python + 知识库检索
【免费下载链接】ollama-python 项目地址: https://gitcode.com/GitHub_Trending/ol/ollama-python
引言:告别通用AI的知识局限
你是否遇到过这样的困境:当使用AI模型回答专业领域问题时,它要么给出泛泛而谈的答案,要么编造看似合理却错误的信息?传统大语言模型(LLM)受限于训练数据的时效性和领域覆盖范围,在企业内部文档、专业知识库等特定场景下表现不佳。本文将带你构建一个基于ollama-python的智能问答系统,通过本地知识库检索与大语言模型的结合,实现精准、可靠的问答能力。
读完本文后,你将掌握:
- 如何使用ollama-python进行文本嵌入(Embedding)生成
- 构建轻量级向量知识库的完整流程
- 实现"检索-增强生成(RAG)"的核心逻辑
- 开发支持上下文记忆的智能问答系统
- 系统性能优化与部署最佳实践
技术架构概览
智能问答系统的核心在于将用户查询与知识库内容精准匹配,并结合上下文生成回答。以下是基于ollama-python的系统架构:
核心技术组件
| 组件 | 功能 | ollama-python实现 |
|---|---|---|
| 文本嵌入 | 将文本转换为向量表示 | client.embed(model="llama3.2", input=text) |
| 向量存储 | 存储和检索文本向量 | 可结合FAISS/Chroma等库实现 |
| 检索引擎 | 相似文档匹配 | 余弦相似度计算 |
| 对话管理 | 上下文状态维护 | 消息列表(messages)管理 |
| 生成模块 | 基于检索结果生成回答 | client.chat(model="qwen3", messages=prompt) |
环境准备与依赖安装
系统要求
- Python 3.8+
- Ollama服务端(0.1.26+)
- 至少4GB内存(推荐8GB+)
快速安装
# 克隆仓库
git clone https://gitcode.com/GitHub_Trending/ol/ollama-python
cd ollama-python
# 创建虚拟环境
python -m venv venv
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
# 安装依赖
pip install -r requirements.txt
核心依赖解析
requirements.txt中关键依赖:
httpx==0.28.1 # HTTP客户端,ollama API通信
pydantic==2.10.6 # 数据验证与模型定义
anyio==4.8.0 # 异步支持
构建知识库检索系统
1. 文本嵌入生成
使用ollama-python的embed方法将文本转换为向量:
from ollama import Client
client = Client()
def generate_embedding(text: str) -> list[float]:
"""生成文本嵌入向量"""
response = client.embed(
model="llama3.2", # 使用适合嵌入的模型
input=text,
options={"temperature": 0} # 嵌入生成不需要随机性
)
return response["embeddings"][0] # 返回向量列表
# 示例
text = "ollama-python是Ollama的Python客户端库,支持对话、生成和嵌入等功能。"
vector = generate_embedding(text)
print(f"嵌入向量维度: {len(vector)}")
print(f"向量前5个值: {vector[:5]}")
注意:选择专为嵌入设计的模型(如
llama3.2、bge等)可获得更好效果。不同模型生成的向量维度可能不同,需统一处理。
2. 实现向量存储与检索
由于ollama-python本身不提供向量存储功能,我们可以实现一个轻量级向量数据库:
import numpy as np
from typing import List, Dict, Tuple
class SimpleVectorDB:
def __init__(self):
self.vectors = [] # 存储向量
self.texts = [] # 存储原始文本
self.metadata = [] # 存储元数据
def add(self, text: str, vector: List[float], meta: Dict = None):
"""添加文本及其向量到数据库"""
self.texts.append(text)
self.vectors.append(vector)
self.metadata.append(meta or {})
def search(self, query_vector: List[float], top_k: int = 3) -> List[Tuple[str, float, Dict]]:
"""检索与查询向量最相似的文本"""
if not self.vectors:
return []
# 转换为numpy数组进行计算
vectors_np = np.array(self.vectors)
query_np = np.array(query_vector)
# 计算余弦相似度
similarities = np.dot(vectors_np, query_np) / (
np.linalg.norm(vectors_np, axis=1) * np.linalg.norm(query_np)
)
# 获取Top K结果
top_indices = similarities.argsort()[-top_k:][::-1]
return [
(self.texts[i], similarities[i], self.metadata[i])
for i in top_indices
]
# 使用示例
db = SimpleVectorDB()
# 添加示例文档
documents = [
"ollama-python支持同步和异步两种调用方式。",
"使用client.chat()方法可以进行多轮对话。",
"embed接口能将文本转换为向量用于相似性搜索。",
"工具调用功能允许模型调用外部函数获取信息。",
"stream参数设为True可实现流式响应输出。"
]
for doc in documents:
vec = generate_embedding(doc)
db.add(doc, vec, {"length": len(doc)})
# 查询相似文档
query = "如何进行多轮对话?"
query_vec = generate_embedding(query)
results = db.search(query_vec, top_k=2)
print(f"查询: {query}")
for i, (text, score, meta) in enumerate(results, 1):
print(f"结果{i} (相似度: {score:.4f}): {text}")
3. 构建知识库索引
实际应用中,我们需要处理大量文档,可按以下流程构建索引:
import os
from pathlib import Path
def load_documents(docs_dir: str) -> List[str]:
"""从目录加载文档"""
documents = []
for ext in ['.txt', '.md', '.pdf']: # 支持多种格式
for file in Path(docs_dir).glob(f'**/*{ext}'):
try:
with open(file, 'r', encoding='utf-8') as f:
documents.append(f.read())
except Exception as e:
print(f"无法读取文件 {file}: {e}")
return documents
def split_text(text: str, chunk_size: int = 500, chunk_overlap: int = 50) -> List[str]:
"""文本分块处理"""
chunks = []
for i in range(0, len(text), chunk_size - chunk_overlap):
chunks.append(text[i:i+chunk_size])
return chunks
# 完整索引构建流程
def build_knowledge_base(docs_dir: str, db: SimpleVectorDB):
"""构建知识库索引"""
print(f"从{docs_dir}加载文档...")
documents = load_documents(docs_dir)
print(f"加载了{len(documents)}个文档")
total_chunks = 0
for doc in documents:
chunks = split_text(doc)
total_chunks += len(chunks)
for chunk in chunks:
vec = generate_embedding(chunk)
db.add(chunk, vec, {"source": "local"})
print(f"知识库构建完成,共{total_chunks}个文本块")
# 使用示例
# build_knowledge_base("./docs", db)
实现智能问答系统
1. 核心问答逻辑
结合检索与生成功能,实现智能问答:
def build_prompt(query: str, context_chunks: List[str]) -> List[Dict]:
"""构建带上下文的提示词"""
system_prompt = """你是一个基于知识库的问答助手。使用以下提供的上下文信息来回答用户问题。
如果上下文信息不足以回答,直接说"根据提供的知识库,我无法回答该问题",不要编造信息。
回答要简洁明了,基于事实。"""
context = "\n\n".join([f"[{i+1}] {chunk}" for i, chunk in enumerate(context_chunks)])
return [
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"上下文信息:\n{context}\n\n用户问题: {query}"}
]
def qa_system(query: str, db: SimpleVectorDB, model: str = "qwen3") -> str:
"""智能问答系统主函数"""
# 1. 生成查询向量
query_vec = generate_embedding(query)
# 2. 检索相关上下文
results = db.search(query_vec, top_k=3)
context_chunks = [text for text, _, _ in results]
# 3. 构建提示词
prompt = build_prompt(query, context_chunks)
# 4. 调用LLM生成回答
response = client.chat(model=model, messages=prompt)
return response.message.content
# 使用示例
query = "ollama-python如何实现多轮对话?"
answer = qa_system(query, db)
print(f"Q: {query}\nA: {answer}")
2. 对话历史管理
扩展系统以支持多轮对话:
class ChatManager:
"""对话管理器,维护对话历史"""
def __init__(self, db: SimpleVectorDB, model: str = "qwen3", max_history: int = 10):
self.db = db
self.model = model
self.max_history = max_history
self.history = [] # 存储对话历史
def add_message(self, role: str, content: str):
"""添加消息到历史"""
self.history.append({"role": role, "content": content})
# 限制历史长度
if len(self.history) > self.max_history * 2: # 每条对话包含user和assistant
self.history = self.history[-self.max_history*2:]
def query(self, user_query: str) -> str:
"""处理用户查询并返回回答"""
# 1. 生成查询向量并检索
query_vec = generate_embedding(user_query)
results = self.db.search(query_vec, top_k=3)
context_chunks = [text for text, _, _ in results]
# 2. 构建带历史和上下文的提示词
system_prompt = """你是一个基于知识库的问答助手。使用提供的上下文信息和对话历史来回答用户问题。
如果上下文信息不足以回答,直接说"根据提供的知识库,我无法回答该问题",不要编造信息。"""
context = "\n\n".join([f"[{i+1}] {chunk}" for i, chunk in enumerate(context_chunks)])
# 构建完整消息列表
messages = [{"role": "system", "content": system_prompt}]
# 添加对话历史
messages.extend(self.history)
# 添加当前查询(带上下文)
messages.append({
"role": "user",
"content": f"上下文信息:\n{context}\n\n用户问题: {user_query}"
})
# 3. 获取回答
response = client.chat(model=self.model, messages=messages)
answer = response.message.content
# 4. 更新对话历史
self.add_message("user", user_query)
self.add_message("assistant", answer)
return answer
# 使用示例
chatbot = ChatManager(db)
queries = [
"ollama-python有哪些核心功能?",
"如何使用embed方法生成文本向量?",
"这些向量可以用来做什么?"
]
for q in queries:
print(f"Q: {q}")
print(f"A: {chatbot.query(q)}\n")
3. 工具调用增强(高级功能)
结合ollama-python的工具调用能力,实现更强大的问答系统:
from typing import List, Callable, Dict, Any
class ToolAugmentedChat(ChatManager):
"""支持工具调用的增强型对话管理器"""
def __init__(self, db: SimpleVectorDB, tools: List[Callable], model: str = "qwen3"):
super().__init__(db, model)
self.tools = {tool.__name__: tool for tool in tools}
self._register_tools()
def _register_tools(self):
"""注册工具到系统提示词"""
tool_descriptions = []
for name, tool in self.tools.items():
docstring = tool.__doc__ or "无描述"
tool_descriptions.append(f"- {name}: {docstring}")
tool_prompt = "\n你可以使用以下工具来获取额外信息(如果需要):\n" + "\n".join(tool_descriptions)
tool_prompt += "\n如果需要调用工具,使用和<|FunctionCallEnd|>包裹,格式为:"
tool_prompt += "\n<|FunctionCallBegin|>[{"name": "工具名", "parameters": {"参数名": "参数值"}}]<|FunctionCallEnd|>"
# 更新系统提示词
self.system_prompt = super().system_prompt + tool_prompt
def _process_tool_calls(self, response_content: str) -> str:
"""处理工具调用并返回结果"""
import json
import re
# 提取工具调用指令
pattern = r"<\|FunctionCallBegin\|>(.*?)<\|FunctionCallEnd\|>"
matches = re.findall(pattern, response_content, re.DOTALL)
if not matches:
return response_content
# 执行工具调用
tool_results = []
for match in matches:
try:
call = json.loads(match)
tool_name = call["name"]
params = call["parameters"]
if tool_name not in self.tools:
tool_results.append(f"错误:工具 {tool_name} 不存在")
continue
# 调用工具
result = self.tools[tool_name](**params)
tool_results.append(f"工具 {tool_name} 返回结果:{result}")
except Exception as e:
tool_results.append(f"工具调用错误:{str(e)}")
# 将工具结果添加到对话历史
self.add_message("system", "\n".join(tool_results))
return "\n".join(tool_results)
# 示例工具
def current_time() -> str:
"""获取当前时间"""
from datetime import datetime
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 使用示例
# augmented_chat = ToolAugmentedChat(db, tools=[current_time])
# print(augmented_chat.query("现在是什么时间?"))
系统优化与最佳实践
1. 性能优化策略
| 优化方向 | 实现方法 | 效果 |
|---|---|---|
| 嵌入缓存 | 使用字典缓存已生成的文本嵌入 | 减少重复计算,提升检索速度 |
| 批量处理 | 批量生成文本嵌入 | 降低API调用次数,提升效率 |
| 模型选择 | 嵌入用轻量级模型(如nomic-embed-text) | 减少资源占用,提升速度 |
| 分块优化 | 根据文本长度动态调整分块大小 | 平衡检索精度和效率 |
2. 部署建议
对于生产环境部署,建议:
# 使用异步API提高并发性能
import asyncio
from ollama import AsyncClient
async def async_embed(text: str):
"""异步嵌入生成"""
async with AsyncClient() as client:
response = await client.embed(model="llama3.2", input=text)
return response["embeddings"][0]
# FastAPI部署示例
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
app = FastAPI(title="Ollama知识库问答API")
db = SimpleVectorDB() # 实际部署时应使用更高效的向量数据库
chat_manager = ChatManager(db)
class QueryRequest(BaseModel):
question: str
session_id: str = "default"
class QueryResponse(BaseModel):
answer: str
sources: List[str] = []
@app.post("/query", response_model=QueryResponse)
async def api_query(request: QueryRequest):
try:
answer = chat_manager.query(request.question)
return {"answer": answer}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
# 启动命令: uvicorn main:app --host 0.0.0.0 --port 8000
3. 常见问题解决
| 问题 | 解决方案 |
|---|---|
| 回答不准确 | 增加top_k检索数量,优化分块策略 |
| 响应速度慢 | 使用缓存,优化模型选择 |
| 内存占用高 | 减少历史对话长度,使用更轻量模型 |
| 知识库更新 | 实现增量索引更新机制 |
总结与未来展望
本文详细介绍了如何使用ollama-python构建结合知识库检索的智能问答系统,涵盖从文本嵌入生成、向量存储构建到问答逻辑实现的完整流程。通过这种架构,我们能够克服传统LLM的知识局限,实现基于私有知识库的精准问答。
未来可以进一步探索:
- 多模态知识库(支持图片、表格等)
- 知识图谱增强的检索能力
- 模型微调与领域适应
- 用户反馈机制与系统迭代优化
通过不断优化和扩展,这个系统可以应用于企业内部文档问答、客户支持、智能教育等多个领域,为用户提供更精准、可靠的AI助手服务。
附录:完整代码示例
可在项目的examples目录中找到更多示例代码:
- embed.py: 文本嵌入生成示例
- chat-with-history.py: 对话历史管理示例
- multi-tool.py: 工具调用功能示例
- structured-outputs.py: 结构化输出示例
# 完整的智能问答系统示例代码(整合版)
from ollama import Client
import numpy as np
from typing import List, Dict, Tuple, Callable
# 初始化客户端
client = Client()
# 向量数据库实现
class SimpleVectorDB:
def __init__(self):
self.vectors = []
self.texts = []
self.metadata = []
def add(self, text: str, vector: List[float], meta: Dict = None):
self.texts.append(text)
self.vectors.append(vector)
self.metadata.append(meta or {})
def search(self, query_vector: List[float], top_k: int = 3) -> List[Tuple[str, float, Dict]]:
if not self.vectors:
return []
vectors_np = np.array(self.vectors)
query_np = np.array(query_vector)
similarities = np.dot(vectors_np, query_np) / (
np.linalg.norm(vectors_np, axis=1) * np.linalg.norm(query_np)
)
top_indices = similarities.argsort()[-top_k:][::-1]
return [
(self.texts[i], similarities[i], self.metadata[i])
for i in top_indices
]
# 对话管理器
class ChatManager:
def __init__(self, db: SimpleVectorDB, model: str = "qwen3", max_history: int = 10):
self.db = db
self.model = model
self.max_history = max_history
self.history = []
def add_message(self, role: str, content: str):
self.history.append({"role": role, "content": content})
if len(self.history) > self.max_history * 2:
self.history = self.history[-self.max_history*2:]
def query(self, user_query: str) -> str:
# 生成查询向量并检索
query_vec = client.embed(model="llama3.2", input=user_query)["embeddings"][0]
results = self.db.search(query_vec, top_k=3)
context_chunks = [text for text, _, _ in results]
# 构建提示词
system_prompt = """你是一个基于知识库的问答助手。使用提供的上下文信息回答用户问题。
如果上下文信息不足以回答,直接说"根据提供的知识库,我无法回答该问题",不要编造信息。"""
context = "\n\n".join([f"[{i+1}] {chunk}" for i, chunk in enumerate(context_chunks)])
messages = [{"role": "system", "content": system_prompt}]
messages.extend(self.history)
messages.append({
"role": "user",
"content": f"上下文信息:\n{context}\n\n用户问题: {user_query}"
})
# 获取回答
response = client.chat(model=self.model, messages=messages)
answer = response.message.content
# 更新对话历史
self.add_message("user", user_query)
self.add_message("assistant", answer)
return answer
# 使用示例
if __name__ == "__main__":
# 初始化知识库
db = SimpleVectorDB()
# 添加示例文档
sample_docs = [
"ollama-python是Ollama的Python客户端,支持同步和异步调用。",
"主要功能包括对话(chat)、生成(generate)、嵌入(embed)等。",
"使用client.chat()方法可以进行多轮对话,支持上下文管理。",
"嵌入功能通过client.embed()实现,可将文本转换为向量用于检索。",
"工具调用功能允许模型根据需要调用外部函数获取信息。"
]
for doc in sample_docs:
vec = client.embed(model="llama3.2", input=doc)["embeddings"][0]
db.add(doc, vec)
# 启动对话
chatbot = ChatManager(db)
print("知识库问答系统已启动,输入'退出'结束对话")
while True:
user_input = input("你: ")
if user_input.lower() in ["退出", "q", "quit"]:
print("再见!")
break
response = chatbot.query(user_input)
print(f"AI: {response}")
【免费下载链接】ollama-python 项目地址: https://gitcode.com/GitHub_Trending/ol/ollama-python
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



