---
title: LLM 与 Embedding：配置相同提供方也要区分任务
description: 从生成文本与生成向量的接口差异出发，核对 ChatCrystal 的两套模型配置、连接测试与索引重建边界。
image: "https://zengliangyi.com/og/blog/llm-and-embedding-separation.png"
---

两处设置都叫“模型”，不代表它们可以填同一个名字。生成笔记需要语言模型输出内容，语义搜索需要 Embedding 接口输出数值向量。排查配置问题时，应先确认任务和返回类型，再检查提供方与模型名。

本文核对 [ChatCrystal](/projects/chatcrystal) 提交 [`7642768`](https://github.com/ZengLiangYi/ChatCrystal/tree/764276814e5c5a33ecbfeae63754f74b9261a3a8) 的配置与提供方实现，不给出跨提供方的模型质量排名。

## 同一输入，两种输出

- 文本生成 ：输入一段问题与排查对话，输出标题、摘要、结论等内容，用于生成笔记和发现关系。

- Embedding ：输入用于检索的笔记文本或查询，输出数值向量，用于建立索引和查询相似候选。

[OpenAI 的 Embedding 文档](https://developers.openai.com/api/docs/guides/embeddings)展示了专门的向量请求与响应。不能把生成接口返回的一段文字直接塞进向量索引，也不能仅因为某个模型名称含有 GPT、Claude 或 Qwen，就推断其支持哪些任务；要检查实际模型与接口能力。

生成接口也并非都叫 `/v1/chat/completions`。提供方可能使用 Responses 或自己的协议；[ChatCrystal 的适配代码](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/services/providers.ts)决定具体调用方式。这里的配置分离来自任务契约，不是对所有模型架构作绝对判断。

## 应用中确实有两套配置

[配置代码](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/config.ts)分别保存 `llm` 与 `embedding`，各自包含 `provider`、`baseURL`、`apiKey`、`model`。环境变量提供默认值，已有 `config.json` 中的模型配置会覆盖对应默认值。因此，修改环境变量后，也要确认服务实际加载的结果。



```bash
crystal   config   get  
  crystal   config   test
```



`get` 显示模型名、端点和是否设置密钥，不显示密钥正文。`test` 分别测试两条路径。看见 LLM 成功，不能据此忽略 Embedding 的失败信息。

## 用本地组合说明配置关系

下面是一个明确选择两种任务的示例，不是最快或最准确的模型推荐：



```bash
crystal   config   set   llm.provider   ollama  
  crystal   config   set   llm.baseURL   http://localhost:11434  
  crystal   config   set   llm.model   qwen2.5:7b  
  crystal   config   set   embedding.provider   ollama  
  crystal   config   set   embedding.baseURL   http://localhost:11434  
  crystal   config   set   embedding.model   nomic-embed-text
```



前提是相应模型已下载，服务正在运行。当前 Ollama 适配器会在配置地址后追加 `/v1`，因此这里填写服务根地址，不再重复添加 `/v1`。[Ollama 兼容接口说明](https://docs.ollama.com/api/openai-compatibility)可用于核对生成与向量端点；兼容一个接口，不代表服务支持该接口的所有功能。

当前 ChatCrystal 的 Anthropic 与 OrcaRouter 条目没有创建 Embedding 模型的实现；需要为检索选择另一个支持该任务的条目。这是本版本应用适配的边界，不能据此断言某个厂商永远不会提供向量服务。

混合本地 Embedding 与远端语言模型也可作为配置方案。这样笔记或查询的向量计算可以留在本机，但发送给远端生成模型的材料仍会离开本机；详见[数据流与隐私边界](/blog/local-first-ai-data-boundaries)。

## 连接测试应怎样解释

[测试路由](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/routes/config.ts)会执行短文本生成，再调用 Embedding 处理测试字符串。它分别捕获错误，并用 `connected` 表示两项结果。HTTP 响应成功不等于两项连接都成功；CLI 的输出中出现失败项时，也不能仅凭进程退出码判断通过。

| 现象 | 优先检查 |

| --- | --- |

| 连接被拒绝或超时 | 模型服务是否启动、端点是否可达、地址属于哪个进程 |

| 404 或模型不存在 | 路径是否正确、模型 ID 是否可用、模型是否支持本次任务 |

| 授权失败 | 对应配置是否有有效密钥、账户是否允许调用 |

| 短测试成功，摘要失败 | 实际输入长度、结构化输出能力、运行资源和返回错误 |

错误码只是线索，404 不会自动证明“把 LLM 填进了 Embedding”。保留完整错误和对应配置，分别排查两条调用链。

## 更换向量模型还涉及已有索引

新旧向量不能只因为维度相同就直接混用。模型、版本及输入处理方式改变后，表示空间可能不同。需要让笔记向量与查询向量使用匹配的配置，重新检查检索质量。

ChatCrystal 对部分 Embedding 配置变更会返回确认要求与警告。确认更换提供方或模型后，当前实现会清空已有向量及索引，把笔记标为 `pending`，但不会自动将重建任务入队。先备份并读懂提示，再决定是否带 `--confirm`；不要把配置更新成功当成重建已开始。

在新的模型配置测试通过后，本机模式可通过[批量向量接口](https://github.com/ZengLiangYi/ChatCrystal/blob/764276814e5c5a33ecbfeae63754f74b9261a3a8/server/src/routes/notes.ts)显式提交待处理笔记：



```bash
curl   --request   POST   http://localhost:3721/api/embeddings/batch
```



返回的 `queued` 是入队数量，不是已经完成的数量。可读取任务快照，并用列表中实际的笔记 ID 查看详情：



```bash
curl   http://localhost:3721/api/queue/status  
  crystal   --json   notes   list
```





```text
crystal --json notes get <note-id>
```



队列响应在 `data` 中提供状态；笔记详情的 JSON 直接包含 `embedding_status`。笔记为 `done` 后，再验证已知答案和不应匹配的查询。`pending` 或 `syncing` 表示尚未完成，`failed` 需要结合任务错误排查。不能只看队列暂时为空就判断所有笔记成功。修改 `baseURL` 等其他设置时，也应检查旧索引是否仍与新查询匹配。

第一次使用可以先完成[安装与单条笔记验证](/blog/chatcrystal-getting-started)。测试一条已知答案的查询，再加入一个不应匹配的查询，才能同时观察成功与失败路径。

分享：

##  相关文章

[##  实现 Embedding 服务：文本、分块与提交边界

对照 ChatCrystal 的真实 Embedding 流程，区分文本选择、软分块、向量校验与提交，并用离线反例验证边界。          曾亮懿       2026年10月6日      阅读约 4 分钟

#ChatCrystal

#AI

#Node.js](/blog/embedding-service-design)    [##  结构化 JSON Prompt：把输出字段与来源证据一起设计

以 ChatCrystal 摘要和关系发现为例，设计字段契约、可见输入与反例样本，并用离线 Zod 练习区分格式验证和证据验证。          曾亮懿       2026年10月6日      阅读约 4 分钟

#ChatCrystal

#AI

#Node.js](/blog/structured-json-prompts)    [##  Vectra 本地搜索：用固定向量验证排序、过滤与持久化

在临时目录运行 Vectra 0.15.0 的确定性练习，检查余弦分数、元数据过滤、重新打开索引和取消更新。          曾亮懿       2026年10月6日      阅读约 4 分钟

#ChatCrystal

#AI

#Node.js](/blog/vectra-local-search)

##  从文章到代码

到我的 GitHub 看看 ChatCrystal、开发者工具和日常学习记录，欢迎交流实现细节。

[访问我的 GitHub](https://github.com/ZengLiangYi)

```json
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "ZengLiangYi Blog",
  "alternateName": [
    "Zeng Liangyi",
    "ZengLiangYi",
    "zengliangyi.com"
  ],
  "url": "https://zengliangyi.com",
  "description": "曾亮懿的个人网站。记录 AI Native 探索、开发者工具与全栈产品实践。"
}
{
  "@context": "https://schema.org",
  "@type": "BlogPosting",
  "headline": "LLM 与 Embedding：配置相同提供方也要区分任务",
  "description": "从生成文本与生成向量的接口差异出发，核对 ChatCrystal 的两套模型配置、连接测试与索引重建边界。",
  "url": "https://zengliangyi.com/blog/llm-and-embedding-separation/",
  "image": "https://zengliangyi.com/images/blog/llm-and-embedding-separation.svg",
  "datePublished": "2026-10-03T00:00:00.000Z",
  "dateModified": "2026-10-03T00:00:00.000Z",
  "author": {
    "@type": "Person",
    "name": "曾亮懿",
    "url": "https://zengliangyi.com/about"
  },
  "publisher": {
    "@type": "Organization",
    "name": "ZengLiangYi Blog",
    "logo": {
      "@type": "ImageObject",
      "url": "https://zengliangyi.com/favicon-96x96.png"
    }
  },
  "mainEntityOfPage": {
    "@type": "WebPage",
    "@id": "https://zengliangyi.com/blog/llm-and-embedding-separation/"
  }
}
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    {
      "@type": "ListItem",
      "position": 1,
      "name": "首页",
      "item": "https://zengliangyi.com/"
    },
    {
      "@type": "ListItem",
      "position": 2,
      "name": "文章",
      "item": "https://zengliangyi.com/blog"
    },
    {
      "@type": "ListItem",
      "position": 3,
      "name": "LLM 与 Embedding：配置相同提供方也要区分任务",
      "item": "https://zengliangyi.com/blog/llm-and-embedding-separation/"
    }
  ]
}
```
