Ollama API Embed 生成文本向量教程
Ollama Embed 接口返回的向量,到底该怎么核对?
调用 Ollama 的 Embed 接口之后,返回的是一长串小数。很多人卡壳的点不是“有没有返回结果”,而是不知道该怎么核对这串数字:一段文本到底对应几个向量?向量有多少维?批量返回的结果和输入顺序对不对得上?
其实,Ollama 是把文本向量存在 embeddings 这个二维数组里的。先确认外层的数量,再检查每个内层数组的长度,后面做语义检索的时候才不会把数据搞乱。这个方法在 Windows、macOS 和 Linux 上的本地 Ollama API 都能用。
动手之前,得先保证 Ollama 服务是开着的,还要准备好一个嵌入模型。目前官方推荐的模型有 embeddinggemma、qwen3-embedding 和 all-minilm,咱们示例就用 embeddinggemma。如果你电脑上还没这个模型,先打开 PowerShell(Windows)或者终端(macOS/Linux),跑一下 ollama pull embeddinggemma 就行。
官方接口文档里写的生成接口是 POST /api/embed,其中 model 和 input 是必填项。文档右侧的示例同时给了单文本请求的写法,还有对应的二维数组响应格式。先把端点、模型名、输入字段这些基础的对齐了,再去搞向量数据库或者 RAG 相关的逻辑,这样才靠谱。

第 1 步:用单段文本验证 Embed 端点
先做个最小请求测试,这样能把服务、模型、JSON 格式这些基础问题,和后面的代码问题分开排查。
入口位置:
主要动作:
api/embed 接口发个请求,带上模型名和一段文本:
curl -s localhost:11434/api/embed -d '{
"model": "embeddinggemma",
"input": "检索系统需要把文本转换成向量。"
}'
返回的对象里应该能看到 model 和 embeddings 这两个字段。
成功标志:
embeddings 的外层数组只有 1 个元素,里面是一串连续的数值,不是自然语言回答;响应里可能还会带 total_duration、load_duration 和 prompt_eval_count 这些统计字段。
失败处理:
ollama list 命令检查下模型名对不对,不对的话重新拉取对应模型。返回 400 就检查下引号、逗号有没有写错,还有那两个必填字段是不是都传了。
别光凭“返回了一堆小数”就觉得成功了。项目里要往向量库写数据的话,至少得把模型名、向量长度、输入文本的标识记下来。要是索引阶段的模型名或者向量维度变了,到查询的时候就算能正常发请求,也没法和之前存的旧向量直接比对。
第 2 步:明确 input、truncate 与 dimensions 的作用
单文本的请求跑通之后,再来看可选参数怎么用。
入口位置:
主要动作:
input 字段既可以传单个字符串,也可以传字符串数组;truncate 默认值是 true,意思是如果输入内容超过了模型的上下文窗口,会自动截断。要是把它设成 false,输入超长的话就会直接返回错误。dimensions 是用来指定输出向量的维度的,keep_alive 则用来控制模型在内存里驻留的时长。
{
"model": "embeddinggemma",
"input": "需要写入知识库的一段文本。",
"truncate": false,
"dimensions": 128,
"keep_alive": "5m"
}
成功标志:
len(embeddings[0]) 算出来的长度和你项目预期的维度对得上。
失败处理:
官方文档的字段说明区,把 truncate 的默认值、dimensions 的整数类型、还有 keep_alive 的字符串类型放在一块讲。这里最要留心核对的就是默认截断的行为:如果你需要完整保留原文内容,就得自己主动做文本切块,还要设置明确的失败处理逻辑,不能依赖默认的自动截断。

第 3 步:在 Python 中读取向量数量与维度
终端里的请求测稳定了,再把同样的校验逻辑搬到代码里。
入口位置:
主要动作:
ollama.embed 方法,再分别读取外层数组的长度(也就是向量数量)和第一个向量的长度(也就是维度):
python -m pip install ollama
import ollama
response = ollama.embed(
model="embeddinggemma",
input="检索系统需要把文本转换成向量。",
)
vectors = response["embeddings"]
print("向量数量:", len(vectors))
print("每个向量维度:", len(vectors[0]))
成功标志:
失败处理:
ModuleNotFoundError,先确认你装库的 Python 环境和跑脚本的是同一个。要是报 KeyError,就先把整个响应对象打印出来,看看请求到底有没有成功,是不是返回了 error 字段。要是返回的向量是空的,绝对别往数据库里写,得把输入的标识留好,再记清楚失败原因。
官方的响应说明里,把 embeddings 定义成 number[][] 类型。外层数组的每个元素对应一条输入,内层数组才是真正的向量数据。prompt_eval_count 是处理的输入令牌数,耗时类的字段用的是纳秒单位;这些统计数据适合用来做性能记录,别和向量本身混在一起。

第 4 步:批量生成时保持输入与结果顺序一致
文档切好块之后,一条一条发请求太浪费资源了,用数组传批量输入效率更高。
入口位置:
input 字段。
主要动作:
curl -s localhost:11434/api/embed -d '{
"model": "embeddinggemma",
"input": [
"第一段:Ollama 在本地提供模型服务。",
"第二段:Embed 接口把文本转换成向量。",
"第三段:查询与索引要使用同一个模型。"
]
}'
成功标志:
embeddings 外层数组的长度是 3,和三条输入是按顺序一一对应的;三个内层向量的长度也都一样。
失败处理:
官方的批量示例就是直接把三个字符串传给 input 字段。文档里还特意提醒:绝大多数语义搜索场景用的都是余弦相似度,而且索引文本和查询文本必须用同一个嵌入模型才行。

第 5 步:用同一模型验证余弦相似度
向量能生成成功,不代表检索的逻辑就没问题,还得做一组能说清道理的对照测试。
入口位置:
主要动作:
from math import sqrt
def cosine(a, b):
dot = sum(x * y for x, y in zip(a, b))
norm_a = sqrt(sum(x * x for x in a))
norm_b = sqrt(sum(y * y for y in b))
if norm_a == 0 or norm_b == 0:
raise ValueError("向量范数不能为 0")
return dot / (norm_a * norm_b)
query, related, unrelated = vectors
print(cosine(query, related))
print(cosine(query, unrelated))
成功标志:
失败处理:
dimensions 的设置。
第 6 步:给超长输入和接口错误留出补救路径
要做稳定的向量生成任务,得把错误和空结果区分开。
入口位置:
主要动作:
error 字段分类记录问题。400 一般是缺字段、JSON 格式不对或者参数有问题;404 大多是模型不存在;429 说明你调用太频繁了;500 和 502 则是服务端或者上游连接的问题。
成功标志:
失败处理:
truncate:false 导致超长输入错误,得回到文本切块的流程去处理,不能无条件改回默认截断,把数据缺失的问题掩盖过去。
结果核对清单
- 本地 Ollama 服务能正常访问,要用的嵌入模型在
ollama list里能查到。 - 单文本请求能返回 1 个非空向量,模型名和向量维度都已经记录好。
- 批量请求返回的向量数量和输入条数一致,顺序和文本 ID 是一一对应的。
- 索引和查询用的是同一个嵌入模型,
dimensions的设置也完全一致。 - 相关文本和查询的余弦相似度,比明显无关文本的得分高,测试结果符合任务预期。
- 超长输入会进入切块或者错误处理流程,400、404、429、500、502 这些错误都有明确的补救方法。