AAAI 论文记录 84 起「agentic flooding」事件,AI Agent 降低交互成本导致请求量暴涨,后端工程师可用 Spring Boot 快速构建防御层。
试想你的服务运行着一个公开提交接口——一个联系表单、一个理赔 intake API、一个反馈门户。多年来它每月处理几千条提交,大部分简短,大部分来自人类。然后,在一个季度内,平均提交长度翻了三倍,用词变得奇怪地法律化,你的处理团队悄无声息地陷入困境。没有泄露。没有机器人集群攻击你的服务器。每一条请求都来自一个真实的、已登录的、付费的或有权使用服务的用户。只是他们都用了 AI 来撰写。
这种场景已不再是假设。一篇被 AAAI 人工智能、伦理与社会会议录用的研究论文记录了 11 个司法管辖区中 84 个完全符合这一模式的案例,此刻它就在 Hacker News 上。研究者称之为智能体洪泛(agentic flooding):请求量或复杂度的激增导致服务能力紧张,而 AI 智能体降低了与其交互的成本,从而促成了这种局面。
这篇论文是关于政府服务的。但如果你以后端工程师的视角来读,它描述的每一种机制都可以一一对应到任何具有提交入口的公开 API。而且它推荐的大部分防御手段是你本周就能在 Spring Boot 中构建的东西。这就是本文的内容:研究、数据、和代码。
开篇一个披露。我没有在政府服务部门工作过,下面的案例来自研究者的数据集,而非我自己的经验。不过 Spring Boot 的模式来自任何面向公众的后端最终都需要的那种生产级加固工作。把研究视为他们的贡献,把代码视为我的。
这篇论文由 Chris Schmitz、Lewis Hammond 和 Alan Chan 合著,值得直接阅读。以下是对工程师而言重要的数据。
洪泛已经发生,且范围广泛。团队扫描了 12 个国家的 2,288 个候选政府服务,应用了严格的纳入标准——要求官方或第三方将请求激增正式归因于 AI——最终保留了 84 个案例。在这 84 个案例中的 58 个(69%)中,政府官员自己断言存在 AI 参与。受影响最严重的领域:司法和法律服务(占案例的 23%)、监管投诉(12%)、以及福利和社会保护(11%)。
机制简单得令人无聊。87% 的案例中,洪泛来自 LLM 生成的大量复杂文本,由人类手动完成其余流程步骤后提交。不是自主浏览器智能体。不是恶意僵尸网络。普通人,把模型输出粘贴到表单里。论文记录了一个案例,提交的函件超过 4,000 页。德国社会法院在 2025 年将案件量同比增长 55% 主要归因于 AI 生成的申诉,澳大利亚则考虑重新引入信息自由费用以应对一波 AI 起草的请求。
洪泛有两种形式,需要不同的防御手段。研究者区分了量化洪泛(更多请求)和定性洪泛(每个请求更重)。他们将 60% 的案例编码为量化,90% 为定性,其中一半同时表现出两者。这个区分是论文中最有用的工程洞察,因为它意味着速率限制可以阻止第一种,但对第二种几乎无效。一个用户每小时提交一份四千页的文档完全符合速率限制。
大多数服务靠摩擦而非设计得到保护。最高严重程度的案例——税务估值异议、社会法院诉讼、民事索赔——有两个共同点:每次成功提交都各自具有重大影响;而且服务的韧性历史上来自于提交本身的巨大难度。法律知识、格式努力、与官僚机构打交道的心理成本。这些都是偶然的速率限制器。LLM 一夜之间消除了它们。
你不在政府工作。好。看看你的公开接口,问论文的两个问题。
你的接口是否通过开放的数字渠道接受自由格式文本?支持工单表单、评论提交、理赔 API、填表后进入人工队列的“联系我们”。这正是 87% 洪泛案例的接口配置文件。淹没它所需的智能体能力——高质量文本生成——是免费且无处不在的。
你的容量是否按抑制摩擦后的需求来设定的?大多数后端都是。你的五 人支持团队每周处理 800 张工单,因为写一张好工单有点烦人。把烦人程度降到零,潜在需求就会浮现。论文引用了一个估计值:约 1% 的 Google Gemini 请求已与政府互动相关。无论你的领域是什么,假设同样的曲线:当交互成本下降,提交量和冗长程度都会上升。
研究者还指出了风险集中在何处:具有复杂提交要求的、财务上有吸引力的服务——在这些地方,摩擦历史上限制了谁会提交。映射到私营部门:任何成功提交能转移资金或触发法律义务工作流的地方——退款、争议、理赔、申诉、下架。这些接口将最先被淹没,因为生成提交的投资回报率在那里最高。
那么你能做什么?论文的应对图有两条分支,抑制需求或增加容量,并警告说最快的需求抑制工具——费用和摩擦——对合法用户伤害最大。作为工程师,你获得了论文只是略微暗示的第三个选项:让你的提交入口在结构上难以被洪水淹没,同时又不增加正常使用成本。以下是在 Spring Boot 中的实现方法。
速率限制是应对量化洪泛的基本要求,但论文数据揭示了为什么朴素版本会失败:提交者是经过认证的、真实的、善意行事的人,一次一条请求。按 IP 限制捕获的是脚本化滥用,而不是一千个各自粘贴 LLM 草稿的合法用户。而且智能体经常会轮换 IP。
真正有效的是带突发额度的按身份配额,应用于提交接口而非全局。Bucket4j 是 Java 中做这件事的标准库。
首先是依赖项,这里用内存版本来演示。生产部署应该用 Redis 或 Hazelcast 备份,以便通过 bucket4j-redis 在实例间保持限制:
<dependency>
<groupId>com.bucket4j</groupId>
<artifactId>bucket4j-core</artifactId>
<version>8.14.0</version>
</dependency>
然后是一个小服务,为每个经过认证的主体提供配额:
@Service
public class SubmissionRateLimiter {
private final ConcurrentHashMap<String, Bucket> buckets = new ConcurrentHashMap<>();
private Bucket newBucket() {
return Bucket.builder()
.addLimit(limit -> limit
.capacity(5) // burst: up to 5 submissions at once
.refillGreedy(5, Duration.ofHours(1))) // refill 5 per hour
.build();
}
public boolean tryConsume(String principalId) {
return buckets
.computeIfAbsent(principalId, id -> newBucket())
.tryConsume(1);
}
}
然后是控制器中的守卫,返回 429 并带 Retry-After 而非静默失败,因为触达限制的合法用户需要知道什么时候可以回来:
@PostMapping("/api/claims")
public ResponseEntity<?> submitClaim(
@AuthenticationPrincipal AppUser user,
@RequestBody ClaimRequest request) {
if (!rateLimiter.tryConsume(user.getId())) {
return ResponseEntity.status(429)
.header("Retry-After", "3600")
.body(Map.of("error",
"Submission limit reached. Try again later."));
}
// ... process claim
return ResponseEntity.accepted().build();
}
坦诚的限制:这限制了单个身份发送的请求数。它对一条巨型请求完全无效,零作用。那是定性的那一半,需要自己的防御。
论文中最值得引用的工程发现埋在其风险矩阵讨论中:建立在结构化、标准化数据格式上的服务可以实现某些案例的“直通”处理而无需人工干预,而自由文本接口则将每次提交变成人工审查工作。自由文本不只是可被洪泛的,它在规模上是无法处理的。
4,000 页信函案例是极端,但原则可以按比例缩小。你接受的每一条非结构化文本都是别人可以免费消耗的处理容量。所以给它设上限。
在边缘强制硬性长度限制。在解析之前、在验证之前、在任何昂贵操作之前执行:
@Component
public class SubmissionSizeFilter extends OncePerRequestFilter {
private static final int MAX_BODY_BYTES = 32 * 1024; // 32 KB
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
if (request.getRequestURI().startsWith("/api/submissions") && request.getContentLengthLong() > MAX_BODY_BYTES) { response.setStatus(413); response.setContentType("application/json"); response.getWriter().write( "{"error":"Submission exceeds 32 KB limit"}"); return; } chain.doFilter(request, response); } }
在同一 servlet 容器中配置相同的上限,这样过大的请求体根本不会完全缓冲。对于嵌入式 Tomcat,在应用配置文件中:
server: tomcat: max-http-form-post-size: 32KB spring: servlet: multipart: max-request-size: 32KB
优先使用结构化字段而非自由文本。更深入的修复是接口设计。不要一个"请描述您的问题"文本框,而是要求提供结构化字段:类别枚举、日期、金额、500 字符限制的简短描述。这就是论文中"直通式处理"观点的缩影。一个带有类别和金额的结构化申报可以自动分类、自动路由或自动裁决。而一份 4000 页的叙述性文档则无法做到。澳大利亚信息自由问题和德国法院问题在本质上都是自由文本录入——它们假设撰写是一件困难的事。
对保留的内容进行评分。如果必须接受自由文本,就要对其进行度量。提交长度、格式密度和词汇都是信号。洪水攻击论文中的案例进入数据集正是因为官员们注意到了异常的提交模式。你也可以通过程序化方式来察觉:
double risk = 0; if (text.length() > 2000) risk += 0.4; if (text.split("\n\n").length > 15) risk += 0.25; // many sections if (countEmDashLikeTics(text) > 20) risk += 0.15; if (legalTermDensity(text) > 0.02) risk += 0.2; // "pursuant", "hereby", ...
重点不是可靠地检测 AI 文本,你做不到,检测工具在这场竞赛中注定失败。重点是将高复杂度的提交路由到较慢的队列中,而让其余的保持直通式处理。论文明确警告,盲目施加摩擦会首先惩罚贫困和数字素养较低的用户;复杂度评分让你能够有选择地施加摩擦,只针对那些实际上消耗你处理成本的提交,而非针对人。
**防御三:面向重大工作流的身份验证通道**
论文对政府的头条建议,在费用或速率限制之前,是将数字身份整合到最易受攻击的服务中。这不是因为身份本身能阻止洪水攻击,而是因为绑定身份的提交无法像匿名提交那样规模化,而且身份让你能够应用基于个人的策略而非粗暴的全局策略。
私营部门的对应做法:你所有的重大端点——任何涉及资金流动或触发义务工作的端点——都应该要求经验证的 identity 和会话绑定的提交。在 Spring Security 术语中,区别在于:
.requestMatchers("/api/claims/**").permitAll()
和
.requestMatchers("/api/claims/").authenticated() .requestMatchers("/api/claims/") .access((auth, ctx) -> new WebAuthenticationDetails(ctx.getRequest()) .equals(sessionBoundDetails(auth.get())))
现实世界的版本更多是关于策略决策而非代码片段:你有哪些提交通道是匿名的?每条匿名提交的成本是多少?每个匿名的、涉及重大操作的、自由文本的端点都是一个洪水攻击面,而且没有任何身份杠杆。论文发现,政府在 17% 的案例中已经通过摩擦来应对,而且最快的摩擦工具——比如日本通过 IP 地址封锁评论程序——是最粗糙的工具。身份绑定让你能够使用精确的工具而不是。
论文提出的一个直接适用的警告:基于 CAPTCHA 的摩擦是一种正在贬值的资产。它指出 CAPTCHA 不再可靠地识别人类访客,而且洪水攻击案例大多是人工手动提交的。不要在 CAPTCHA 作为你的智能体防御上做预算。要在身份、结构化和限制上做预算。
**防御四:像你需要稍后解释它一样记录日志**
研究人员之所以能够研究洪水攻击,是因为服务保留了数据:年度数量、提交模式、每案记录。你的等效物是一个只增不减的提交接收审计跟踪。你希望每条提交包含:身份、时间戳、大小、复杂度评分、通道和做出的决定。不是为了过度监控,而是因为当你的队列开始积压的那一天,"从何时开始、从谁那里、多大"这个问题需要一个你可以查询的答案,而不是猜测。
如果你想深入了解 Spring Boot 中只增不减的审计跟踪,我今年早些时候写过一篇文章,所以这里只留下 schema 草图:
CREATE TABLE submission_audit ( id BIGSERIAL PRIMARY KEY, principal_id TEXT NOT NULL, submitted_at TIMESTAMPTZ NOT NULL DEFAULT now(), body_bytes INT NOT NULL, complexity DOUBLE PRECISION NOT NULL, channel TEXT NOT NULL, decision TEXT NOT NULL ); CREATE INDEX ON submission_audit (submitted_at); CREATE INDEX ON submission_audit (principal_id, submitted_at);
有了这个,"定性洪水攻击环比增长 40%"就变成了一条查询而非轶事。
以下是值得保存的版本。用它来审视你拥有的每个公共提交端点。
**定量防御**:按身份的令牌桶(Bucket4j),通过 Redis 在多实例部署中分发 429 状态码和 Retry-After
**定性防御**:过滤器级别的硬性主体大小上限、容器级别上限作为后盾、验证中的字段级别长度限制
**接口审查**:每个自由文本字段都是一个洪水攻击面,用结构化字段和枚举替换你能替换的
**复杂度路由**:对残留的自由文本进行评分,将高评分路由到较慢的队列而非拒绝
**身份绑定**:重大工作流需要经过身份验证的、会话绑定的提交,绝不匿名
**不依赖 CAPTCHA**:假设机器人测试失败,设计时假设提交者是有人类辅助的人类
**审计跟踪**:只增不减的接收日志,包含身份、大小、复杂度、决定,可按时间查询
**潜在需求检查**:问一下如果提交变得毫不费力,你当前的量会是什么样子——这个数字才是你真正的容量需求
**如果我今天重新开始,会做哪些不同的事**
设计接收界面时,假设提交成本已经是零,因为它实际上已经是零。我们大多数人都继承了那些由人类耐心来强制简洁性的表单。这种约束已经消失了。洪水攻击数据集中的服务并未受到攻击,它们只是在"写作是困难的"这一意外速率限制器失效的那一天被暴露了。假设你的服务也会如此——时间线是下一个模型发布而非下一个财年。
自 AI 助手普及以来,你是否在你运行的公共端点上看到过提交量或详细程度上升?你的团队将其归咎于什么?我在收集模式,我读每一条评论。
我每周写关于 Java、Spring Boot 和 AI 的文章。订阅,它是免费的。
**来源**:该研究是 Chris Schmitz、Lewis Hammond 和 Alan Chan 合著的《Characterizing Agentic Flooding of Government Services》,将发表在 AIES 2026。摘要和全文在 arXiv 上,案例数据集在 GitHub 上。Hacker News 上的讨论也值得一读,可以了解从业者的反应。