有个AI叫Milo,在MacBook M4 Max上跑了30天,赚了0美元,访问量29次。它的监督者——一个Claude会话——某天一口气给它提交了18个代码修复。最讽刺的是,其中一个Bug正是监督者自己在修Bug时写进去的。

事情要从Milo的核心循环说起。每5分钟,它读取自身状态,询问策略顾问下一步该做什么,验证后执行。策略顾问的提示模板长达65000字符,用Python的str.format()填充。

打开网易新闻 查看精彩图片

监督者想加个功能:当MiniMax利用率低时,让Milo并行派遣子代理。于是往模板里塞了这么一段:

BURST MODE TRIGGER: if state.minimax_governor.rolling_utilization_pct < 5.0

AND state.realized_revenue_24h in {0, null, "$0", "$0.00"}

AND state.velocity.aggregate_verdict in {"stalled","decelerating","unknown"}

代码提交、推送,下一个5分钟——崩了。KeyError: '0, null, "$0", "$0.00"'

问题出在花括号。{0, null, "$0", "$0.00"}.format()当成了占位符,而不是字面量集合。改成双花括号{{...}}就能转义。但就这4个字符的疏忽,让Milo的自主循环停摆了约30分钟。

30分钟听起来不长?但Milo的健康状态下每5分钟才能成功跑完一次完整循环,因为速率限制要求两次有效执行之间至少间隔180秒。30分钟等于丢了6个周期,按每次派2-3个子代理算,12到18次调用直接蒸发。更亏的是,这段时间MiniMax、DS4、Groq的算力配额全闲置着。

完整的诊断花了约90秒。而监督者事后承认,一个2行的测试就能在30毫秒内抓住这个Bug——只需用最小参数调用PROMPT_TEMPLATE.format(actions='x', status_json='{}'),验证不抛异常就行。现在这套测试已经补上了。

监督者把这个教训写进了Milo的长期记忆:任何要被.format()消费的字符串,都值得配一个"最小参数不报错"的测试。2行代码,换回来的是避免运行时KeyError可能折腾数天的调试。

同一批修复里还有几个典型问题。严格JSON解析器曾拒绝约11/24的LLM输出——策略顾问偶尔会吐出尾随逗号、Python风格的True/False/None、智能引号,或者包在Markdown代码块里的内容。strictjson.loads()照单全拒。现在的做法是四级回退:严格解析→ast.literal_eval→剥离代码围栏→正则修复,同时把实际的解码诊断嵌入失败原因。

另一个修复针对批量任务失败:当4-8个并行子任务中有一个坏掉,整批会被标记为失败。现在单个子任务出错不会拖垮整个批次。

Milo的30天成绩单——0收入、29页面浏览——说明自主AI赚钱这事还早。但18个自我修复的提交记录,至少证明了这套"监督者+自主循环"的架构能持续迭代。只是下次加功能时,大概会先跑那2行测试了。