ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

oh-my-opencode-slim 的运行时缓存监视器(cache-monitor):捕获 Provider 提示词缓存失效与缓读写停滞的线上看门狗

oh-my-opencode-slim 的运行时缓存监视器(cache-monitor):捕获 Provider 提示词缓存失效与缓读写停滞的线上看门狗 人工智能AI AgentAgent 编排AI 技能【免费下载链接】oh-my-opencode-slimLean, fine tuned Opencode multi agent suite · Mix any models · Auto delegate tasks项目地址https://gitcode.com/gh_mirrors/oh/oh-my-opencode-slim点击查看免费下载导读本文深入讲解 oh-my-opencode-slim 插件中负责提示词缓存prompt cache运行时监控的cache-monitor模块它监听 OpenCode 上报的每次请求缓存遥测tokens.cache.read/tokens.cache.write在真实会话中识别三种缓存失效特征会话中途 bust、从头到尾从未命中、cache-read 平台期停滞并输出带上下文数据的警告日志。读完本文你将掌握该模块的三种检测模式与全部阈值参数、事件解析与去重机制、与离线缓存安全测试的分工关系以及如何在测试中注入自定义 logger 验证其行为。为什么需要一个线上缓存看门狗提供方Provider的提示词缓存是精确字节前缀匹配只有当请求渲染后的前缀字节与上次完全一致才能复用已缓存的 token。oh-my-opencode-slim 通过 离线测试、快照测试 与 tripwire 测试 证明插件投射出的载荷是字节稳定的——但离线测试只能证明插件没有破坏前缀无法证明Provider 真的复用了前缀。缓存是否被复用只有 Provider 自己知道。OpenCode 会在 assistant 消息的info.tokens.cache字段中暴露每次请求的缓存遥测read本次请求读取的缓存 token 数与write本次请求写入缓存的 token 数。cache-monitor就是盯着这两个数字的运行时看门狗一旦某个此前一直命中缓存的会话突然在某个大请求上报告cacheRead 0这就是会话中途提示词前缀字节变化的典型特征bust 签名hook 会输出一条醒目的警告。该模块只观察、不干预它从不修改消息或状态遇到任何意外事件形状都fail open放行不报错。完整的四层缓存验证体系CI 连续性测试、确定性载荷验证、实时缓存基准、运行时监控、cache:smoke冒烟见 docs/cache-verification.md。设计与常量三个阈值组模块入口是 src/hooks/cache-monitor/index.ts 中的工厂函数createCacheMonitorHook(options)它返回一个event钩子对象。关键设计决策与阈值常量如下const MIN_INPUT_TOKENS_FOR_WARNING 2048; // 低于此输入规模的小请求一律忽略 const MAX_TRACKED_SESSIONS 256; // 最多同时跟踪的会话数 const MAX_TRACKED_MESSAGES_PER_SESSION 512; // 每个会话最多记录的消息 ID 数 const NEVER_CACHED_STREAK_FOR_WARNING 3; // 从未缓存警告连续规模性零缓存请求数 const NEVER_CACHED_INPUT_TOKENS_FOR_WARNING 100_000; // 从未缓存警告累计未缓存输入 token const PLATEAU_STREAK_FOR_WARNING 4; // 平台期警告连续冻结请求数 const PLATEAU_INPUT_TOKENS_FOR_WARNING 50_000; // 平台期警告期间累计未缓存输入 token对应的 codemap.md 明确了分层职责工厂createCacheMonitorHook(options)返回单一event钩子。它在插件启动时、配置加载之前就创建见下文集成因此能观察到每一个事件且位于初始化 try-block 之外。会话级状态内部维护MapsessionID, SessionCacheState每个会话跟踪已完成请求数、everReportedCache是否曾报告过缓存、最近一次cache.read、warnedSinceLastHit自上次命中后是否已警告过、从未缓存连续计数/累计输入、平台期连续计数/累计输入以及按消息 ID 去重的processedMessageIDs集合。三种检测模式下文逐一展开。小请求忽略输入 2048 token 的请求被忽略——它们低于 Provider 的最小可缓存前缀阈值报告零缓存是合理行为。警告措辞保守所有警告都带对冲表述并指向 docs/cache-verification.md 作为背景说明。事件流从message.updated到警告模块的完整处理流程在 codemap.md 中描述如下message.updated (completed assistant, roleassistant, time.completed set) ↓ parseCompletedAssistantMessage() → { sessionID, messageID, inputTokens, cacheRead, cacheWrite } ↓ observe() (dedup by messageID) ├─ busted? (everReportedCache cacheRead 0 inputTokens ≥ 2048) → warn (once per hit) ├─ never cached? (cacheRead 0 cacheWrite 0 sizeable) │ → extend streak; warn at thresholds ├─ plateau? (cacheRead 0 cacheRead lastCacheRead) │ → extend streak; warn at thresholds (any change resets) └─ cacheRead 0 → re-arm warnedSinceLastHit; update everReportedCache/lastCacheRead session.deleted → drop per-session state事件解析只认已完成的 assistant 消息parseCompletedAssistantMessage严格校验事件形状见 index.ts事件type必须是message.updatedinfo.role必须是assistantsessionID与id必须是字符串只有带time.completed的请求才携带最终 token 统计——message.updated在流式输出过程中也会触发那些没有 completed 时间戳的更新会被跳过流式增量没有最终计数tokens.input、tokens.cache.read、tokens.cache.write必须都是有限数值经asFiniteNumber校验非数值/缺失一律视为不可观察事件整体先经isRecordsrc/utils/guards.ts做安全的 Record 形状判定再逐层取properties.info.time/tokens.cache。去重与状态生命周期observe()首先用processedMessageIDs集合按 messageID 去重——同一个完成事件被投递两次只会统计一次集合达到 512 上限时整体清空重新计数。会话数超过 256 时按 Map 插入顺序淘汰最旧的会话sessions.keys().next().value。session.deleted事件deletedSessionID解析会直接删除对应会话的状态让后续零缓存请求重新视为新会话避免误报。三种检测模式详解模式一会话中途 bust经典前缀变更签名判定条件index.tscompletedRequests 2 everReportedCache cacheRead 0 inputTokens 2048即一个此前命中过缓存的会话在完成第 2 个及以上请求、输入 ≥ 2048 token 时突然报告cacheRead 0。警告每个命中周期只触发一次由warnedSinceLastHit标志控制且一旦后续某个请求cacheRead 0就会重新武装re-arm下次再归零可再次告警。测试 index.test.ts 验证了命中→归零→告警一次→重新命中→再归零→再次告警的完整序列。警告样例消息与附带数据[cache-monitor] possible prompt-cache bust: a session that was hitting the provider cache reported 0 cache-read tokens. A prompt-prefix byte likely changed mid-session — see docs/cache-verification.md.附带数据sessionID、requestNumber、inputTokens、previousCacheRead。模式二从未缓存从头 bust 到第一轮这是 v2.2.5 checkpoint-board 回归事故在线上呈现的样子从第一轮起每次请求都全额重付输入 token而模式一依赖everReportedCache永远无法武装。但 OpenCode 会把 Provider 缺失的缓存遥测合并为 0因此显式零值无法区分前缀每次都在变与该 Provider 根本没有提示词缓存——两者必须同时满足才告警cacheRead 0 cacheWrite 0 inputTokens 2048 连续规模性零缓存请求 且 连续请求数 3 累计未缓存输入 token 100_000只有在这两个阈值都达标时才发出从未命中缓存警告每会话一次neverCachedWarned防重复保证警告只出现在本该省下大量 token的场景措辞也保持对冲。测试 index.test.ts 展示了两个关键行为三次 20k 输入、零缓存的适度会话不告警累计未达 10 万阈值给无缓存 Provider 保留宽容度连续三次 ~146k 输入的会话才告警累计 438k数据字段含consecutiveUncachedRequests: 3与uncachedInputTokens: 438000。值得一提的反例一个 Anthropic 风格的会话首轮cacheWrite: 140000写了缓存后续全为零——由于everReportedCache已因写入而置位它走的是模式一的 bust 路径而非模式二见 index.test.ts。模式三cache-read 平台期issue #874 签名判定条件cache.read冻结在同一个非零值上cacheRead 0 cacheRead lastCacheRead同时规模性未缓存输入持续累积。阈值连续冻结请求数 4 期间累计未缓存输入 token 50_000警告每平台期一次cache.read一旦变化任意方向即重置计数并重新武装。测试验证了冻结期间consecutiveFrozenRequests: 4、frozenCacheRead: 42496以及读值增长到 60416 后新平台期可再次告警index.test.ts。同时两个静默用例很关键小输入冻结不告警Provider 会把 reads 四舍五入到粗糙边界短小的冻结流是正常的index.test.ts读值持续增长不告警read从 17920 每次 1024 递增说明可复用前缀在正常生长index.test.ts。平台期的意义在于即使没有任何请求读到 0可复用前缀也可能停止生长。警告会附带建议考虑backgroundJobs.strategy改为checkpoint-compatible。错误处理与性能边界失败开放fail open每个事件都被try/catch包裹遥测处理绝不能破坏事件管线非数值/缺失的 token 字段视为不可观察直接跳过无 completed 时间戳的事件流式更新跳过任何畸形事件event: null、缺字段、input: NaN都静默通过测试 index.test.ts 专门钉住了这一行为。性能考量纯观察无定时器、无 I/O、无消息修改只在内存中累加计数有界状态每会话状态有上限会话总数 256 上限消息 ID 集合到 512 即清空重来日志写入走 src/utils/logger.ts 的异步串行 write-chain且所有条目经redactSecretsForLog统一脱敏后才落盘默认路径OPENCODE_LOG_DIR或~/.local/share/opencode/log下的oh-my-opencode-slim.sessionId.log保留 7 天。集成在插件主入口中的接线src/index.ts 在插件工厂的最前端创建监视器// Observation-only prompt-cache watchdog; safe to create before config // loads and must see every event, so it sits outside the try block. const cacheMonitor createCacheMonitorHook();随后在event钩子中跳过流式 delta 事件message.part.delta、session.next.text.delta、session.next.reasoning.delta之后把每个事件都路由给它src/index.tsevent: async (input) { if (input.event.type server.instance.disposed) terminalGate?.dispose(); // ... skip stream deltas ... await cacheMonitor.event(input); // ... 其他事件消费者 ... },消费方插件主入口 src/index.ts经钩子桶 src/hooks/index.ts 导出createCacheMonitorHook依赖isRecordsrc/utils/guards.ts做安全形状解析logsrc/utils/logger.ts输出警告CacheMonitorOptions.logger可注入自定义 logger 以便测试捕获警告v2 兼容src/v2/event-adapter.test.ts 验证了 v2 主机的session.usage.updated事件经mapV2EventToV1映射成message.updated后能真实驱动 cache-monitor 触发 bust 警告——这证明监视器在 OpenCode v1/v2 双宿主上都能拿到缓存遥测关系定位它与离线缓存安全测试src/hooks/cache-safety.property.test.ts、src/hooks/cache-payload.snapshot.test.ts、src/cache-safety-tripwire.test.ts互补——离线证明插件不改前缀本模块是只有 Provider 才能确认的线上另一半是 Provider 侧行为的现场安全网docs/cache-verification.md 的 Runtime cache monitoring 一节。警告信息速查表警告前缀触发签名阈值触发频率典型应对possible prompt-cache bust曾命中缓存 规模性请求读 0input ≥ 2048非首请求每个命中周期一次命中后 re-arm排查会话中途前缀字节变化如注入内容漂移never hit the provider cache每轮规模性请求读写均为 0连续 ≥ 3 次且累计 ≥ 100k token每会话一次若 Provider 支持提示词缓存前缀可能在每轮变化否则每轮都在重付全量输入cache-read plateaureads 冻结在同一非零值连续 ≥ 4 次且累计 ≥ 50k token每平台期一次读值变化即重置尝试backgroundJobs.strategy checkpoint-compatible测试验证路径模块行为全部由 index.test.ts 钉住共 12 个用例覆盖bust 告警与 re-arm、从未缓存阈值含适度会话静默、平台期告警与重置、首请求/小请求静默、流式与重复事件去重、多会话独立跟踪与session.deleted清理、畸形事件 fail open。想快速复现监视器行为可注入自定义 loggerconst hook createCacheMonitorHook({ logger: (message, data) warnings.push({ message, data }), });在真实环境中它与 docs/cache-verification.md 描述的bun run cache:smoke实时缓存冒烟配合使用冒烟是一次性脚本化探测给出 SUSPECT/plateau 判定与退出码cache-monitor 则是常驻在真实会话中的持续安全网二者互为补充。赞分享人工智能AI AgentAgent 编排AI 技能【免费下载链接】oh-my-opencode-slimLean, fine tuned Opencode multi agent suite · Mix any models · Auto delegate tasks项目地址https://gitcode.com/gh_mirrors/oh/oh-my-opencode-slim点击查看免费下载相关推荐oh-my-opencode-slim 提示词缓存验证体系实战从字节级前缀稳定性到线上缓存冒烟oh my opencode slim 提示词缓存验证体系实战从字节级前缀稳定性到线上缓存冒烟 提示词缓存prompt cache是 LLM 会话成本与延人工智能AI AgentAgent 编排AI 技能Laravel Debugbar缓存收集器监控缓存命中与失效Laravel Debugbar缓存收集器监控缓存命中与失效 你是否还在为Laravel应用中的缓存问题头疼不知道缓存是否真的生效缓存失效时找不到原因本开发工具后端sing-app-vue-dashboard与其他Vue管理模板对比为什么它是2024年的最佳选择sing app vue dashboard与其他Vue管理模板对比为什么它是2024年的最佳选择 在当今快速发展的Web开发领域Vue.js已经成为构建现上一篇实现95%准确率的手写汉字识别基于CASIA-HWDB1.1的CNN实践指南下一篇Darknet跨平台部署终极指南Windows、Linux、macOS兼容性详解创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表