pricing-api-integrator Hunt 调研报告 v1
任务: T-mt60zv33 | 阶段: FDE Hunt | 日期: 2026-08-24 目的: 为 Digest 阶段设计 benchmark 打地基,不是从零调研,而是深挖三块存量信息 + 探一批可用于 Evolve 真实自测的免鉴权 API
1. 仓库内先例对照:youtube-crawler(benchmark_score=95.5)
1.1 先例的产出结构(本体训练完整走过 FDE 四阶段)
| 阶段 | 产出目录 | 关键文件 |
|---|---|---|
| Hunt | workspace/hunt/ |
knowhow.md(方案对比+API细节)、seed_dataset.json、api_validation.md |
| Digest | workspace/digest_v2/ |
benchmark_v2.md(8维度加权评分表+11条自动化测试用例)、train.json/test.json、industry_avg.json |
| Evolve | workspace/evolve_v2/ |
youtube_crawler.js(生产代码)、benchmark_v2_test.js(自动化打分器)、benchmark_v2_result.json、verification_report.md |
| 汇总 | workspace/fde_report_v2.md |
全流程综合报告 |
出处:system/agents/youtube-crawler/workspace/{fde_report_v2.md, hunt/knowhow.md, digest_v2/benchmark_v2.md, evolve_v2/evolution_report_v2.md, evolve_v2/verification_report.md}
1.2 三级降级链的判定时机怎么设计的(可直接对照,但不可直接照搬——见 1.4 的关键差异)
digest_v2/benchmark_v2.md §2「API使用规范」检查项明确写死判定条件,不是笼统的"要有降级":
- 触发降级的具体信号:
403(区分quotaExceeded停止当天 vs 普通 403 走降级)、429重试耗尽后降级、超时(AbortSignal.timeout(30000))后降级。 - 降级顺序固定:API → yt-dlp → Invidious,任何一级失败自动尝试下一级(
SKILL.md§1)。 - 验收用自动化测试直接断言链路,不是靠人读代码判断:
benchmark_v2.mdTC-011test_fallback_chain()预期API(403) -> yt-dlp(timeout) -> Invidious(success),即测试用例本身构造三段式的失败注入,逐级验证真的切换了数据源。 - 重试参数写死到具体数字,不是"合理重试"这种模糊描述:429 base 2s / max 60s / retry 5 次;503 base 5s / max 120s / retry 5 次;500/502 最多重试 2-3 次(
evolution_report_v2.md§4 与benchmark_v2.md§6 两处数字一致,互相印证不是笔误)。
1.3 配额/缓存管理怎么验收
- 配额:
benchmark_v2.md§2 检查项「是否有配额监控与计数器(10,000 units/day)」——验收点是"有没有计数器"这个工程实体,不是"有没有用超配额"这种结果论。 - 缓存:§7「性能与效率」检查项「缓存时间是否合理(建议 fetch_interval_hours: 4)」+ SKILL.md 写死 TTL 15 分钟、缓存键
{regionCode}:{maxResults}:{videoCategoryId}——验收落到了具体的缓存粒度设计,能直接对着代码查有没有这个 key 结构。 - 评分公式是纯加权和(
总分 = Σ 维度分数 × 权重),8 个维度里"安全与合规"独立占 10%(API Key 环境变量注入、无硬编码、robots.txt),这点对 pricing-api-integrator 同样适用(见 §3)。
1.4 关键差异:先例的降级模式对 pricing-api-integrator 不能直接搬
这是本次调研最重要的一条结论,直接影响 Digest 阶段怎么设计维度权重:
youtube-crawler 的核心可靠性策略是"换数据源"(API 不行就换 yt-dlp,再不行换 Invidious)——因为它抓的是公开可见的同一份热榜信息,三个源理论上返回同一件事实,换源不改变数据的真实性含义。
pricing-api-integrator 的 agent.md 硬约束第 7 条明确禁止这种模式:"不许改上游给的目标清单来迁就实现……不要偷偷跳过不说、也不要换成别的数据源静默交付"。因为竞品定价是每家私有数据,A 家的价格不能拿 B 家的价格顶替——"换源"在这里等于伪造数据,与硬约束第 2 条的红线直接冲突。
结论:Digest 阶段设计 benchmark 时,「错误处理与降级策略」这一维度的评分标准不能照抄 youtube-crawler 的"三级降级链完整度",而应该改成"状态分类正确性"(ok/blocked_on_credential/unavailable 三态判断准不准、有没有在 status≠ok 时依然塞了 price 值)。这是两个本体在同一个维度名下、完全不同的验收内核,混着抄会把 benchmark 设计错方向。
2. 本体现状漏洞排查(agent.md 9条硬约束 + SKILL.md 价格快照 schema)
出处:system/agents/pricing-api-integrator/agent.md、.claude/skills/main_skill/SKILL.md。以下每条是手工走边界场景后发现的规则模糊/矛盾/未覆盖点,不是复述规则本身。
2.1 「API 返回 200 但 body 是空数组」该判什么 status?—— 确认的规则空白
SKILL.md §「价格快照输出格式」写死 status 只能是 ok / blocked_on_credential / unavailable,且 unavailable 的定义是"超时、限流、接口不存在等其它失败"(SKILL.md L28)。
走一遍这个场景:请求成功、HTTP 200、body 是 [](比如查询的 SKU 在该竞品的商品库里确实不存在,或者该地区没有上架)——这不是失败(请求本身没出错),但也没有价格可报。三个枚举值都套不上:
- 判
ok但price给 null?—— schema 规定status != "ok"时price才必须为 null(SKILL.md L77),反过来意味着status == "ok"隐含"这条有价格",ok+price:null是未定义组合,下游 sdd/benchmark 消费时大概率按"有效价格条目"计数,会把"这个 SKU 不存在"误算成"抓到了价格"。 - 判
unavailable?—— 语义上牵强,unavailable描述的是"该拿的东西没拿到"(限流/超时/无接口),不是"接口如实告诉你这东西不存在"。把这两种情况合并会让下游没法区分"这次该重试"还是"这个目标本来就没有这个 SKU,重试也没用"。
建议 Digest 阶段设计验收判据时把这个场景做成显式测试用例(类比 youtube-crawler TC-002/TC-010 的做法),逼 Evolve 阶段的实现在 PLAN 里就把这个分支写清楚,而不是留给运行时现场发挥。
2.2 「同一竞品清单里一半目标缺 key 一半不缺,继续处理其它目标」具体怎么落地不卡死?—— 确认的操作化空白
规则原文(agent.md 硬约束 6 + SKILL.md「缺 API Key 时的求助流程」)说"标记该条 blocked_on_credential,继续处理清单里其它目标",但没有回答几个必然会遇到的操作问题:
- 去重粒度:如果清单里 5 个目标共用同一个环境变量名(比如都靠
VENDOR_A_API_KEY鉴权,因为都是同一家聚合平台的子品牌),human request 是每个目标调一次(5 次重复求助同一把 key),还是按环境变量名去重只求助一次?SKILL.md 的示例是单目标视角("抓取定价需要"),没有给多目标共享同一凭证时的批处理指引。5 次重复 human request 对下游人类是噪音,但规则没禁止,也没要求去重。 - 求助后是否等待、等多久:human request 之后,是当场阻塞等人类回应(拖慢其它不缺 key 的目标),还是发完请求立刻标记 blocked_on_credential 就跳到下一个目标,同一次 EXECUTE 内不再回头检查这把 key 有没有配上?规则原文倾向后者("继续处理其它目标"暗示不阻塞),但没有明写,也没规定"如果 EXECUTE 阶段还没结束、人类已经把 key 配上了,要不要回头重抓那个被标记 blocked 的目标"。按当前四段式设计(一次流转清空对话记忆),大概率答案是"不回头,留到下一轮任务重跑",但这个隐含结论值得在 Digest 阶段的验收清单里显式写出来,否则不同实现会做出不同选择,benchmark 打分时容易产生分歧。
- 「缺失」与「无效」的边界没有覆盖:SKILL.md 的检测方法是
echo $VAR判断环境变量存不存在(L84, L41)。但如果变量存在、值也非空,只是这把 key 已过期/权限不够,API 返回 401/403——这不是"缺失",规则完全没提这种情况该走blocked_on_credential(复用求助流程,因为本质也是"当前环境缺一把能用的 key")还是走unavailable(因为技术上请求确实发出去也拿到响应了,只是被拒)。两条路径下游处理逻辑不同:前者会触发再次 human request,后者不会。这个判断留白,实现者只能自己猜。
2.3 「超时重试次数 SKILL.md 里写的是'按 _plan.md 定的次数'但没给 default」—— 确认属于规则漏洞,且是本次调研最值得带回 Digest 的一条
核实原文:SKILL.md §EXECUTE「遇到超时/限流:按 _plan.md 里定的重试次数重试;重试耗尽仍失败,标 unavailable 并写明原因,不要无限重试卡死任务」(L98)。通篇 agent.md + SKILL.md 没有任何地方给出:
- 默认重试次数是几次
- 退避策略是固定间隔还是指数退避、base 是多少、上限是多少
- 429(限流)和纯网络超时是否要用同一套重试参数,还是分开处理
- 单个目标的总耗时上限(避免一个目标反复重试拖爆整个任务的时间预算)
对照 1.2 节:youtube-crawler 在 SKILL.md/benchmark_v2.md 里把这些数字写死在技能本体层(429: base 2s max 60s retry 5;503: base 5s max 120s retry 5;网络超时 30s),任何一次训练/复训都有统一基线可对齐,Evolve 阶段的 benchmark 测试脚本能直接断言这些具体数字。而 pricing-api-integrator 把这个决定完全下放给每次任务的 _plan.md——即由 PLAN 阶段的 Agent 现场决定重试次数。这带来两个后果:
- 不同任务、不同次训练可能拍出不同的重试参数,Digest 阶段没有一个稳定基线可以拿来自动化打分(youtube-crawler 的 benchmark 可以直接检查"429 base 2s max 60s retry 5 是否命中",pricing-api-integrator 目前做不到,因为"标准答案"每次都不一样)。
- 如果 PLAN 阶段的 Agent 图省事,拍一个明显不合理的数字(比如 retry=0 或 retry=999),当前规则没有任何机制拦——SKILL.md 只要求"不要无限重试卡死任务"这种模糊上限,没有数值兜底。
建议:这不是"等 Evolve 阶段实现时再说"的细节,而是 Digest 阶段就该定的基线数字(比照 youtube-crawler 的量级:超时 20-30s、限流指数退避 base 1-2s / retry 3-5 次是行业常见区间,见第 3 节),否则 benchmark 无法对"重试策略是否合理"这一项打出稳定、可复现的分数。
2.4 其它顺带发现的小缺口(未在任务描述里点名,但走查中冒出来的)
- acceptance 清单不在本体文件里:agent.md 硬约束 5 提到"acceptance 是判定标准",但验收清单本身"路径不在本文件里,去任务描述取"(agent.md L7-L10 同一模式)——即 pricing-api-integrator 目前没有类似 youtube-crawler
benchmark_v2.md那样固化在技能本体里的评分表/自动化测试脚本,验收标准完全靠每次任务临时下发。这与 1.4 节呼应:Digest 阶段的核心产出物,恰恰应该是把这份目前不存在的benchmark_v1.md(+ 配套测试用例)产出来,而不是假设它已经存在只需要复用。 status: unavailable缺少子分类:SKILL.md 把"超时、限流、接口不存在"三种性质不同的失败都塞进同一个unavailable值(L28),但这三者对下游"要不要重试/什么时候重试"的含义完全不同(超时和限流值得下次任务重试,"接口不存在"重试无意义)。当前 schema 没有reason枚举,只在blocked_on_credential的示例里出现了自由文本reason字段(L70),unavailable该不该也强制填reason且做成受控枚举,规则没写清楚。- config.json 尚未挂 skill 版本(
system/agents/pricing-api-integrator/config.json):对照 youtube-crawler config 里的skills.youtube-crawling.{version, benchmark_score, status}结构,pricing-api-integrator 当前 config.json 没有skills字段,只有裸的type/status/cli/name/description——印证这确实是首训(status: training),Digest/Evolve 完成后要记得回填这个结构,否则后续复训无法读到上一版 benchmark_score 做对比。
3. 外部方法论:API 集成可靠性通用最佳实践
3.1 幂等性(Idempotency)
- 对写操作(本体目前是只读抓价,暂不适用,但如果后续扩展到"标记该条价格已核实"之类的写回操作要留意)应使用幂等键(idempotency key,通常是每个逻辑操作生成一个 UUID 放在请求头),确保重试不会造成重复副作用。
- 对 pricing-api-integrator 当前的纯读场景,"幂等"体现为:同一个
(competitor, product_id)目标在同一次 EXECUTE 里只应该产生一条最终快照记录,重试不应该在快照里出现同一目标的多条冲突数据。
3.2 退避重试(Exponential Backoff + Jitter)
- 标准模式:捕获限流/服务端错误 → 优先读
Retry-After响应头(若目标 API 提供)→ 没有该头则用指数退避(1s→2s→4s→8s…)。 - "Full Jitter"(在每次退避时间上叠加随机抖动)相比无抖动的纯指数退避,在 100 并发客户端场景下能把总请求量降低超过 50%——因为它打散了同步重试造成的请求洪峰。这点对本体虽不是并发场景(单 Agent 顺序处理目标清单),但如果未来同一竞品清单在多个任务并发跑时值得留意。
- 数量级参考(与第 1.2 节 youtube-crawler 的实际参数一致,可作为 Digest 阶段定基线数字时的外部佐证):连接超时建议 5s、读超时按目标 API 的 p99 延迟设定、重试总次数设上限并配合总耗时截止时间(deadline),避免"重试到天荒地老"。
3.3 错误分类(哪些该重试,哪些不该)
- 应重试:HTTP 429(限流)、500/502/503/504(服务端错误)、DNS 解析失败、连接超时。
- 不应重试(重试没有意义,属于"结果确定"的失败):多数 4xx(401/403 鉴权问题、400 参数错误、404 资源不存在)——这类错误换个时间点重试大概率还是同样的结果,应该直接分类落地,不占重试预算。
- 这条对应 2.1 节的空白:pricing-api-integrator 目前的
unavailable分类没有区分"该重试"和"不该重试"的失败,是个可以直接引用这条外部实践去补的具体依据。
3.4 限流处理(429)
- 优先读
Retry-Afterheader 的精确等待时间;没有该 header 才退化到指数退避估算。 - 本体当前的 curl 调用示例(SKILL.md L34-L37)没有演示读取
Retry-After,只记录状态码和响应体——建议 Digest 阶段的验收清单里加一条"429 响应时是否检查并遵循Retry-Afterheader"。
3.5 超时分类
- 连接超时(connect timeout)与读超时(read timeout)应该分开设置和处理:前者通常意味着网络/DNS 问题,后者意味着服务端处理慢。本体当前规则(agent.md/SKILL.md)没有区分这两种超时,统一按"超时"笼统处理——与 2.3 节发现的空白是同一类问题的不同侧面。
3.6 凭证缺失的正确处置
- 通用共识:API 凭证缺失应该被当作"配置问题"而非"运行时错误"来对待——即在请求发出前先做前置校验(本体的
echo $VAR检测已经是这个模式),失败时给出明确、可操作的报错(本体的blocked_on_credential+ human request 流程同样符合这个共识),而不是让请求带着空凭证发出去、拿到一个含糊的 401 再回头猜是不是缺 key。 - 本体在这点上的设计是对的,与行业共识一致,值得在 Digest 阶段作为"已经做好、不用扣分"的项保留,而不是把它当成待改进点。
3.7 LLM Agent 反幻觉对策(专门针对本体的核心红线)
- 这类问题在业界被称为 "tool-use hallucination"(工具调用幻觉),区别于一般的事实性幻觉——Agent 可能"声称"调用了 API、查了实时价格,但实际上什么都没做,直接编了一个看起来合理的数字。已知的三种子类型:
- 参数幻觉(Parameter Hallucination):调用了正确的工具,但参数是编的/缺失的/格式错的。
- 工具选择幻觉(Tool-Selection Hallucination):选错工具,或者干脆编造一个不存在的工具调用。
- 工具绕过错误(Tool-Bypass Error):不调用工具,直接编一个答案冒充调用结果——这正是 pricing-api-integrator 硬约束第 2/9 条要防的场景("用估算/缓存/编造数据充当实时价格")。
- 已知对策,且与本体现有设计逐条对得上:
- 严格的工具/参数 schema——本体的价格快照 JSON schema(SKILL.md L50-L77)本身就是这种对策的体现:把"status 只能是三选一,非 ok 时 price 必须为 null"做成结构化约束,比靠 Agent 自觉不编数字更可靠。
- 执行可追溯性(Execution Traceability)——要求记录"思考→行动"全链路:具体 prompt、生成的请求参数、真实的 API 响应。这正对应本体硬约束第 5 条"acceptance 交付前自己把验收命令跑一遍,把真实输出贴进日志",以及 VERIFY 阶段"抽查快照里每一条价格能不能对应到日志里一次真实请求/响应"(agent.md L51, SKILL.md L104)——这是本体已经内置的、业界公认有效的反幻觉机制,Digest 阶段设计 benchmark 时应该把这条"日志与快照的可交叉验证性"作为独立的高权重评分维度,而不只是流程合规检查。
- 已知薄弱点:即使 Agent 真的调用了工具,在"解释/转述工具返回结果"这一步依然可能出现幻觉(比如把响应里的某个字段读错、编了个响应里没有的细节)。本体当前的 VERIFY 阶段做法(抽查快照条目能否对应日志里的真实响应)部分覆盖了这个风险,但只覆盖"有没有调用",没有专门覆盖"转述得对不对"(比如把
"price": {"amount": 29.99}抄成了 30 或者抄错了货币单位)——这是 Digest 阶段可以补的验收点:不仅要求日志里有对应请求,还要求日志里的原始响应数值与快照里的最终数值逐字段核对一致。
4. 真实、公开、免鉴权、返回真实数值型数据的候选 API(供 Evolve 阶段自测替代 mock)
沙盒已验证有出网权限。以下三个端点已实测(2026-08-24),全部返回 200 + 真实数值,且均为无需注册/无需 API Key 的公开端点,可以直接在 Evolve 阶段用来做"真实调用而非纯 mock"的自测替代品——用它们模拟"竞品定价 API"的真实调用场景(价格数值 + 状态码 + 无鉴权/有鉴权两种模式都能覆盖,见下方注记)。
| # | 名称 | 端点 | 实测响应 | HTTP | 备注 |
|---|---|---|---|---|---|
| 1 | CoinGecko Simple Price | GET https://api.coingecko.com/api/v3/simple/price?ids=bitcoin,ethereum&vs_currencies=usd |
{"bitcoin":{"usd":77304},"ethereum":{"usd":2444.97}} |
200 | Keyless 公共 API,免费层 30 次/分钟,月配额 10,000 次;比另两个更贴近"多目标批量查价"场景(一次请求可传多个 ids,可模拟"一次抓一批竞品") |
| 2 | Coinbase Spot Price | GET https://api.coinbase.com/v2/prices/BTC-USD/spot |
{"data":{"amount":"77374.715","base":"BTC","currency":"USD"}} |
200 | 无需鉴权,公开端点限速 3 req/s(突发 6 req/s);单目标查询,字段结构最接近 pricing-api-integrator 快照里 price.amount 的形态 |
| 3 | Binance Ticker Price | GET https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT |
{"symbol":"BTCUSDT","price":"77397.55000000"} |
200 | 无需鉴权,权重制限流(单 symbol 权重 1,2400 权重/分钟 ≈ 2400 次/分钟);最适合用来测"高频轮询 + 限流应对"场景 |
用法建议:
- 用 #1(CoinGecko)模拟"多目标批量清单"场景,测试硬约束第 6/7 条(部分目标缺条件时继续处理其它目标)——可以人为传一个不存在的
ids(如notarealcoin)混进请求,观察真实 API 对"无效目标"的响应形态(是整体报错还是该 key 静默缺失),直接对应 2.1 节发现的"空结果该判什么 status"的规则空白,用真实数据而非假设去验证。 - 用 #2(Coinbase)模拟"单目标精确查价"场景,字段形状(
amount/currency)可以直接对着 SKILL.md 的价格快照 schema 做映射测试。 - 用 #3(Binance)因限流额度最宽松,适合用来测试"请求间隔/退避策略"逻辑本身(比如故意打高频请求触发它的限流响应,验证 Evolve 产出的重试/退避代码是不是真的按参数工作),弥补 2.3/3.4 节发现的"重试参数无默认值"空白——用真实限流响应校准出合理的 base/max/retry 默认值,而不是拍脑袋定数字。
- 三者都不需要鉴权,所以不能直接测试"缺 API Key → human request" 分支(2.2 节场景);如果 Evolve 阶段需要真实测这条分支,需要另外找一个免费但要求注册 Key 的 API(如 exchangerate-api.com 免费层需要注册但可申请,未在本次范围内实测,留给 Evolve 阶段按需处理)。
5. 交给 Digest 阶段的关键结论摘要
- 不能照抄 youtube-crawler 的"降级链完整度"维度——本体设计禁止换数据源,benchmark 的对应维度应改成"状态分类正确性 + 日志可交叉验证性"(§1.4, §3.7-2)。
unavailable状态缺子分类,"空结果/超时/限流/接口不存在/凭证无效"五种性质不同的失败目前全部混在一个枚举值里,建议 Digest 阶段的 benchmark 检查项里显式拆开验收(§2.1, §2.4, §3.3, §3.5)。- 重试/退避参数没有基线数字,建议参考 youtube-crawler 与业界共识(限流 base 1-2s / retry 3-5 次、超时 20-30s)在 Digest 阶段定死,否则无法自动化打分(§2.3, §3.2-3.4)。
- 凭证缺失处置流程设计是对的,属于已达标项,不用在 benchmark 里额外扣分空间(§3.6)。
- 反幻觉的核心机制(日志与快照交叉验证)已经内置在 VERIFY 阶段,建议 Digest 把这条设计成高权重独立维度,并补上"转述准确性"这个当前没覆盖的子项(§3.7)。
- 三个免鉴权真实 API 已验证可用,可供 Evolve 阶段做非 mock 自测,覆盖批量目标/精确查价/限流压测三种场景(§4)。