makecindy / makecindy/cindy

bug: 长 prompt 场景缓存命中率低(XD 网关路线缺缓存断点),且长输入一次性粘贴缺少思考拆解

Open
#2,503 0 comments 0 reactions 0 assignees View on GitHub
bug
Dominant language
TypeScript
Stars
2.7k
Forks
395
Avg merge
21h 48m
Merged PRs (30d)
776

Description

## 问题描述 / What happened

长 prompt(大工具集 + 长 system 前缀)会话中存在两个相互叠加的效率问题:

1. **prompt 缓存命中率低**:部分路线下缓存持续 miss,每轮请求都全量重读长前缀,延迟与费用明显偏高。期望行为:稳定前缀(tools + system)在会话内应持续命中缓存。
2. **长输入一次性粘贴缺少思考与拆解**:用户把整份需求文档 / 多任务混合的大段文本一次性粘贴进输入框时,原文全量进入单条 user 消息,模型容易囫囵吞枣、遗漏子任务。期望行为:长输入场景下模型应先重述理解、拆解为有序子任务,再逐项执行并核对遗漏。

## 环境 / Environment

- Cindy 版本或 commit / version or commit: main @ 9d41cb29(代码走读结论,与运行版本无关)
- 平台与版本 / platform & OS version: 全平台
- 安装方式 / install method: 源码

## 复现步骤 / Steps to reproduce

**缓存问题**

1. 使用 Codex agent,模型走 XD 网关路线(`responses-anthropic-bridge` 翻译)。
2. 发送请求使入站 body 不带 `prompt_cache_key` 字段。
3. 观察上游收到的 Anthropic 请求:没有任何 `cache_control` 断点,缓存必然 miss。
4. 即使带了断点的路线,断点 TTL 恒为默认 5 分钟;回合间隔超过 5 分钟(长工具执行、用户阅读思考)后整个长前缀全量重写。

**长输入问题**

1. 在输入框一次性粘贴超过折叠阈值(24 行或 4000 字符)的长篇需求文本并发送。
2. 输入框折叠只是 UI 层(`pastePipeline.ts` 的 PastedTextChip),agent 收到全量原文、无任何附加指引。
3. 观察模型行为:是否拆解子任务全凭模型自觉,长输入下常见遗漏。

## 根因分析

### 缓存:断点门控与 TTL 都在桥接层

- `packages/responses-anthropic-bridge/src/translate-request.ts` 的断点门控原为 `options.promptCaching !== false && (Boolean(raw.prompt_cache_key) || options.automaticPromptCaching === true)`。XD 网关路线 `promptCaching=true`、`automaticPromptCaching=false`(`codex-proxy-host.ts`),是否放断点完全取决于 Codex app-server 是否恰好带 `prompt_cache_key`——而该字段桥接后即被丢弃,纯属被借来当开关,行为不可控。
- 全仓没有任何代码使用 `ttl: '1h'`(`types.ts` 的 `CacheControl` 已声明该字段但无人使用)。
- 已排除 prompt 组装层:`packages/maker-core` 的 system 各段均为会话启动一次性快照,无每轮变动的易变内容注入前缀,工具列表会话内顺序稳定。

### 长输入:全链路无任何长输入特殊处理

- 链路:输入框 → `makerChatStore` → IPC → `agent-input-coordinator` → `makerSendTransaction` → 各 agent。送出前的加工只有交接前缀、手机渠道说明、IM 渠道说明等 wire 层 note,**没有**针对长输入的阈值判定、摘要或拆解指引。
- system prompt 中也没有「先理解拆解再执行」的段落(且按仓库规则 §3.1/§4,条件化内容不应进 system 段)。
- plan 模式与 goal 模式均为纯手动触发,无按输入特征自动触发的先例。

## 优化方案

### 缓存(修复已就绪,稍后提 PR)

1. 断点门控只看 provider 级能力开关(`promptCaching === true`),不再依赖入站 `prompt_cache_key`——host 本来就按 provider 判断了上游是否支持缓存。
2. 稳定前缀(tools + system,长 prompt 的主体、逐轮逐字节不变)使用 `ttl: '1h'`,移动的对话尾部保持 5m 默认,兼顾命中寿命与写放大成本。

影响面:仅 Codex 通道经 `responses-anthropic-bridge` 的路线(XD 网关、官方 Anthropic 上游);用户自定义 provider 维持 `promptCaching=false` 不变;订阅直连方向(`anthropic-responses-bridge` 丢弃 `cache_control` 仅靠 `prompt_cache_key`)是另一条链路,不在本次范围内。

### 长输入拆解(实现中,稍后提 PR)

采用 wire 消息 note 方案(与手机客户端说明 `mobileClientPromptNote` 同层同语义):

- 在 `makerSendTransaction.ts`(send 路径)与 `register.ts`(steer 路径)按长度阈值(与输入框折叠口径一致:24 行 / 4000 字符)判定,向 wire payload 前置一段逐字节稳定的固定提示:先重述理解、拆解为有序子任务清单、歧义影响执行方向时先澄清、完成后对照清单确认无遗漏。
- 只进喂给 agent 的内容,不进落库/显示的用户消息原话;不进 system 段,零缓存率影响,绕开 §4 门禁;三 agent(claude-code / codex / pi)天然一致。

曾评估的备选:Ghost `screenUserMessage` rewrite(有 16000 字符上限且串行 LLM 调用增加延迟)、自动进 plan 模式(语义偏移、三 agent 行为差异大)、旁路 LLM 预拆解(额外延迟与费用)。wire note 成本最低、最贴合现有架构,更强的约束可后续叠加。

## 日志与截图 / Logs & screenshots

无(代码走读结论)。可用 `UsageTracker.getCacheStats()` 的 session 级缓存命中桶(`packages/maker-core/src/agents/shared/usage-tracker.ts`)观测修复前后的命中率变化。

Contributor guide

Open the contributing guide

Research direction

Start with packages/responses-anthropic-bridge/src/translate-request.ts and codex-proxy-host.ts to trace prompt-cache breakpoint gating and TTL handling. Then read makerSendTransaction.ts and register.ts for long-input wire notes, using the 24-line/4000-character threshold described in the issue. Check packages/maker-core/src/agents/shared/usage-tracker.ts and confirm cache behavior and agent handling of long inputs match the stated expectations.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
ai, backend-api-design
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.