使用量跟踪
wippy/usage 模块记录 LLM 令牌消耗,并提供按时间区间、模型或用户分组的聚合查询。它绑定 wippy.llm:usage_tracker 契约,因此任何通过 LLM 模块调用的代码都会自动产生使用量记录。
将模块添加到项目:
wippy add wippy/usagewippy install声明依赖并将 target_db 要求指向用于存放使用量记录的数据库:
version: "1.0"namespace: app
entries: - name: app_db kind: db.sql.sqlite path: ./data/app.db
- name: dep.usage kind: ns.dependency component: wippy/usage version: "*"
- name: target_db kind: registry.entry meta: wippy.usage.target_db: app:app_db当应用启动时,wippy/migration 会运行该模块的 01_create_token_usage_table 迁移,创建 token_usage 表及其在 user_id、context_id、model_id 和 timestamp 上的索引。
token_usage├── usage_id text primary key (uuid v7)├── user_id text not null├── context_id text├── model_id text not null├── prompt_tokens integer├── completion_tokens integer├── thinking_tokens integer default 0├── cache_read_tokens integer default 0├── cache_write_tokens integer default 0├── timestamp timestamp└── meta text (JSON)wippy/llm 在每次生成之前解析 wippy.llm:usage_tracker 契约。wippy/usage 将其实现绑定为默认值:
contracts: - contract: wippy.llm:usage_tracker default: true methods: track_usage: wippy.usage:usage_tracker每次成功的 LLM 调用都会以模型 id、令牌计数和可选的 context_id 调用 track_usage。user_id 取自当前的安全主体;不在用户上下文中的调用会被记录为 "system"。
跟踪器 API
Section titled “跟踪器 API”当你需要在 LLM 流程之外记录使用量时,可直接导入跟踪器:
imports: usage_tracker: wippy.usage:usage_trackerlocal tracker = require("usage_tracker")
local usage_id, err = tracker.track_usage( "openai:gpt-4o", prompt_tokens, completion_tokens, thinking_tokens, cache_read_tokens, cache_write_tokens, { context_id = "chat-42", metadata = { feature = "summary" } })| 参数 | 类型 | 说明 |
|---|---|---|
model_id | string | 规范化的模型 id |
prompt_tokens | number | 输入令牌 |
completion_tokens | number | 输出令牌 |
thinking_tokens | number | 推理令牌(未报告时为 0) |
cache_read_tokens | number | 提示词缓存命中 |
cache_write_tokens | number | 提示词缓存写入 |
options.context_id | string | 自由格式标签;回退到 ctx.get("context_id") |
options.timestamp | number | Unix 时间戳;默认为当前(UTC) |
options.metadata | table | 与记录一同存储的任意 JSON 元数据 |
返回 usage_id 或 nil, err。
仓储 API
Section titled “仓储 API”wippy.usage:token_usage_repo 提供聚合查询:
imports: usage: wippy.usage:token_usage_repolocal usage = require("usage")
local summary = usage.get_summary(start_unix, end_unix)local by_time = usage.get_usage_by_time(start_unix, end_unix, usage.INTERVAL.DAY)local by_model = usage.get_usage_by_model(start_unix, end_unix)local by_user = usage.get_usage_by_user(start_unix, end_unix)| 函数 | 返回值 |
|---|---|
get_summary(start, end) | 范围内的总计:prompt/completion/thinking/cache 令牌、请求数、total_tokens(prompt + completion + thinking) |
get_usage_by_time(start, end, interval) | 分桶数组,每个区间一个;缺失的桶返回零 |
get_usage_by_model(start, end) | 每模型总计,按 total_tokens 降序 |
get_usage_by_user(start, end) | 每用户总计,按 total_tokens 降序 |
create(user_id, model_id, prompt, completion, options) | 由跟踪器使用的低层插入 |
usage.INTERVAL.HOUR -- "hour"usage.INTERVAL.DAY -- "day"usage.INTERVAL.WEEK -- "week"usage.INTERVAL.MONTH -- "month"get_usage_by_time 将分桶对齐到所配置的区间。在 PostgreSQL 上使用 generate_series 配合区间运算;在 SQLite 上使用基于 UNIX 时间戳的递归 CTE。每个桶中的 total_tokens 不包含缓存令牌。
跟踪器和仓储在公共 API 边界都接受 UNIX 时间戳。仓储内部将其转换为 RFC3339 字符串用于存储和查询。传入 os.time() 或 time.now():unix() 值,而不是格式化字符串。
元数据与上下文
Section titled “元数据与上下文”meta 列存储自由格式的 JSON 块。使用它将记录与应用事件相关联:
tracker.track_usage(model_id, prompt, completion, 0, 0, 0, { context_id = "chat-42", metadata = { session_id = "s-7", route = "/api/summarise", agent_id = "writer", },})context_id 是顶级列,可建立索引;metadata 以文本形式存储,旨在用于展示,而非过滤。