本地 RAG 实战:用 Easysearch + Ollama SDK 半小时搭建检索增强问答系统
✅ 目标:只用两台服务器(或同一台)就跑通 “向量检索 + 本地大模型” 原型
✅ 特点:完全离线、依赖极少、部署脚本即文档
✅ 适合:快速 PoC、内网合规场景、想深挖 RAG 工作机理的开发者
0. 背景与动机
生成式 AI 聊天固然强大,但当问题依赖本地私有知识时,单靠 LLM 参数内的“世界记忆”往往答非所问。RAG(Retrieval-Augmented Generation) 的思路是:
- 把文档切片 → 向量化 → 入库
- 用户提问 → 同样向量化 → 检索
- 将召回片段拼进 prompt,让大模型“带着材料”再回答
多数教程直接用云端 Embedding+OpenAI GPT-4o,但一些团队因隐私、成本或离线环境无法这样做。
本文选用:
- EasySearch (= OpenSearch + Elastiknn) 做向量存取
- Ollama SDK 连接本地 LLM
- Python + requests + ollama 三个依赖即可
1. 系统架构
1 | 用户问题 ──▶ 嵌入模型 (Ollama) ──▶ EasySearch 向量检索 ──▶ Top-k 片段 |
- 嵌入模型:
nomic-embed-text
(768 维,多语言通用) - 检索引擎:EasySearch 2.x + Elastiknn
knn_dense_float_vector
- 对话模型:
deepseek-r1:7b
(轻量,好部署;可换llama3
/qwen
)
2. 环境与依赖
1 | import os, json, requests, warnings |
1 | # Python 依赖 |
3. 代码逐段拆解
3.1 全局配置
1 | # ────────────── 配置区 ────────────── |
这段代码只是给脚本提前设定一些“连接参数”与“模型选择”,方便后面统一引用。逐行解释如下:
1 | ES_URL = "https://<es_host>:9200" |
ES_URL:EasySearch / OpenSearch 集群的完整地址(含协议与端口)。
<es_host>
是占位符,实际部署时要替换成你的 IP 或域名。- 如果你的集群没开 TLS,可写成
http://10.0.0.8:9200
。
1 | ES_AUTH = ("elastic", "password") # 无认证设为 None |
ES_AUTH:连接集群的账号密码元组。
- 脚本里传给
requests
的auth=
参数,会自动加 Basic Auth 头。 - 若集群关闭了安全认证或走内网匿名访问,就把它设成
None
。
- 脚本里传给
1 | INDEX = "rag_demo" |
INDEX:向量索引(或文档索引)的名称。
- 脚本后面会对该索引做 create / bulk write / search 等操作。
- 换成别的名字时记得保持一致,例如
"knowledge_base"
。
1 | OLLAMA_HOST = "http://<ollama_host>:11434" |
OLLAMA_HOST:本地 Ollama 服务的 HTTP 起始地址。
<ollama_host>
也是占位符;若脚本与 Ollama 在同一台机器,可写http://localhost:11434
。- 端口
11434
是 Ollama 默认 REST 端口。
1 | EMBED_MODEL = "nomic-embed-text" |
EMBED_MODEL:用于生成文本向量(embeddings)的模型名。
- 在脚本里会调用
client.embeddings(model=EMBED_MODEL, …)
。 - 替换规则:先执行
ollama pull <模型名>
,确保本地已下载。
- 在脚本里会调用
1 | CHAT_MODEL = "deepseek-r1:7b" |
CHAT_MODEL:负责最终回答的聊天 / 生成式模型。
- 脚本会用
client.chat(model=CHAT_MODEL, …)
进行对话。 - 同理,若想用
llama3:8b-chat
、qwen:7b-chat
等,先ollama pull
再改这里。
- 脚本会用
3.2 嵌入与对话(Ollama SDK)
client 是连接 Ollama 模型服务的客户端,用来发请求。
session 是访问 Elasticsearch 用的请求会话,能提高网络效率。
用指定的嵌入模型(比如 nomic-embed-text)把文本转成向量,用于相似度搜索。
用指定的聊天模型(比如 deepseek-r1:7b)回答问题,返回回复文本。
1 | # ────────────── 初始化 ────────────── |
3.3 建索引(Elastiknn)
在构建基于向量的 RAG(Retrieval-Augmented Generation)系统时,我们首先需要在向量数据库中创建一个支持向量检索的索引。本文使用 EasySearch 作为底层存储,向其中注册一个支持近似向量搜索的索引结构。
create_index 函数的作用是通过 RESTful API 创建一个名为 rag_demo 的索引,并定义字段结构如下:
content:文本内容字段,类型为 text,可用于全文搜索或作为上下文返回。
vec:向量字段,类型为 knn_dense_float_vector,支持高维向量的快速相似度搜索。
配置中使用了 LSH(局部敏感哈希)模型与 cosine 相似度度量,同时设定了近似参数 L 与 k,分别控制候选样本数量和返回结果数。
通过设定 “index.knn”: True,该索引支持使用 k-NN 查询来高效地检索与查询向量最相似的文档。在实际使用中,嵌入模型如 nomic-embed-text 可将输入文本转换为高维向量,存入此索引中,与用户查询语义对齐,实现高效的语义检索能力。
1 | # ---------- ① 创建索引:Elastiknn 映射 ---------- |
3.4 写入文档
以下是对这段 bulk_upload
函数的简明解释,可用于博客正文或技术文档:
在 RAG 系统中,为了支持高效的语义检索,我们需要将原始文本与其对应的向量一起写入向量索引中。bulk_upload
函数正是完成这一任务的核心组件,它使用 Elasticsearch 的 _bulk
接口实现批量写入,显著提高写入效率。
每条记录包含两个部分:
index
元数据,指定目标索引(rag_demo
)及文档_id
。实际文档内容,包括:
content
:原始文本内容;vec
:对应的文本向量,必须使用{"values": [...]}
的对象结构。
向量通过
embed(t)
获得,调用本地部署的 Ollama 模型(如nomic-embed-text
)生成。所有数据最终编码为 JSON,通过
Content-Type: application/x-ndjson
提交到/_bulk
API 接口,实现一次性批量写入。
1 | # ---------- ② 批量写入:向量必须包 {"values": …} ---------- |
3.5 语义检索
这段 search
函数的作用是在 RAG 系统中执行基于向量的语义检索,以下是适合用于博客中的简明解释:
RAG 系统的核心是从向量索引中找到与用户问题最相近的语义片段。search
函数即完成了这个过程,它调用 EasySearch 的向量检索接口,返回最相似的文本内容。
文本向量化:通过
embed(question)
把用户输入的问题转换成向量qvec
。构造检索请求:
使用knn_nearest_neighbors
查询field
: 向量字段名(本例中是"vec"
);vec
: 查询向量,必须写成{ "values": [...] }
的对象结构;model
: 向量近似检索模型(如"lsh"
);similarity
: 相似度度量方式(如"cosine"
);k
: 返回的结果数;candidates
: 候选池大小,用于粗排优化检索效果。
发送请求并解析响应:
请求通过 Elasticsearch_search
接口提交,若返回不成功,则输出报错信息;成功后提取_source["content"]
字段,返回给上层用于回答生成。
✅ 示例用途:
用户提问:“张三是谁”,系统会将该问题向量化,然后在已有文本向量中进行相似度匹配,从而返回如“张三是法律专家……”的片段,作为构建回答的上下文。
这段逻辑是 RAG 模型“Retriever”阶段的核心,让大模型在“有知识”的基础上作答,提升准确性和实用性。
1 | def search(question: str, top_k: int = TOP_K): |
3.6 主循环
1 | # ────────────── CLI 主逻辑 ────────────── |
4. 运行效果
1 | Q: 张三擅长什么 |
结果如下:
完整代码:
1 | import os, json, requests, warnings |
小结
EasySearch × Ollama 让我们在本地就能体验到“RAG 的爽点”:检索带来实时、可信的上下文,大模型负责自然语言表达,二者合体即是一个可交付的“企业私有知识助手”。如果你也想在内网快速验证 PoC,这份脚本拷过去改两个地址即可开跑。祝玩得开心!
本地 RAG 实战:用 Easysearch + Ollama SDK 半小时搭建检索增强问答系统
https://xu-hardy.github.io/本地-rag-实战:用-easysearch-ollama-sdk-半小时搭建检索增强问答系统/