agentscope-ai / agentscope-ai/QwenPaw
[Feature]: Support GPT-5.6 prompt caching parameters in Responses API provider
- Dominant language
- Python
- Stars
- 34.9k
- Forks
- 3.1k
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 225
Description
## Summary
支持 GPT-5.6 模型的 prompt caching 参数(`prompt_cache_key`、`prompt_cache_options`、`prompt_cache_breakpoint`),使 Agent 循环中的多轮对话能够复用缓存前缀,降低延迟和成本。
## Component(s) Affected
- [x] Core / Backend (app, agents, config, providers, utils, local_models)
- [ ] Console (frontend web UI)
- [ ] Channels (DingTalk, Feishu, QQ, Discord, iMessage, etc.)
- [ ] Skills
- [ ] CLI
- [ ] Documentation (website)
- [ ] Tests
- [ ] CI/CD
- [ ] Scripts / Deploy
## Problem / Motivation
### 问题描述
当使用 GPT-5.6 模型通过 Responses API 提供商时,prompt caching 功能基本失效:
- `cache_write_tokens`(缓存写入)非常少或几乎没有
- `cached_tokens`(缓存读取)在多轮 Agent 对话中持续接近 0
- 无法观察到 prompt caching 带来的成本/延迟收益
### 根因分析
通过检查 QwenPaw 源码,发现问题在于 Responses API 提供商没有传递 GPT-5.6 特有的缓存控制参数:
1. **`providers/openai_response_provider.py`**:`OpenAIResponseModelCompat._call_api()` 仅转发 `extra_generate_kwargs` 和标准 `generate_kwargs`,没有对以下参数做特殊处理:
- `prompt_cache_key`(注:顶层参数,实际可经 `generate_kwargs` 透传,但无专门配置入口/文档)
- `prompt_cache_options`(注:顶层参数,实际可经 `generate_kwargs` 透传,但无专门配置入口/文档)
- `prompt_cache_breakpoint`(无法经 `generate_kwargs` 透传:需附加到 input 内 content block)
- `previous_response_id`(无法静态配置:每轮响应 id 不同,需框架自动追踪注入)
2. **GPT-5.6 缓存行为变更**:根据 OpenAI 官方文档,GPT-5.6 模型与早期模型的行为不同:
> GPT-5.6 模型在缓存断点处缓存精确的 prompt 前缀。默认情况下,服务在**最新的 user 或 tool 消息**处放置隐式断点。与早期模型不同,它**不会**自动回退到该断点之前最长的匹配未标记前缀。
3. **Agent 循环场景**:在 QwenPaw 的 Agent 循环中,每一轮都会在对话末尾追加新的工具调用和工具结果。因此隐式断点落在**每轮都变化**的内容上,导致缓存前缀实际上永远不会被复用。
### 受益用户
- 使用 GPT-5.6 系列模型的用户
- 运行多轮 Agent 对话(包含工具调用)的用户
- 关注 API 成本和响应延迟的用户
## Proposed Solution
### A. 提供商/模型级别的 `prompt_cache_key`
在提供商或模型配置中添加 `prompt_cache_key` 字段(类似于现有的 `generate_kwargs`)。将其作为 `responses.create()` 的顶层参数传递。
```json
{
"provider_id": "openai-response",
"model": "gpt-5.6",
"prompt_cache_key": "qwenpaw-agent-default-v1"
}
```
### B. 显式缓存断点注入
在构建 `OpenAIResponseModel` 的 `input` 数组的格式化器中,识别"稳定前缀"的最后一个 content block(例如最后一个系统消息或最后一个工具定义 block),并附加:
```json
{
"prompt_cache_breakpoint": { "mode": "explicit" }
}
```
这应该是可选的,由配置标志控制,例如 `enable_prompt_cache_breakpoint: true`。
### C. `prompt_cache_options` 透传
允许在 `generate_kwargs` 或专用配置字段中指定 `prompt_cache_options`:
```json
{
"prompt_cache_options": {
"mode": "explicit",
"ttl": "30m"
}
}
```
### D. `previous_response_id` 追踪(远期目标)
在单个 Agent 会话内,存储每轮的 `response.id`,并在下一轮作为 `previous_response_id` 传递。这将允许服务端复用完整的先前上下文,而无需重新传输。
## Alternatives Considered
1. **手动修改源码**:用户直接修改 `openai_response_provider.py` 添加参数传递——不可维护,每次升级会被覆盖
2. **通过 `generate_kwargs` 传递**:`prompt_cache_key` 和 `prompt_cache_options` 是请求**顶层参数**,可以通过 `generate_kwargs` 直接透传(`OpenAIResponseModelCompat._call_api()` 只过滤 `modalities`/`audio` 两个键,其余键会 `api_kwargs.update(...)` 原样透传到 `client.responses.create()`);但 `prompt_cache_breakpoint` **无法**通过顶层参数实现——它必须附加到 `input` 数组内的特定 content block(如 `input_text` block)上,需要修改 formatter 层
3. **提供商特定配置字段**:为每个缓存参数添加独立配置项——过于僵化,不如通用方案灵活
## Additional Context
### 相关 Issue
- #1003 - Performance bottleneck in distributed self-hosted providers: cache miss amplification without session-sticky routing(提到"需要显式 cache breakpoints")
### OpenAI 官方文档
- [Prompt Caching Guide](https://platform.openai.com/docs/guides/prompt-caching)
- [Conversation State](https://platform.openai.com/docs/guides/conversation-state)
- [Responses API Reference](https://platform.openai.com/docs/api-reference/responses)
Contributor guide
Assessment
This issue has not been assessed yet.