Skip to content

Feat/ai billing jdk17#1079

Open
itkdm wants to merge 34 commits intoYunaiV:master-jdk17from
itkdm:feat/ai-billing-jdk17
Open

Feat/ai billing jdk17#1079
itkdm wants to merge 34 commits intoYunaiV:master-jdk17from
itkdm:feat/ai-billing-jdk17

Conversation

@itkdm
Copy link
Copy Markdown
Contributor

@itkdm itkdm commented Feb 26, 2026

背景

本 PR 完成 AI 模块 token 统计与预算计费主链路建设,目标是保证“可计量、可限额、可追溯、可告警”。

变更范围

  • 模块:yudao-module-ai
  • 主要涉及:Chat / Write / MindMap 的调用日志、预算预扣与结算、预算周期、阈值告警、计费策略、SSE 异常处理
  • 分支:feat/ai-billing

主要改动

  • 新增并完善 AI token 统计与计费相关表结构
  • 完成调用日志能力:
  • Chat 非流式与流式日志埋点
  • Write/MindMap 流式日志埋点
  • 调用日志统计接口与 Excel 导出
  • 完成预算能力:
  • 预算配置 CRUD
  • 预算使用情况查询
  • Redis Lua 原子预扣(用户+租户多维)
  • 预算事件日志、阈值告警、超限拦截记录
  • 预算用量 SQL 原子累加(修复热点并发场景)
  • 计费策略重构:
  • 引入策略模式(默认策略 + 管理器)
  • 支持按模型计费配置快照计算费用
  • 流式稳定性与错误处理增强:
  • SSE 入口对业务异常返回统一事件
  • 取消/异常路径保证预算释放或结算闭环
  • 预算结算安全修复:
  • 修复结算正向补扣穿透限额风险(补扣封顶)
  • 强化 settle 兜底,避免异常时错误反向冲销
  • 预扣估算改进:
  • Chat 侧改为基于真实 Prompt 估算(覆盖附件内容)
  • 对“缺失 usage 时回落预估”增加明确注释说明

兼容性与影响

  • 主要为 AI 模块内部计费/预算链路增强,对外接口语义保持兼容
  • 数据库需要应用本分支新增/调整的 AI 计费相关 SQL 变更

测试与验证

  • yudao-module-ai 全量测试通过:
  • Tests run: 195
  • Failures: 0
  • Errors: 0
  • Skipped: 86
  • 针对关键修复补充了单测

备注

  • 成功请求通常依赖厂商返回 usage 进行精确计费;极少数缺失 usage 的场景按预估费用(预估较高)回落处理(代码中已明确注释)。

itkdm added 30 commits February 26, 2026 22:03
…el_call_log、ai_model_pricing、ai_budget_config、ai_budget_usage、ai_budget_log), 对应 5 个 DO、5 个 Mapper、5 个业务枚举和 3 个 ErrorCode
… price_in_per_1m 等列名 - 流式回调 executeIgnore 改为 execute(tenantId) 修复 tenant_id 丢失 - OpenAiChatOptions 加 streamUsage(true) 修复豆包等模型流式token为0 - 同步修复 H2 测试 DDL 列名
…接口 + DefaultPricingStrategy + AiPricingStrategyManager - AiModelPricingDO新增strategy_type/strategy_config字段 - 修复AiBudgetChecker/AiBudgetUsageController写死MONTHLY导致DAILY配置不生效 - 修复流式接口预算超限时HttpMediaTypeNotAcceptableException - AiCostCalculator标记@deprecated,指向DefaultPricingStrategy  - Redis key格式yyyyMM改为yyyyMMdd,支持DAILY周期  - 新增DefaultPricingStrategyTest + AiPricingStrategyManagerTest
…加方法 - AiBudgetChecker 适配原子累加逻辑 - AiBudgetUsageServiceImpl settle 改为原子累加
…lTest / AiBudgetUsageServiceImplTest 补充原子累加场景 - 新增 AiModelCallLogServiceImplTest / AiBudgetLogServiceImplTest / AiModelPricingServiceImplTest - create_tables.sql 同步更新测试 DDL
…插件,手动加 AND tenant_id 条件 - addUsage 通过 TenantContextHolder.getRequiredTenantId() 传入 tenantId - 单元测试 @beforeeach 设置 TenantContextHolder 匹配 H2 默认值
…ct 移到 insert 之前 - 预算超限抛异常时不会产生未执行的空消息/空任务记录
…务记录 insert 之前,超限时不留脏数据 - createCallLog 中 settle 移到 finally 块,日志写入失败也能结算预扣费 - settle 自身异常时 fallback 到 release,避免 Redis 预扣金额永久占用
- createBudgetConfig/updateBudgetConfig 新增唯一性校验(同租户同用户同周期类型)
- H2 测试 DDL 同步加唯一索引
- 新增 BUDGET_CONFIG_DUPLICATE 错误码
- 原逻辑 MONTHLY 存在但禁用时直接返回 null,跳过 DAILY 检查
- 改为逐个检查 MONTHLY/DAILY 的启用状态,优先返回启用的配置
@itkdm
Copy link
Copy Markdown
Contributor Author

itkdm commented Mar 6, 2026

PR 计费策略说明

之前的 PR 考虑到不同厂商计费策略差异较大,实现复杂度较高,且多数开源项目仅提供粗略或自定义计费方式,因此只实现了一套基础默认计费策略,可覆盖部分厂商。

但像阿里通义千问这类厂商模型,需要单独实现自定义计费策略

当前 PR 的功能设计已具备完整扩展性,完全支持自定义计费策略。如需扩展,可参考开源项目:
LiteLLM
该项目内置了多种国内外厂商的基础价格与特殊计费逻辑。

⚠️ 注意事项:

  • LiteLLM 以国外开发者贡献为主,默认价格不一定与国内厂商一致
  • 自定义计费策略时,需额外核对国内厂商官方定价,避免误差

@itkdm
Copy link
Copy Markdown
Contributor Author

itkdm commented Mar 16, 2026

后续可演进方向

1. 账务防重与状态机显式化

背景
当系统需要达到金融级账务审计标准,并且要彻底杜绝极端网络抖动场景下的幂等边界问题时,需要进一步增强账务链路的确定性与可追溯性。

规划
剥离单笔业务与结算之间的强耦合关系,引入显式的计费状态流转机制,并增加独立的结算凭证表作为兜底,提升账务一致性、可审计性与异常恢复能力。


2. 多级存储对账与补偿机制

背景
当系统部署规模进一步扩大后,应用宕机或中间件异常可能导致 Redis(实时视图)与 DB(持久化账本)之间出现微小偏差,而这类问题依赖人工排查的成本较高。

规划
建设周期性的自动化对账链路,并针对异常偏差引入自动补偿机制,降低人工介入成本,提升账务系统稳定性与数据一致性。


3. 租户级预算热点行写优化

背景
当单租户并发调用激增时,底层数据库对同一条 usage(用量)记录的并发更新可能引发较严重的行锁竞争,进而影响整体吞吐与时延表现。

规划
调整现有同步累加模型,引入更适合高并发场景的归集方案,以降低锁争用,提升预算扣减链路的可扩展性。


4. 计费域与业务域的深度解耦

背景
随着未来接入更多 AI 场景(如多模态、Agent、Workflow),若继续由业务层承载预扣、结算等逻辑,会带来较高的重复开发成本和接入复杂度。

规划
抽象统一的 Billing Facade(计费门面)编排层,业务线仅需关注模型调用本身,预扣、结算、补偿等账务闭环逻辑对业务侧透明。


5. 预估精度与精细化运营指标(Observability)

背景
当业务进入商业化运营阶段后,对超扣体验、计费准确率以及整体账务可观测性会提出更高要求。

规划
抽象更精确的 Token 估算器(TokenCountEstimator),并建立全视角的计费监控体系,例如结算失败率、拦截分布、账务偏差率等关键指标埋点,支撑后续精细化运营与问题定位。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant