配额管理
wesgine 为每个 Cell 提供细粒度的资源配额控制,防止资源滥用和失控增长。
配额维度
计算配额
| 字段 | 说明 | 超限行为 |
|---|
| MaxConcurrentRuns | 最大并发 Run 数 | 429 拒绝 |
| TokensPerMinute | 每分钟 Token 限额 | 429 排队 |
| TokensPerDay | 每日 Token 限额 | 429 拒绝 |
存储配额
| 字段 | 说明 | 超限行为 |
|---|
| 磁盘总量 | Cell 磁盘使用上限 | 触发 GC / 拒绝写入 |
外设配额
| 字段 | 说明 | 超限行为 |
|---|
| MaxIMChannels | 最大 IM 渠道数 | 拒绝添加 |
| MaxMCPServers | 最大 MCP Server 数 | 拒绝注册 |
| MaxCronJobs | 最大定时任务数 | 拒绝添加 |
| MaxEmailAccounts | 最大邮箱账号数 | 拒绝添加 |
| MaxSkillsInstalled | 最大已装技能数 | 拒绝安装 |
| MaxPlugins | 最大插件数 | Boot 时截断 |
执行配额
判据位置原则
INV-QUOTA-05
配额判据在唯一增长点,与增长操作在同一个临界区:
适配器 → QuotaFn(current, delta) error → 增长操作
| 原则 | 说明 |
|---|
| 适配器不知道 cap 的数值 | 只通过 QuotaFn 提问 |
| 每个子系统恰好一处能让集合变大 | 唯一写入点 |
| 问与长同一临界区 | 防止并发越界 |
| 覆盖已有名字 delta=0 | upsert 是编辑不是增长 |
反模式
| 禁止 | 正确做法 |
|---|
| 在调用方检查配额 | 在唯一增长点检查 |
| 先 count 再 append 无锁 | 问与长同临界区 |
| 让适配器持有 cap 值 | 适配器只收 QuotaFn |
各子系统配额
IM 渠道
// adapter/channel 的增长点
channelAdapter.Add(ctx, config) // 内部调 QuotaFn
MCP Server
// adapter/mcp 的增长点
cell.MCPs().Upsert(ctx, serverConfig) // 内部调 QuotaFn
定时任务
// adapter/cron 的增长点
cron.Scheduler.Add(ctx, job) // 内部调 QuotaFn
邮箱账号
// adapter/email 的增长点
email.Store.PutAccount(ctx, account) // 内部调 QuotaFn
技能
// skills 的增长点
cell.Skills().InstallPackage(ctx, pkg) // 内部调 QuotaFn
创建时声明检查
validateSeedDeclarationCaps 在 Cell 创建时验证声明不超出配额:
| 检查 | 说明 |
|---|
| CellSpec.Cron | 声明的定时任务数 ≤ MaxCronJobs |
| CellSpec.Email | 声明的邮箱数 ≤ MaxEmailAccounts |
| CellSpec.Channels | 声明的渠道数 ≤ MaxIMChannels |
| CellSpec.MCPs | 声明的 MCP 数 ≤ MaxMCPServers |
配额查询
API
GET /cells/{id}/quotas
返回当前 Cell 的配额配置。
修改配额
PATCH /cells/{id}/quotas
{
"max_concurrent_runs": 5,
"tokens_per_day": 1000000
}
在各产品中的配置
wescode
quotas:
max_concurrent_runs: 1 # 单 workspace 通常够用
max_skills_installed: 50
max_mcp_servers: 10
wesclaw 桌面版
quotas:
max_concurrent_runs: 3
max_im_channels: 5
max_email_accounts: 3
max_cron_jobs: 20
企业版 (teleclaw)
按部门差异化配置:
| 部门 | MaxConcurrentRuns | TokensPerDay |
|---|
| 法务 | 5 | 500,000 |
| 业务 | 10 | 1,000,000 |
| HR | 3 | 200,000 |
注意事项
- 配额判据只在唯一增长点,不在调用方
- 问与长必须在同一临界区
- 覆盖已有名字是编辑手势,delta=0
- 创建时声明检查防止 Cell 装不下自己的声明
- MaxPlugins 在 boot 时截断,没有运行时写门