
AI Agent人工智能大模型AI 应用工具调用本地部署MCP ClientsAgent 记忆【免费下载链接】OperitThe most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent项目地址https://gitcode.com/gh_mirrors/op/Operit点击查看免费下载本篇技术指南基于 Operit 开源仓库中的改造设计文档 3_cache_ratio_and_theme.md完整拆解 Token 统计页面一次展示层去 Provider 依赖 主题色规范化的改造用缓存率cache rate取代缓存写入cache writetoken 的统计展示并让页面所有统计视觉统一由活动主题的 primary/secondary 色族推导。读完本文你将掌握缓存率计算的三重前置条件完全已知约束、Provider 侧 cache-write 数据如何保留为内部计费用途以及基于 Material 3ColorScheme推导确定性调色板的完整实现路径可直接对照源码验证。改造背景为什么缓存写入不该出现在统计页之前的行为Previous Behavior改造前的 Token 统计页存在三个结构性问题生命周期卡片展示 cache-write tokens。缓存写入 token 是高度 Provider 相关的度量——OpenAI 兼容系端点、Anthropic、Gemini 对缓存写入的字段命名与计费语义各不相同把它作为页面级统计口径既不通用也不可比较页面混用 primary、secondary、tertiary、error 与中性 theme roles。Material 3 的ColorScheme中 tertiary/error 等角色在用户自定义主题场景下可能并未被完整生成直接引用会导致视觉失控自定义主题生成只重建 primary 和 secondary 角色。当用户选择了自定义主色后其他主题角色的行为是不确定的页面直接引用这些角色会让图表、进度条、热力图出现不可预期的颜色。改造后的目标Intended Behavior生命周期卡片保留未缓存输入uncached input与缓存读取cache read将缓存写入展示替换为缓存率cache rate缓存率的定义是cache read ÷ total input且仅当两者都完全已知时才计算并展示否则显示占位符--所有统计视觉卡片、图表、热力图、徽章、对话框等只从活动主题的 primary/secondary 色族及其容器色、匹配内容色推导明暗主题各自成立。改造在整个 token_stats_success_only_20260816 系列中处于第 3 步前置步骤是只记录成功的正式推理请求与移除调用类型/状态分类过滤本文聚焦其缓存率口径与主题色标准化两大部分。核心改造一缓存率Cache Rate替换缓存写入展示缓存率的语义定义与完全已知约束缓存率的计算不是简单的除法而是一个强约束条件下的确定性公式。在 TokenStatsQueryModels.kt 中缓存率被实现为TokenStatsTotals的扩展属性internal val TokenStatsTotals.cacheRate: Double? get() { if ( !cachedInput.isFullyKnown || !totalInput.isFullyKnown || totalInput.knownSum 0L || cachedInput.knownSum !in 0L..totalInput.knownSum ) { return null } return cachedInput.knownSum.toDouble() / totalInput.knownSum.toDouble() }可以看到缓存率返回null而非错误的伪值需同时满足四个条件条件含义不满足时cachedInput.isFullyKnown缓存读取分量的聚合中没有任何未知事件unknownEventCount 0见TokenStatsTokenAggregate返回 null → 展示--totalInput.isFullyKnown总输入分量同样完全已知返回 null → 展示--totalInput.knownSum 0分母必须为正避免除零返回 null → 展示--cachedInput.knownSum in 0..totalInput.knownSum缓存读取不可能超过总输入防止上游脏数据产生 100% 的非法比率返回 null → 展示--这一设计的本质是**宁可展示未知也不展示可能误导的数值**只有数据链路上每个事件都携带了真实的缓存与总量拆分时缓存率才是一个可信的产品指标。UI 层的呈现缓存率进入 2×2 核心指标格在页面骨架 TokenUsageStatisticsScreen.kt 中缓存率被格式化为百分数后传入指标网格cacheRate range?.summary?.cacheRate?.let { String.format(Locale.getDefault(), %.1f%%, it * 100.0) } ?: –,当cacheRate为 null 时即上述任一条件不满足展示占位符–文档约定为--的等价呈现页面空值统一使用–否则按一位小数百分比格式化如42.3%。承载它的组件是 TokenStatsComponents.kt 中的TokenStatsMetricGrid——2×2 核心指标的固定顺序为峰值 Token / 总请求、缓存率 / 输出其中缓存率卡片使用Icons.Outlined.PieChart图标与token_stats_cache_rate缓存率文案见 strings.xmlTokenStatsMetricCard( icon Icons.Outlined.PieChart, label stringResource(R.string.token_stats_cache_rate), value cacheRate, modifier Modifier.weight(1f), )Cache-Write 数据保留仅供 Provider 计费内部使用文档强调Leave cache-write measurements and pricing internal where required for provider billing; remove only obsolete statistics display behavior.也就是说缓存写入 token 并非被删除而是从页面展示降级为计费内部数据。在数据契约 ProviderUsageSnapshot.kt 中ProviderUsageSnapshot仍然完整保留cacheWriteTokens字段并额外携带计费语义标志data class ProviderUsageSnapshot( val uncachedInputTokens: Long? null, val cachedInputTokens: Long? null, val cacheWriteTokens: Long? null, val totalInputTokens: Long? null, val outputTokens: Long? null, val reasoningTokens: Long? null, val reasoningIncludedInOutput: Boolean? null, val cacheWriteSeparateBilling: Boolean true, ... )cacheWriteSeparateBilling的语义值得展开true默认保守取值Provider 把缓存写入作为独立计费分量该分量未知则费用未知——典型如Anthropic其cache_creation_input_tokens独立计费false无独立缓存写入计费概念OpenAI 兼容系、Gemini、本地模型、ToolPkg缓存写入成本已包含在输入单价内字段缺失不阻碍费用计算。在定价编辑侧缓存写入单价依然存在于PriceSettingsDialog的输入项TokenStatsDialogs.kt 中cacheWritePrice随 input/cachedInput/output 一同参与校验与保存印证了保留计费用途、移除展示用途的分层设计。Provider 归一化null 是未知0 是确认无缓存率完全已知的前提依赖于 Provider 适配层把原始 usage 精确归一化为ProviderUsageSnapshot。核心语义见 ProviderUsageSnapshot.kt 的ProviderUsageNormalizernull 字段 未知Provider 未提供0 Provider 确认该分量为 0。任何字段都不得静默把未知当作 0各 Provider 的拆分规则OpenAI 兼容系chat/completions 与 Responsesprompt_tokens/input_tokens已含缓存命中cachedInputTokens取自prompt_tokens_details.cached_tokensuncachedInputTokens为差值当 cached 拆分未知时绝不把总输入确定为 uncached分类确定性cacheWriteSeparateBilling falseAnthropicinput_tokens不含cache_read_input_tokens与cache_creation_input_tokens总量 三者之和三个分量各自独立保留总输入仅在三个分量全部已知时才确定cacheWriteSeparateBilling trueGeminipromptTokenCount含缓存命中cachedContentTokenCount缺失时不得确定 uncached无独立缓存写入计费本地模型llama/MNN无 Provider usage 对象token 为本地实测计数缓存分量明确为 0ToolPkginput视为总量含缓存命中uncached 为差值缺省字段 未知绝不继承全局累计计数。正因为未知与 0 严格区分聚合层的isFullyKnown判定unknownEventCount 0L才具有可信度缓存率公式中的完全已知约束也因此成立——这是整个缓存率特性的数据底座。核心改造二主题色标准化——TokenStatsColorsProvider旧问题的根源文档指出的第三类问题是页面混用 primary、secondary、tertiary、error 与中性角色而自定义主题生成只重建 primary 和 secondary。直接引用 tertiary/error 会导致用户切主题后这些角色要么沿用默认值、要么被错误映射图表、选中态、提示色与主视觉脱节。新方案单一权威调色板全部由 primary/secondary 推导改造后的核心是 TokenStatsColors.kt 中定义的TokenStatsColors数据类——一个不含任何硬编码色值的完整统计调色板其每个字段都从MaterialTheme.colorScheme的确定性映射推导而来字段分组字段来源映射说明页面层pageBackground/pageContent/pageSupportingContent/pageAccentbackground/onBackground/onSurfaceVariant/visibleAccent(primary, background, onBackground)应用标准背景主色仅作强调一级卡片cardContainer/cardContent/cardSupportingContent/cardWeakContent/cardBorder/cardAccentsurfaceContainer归一化 alpha1/onSurface/onSurfaceVariant/onSurfaceVariant 0.72α/outlineVariant/visibleAccent(primary, cardContainer, onSurface)页面容器走中性 surface 阶梯用户自选主色不浸染容器二级容器innerContainersurfaceContainerHighalpha1图标底座 / tooltip / 徽章 / 未选中分段分段选中selectedSegmentContainerprimary 0.30α主色低透明度叠于卡片避免大面积实心主色图表chartGrid/chartLabel/chartAccent/chartAreaFillBaseoutlineVariant/onSurfaceVariant/cardAccent/cardAccent 0.28α折线、柱形、面积图统一取色热力图heatmapInactive/heatmapLevelsonSurface 0.10α/ 主色五档透明度0.16 / 0.34 / 0.54 / 0.76 / 1.0level 0 未激活灰格1..5 主色透明度阶多模型modelPalette主色 / 次色交替变体共 6 项模型序列确定性配色保证可区分Token 构成componentColors主色三档透明度0.42 / 0.68 / 1.0未缓存 / 缓存 / 输出堆叠分量未知提示unknownHintonSurfaceVariant未知数据提示色其中图表系列采用TokenStatsChartStyletokenStatsChartStyle()组合函数聚合 container/content/accent/grid/label/tooltip 六件套折线图与堆叠条形图统一复用。对比度兜底visibleAccent 保证任意主题可读由于用户自定义主色可能是任意色值文档源码注释明确示例稿中的橙色仅为示例直接使用scheme.primary作强调色可能与卡片容器对比不足。为此实现了 visibleAccent 对比度校验private fun visibleAccent(preferred: Color, container: Color, content: Color): Color { val opaquePreferred preferred.copy(alpha 1f) return if (contrastRatio(opaquePreferred, container) 3f) opaquePreferred else content } private fun contrastRatio(first: Color, second: Color): Float { val lighter maxOf(first.luminance(), second.luminance()) val darker minOf(first.luminance(), second.luminance()) return (lighter 0.05f) / (darker 0.05f) }规则主色与容器对比度≥ 3:1WCAG 大文本/图形的最低标准时采用主色否则回退到内容色保证关键数字在极端自定义主题下依然可读——这是任意用户主题成立的算法保证。注入机制与消费方式调色板通过CompositionLocal注入TokenStatsColorsProvider 保留应用的完整ColorScheme但用CompositionLocalProvider(LocalTokenStatsColors provides colors)覆盖统计页内部的所有取色页面骨架 TokenUsageStatisticsScreen.kt 在最外层包一层TokenStatsColorsProvider内部所有组件通过LocalTokenStatsColors.current取色例如热力图色阶palette.heatmapInactive与palette.heatmapLevels[(level-1).coerceIn(...)]TokenActivitySection.kt活跃记录序列图chartAccent / chartGrid / chartLabel驱动 Canvas 绘制TokenActivitySection.ktToken 构成堆叠条形图componentColors[0..2]对应未缓存/缓存/输出三分量TokenUsageStatisticsScreen.kt趋势卡指标切换的分段控件selectedSegmentContainer与innerContainer区分选中/未选中TokenUsageStatisticsScreen.kt。由于所有颜色均源自活动主题的 primary/secondary 及其表面层级明暗主题天然各自成立tertiary 与 error 角色不再出现在统计页的视觉路径上。改造清单与完成状态原文档的 Work 清单逐项对应如下落地结果Completion 状态为 [DONE]仓库代码已可验证缓存写入度量与定价保留在 Provider 计费内部ProviderUsageSnapshot.cacheWriteTokens与cacheWriteSeparateBilling契约不变定价编辑支持缓存写入单价——仅移除页面展示行为tertiary / error 页面强调替换为标准化本地调色板TokenStatsColors全部字段映射自 primary/secondary/中性表面统计页不再引用 tertiary/error 角色图表与模型序列使用确定性 primary/secondary 家族变体modelPalette6 项交替变体、heatmapLevels5 档透明度、componentColors3 档均由推导生成无字面量色值。生命周期卡片最终形态保留未缓存输入与缓存读取两项数值对应字符串token_stats_token_uncached/token_stats_token_cached新增缓存率指标token_stats_cache_rate缓存写入 token 仅存在于内部统计记账与计费链路。相关源码索引缓存率计算 TokenStatsQueryModels.kt页面指标格式化与 2×2 网格 TokenUsageStatisticsScreen.kt、TokenStatsComponents.ktProvider usage 归一化契约 ProviderUsageSnapshot.kt主题调色板推导与注入 TokenStatsColors.kt图表实现 TokenStatsCharts.kt系列设计文档 token_stats_success_only_20260816/index.md适用前提说明以上实现以当前仓库代码为准缓存率的完全已知语义依赖 Provider 适配层对未知与 0的严格区分若要复现该改造需同时具备 v20→v21 统计记账 schema 的多 Provider 归一化能力以及基于 Material 3ColorScheme的主题推导链路。赞分享AI Agent人工智能大模型AI 应用工具调用本地部署MCP ClientsAgent 记忆【免费下载链接】OperitThe most powerful AI agent and AI chat software on Android/Operit是一款Android上能力最为强大、发展最久的AI Agent项目地址https://gitcode.com/gh_mirrors/op/Operit点击查看免费下载相关推荐Twig cache-extra 扩展实战用 {% cache %} 标签缓存模板片段Twig cache extra 扩展实战用 {% cache %} 标签缓存模板片段 本指南以 Twig 官方 twig/cache extra 扩展包为核后端终极指南解决Feign缓存一致性难题的Cache-Aside与Write-Through实战方案终极指南解决Feign缓存一致性难题的Cache Aside与Write Through实战方案 Feign作为一款让Java HTTP客户端编写更简单的工具后端API设计Twig cache 标签实战指南使用 twig/cache-extra 缓存模板片段Twig cache 标签实战指南使用 twig/cache extra 缓存模板片段 导读 本文以 Twig 官方文档 doc/tags/cache.rst后端上一篇AL语言扩展与Docker集成使用容器化环境进行开发测试下一篇ComfyUI-AnimateDiff-Evolved采样设置详解自定义噪声调度与迭代优化创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考