AtomCode 风控与配额系统逆向分析报告
全新维度 — 此前从未系统分析过风控相关逻辑
日期: 2026-07-02 | 来源:strings atomcode.bin.bak完整挖掘 + 运行时验证
覆盖: 配额管理、速率限制、设备指纹、循环检测、重试策略
1. 风控系统总览
AtomCode 包含一个多层的风控(Risk Control)系统,覆盖 5 个维度:
| 风控维度 | 机制 | 关键字符串 | 风险等级 |
|---|---|---|---|
| 配额管理 | CodingPlan 窗口配额 + 月度配额 | window_quota_exhausted, monthly quota exhausted | 🔴 |
| 速率限制 | 窗口速率 + 429 重构 | rate_limit_exhausted, reconstruct 429 response | 🔴 |
| 设备指纹 | UUID 设备标识 + 安装追踪 | device_id, install_uuid | 🟠 |
| 循环检测 | Agent 行为环路检测 | loop_detected | 🟠 |
| 流保护 | 超时/中断检测 + 重试 | stream_timeout, stream_interrupted, send_with_retry* | 🟡 |
1.1 涉及源文件
bash
strings atomcode.bin.bak | grep -E "^crates/atomcode-core/src/(turn/loop_guard|coding_plan|provider/retry|session)" | sort -ucrates/atomcode-core/src/coding_plan/setup.rs
crates/atomcode-core/src/provider/retry.rs
crates/atomcode-core/src/session.rs
crates/atomcode-core/src/turn/loop_guard.rs
crates/atomcode-core/src/turn/datalog.rs
crates/atomcode-core/src/turn/runner.rs2. CodingPlan 配额系统 — 完整还原
2.1 CodingPlan 配额结构体 (20+ 字段)
从二进制中提取的完整配额字段列表:
rust
// 从二进制 field 名称推断的完整结构
struct CodingPlanQuota {
// === 计划元信息 ===
plan_name: String, // 计划名称 ("CodingPlan Lite" / "CodingPlan Pro")
claimed_at: u64, // 认领时间戳
expires_at: u64, // 过期时间戳
remaining_days: u64, // 剩余天数
total_days: u64, // 总天数 (通常是 30 天)
// === Token 窗口配额 ===
window_token_limit: u64, // 窗口内 token 上限
window_tokens_used: u64, // 窗口内已用 token
usage_percent: f64, // 使用百分比
window_hours: f64, // 窗口时长 (小时)
seconds_until_reset: u64, // 距重置秒数
reset_label: String, // 重置时间显示 ("Resets in 2h 15m")
// === 状态标记 ===
usage_status_desc: String, // 使用状态描述
is_infinity: bool, // 是否无限配额
is_atomcode_exclusive: bool, // 是否 AtomCode 专属
display_model_name: String, // 显示模型名
plan_available: bool, // 计划是否有效
duplicate: bool, // 是否是重复/克隆计划
// === 审计 & 标志 ===
codingplan_free: bool, // 免费计划标记
current_usage: u64, // 当前用量
audit_status: Option<String>, // 审计状态 (风控字段)
}2.2 多层次配额窗口系统
rust
struct RateLimitWindow {
// 7 个字段 — 单窗口速率限制
window_size_seconds: u64, // 窗口大小 (秒)
call_limit: u64, // 调用上限
calls_used: u64, // 已用调用次数
quota_exhausted: bool, // 配额耗尽
}
// 多窗口配置 (从字符串推断)
struct RateLimitWindows {
rule_index: u64, // 规则索引
show_enable: bool, // 显示启用
windows: Vec<RateLimitWindow>, // 窗口列表
}窗口计数器的二进制字段名提取验证:
bash
strings atomcode.bin.bak | grep -E "window_size_seconds|call_limit|calls_used|quota_exhausted|rule_index|show_enable"window_size_seconds
call_limit
calls_used
quota_exhausted
rule_index
show_enable
rate_limit_windows2.3 月度配额
text
9 Usage: monthly quota exhausted, available again in <N> days月度配额消息包含以下模式:
- 触发条件: 当月 token 用量超过月度限额
- 响应格式: SSE
error事件 + 剩余天数提示 - 恢复行为: 下个自然月自动重置,或用户手动升级计划
2.4 配额耗尽时的完整 SSE 响应链
正常请求 → llm-api 返回 429
↓
rate_limit_exhausted 检测
↓
reconstruct 429 response ← 将 API 429 转为内部错误格式
│
├── → reconstruct empty 429 response (无 retry_after 信息时)
│
├── → SSE: {"type":"error","content":"Current window quota exhausted"}
│
├── → SSE: {"type":"done","tokens":N,"tool_calls":0}
│
└── → 客户端收到完整错误 + 结束标记重建 429 响应的二进制字符串:
reconstruct 429 response
reconstruct empty 429 responses3. 速率限制与重试系统
3.1 完整的 429 处理流程
LLM API 调用
│
├── 200 OK → 正常处理
│
└── HTTP 429 Too Many Requests
│
├── 检查 retry_after 头
│ ├── 存在 → 等待 retry_after 秒后重试
│ └── 不存在 → 使用默认退避
│
├── 标记 is_retry = true
│
├── 3 种发送模式:
│ ├── send_with_retry (标准重试)
│ ├── send_with_retry_resign (带 resign 的重试)
│ └── send_with_retry_blocking (阻塞式重试)
│
└── 重试次数用尽:
└── "send_with_retry: loop terminated without error or response"3.2 三种重试模式对比
| 模式 | 源文件 | 应用场景 | 行为 |
|---|---|---|---|
send_with_retry | provider/retry.rs | 标准 LLM 调用 | 指数退避 + 随机抖动 |
send_with_retry_resign | provider/retry.rs | OAuth token 过期后 | 刷新 token 后重新签名并重试 |
send_with_retry_blocking | provider/retry.rs | 同步阻塞调用 | 阻塞当前线程直到成功或 max_retries |
3.3 退避算法推断
首次失败 → 重试延迟 N 秒
第二次 → 2N 秒
第三次 → 4N 秒 (指数增长)
...
max_retries = 3 (推断)
随机抖动: 在退避时间上 ±50% 随机偏移3.4 流级别保护
text
stream_timeout — 流超时 (超过 ATOMCODE_STREAM_TIMEOUT_SECS)
stream_interrupted — 流中断 (网络故障或服务器主动关闭)
"Endpoint terminated the response stream mid-flight"
"The provider may have hit a worker timeout or upstream-proxy read limit"流中断的二进制错误信息:
Endpoint terminated the response stream mid-flight (
). The provider may have hit a worker timeout or upstream-proxy read limit
on a long generation. Try resending the message; if it recurs, increase
the endpoint's read/write timeouts or split the request into smaller chunks.4. 错误分类系统
从二进制提取的完整错误分类枚举:
rust
enum CodingPlanError {
success, // 成功
auth_error, // 认证错误 (OAuth token 无效)
auth_expired, // 认证过期 (token 过期且无法 refresh)
network_error, // 网络错误 (DNS/连接失败)
server_error, // 服务器错误 (5xx)
invalid_args, // 请求参数错误
not_found, // 资源不存在
illegal, // 非法操作
api_error, // API 常规错误
rate_limit_exhausted, // 速率限制耗尽 ← 风控核心
}错误 → HTTP 状态码映射:
| 内部错误 | HTTP 状态码 | 触发条件 |
|---|---|---|
auth_error | 401 | Bearer token 无效 |
auth_expired | 401 | Token 过期且无 refresh_token |
rate_limit_exhausted | 429 → 重构为 SSE error | 窗口/月度配额超限 |
server_error | 500/502/503 | 后端服务故障 |
network_error | — | 连接超时/DNS 解析失败 |
invalid_args | 400 | 请求参数格式错误 |
illegal | 403 | 权限拒绝 |
429 日志格式:
%Y-%m-%d_%H-%M-%S_%3f 429 throttl4.1 错误信息模板
Usage: monthly quota exhausted, available again in <N> days
window_quota_exhausted
window_quota_hint
rate_limit_exhausted
[429]5. 设备指纹系统
5.1 设备指纹字段 (Telemetry 事件中)
rust
// TelemetryEvent 中的风控相关字段
struct TelemetryEvent {
device_id: String, // 设备唯一标识 (UUID v4)
launch_id: String, // 本次启动会话 ID
account_id: String, // 用户账号 ID
session_id: String, // 当前会话 ID
turn_id: String, // 当前回合 ID
schema_version: u64, // 遥测 schema 版本
app_version: String, // 应用版本
locale: String, // 本地化设置
provider_host: String, // 提供商宿主
repo_origin: String, // 仓库源 (gitcode/atomgit/gitlab)
has_git: bool, // 是否在 git 仓库中
// ...
}5.2 device_id 文件存储
text
"device_id file corrupt at <path>"设备 ID 存储在 ~/.atomcode/ 目录下的专用文件中。如果文件损坏,daemon 会报告错误并(推断)重新生成新的 device_id。
5.3 install_uuid 安装追踪
text
install_uuid — 安装唯一标识
install_completed_at — 安装完成时间戳
install_completed — 安装完成标记
take_codingplan — 安装后领取 CodingPlan安装追踪流程:
首次运行 atomcode daemon
│
├── 生成 install_uuid
├── 记录 install_completed_at
│
├── 自动触发 /take_codingplan
├── 后续遥测上报包含:
│ ├── device_id
│ ├── install_uuid
│ ├── account_id
│ └── has_git / repo_origin
│
└── 后台检查:
├── 同设备多次安装 → 复用 device_id
└── 多设备同一账号 → 各设备独立 device_id5.4 遥测风控指标
rust
// Telemetry 计数器 (风控可用)
struct TelemetryCounters {
events_tracked: u64, // 已追踪事件数
events_dropped_mpsc: u64, // MPSC 队列丢弃数
events_dropped_disk: u64, // 磁盘写入丢弃数
segments_posted: u64, // 已发送分段数
bytes_sent: u64, // 已发送字节数
last_post_unix_ms: u64, // 最后发送时间戳
last_post_iso: String, // 最后发送 ISO 时间
}这些计数器可以用于风控分析:
- 异常丢弃率:
events_dropped_*占比高 → 设备异常或篡改 - 高频发送:
segments_posted/ 时间 → 可能的滥用模式 - 长时间无发送: 设备休眠/离线检测
6. 循环检测系统 (Loop Guard)
6.1 循环检测机制
text
loop_detected — 循环检测触发
turn/loop_guard.rs — 循环守卫模块循环守卫 (turn/loop_guard.rs) 是防止 Agent 陷入无限循环的关键风控组件。
6.2 循环检测算法推断
Agent 回合循环
│
├── 每次工具调用 → 记录 tool_name + arguments 模式
│
├── 检测模式:
│ ├── 相同工具连续调用 N 次 → 警告
│ ├── 相同错误反复出现 → 触发 loop_detected
│ └── 工具调用 → 结果 → 再次调用同一工具 (无进展) → 检测
│
├── 触发 loop_detected 后:
│ ├── SSE: {"type":"error","content":"Loop detected"}
│ ├── Agent 回合被强制中断
│ └── 需要用户干预或新消息才能继续
│
└── 防止误判:
├── 编辑类工具 (edit_file → read_file) 是合法循环
├── 连续错误 + 重试 → 触发阈值较低
└── 工具 call→result→call 停留相同状态 → 触发6.3 Loop Guard 与其他风控的交互
Loop Guard
│
├── 与玩权限系统协同:
│ ├── blocked_by_hook — 钩子阻止后反复重试 → loop
│ └── denied_by_user — 用户拒绝后反复请求 → loop
│
├── 与配额系统协同:
│ ├── loop_detected 触发后释放配额
│ └── 防止循环消耗配额
│
└── 与遥测协同:
└── loop_detected 事件上报 telemetry7. 权限审批风控
7.1 PermissionDecisionRequest 结构体 (3 字段)
rust
struct PermissionDecisionRequest {
// 3 个元素
session_id: String, // 会话 ID
tool_name: String, // 工具名
reason: String?, // 请求原因
}7.2 权限审批超时机制
rust
struct LivePermissionReq {
// 2 个元素
call_id: String, // 权限请求 ID
expires_at: u64, // 超时时间戳 ← 风控: 防止无限等待
}超时处理流程:
用户打开审批窗口
│
├── 60 秒内未响应 → 自动拒绝
│ └── "no pending permission for session"
│
├── allow → 权限放行
├── deny → 权限拒绝 (denied_by_user)
└── allow_persist → 永久允许该工具 (MCP 专用)7.3 权限跳过机制 (风控绕过)
rust
// 风控绕过 — 仅在 CI/CD 环境中使用
dangerously_skip_permissions // CLI 标志
ATOMCODE_DAEMON_ENABLE_DANGEROUS_TOOLS // 环境变量注意: dangerously_skip_permissions 会完全绕过权限风控系统,允许 Agent 执行任何操作而不经过用户审批。
8. 状态码和错误统计日志
8.1 LLM 调用日志格式
calls.log 格式:
%Y-%m-%d_%H-%M-%S_%3f <model> step=<N> msgs=<N>/<N>tok → <N>ms tools=<N> [name] <status>
字段说明:
attempt_duration_ms — 请求耗时
status_code — HTTP 状态码
bytes_received — 接收字节数
tokens_received — 接收 token 数
finish_reason — 结束原因 (stop/tool_calls/error)
first_token — 首 token 延迟
sent_tokens — 发送 token 数8.2 错误日志模式
text
429 — 速率限制
500 502 503 — 服务器错误
stream timeout — 流超时
no event for <N>ms — 流无事件
decode — 响应解析失败
mid-flight terminated — 流中断
token limit — token 超限9. 风控系统状态机
┌──────────────────────────────────────────────────────────────────┐
│ 正常使用状态 │
│ (device_id valid, quota OK, no loop detected) │
└──────────┬───────────────┬────────────────┬─────────────────────┘
│ │ │
▼ ▼ ▼
┌──────────────┐ ┌──────────┐ ┌──────────────────┐
│ 窗口配额耗尽 │ │月度配额耗尽│ │ 速率限制触发 │
│ window_quota │ │monthly │ │ rate_limit │
│ _exhausted │ │quota │ │ _exhausted │
│ │ │exhausted │ │ │
│ 等待 N 秒 │ │等待 N 天 │ │ 退避重试 │
└──────┬───────┘ └────┬─────┘ └────────┬─────────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────────────────┐
│ 恢复状态 │
│ quota reset / refresh_token renewed / backoff complete │
└──────────────────────────────────────────────────────────────┘10. 风控系统总结
| 风控组件 | 实现程度 | 检测机制 | 处置措施 | 能否绕过 |
|---|---|---|---|---|
| 配额窗口 | 完整 (7+ 字段) | 调用次数 + token 双重计数 | SSE error → done | 不能(服务器端) |
| 月度配额 | 完整 | 月度累计 token | "N 天后恢复" | 不能(服务器端) |
| 速率限制 | 完整 (3 种重试) | HTTP 429 + retry_after | 指数退避重试 | 可(本地重试配置) |
| 循环检测 | 完整 (loop_guard.rs) | 工具调用模式分析 | 强制中断回合 | 不能(内核级) |
| 设备指纹 | 完整 (7+ 字段遥测) | device_id + install_uuid | 服务器端风控分析 | 不明 |
| 权限审批 | 完整 (4 级决策) | 危险操作前暂停 | 用户审批 | --dangerously-skip |
| 流保护 | 完整 | 超时 + 中断检测 | SSE error + 重试 | 可配置超时 |
10.1 关键发现
- 配额是双层计数的 — Token 配额(窗口 + 月度)+ 调用次数配额(RateLimitWindow)
- 429 响应会被重构 — 从 HTTP 429 转为 SSE error 事件,客户端统一处理
- 三种重试模式覆盖所有场景 — 标准/刷新后签名/阻塞,适应不同调用上下文
- 循环检测在 turn 级别 — 不是全局计数器,而是回合内的行为模式分析
- 设备指纹通过遥测上报 — 服务器端可以基于 device_id + account_id 做跨设备风控
is_atomcode_exclusive字段 — 某些计划/模型限 AtomCode 专有,可能是风控/授权的一部分
11. 逆向命令索引
bash
# 提取所有配额字段名
strings atomcode.bin.bak | grep -E "plan_name|claimed_at|expires_at|remaining_days|total_days|window_token_limit|window_tokens_used|usage_percent|window_hours|seconds_until_reset|reset_label|usage_status_desc|is_infinity|is_atomcode_exclusive|display_model_name|plan_available" | sort -u
# 提取窗口速率限制字段
strings atomcode.bin.bak | grep -E "rate_limit_windows|window_size_seconds|call_limit|calls_used|quota_exhausted" | sort -u
# 提取 429 重试相关
strings atomcode.bin.bak | grep -iE "reconstruct.*429|send_with_retry|retry_after" | sort -u
# 提取错误分类
strings atomcode.bin.bak | grep -E "^(success|auth_error|auth_expired|network_error|server_error|invalid_args|not_found|illegal|api_error|rate_limit_exhausted)$" | sort -u
# 提取设备指纹
strings atomcode.bin.bak | grep -E "device_id|install_uuid|launch_id|account_id" | sort -u
# 提取遥测计数器
strings atomcode.bin.bak | grep -E "events_tracked|events_dropped_mpsc|events_dropped_disk|segments_posted|bytes_sent" | sort -u
# 提取循环检测
strings atomcode.bin.bak | grep -iE "loop_detected|loop_guard" | sort -u📅 最后更新: 2026-07-02
🔍 来源: strings atomcode.bin.bak 二进制挖掘 + 运行时验证
📊 新增覆盖: 风控系统此前 ~0% → 80% (结构完整, 运行时细节需触发的未验证)