[GH-ISSUE #328] [Bug] Claude Code -> Codex 的会话缓存隔离与跨模型缓存命中问题 #237

Closed
opened 2026-02-27 07:18:36 +03:00 by kerem · 3 comments
Owner

Originally created by @ylqgithubylq on GitHub (Feb 14, 2026).
Original GitHub issue: https://github.com/justlovemaki/AIClient-2-API/issues/328

(我有几个使用上的疑问,所以让让ai分析了代码,然后让ai生成的如下内容,不一定对,供参考)

简版总结

当前 Claude Code -> openai-codex-oauth 路径存在两类问题:

  1. 会话隔离风险Claude -> Codex 转换未透传 metadata.user_id,导致缓存键退化为 model-default,不同会话可能共享缓存会话。
  2. 跨模型缓存断开:缓存键包含 model,同一会话切换模型时会生成新缓存键,缓存命中中断。
  3. 潜在数据外传风险:部分路径会把 metadata 透传给上游 Codex 请求,建议仅本地使用后剥离。

当前 commit:a6778ce66d2d70d50c2339e876bf9f47cd0baed8


背景

本项目在 openai-codex-oauth 下,会为每次请求生成并复用 prompt_cache_key,并写入 Conversation_id/Session_id
问题出在缓存键构造所依赖的会话字段在不同转换路径中的保留不一致。

影响范围

  • 并发多个 Claude Code 会话时,可能发生缓存会话串用(隔离性不足)。
  • 同一会话内切换模型时,缓存连续性中断,命中率下降。
  • 某些路径可能把 metadata 透传上游,存在不必要字段外发。

实际行为(代码定位)

1) Claude -> Codex 未透传 metadata

  • src/converters/strategies/ClaudeConverter.js:1866

2) 缓存键依赖 model + metadata.user_id,缺失时回退 default

  • src/providers/openai/codex-core.js:304

3) prompt_cache_key 作为会话头发送

  • src/providers/openai/codex-core.js:320
  • src/providers/openai/codex-core.js:285
  • src/providers/openai/codex-core.js:286

4) 模型可能在链路中被映射(影响缓存键稳定性)

  • src/utils/common.js:853
  • src/utils/common.js:876

5) 其他转换路径会保留 metadata,并可能透传上游

  • src/converters/strategies/CodexConverter.js:85
  • src/providers/openai/codex-core.js:317

复现建议

  1. 配置 MODEL_PROVIDER=openai-codex-oauth
  2. 同时开两个 Claude Code 会话并发请求(同模型)。
  3. 观察缓存键因缺失 metadata.user_id 回退 default
  4. 在同一会话内切换模型后再次请求,观察缓存键变化导致命中断开。

期望行为

  • 不同会话应稳定隔离缓存。
  • 同会话缓存策略应明确(跨模型是否共享应可配置或有清晰规则)。
  • metadata 若仅用于本地缓存,应避免透传上游。

建议修复

  1. codex-core 中提取 metadata.user_id 仅用于本地缓存键,发送前移除 metadata
  2. 缓存键引入明确会话维度(避免回退 default 造成共享)。
  3. 明确是否保留 model 作为缓存键组成:
    • 保留:接受跨模型不共享;
    • 不保留/弱化:提升同会话跨模型命中。
  4. 增加测试:
  • 不同会话同模型隔离测试
  • 同会话跨模型命中策略测试
  • 上游请求字段白名单测试(确保不透传不必要 metadata)
Originally created by @ylqgithubylq on GitHub (Feb 14, 2026). Original GitHub issue: https://github.com/justlovemaki/AIClient-2-API/issues/328 (我有几个使用上的疑问,所以让让ai分析了代码,然后让ai生成的如下内容,不一定对,供参考) ## 简版总结 当前 `Claude Code -> openai-codex-oauth` 路径存在两类问题: 1. **会话隔离风险**:`Claude -> Codex` 转换未透传 `metadata.user_id`,导致缓存键退化为 `model-default`,不同会话可能共享缓存会话。 2. **跨模型缓存断开**:缓存键包含 `model`,同一会话切换模型时会生成新缓存键,缓存命中中断。 3. **潜在数据外传风险**:部分路径会把 `metadata` 透传给上游 Codex 请求,建议仅本地使用后剥离。 当前 commit:a6778ce66d2d70d50c2339e876bf9f47cd0baed8 --- ## 背景 本项目在 `openai-codex-oauth` 下,会为每次请求生成并复用 `prompt_cache_key`,并写入 `Conversation_id/Session_id`。 问题出在缓存键构造所依赖的会话字段在不同转换路径中的保留不一致。 ## 影响范围 - 并发多个 Claude Code 会话时,可能发生缓存会话串用(隔离性不足)。 - 同一会话内切换模型时,缓存连续性中断,命中率下降。 - 某些路径可能把 `metadata` 透传上游,存在不必要字段外发。 ## 实际行为(代码定位) ### 1) `Claude -> Codex` 未透传 `metadata` - `src/converters/strategies/ClaudeConverter.js:1866` ### 2) 缓存键依赖 `model + metadata.user_id`,缺失时回退 `default` - `src/providers/openai/codex-core.js:304` ### 3) `prompt_cache_key` 作为会话头发送 - `src/providers/openai/codex-core.js:320` - `src/providers/openai/codex-core.js:285` - `src/providers/openai/codex-core.js:286` ### 4) 模型可能在链路中被映射(影响缓存键稳定性) - `src/utils/common.js:853` - `src/utils/common.js:876` ### 5) 其他转换路径会保留 `metadata`,并可能透传上游 - `src/converters/strategies/CodexConverter.js:85` - `src/providers/openai/codex-core.js:317` ## 复现建议 1. 配置 `MODEL_PROVIDER=openai-codex-oauth`。 2. 同时开两个 Claude Code 会话并发请求(同模型)。 3. 观察缓存键因缺失 `metadata.user_id` 回退 `default`。 4. 在同一会话内切换模型后再次请求,观察缓存键变化导致命中断开。 ## 期望行为 - 不同会话应稳定隔离缓存。 - 同会话缓存策略应明确(跨模型是否共享应可配置或有清晰规则)。 - `metadata` 若仅用于本地缓存,应避免透传上游。 ## 建议修复 1. 在 `codex-core` 中提取 `metadata.user_id` 仅用于本地缓存键,发送前移除 `metadata`。 2. 缓存键引入明确会话维度(避免回退 `default` 造成共享)。 3. 明确是否保留 `model` 作为缓存键组成: - 保留:接受跨模型不共享; - 不保留/弱化:提升同会话跨模型命中。 4. 增加测试: - 不同会话同模型隔离测试 - 同会话跨模型命中策略测试 - 上游请求字段白名单测试(确保不透传不必要 metadata) ```
kerem closed this issue 2026-02-27 07:18:36 +03:00
Author
Owner

@ylqgithubylq commented on GitHub (Feb 15, 2026):

看到作者更新了,扫了一眼代码,对这一部分的改动存疑:
src\providers\openai\codex-core.js的prepareRequestBody里:

        // 生成会话缓存键
        // 默认弱化 model 依赖,以提升同会话跨模型的缓存命中率
        // 如果 sessionId 为 'default',则必须加上 model 以提供基础隔离
        let cacheKey = sessionId;
        if (sessionId === 'default') {
            cacheKey = `${model}-default`;
        } else {
            cacheKey = `${model}-${sessionId}`;
        }

这个else里是不是不应该再有model被拼进去了?

<!-- gh-comment-id:3903514684 --> @ylqgithubylq commented on GitHub (Feb 15, 2026): 看到作者更新了,扫了一眼代码,对这一部分的改动存疑: src\providers\openai\codex-core.js的prepareRequestBody里: ~~~ // 生成会话缓存键 // 默认弱化 model 依赖,以提升同会话跨模型的缓存命中率 // 如果 sessionId 为 'default',则必须加上 model 以提供基础隔离 let cacheKey = sessionId; if (sessionId === 'default') { cacheKey = `${model}-default`; } else { cacheKey = `${model}-${sessionId}`; } ~~~ 这个else里是不是不应该再有model被拼进去了?
Author
Owner

@justlovemaki commented on GitHub (Feb 20, 2026):

看到作者更新了,扫了一眼代码,对这一部分的改动存疑: src\providers\openai\codex-core.js的prepareRequestBody里:

        // 生成会话缓存键
        // 默认弱化 model 依赖,以提升同会话跨模型的缓存命中率
        // 如果 sessionId 为 'default',则必须加上 model 以提供基础隔离
        let cacheKey = sessionId;
        if (sessionId === 'default') {
            cacheKey = `${model}-default`;
        } else {
            cacheKey = `${model}-${sessionId}`;
        }

这个else里是不是不应该再有model被拼进去了?

为什么呢?

<!-- gh-comment-id:3933263222 --> @justlovemaki commented on GitHub (Feb 20, 2026): > 看到作者更新了,扫了一眼代码,对这一部分的改动存疑: src\providers\openai\codex-core.js的prepareRequestBody里: > > ``` > // 生成会话缓存键 > // 默认弱化 model 依赖,以提升同会话跨模型的缓存命中率 > // 如果 sessionId 为 'default',则必须加上 model 以提供基础隔离 > let cacheKey = sessionId; > if (sessionId === 'default') { > cacheKey = `${model}-default`; > } else { > cacheKey = `${model}-${sessionId}`; > } > ``` > > 这个else里是不是不应该再有model被拼进去了? 为什么呢?
Author
Owner

@ylqgithubylq commented on GitHub (Feb 20, 2026):

因为一个对话内部会切换model吧,如果这个model的含义是用户指定的model的话(比如第一个问题用gpt 5.3 codex,ai回复后切换到gpt 5.2继续对话这种)。不过我不确定是不是这个机制,如果不是的话那就是我理解错了。

<!-- gh-comment-id:3933304060 --> @ylqgithubylq commented on GitHub (Feb 20, 2026): 因为一个对话内部会切换model吧,如果这个model的含义是用户指定的model的话(比如第一个问题用gpt 5.3 codex,ai回复后切换到gpt 5.2继续对话这种)。不过我不确定是不是这个机制,如果不是的话那就是我理解错了。
Sign in to join this conversation.
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/AIClient-2-API-justlovemaki#237
No description provided.