用假时钟复现突发流量来验证AI生成的token bucket,再用真实HTTP环境捕获状态码和时序错误,两步走才能覆盖单位测试盲区。
从你想要捕获的失败出发,而不是从模型的置信度出发。限流器有一个恼人的特性:它的大部分行为在客户端刚好越过边界的那一刻之前都是不可见的,而一旦在生产环境中越过边界,损害就已经堆积出一堆 429、 重试请求和支持工单了。审查 AI 编写的令牌桶限流器的一种低成本方法是给它一个假时钟,然后重放一个设计好的突发流量,因为常见的缺陷隐藏在边界间距、key 隔离以及墙上时间(wall time)和测试时间之间的差异中。然后,当本地测试通过后,把同一个生成的限流器部署到一个临时服务器上,通过真实的 HTTP 发送相同的序列,以捕获单元测试永远看不到的状态码、响应头和时序错误。
你只需要很少的胶水代码就能做到这一点。MonkeyCode 的免费模型访问和免费服务器选项为你提供了一个生成候选限流器的地方,以及一个不触及生产环境就能运行它的地方。披露:本文是 MonkeyCode 产品推广的一部分。重点不是信任生成器,而是让生成的产物在你控制的条件下证明一个狭义属性。
首先让模型为一个小型 HTTP 服务生成一个令牌桶限流器,并增加一个塑造整个审查过程的要求:生成的代码必须接受一个时钟作为参数,而不是直接读取系统时钟。这一单个要求比要求生产级代码更有价值,因为它使时序变得确定,并将限流器中最难测试的部分变成一个你可以测试的纯函数。一个典型的生成的 TokenBucket 类会维护一个表示上次补充时间的浮点数,如果它在 allow(key) 内部调用了 time.time(),你应该推动模型或直接修改代码,直到时间戳从外部传入。
假时钟不是 mocking 库意义上的 mock。它是一个知道当前虚拟时间并能按你选择的量向前移动的小对象。在测试中,你组装一个事件时间线,将时钟推进到下一个事件,调用限流器,并记录每个请求是否被允许。下面的测试套件故意做得足够小,可以粘贴到一个临时文件中:
class FakeClock:
def __init__(self):
self.now = 0.0
def sleep(self, seconds):
self.now += seconds
def time(self):
return self.now
def send_burst(allow, timeline):
clock = FakeClock()
results = []
for at, key in timeline:
clock.sleep(at - clock.now)
results.append((at, key, allow(key, clock.now)))
return results
allow 函数是你的生成限流器暴露的任何接口,timeline 是虚拟时间和 key 对的列表。因为时钟按照你指定的顺序前进,通过或失败的序列在每次运行中都是可重现的,这意味着你可以将失败的用例保存在你的代码库中,而不是试图从记忆中解释一个不稳定的生产事故。
能发现大多数错误的那个突发流量不是随机负载测试。使用一个短时间线,结合一个满桶、一次边界补充、两个交错的 key 和一段较长的静默期。对于配置为每秒允许两个请求且突发容量为三的限流器,一个有用的序列可能是:key a 在零、50 毫秒、100 毫秒、450 毫秒、950 毫秒和 1100 毫秒时发出请求。预期模式是允许前三个并拒绝后三个,因为桶的消耗速度快于补充速度。在 450 毫秒时允许第四个请求的模型生成版本可能有四舍五入的时钟算术问题,而因为 key a 耗尽了桶就允许 key b 的请求的版本则混淆了 per-key 状态和全局状态。这些正是快速浏览 diff 时容易漏掉的 bug。
一旦假时钟测试套件变绿,免费服务器就派上用场了。将生成的限流器作为一个小型 HTTP 服务运行,提供一个接受 API key 并返回 200 或 429 的端点,然后让一个小客户端指向它,并用真实的 sleep 重放相同的时间线。这里的目的不是测量容量或证明它能在生产流量下存活;而是观察限流器周围的契约,包括响应体、retry-after header、当 key 缺失时服务器是否崩溃,以及长暂停后的第一个请求是否按照令牌桶的预测行事。一个在免费服务器上的一文件服务就足够完成这个检查,而且它将实验隔离在你的真实 API 之外。
完整的工作流程有四个步骤。用可注入的时钟生成限流器。通过一个确定性的突发流量在本地驱动生成的代码,并断言允许和拒绝的序列。将相同的文件部署到免费服务器上,并通过 HTTP 重放序列,同时记录状态和响应头。如果任何观察到的行为与本地预测不同,就停下来修复生成的代码,然后再和别人讨论。这不是一个让 AI 写你的基础设施然后稍微测试一下的工作流程;它更接近于将生成的代码当作一个不受信任的补丁,必须先通过一个小契约,然后你才花时间审查实现。
这种方法有明确的局限性。假时钟证明了限流器的算术和 key 作用域逻辑,但它不能证明生成的服务在真实并发下是线程安全的,也不能告诉你免费服务器是否有足够的容量来处理你的实际流量。它也不会从以某种方式使用全局变量的限流器中拯救你——只有在许多用户同时在同一个毫秒访问时才会崩溃的那种。如果你正在保护一个支付端点、合规边界或任何坏 429 或意外 200 代价高昂的地方,请使用一个维护良好的限流库或网关功能,并把生成的代码当作学习案例,而不是依赖项。当缺点只是一个有噪声的端点,而且你想在引入真实用户之前快速获得一个关于候选实现诚实的答案时,这个工作流程最有用。
失败预算是一种思维转变。你不是让模型生成一个限流器然后让它给自己的工作打分;而是让它生成一个接受时钟的限流器,然后你用假时钟加免费服务器在错误廉价的地方花费小的失败预算。这给你一个明天可以重复的审查,用不同的时间线、不同的 key 布局或不同的生成实现,而不需要保留初稿的脆弱性。
如果你可以访问 MonkeyCode 的免费模型和服务器选项,最小的有用改变是让生成的限流器接受一个时钟,并在你阅读 diff 的样式之前运行这个重放。审查变成了你的预测序列和观察序列之间的比较,这是一个比代码看起来是否正确更具体、更容易争论的事情。