Skip to content

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 -u
crates/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.rs

2. 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_windows

2.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 responses

3. 速率限制与重试系统

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_retryprovider/retry.rs标准 LLM 调用指数退避 + 随机抖动
send_with_retry_resignprovider/retry.rsOAuth token 过期后刷新 token 后重新签名并重试
send_with_retry_blockingprovider/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_error401Bearer token 无效
auth_expired401Token 过期且无 refresh_token
rate_limit_exhausted429 → 重构为 SSE error窗口/月度配额超限
server_error500/502/503后端服务故障
network_error连接超时/DNS 解析失败
invalid_args400请求参数格式错误
illegal403权限拒绝

429 日志格式:

%Y-%m-%d_%H-%M-%S_%3f  429    throttl

4.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_id

5.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 事件上报 telemetry

7. 权限审批风控

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 关键发现

  1. 配额是双层计数的 — Token 配额(窗口 + 月度)+ 调用次数配额(RateLimitWindow)
  2. 429 响应会被重构 — 从 HTTP 429 转为 SSE error 事件,客户端统一处理
  3. 三种重试模式覆盖所有场景 — 标准/刷新后签名/阻塞,适应不同调用上下文
  4. 循环检测在 turn 级别 — 不是全局计数器,而是回合内的行为模式分析
  5. 设备指纹通过遥测上报 — 服务器端可以基于 device_id + account_id 做跨设备风控
  6. 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% (结构完整, 运行时细节需触发的未验证)

基于 VitePress 构建 · AtomCode v4.25.3 逆向工程分析文档