LocalAI Embeddings 实战指南:从模型接入到对话级 Go 侧 Pooling
【免费下载链接】LocalAILocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required.项目地址: https://gitcode.com/GitHub_Trending/lo/LocalAI
LocalAI 的 Embeddings 能力让任意本地文本模型(llama.cppGGUF、bert.cpp、HuggingFacesentence-transformers)通过一条 OpenAI 兼容的/v1/embeddings接口统一输出文本/Token 向量,并额外扩展出"整段聊天对话嵌入"与"请求级 Go 侧 pooling"能力,可直接支撑 RAG 检索、向量存储与语义路由等场景。本文以仓库内文档 docs/content/features/embeddings.md 为核心脉络,结合 core/backend/embeddings.go、core/backend/pooling.go 与 core/http/endpoints/openai/embeddings.go 等源码实现,帮助你完整掌握模型接入、请求构造、Pooling 选型与常见故障排查。
功能概览:本地推理引擎的通用向量出口
LocalAI 支持为一段文本或一组 token生成 embeddings,接口语义对齐 OpenAI 的 Embeddings API 功能——它产出 512 维、L2 归一化、专为面部相似度比对的向量,与本文通用的文本 embedding 属于两条不同的技术栈。
模型兼容性
从源码结构看,embedding 请求最终由 ModelEmbedding 分发到已加载模型的 gRPC 后端,因此后端只需实现EmbeddingsRPC 即可接入。当前embeddings路径兼容的后端包括:
llama.cpp模型(GGUF,llama-cpp后端)bert.cpp模型- HuggingFace 上的 sentence-transformers 模型(
sentencetransformers后端)
方式一:使用 Gallery 内置模型(推荐)
LocalAI 的模型画廊(Model Gallery,见 Model Gallery)预置了配置好的 embedding 模型。在 gallery/index.yaml 中可以看到典型的qwen3-embedding-*条目,例如qwen3-embedding-4b的关键定义:
- name: qwen3-embedding-4b urls: - https://huggingface.co/Qwen/Qwen3-Embedding-4B-GGUF overrides: embeddings: true parameters: model: Qwen3-Embedding-4B-Q4_K_M.gguf files: - filename: Qwen3-Embedding-4B-Q4_K_M.gguf使用 Gallery 模型的步骤只有两步:
- 确认模型已在画廊中可用(通过
local-ai models list或 Model Gallery 检查) - 在 API 调用中直接使用模型名
画廊内置的示例 embedding 模型有:
qwen3-embedding-4b— Qwen3 Embedding 4Bqwen3-embedding-8b— Qwen3 Embedding 8Bqwen3-embedding-0.6b— Qwen3 Embedding 0.6B
示例:从 Gallery 使用 Qwen3-Embedding-4B
curl http://localhost:8080/embeddings -X POST -H "Content-Type: application/json" -d '{ "input": "My text to embed", "model": "qwen3-embedding-4b", "dimensions": 2560 }'其中dimensions用于指定输出维度(Qwen3-Embedding-4B 支持 32~2560 范围),不传则使用模型默认维度。画廊条目通过overrides.embeddings: true预先声明该模型可用于 embedding,模型文件则按 gallery/index.yaml 中记录的sha256与uri从 HuggingFace 拉取,无需手工书写任何 YAML。
方式二:手动配置模型 YAML
如果你已有本地模型文件,在models目录新建一个 YAML 配置文件即可。核心是三个字段:API 使用的模型名name、模型文件parameters.model、后端标识backend,并显式设置embeddings: true:
name: text-embedding-ada-002 # The model name used in the API parameters: model: <model_file> backend: "<backend>" embeddings: trueembeddings: true缺失是文档中列出的最常见配置错误(详见下文"故障排查")。backend的取值决定走哪条 embedding 链路,下面分后端展开。
HuggingFace / sentence-transformers 嵌入
要使用sentence-transformers及 HuggingFace 上的向量模型,指定sentencetransformers后端:
name: text-embedding-ada-002 backend: sentencetransformers embeddings: true parameters: model: all-MiniLM-L6-v2parameters.model直接填 HuggingFace 上的模型标识(如all-MiniLM-L6-v2),模型会在首次调用 API 时自动下载,无需预下载。该后端基于 Python 的 sentence-transformers 生态,仓库侧自动识别逻辑见 core/gallery/importers/sentencetransformers.go:只要 HuggingFace 仓库包含modules.json(ST 流水线清单)或sentence_bert_config.json(旧版标记),或作者为sentence-transformers,就会被路由到sentencetransformers后端并自动生成embeddings: true的配置。注意使用该后端有几点前提:
sentencetransformers是 LocalAI 的可选 Python 后端。若运行官方容器,通常已内置就绪;本地执行则须在EXTERNAL_GRPC_BACKENDS环境变量中显式声明它,例如:EXTERNAL_GRPC_BACKENDS="sentencetransformers:/path/to/LocalAI/backend/python/sentencetransformers/sentencetransformers.py"- 该后端只支持嵌入文本,不支持嵌入 token。需要嵌入 token 时请改用
bert后端或llama.cpp后端。
llama.cpp 嵌入
llama-cpp后端同样支持 embeddings,但必须开启embeddings: true:
name: my-awesome-model backend: llama-cpp embeddings: true parameters: model: ggml-file.bin然后调用/embeddings(或 OpenAI 兼容的/v1/embeddings)即可:
curl http://localhost:8080/embeddings -X POST -H "Content-Type: application/json" -d '{ "input": "My text", "model": "my-awesome-model" }' | jq "."底层链路为:HTTP 端点构造modelConfig.InputStrings→ backend.ModelEmbedding 经loader.Load取出模型 → 调用 gRPC 后端的EmbeddingsRPC → 由 finishEmbeddingResult 根据返回结果的布局(layout)做终处理。处理结果随后由 EmbeddingsEndpoint 组装成标准 OpenAI 响应;同时支持encoding_format=base64,将 float32 向量按小端序打包为 base64 字符串返回(Node.js SDK v4+ 默认即此格式)。
嵌入聊天对话与 Go 侧 Pooling
/v1/embeddings是 LocalAI 的OpenAI 兼容扩展端点:除了input,它还接受一段完整的对话(messages),并支持请求级的pooling方案——由 LocalAI 自身(Go 层)把后端返回的逐 token 原始向量归约成一个向量:
curl http://localhost:8080/v1/embeddings -X POST -H "Content-Type: application/json" -d '{ "model": "my-awesome-model", "messages": [ {"role": "system", "content": "You are a support agent."}, {"role": "user", "content": "My invoice is wrong."} ], "pooling": "decayed_mean", "pooling_half_life_tokens": 256 }'该扩展的行为约束如下:
- 每个请求只能携带一段对话,响应仍是标准 OpenAI embeddings 形态,包含单个
data[0].embedding项; input与messages互斥,同时出现返回 400;未知的pooling取值同样返回 400(校验逻辑见 ValidatePooling);- 若模型配置同时带有
template.chat与template.chat_message,对话会像 chat 提示词一样被完整渲染,使 embedding 与 chat 模型实际看到的内容完全一致(渲染入口见 embeddings.go 的evaluator.RenderConversationForEmbedding);否则使用固定的角色前缀兜底:按换行拼接<role>: <content>,跳过空内容消息;消息中的图片、音频、视频等非文本内容一律忽略。
Pooling 方案对照表
pooling决定如何把逐 token 向量归约成单个 embedding:
| 值 | 含义 |
|---|---|
(空)/backend | 由后端自行 pooling——这是默认值,即历史上完全一致的行为 |
mean | 对所有 token 向量求平均 |
last | 取最后一个 token 的向量 |
decayed_mean | 按时间加权平均:第i个 token(共T个)权重为2^(-(T-1-i)/H),半衰期H=pooling_half_life_tokens(默认 256)——近期内容占主导,同时不会抹掉更早的上下文 |
Go 侧方案的三种实现对应 core/backend/pooling.go:poolMean用 float64 累加求平均;poolLast复制末位 token 向量;poolDecayedMean用math.Exp2计算指数衰减权重后加权平均,半衰期 <=0 时回退到默认值 256(见常量 DefaultPoolingHalfLifeTokens)。具体调用路径为 PoolEmbeddingResult,其先通过 reshapeEmbeddings 把 gRPC 按行主序打包的扁平 float 载荷还原为tokens × dim矩阵,再执行归约与归一化。
布局声明与兼容性规则
Go 侧 pooling 需要后端返回逐 token 原始向量,因此每个后端都要在EmbeddingResult中声明结果是"最终向量"还是"逐 token 矩阵":
- LocalAI 在遇到"请求 Go 侧方案但后端返回最终向量",或"请求
backend透传但后端返回逐 token 矩阵"时直接拒绝,绝不依据向量形状去猜测(形状不可靠:1 个 token 的原始向量与 1 个最终向量都是1 × dim),对应错误类型与提示见 finishEmbeddingResult; - 不声明布局的旧后端仅兼容
backendpooling; - llama.cpp 在模型加载时就决定了布局:当模型配置了 Go 侧
parameters.pooling方案时,LocalAI 会自动追加后端选项pooling:none(原始逐 token 加载),见 core/config/pooling_config_test.go 中对SetDefaults的断言。该实例可在mean、last、decayed_mean之间按请求切换,但不能切回backendpooling(需重新加载模型);反之,后端 pooling 的 llama.cpp 实例会拒绝请求级 Go pooling。模型加载期的双向配置一致性检查位于 model_config.go; - 若后端显式返回逐 token 向量,其他后端也可能支持 Go 侧 pooling。
归一化:与 llama.cpp 完全一致的embd_normalize
Go 侧 pooling 完成后,向量会按 llama.cpp 的embd_normalize规则归一化。由于pooling:none下 llama.cpp 只输出未归一化的原始向量(服务端只归一化它自己 pooling 的结果),LocalAI 在 Go 层实现了对 llama.cppcommon_embd_normalize的逐位移植,见 normalizeEmbedding:
embdNorm < 0:不归一化;embdNorm == 0:按最大绝对值缩放(并除以 32760.0 对齐 int16 范围);embdNorm == 2(默认,L2/欧氏归一化);- 其他值:p-范数(1 为曼哈顿)。
归一化系数通过模型配置中的options: ["embd_normalize:<n>"]控制(别名embedding_normalize:<n>),解析逻辑 embdNormalizeFromOptions 默认返回 2,不可解析的值会被静默忽略——与 llama.cpp 后端吞掉std::stoi失败的行为保持一致。
模型级默认配置
池化方案同样可以在模型 YAML 的parameters:中固化(请求级参数会覆盖之,两者共用同一套 ValidatePooling 校验,且pooling_half_life_tokens只在pooling: decayed_mean时被允许):
name: conversation-embedder backend: llama-cpp embeddings: true parameters: model: ggml-file.bin pooling: decayed_mean pooling_half_life_tokens: 256需要提醒的是:Go 侧 pooling 依赖能上报 embedding 布局的新版后端;旧后端对 Go 侧方案会失败关闭(fail closed),直接返回要求重建或升级后端的错误,而不是静默给出错误向量。
应用示例:LLamaIndex 检索
- 将 LLamaIndex 与 LocalAI 组合用作 embedding 的完整示例,见仓库外维护的
mudler/LocalAI-examples项目中query_data目录(使用该脚本/数据端配合本接口即可搭建本地 RAG 检索链路)。
常见问题与故障排查
问题一:Embedding 模型返回结果不正确
症状:模型返回空向量或错误向量;调用 embedding 端点时报错。
常见原因与处置:
- 模型文件名错误:确保使用了画廊或本地模型文件位置的正确文件名。画廊模型有固定的文件名(例如
Qwen3-Embedding-4B-Q4_K_M.gguf),可对照 Model Gallery 或 gallery/index.yaml 核实。 - 上下文尺寸不匹配:确保
context_size不超过模型最大上下文:- Qwen3-Embedding-4B:最大 32k(32768)
- Qwen3-Embedding-8B:最大 32k(32768)
- Qwen3-Embedding-0.6B:最大 32k(32768)
- 缺少
embeddings: true:模型配置必须显式开启该标志。
正确配置示例:
name: qwen3-embedding-4b backend: llama-cpp embeddings: true context_size: 32768 parameters: model: Qwen3-Embedding-4B-Q4_K_M.gguf问题二:维度不匹配
症状:返回的 embedding 维度与预期不一致。
解决方案:在 API 请求中使用dimensions参数指定输出维度。Qwen3-Embedding 系列支持 32 到最大维度之间的任意取值(4B 最大 2560,8B 最大 4096)。
curl http://localhost:8080/embeddings -X POST -H "Content-Type: application/json" -d '{ "input": "My text", "model": "qwen3-embedding-4b", "dimensions": 1024 }'问题三:模型未找到
症状:API 返回 404 或 "model not found"。
解决方案:
- 确认模型已在 models 目录正确配置;
- 请求中的模型名必须与配置中的
name字段完全一致(端点会校验请求model是否为空并据其加载配置,见 EmbeddingsEndpoint); - 对画廊模型,确认画廊已正确加载。
Qwen3 Embedding 系列模型规格
Qwen3 Embedding 系列在 gallery/index.yaml 中有完整收录,其关键特性如下:
| 模型 | 参数量 | 最大上下文 | 最大维度 | 支持语言 |
|---|---|---|---|---|
| qwen3-embedding-0.6b | 0.6B | 32k | 1024 | 100+ |
| qwen3-embedding-4b | 4B | 32k | 2560 | 100+ |
| qwen3-embedding-8b | 8B | 32k | 4096 | 100+ |
全部模型共同支持:
- 用户自定义输出维度(32 到各自最大维度);
- 多语言文本嵌入(100+ 种语言,含各编程语言的跨语言/代码检索能力);
- 基于指令调优的 embedding——可通过自定义指令针对特定任务、语言或场景增强效果。
画廊为各规格默认配置的量化文件与校验信息可在 gallery/index.yaml 中核对(0.6B 提供Q8_0/f16,4B/8B 提供Q4_K_M至f16等多种量化)。
小结
在 LocalAI 中接入文本 embedding 是一条清晰而灵活的路径:画廊模型零配置起步、手动 YAML 支持按后端定制、sentencetransformers覆盖 HuggingFace Python 生态、llama-cpp主打 GGUF 高性能本地推理。而/v1/embeddings的messages+ 请求级pooling扩展更是把"对话语义向量化"做成了开箱即用的能力——配合模型级默认值与 llama.cpp 对齐的embd_normalize归一化,无论做 RAG 检索、向量库写入还是语义路由,都能拿到行为可预期、与 OpenAI 兼容的稳定向量结果。
【免费下载链接】LocalAILocalAI is the open-source AI engine. Run any model - LLMs, vision, voice, image, video - on any hardware. No GPU required.项目地址: https://gitcode.com/GitHub_Trending/lo/LocalAI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考