OpenHuman 账单与用量体系解析:云端计费 RPC 与本地实时成本仪表盘
【免费下载链接】openhumanOpenHuman is an open source personal AI for Mac, Windows and Linux — local-first memory, agent orchestration, and deep research.项目地址: https://gitcode.com/GitHub_Trending/op/openhuman
OpenHuman 将"钱花在哪里"拆成两个相互独立又互补的台账:面向托管后端的Billing(计费),以及完全留在本地的Cost & Usage(成本与用量)。本指南以 billing-and-usage.md 为核心脉络,结合仓库中src/openhuman/hosted/billing与src/openhuman/platform/cost的源码实现,讲解套餐、积分、自动充值、优惠券的 RPC 接入方式,以及按 token 实时核算成本、执行预算封顶、渲染 7 天仪表盘的完整机制。读完你将掌握如何配置[cost]预算块、理解check_budget的强制语义边界、区分云端账单与本地用量的数据流向,并能在源码中定位每一条费用链路。
双台账架构:Billing 与 Cost & Usage 的分工
OpenHuman 刻意维护两套"账本",它们的归属与生命周期完全不同:
- Billing(计费):你向托管后端支付的费用——套餐、积分充值、已保存卡片、优惠券,全部经 Stripe 或 Coinbase 结算。它存在于云端。
- Cost & Usage(成本与用量):Agent 替你消费的 token 所折算的美元成本,按每次 provider 调用在本地追踪,让你在账单落地之前就能看到并封顶真实的 token 开销。
一句话概括文档的定位:前者活在云端,后者从不离开你的工作区(workspace)。
在源码中,这两块分别由 src/openhuman/hosted/billing(RPC 适配器)和 src/openhuman/platform/cost/README.md(本地成本追踪模块)承载,下文分两部分深入。
Part 1:Billing 云端计费
薄 RPC 适配器:不含任何支付逻辑
billing域是一个薄 RPC 适配器,本身不持有支付逻辑或状态。从 ops.rs 的模块注释可以确认其安全模型:
- 每个操作都携带通过
auth_store_session保存的 app-session JWT,以Authorization: Bearer …头发送 HTTPS 请求到托管后端(/payments/*、/coupons/*),并把后端的 JSON 响应原样透传给调用方; - 授权、套餐归属与支付策略全部由后端强制执行,本地不复制任何服务端授权逻辑;
- 会话缺失或失效时,直接透传后端的
401/403;get_authed_value通过flatten_authed_error把预期的Unauthorized映射成SESSION_EXPIRED哨兵,让 JSON-RPC 层将其归类为会话过期并跳过 Sentry 上报(见 ops.rs); - JWT 与卡片数据永不写入日志,日志只记录脱敏后的状态码与路径。
在发 HTTP 请求之前,适配器只做轻量输入校验(同样见 ops.rs):
- plan / coupon / payment-method id 必须非空(
trim后判空); amountUsd必须是有限正数(is_finite() && > 0,见top_up_credits);- gateway 白名单仅允许
stripe/coinbase(normalize_gateway,空或纯空白网关会被归一化为 Stripe)。
套餐与定价
三个套餐,各提供月度与年度两种计费周期:
| 套餐 | 月度 | 年度 | 相对按量付费的每调用折扣 |
|---|---|---|---|
| Free | $0 | $0 | 无(按量付费基线) |
| Basic | $19.99 | $199 | 每次调用便宜 50% |
| Pro | $199.99 | $1,799.99 | 每次调用便宜 90% |
文档特别强调:更高套餐并不是解锁更多功能,而是降低相对按量付费基线的"每调用毛利"。所有套餐都"能访问一切"——你购买的是更便宜的推理,而不是被门控的能力。
支付渠道
系统只接入两条网关:
- Stripe:套餐购买(Checkout 会话)、客户账单门户(billing portal)、积分充值、已存卡管理(SetupIntent)与自动充值。
- Coinbase Commerce:加密货币支付,用于积分充值与年度账单。
两个默认值值得注意:top_up_credits默认走stripe网关;create_coinbase_charge的interval默认是annual(源码中unwrap_or("annual"),见 ops.rs)。
积分、充值、自动充值
在订阅之外,你持有一个USD 积分余额。可以:
- 读取余额(
GET /payments/credits/balance); - 分页浏览交易历史(
GET /payments/credits/transactions?limit=&offset=,默认limit=20、offset=0,见 ops.rs); - 通过任一网关充值(
POST /payments/credits/top-up,请求体为{ amountUsd, gateway },其中gateway缺省为"stripe"); - 自动充值(Auto-recharge,仅 Stripe):当余额偏低时从已存卡自动补充积分;可以读取和更新设置(
GET/PATCH /payments/credits/auto-recharge),并列出 / 新增 / 更新 / 删除已存卡(/payments/credits/auto-recharge/cards系列端点)。
添加卡片会创建 Stripe SetupIntent(POST /payments/credits/auto-recharge/cards/setup-intent);删除卡片被视为危险操作。
优惠券
优惠券码向后端兑换:POST /coupons/redeem(请求体{ code },code 必须非空),并可通过GET /coupons/me列出当前账户已兑换的优惠券。对应源码见 ops.rs。
桌面端 Billing 面板与 Agent 工具
桌面端Settings → Billing面板刻意不内嵌支付 UI,而是链接到托管的 Webbilling dashboard——那是管理套餐、卡片与发票的唯一入口。
Agent 可以通过默认开启的只读工具读取账单状态(当前套餐、余额、交易、卡片、优惠券、Stripe 门户链接);所有涉及资金移动或支付方式的写操作则默认关闭,受billing_writes开关控制,且删除卡片被标记为危险操作。这与 settings_agent/agent.toml 中的注释一致:Settings Agent 只继承"会话/凭据/OAuth 读取"等只读账户状态,资金移动与团队管理相关的写工具族不在此列。
RPC 面(15 个方法)
命名空间billing,暴露为openhuman.billing_*。从 schemas.rs 可以列出完整 15 个注册控制器:
| 方法 | 后端端点 | 说明 |
|---|---|---|
billing_get_current_plan | GET /payments/stripe/currentPlan | 当前套餐 |
billing_get_balance | GET /payments/credits/balance | 积分余额 |
billing_purchase_plan | POST /payments/stripe/purchasePlan | 创建套餐购买会话(参数{ plan }) |
billing_create_portal_session | POST /payments/stripe/portal | 客户账单门户会话 |
billing_top_up | POST /payments/credits/top-up | 积分充值({ amountUsd, gateway }) |
billing_create_coinbase_charge | POST /payments/coinbase/charge | 加密支付链接({ plan, interval }) |
billing_get_transactions | GET /payments/credits/transactions | 交易历史(limit/offset) |
billing_get_auto_recharge | GET /payments/credits/auto-recharge | 自动充值设置 |
billing_update_auto_recharge | PATCH /payments/credits/auto-recharge | 更新自动充值设置 |
billing_get_cards | GET /payments/credits/auto-recharge/cards | 已存卡列表 |
billing_create_setup_intent | POST /payments/credits/auto-recharge/cards/setup-intent | 创建 SetupIntent |
billing_update_card | PATCH /payments/credits/auto-recharge/cards/{id} | 更新已存卡 |
billing_delete_card | DELETE /payments/credits/auto-recharge/cards/{id} | 删除已存卡(危险) |
billing_redeem_coupon | POST /coupons/redeem | 兑换优惠券 |
billing_get_coupons | GET /coupons/me | 已兑换优惠券列表 |
Part 2:Cost & Usage 本地成本仪表盘
cost域完全本地化。其核心职责在 platform/cost/README.md 中有完整定义:把每次 provider 调用的 token 用量与折算的美元成本追加写入 append-only JSONL 文件(<workspace>/state/costs.jsonl),在内存中维护日/月聚合,执行预算封顶,并通过 JSON-RPC 提供 7 天仪表盘。Agent 回合循环(每次 provider 调用后记录遥测)与仪表盘处理器共享同一个进程级单例追踪器,因此每次调用恰好持久化一次。
本地 JSONL 存储与进程级单例
- 存储路径:
<workspace>/state/costs.jsonl,每行一条CostRecord,写入采用write + sync_all保证持久性; - 首次
CostTracker::new时会做遗留数据迁移:旧路径<workspace>/.openhuman/costs.db会被改名(失败则回退为复制)到新路径(见 tracker.rs); - 全局单例由
OnceCell<Arc<CostTracker>>承载(global.rs),init_global幂等且初始化失败只记日志、绝不 panic,未初始化的调用方把缺失当作软 no-op; - 存储层同时维护
daily_cost_usd/monthly_cost_usd缓存,在日/月翻卷时通过全文件扫描重建;损坏的行跳过并记warn。
实时 token 与成本追踪
每次调用的成本由 token 数与每百万 token 单价计算得出(TokenUsage::new),非有限或负数的价格被钳制为0.0。判定优先级是:
- 若 provider 回传了权威的
charged_amount_usd,该值直接胜出,记录标记为CostSource::ProviderCharged; - 否则回退到内置静态定价目录(已知模型的每百万 token 价格),记录标记为
CostSource::Estimated。
build_token_usage(global.rs)还包含几个关键细节:
- 全零用量跳过:
input==0 && output==0 && charged==0.0时返回None,不落盘,避免不回报用量的 provider 虚增请求计数; - 缓存输入 token 会被钳制到
input_tokens以内(cached_input_tokens.min(input_tokens)); - 时间统一按UTC分桶(
naive_utc().date()),以 model 为分桶键,provider由provider/model前缀推导; - 会话级
Vec<CostRecord>支撑get_summary的 session 维度汇总。
默认定价目录来自 identity_cost.rs(单位:USD / 1M tokens),模型标识与 types_part_01.rs 中的托管模型注册表对应:
| 模型 tier | 标识 | 输入单价 | 输出单价 |
|---|---|---|---|
| Reasoning | reasoning-v1 | 0.84 | 2.52 |
| Chat | chat-v1 | 0.60 | 2.50 |
| Reasoning Quick | reasoning-quick-v1 | 0.60 | 2.50 |
| Agentic | agentic-v1 | 0.45 | 1.80 |
| Coding | coding-v1 | 0.90 | 3.30 |
| Burst | burst-v1 | 0.208 | 0.208(双向统一价) |
此外还有独立的 embedding 成本记录路径record_embedding_usage:以"<provider>/<model>"(如voyage/voyage-3)为桶键,经catalog::estimate_cost_usd定价;若模型不在定价目录中则以零成本记录并打日志,绝不伪造费率,且该路径非致命、不会中断 embed 或召回回合。
预算与强制([cost]配置块)
预算强制在[cost]配置块下配置:
| 配置项 | 默认值 | 作用 |
|---|---|---|
enabled | true | 只门控强制,不门控遥测采集 |
daily_limit_usd | 10.00 | 硬性每日上限 |
monthly_limit_usd | 100.00 | 硬性每月上限 |
warn_at_percent | 80 | check_budget的告警阈值百分比 |
一个典型的config.toml片段:
[cost] enabled = true daily_limit_usd = 10.0 monthly_limit_usd = 100.0 warn_at_percent = 80 [cost.dashboard] enabled = true currency = "USD" warn_threshold = 0.8 alert_threshold = 0.95check_budget返回三态:Allowed、Warning(达到告警阈值)、Exceeded(超过日或月上限)。源码中的判定顺序(tracker.rs)是:先算projected = 当前花费 + 本次预估,先比日上限、再比月上限、最后比告警阈值(warn_at_percent.min(100) / 100换算成百分比阈值),命中即返回对应状态。
最关键的一个细节:enabled控制的是"强制"而不是"采集"。当enabled = false时:
check_budget直接返回Allowed,硬性上限关闭;- 但 Agent 路径走的是
record_usage_unconditional(无条件记录),costs.jsonl照常增长,只是record_usage(有条件版)变成 no-op(见 tracker.rs)。
这是成本仪表盘 PR 引入的刻意行为变更(global.rs 在初始化时会为升级用户打一条warn日志说明):让用户在开启硬性封顶之前先积累并审查历史花费。要隐藏面板,设dashboard.enabled = false;要清空历史,直接删除 JSONL 文件即可(它完全本地、从不离开工作区)。
另一个容易踩的边界(源码注释 #5016):check_budget只针对managed(OpenHuman 积分)推理累计——自带 key(BYOK)与本地推理由用户自己的 provider 计费,会记录进仪表盘供查看,但不计入预算上限、也永远不会因预算拒绝请求。纯 BYOK 用户的管理支出为零,因此永远无法触发该闸门;仪表盘中的month_to_date_usd虽展示全路由总额,但预算利用率与状态只按 managed 花费计算(tracker.rs),避免出现"对着一个永远不会触发的上限把仪表盘灌到 100%"的幻影限制。
7 天仪表盘(Settings → Usage & Limits)
Settings →Usage & Limits承载成本仪表盘(与后台活动控制同页)。它渲染:
- 7 天每日历史(缺失天零填充,最旧在前,由
get_daily_history的 BTreeMap 分桶保证,见 tracker.rs); - token 用量图表;
- 月度节奏预估(
monthly_pace_usd = 日均值 × 30); - 预算利用率与状态;
- 按模型拆分的成本占比。
仪表盘的配色按月度预算的分数切换:柱子到达warn_threshold(默认0.8)变琥珀色,到达alert_threshold(默认0.95)变红色。budget_utilization显示时被钳制到1.0,但budget_status由未钳制的原始值计算;月上限非正数时状态强制为Normal、利用率为0.0。面板约每 10 秒轮询一次,并显示 "Updated Ns ago" 的新鲜度胶囊。
当全局追踪器尚未初始化(例如启动竞态或构造失败)时,RPC 层通过resolve_tracker构建一个只读回退追踪器(rpc.rs):它与真实追踪器共享同一份 JSONL 文件,按工作区路径缓存,构造错误会在FALLBACK_ERROR_TTL(30 秒)内重放,避免 UI 的 ~10 秒轮询反复锤击一个坏工作区。
RPC 面
命名空间cost,暴露为openhuman.cost_*:
| 方法 | 输入 | 输出 |
|---|---|---|
cost_get_dashboard | 无 | 7 天分桶、汇总指标、预算利用率/状态、按模型拆分 |
cost_get_daily_history | days?(默认 7,钳制在 1~366) | 有序每日条目,最旧在前,缺口零填充 |
cost_get_summary | 无 | 实时 session / 日 / 月成本汇总 |
RPC DTO(CostDashboardDto、DailyCostEntryDto、ModelStatsDto、CostSummaryDto、UsageLogRecordDto,见 rpc.rs)在领域类型之上补充展示字段:provider(由provider/model前缀推导)、percent_of_total,以及来自cost.dashboard的阈值与enabled标志。
这三个方法还作为只读、默认开启的 Agent 工具暴露给 Settings Agent(见 settings_agent/agent.toml),让 Agent 能自查自己的开销。同时cost_get_*工具遵循与账单相同的原则:只读、默认开;任何资金写操作都默认关。
预算门在 Agent 运行时中的落地:OpenHumanBudgetGate
预算检查并非只服务于仪表盘展示——它直接参与 Agent 运行时的准入控制。budget_gate.rs 将 OpenHuman 的三个计量关注点汇聚到统一的BudgetGatetrait 上:
- 准入与背压:
scheduler_gate::wait_for_capacity,持有全局单槽 LLM 信号量与 AC 电源 / CPU / 登出策略退避; - 预算拒绝与记账:
CostTracker::check_budget与record_provider_usage,经catalog::estimate_cost_usd定价; - 压缩建议:Agent 的 TokenJuice 配置档决定它能容忍多大程度的有损压缩。
关键行为(都有源码依据):
acquire先查预算、后排队:超预算的调用在拿到全局 LLM 槽位之前就被拒绝(TinyAgentsError::LimitExceeded),避免一个付不起的调用占用本该给可负担调用的槽位;未入目录的模型按0.0估算,"未知"不等于"免费",且零估算只会让check_budget更宽松、不会制造拒绝;- 交互式回合不进入后台调度闸门,只有 cron / 潜意识 tick / 内存 worker 等后台工作通过
as_background_work选择进入; compression_hint用原子变量缓存三态预算压力(PRESSURE_NORMAL/PRESSURE_WARNING/PRESSURE_EXCEEDED),让运行时在回合每轮迭代之间都能廉价读取;上下文利用率只用于升级已由预算触发的软提示(ESCALATE_AT_UTILIZATION = 0.9),绝不单独发起压缩提示;- 压缩提示最终经
cap_hint按 Agent 的 TokenJuice 档位封顶(Off一律返回None,Light把Hard降为Soft),并且提示是"并集"语义——本闸门不请求压缩 ≠ 禁止压缩。
预算读取失败(如 JSONL 损坏)不构成拒绝——坏文件不该让"任何 Agent 都无法运行",因此按"无预算意见"放行并打日志。
成本与 token 压缩:让每一分钱都花得更少
因为成本追踪的是真实 token 数,任何能缩减 prompt 的机制都会直接降低开销:
- TokenJuice token 压缩:减少每次调用发送的 token 数;
- 模型路由:把任务派发给能胜任的最廉价模型。
两者最终都会体现为仪表盘上更低的柱子与更慢的预算消耗——这也是budget_gate在预算吃紧时主动给出压缩提示的原因:预算压力驱动的压缩建议,直接作用于每次调用的 token 成本。
运维实践要点速查
| 场景 | 做法 |
|---|---|
| 只想看历史、暂不封顶 | cost.enabled = false(遥测照常记录) |
| 隐藏仪表盘面板 | cost.dashboard.enabled = false |
| 清空成本历史 | 删除<workspace>/state/costs.jsonl(本地文件,不会外传) |
| 调低告警灵敏度 | 改warn_at_percent(预算检查)与dashboard.warn_threshold/alert_threshold(图表配色,均为月度预算的分数) |
| 排查"没扣钱却超限" | 检查是否误把 BYOK/本地推理计入 managed 预算——check_budget只对 managed 路由生效 |
| 升级后的遗留数据 | 旧.openhuman/costs.db会在首次初始化时自动迁移到新 JSONL 路径 |
参见
- Token 压缩(TokenJuice)
- 模型路由
- 成本追踪模块设计与关键文件
- 计费 RPC 适配器实现
- 成本配置结构体与默认定价目录
【免费下载链接】openhumanOpenHuman is an open source personal AI for Mac, Windows and Linux — local-first memory, agent orchestration, and deep research.项目地址: https://gitcode.com/GitHub_Trending/op/openhuman
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考