# 语义缓存技术参考

本页供需要直接配置 Gate、调用管理接口或核对匹配规则的管理员与开发者查阅。日常使用请先阅读[语义缓存指南](/guide/semantic-cache)。

## 管理员配置

配置作用于接收管理请求的 Gate 实例。管理员先确认目标实例、存储连接和管理权限；多个 Gate 不会因保存其中一个实例的配置而自动同步。

控制台已接入缓存配置能力时，可在对应实例中操作；菜单、按钮和筛选项以所部署版本为准。以下提供 Gate 管理接口的完整操作路径，适用于控制台尚未提供入口或需要直接维护实例的部署。

### 准备管理入口与存储

Gate 管理地址由运维提供，与 New API 管理地址、业务 API 地址分别确认。示例使用 `https://gate-admin.example.com`，路径不带业务 API 的 `/v1` 前缀；直接访问 Gate 的默认监听端口为 `8025`。

管理接口默认关闭。运维需配置至少 32 字符的独立 `proxy.admin_token`，或通过 `ONEGATEWAY_ADMIN_TOKEN` 环境变量注入，并重启 Gate 使管理入口启用。业务 API Key 和 New API 管理凭据不能替代 Gate 管理凭据。后续缓存配置更新无需重启。

以下管理命令假定调用端也已将该独立管理凭据放入 `ONEGATEWAY_ADMIN_TOKEN` 环境变量；Gate 进程中的环境变量不会自动传到调用端。

缓存配置 API 要求 Gate 配置文件中已有 `name: semantic_cache` 插件条目；没有该条目时，由运维先在既有配置的 `plugins` 列表中增加，不要覆盖其他插件。使用 API 保存时，配置文件及其所在目录应满足 Gate 的读取、创建临时文件与原子替换权限要求；只读配置部署应通过原有配置发布流程更新。

#### 存储配置参考

两种模式都使用下表中的存储适配器。仅精确模式写入与配置维度相同的占位向量，不调用 Embedding；语义模式写入真实向量。两种模式都必须满足后端的维度、索引和权限要求。

| `vector_store` | 连接与认证字段 | 集合或索引准备 |
| --- | --- | --- |
| `qdrant` | `qdrant.endpoint`，例如 `http://qdrant:6333`；认证使用 `qdrant.api_key` | Gate 创建同名 collection；已有集合校验向量维度 |
| `weaviate` | `weaviate.endpoint`，例如 `http://weaviate:8080`；认证使用 `weaviate.api_key` | Gate 创建对应 class；已有 class 检查维度兼容性 |
| `milvus` | `milvus.address`，例如 `milvus:19530`；可配置 `username`、`password` | Gate 创建 collection 与向量索引；已有集合检查维度和字段结构 |
| `redis` | `redis.addr`，例如 `redis:6379`；可配置 `username`、`password`、`db` | 需要 Redis Stack 的 RediSearch 能力；Gate 创建搜索索引，即使仅精确模式也需要这些能力 |
| `pinecone` | `pinecone.index_host` 与 `pinecone.api_key` | 预先创建与 `dimension` 一致的向量索引，语义检索使用 cosine 度量；namespace 在首次写入时产生 |

地址必须从 Gate 所在网络可达；容器中的 `localhost` 指向该容器自身。认证字段按后端实际要求填写。仅精确模式可使用下文的 Qdrant 一维配置；换用其他后端或已有索引时，按该后端支持的维度配置，不能一律照搬 `dimension: 1`。

命名空间 `namespace` 用于区分底层缓存集合，默认值为 `OGSemanticCache`；缓存键用于区分集合内的业务空间。测试与生产应使用不同命名空间或独立存储。为已有索引切换维度时，参阅[配置变更与重启](#配置变更与重启)。

### 最小配置：仅精确匹配

以下示例用于一个已经部署 Gate、准备好 Qdrant 的实例。先读取当前配置与 ETag，确认操作对象：

```bash
SC_ADMIN_URL='https://gate-admin.example.com'
curl -i "$SC_ADMIN_URL/admin/v1/plugins/semantic-cache/config" \
  -H "Authorization: Bearer $ONEGATEWAY_ADMIN_TOKEN"
```

将下面的 JSON 保存为本地 `semantic-cache-update.json`。将 Qdrant 地址和认证替换为实际值，并选择一个新的测试命名空间。此示例是完整替换用的配置，不要直接覆盖需要保留的现有策略：

```json
{
  "enabled": true,
  "config": {
    "embedding_url": "",
    "dimension": 1,
    "vector_store": "qdrant",
    "qdrant": {
      "endpoint": "http://qdrant:6333",
      "api_key": ""
    },
    "namespace": "OGFaqDirect",
    "ttl": "5m",
    "threshold": 0.8,
    "max_history": 3,
    "default_cache_key": "",
    "cache_by_model": true,
    "cache_by_provider": true,
    "exclude_system_prompt": false,
    "max_cacheable_bytes": 0
  }
}
```

`embedding_url` 留空即为仅精确模式；未提供维度时默认使用 `1`。本例默认缓存键为空，验证时显式传入 `hcd-og-cache-key: faq-demo`。存在 `proxy.upstream` 时，缓存前凭据校验默认启用。

### 增加语义匹配

在同一份完整候选配置中，将以下字段合并进 `config`，替换仅精确模式的地址、维度和命名空间。该片段不是可单独提交的完整请求：

```json
{
  "embedding_url": "http://ollama:11434/api/embed",
  "embedding_format": "ollama",
  "embedding_api_key": "",
  "embedding_model": "bge-m3:latest",
  "embedding_provider": "ollama",
  "dimension": 1024,
  "namespace": "OGFaqSemantic"
}
```

此例要求该服务已加载对应模型，且实际返回 1024 维向量；应通过下文的配置校验确认。原先一维的 `OGFaqDirect` 集合不能直接用于此示例。即使新旧模型维度相同，更换模型也应使用新命名空间，避免混用不同模型的向量。

| 字段 | 填写规则 |
| --- | --- |
| `embedding_url` | 完整接口地址，Gate 原样发送 POST，不自动追加路径 |
| `embedding_format` | `openai` 或 `ollama` |
| `embedding_api_key` | 需要认证时填写；非空时以 Bearer 方式发送 |
| `embedding_model` | 服务中实际可用的模型名 |
| `dimension` | 必须与模型实际返回的向量长度一致；不能仅根据模型名称推测 |
| `embedding_provider` | 日志和遥测中的 Embedding 提供方名称 |

OpenAI 兼容格式的地址形如 `https://embedding.example.com/v1/embeddings`，Ollama 格式形如 `http://ollama:11434/api/embed`。只填写主机地址或 `/v1` 不会被自动补全；所选服务若使用自定义路径，填写其实际接口路径。

### 基础参数

| 配置项 | 默认值 | 说明 |
| --- | --- | --- |
| 缓存有效期（TTL） | `5m` | 新缓存条目的有效时长。支持 `30s`、`5m`、`1h` 或秒数 |
| 相似度阈值 | `0.8` | 语义匹配的最低相似度；自定义阈值大于 `0` 且不超过 `1`，配置为 `0` 时使用默认值。越高越严格，仅精确模式不使用此参数 |
| 默认缓存键 | 空 | 未指定 `hcd-og-cache-key`、未提供 `hcd-og-tenant-id`、且网关上下文没有用户标识时使用的缓存空间 |
| 对话历史阈值 | `3` | 参与计数的消息条数超过阈值时，整次请求跳过缓存 |
| 最大可缓存响应大小 | `0` | 单位为字节；`0` 表示不限制，超过上限的响应不会写入缓存 |

缓存有效期从条目写入时开始计算，命中不会续期。修改默认 TTL 不会重置已有条目的过期时间。

::: details 显式零值的含义

缓存配置中的 `threshold: 0`、`ttl: 0`（或兼容字段 `ttl_seconds: 0`）、`max_history: 0` 都表示使用各自默认值，分别为 `0.8`、5 分钟、3 条消息。因此，`max_history: 0` 不能用于让全部对话跳过缓存，`ttl: 0` 也不表示永久有效。最大响应大小的 `max_cacheable_bytes: 0` 则表示不限制。

:::

::: tip 消息条数与对话轮数不同

对话历史阈值按消息条数计算。例如，`system + user + assistant + user` 共 4 条消息，在默认阈值 `3` 下会跳过缓存。开启“排除系统提示词”后，`system` 消息不计入该阈值。

Responses 的字符串 `input` 按 1 条计数，数组 `input` 按条目计数。

:::

### 隔离规则

| 隔离配置 | 默认状态 | 说明 |
| --- | --- | --- |
| 按模型隔离 | 开启 | 不同模型分别缓存 |
| 按提供方隔离 | 开启 | 不同上游提供方分别缓存 |
| 排除系统提示词 | 关闭 | 默认让系统提示词参与缓存判定；开启后忽略 `system` 消息，并将其排除在历史条数计数之外 |

通常保留默认隔离规则。关闭模型或提供方隔离后，可能复用其他模型或提供方生成的回答；排除系统提示词后，也可能复用其他角色设定下生成的回答。

### 保存并确认生效

1. 使用上文准备的完整 JSON 校验配置。
2. 校验成功后，使用首次 GET 返回的完整 ETag 保存同一份配置。
3. 检查保存结果和当前状态，再执行[快速验证](/guide/semantic-cache#快速验证)。

校验命令：

```bash
curl -i -X POST "$SC_ADMIN_URL/admin/v1/plugins/semantic-cache/config:validate" \
  -H "Authorization: Bearer $ONEGATEWAY_ADMIN_TOKEN" \
  -H 'Content-Type: application/json' \
  --data-binary @semantic-cache-update.json
```

成功返回 `200`，响应中的 `valid` 为 `true`。语义模式下会探测 Embedding 服务并核对维度，最多等待 30 秒；此步骤不连接缓存存储、不创建集合，也不保存配置。

保存前，将下面的 `SC_ETAG` 替换为 GET 响应头中的完整值，保留双引号：

```bash
SC_ETAG='"sc-<GET 返回的版本值>"'
curl -i -X PUT "$SC_ADMIN_URL/admin/v1/plugins/semantic-cache/config" \
  -H "Authorization: Bearer $ONEGATEWAY_ADMIN_TOKEN" \
  -H 'Content-Type: application/json' \
  -H "If-Match: $SC_ETAG" \
  --data-binary @semantic-cache-update.json
```

PUT 完整替换该插件的 `enabled` 和 `config`，不是局部更新。GET 返回的密钥是脱敏对象，不能原样提交；需使用自己保存的完整配置并补回所需密钥。PUT 不重复执行 Embedding 探测，因此应校验和保存同一份候选文件。

成功返回 `200`、新的 ETag 和当前脱敏配置。启用时，Qdrant、Weaviate、Milvus、Redis 的连接或集合初始化失败会使本次保存失败；Pinecone 初始化不检查索引连通性，保存成功后仍需通过实际请求验证读写。

```bash
curl -sS "$SC_ADMIN_URL/admin/v1/plugins/semantic-cache/config/status" \
  -H "Authorization: Bearer $ONEGATEWAY_ADMIN_TOKEN"
```

检查 `enabled`、`applied_version` 是否符合本次保存结果，并查看 `last_reload_failed`。仅看到 `status: applied` 不能排除最近一次文件热更新失败。

| 结果 | 下一步 |
| --- | --- |
| `401 admin_unauthorized` | 核对独立 Gate 管理凭据 |
| `404 not_found` / `semantic_cache_config_missing` | 核对管理入口是否启用、路径及插件条目 |
| `409 config_drift` / `412 config_precondition_failed` | 重新 GET，合并其他人的变更后再校验、保存 |
| `422 semantic_cache_config_invalid` / `semantic_cache_dependency_invalid` | 按错误信息检查字段、模型维度、存储和插件配置 |
| `503 config_persist_failed` | 检查配置目录权限、挂载方式和磁盘；不要仅凭健康检查成功判断配置已更新 |

配置更新失败时，网关保留上一份有效配置。正在处理的普通和流式请求继续使用原配置直到生命周期结束。关闭缓存后，新请求不查询也不写入；关闭功能不等于[清理缓存](#清理缓存)。

## 请求头解析细节

不带单位的 TTL 必须是整数：`300` 表示 300 秒，`1.5` 非法并回退到默认值；需要小数秒时可使用 `1.5s`。

No-Store 的开启值为 `true`、`True`、`TRUE`、`1`、`t`、`T`，建议统一使用 `true`。关闭值为 `false`、`False`、`FALSE`、`0`、`f`、`F`；非法值也不会开启只读模式。

## 缓存空间与匹配边界

当前 Gate 数据面按以下优先级选择缓存键：

1. 请求头 `hcd-og-cache-key`。
2. 请求头 `hcd-og-tenant-id` 提供的租户标识。
3. 网关上下文中已设置的用户标识，组成 `user:<用户标识>`；没有该上下文值时跳过此层。
4. 缓存配置中的 `default_cache_key`。

所有来源均为空时，请求不查询也不写入缓存。仅仅省略 `hcd-og-cache-key`，并不代表一定跳过缓存。

在业务缓存空间之外，缓存还按 API 凭据隔离。不同 API Key 即使使用相同缓存键，也不会互相命中。缓存键用于业务分区，不能替代身份认证或租户授权。

::: warning 租户标识的信任边界

`hcd-og-tenant-id` 可由调用方设置，当前未与已认证的 API 凭据绑定，因此它是业务分区标识，不能作为租户授权依据。不同凭据之间仍有缓存隔离，但共用同一凭据的调用方可以通过修改该头选择租户缓存空间。需要按租户隔离时，应由可信入口控制并注入租户头和业务缓存键。

:::

### 支持的凭据形式

请求可使用单一的 `Authorization: Bearer <token>`，或单一的 `X-Api-Key: <key>`（例如 Claude 原生客户端）。两种形式同时传入、同类凭据头重复，或凭据格式不合法时，网关因无法明确凭据而跳过缓存，继续交由上游处理业务请求。

缓存隔离依据是凭据值。同一个值分别通过 Bearer 和 `X-Api-Key` 传入时，隔离范围相同；在其他匹配条件一致且凭据校验通过时，可以复用同一缓存。不同的值不会共享缓存。

### 请求匹配边界

| 条件变化 | 对命中的影响 |
| --- | --- |
| API Key 或缓存键不同 | 不共享缓存 |
| 接口不同 | 不共享缓存，例如 Chat Completions 与 Messages 分别缓存 |
| 流式与非流式不同 | 分别缓存，不互相转换 |
| 模型或提供方不同 | 默认不共享；受隔离配置控制 |
| 生成参数不同 | `temperature`、`max_tokens` 等参与匹配边界，变化可能导致未命中 |
| 工具定义或附件不同 | 参与匹配边界，不会只按问题文本复用 |
| 系统提示词或对话文本不同 | 默认影响精确匹配，并参与语义判断；系统提示词可配置为排除 |

精确匹配会进行归一化，包括文本转小写和去除首尾空白；不是对原始 HTTP 请求逐字节比较。语义匹配则在满足参数及隔离条件后，根据文本相似度选择缓存。

对于多模态或结构化内容块数组，生成请求指纹时会从每个对象提取非空的 `type`、`text`、`source`、`name`、`id` 字段；提取到这些字段后，其余字段不进入该内容块的请求指纹。若没有可提取的关键字段，则保留原对象。因此，仅 `annotations` 等被忽略字段不同、且没有触发参数或附件的独立隔离条件时，两个请求仍可能精确命中。不要把“结构化字段有变化”直接等同于“一定不会命中”。

### 缓存前的凭据校验

配置了 `proxy.upstream` 时，`auth_validation` 默认启用。符合缓存条件的请求在查找缓存前，会向对应的 New API 上游发送 `GET /v1/models`，按业务请求原本使用的凭据头形式验证凭据；校验路径可由管理员配置。

默认情况下，有效凭据的校验结果缓存 5 分钟，拒绝结果缓存 30 秒，单次探测超时为 3 秒。同一上游、凭据和凭据头形式的并发探测会合并，并非每次业务请求都发送一次探测。

探测会增加对 New API 的请求量，并可能增加首次访问或校验结果过期后的等待时间；即使精确命中缓存，也可能需要先完成探测。校验被拒绝或探测出错时，本次跳过缓存，由上游继续处理业务请求。`og-cache-latency-ms` 不包含这段凭据探测耗时。

## 生命周期与清理

### 写入与过期

非流式请求在成功响应后异步写入；流式请求在成功结束后异步保存完整事件序列。写入失败不影响已经返回的业务响应，但后续请求可能无法命中。

缓存条目到期后不再用于响应，下次请求会重新查找可用缓存或调用上游。命中不会延长有效期，也不会重复写入该条目。

### 不参与缓存或不写入的情况

| 情况 | 行为 |
| --- | --- |
| 未启用缓存、接口不支持或请求结构不满足条件 | 跳过缓存 |
| 缺少可用凭据，或启用的凭据校验未通过 | 跳过缓存，继续由上游处理业务请求 |
| 无法确定缓存键 | 不查询、不写入 |
| 对话历史超过阈值 | 不查询、不生成 Embedding、不写入 |
| 仅语义请求但未配置 Embedding 服务 | 跳过缓存 |
| `hcd-og-no-store: true` | 可读取，不写入新响应 |
| 上游返回非 `200`，或响应超过大小上限 | 不写入 |
| 流式响应中断或未成功结束 | 不保存不完整的流式回答 |
| Responses 返回失败、未完成、取消或仍在执行的状态 | 不写入 |

Embedding 或缓存存储查询失败时，请求继续调用上游。精确查找先于 Embedding 执行，已有精确缓存仍可在 Embedding 服务异常时命中。

### 流式响应

使用 `stream: true` 时，未命中请求正常接收上游 SSE 输出，命中请求回放已缓存的 SSE 事件。客户端仍按原协议处理流式响应。

缓存回放不保证保留原回答逐字生成的时间间隔。测试流式命中时，前后两次请求都需要开启 `stream: true`。

### 配置变更与重启

| 操作 | 对旧条目和后续请求的影响 |
| --- | --- |
| 关闭后再启用 | 关闭不删除条目；重新启用后，仍可复用存储中未过期且满足匹配条件的条目 |
| 重启 Gate | 插件关闭时不清空后端缓存；重新连接相同存储和命名空间后，可继续查找尚未过期的条目 |
| 重启或重建缓存存储 | 数据是否保留取决于后端持久化、数据卷及恢复方式，不能仅根据 Gate 重启行为判断 |
| 修改默认 TTL | 只影响后续新写入的条目，不更改已有条目的过期时间 |
| 切换命名空间 | 新请求使用新空间；原空间的数据仍保留，切回时可能继续命中未过期条目 |
| 更换 Embedding 模型或维度 | 使用新命名空间；维度变化还需匹配的集合或索引，Pinecone 必须另行准备匹配维度的索引 |
| 主动清理缓存 | 删除指定范围内的条目，不停止新请求或在途请求的后台写入 |

Gate 正常释放插件时会等待已登记的后台写入结束，再关闭存储连接；强制终止进程或主机故障不保证尚未完成的写入落库。热更新前已开始的请求仍使用旧配置，也可能继续向旧命名空间写入。

TTL 到期表示条目不再用于回答，不代表存储空间在同一时刻释放。Gate 会对查找到的过期条目进行异步删除；不能把 TTL 当作全库定时清扫承诺。

### 清理缓存

业务知识更新或发现缓存回答不适用时，管理员可以主动清理缓存，使后续请求重新获取回答。

| 清理方式 | 操作依据 | 适用场景 |
| --- | --- | --- |
| 按条目 ID 清理 | 从命中响应的 `og-cache-id` 或日志详情取得 ID | 清除某一条回答 |
| 按缓存键清理 | 指定需要清理的业务缓存键 | 某一业务空间的知识整体更新 |

清理前确认清理范围。按缓存键清理会删除当前命名空间内该键对应的 OneGateway 缓存，可能包含多个 API Key 各自生成的条目。

删除后已有日志仍可用于排查；后续请求也可能命中其他符合条件的条目。若需要整体更新某个业务空间，应按缓存键清理，或切换到新的版本化缓存键，例如从 `product-faq:v1` 改为 `product-faq:v2`。

#### 使用管理接口清理

由具备权限的管理员调用，使用[管理员配置](#准备管理入口与存储)中确认的 Gate 管理地址及独立管理凭据。

1. 从命中响应的 `og-cache-id` 或日志取得来源条目 ID；MISS 中的候选 ID 不保证实际存在。
2. 确认目标实例、命名空间以及按 ID 或按键清理的范围。
3. 执行以下一种清理方式，检查响应结果。
4. 等待存储变更可见后，以同一凭据和缓存键再次请求，检查 `og-cache`、`og-cache-type` 和条目 ID。

按条目 ID 清理：

```bash
SC_ADMIN_URL='https://gate-admin.example.com'
curl -i -X DELETE --get \
  "$SC_ADMIN_URL/admin/plugins/semantic_cache/cache" \
  -H "Authorization: Bearer $ONEGATEWAY_ADMIN_TOKEN" \
  --data-urlencode 'cache_id=<命中的缓存条目 ID>'
```

按业务缓存键清理：

```bash
curl -i -X DELETE --get \
  "$SC_ADMIN_URL/admin/plugins/semantic_cache/cache" \
  -H "Authorization: Bearer $ONEGATEWAY_ADMIN_TOKEN" \
  --data-urlencode 'cache_key=product-faq:v1'
```

`--get` 将参数放入 URL，`-X DELETE` 指定删除方法，`--data-urlencode` 负责参数编码。一次请求必须且只能提供 `cache_id` 或 `cache_key` 中的一个。

成功响应：

```http
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store

{"status":"ok"}
```

按 ID 删除不存在的条目也可能成功返回；成功响应不包含实际删除数量。删除不等待所有业务请求停止，在途请求可能再次写入旧回答；若要发布新版知识，优先切换业务缓存键版本，并让应用统一使用新键。

验证时若仍为 HIT，应比较条目 ID：可能命中了另一条相似回答，也可能受到后台写入或后端可见性延迟影响。不要将“删除一条成功”理解为“整个业务空间此后必然 MISS”。

| HTTP / 错误码 | 检查或处理 |
| --- | --- |
| `400 bad_request` | 两个清理参数是否恰好提供一个，且不为空 |
| `401 admin_unauthorized` | 是否使用正确、单一的 Gate Admin Bearer 凭据 |
| `404 not_found` | 管理入口是否启用，是否访问正确 Gate 地址与路径 |
| `503 plugin_unavailable` | 语义缓存插件是否已加载；关闭插件后不能通过此入口清理，应先恢复可用配置 |
| `500 clear_cache_failed` | 检查后端错误与连接；不能假定一次失败完全没有删除数据，应重新确认范围 |

错误响应采用 `{"error":{"code":"…","message":"…"}}` 结构。先解决错误原因，再决定是否重试。

## 观察效果与排障

### 响应头

调用方可以直接检查响应头判断本次缓存行为，无需访问管理控制台。

| 响应头 | 含义 | 出现条件 |
| --- | --- | --- |
| `og-cache` | `HIT` 表示命中，`MISS` 表示缓存路径参与但没有返回缓存 | 执行缓存查找时 |
| `og-cache-type` | `direct` 或 `semantic` | 命中时 |
| `og-cache-id` | 命中的来源条目 ID，或未命中时的候选写入 ID | 执行缓存查找时 |
| `og-cache-latency-ms` | 缓存查找耗时，单位毫秒 | 执行缓存查找时 |
| `og-cache-similarity` | 匹配到的相似度 | 语义命中时 |
| `og-cache-threshold` | 本次使用的相似度阈值 | 语义命中时 |
| `og-cache-provider-used` | 实际使用的 Embedding 提供方 | Embedding 成功且该信息可用时 |
| `og-cache-model-used` | 实际使用的 Embedding 模型 | Embedding 成功且该信息可用时 |
| `og-cache-input-tokens` | 本次 Embedding 输入 Token 数 | Embedding 成功且返回正数用量时 |

缓存查找耗时不等于整个请求的响应时间，也不包含缓存前的凭据探测耗时。未命中时返回的候选 ID 不代表条目已保存成功；No-Store、写入失败等情况都可能使该条目不存在。

### 缓存监控

缓存监控读取目标 Gate 的请求日志。管理员可通过下列接口按时间范围、租户、模型和协议查询；控制台已接入时，也可使用对应实例的监控页面，具体筛选项以部署版本为准。

接口使用与配置、清理相同的独立管理凭据。汇总、趋势、Token 与日志查询还要求启用 `logging` 插件及 MySQL 日志存储；缓存可用并不表示这些依赖已配置。

| 用途 | GET 路径 |
| --- | --- |
| 请求与命中汇总 | `/admin/v1/plugins/semantic-cache/monitoring/summary` |
| 按日趋势 | `/admin/v1/plugins/semantic-cache/monitoring/trend` |
| Token 汇总 | `/admin/v1/plugins/semantic-cache/monitoring/tokens` |
| 日志列表 | `/admin/v1/plugins/semantic-cache/logs` |
| 日志详情 | `/admin/v1/plugins/semantic-cache/logs/{request_id}` |

例如，查询指定模型最近 24 小时的汇总：

```bash
SC_ADMIN_URL='https://gate-admin.example.com'
curl -sS --get "$SC_ADMIN_URL/admin/v1/plugins/semantic-cache/monitoring/summary" \
  -H "Authorization: Bearer $ONEGATEWAY_ADMIN_TOKEN" \
  --data-urlencode 'model=<MODEL_ID>'
```

省略时间参数时，汇总默认查询最近 24 小时。需要指定范围时，使用 RFC3339 格式的 `from`（包含）与 `to`（不包含）；其他筛选参数为 `tenant_id` 和 `protocol`。这些统计反映目标 Gate 配置的日志存储与筛选范围，不应假定跨实例自动聚合。


| 指标 | 说明 |
| --- | --- |
| 完成请求数 | 筛选范围内成功保存到日志库的全部完成请求 |
| 精确命中数 | 通过 Direct 返回缓存的请求数 |
| 语义命中数 | 通过 Semantic 返回缓存的请求数 |
| 本地缓存命中率 | 精确命中数与语义命中数之和，除以完成请求数 |
| 节省的上游调用次数 | 同一统计范围内的缓存命中总数，表示免去的模型生成调用次数 |

例如，共记录 100 次完成请求，其中 20 次精确命中、10 次语义命中，则本地缓存命中率为 **30%**。跳过缓存、未启用缓存和不支持缓存的请求也进入分母，因此该指标表示全部已记录流量中由缓存承接的比例。

命中率趋势默认覆盖近 15 天，按 UTC 自然日统计，包含当天尚未结束的数据。查看趋势时应注意日期边界与本地时区的差异。


缓存 Token 汇总包含：

- **缓存读取 Token**：缓存命中请求的输入 Token 本地估算之和。
- **缓存写入 Token**：实际成功写入缓存、且有上游用量数据的响应，其输出 Token 之和。
- **覆盖样本数**：有可用 Token 数据的请求或写入次数，用于判断统计完整性；未知用量不视为真实的零。

::: info 统计范围

监控依赖请求日志持久化。日志异步写入，缓存写入统计也可能短暂滞后；日志丢失或写库失败会影响统计完整性。

这里的 Token 是 OneGateway 缓存遥测，不是供应商提示词缓存的计费字段，也不能直接折算为实际节省金额。语义检索还可能产生 Embedding 开销。

:::

### 请求日志与详情

日志列表接口支持按时间、租户、模型、协议筛选，并通过 `cache_hit_types` 选择 `direct` 或 `semantic` 命中。不传该参数时，列表还可能包含未命中、查找异常及跳过缓存的请求；不要传入 `miss` 作为命中类型。

使用列表中的请求 ID 查询日志详情；控制台已接入时也可打开对应记录。详情可以查看请求 ID、模型、流式标志、响应状态、请求耗时，以及缓存命中类型和条目 ID。执行过语义检索且信息可用时，还能查看 Embedding 提供方、模型、输入 Token、阈值和相似度。


排查时，先区分“执行了查找但未命中”和“请求跳过了缓存”。跳过缓存的记录没有缓存查找详情，不能仅凭空白字段判断为缓存故障。

### 按现象排查

先判断请求是跳过缓存、参与查找但未命中，还是已经命中。响应头应在业务响应上检查，管理接口的 `Cache-Control: no-store` 不表示业务缓存状态。

| 现象 | 检查顺序 | 确认依据与下一步 |
| --- | --- | --- |
| 没有 `og-cache` | 功能开关 → 接口和请求形式 → 凭据 → 缓存键 → 消息条数 | 对照[使用前提](/guide/semantic-cache#使用前提与模式选择)；同时确认中间代理是否保留响应头 |
| 相同请求持续 MISS | 首次成功结束 → 后台写入 → TTL → 凭据、键、参数及流式标志 → No-Store | 对照原始请求；候选 ID 不证明写入成功，检查 Gate 的存储错误和写入统计 |
| 精确命中正常，语义始终 MISS | 是否启用语义模式 → 请求级模式 → Embedding → 模型维度 → 匹配边界与阈值 | 先执行配置校验；只有确认回答适合复用后才调整阈值 |
| 换模型后保存失败或读写异常 | 命名空间 → 集合或索引维度 → Embedding 实际输出 | 使用新空间及匹配索引；Pinecone 保存成功仍需验证读写 |
| HIT 但总耗时仍高 | 凭据探测 → 缓存查找 → 客户端端到端耗时 | `og-cache-latency-ms` 不包含凭据探测，也不是完整请求耗时 |
| 响应头正常但监控无数据 | logging → MySQL 日志存储 → 时间与筛选 → 异步延迟 | 查询同一目标 Gate 的汇总和日志；检查日志写库失败 |
| 清理后仍返回旧回答 | 删除结果 → 是否另一条语义命中 → 在途写入 → 存储可见性 | 对比来源 ID；知识升级时统一切换版本化缓存键 |
| 配置校验成功但保存失败 | 存储连接和维度 → 配置目录权限 → ETag / 文件漂移 | 校验不测试存储；按[保存结果表](#保存并确认生效)处理 |

`og-cache-similarity` 与 `og-cache-threshold` 仅在语义命中时提供，不能要求每次 MISS 都返回相似度。语义命中请求的分值也不能用来推断未命中请求的分值。
