@dijkspicy/agent-billing
v2.3.0
Published
本地一体化 MaaS 用量看板:托管静态面板、反代用量接口、本地存储会话用量
Readme
agent-billing
查自己的 LLM 网关用量。面板由本地服务托管,opencode 插件负责采集会话级消耗。
它补的是什么缺口
OpenAI、Anthropic 这类平台的用量接口要求管理级 Key,普通推理 Key 查不到自己花了多少。OpenRouter、LiteLLM、new-api 这些网关都把「用自己的 Key 查自己的用量」做成了标配。
这套东西按最小成本把它落地:不额外搭数据库,也不额外搭监控。
快速开始
本地服务
npm i -g @dijkspicy/agent-billing
agent-billing web start打开 http://127.0.0.1:8787。
这条命令做了三件事:托管面板、把用量查询请求反代到你的网关、在本地 SQLite 存会话用量。
网关地址和 Key 一般不用填。默认从 opencode 配置里推,取当前模型对应 provider 的 options.baseURL 和 options.apiKey;配置里没写 Key 就回退到 opencode 的凭据存储 auth.json。想显式指定:
agent-billing config set --gateway <你的网关地址> --key <你的 Key>面板
三页分页监控,围绕你这把 Key(网关消费者身份)组织。常驻层(sticky,每页可见):根对象头部(消费者身份、连通状态、两个数据域的数据截至时间——点时间戳立即拉取,10 秒防抖,无手动刷新按钮)+ 统计周期切换(今日/近24小时/本周/近一周/本月/近一个月,全局作用于 KPI、图表与会话窗口;日历维度按 UTC+8 对齐,滚动维度为近 N 小时/天窗口)+ 分页导航 + 三维度 Credit 额度条(今日/本周/本月用量/限额并列,不随周期切换变化,本月段保留日均累计 pacing 口径;限额配置入口仅在设置抽屉)。
- 概览页
#overview:Credit、总 token、输入(缓存命中拆分)、输出、请求数、缓存命中率、平均 TTFT 带环比(跟随全局周期,环比基准由上游 compare 提供);图卡按维度粒度二选一——小时粒度维度(今日/近24小时)只展示分时图(今日为当日桶、近24小时为滚动 24 桶),日粒度维度(本周/近一周/本月/近一个月)只展示每日趋势(天数=窗口天数)。Credit 估算按日分段计量:当日 token 数 × 当日生效系数 ÷ 百万,系数中途变更自动分段 - 分析页
#analysis:模型分布、供应商分布、可用模型目录;模型明细表可排序、导出 CSV,表格容器内滚动、表头吸顶 - 会话页
#sessions:按顶层任务组织,任务默认收起、点箭头展开(单会话任务也可展开看单节点轨迹),展开区顶部内嵌执行轨迹(agent 泳道 × 时间轴,会话为创建 → 最后活动的区间条,父子派生关系画 spawn 连线,节点点击查看会话详情;已知限制:复活会话——同一 session id 多次工作——渲染为一条连续区间);任务行 token 合计来自服务端聚合,口径为活动归属 + 完整数据——窗口内活动过的任务整任务入选,合计为成员会话完整累计(跨窗口延续的任务会把窗口前的用量带进来,它回答「这个任务总成本」;对账卡按窗口归属口径回答「窗口覆盖率」,两者分工)(面板 token 数字按万/亿缩写显示,悬浮见完整值);对账卡网关权威总量 − 会话上报合计 = 未归属用量(会话数字来自客户端上报,会延迟也会遗漏;网关那个才是权威值;近24小时维度下会话用量按日分桶、无法对齐 24 小时滚动窗口,对账卡展示不支持态)。统计窗口跟随全局周期(六维),切换立即重载
hash 路由:#overview / #analysis / #sessions,刷新与浏览器前进后退保持当前页,直接打开时恢复上次所在分页。后台自动轮询:用量数据 5 分钟一次,会话数据 30 秒一次;标签页切后台暂停,切回立即补拉。浅色、深色、跟随系统三种主题。
面板必须经 agent-billing web start 托管访问;脱离服务直接打开页面文件会显示启动指引。
架构
浏览器面板
│ /v1/usage/* /v1/models /v1/sessions /v1/tasks
▼
本地服务 agent-billing ← 用量类反代出去,会话类落本地 SQLite
│
▼
API 网关(key-auth 校验,注入消费者身份)
▼
用量查询函数(独立部署,源码不在本仓库)
▼
Prometheus(网关访问日志聚合出的用量指标)两个设计点。
用户凭证止于网关。 网关校验通过后注入消费者 ID,函数只拿这个 ID 去过滤指标,用户的 API Key 不进函数。对函数来说,这只是一次普通的网关调用。
函数查数据源不需要凭证。 走云平台内部的服务间授权,没有凭证可以泄露。
当前实现跑在火山引擎上(VeFaaS + APIG + VMP)。换成别的「网关 + 函数 + Prometheus 兼容数据源」也成立。
配置
命令
| 命令 | 作用 |
|---|---|
| agent-billing web start | 启动本地服务并托管面板。可选 --port、--host、--open、--mode、--consumer-header |
| agent-billing config set --gateway <url> --key <key> [--endpoint <url>] | 配置上游网关、Key、插件上报端点 |
| agent-billing config get | 查看配置,Key 脱敏 |
| agent-billing plugin install | 把上报插件装到 ~/.config/opencode/plugins/ |
agent-billing -h 看完整帮助。
环境变量
| 变量 | 作用 |
|---|---|
| AGENT_BILLING_GATEWAY | 上游网关地址,覆盖自动推导 |
| AGENT_BILLING_GATEWAY_API_KEY | 本地服务访问上游用的 Key |
| AGENT_BILLING_ENDPOINT | 插件上报端点,覆盖 config.json 里的 reportEndpoint |
| AGENT_BILLING_REPORT_API_KEY | 插件上报请求带的 Key。本地模式不需要 |
| AGENT_BILLING_MODE | local(默认)或 gateway |
| AGENT_BILLING_CONSUMER_HEADER | 指定消费者身份头名。设了就只认这个头,取不到直接 401 |
| AGENT_BILLING_CONFIG_DIR | 覆盖配置目录 |
| AGENT_BILLING_DATA_DIR | 覆盖数据目录 |
优先级是:本工具配置 > 环境变量 > 从 opencode 配置推导。
数据落在哪
| 路径 | 内容 |
|---|---|
| ~/.config/agent-billing/config.json | 网关地址、Key、插件上报端点 |
| ~/.local/share/agent-billing/monitor.db | 会话用量(SQLite) |
| ~/.local/state/agent-billing/install_id | 本机安装标识 |
install_id 是每台机器一个的 UUID。会话记录按它区分来源,也决定了同一条会话 id 在两台机器上算两行。
从旧版本升级
包名从 @dijkspicy/opencode-stats-reporter 改成 @dijkspicy/agent-billing,命令名、目录名、环境变量都跟着改了,没有旧名回退。如果你在 shell 或服务里设过 SESSION_USAGE_*、OPENCODE_STATS_*、MONITOR_*,需要换成 AGENT_BILLING_*。
第一次运行新命令时,工具会把旧目录一次性复制到新目录。只复制不移动,旧目录留着当备份。monitor.db 用 SQLite 的一致性快照导出,所以旧服务还开着也不会拷到一半的状态。
上报插件的 install_id 也会沿用旧值(新路径没有就先读旧路径),所以改名不会让同一个会话在新库里多出一行。
但迁移只是一瞬间的快照。先停掉旧服务再跑新命令,否则迁移之后旧服务继续写的数据不会跟过来。
opencode 插件
推荐用 opencode 自带的命令装,走 npm,跟着包更新:
opencode plugin @dijkspicy/agent-billing -g离线或想用本地文件,改成 agent-billing plugin install。它会把 plugin/reporter.ts 拷到 ~/.config/opencode/plugins/。
插件零配置。web start 会把实际监听端口写进 config.json 的 reportEndpoint,插件启动时读它;什么都没配时回落到 http://127.0.0.1:8787/v1/session-usage/report。插件初始化会通过 opencode 日志输出生效端点与来源,排查时先看那行。
一个注意点:别用 --pure 启动 opencode,那会禁掉所有外部插件。
目录结构
bin/ CLI 入口
src/
├── server.js HTTP 装配
├── routes/ static(面板托管)/ usage(网关反代)/ sessions(会话与任务)
├── services/ session-store(SQLite)/ session-api
├── lib/ config / paths / proxy / opencode-config / identity / http / migrate
└── cli.js
plugin/
├── index.ts npm 形态插件入口(exports["."] 与 exports["./server"])
├── reporter.ts opencode 上报插件(可独立复制到 ~/.config/opencode/plugins/)
├── reporter.test.ts
└── README.md
public/ 零构建面板(原生 JS + ECharts CDN,经本地服务托管)
├── index.html 面板入口
└── css/ js/ js:config / format / api / charts / poller / header / usage / sessions / app
test/ Node 侧测试
scripts/ 可运行校验脚本用量查询函数是独立部署组件,源码不在本仓库,仓库只保留它的接口契约,见 docs/maas-gateway-api.md。
开发
npm test # Node 侧测试
npm run test:plugin # 插件测试(bun)
npm run e2e:tasks # 任务聚合端到端
npm run e2e:lineage # 会话血缘端到端
npm run check:panel-expand # 面板展开交互要求 Node ≥ 24。用了内置的 node:sqlite,没有外部依赖。
托管部署
本地模式默认只监听 127.0.0.1。要放到网关后面给多个消费者共用:
agent-billing web start --mode gateway这时会话接口要求网关注入的消费者身份(X-Forward-Consumer),取不到就返回 401,每个消费者的数据互相隔离。
三个前提:
- 用量查询函数以 Webserver 模式跑起来并监听
VEFAAS_PORT。源码独立部署,不在本仓库 - API 网关配好路由转发,用量类接口绑 key-auth 和限流。托管模式下会话接口同样走 key-auth
- Prometheus 兼容的数据源里存着带
consumer标签的用量指标
安全约定
仓库里不含也不接受真实凭证,API Key、AK/SK、域名、实例 ID 都不收。方案运行时不依赖凭证配置:用户凭证止于网关,函数到数据源走平台内部授权。
提交前跑一下 gitleaks 之类工具。
