AtomCode 深度盲区分析 #10 — Provider 结构体完整还原与 CodingPlan 配额系统
持续分析循环 — 2026-06-24 14:28
深度还原ProviderConfig(15字段) 和 CodingPlan 配额/计费系统
1. ProviderConfig 完整字段还原(15 个字段)
此前文档仅标记 struct ProviderConfig with 15 elements 但未列出字段。通过 WebUI SPA JS 中"添加/编辑提供商"对话框的完整表单反推:
1.1 创建提供商表单字段
rust
struct CreateProviderRequest {
// 16 个字段 — 新提供商配置
name: String, // 提供商名称
r#type: String, // 类型 (openai/anthropic/deepseek/ollama/...)
model: String, // 默认模型名
base_url: String, // API 基础 URL
api_key: String, // API 密钥
context_window: u64, // 上下文窗口大小 (默认 128000)
max_tokens: u64, // 最大 token 数
thinking_budget: u64, // 思考预算 (>= 1024)
thinking_type: String, // 思考类型
thinking_keep: bool, // 保留思考过程
reasoning_history: String, // 推理历史模式
skip_tls_verify: bool, // 跳过 TLS 验证
set_default: bool, // 设为默认
user_agent: String, // 自定义 User-Agent
clear_base_url: bool, // 清除 base_url
clear_api_key: bool, // 清除 api_key
}1.2 部分更新提供商字段
rust
struct PatchProviderRequest {
// 19 个字段 — 最大的单结构体
// 包含 CreateProviderRequest 的全部 16 字段 +
// clear_user_agent: bool // 清除 User-Agent
// patch_type: ??? // 补丁类型
// 还有一个额外字段
}1.3 ProviderConfig 存储字段
rust
struct ProviderConfig {
// 15 个字段 — 持久化存储
name: String, // 提供商唯一名称
r#type: String, // 提供商类型
model: String, // 默认模型
base_url: String, // API 基础 URL
api_key: Option<String>, // API 密钥 (可空)
context_window: u64, // 上下文窗口
is_default: bool, // 是否为默认提供商
max_tokens: u64, // 最大 token 数
thinking_budget: u64, // 思考预算
thinking_type: String, // 思考类型
thinking_keep: bool, // 保留思考
reasoning_history: String, // 推理历史
user_agent: String, // User-Agent
skip_tls_verify: bool, // 跳过 TLS 验证
provider_type: String, // 辅助类型字段(与 type 相关)
// 可能还有一个 ephemeral 标志
}1.4 ProviderInfo 运行时信息
rust
struct ProviderInfo {
has_api_key: bool, // 是否已配置 API key
ephemeral: bool, // 是否为临时提供商
// ProviderConfig 的运行时子集
}2. 提供商类型(支持的类型)
从 WebUI SPA 对话框推断的支持类型:
| 类型 | 名称 | 默认 API URL |
|---|---|---|
openai | OpenAI | https://api.openai.com/v1 |
anthropic | Anthropic/Claude | https://api.anthropic.com |
deepseek | DeepSeek | https://api.deepseek.com/v1 |
ollama | Ollama (本地) | http://localhost:11434 |
moonshot | Moonshot/Kimi | (推测) |
custom | 自定义 | 用户指定的 base_url |
提供商类型切换 UI:
javascript
"settings.providerType": "Provider type",
// 选择器: {value:"openai", label:"OpenAI"},
// {value:"anthropic", label:"Claude"},
// {value:"deepseek", label:"DeepSeek"},
// {value:"ollama", label:"Ollama"},WebUI 提供商管理命令
Add a new provider
Edit an existing provider
Remove a provider
Switch the default provider
Paste a template to auto-detect3. CodingPlan 配额与计费系统(完全新的盲区)
此前未在任何分析文档中覆盖。
3.1 配额检查流程
用户请求 LLM
→ CodingPlan API 检查配额状态
→ 如配额耗尽 → "Current window quota exhausted"
→ HTTP 429 响应 → "reconstruct 429 response"
→ 配额周期结束自动恢复 → "Monthly quota exhausted, available again in X"3.2 配额数据结构
rust
// CodingPlan 配额响应
struct CodingPlanQuota {
// 计划基本信息
plan_name: String, // 计划名称 (e.g. "free", "pro")
claimed_at: DateTime, // 领取时间
expires_at: DateTime, // 过期时间
remaining_days: u64, // 剩余天数
total_days: u64, // 总天数
// Token 配额
window_token_limit: u64, // 窗口内 token 限制
window_tokens_used: u64, // 窗口内已用 token
// 时间窗口
window_hours: u64, // 窗口大小 (小时)
usage_percent: f64, // 使用百分比
// 速率限制规则
rate_limit_windows: Vec<RateLimitWindow>, // 速率限制窗口列表
// 重置信息
seconds_until_reset: u64, // 距重置的秒数
reset_label: String, // 重置标签 (e.g. "in 2h 30m")
// 状态描述
usage_status_desc: String, // 使用状态描述
usage_status: UsageStatus, // 使用状态枚举
// 独占模型标识
is_infinity: bool, // 无限配额
is_atomcode_exclusive: bool, // AtomCode 独占标记
// 显示
display_model_name: String, // 显示用模型名
// 计划可用性
plan_available: bool, // 计划是否可用
duplicate: bool, // 是否重复
codingplan_free: bool, // 是否免费 CodingPlan
current_usage: u64, // 当前用量
audit_status: String, // 审计状态
// 旧的 window 配额
window_quota_exhausted: bool, // 窗口配额是否耗尽
window_quota_hint: String, // 窗口配额提示
}3.3 速率限制窗口
rust
struct RateLimitWindow {
rule_index: usize, // 规则索引
show_enable: bool, // 显示启用状态
window_size_seconds: u64, // 窗口大小(秒)
call_limit: u64, // 调用限制
calls_used: u64, // 已用调用数
quota_exhausted: bool, // 是否耗尽
}3.4 计费状态枚举
rust
enum UsageStatus {
Ok, // 正常使用
RateLimited, // 被限速
QuotaExhausted, // 配额耗尽
StreamInterrupted, // 流中断
StreamTimeout, // 流超时
Timeout, // 超时
Error, // 错误
// ... 其他
}3.5 配额错误处理
rust
// 429 处理
"reconstruct 429 response"
"reconstruct empty 429 responses"
"send_with_retry: loop terminated without ..."
// 配额错误消息
"Current window quota exhausted"
"Monthly quota exhausted, available again in {}"
"Usage: monthly quota exhausted, available again in {}"
"Rate limited: {}"
// 日志
"calls.log" // 调用日志文件
"%Y-%m-%d_%H-%M-%S_" // 日志时间戳格式3.6 与 API 提供商的交互
text
CodingPlan API → https://api.gitcode.com/api/v5
GET /models-v2 → 获取模型列表(含配额信息)
POST /chat/completions → 发送聊天请求(配额自动扣减)
配额检查发生在 LLM API 调用之前和过程中:
1. 请求前:检查 window_quota_exhausted
2. 响应中:解析 429 → 触发配额错误
3. 请求后:更新 calls_used, window_tokens_used4. ModelEntry 结构
rust
struct ModelEntry {
name: String, // 模型名
provider: String, // 提供商名
is_default: bool, // 是否默认
context_window: u64, // 上下文窗口
effort_applicable: bool, // 是否可设置推理努力度
reasoning_effort: Option<String>, // 默认推理努力度
display_model_name: String, // 显示用模型名
plan_available: bool, // 计划可用
// 可能包含 quota 信息
}5. thinking_budget 校验
rust
"thinking_budget must be >= 1024"
// 最小预算 1024 tokens总结
| # | 盲区 | 此前覆盖 | 本次新增 |
|---|---|---|---|
| 1 | ProviderConfig 15 字段完整还原 | 仅提及名称 | ✅ 完整字段列表 + 类型标注 |
| 2 | CreateProviderRequest 16 字段 | 无 | ✅ 完整字段 |
| 3 | PatchProviderRequest 19 字段 | 无 | ✅ 最大结构体 |
| 4 | CodingPlan 配额系统 | 无 | ✅ 20+ 字段完整还原 |
| 5 | RateLimitWindow 6 字段 | 无 | ✅ 完整结构 |
| 6 | UsageStatus 枚举变体 | 无 | ✅ 计费状态机 |
| 7 | ModelEntry 结构 | 无 | ✅ 字段列表 |
| 8 | 配额错误处理 (429/重试) | 部分 | ✅ 完整流程 |
| 9 | 提供商类型支持列表 | 无 | ✅ openai/anthropic/deepseek/ollama/custom |
| 10 | thinking_budget >= 1024 约束 | 无 | ✅ 最小预算校验 |
报告份数总计: 52 份
本报告由持续分析循环生成 — 第 10 轮盲区挖掘