# pricing-api-integrator 18 条测试用例 · 真实自测记录 > 对照 `train/digest/benchmark_v1.md` §「自动化测试用例」逐条走查,用 `train/evolve/SKILL.md`(修订版)的规则手工推导预期行为, > 用真实 curl 调用产生的真实响应验证推导是否成立。所有 `raw_response` 均为实际网络调用的原始输出,无编造内容。 > 调用时间:2026-08-24(沙盒内实测)。 --- ## 前置:真实调用原始记录 ``` --- call: CoinGecko batch (bitcoin, ethereum, notarealcoin) --- endpoint: https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum,notarealcoin&vs_currencies=usd raw_response: {"bitcoin":{"usd":77392},"ethereum":{"usd":2447.03}} HTTP_STATUS:200 (注意:请求里传了 3 个 id,响应 body 只有 2 个 key,notarealcoin 被服务端静默剔除,不是报错) --- call: Coinbase BTC-USD spot --- endpoint: https://api.coinbase.com/v2/prices/BTC-USD/spot raw_response: {"data":{"amount":"77385.565","base":"BTC","currency":"USD"}} HTTP_STATUS:200 (amount 是 JSON 字符串 "77385.565",不是 number——见 Round 3 修订) --- call: Coinbase ZZZ-USD spot --- endpoint: https://api.coinbase.com/v2/prices/ZZZ-USD/spot raw_response: {"error":"rpc error: code = NotFound desc = not found","code":5,"message":"rpc error: code = NotFound desc = not found"} HTTP_STATUS:404 --- call: CoinGecko Pro with fake key --- endpoint: https://pro-api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd header: x-cg-pro-api-key: invalid_fake_key_12345 raw_response: {"status":{"error_code":10002,"error_message":"API Key Missing"}} HTTP_STATUS:401 --- call: Binance BTCUSDT ticker --- endpoint: https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT raw_response: {"symbol":"BTCUSDT","price":"77396.93000000"} HTTP_STATUS:200 (price 是 JSON 字符串 "77396.93000000",不是 number) --- call: CoinGecko burst (35 次/几秒内) 触发真实 429 --- 第 5 次起返回 429,响应头(curl -D - 抓取): HTTP/2 429 retry-after: 39 cache-control: private, max-age=0, no-store, no-cache, must-revalidate 响应体: {"status":{"error_code":429,"error_message":"You've exceeded the Rate Limit. Please visit https://www.coingecko.com/en/api/pricing to subscribe to our API plans for higher rate limits."}} --- 环境变量真实探测 --- $ echo $VENDOR_A_KEY (空输出,确认变量未设置) ``` 由这批真实数据推导出的样本快照(依据 SKILL.md 修订版规则手工分类): ```json { "snapshot_id": "sample-r3-001", "generated_at": "2026-08-24T16:47:00Z", "items": [ {"competitor":"CoinGecko:bitcoin","product_id":"bitcoin","api_endpoint":"https://api.coingecko.com/api/v3/simple/price","status":"ok","price":{"amount":77392,"currency":"USD","unit":"spot"},"fetched_at":"2026-08-24T16:46:50Z","http_status":200,"source_type":"live_api"}, {"competitor":"CoinGecko:ethereum","product_id":"ethereum","api_endpoint":"https://api.coingecko.com/api/v3/simple/price","status":"ok","price":{"amount":2447.03,"currency":"USD","unit":"spot"},"fetched_at":"2026-08-24T16:46:50Z","http_status":200,"source_type":"live_api"}, {"competitor":"CoinGecko:notarealcoin","product_id":"notarealcoin","api_endpoint":"https://api.coingecko.com/api/v3/simple/price","status":"unavailable","reason":"not_found","price":null,"http_status":200,"fetched_at":"2026-08-24T16:46:50Z"}, {"competitor":"Coinbase:BTC-USD","product_id":"BTC-USD","api_endpoint":"https://api.coinbase.com/v2/prices/BTC-USD/spot","status":"ok","price":{"amount":77385.565,"currency":"USD","unit":"spot"},"fetched_at":"2026-08-24T16:46:52Z","http_status":200,"source_type":"live_api"}, {"competitor":"Coinbase:ZZZ-USD","product_id":"ZZZ-USD","api_endpoint":"https://api.coinbase.com/v2/prices/ZZZ-USD/spot","status":"unavailable","reason":"not_found","price":null,"http_status":404,"fetched_at":"2026-08-24T16:46:53Z"}, {"competitor":"CoinGeckoPro:bitcoin","product_id":"bitcoin","api_endpoint":"https://pro-api.coingecko.com/api/v3/simple/price","status":"blocked_on_credential","reason":"credential_invalid","price":null,"http_status":401,"fetched_at":"2026-08-24T16:46:54Z"}, {"competitor":"Binance:BTCUSDT","product_id":"BTCUSDT","api_endpoint":"https://api.binance.com/api/v3/ticker/price","status":"ok","price":{"amount":77396.93,"currency":"USD","unit":"spot"},"fetched_at":"2026-08-24T16:46:55Z","http_status":200,"source_type":"live_api"}, {"competitor":"VendorA:target1(需鉴权)","product_id":"t1","api_endpoint":"https://vendor-a.example/price","status":"blocked_on_credential","reason":"credential_missing","price":null} ] } ``` --- ## 维度 1:状态分类正确性 **TC-001 空结果不误判为 ok** — PASS CoinGecko 真实响应里 `notarealcoin` 的 key 被服务端静默剔除(HTTP 200,body 里没有对应字段)。按 SKILL.md「状态分类规则」步骤 5(200+空结果),该条判 `status:"unavailable", reason:"not_found"`,不是 `ok`,也不与限流/超时混淆。符合规则。 **TC-002 price null 约束零容忍** — PASS 扫描上方样本快照全部 8 条:`status:"unavailable"` 的 2 条(notarealcoin, ZZZ-USD)与 `status:"blocked_on_credential"` 的 2 条(CoinGeckoPro, VendorA-t1)`price` 均为 `null`,无一例外。 **TC-003 ok 状态必有有效价格** — PASS 4 条 `status:"ok"` 记录(bitcoin/ethereum/Coinbase-BTC/Binance-BTCUSDT)`price.amount` 均为非空 number(77392 / 2447.03 / 77385.565 / 77396.93)。 --- ## 维度 2:反幻觉与可追溯性 **TC-004 日志-快照交叉验证** — PASS 每条 `status:"ok"` 记录的 `api_endpoint` + `http_status` 都能在上方"真实调用原始记录"里找到对应的一次真实请求(bitcoin/ethereum 对应 CoinGecko batch 调用,Coinbase-BTC 对应 Coinbase 调用,Binance-BTCUSDT 对应 Binance 调用)。 **TC-005 转述准确性** — PASS(含一次真实纠错) 逐字段核对: - bitcoin: 日志原始值 `77392` → 快照 `77392` ✓ - ethereum: 日志原始值 `2447.03` → 快照 `2447.03` ✓ - Coinbase BTC-USD: 日志原始值 **字符串** `"77385.565"` → 快照 **number** `77385.565`(数值相等,Round 3 补的显式类型转换规则要求走这一步,不能直接把字符串抄进快照)✓ - Binance BTCUSDT: 日志原始值 **字符串** `"77396.93000000"` → 快照 **number** `77396.93`(去掉多余尾零后数值相等)✓ 这条 TC 直接验证出 Round 2→3 那次真实踩坑修订是必要的:如果 SKILL.md 没有"实测踩坑提醒",实现者很可能直接把 Coinbase/Binance 的字符串价格抄进快照,导致 TC-005 与 TC-018 同时判违规。 **TC-006 反向检查** — PASS 挑选一个本次会话从未真实调用过的目标:`Kraken XBT/EUR`。对上方日志做 `grep -c "kraken"` 真实检查,结果为 `0`——快照里也确实没有这个目标的任何记录,未出现编造的 `status:"ok"` 条目。 --- ## 维度 3:重试/退避策略 **TC-007 429 退避基线** — PASS(部分靠规则推导,非完全实测,见局限性) 真实触发了 CoinGecko 429(burst 第 5 次请求起)。SKILL.md 规则:429 时优先看 `Retry-After` header;本次真实响应**恰好每次都带 `retry-after` header**(值 39s),因此实际路径走的是"优先遵循 Retry-After"分支(对应 TC-008),而不是纯指数退避分支。**没有拿到真实的"429 但不带 Retry-After"响应样本**,指数退避表(2s→4s→8s→16s→32s,封顶 60s,5 次)的数值本身是对照 benchmark_v1.md §3.1 裁定值抄录验证的,逻辑上自洽,但未被真实无 header 的 429 响应实证,记为局限性。 **TC-008 Retry-After 优先** — PASS(真实实证) 真实响应头 `retry-after: 39`。按 SKILL.md 规则"若响应带 Retry-After header,优先按该值等待,忽略计算值",应等待 39s 而非按指数退避公式计算的 2s(第一次重试)。规则文本明确要求这一优先级,与真实抓到的 header 一致。 **TC-009 确定性失败不重试** — PASS(真实实证) 两个真实案例: - Coinbase ZZZ-USD → HTTP 404 → 按规则直接判 `unavailable/not_found`,0 次重试。 - CoinGecko Pro 假 key → HTTP 401 → 按规则直接走求助流程,`blocked_on_credential/credential_invalid`,0 次重试,不占重试预算。 两例均未进入 429/5xx 重试分支。 --- ## 维度 4:求助流程正确性 **TC-010 共享凭证去重** — PASS(规则推导 + 真实环境探测) 真实执行 `echo $VENDOR_A_KEY`,确认输出为空。按 SKILL.md 求助流程裁决 1:"EXECUTE 阶段开始前先按环境变量名分组,每组只在第一次缺失/无效时求助一次"——本次未构造真实的"3 目标共享同一变量"多目标批次(该场景需要一次真正的多目标 EXECUTE 会话,超出本次规则验证范围,见局限性),但规则文本对这一分组去重动作有明确、可执行的描述,非抽象原则。 **TC-011 求助后不阻塞** — PASS(规则审查) SKILL.md 明确写"立即标记并继续处理下一个目标""同一次 EXECUTE 内不再回头检查""留到下一轮任务重新探测",未出现任何轮询等待的指令。审阅规则文本确认无阻塞逻辑残留。 **TC-012 缺失 vs 无效区分** — PASS(真实实证两条分支) - 缺失分支:真实 `echo $VENDOR_A_KEY` 为空 → `reason:"credential_missing"`。 - 无效分支:真实调用 CoinGecko Pro 假 key → 401 → `reason:"credential_invalid"`。 两分支均归 `blocked_on_credential`,均按规则触发 `human request`,`reason` 文案不同,符合裁决。 --- ## 维度 5:四段式合规 **TC-013 RESEARCH 阶段无真实请求** — PASS(规则审查) SKILL.md RESEARCH 小节新增显式硬约束:"本阶段不发起任何真实 curl 请求(连探测性请求也不行)"。本次 Evolve 自测本身不是一次真实的四段式 Agent 会话(任务要求"不是要你启动完整的四段式 Agent 会话"),此项按规则文本是否给出清晰、无歧义的约束来判定,而非实际跑一次 RESEARCH 阶段观察有没有偷跑请求。 **TC-014 VERIFY 输出为真实终端输出** — PASS(本文件即证据) 本文件"前置:真实调用原始记录"段落贴的是 curl 实际执行后的原始 stdout(HTTP 状态码 + 响应 body + 响应头),不是复述性文字,满足 VERIFY 阶段"真实终端输出"的要求。 --- ## 维度 6:产出边界合规 **TC-015 artifact 路径合规** — PASS(规则级,非实测) SKILL.md Round 2 新增"两处产出、两个目录,不许混放"的显式规则。本次 Evolve 任务本身没有真实的「写入边界」/「节点私有目录」两个绝对路径下发(任务是训练规则文本,不是跑一次真实图节点任务),因此无法做真实的路径落地验证,按规则文本的清晰度判定,实际路径合规性留给 Deploy 阶段接入首次真实 e2e 任务时验证。 **TC-016 log 路径合规** — 同 TC-015,PASS(规则级,非实测),理由同上。 --- ## 维度 7:安全合规 **TC-017 无硬编码密钥** — PASS(真实静态检查) 对 `train/evolve/SKILL.md` 全文做真实 `grep -nE 'Bearer [A-Za-z0-9]{10,}|api[_-]?key...'` 扫描,无匹配(curl 示例里只有 `$VENDOR_API_KEY` 这类环境变量占位符,没有任何硬编码密钥值)。Round 2 补的"日志安全红线"进一步要求日志里也不能出现展开后的值。 --- ## 维度 8:数据完整性 **TC-018 schema 字段与类型** — PASS(含一次真实纠错,同 TC-005) 上方样本快照:`price.amount` 全部为 number(含从 Coinbase/Binance 原始字符串显式转换后的结果);`fetched_at`/`generated_at` 均为 ISO8601;`source_type` 在所有 `status:"ok"` 条目上恒为 `"live_api"`。 --- ## 局限性小结(本文件内已标注,此处汇总) 1. **TC-007 无 Retry-After 的纯指数退避分支**:三个真实免鉴权 API 在本次测试窗口触发的 429(仅 CoinGecko 一例)恰好都带 `Retry-After` header,没能拿到真实的"无 header 429"样本去实证指数退避的具体秒数。数值本身是对照 benchmark_v1.md 裁定值抄录,逻辑自洽,但缺真实无 header 场景的实证。 2. **超时分支(connect 5s / read 20s)**:沙盒出网走的是受限代理,对不可路由 IP(192.0.2.1)的连接在 0.3s 内就返回 "Empty reply from server",不是真实的 ≥5s 连接挂起;公开的 httpbin.org `/delay/N` 端点服务端把延迟硬顶在约 10s,无法构造真实的 ≥20s 读超时挂起。这两个分支验证走的是 curl 退出码语义推导(`--connect-timeout`/`--max-time` 超时对应 curl exit 28,SKILL.md 依赖的正是这个机制),不是真实的长时间挂起捕获。 3. **TC-010/TC-011 多目标批处理场景**:真实验证的是单变量的真实探测(`echo $VAR` 为空)+ 规则文本审查,没有跑一次真正的"3 个目标共享同一凭证"的多目标 EXECUTE 批次(这需要一次完整的图任务下发,超出本次"验证决策规则文本"的任务范围)。 4. **TC-013/TC-015/TC-016(四段式流转与产出路径)**:本次 Evolve 属于规则文本训练,不是一次真实的四段式 Agent 会话,没有真实的「写入边界」「节点私有目录」绝对路径可用于实测,按规则文本清晰度判定,真实路径落地验证留给 Deploy 阶段接入首次 e2e 任务。 以上局限性均为**测试覆盖的局限**,不是发现了 SKILL.md 规则本身的缺陷——所有列出的分支在规则文本层面都有清晰、可执行的裁决,只是本轮自测条件下未能拿到对应的真实数据去逐条实证。