IntentKit 团队计费前端与 API 实战:Usage 用量页与光标分页实现解析
2026/9/17 3:33:46 网站建设 项目流程

IntentKit 团队计费前端与 API 实战:Usage 用量页与光标分页实现解析

【免费下载链接】intentkitIntentKit is an open-source, self-hosted cloud agent cluster that manages a collaborative team of AI agents for you.项目地址: https://gitcode.com/GitHub_Trending/int/intentkit

本篇技术指南聚焦 IntentKit(开源自托管的 AI Agent 云集群)中「团队计费前端与 API」这一 P2 里程碑(对应任务文档 agent_docs/todo/03-billing-frontend-p2.md),完整讲解已落地的三个核心能力:团队信用余额展示 APIGET /teams/{team_id}/usage、基于光标(cursor)分页的消费历史查询、以及 intentcat 控制台/team/usage用量页面。读者阅读后,将掌握 IntentKit 团队侧计费端点的请求参数与响应结构、底层信用账户(CreditAccount)与信用事件(CreditEvent)的数据模型、光标分页的实现原理,并清晰了解 P2 剩余的待办路线图。

一、任务背景:P2 在整个计费体系中的定位

IntentKit 的计费体系分为多个递进的里程碑。P1(定价计划与 Stripe 集成,见 agent_docs/todo/02-pricing-plans-p1.md)已完成了TeamPlan枚举(NONE/FREE/PRO/MAX)、计划配额分配、月度计划信用发放(issue_all_plan_credits())与计划过期跟踪等数据与调度层能力;P2 则是在此之上的「计费前端与 API」层,目标是让团队用户在控制台中直观地看到自己团队的信用余额与消费流水。

从任务文档看,P2 当前状态为PARTIALLY COMPLETED(部分完成),已完成三件事:

  1. 团队信用余额展示:GET /teams/{team_id}/usageAPI 端点
  2. 团队消费历史:带光标分页的最近事件列表
  3. intentcat 中的用量页面:/team/usage,包含信用条(credit bars)与活动日志(activity log)

剩余部分仍为 TBD:团队充值/充值流程(依赖 P1 的 Stripe)、套餐管理 UI、发票/账单历史、按 Agent 拆分的用量分析仪表盘、事件"加载更多"分页 UI。

二、核心 API:GET /teams/{team_id}/usage

该端点是整个用量页面的数据来源,实现在 app/team/usage.py 中,属于team_usage_router(标签Billing),并被挂载到独立的 Team API 服务上(见 app/team/api.py 与include_router(team_usage_router)的注册逻辑)。

2.1 请求参数

参数类型位置默认值说明
team_idstr路径必填团队 ID
directionDirection 枚举query按资金流向过滤:income/expense
event_typeEventType 枚举query按事件类型过滤(见下方枚举)
cursorstrquery分页游标,上一页返回的next_cursor
limitintquery50每页事件条数,范围ge=1, le=100

参数中的directionevent_type对应 intentkit/models/credit/event.py 中的枚举定义:

  • DirectionINCOME = "income"(收入)、EXPENSE = "expense"(支出)
  • EventTypememorymessagetool_callmediaknowledge_baserecharge(充值)、refund(退款)、adjustment(调整)、refill(免费额度补充)、withdraw(提现)、rewardevent_rewardrecharge_bonusplan_credit(计划信用)

其中plan_credit正是 P1 中每月计划信用发放所产生的事件类型,与上游issue_all_plan_credits()闭环呼应。

2.2 响应结构

端点返回UsageResponse(Pydantic 模型),序列化为 JSON:

{ "account": { "id": "…", "owner_type": "team", "owner_id": "…", "free_quota": 5000, "refill_amount": 5000, "free_credits": 1234.5678, "reward_credits": 0, "credits": 0, "income_at": "2026-09-16T06:00:00.000Z", "expense_at": "2026-09-16T06:30:00.000Z", "last_event_id": "…", "total_income": 5000, "total_expense": 3765.4322 }, "events": [ { "id": "…", "account_id": "…", "event_type": "tool_call", "team_id": "…", "upstream_type": "executor", "upstream_tx_id": "…", "direction": "expense", "total_amount": 12.5, "credit_type": "free", "tool_name": "search_web", "balance_after": 1890.25, "note": "…", "created_at": "2026-09-16T06:25:00.000Z" } ], "next_cursor": "…", "has_more": false }

字段说明:

  • account:团队信用账户(CreditAccount),核心余额字段为free_credits(当日可用免费额度)、reward_credits(奖励积分)、credits(充值积分);代码中还定义了balance属性,即三者之和,见 intentkit/models/credit/account.py。
  • events:按时间倒序的信用事件列表(CreditEvent)。
  • next_cursor:下一页游标(即本页最后一条事件的 ID);has_more标记是否还有更多数据。
  • 所有金额字段统一保留 4 位小数(Decimal("0.0001"),ROUND_HALF_UP 四舍五入),由round_decimal校验器保证,避免浮点误差累积。

2.3 边界行为

端点实现中有两个值得注意的边界处理(见 app/team/usage.py):

  • 若团队账户不存在(CreditAccount.get_in_session抛出IntentKitAPIError),account返回nullevents返回空数组、has_more=falsenext_cursor=null,而不是直接 500 或 404,保证前端拿到稳定的空态结构;
  • 认证使用Depends(verify_team_member),只有团队真实成员才能访问该团队的用量数据,非成员会收到 403NotTeamMember(见 app/team/auth.py)。

三、消费历史与光标分页的实现原理

GET /teams/{team_id}/usage内部委托给list_credit_events_by_team(),实现在 intentkit/core/credit/list_events.py,这是整个分页逻辑的核心。

3.1 数据模型:信用账户与信用事件

分页查询依赖两张表:

  • credit_accounts(intentkit/models/credit/account.py):按(owner_type, owner_id)唯一定位账户,团队账户的owner_typeteam。表中还维护了total_incometotal_free_incometotal_expense等累计统计字段,供用量页顶部的汇总展示直接读取。
  • credit_events(intentkit/models/credit/event.py):记录每笔业务事件,关键列包括directionevent_typetotal_amountbalance_afteragent_idtool_namemodelupstream_type/upstream_tx_id等,并通过(upstream_type, upstream_tx_id)唯一索引保证幂等(check_upstream_tx_id_exists会拒绝重复提交)。

团队在创建信用账户时,其free_quotarefill_amount会自动读取团队当前套餐的PLAN_CONFIGS(见 intentkit/models/credit/account.py 中create_in_sessionTeamPlan的读取逻辑),这正是 P1 与 P2 的衔接点:套餐决定额度,用量页展示额度消耗。

3.2 光标分页算法

list_credit_events_by_team的实现要点:

  1. 先按OwnerType.TEAM + team_id查出团队账户,不存在则返回空结果;
  2. 构造查询:WHERE account_id = 账户ID,按id倒序,LIMIT limit + 1(多取一条用于判断是否还有下一页);
  3. 可选过滤:direction精确匹配、event_type精确匹配、cursor使用id < cursor(因为是倒序,下一页取比游标更小的 ID);
  4. 判断has_more = len(结果) > limit,只返回前limit条;
  5. next_cursor仅在has_more为真时取本页最后一条的 ID,否则为null

这种「ID 即游标」的方案相比OFFSET分页的优势是:不依赖行号偏移,并发写入下也不会出现翻页重复或遗漏,且走主键索引性能稳定。同文件中还有面向用户的list_credit_events(默认direction=EXPENSE、升序、支持created_at时间区间过滤)与面向 Agent 分润的list_fee_events_by_agent,可作为实现其他计费列表的参考。

3.3 上游链路的幂等保证

每条消费事件都带有upstream_typeapi/scheduler/executor/initializer)与upstream_tx_id,并在credit_events表上有唯一索引。这意味着用量页上看到的每条记录都对应一次确凿的上游业务动作(一次工具调用、一条消息、一次计划信用发放等),既可用于对账,也防止重放扣费。这也解释了为什么消费历史能直接作为"活动日志"展示——事件本身已经携带了tool_namemodelnote等业务上下文。

四、前端:intentcat /team/usage 用量页

根据任务文档,/team/usage用量页属于 intentcat(独立的前端控制台项目),不在本仓库的frontend/目录中。该页面已实现两大区块:

  1. 信用条(credit bars):以可视化条形展示free_creditsreward_creditscredits三种余额的占比,数据直接对应UsageResponse.account的余额字段;
  2. 活动日志(activity log):渲染events列表,按时间倒序展示每笔消费/收入,包含事件类型、金额与业务上下文。

从 API 能力反推页面交互设计要点:

  • 首次进入调用无cursor的请求,拿到第一页 50 条;下拉或点击"加载更多"时携带next_cursor继续请求;
  • 页面顶部提供方向与事件类型筛选,对应direction/event_type查询参数;
  • has_more=false时隐藏加载入口,避免无效请求。

五、剩余路线图(TBD)与扩展建议

任务文档明确列出了 P2 尚未完成的部分,这也为后续开发者提供了清晰的实现顺序:

  1. 团队充值/充值流程:依赖 P1 的 Stripe 集成。落地后充值产生的recharge/recharge_bonus事件会自动进入credit_events,无需改动用量 API 即可在活动日志中自然呈现;
  2. 套餐管理 UI:展示当前套餐(NONE/FREE/PRO/MAX)及升级/降级入口,可复用TeamTable.planplan_expires_atnext_credit_issue_at字段(P1 已完成);
  3. 发票 / 账单历史:可基于credit_events中的rechargerefund类型事件聚合生成;
  4. 用量分析仪表盘:按 Agent 拆分(events[].agent_id已就绪)、成本趋势(events[].created_at按时间聚合)所需的数据字段当前都已存在于事件模型中;
  5. 事件"加载更多"分页 UI:后端next_cursor/has_more已完整支持,前端只需补交互。

从实现角度看,TBD 项大多可以复用现有数据基础设施,尤其是统一的credit_events事件流,这让计费相关功能的横向扩展成本大幅降低。

六、快速验证

本地启动 Team API 服务后,可通过如下方式验证用量端点:

# 携带团队成员的 Supabase JWT 访问 curl -H "Authorization: Bearer <JWT>" \ "http://localhost:8000/teams/<team_id>/usage?limit=20" # 带过滤与分页 curl -H "Authorization: Bearer <JWT>" \ "http://localhost:8000/teams/<team_id>/usage?direction=expense&event_type=tool_call&limit=50"

响应中的next_cursor可在下一次请求中作为cursor参数传入以翻页。注意:本地开发模式(config.debug=True)下可先用debugtoken 模拟system用户(见 app/team/auth.py),便于快速调试。

总结

IntentKit 的 P2 里程碑已为团队计费打下坚实的前端与 API 基础:GET /teams/{team_id}/usage用一处端点同时承载了余额展示与光标分页的消费历史,底层有设计严谨的CreditAccount余额模型、带幂等约束的CreditEvent事件流以及 ID 游标分页算法支撑;/team/usage用量页则将其转化为信用条与活动日志两个直观视图。剩余的充值、套餐管理、发票与分析仪表盘虽列为 TBD,但数据层已为其铺好道路,是沿着事件流模型继续扩展的典型增量任务。

【免费下载链接】intentkitIntentKit is an open-source, self-hosted cloud agent cluster that manages a collaborative team of AI agents for you.项目地址: https://gitcode.com/GitHub_Trending/int/intentkit

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询