通用基础项目
15. 完成统计和消耗机制
会员专享 · 非会员仅可阅读 30% 的正文。
- 发布时间
- August 10, 2025
- 阅读时间
- 2 min read
- 作者
- Felix
- 访问
- 会员专享
这是预览内容
非会员仅可阅读 30% 的正文。
因为我们是做AI应用,就需要对于用户的消耗进行统计,以便限制无限的刷量,而现在市面上有两种最主流对于用户消耗限制的方法:
- 基于Token的计算:
- 这种方法主要用于大语言模型(LLM)API的计费,如OpenAI的GPT系列模型 - Token是文本的基本单位,通常一个单词约为1.3个token,一个汉字约为2个token - 优点:精确反映模型处理的实际计算量,与模型的计算成本直接相关 - 缺点:对于用户来说较难理解,不同语言的token数量差异较大 - 实现方式:通过模型返回的token消耗,累计计费
- 基于次数的计算: - 这种方法以用户的请求次数为基础进行计费 - 优点:简单直观,用户容易理解自己的使用情况 - 缺点:自己在计算成本和消耗的时候会比较困难,并且太透明了 - 实现方式:记录API调用次数,可以按不同功能或模型分别统计
而我比较倾向Token的计算消耗机制,举个例子:你某个功能最开始让用户用5次,但这时候我们发现消耗成本太大了,发现你要削减次数,你一削减次数用户就抱怨。 如果采用Token机制,你可以自己调控消耗倍率,原本是一倍的消耗,如果这时候要提高收益率就可以提升到2倍的消耗,这比较隐形(大多数用户是不会去算的),并且使用Token的机制会更好的统计成本。
完成表结构
非常简单,只需要加一个关联用户消耗的关联表即可,跑一下pnpm db:generate和pnpm db:migrate-local。
// next-cloudflare-template/lib/db/schema.ts
export const userUsage = sqliteTable('userUsage', {
id: text('id')
.primaryKey()
.$defaultFn(() => crypto.randomUUID()),
userId: text('userId')
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
usedTokens: integer('usedTokens').notNull().default(0),
totalTokens: integer('totalTokens').notNull().default(0)
})
```
表里有二个字段解释一下:
1. `usedTokens`:消耗的总Token数量
2. `totalTokens`:拥有的总Token数量
实际上,更完备的做法是两张表、一张是总消耗的聚合表、一张是每一条消耗的具体信息(包含各种模型参数、输入、输出)。但在初期这是没必要的,只需要一张消耗聚合表(`userUsage`)就够了,一条记录对应一个用户的消耗。
> 有一件非常讨厌的事情,就是D1是不支持事务的,所以在表结构设计(尽量单表、幂等、补偿)的时候要去尽量避免事务,这里有一个为什么不支持的[文档](https://blog.cloudflare.com/whats-new-with-d1/)。
## 完成API和基本逻辑
### 插入逻辑
这张表适插入新的数据时机是当用户注册创建的时候(因为会需要展示用户一共有多少用量),在Auth添加一个 createUser 事件处理器
```typescript
//lib/auth.ts
events: {
createUser: async ({ user }) => {
db.insert(userUsage).values({
userId: user.id!,
usedTokens: 0,
totalTokens: 1000
})
}
}
```
简单尝试一下,本地新注册一下,可以看到是正常插入的。

### 添加Google生态的API
因为要做模型消耗的统计,正好就把Google生态的AI接入,最近他们的表现非常好。`pnpm add @google/genai`,紧接着`https://cloud.google.com/`去领取300$,最后去`https://aistudio.google.com/apikey`创建API Key。
后续的调试模型也是直接在`Studio`里调试,在开发之前,我们需要把上一步得到的`key`贴到`env`中(我的变量名是叫`GEMINI_API_KEY`),同样先完成Actions。
```typescript
'use server'
import { GoogleGenAI } from '@google/genai'
export type GeminiGenerationParams = {
prompt: string
userId: string
model?: string
temperature?: number
maxOutputTokens?: number
systemPrompt?: string
userPrompt?:会员专享
订阅后解锁完整文章
支持创作、解锁全文,未来更新也会第一时间送达。
评论
加入讨论
登录后评论
还没有评论,来占个沙发吧。