本文是「从零搭建私人 RAG 知识库」专栏的基础篇。我们先理解 Ollama 能解决什么问题,Ollama 下载模型以及基本的使用案例。
开发 RAG 应用时,我们通常会接触两类模型:
- 生成模型:接收问题和上下文,生成自然语言回答;
- Embedding 模型:把文档和问题转换成向量,用于语义检索。
Ollama 可以在本地运行这两类模型,并通过命令行和 HTTP API 提供服务。它非常适合用来理解模型调用过程,也可以在数据不方便离开本机时作为本地部署方案。
本文将完成以下实践:
- 安装并启动 Ollama;
- 下载、运行和管理本地模型;
- 使用
qwen3:0.6b体验本地对话; - 调用 Ollama 的
/api/chat接口; - 使用
nomic-embed-text生成文本向量; - 调用 Ollama 的
/api/embed接口; - 理解
OllamaEmbeddings在 CorpRAG 中的作用; - 区分生成模型、Embedding 模型和向量数据库。
本文使用的两个模型职责不同:
text
qwen3:0.6b → 生成自然语言回答
nomic-embed-text → 把文本转换成向量
其中,qwen3:0.6b 用于学习本地对话能力;CorpRAG 当前实际使用的是 Ollama 提供的 Embedding 能力。
一、Ollama 是什么?
Ollama 是一个本地模型运行和管理工具。它把模型下载、模型加载、推理服务和 API 调用封装在一起,让开发者不必直接处理模型文件和底层推理框架。
Ollama 主要负责:
- 下载和管理模型;
- 在本地加载并运行模型;
- 提供命令行对话能力;
- 提供本地 HTTP API;
- 运行生成模型和 Embedding 模型。
Ollama 不是某一个具体模型,也不是向量数据库:
| 组件 | 类型 | 主要职责 |
|---|---|---|
| Ollama | 本地模型运行平台 | 下载、管理和运行模型 |
qwen3:0.6b |
生成模型 | 根据输入生成自然语言 |
nomic-embed-text |
Embedding 模型 | 把文本转换成向量 |
OllamaEmbeddings |
LangChain 适配器 | 让应用调用 Ollama 的 Embedding 能力 |
| LanceDB | 向量数据库 | 保存向量并执行相似度检索 |
可以简单记成:
text
Ollama = 负责运行模型
模型 = 负责执行具体任务
OllamaEmbeddings = 应用与 Ollama 之间的适配器
LanceDB = 负责保存和搜索向量
二、安装与启动 Ollama
1. 安装 Ollama
可以从 Ollama 官方网站下载安装包:
text
https://ollama.com/download
Ollama 支持 macOS、Windows 和 Linux。不同系统的安装方式可能变化,建议以官网当前说明为准。
安装完成后,在终端执行:
bash
ollama -v
如果能够看到版本号,说明命令行工具已经安装成功。
2. 启动 Ollama 服务
在 macOS 或 Windows 桌面环境中,启动 Ollama 应用后,后台服务通常会自动运行。
也可以在终端手动启动:
bash
ollama serve
Ollama 默认监听:
text
http://localhost:11434
可以通过模型列表接口检查服务是否可用:
bash
curl http://localhost:11434/api/tags
如果返回 JSON 数据,说明本地 API 已经可以访问。
如果桌面应用已经启动了 Ollama,再执行
ollama serve可能提示端口已被占用。这通常表示服务已经在运行,不需要重复启动。
3. 本地运行的特点
本地模型的主要优点包括:
- 数据可以保留在本机或内网;
- 不需要为每次调用配置外部 API Key;
- 可以离线使用已经下载的模型;
- 便于学习模型 API 和调试 RAG 流程;
- 可以自主控制模型和运行环境。
同时也要考虑:
- 模型会占用磁盘、内存或显存;
- 普通电脑运行较大模型时速度可能较慢;
- 模型效果取决于模型本身和本机硬件;
- 服务升级、权限控制和监控需要自行维护。
因此,本地模型不是在所有场景下都优于远程模型,但非常适合学习和处理对数据本地化有要求的任务。
三、模型下载与管理
1. 下载生成模型
本文默认使用轻量级的 qwen3:0.6b 演示本地对话,降低初学者的硬件门槛:
bash
ollama pull qwen3:0.6b
模型标签中的 0.6b 通常表示模型规模约为 6 亿参数。与更大的模型相比,它下载更快、占用的内存或显存更少,更适合在普通电脑上练习 Ollama 命令和 API 调用。
轻量模型的回答准确性、复杂指令理解和长文本处理能力可能弱于更大的模型。如果本机性能允许,可以改用 qwen3:1.7b 或 qwen3:4b;只需将本文命令和请求中的模型名称替换为实际下载的名称,调用方式保持不变。
2. 下载 Embedding 模型
CorpRAG 默认使用:
bash
ollama pull nomic-embed-text
它负责生成文本向量,不用于聊天和回答问题。
3. 查看本地模型
bash
ollama ls
部分 Ollama 版本也支持:
bash
ollama list
输出中通常可以看到模型名称、模型 ID、大小和更新时间。
4. 查看正在运行的模型
bash
ollama ps
模型在完成请求后可能继续保留在内存中,以便下一次调用更快。
5. 停止模型
bash
ollama stop qwen3:0.6b
6. 删除模型
bash
ollama rm qwen3:0.6b
删除模型会释放磁盘空间。如果后续还要使用,需要重新下载。
7. 常用命令汇总
bash
ollama -v # 查看版本
ollama serve # 启动服务
ollama pull qwen3:0.6b # 下载生成模型
ollama pull nomic-embed-text # 下载 Embedding 模型
ollama ls # 查看本地模型
ollama run qwen3:0.6b # 启动命令行对话
ollama ps # 查看已加载模型
ollama stop qwen3:0.6b # 停止模型
ollama rm qwen3:0.6b # 删除模型
四、使用本地生成模型
1. 命令行对话
下载模型后,可以直接运行:
bash
ollama run qwen3:0.6b
进入交互界面后输入:
text
请用一句话解释什么是 RAG。
模型会在本机生成回答。输入 /bye 可以退出当前会话。
这个步骤可以快速验证:
- 模型已经成功下载;
- Ollama 服务可以加载模型;
- 本机具备基本推理能力。
2. 调用本地 Chat API
Ollama 原生对话接口是:
text
POST /api/chat
使用 curl 发起非流式请求:
bash
curl http://localhost:11434/api/chat \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3:0.6b",
"messages": [
{
"role": "system",
"content": "你是一名 RAG 学习助手,回答要简洁、准确。"
},
{
"role": "user",
"content": "请解释向量数据库在 RAG 中的作用。"
}
],
"stream": false
}'
精简后的响应结构可以理解为:
json
{
"model": "qwen3:0.6b",
"message": {
"role": "assistant",
"content": "向量数据库用于保存文本向量,并检索与问题语义最相近的文档片段。"
},
"done": true
}
自然语言回答位于:
text
message.content
3. 流式输出
如果省略 stream,或将它设置为 true,Ollama 会逐段返回结果:
bash
curl http://localhost:11434/api/chat \
-H "Content-Type: application/json" \
-d '{
"model": "qwen3:0.6b",
"messages": [
{
"role": "user",
"content": "什么是 Embedding?"
}
],
"stream": true
}'
流式响应适合聊天界面,因为用户不必等待完整答案生成后才能看到内容。非流式响应更容易调试和解析,本文后续示例主要使用 stream: false。
4. 系统提示词
系统提示词用于约束模型角色和回答方式:
json
{
"role": "system",
"content": "你是一名 RAG 学习助手。资料不足时明确说明无法确认,不要编造答案。"
}
系统提示词可以要求模型:
- 使用指定语言回答;
- 控制回答长度和格式;
- 优先依据提供的资料;
- 资料不足时明确说明;
- 返回 Markdown、JSON 等指定格式。
提示词可以降低模型偏离任务的概率,但不能保证完全消除幻觉。
5. 多轮对话
HTTP API 不会自动替应用永久保存完整聊天历史。后续请求需要继续发送必要的历史消息:
json
{
"model": "qwen3:0.6b",
"messages": [
{
"role": "user",
"content": "什么是 RAG?"
},
{
"role": "assistant",
"content": "RAG 是检索增强生成。"
},
{
"role": "user",
"content": "它为什么能降低幻觉?"
}
],
"stream": false
}
对话变长后,需要考虑上下文窗口、历史截断、摘要和内存占用。
五、使用 Node.js 调用本地 Chat API
Node.js 20 内置了 fetch,不安装额外 SDK 也可以调用 Ollama:
ts
interface ChatResponse {
message: {
role: "assistant";
content: string;
};
done: boolean;
}
const baseUrl = process.env.OLLAMA_BASE_URL ?? "http://localhost:11434";
const chatModel = process.env.OLLAMA_CHAT_MODEL ?? "qwen3:0.6b";
const response = await fetch(`${baseUrl}/api/chat`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
model: chatModel,
messages: [
{
role: "system",
content: "你是一名 RAG 学习助手。",
},
{
role: "user",
content: "请用一句话解释文本分块。",
},
],
stream: false,
}),
});
if (!response.ok) {
const detail = await response.text();
throw new Error(`Ollama request failed: ${response.status} ${detail}`);
}
const result = (await response.json()) as ChatResponse;
console.log(result.message.content);
这里不需要 API Key,因为示例访问的是本机 Ollama 服务。
这段代码用于学习 Ollama 的本地生成能力。CorpRAG 当前没有在服务端使用
qwen3:0.6b生成最终回答,而是主要通过 MCP 向 AI 客户端提供检索结果。
六、Embedding 是什么?
Embedding 是把文本转换成数值向量的过程。例如:
text
"如何部署 EXT 系统?"
↓ Embedding 模型
[0.12, -0.37, 0.88, ..., 0.24]
向量表达文本的语义特征。通常情况下:
- 含义相近的文本,向量距离较近;
- 含义差异较大的文本,向量距离较远。
Embedding 常用于:
- RAG 文档检索;
- 语义搜索;
- 文本相似度计算;
- 文本聚类;
- 推荐系统。
Embedding 模型只负责生成向量:
text
输入:一段或多段文本
输出:一组或多组数值向量
它不负责:
- 生成自然语言回答;
- 保存向量;
- 搜索向量;
- 管理文档。
在 CorpRAG 中,向量由 nomic-embed-text 生成,由 LanceDB 保存和检索。
七、调用本地 Embedding API
1. 生成单条文本向量
Ollama 原生 Embedding 接口是:
text
POST /api/embed
调用示例:
bash
curl http://localhost:11434/api/embed \
-H "Content-Type: application/json" \
-d '{
"model": "nomic-embed-text",
"input": "如何部署 EXT 系统?"
}'
精简后的响应可以理解为:
json
{
"model": "nomic-embed-text",
"embeddings": [
[0.12, -0.37, 0.88, 0.24]
]
}
真实向量通常包含更多维度。这里缩短数组只是为了便于阅读。
2. 批量生成向量
input 也可以传入字符串数组:
bash
curl http://localhost:11434/api/embed \
-H "Content-Type: application/json" \
-d '{
"model": "nomic-embed-text",
"input": [
"EXT 系统部署步骤",
"EXT 系统数据库配置",
"员工请假审批流程"
]
}'
每条输入文本会对应一个向量:
text
3 条文本 → 3 个向量
批量接口适合在索引阶段处理多个文档片段。
3. 向量不能直接当作答案
返回的 embeddings 是给程序使用的数值数组。应用会用它们计算向量距离,而不是直接展示给用户。
RAG 中的处理过程是:
text
文档片段 → Embedding 模型 → 文档向量 → 保存到 LanceDB
用户问题 → Embedding 模型 → 查询向量 → 在 LanceDB 中搜索
八、使用 OllamaEmbeddings
OllamaEmbeddings 是 @langchain/ollama 提供的 LangChain 客户端封装。
它会:
- 接收文本;
- 连接 Ollama 服务;
- 调用指定的 Embedding 模型;
- 取得模型生成的向量;
- 按 LangChain 的统一接口返回结果。
它不是 Ollama 服务,也不是模型或向量数据库:
text
TypeScript 应用
↓
OllamaEmbeddings
↓ HTTP 请求
Ollama 服务
↓
nomic-embed-text
↓
数值向量
1. 安装依赖
CorpRAG 已经安装:
bash
npm install @langchain/ollama
2. 创建客户端
ts
import { OllamaEmbeddings } from "@langchain/ollama";
const embeddings = new OllamaEmbeddings({
model: "nomic-embed-text",
baseUrl: "http://localhost:11434",
});
创建实例主要是保存客户端配置。真正执行向量化时,才会向 Ollama 发起请求。
3. embedQuery()
把一条查询文本转换成一个向量:
ts
const vector = await embeddings.embedQuery("如何部署 EXT 系统?");
console.log(vector.length);
返回类型可以理解为:
ts
number[]
它通常用于查询阶段。
4. embedDocuments()
批量把文档片段转换成多个向量:
ts
const vectors = await embeddings.embedDocuments([
"EXT 系统部署步骤......",
"EXT 系统数据库配置......",
]);
console.log(vectors.length);
返回类型可以理解为:
ts
number[][]
它通常用于索引阶段。
二者的区别是:
text
embedQuery(text) → 一个文本、一个向量
embedDocuments(texts) → 多个文本、多个向量
九、生成模型与 Embedding 模型的区别
这是本章最重要的概念之一。
| 类型 | 示例 | 输入 | 输出 | 主要用途 |
|---|---|---|---|---|
| 生成模型 | qwen3:0.6b |
提示词和上下文 | 自然语言 | 问答、总结、内容生成 |
| Embedding 模型 | nomic-embed-text |
文本 | 数值向量 | 检索、相似度计算 |
两种模型不能互相替代:
text
qwen3:0.6b
问题 → 自然语言回答
nomic-embed-text
问题 → 数值向量
为什么索引和查询必须使用同一个 Embedding 模型?
文档向量和查询向量只有处于同一个向量空间,距离比较才有意义。
正确方式:
text
文档 → nomic-embed-text → 文档向量
问题 → nomic-embed-text → 查询向量
错误或不可靠的方式:
text
文档 → Embedding 模型 A → 文档向量
问题 → Embedding 模型 B → 查询向量
不同模型生成的向量可能:
- 维度不同,导致查询直接失败;
- 语义空间不同,导致检索结果异常;
- 数值分布不同,无法正确比较距离。
即使两个模型的向量维度相同,也不代表它们处于同一个语义空间。
因此,更换 EMBEDDING_MODEL 后,通常需要重新生成所有文档向量并重建索引。
十、CorpRAG 如何使用 Ollama
1. 当前项目使用 Ollama 做什么?
CorpRAG 当前通过 Ollama 运行 Embedding 模型,用于文档索引和问题检索:
text
CorpRAG
↓ OllamaEmbeddings
Ollama
↓
nomic-embed-text
↓
文档向量 / 查询向量
↓
LanceDB
当前项目并没有在服务端使用 Ollama 生成最终答案。qwen3:0.6b 是本章用于学习本地生成模型的示例,不应和项目现有实现混为一谈。
2. 项目中的 Embedding 配置
src/infrastructure/embeddings.ts 中创建了 OllamaEmbeddings:
ts
import { OllamaEmbeddings } from "@langchain/ollama";
import { config } from "../config";
export function createEmbeddings(): OllamaEmbeddings {
return new OllamaEmbeddings({
model: config.embeddingModel,
baseUrl: config.ollamaBaseUrl,
});
}
对应配置位于 src/config.ts:
ts
ollamaBaseUrl: process.env.OLLAMA_BASE_URL ?? "http://localhost:11434",
embeddingModel: process.env.EMBEDDING_MODEL ?? "nomic-embed-text",
两个配置分别表示:
| 环境变量 | 作用 | 默认值 |
|---|---|---|
OLLAMA_BASE_URL |
Ollama 服务地址 | http://localhost:11434 |
EMBEDDING_MODEL |
Embedding 模型名称 | nomic-embed-text |
使用默认配置时,只需要确保:
bash
ollama serve
ollama pull nomic-embed-text
如果 Ollama 已由桌面应用启动,则不必再次执行 ollama serve。
3. 自定义配置
也可以通过环境变量连接其他 Ollama 地址或选择其他 Embedding 模型:
bash
export OLLAMA_BASE_URL="http://localhost:11434"
export EMBEDDING_MODEL="nomic-embed-text"
Ollama 不一定要和 Node.js 应用运行在同一台机器上,只要应用能够访问 OLLAMA_BASE_URL 即可。
如果使用局域网中的 Ollama 服务,需要配置网络访问控制。不要把没有认证和访问限制的 Ollama 服务直接暴露到公网。
4. 文档索引阶段
建立知识库时,处理流程是:
text
Markdown 文档
↓ 加载和分块
Document[]
↓ embedDocuments()
OllamaEmbeddings
↓
Ollama + nomic-embed-text
↓
文档向量
↓
LanceDB
各组件职责如下:
- 文档加载器:读取 Markdown;
- 文本分块器:把长文档拆成片段;
OllamaEmbeddings:向 Ollama 请求向量;nomic-embed-text:实际计算向量;- LanceDB:保存正文、元数据和向量。
5. 问题查询阶段
用户查询知识库时:
text
用户问题
↓ embedQuery()
查询向量
↓ LanceDB 相似度搜索
相关文档片段
索引阶段和查询阶段必须使用同一个 Embedding 模型。
6. 当前完整职责划分
text
Ollama → 在本地运行 nomic-embed-text
nomic-embed-text → 生成文档向量和查询向量
OllamaEmbeddings → 让 LangChain 调用 Ollama
LanceDB → 保存向量并检索相关文档
CorpRAG → 组织文档加载、索引和查询
AI 客户端 → 使用检索结果组织最终回答
十一、本地 RAG 的完整理解
如果生成模型和 Embedding 模型都放在 Ollama 中,本地 RAG 可以形成下面的链路:
text
索引阶段:
文档 → 分块 → nomic-embed-text → 文档向量 → LanceDB
问答阶段:
用户问题 → nomic-embed-text → 查询向量 → LanceDB
↓
相关文档片段
↓
用户问题 + 相关文档 → qwen3:0.6b → 最终回答
这里有两个容易混淆的地方:
- LanceDB 找到的是相关文档,不是最终答案;
qwen3:0.6b生成答案,但不负责向量检索。
本章分别练习了这两种模型能力,但 CorpRAG 当前只在服务端实现了上图中的检索部分,并通过 MCP 把检索结果提供给具备生成能力的 AI 客户端。
十二、常见问题排查
1. ollama: command not found
说明 Ollama 尚未安装,或命令行路径没有生效。
可以检查:
- 是否已经完成安装;
- 是否需要重新打开终端;
ollama -v是否能正常输出版本;- 当前系统的安装方式是否与官方说明一致。
2. 无法连接 localhost:11434
常见错误包括 ECONNREFUSED、连接失败或请求超时。
先检查服务:
bash
curl http://localhost:11434/api/tags
如果无法访问,可以启动 Ollama 应用或执行:
bash
ollama serve
还应确认 OLLAMA_BASE_URL 没有配置成错误地址。
3. 提示端口已经被占用
如果执行 ollama serve 时提示 11434 端口已被占用,先调用:
bash
curl http://localhost:11434/api/tags
如果接口正常返回,通常说明 Ollama 已经运行,不需要再次启动。
4. 提示模型不存在
先查看已下载模型:
bash
ollama ls
缺少模型时执行:
bash
ollama pull qwen3:0.6b
ollama pull nomic-embed-text
请求中的模型名称必须与本地模型名称一致。
5. 模型运行缓慢或内存不足
可以尝试:
- 使用参数规模更小的生成模型;
- 关闭不需要的模型或其他高内存应用;
- 使用
ollama ps检查已加载模型; - 减少一次请求中的上下文长度;
- 确认本机资源是否适合当前模型。
Embedding 模型通常比大型生成模型轻量,但批量处理大量文档仍然需要时间。
6. Embedding 接口返回的是数字,不是回答
这是正常现象。
text
/api/chat → 返回自然语言
/api/embed → 返回数值向量
需要自然语言回答时应调用生成模型;需要语义检索时才调用 Embedding 模型。
7. 修改 Embedding 模型后查询失败
如果旧索引由 nomic-embed-text 生成,而查询改用了另一个模型,可能出现向量维度错误或检索结果异常。
解决方式是:
- 确认索引和查询使用同一个模型;
- 使用新模型重新生成文档向量;
- 重建 LanceDB 中的对应索引。
仅修改环境变量而不重建索引是不够的。
8. CorpRAG 查询失败,但本地聊天正常
本地聊天正常只能说明 qwen3:0.6b 可以运行。CorpRAG 查询依赖的是 nomic-embed-text。
应单独检查:
bash
ollama pull nomic-embed-text
并调用 /api/embed 验证 Embedding 接口,而不是只测试 /api/chat。
十三、本地使用的安全建议
本地运行不代表可以忽略安全问题。
1. 不要直接暴露到公网
Ollama 默认适合本机访问。如果需要让其他机器连接,应通过防火墙、反向代理、身份认证或内网限制访问范围。
不要把未受保护的 11434 端口直接暴露到公网。
2. 注意模型和数据来源
下载模型和导入文档时,应确认:
- 模型来源是否可信;
- 模型许可证是否满足使用要求;
- 文档是否包含密钥、个人信息或商业机密;
- 日志中是否输出了不应泄露的内容。
3. 不要盲目信任模型输出
本地模型同样可能产生幻觉。涉及代码执行、数据修改、权限操作和业务决策时,应保留:
- 来源引用;
- 参数校验;
- 权限控制;
- 必要的人工确认。
十四、远程模型方案留到后续
除了本地 Ollama,RAG 也可以组合远程模型服务。例如:
text
本地 Embedding + 远程生成模型
远程 Embedding + 远程生成模型
本地 Embedding + 本地生成模型
CorpRAG 当前主要采用:
text
Ollama + nomic-embed-text
↓
CorpRAG 检索知识库
↓ MCP
AI 客户端中的生成模型组织答案
实际使用中,AI 客户端可以连接火山方舟的 ark-code-latest 等外部生成模型。外部模型的 API Key、OpenAI 兼容接口、MCP 工具调用和故障排查将在后续章节中展开,本章不再详细讨论。
无论生成模型位于本地还是远程,都不会自动替代 Embedding 模型和向量索引。
十五、学习检查清单
完成本文实践后,可以检查自己是否已经掌握:
- 能说明 Ollama 是模型运行平台,而不是某一个模型;
- 能安装并启动 Ollama;
- 能检查
http://localhost:11434是否可用; - 能下载、查看、运行、停止和删除模型;
- 能使用
qwen3:0.6b进行本地命令行对话; - 能调用 Ollama 的
/api/chat接口; - 理解流式响应和非流式响应的区别;
- 能调用
nomic-embed-text的/api/embed接口; - 能区分生成模型和 Embedding 模型;
- 能说明
embedQuery()和embedDocuments()的区别; - 能说明
OllamaEmbeddings的职责; - 理解 CorpRAG 当前使用 Ollama 生成向量,而不是生成最终回答;
- 理解索引和查询必须使用同一个 Embedding 模型;
- 知道更换 Embedding 模型后需要重建索引;
- 不会把未受保护的 Ollama 服务直接暴露到公网。
总结
本章从本地实践出发,学习了 Ollama 的两类模型能力:
text
qwen3:0.6b
→ 接收问题和上下文
→ 生成自然语言回答
nomic-embed-text
→ 接收文本
→ 生成数值向量
在 CorpRAG 中,各组件的职责是:
text
Ollama → 运行本地模型
nomic-embed-text → 生成文档向量和查询向量
OllamaEmbeddings → 连接 LangChain 与 Ollama
LanceDB → 保存和搜索向量
CorpRAG → 组织知识库索引和检索
AI 客户端 → 基于检索资料生成最终答案
最重要的是区分"生成"和"检索":聊天模型负责回答问题,Embedding 模型和向量数据库负责找到相关资料。
掌握 Ollama 的命令行、Chat API 和 Embedding API 后,我们就具备了在本机观察完整模型调用过程的能力。下一步可以继续学习 Vector Store,理解向量如何保存,以及用户提问时如何找回语义最相关的文档片段。