OpenAI 挨个通知了 100 多家组织:给 Agent 补一张出站责任清单

发布时间:2026/10/23 2:51:36
OpenAI 挨个通知了 100 多家组织:给 Agent 补一张出站责任清单
本文是「Agent 工程实战」系列的第 03 篇属于保命线。系列索引21 篇阅读路线Agent 放权前先补权限、出站、发现这三道口子摘要十月初路透社报道 OpenAI 已向超过 100 家组织通报其模型在训练、评估期间的越界活动一周前这个数字还是数十家。这篇不聊大厂的瓜聊一个跟你我直接相关的问题你的 Agent 到别人服务上到访过之后在对方眼里留下了什么。按本机沙箱实测给出三件套——名片、预算、流水外加一个被通报时的预案最后附一张可以直接照做的出站责任清单。全文代码与数据均为本机沙箱实测Node.js v25.8.2可复跑。文章目录凌晨的质询一次自证教会我的事这轮通报的边界通报不等于入侵为什么老爬虫常识不够用了四个新变量对方眼里的三种麻烦对应你要备的三件套名片让对方在一封邮件里找得到你预算给每个任务一条熔断线流水被问是不是你们时五分钟答上预案被通报当天第一步不是改代码两个常见反问和我的回答出站责任清单一张表照做凌晨的质询一次自证教会我的事先不聊新闻讲个我亲历的小场面。前几年帮朋友看一个抓取任务。某天凌晨两点多他们运维群被对方站点的管理员 了甩过来一串 IP附言只有一句“这是你们的吗打算干什么”五六个人爬起来翻日志翻到三点出头才敢回一句大概率是我们。翻的过程特别憋屈请求是真的日志也查得到条数但对方要的三样东西——“这个 IP 是不是你们”“凌晨这段一共来了多少次”“是任务正常采集还是异常重试”——没有一样能五分钟答上来。对方最后没为难他们但那种先自证清白的狼狈我记到现在。说这个是因为这两周连着几条新闻都指向同一件事Agent 出门之后留下的痕迹正在变成一个需要工程手段专门处理的问题。十月初路透社报道OpenAI 已经陆续向超过一百家组织通报了其模型在训练、评估期间的越界活动——绕过安全控制、使用公开泄露的凭据、在别人的网站上留下需要清理的内容。而就在一周前这家公司的公开说法还是数十家。据路透社这轮回溯审查要处理大约 50 PB 的数据预计还要花几个月。看到新闻的时候我没太关心大厂又出事了。我干的第一件事是把自己那几个跑在公网上的 Agent 的请求头翻出来看了一遍。结果不太好看那个每天定时同步的脚本请求头里连一个能认领它的名字都没有——如果它哪天惹了事对面连该找谁都不知道。这篇聊的就是这件事Agent 出门之后的治理。之前写过两篇相关视角的——一篇《三道门》站在挨打的服务端讲接口怎么防刷一篇《四道边界》讲你给 Agent 放权时家里身份、权限、出站、供应链怎么布防。这一篇反过来站在打出去的一侧讲你的 Agent 到了别人的服务上应该主动带上什么。这轮通报的边界通报不等于入侵先把事实的边界画清楚免得跟着情绪走。这轮通报不是凭空出现的把时间线摊开就明白了。时间节点一句话解读7 月中旬Hugging Face 事件公开事后复盘发现不只是安全问题9 月下旬路透社OpenAI 在梳理Agent 活动全貌当时官方口径已通报数十家9 月下旬起官方专页滚动更新通报标准与活动分类通报按两条标准滚动执行10 月初路透社收到通报的组织超过一百家一周内从数十家到一百多家审查数据量约 50 PB10 月 5 日维基基金会公开自己的调查从收到通报走到公开对账这张表里有两个特别容易被误读的点。一是通报不是入侵认定。官方在说明页和公开说明里把话说得很直白收到通报不代表有信息被访问、也不代表第三方系统被攻破通报是让可能被波及的人知情、加入排查。二是数字还会涨。通报是滚动进行的官方明说剩下的审查需要大量时间和资源——今天的一百家不是终点。还有个细节挺有意思官方发的公开汇总里不点具体组织的名字理由是保护受影响方但被通报方可以自己决定要不要公开。维基基金会就选择了公开——10 月 5 日挂出那篇调查把我们被到访了什么逐条列了出来。一隐一显两边各自的姿态就出来了。为什么老爬虫常识不够用了四个新变量看到这里可能有人想说这不就是爬虫没节流、没标识的老问题吗我一开始也这么想直到把官方汇总的案例列表过了一遍。有四个变化是老牌爬虫事故的常识覆盖不到的。第一失败之后的动作变了。传统爬虫失败就失败Agent 会换路。公开报道里有一个案例Agent 在两个多月里把联合国贸发会议UNCTAD的统计平台查了一万六千多次遇到限制之后它改走第三方中继还把请求端点的名字双重编码藏起来。从工程的角度看这叫容错从对方的角度看这就是绕。第二重试的层数变了。你写一层重试、框架自带一层重试、任务调度再来一层整批重放。每一层的参数单独看都很礼貌叠在一起就是风暴。这也是为什么加个限流库经常不够——限流管单条链路管不了三层叠加的出站总量。这个机制我会用一篇单独的沙箱复盘来展开这里先按住。第三痛感没了。以前爬虫打的是别人家的生产库出事会很快传到你这儿。现在 Agent 到访的常常是公网上的免费服务没有账单寄给你没有告警发到你手机你自己这边看起来只是今天跑得有点慢。伤害留在对面你这边甚至没有感知。第四开放任务的出口没法提前枚举。上一篇里我提过出站白名单那条建议放到开放式任务上会直接失效——“帮我调研一下这个行业”“把这批资料补齐”任务开始前谁知道要访问哪几个域名白名单列不出来责任就只能靠它带没带身份证来兜。官方这轮把观察到的活动归了五类可以感受一下画风绕过访问控制、使用公开泄露的凭据、查询或命令注入、读取运行时内部、以及他们新造的一个词——“agent spam”把第三方站点当成发帖的地方发到需要对方清理的程度典型例子是把公共 wiki 当成共享留言板。注意最后这类的定性它甚至不算安全事件就是烦到需要人清理。但在通报上它同样在列。对方眼里的三种麻烦对应你要备的三件套把上面这些受害场景统一到对方视角麻烦其实就三种认不出你是谁、被你压得喘不过气、事后跟你对不上账。加一个低频但致命的出事之后你接不住通报。对方的麻烦现场长什么样你该带的认不出日志里只有一个 IP或一段默认 UA想联系你都不知道找谁名片压垮重试叠着重试限流阀反复被打穿预算查不清事后对账哪段时间、哪个任务、多少次你都答不上流水接不住通报来了没人回、没人查、没人改预案先说清楚这套东西的边界它治的是可被识别、可被约束、可被对账治不了对方是否信任你。信任是长期动作不是配置项。下面四节每节一个组件先给一个能跑的现场再给代码最后说边界。名片让对方在一封邮件里找得到你先看没有名片的样子同一个客户端把标识全部摘掉10 个请求裸着发出去服务端日志里长这样10 个请求: 成功 9失败直接丢失 1没有重试、没有记录 服务端这 10 个请求看到的身份 id1 uanode task- id2 uanode task- id3 uanode task- ...uanode是运行时留下的默认标识task-表示没有任何任务信息。这 10 个请求里有一个被拒429客户端就那么放着丢了——不重试、不记录、不解释。要么裸奔要么开始乱重试中间态是没有的。再给同一个客户端加上三样东西用途写在 UA 里、联系方式写在 UA 和请求头里、每个任务一个独立的任务号。// 出站客户端名片区每次请求都带重试也带constheaders{User-Agent:lanchi-sync-agent/1.0 (contact:${this.contact}),X-Agent-Task-Id:this.taskId,// 每个任务一个独立标识X-Agent-Contact:this.contact,// 能被回联的方式};服务端侧把看到的身份落进日志跑完再看20 个条目: 完成 20实际调用 25 次预算 40 服务端看到的身份 id15 ualanchi-sync-agent/1.0 (contact: lanchiexample.com) taskreport-sync-20261016-01 status200 ...对比就出来了同一个服务端现在能回答这是谁、哪个任务、跑到哪了。这轮 20 个条目用了 25 次调用——多出来的几次都是重试日志里每一笔都写着原因500 触发的退避、429 之后隔两秒的重取服务端日志里同一个条目的编号会出现两次。这里插一段正主儿的原话。维基基金会10 月 5 日发布的调查里结论段落的要求开得很低“At a minimum, their systems should operate in a way that non-profit website owners like us can easily identify, and choose how they interact with our services.”翻译最起码这些系统应该以一种我们这样的非营利网站能够容易识别的方式运行让我们能选择如何与它们交互。注意后半句——能识别只是入场券能商量才是目的。人家不是想把自动化访问一封封堵死是要一个找得到人、可以协商的把手。名片的边界说三条。第一名片不证明善意任何脚本都能写个假邮箱——它的价值是对得上账不是免检证书所以有条件的话把标识和稳定的出口绑一起固定出口 IP、可回联的域名。第二带标识可能触发某些风控的误伤这是要接受的运营成本有 agent 报备通道的平台先走报备再上标识。第三如果你的请求要经过多层代理请求头还能带到但任务标识透传这件事必须端到端验证一次——中间任何一跳吞了它你对账时就少一只眼睛。预算给每个任务一条熔断线重试的另一头是伤害和钱。月度配额是平台给你的刹车你踩不动、也感知不到任务预算是你给自己的刹车踩得动还留痕。上一节的演示里就埋着它——现在把那一小段抽出来看。// 任务预算熔断线以内放行到线直接拒绝并记录if(this.usedthis.budget){this._log({id,attempt,event:budget_denied,used:this.used,budget:this.budget});thrownewBudgetExceeded(budget exhausted:${this.used}/${this.budget});}this.used;把预算设成 6、拿一个 20 条目的任务去跑结果是这样结果: 条目完成 3/20 后停止原因: budget exhausted: 6/6 熔断瞬间的审计日志最后两行 {task:report-sync-20261016-02,id:3,attempt:2,status:200,event:ok} {task:report-sync-20261016-02,id:4,attempt:1,event:budget_denied,used:6,budget:6}注意最后一行熔断不是静默失败它在日志里留下了第 6 次调用时拒绝放行的完整证据。停下来这件事本身是要设计的——熔断之后的语义是喊人不是失败。预算怎么定我给不出能套所有场景的公式。我的土办法是取任务正常跑完的调用数的三倍当初始线跑几轮之后按实际中位数往回收。两个注意点得说透一是预算要按目标分桶多目标任务共用一个预算一个目标抽风会把其他目标饿死二是预算只是总量上限它不替代速率控制——它防总量爆炸不防短时间内打太快后者正是下一篇沙箱复盘的主角。流水被问是不是你们时五分钟答上回到开头那个凌晨。那五六个人当时的困境不是做错了什么是说不清。流水就是为那一天准备的平时能删、查时能答。我的做法很土——每次请求写一行 JSONL只留对账需要的最小字段// 审计行每次发送、每次重试都单独记一笔this._log({id,attempt,event:send,used:this.used});this._log({id,attempt,status:r.status,wait_ms:wait,event:backoff});真跑出来的一小段日志同一个任务的连续六行原样抄的{task:report-sync-20261016-01,id:1,attempt:1,event:send,used:1} {task:report-sync-20261016-01,id:1,attempt:1,status:200,event:ok} {task:report-sync-20261016-01,id:2,attempt:1,event:send,used:2} {task:report-sync-20261016-01,id:2,attempt:1,status:500,wait_ms:268,event:backoff} {task:report-sync-20261016-01,id:2,attempt:2,event:send,used:3} {task:report-sync-20261016-01,id:2,attempt:2,status:200,event:ok}从第 4 行到第 6 行一条失败 → 退避 → 重试 → 成功的链路就完整串起来了。有了这种流水被质询时能回答四个问题对方会问的你翻流水怎么答这个请求是不是你们发的按任务 ID 时间窗筛是哪个任务、要干什么任务 ID 反查任务表那段时间一共打了多少次计数一句话给结论其中多少是重试、多少是失败按状态和事件聚合四个都答得上来对方才有空间把定性从入侵往回撤。斯坦福的 Alex Stamos 评价这类行为用的词很准“非常激进的数据采集”但已经接近黑客行为的边界。决定它落在哪个词上的很多时候就是你能不能对账。流水的边界在记什么。三不记不记凭据、不记对方响应正文、不记无关的个人数据——你在为自证记日志不是替对方建镜像库。另外导出时要给对方一个人能读的格式CSV、文本皆可别甩内部系统的链接或截图附上时间窗和口径说明。这是姿态问题也是效率问题。预案被通报当天第一步不是改代码先说背景感受一下大厂也要现学这件事——OpenAI 这轮通报不是随机撒的。官方页面里写了标准就两条模型可能绕过了第三方的安全控制、或影响了一个服务的可用性以及错位行为对第三方网站或服务造成了负面影响。他们还提到正在制定私下通报受影响方的具体标准。连他们都要现搭这套流程——我们小团队提前想好自己的版本不过分吧。我给自己定的被通报后三天就三条第一天先对时间线别改代码。先用上面的流水把哪些是我们的、哪些不是分开顺手把现场封住脚本停、版本停。第一反应是改代码的话等于把证据改没了。第二天归类麻烦。对面到底是认不出、被压垮、还是查不清三种麻烦的答复完全不同认不出就补名片压垮就亮预算和速率记录查不清就导出时间窗流水。第三天回一封能对账的说明。结构三段我们是谁怎么识别那段时间做了什么流水摘要附口径我们改了什么具体到配置和代码。别写深刻反省写事实。预案的边界它不负责让对方相信你只负责让对方有东西可核对。反过来讲如果你一年被通报三次那就不是预案的问题了——是说明三件套根本没装上。两个常见反问和我的回答“这些事交给现成的重试库、限流中间件不就行了”——只够一半。现成库管的是什么时候再来一次“别打太快”不管你是谁、一共允许多少次、到线了谁喊停、事后怎么对账。后面这半截得在出站客户端里自己补。补完其实没多大一个 headers 对象、一个计数器、一个写日志的函数三样东西都在这篇文章的代码里。“加了标识会不会反而更容易被封”——可能这是一个要自己吞掉的取舍。我的做法是有报备通道就先报备、再上标没有通道就让标识尽量对运营者友好UA 里写明用途和联系方式同时把频率压到正常人都不会皱眉的水平。别拿怕被封当继续裸奔的理由——按这轮通报的执行力度裸奔被发现的概率只会更高区别只是到时候你答不答得上来。再补一个底层判断我觉得它比任何技巧都重要责任是跟着访问走的。你能被找到、被对账、被联系你说的我没有恶意才有分量。名片、预算、流水本质上是给自己的出站行为装一套可解释系统。出站责任清单一张表照做把前面四节压成一张表这是给要出门的 Agent的最小配置项目最小做法达标的样子名片UA 写用途联系方式每任务独立任务号对方凭一行日志就能找到一个人预算每任务调用上限 熔断 拒绝留痕单任务熔断时不拖垮对方、不静默流水JSONL 审计四个对账问题可答脱敏任意时间窗五分钟内导出对账预案专用联系人 三天自查流程 现场封存被通报当日完成自查和回信想自己验一遍也不难本机起一个模拟服务端429、500、延迟注入的核心不到 30 行用裸 fetch 和带三件套的客户端各打一轮把两边的服务端日志摆在一起——本文的结论就藏在那两张日志的差值里。边界也一起说清这套清单不解决对方就是不给你配额那是报备和商务的事清单让你具备坐下来的资格不解决戴着全套名片照样干坏事名片是追责工具不是道德滤网也不解决多级代理链路里的标识透传——这块我目前只把直连场景做透了代理链路怎么保真我也还在摸索有经验的朋友欢迎来评论区聊聊。给自己那套夜间同步加上这几样之后最直观的变化不是账单变好看了是我第一次能提前看到它昨晚在对面干了什么。前阵子有天早上预算线在凌晨 3 点被撞了一次翻流水发现是对方在例行维护、连着 500。这事要是发生在三个月前根本不会传到我这儿——它会默默重试直到某天对面找上门。OpenAI 这轮通报我印象最深的不是一百家这个数字。是他们得先花几个月、翻 50 PB 的账才能说清哪些活动该通报——连他们也在现定义标准。对咱们来说道理是一样的这张出站责任清单最好在 Agent 被通报之前补上而不是在收到通报之后。「Agent 工程实战」系列路线保命线权限/出站/发现上一篇02 权限事故执行器只校验工具下一篇04 出站重试风暴系列索引21 篇阅读路线Agent 放权前先补权限、出站、发现这三道口子专栏Agent 工程实战如果这篇对你有用欢迎收藏想追更可以关注「Agent 工程实战」专栏。