文章将注册验证邮箱视为有状态队列,分析工具重试、多个工作进程争抢同一邮件及历史邮件残留造成的误判。它提出明确邮件领取权限、有效时间和交接证据,避免查询与使用之间的竞态。
一个测试注册流程的 LLM Agent,看起来通常很简单:创建账号、等待邮件、提取链接,再确认能否访问。问题出现在 Agent 重复调用同一个工具、两个 worker 看到同一封邮件,或者邮箱里还留着上一次运行的邮件时。
到了这一步,读取邮件就不再是一个无关紧要的操作,而是一个有状态的操作。Agent 需要知道自己可以认领哪封邮件、认领有效期有多长,以及应该向下一步返回什么证据。没有这样的契约,测试可能因为使用了旧邮件而通过,也可能因为邮件已被另一次尝试认领而失败。
测试邮箱很像一个队列,尽管我们通常只是把它当作普通收件箱。一个典型流程包含以下阶段:
竞态发生在第 3 步和第 4 步之间。如果两次调用都先执行 list_messages,然后尝试打开同一封邮件,双方都可能认为自己有权处理它。还有一种时间上的竞态:正确的邮件已经到达,但搜索先返回了一封主题相似的旧邮件。
因此,最好把一次性邮件看作本次运行的资源,而不是永久保存的数据。临时邮箱生成器可以创建邮箱,但测试系统仍然需要决定每次读取由谁负责。
这份契约不需要庞大的平台。对于每次运行,我至少会保存以下信息:
收件地址和主题可以用来寻找候选邮件,但不足以唯一标识一封邮件。两封邮件可能具有相同的地址和主题。如果应用能在邮件头、测试 token 或 metadata 字段中包含 run_id,Agent 也应该核对它。
这条原则很适合需要提供有效证据的邮件验证流程:仅仅说“我找到了一封邮件”还不够,还必须解释为什么这封邮件属于本次运行。
关键操作不是 get_message,而是 claim_message。认领操作会以原子方式改变状态,并为 Agent 提供一个短暂的处理窗口。
{
"operation": "claim_message",
"mailbox_id": "mbx_42",
"run_id": "run_20261014_001",
"filters": {
"recipient": "qa@example.test",
"subject_contains": "Verifica tu cuenta",
"received_after": "2026-10-14T06:00:00Z"
},
"lease_seconds": 90
}
成功响应必须包含稳定的标识符和租约到期时间:
{
"status": "claimed",
"message_id": "msg_884",
"lease_until": "2026-10-14T06:02:11Z",
"body_excerpt": "Confirma tu cuenta..."
}
同一次运行的第二次调用应该返回 already_claimed,而不是另一封邮件。如果 Agent 成功完成操作,就调用 consume_message。如果它崩溃或耗时过长,租约就会到期,再由受控策略决定是否允许重试。设置这样的边界,比放任无限重试更好,否则最终看起来就像是服务提供商出了故障。
相比含糊的文本,明确的结果更有利于 Agent 工作。我会区分以下四种情况:
我不会在每次调用时返回整个邮箱。这样不仅会占用大量上下文,还会增加模型选错证据的可能性。只返回候选邮件、邮件距今的时间、收件人和状态的摘要,会更容易推理。
Agent 也不应该凭空声称某个链接已经通过验证。工具必须返回一份回执,例如包含 message_id、run_id、claimed_at 和 consumed_at。这份回执可以附在测试结果中,供后续检查。
在真实 API 中,我会通过条件操作实现 waiting -> claimed 的状态转换:UPDATE ... WHERE status = 'waiting'。在 Redis 中,使用带过期时间的 SET,并为每个 run_id 设置一个 key,就能覆盖较短的处理窗口。SQL 表更便于审计;Redis 的延迟更低。如何选择,取决于你需要对失败的运行进行多深入的调查。
我会设置以下检查点:
QA 数据中有时会出现人工填写但不够规范的值,例如 tempail mail 或 temp gamil com,尤其是在旧 fixtures 中。它们不应该导致 parser 出错,也不应该成为搜索条件。最好把它们作为测试数据处理,并标明来源,仅此而已。
这种隔离也有助于测试 onboarding,避免污染指标。如果 Agent 使用的账号和邮件与真实流量相互隔离,测试结果就更容易解释。
不能。队列负责执行任务;租约负责控制谁可以消费某封邮件。这是两个不同的问题,可以相互配合。
先从 60 到 120 秒开始,再进行测量。窗口太短会导致不必要的过期;窗口太长则会占用资源,并掩盖 Agent 卡住的问题。
不一定。标记为已消费可以保留证据。出于隐私考虑,删除邮件可能有必要,但应该先保存最小回执,再按照既定的保留策略处理。
核心想法很简单:Agent 需要的不是“查看 inbox”,而是在明确的边界内获取证据。当邮箱提供状态、lease 和回执时,重试就不再难以解释,自动化也会变得更可预测。
如需进一步采取行动,可以考虑屏蔽此人和/或举报滥用行为。