在 linux 环境搭建 AI 知识库服务
背景
目前,市面上已经有很多教程,如何在本地搭建一个 ai 知识库。这些知识库,只能在本地使用,如果想在公司内部、或者家庭内部搭建一个 ai 知识库服务器,还需要额外的工作。
本文基于 linux 环境(ubuntu),搭建一个 AI 知识库服务器,提供可以访问的 RESFul 接口。同时在前端实现一个简单的交互界面。
导言
要完成整个项目,我们需要完成以下几个步骤
下载 ollama
下载 AI 模型
创建自定义知识库
实现 SSE 接口
提供一个交互界面
下载 ollama
linux 下载 ollama 运行如下代码
curl -fsSL https://ollama.com/install.sh | sh
下载完成之后,执行
ollama -v
查看 ollama 版本,执行成功则下载完成。
下载 AI 模型
AI 模型我们推荐 qwen3
,qwen3
是一个可推理、可对话的模型,拥有多个跨度的模型体积,适配各种配置的设备。非常适合个人电脑使用。
最近比较火的 Deepseek 模型,有 Deepseek-R1 模型,是个推理模型。 Deepseek-V3 模型是个对话模型,但是最小的是 671b,不适合个人电脑运行。
下载模型前需要先运行起来 ollama
# 启动服务(安装后通常会自动启动)
sudo systemctl start ollama
# 设置开机自启
sudo systemctl enable ollama
之后,使用 ollama pull
命令下载模型
ollama pull qwen3:8b
下载效果如图
搭建知识库
在 Linux 上搭建 Ollama 的 RAG(Retrieval Augmented Generation,检索增强生成)系统,你可以按照以下步
安装必要的 Python 库
要搭建 RAG 系统,你需要安装一些 Python 库,像 langchain
、chromadb
、sentence-transformers
等。可以通过 pip
来安装:
pip install langchain chromadb sentence-transformers
安装过程可能会超时,最好加上镜像地址
pip install -i https://mirrors.aliyun.com/pypi/simple/ langchain chromadb sentence-transformers
构建 RAG 系统的 Python 代码
以下是一个简单的 Python 示例代码,展示了如何使用 Ollama 和 langchain
构建一个基本的 RAG 系统:
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_community.vectorstores import Chroma
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain_ollama import OllamaLLM
from langchain_core.prompts import PromptTemplate
from langchain.chains.combine_documents import create_stuff_documents_chain
from langchain.chains import create_retrieval_chain
import os
# 加载文档
loader = TextLoader('example.txt')
documents = loader.load()
# 分割文档
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
docs = text_splitter.split_documents(documents)
# 创建嵌入模型
embeddings = HuggingFaceEmbeddings(model_name="sentence-transformers/all-mpnet-base-v2")
# 创建向量数据库
db = Chroma.from_documents(docs, embeddings)
# 创建 Ollama LLM
llm = OllamaLLM(model="qwen3:0.6b")
# 定义提示模板 - 修改为只使用context变量
prompt_template = """使用以下上下文回答问题。如果不知道答案,就说不知道。
{context}
""" # 注意这里改为{input}而不是{question}
prompt = PromptTemplate(template=prompt_template, input_variables=["context", "input"])
# 创建文档链
document_chain = create_stuff_documents_chain(
llm=llm,
prompt=prompt
)
# 创建检索链
retriever = db.as_retriever()
retrieval_chain = create_retrieval_chain(retriever, document_chain)
# 提出问题
query = "你是谁?"
answer = retrieval_chain.invoke({"input": query})
print(answer["answer"])
代码运行过程中会加载 sentence-transformers/all-mpnet-base-v2
,国内访问不了,需要添加镜像
export HF_ENDPOINT=https://hf-mirror.com
这个过程有许多的 Python 知识,不熟悉的慎入,遇到问题多问 AI。同时感谢 AI 工具,不然这个代码是指定跑不起来。。。
创建 SSE 服务
SSE 基于 HTTP 协议,提供服务端推动数据到客户端等能力。目前主要浏览器都以支持,IE不支持。
SSE服务需要注意一下内容:
- 设置响应头
// 设置 SSE 响应头
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
- 数据返回格式
SSE 数据格式 data: ***\n\n
以 data:
开头,以 \n\n
结尾
res.write(`data: ${data}\n\n`);
这里给出调用 ollama API 的服务器完整的代码
const split2 = require('split2');
const aiHost = 'http://localhost:11434'
const getAnswer = async (req, res) => {
const { prompt } = req.query;
// 设置 SSE 响应头
res.setHeader('Content-Type', 'text/event-stream');
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Connection', 'keep-alive');
const data = {
model: 'qwen3:0.6b',
messages: [{ role: 'user', content: `${prompt}/no_think` }],
};
axios
.post(`${aiHost}/api/chat`, data, {
responseType: 'stream', // 设置响应类型为流
headers: {
'Content-Type': 'application/json',
},
})
.then((response) => {
const stream = response.data;
// 使用 split2 按 \n\n 分割流
const lineStream = stream.pipe(split2('\n'));
lineStream.on('data', (line) => {
if (line.trim()) {
// 忽略空行
res.write(`data: ${line}\n\n`); // 符合 SSE 格式
}
});
lineStream.on('end', () => {
console.log('Stream ended');
res.end();
});
lineStream.on('error', (error) => {
console.error('Stream error:', error);
res.end();
});
})
.catch((error) => {
console.error('Error:', error.response?.data || error.message);
res.end();
});
};
split2 用来拆分数据流
/no_think 告诉模型,不需要深度思考,直接出对话模式
客户端
可以端需要使用 EventSource 来发起 SSE 请求,并且通过监听的形式,获取数据
// 创建请求
const source = new EventSource(`/api/ai/v2?prompt=${question}`);
// 监听服务端推送的数据
source.addEventListener('message',(event) => {
console.log(event.data)
})
在服务端执行 res.end()
之后,如果不主动关闭客户端的 source ,则客户端会继续重试发起。没有必要。因此,在请求关闭之后,我们主动结束掉整个请求。
请求断开或者出错会触发 error
事件,结束请求调用 close
方法
source.addEventListener('error', () => {
source.close(); // 客户端手动关闭
});
结语
时间关系,整个工程还是一个简单的 demo 阶段,但是可以验证流程。后续会继续深入学习,填好其中的坑。
参考文档:
https://www.ruanyifeng.com/blog/2017/05/server-sent_events.html
https://juejin.cn/post/7355666189475954725
原文地址:https://webfem.com/post/ai-doc,转载请注明出处