
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点击查看免费下载本文围绕 OperitAndroid 上的 AI Agent 应用中Token 统计模块的一次未发布功能重构展开它把记账范围收敛为仅记录带真实用量确认的成功正式推理请求同步删除调用类别与结果状态两类过滤用缓存率替换缓存写入展示并将整页主题收敛到主色/次色两个家族。读完本文你将掌握TokenTrackingAIService的按尝试per-attempt用量快照与终态确认机制、AIService.sendMessage新增的onUsageFinalized回调语义、v20→v21 Room 一次性历史数据迁移的完整 SQL 路径以及一套可落地到任意 Compose 页面的中性页面 主题色卡片配色令牌设计。背景为什么 Token 统计账本需要一次 Success-Only 收敛重构前的 Token 统计账本存在四个结构性问题它们共同导致统计口径失真与维护负担上升记录了不该记的结果失败、取消、超时以及连接测试请求都会被写入账本有些请求甚至在没有 provider 用量usage的情况下就落了一行记录。持久化了产品里已不存在的维度调用类别call category与结果状态result status的分类只服务于已经被产品移除的过滤功能却仍被持久化保存。缓存写入展示不可移植缓存写入cache writeToken 是 provider 特有的计量口径不同厂商的 usage payload 结构不一致跨 provider 的展示数据不具备可比性。主题色越界统计页同时使用 primary、secondary、tertiary、error 与 neutral 多种 Material 3 角色而自定义主题生成只重建主色与次色两个家族导致页面在某些主题下出现配色断层。重构的意图非常明确账本只保留成功、正式推理、且上报了真实用量的请求范围分析range analysis继续保留模型过滤未缓存输入与缓存读取的展示值保留缓存写入展示改为缓存率cache rate页面配色只使用当前生效的主色/次色家族。详细决策记录见 docs/TODO/token_stats_success_only_20260816/index.md四个分步文档分别对应录制收敛、过滤与迁移、缓存率与主题、验证与远程构建。一、只记录成功的正式推理TokenTrackingAIService终态确认机制1.1 旧行为每个终态都落账旧版TokenTrackingAIService会为每一个终态结果创建记录包括失败、取消、超时与连接测试调用它在不可取消non-cancellable的上下文中写入并且可以在没有 provider usage 的情况下创建请求行。这意味着一次被取消的流、一次超时的重试、甚至一次探测连接都会污染统计口径。1.2 新契约AIService.sendMessage的onUsageFinalized新契约要求只有一条完成的正规推理流且至少携带一个 provider 确认过的用量分量才允许落账显式的零值仍是有效用量。探测与测试调用probe / connection-test走旁路完全跳过追踪内部失败尝试在后续尝试成功后被排除。这个契约通过AIService.sendMessage新增的onUsageFinalized: (suspend (attempt: Int?) - Unit)?回调实现——它只在正常完成时被调用并携带最终成功的尝试序号。该接口签名定义在 AIService.kt并在 TokenTrackingAIService.kt 中实现。TokenTrackingAIService的核心实现逻辑文件 TokenTrackingAIService.kt按尝试保存用量快照RequestTracker内部用linkedMapOfInt, ProviderUsageSnapshot()保存每个尝试序号对应的用量onUsage对同一尝试多次上报的增量分量做合并而completeSnapshot完整快照会直接覆盖旧值。只持久化成功尝试finish()只在successfulAttempt对应的快照存在、且快照hasKnownFields()为真时才构造TokenUsageRecordEntity被取消cancelled的请求直接返回null一行不落。取消纪元cancellation epochcancelStreaming()在synchronized(cancellationLock)内递增cancellationEpoch并取消所有活跃请求sendMessage在创建请求时记录当时的 epoch流真正onStarted时若 epoch 已变化则立即取消该请求。这套机制同时覆盖了被追踪与未被追踪recordTokenUsage false的请求解决流创建与流收集之间发生取消的竞态。持久化在不可取消上下文写入走withContext(Dispatchers.IO NonCancellable)即使收集协程被取消已确认的成功记录仍有机会落库插入失败仅记日志不影响主流程。推理 Token 并入输出当 provider 明确把 reasoning 独立于 output 上报时reasoningIncludedInOutput false持久化时用saturatedAdd把reasoningTokens并入outputTokens保证总量与费用口径完整代码注释见 TokenTrackingAIService.kt。1.3RateLimitedAIService注册与取消共用一把锁配套改动在 RateLimitedAIService.kt请求注册与取消共享同一把锁限流等待与并发等待改为轮询取消标志而非无中断阻塞从而让取消能及时穿透限流队列。1.4 协议级终态确认[DONE]/response.completed/finish_reason/message_stop这是只记成功在数据流层面的关键保障裸 EOFbare EOF不再被视为正常结束而被当作可重试的网络中断抛出只有协议明确宣告完成才算成功。各 provider 的确认信号在源码中可逐一验证Provider终态确认信号源码位置OpenAIchat/completions 与 responses 统一收口[DONE]标记response.completed非空finish_reasonOpenAIProvider.kt、OpenAIProvider.ktAnthropic Claude非空finish_reasonmessage_stop事件ClaudeProvider.kt、ClaudeProvider.ktGemini[DONE]标记Gemini 终态finishReason白名单GeminiProvider.kt、GeminiProvider.kt此外还有两条重要的边界规则GeminipromptFeedback拒绝rejection直接失败、不重试、永不进入终态确认——被安全策略拦截的请求不会留下成功痕迹。探测与连接测试路由保持recordTokenUsage false从请求边界就绕开追踪器同时不再保留任何持久的调用类型概念。1.5 JVM 测试覆盖测试集中在 app/src/test/java/com/ai/assistance/operit/api/chat/llmprovider 下覆盖终态确认terminal confirmation、裸 EOF、未指定 finish reason、prompt feedback、JSONL 兼容性、冷流取消cold-stream cancellation。其中 ColdStreamCancellationTest.kt 验证了流尚未开始收集时即被取消的竞态路径——这正是取消纪元机制要解决的核心场景。二、删除类别/状态过滤保留一次性历史导入2.1 旧行为与目标旧版范围查询接受模型model、调用类别call-category、结果状态result-status三个过滤维度v20→v21 迁移会把聊天记录复制进账本仓库初始化时会导入遗留累计总量。目标则是范围分析只保留模型过滤账本只记录直接、正式的推理事实历史数据通过一次性升级导入保留。2.2 删除面贯穿全栈的清理本次删除不是 UI 层面的局部清理而是贯穿整个数据栈的全链路删除类别与状态类型type、UI 控件、字符串资源、查询参数、SQL 子句、分组统计查询breakdown queries、实体列与索引一并移除。验证清单里点名了四个被彻底移除、且已无任何剩余引用的符号见 4_verification.mdTokenStatCategory调用类别TokenStatStatus结果状态TokenUsageIdentity用量身份ReleasedProviderModelKeyDecoder已发布 provider 模型键解码器从当前仓库看TokenStatCategory/TokenStatStatus/TokenUsageIdentity已确实不存在任何源码引用ReleasedProviderModelKeyDecoder仅剩其独立的解码器实现与其测试 ReleasedProviderModelKeyDecoderTest.kt——它服务于已发布模型键的解析与已删除的过滤器链条解耦。2.3 保留面一次性升级导入与计价存储与删除并列的是两个刻意保留的一升级路径历史聊天复制v20→v21 迁移在 AppDatabase.kt 的MIGRATION_20_21中用两条INSERT ... SELECT把messagessender ai且带 Token 字段与message_variants中的 Token 承载记录导入新表token_usage_records。uncachedInputTokens用MAX(inputTokens - cachedInputTokens, 0)推导requestCount固定为 1并带importKey唯一索引防止重复导入。删除这段迁移会直接导致用户在升级时丢失可见的统计历史。遗留累计总量导入仓库初始化在 TokenUsageRepository.kt 的ensureInitialized()中通过ApiPreferences.readTokenStatsMigrationSnapshot()读取遗留快照把累计总量以importKey legacy-cumulative:{provider}:{model}的标记行写入时间戳为 NULL 的累计行不落入带日期分桶的趋势统计保持口径一致。导入由statsPreferences.importedAtMs()判空控制保证只执行一次完成后调用legacyDataSource.clearMigratedTokenStatsData()清理旧数据源。2.4 计价pricing的保留与迁移正常的请求成本计算仍然需要计价设置因此计价存储整体保留。具体决策见 2_remove_filters_and_legacy.md已发布的api_settings自定义价格含按请求计价pricePerRequest、缓存写入计价cacheWritePricePerMillion等字段与遗留usd_to_cny_exchange_rate汇率在 Room 导入完成后一次性迁移进新的token_stats_models表与 Token 统计偏好TokenStatsPreferences。TokenStatsPreferences.completeMigration(importedAtMs, releasedUsdToCnyRate)是这次迁移的落点见 TokenStatsPreferences.kt。v20→v21 的token_stats_models表结构即configId provider model 主键 各分项单价见 AppDatabase.kt与 UI 的配置详情/统计设置联动。2.5 关键决策不再引入新的数据库版本迁移由于 v20→v21 的 Token 统计 schema 尚未发布本次重构直接把它当作最终 schema 就地编辑不新增数据库版本过渡。同理移除独立reasoningTokens字段时也是直接修改未发布的 v21 schema没有产生版本号跳动详见下文Token 组成精简。三、缓存率替代缓存写入展示主题收敛到主/次色家族3.1 生命周期卡保留未缓存输入与缓存读取展示缓存率生命周期lifetime卡片的展示规则调整为保留未缓存输入uncached input、缓存读取cache read的展示值移除展示缓存写入cache writeToken——它是 provider 特有的计量只保留为计费内部使用新增缓存率cache rate定义为缓存读取 / 总输入。缓存率的计算规则有一个关键边界只有当两个值都完全已知fully known时才计算否则显示--。其实现位于 TokenStatsQueryModels.ktinternal 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() }注意cachedInput.knownSum !in 0L..totalInput.knownSum这个护栏缓存读取不可能超过总输入越界数据直接判为无效并回退到--避免脏数据产生离谱的缓存率。范围分析range analysis里峰值 Token / 总请求、缓存率 / 输出的 2×2 指标网格直接消费该cacheRate见 TokenUsageStatisticsScreen.kt 与 TokenStatsComponents.kt。3.2TokenStatsColorsProvider全部统计表面角色从主/次色家族推导主题工作的核心产物是TokenStatsColorsProvider文件 TokenStatsColors.kt。它让每一个统计表面角色都从当前生效的主色primary与次色secondary家族推导包括卡片card、内层容器innerContainer图标底座/tooltip/徽章、分段选中底selectedSegmentContainer图表网格、标签、强调色、面积填充基色chartGrid / chartLabel / chartAccent / chartAreaFillBase热力图 0..5 级透明度阶梯heatmapLevelslevel 0 为未激活灰格1..5 为cardAccent的 0.16/0.34/0.54/0.76/1.0 透明度阶多模型调色板modelPalette主色/次色透明度交替共 6 色Token 堆叠分量componentColors未缓存/缓存/输出三段明暗主题各自取对应层级无任何硬编码色值。源码注释明确记录了设计规范TokenStatsColors.kt页面与全部卡片走应用中性 surface 阶梯surfaceContainer / surfaceContainerHigh用户自选主色不浸染容器主色只出现在关键数字、图表线条柱形、进度条、选中态与图标上。3.3 主题演进史五次迭代的关键教训主题收敛并不是一步到位文档记录了从全页面单一色到中性页面 彩色卡片的五次演进每一步都对应一次远程构建验证第一版surface 层级压平把surfaceVariant/surfaceContainerHigh/Highest压平成primaryContainer后chip、日历、下拉框与页面背景之间失去分层。修复0416adba变体与高容器角色回到次色家族页面背景改为primaryContainer向primary偏移 6% 的pageBackgroundOutlinedTextField改用显式tokenStatsTextFieldColors()。中性页面 彩色卡片045933b2页面背景改回应用标准background/onBackground作用域主题不再覆盖任何中性 surface 角色只有卡片承载颜色——主色卡片把primaryContainer向primary混入 10%次色卡片向secondary混入卡片容器强制不透明内容色基于最终容器反算保证极端自定义/动态主题下文字依然可读卡片强调色在对比不足时回退到卡片内容色页面强调色则对照页面背景检查。中性 强调卡片分层设计规范版只有数据卡片承载主题色工具性表面回归应用中性色阶。TokenStatsColors新增中性卡片集surfaceContainerHigh强制不透明容器 onSurface/onSurfaceVariant内容 主色强调过滤器栏、配置详情、费率设置、空/无数据卡片使用TokenStatsNeutralCard趋势图卡片成本/请求/Token全部走主色家族useCardColors参数整体移除该 UI 版本未发布无需兼容垫片。整体 IA 重建2026-08-18 设计规范整页按设计稿重建——中性 surface 阶梯贯穿全页卡片 surfaceContainer 1dpoutlineVariant描边图标底座/tooltip/徽章 surfaceContainerHigh不再有整卡被主/次色填充主色只出现在关键数字、图表线条/柱形、进度填充、选中分段、图标与着色操作按钮上。新页面顺序为时间控制行日/周/累计分段 日期范围 日历→ 周期概览卡大号 Token 数、费用、连续徽章、渐变面积图→ 2×2 指标网格峰值/请求/缓存率/输出→ 活动记录连续徽章 星期标签列 5 级主色热力图→ Token 组成3 条进度条→ 模型排行列表徽章 分享条饼图删除→ 范围分析过滤卡 → 趋势分析卡成本折线 / 请求折线 / Token 堆叠柱 三张等宽迷你图→ 配置详情 → 统计设置币种行 费率行 着色保存按钮。被删除的整块内容包括四个蓝/紫迷你统计卡、生命周期大表、模型饼图、三张全宽堆叠趋势卡、所有按卡配色的 chip/文本框/按钮辅助函数、全部彩色对话框DatePicker 与价格对话框回归 M3 默认。数据源、过滤、日期选择、价格编辑与保存逻辑不变范围指标仍从同一批聚合推导峰值 活动日最大缓存率 缓存/总输入。新增中英文案周期概览、Token 组成、活动标题、连续徽章并补齐此前缺失的英文展开/收起全部。定向 UI 与统计修复日热力图改为周一开头网格 更宽星期标签列 更大单元格月行/网格/点击详情/由少到多图例各占独立纵向行避免重叠月份文本约束到可见画布拖拽检测拒绝间隙与越界点周/累计视图使用图表专属点击提示趋势分析为成本/请求/Token 各配独立圆角迷你面板选中日期详情内嵌于各面板。主题演进记录详见 4_verification.md 的 Follow-up 各节。四、Token 组成精简与模型排行联动在定向修复阶段还有两项直接影响统计口径的改动Token 组成只保留三段缓存读取、未缓存输入、输出独立的reasoningTokens字段从实体、Room DAO 投影、聚合、查询模型及未发布的 v21 schema 中直接移除无版本跳动、无迁移。Provider 的 reasoning 只作为瞬态存在单独计费的推理量在持久化时并入输出见 1.2 节的saturatedAdd保证费用口径完整。模型排行反映当前范围与活跃过滤模型过滤的 provider 身份跨范围切换保留复选框点击在菜单关闭前只处理一次排行数据随范围与过滤实时联动。五、验证策略与远程构建工作流本次重构遵循不在本地跑编译、构建或测试的分工提交完成后直接在 GitHub Actions 派发 Android 构建assembleDebug。验证流程见 4_verification.md静态检查审查最终 diff确认TokenStatCategory/TokenStatStatus/TokenUsageIdentity/ReleasedProviderModelKeyDecoder无残留引用。Agent 复查对取消cancellation、流终态stream-terminal、Room v21、配色方案palette四处改动逐项复查发现问题修复后重新验证。空白校验仅做git diff --check只出现 CRLF 警告。提交推送9593b12bcommit message 为fix(stats): record only successful inference with confirmed usage分支为fix/token-statistics。远程构建派发assembleDebug首轮约 21 分钟完成后续五次主题迭代均以远程构建运行验证通过。本地构建策略在文档末尾被明确固化除非显式要求否则不运行任何本地编译/构建/测试命令——这保证了验证结果的可复现性与 CI 一致性。六、落地要点与经验总结把这次重构沉淀为可复用的工程经验只记成功需要协议级配合仅靠上层判断success标志是不够的必须把终态确认下沉到每个 provider 的流式解析层[DONE]/response.completed/finish_reason/message_stop并让裸 EOF 走重试而非落账才能保证账本真实。删除历史维度时迁移数据比迁移 schema 更敏感类别/状态过滤可以整链删除但历史聊天与累计总量必须保留一次性导入路径否则用户可见统计在升级瞬间消失——importKey唯一索引 importedAtMs()判空是幂等导入的标准姿势。展示与计费解耦provider 特有的计量缓存写入可以继续内部计费但不再上屏跨 provider 可比的派生指标缓存率用完全已知才计算否则--的规则保证口径严谨。主题收敛要防止压平把多个 surface 角色压成一个角色会抹掉层叠关系正确做法是中性页面 彩色卡片用不透明容器 内容色反算 对比度回退保证任意自定义主题下可读。未发布 schema 直接就地编辑v20→v21 未发布所有后续结构调整含移除reasoningTokens都不再引入新的版本迁移显著降低升级风险面。以上改动全部可在当前仓库对应源码中交叉验证录制层 TokenTrackingAIService.kt、迁移层 AppDatabase.kt 与 TokenUsageRepository.kt、统计层 TokenStatsQueryModels.kt、主题层 TokenStatsColors.kt以及测试 ColdStreamCancellationTest.kt。赞分享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点击查看免费下载相关推荐机器学习概念总记不住斯坦福CS 229速查手册帮你省一半复习时间机器学习概念总记不住斯坦福CS 229速查手册帮你省一半复习时间 不知道你有没有过这种经历白天刚看完线性回归的推导晚上合上书满脑子只剩好像学过四个字云原生IaC容器编排集群管理BewlyBewly 暗色模式与主题色适配Adapted Styles 目录结构与 SCSS 编写规范实战指南BewlyBewly 暗色模式与主题色适配Adapted Styles 目录结构与 SCSS 编写规范实战指南 本篇技术指南以 src/styles/adap前端BiSheng 数据库迁移工程规范Alembic 单一 Head 铁律与 DDL-Only 迁移实战指南BiSheng 数据库迁移工程规范Alembic 单一 Head 铁律与 DDL Only 迁移实战指南 导读本文以 BiSheng 开源 LLM DevOAI 应用AI AgentLLMOps工作流自动化RAG后端前端上一篇网易云NCM文件打不开这款免费开源工具一键解锁音乐格式下一篇ThinkPad风扇终极静音指南TPFanCtrl2双风扇控制一文搞定创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考