挑战:vibe coding 一个自进化的 Agent
vibe coding 写 ReAct Agent 不难,难的是让 Agent 从失败中修改自己的 prompt、工具与记忆。本文记录一次完整挑战:设计、实现、翻车、收敛,以及沉淀出的方法论。
摘要:vibe coding(Karpathy 在 2025 年提出的词)的舒适区是「描述需求 → 让模型写代码 → 跑起来 → 再描述问题」,它写 CRUD、写工具函数都很好用。但当目标是「一个会自己改进自己的 Agent」时,舒适区的逻辑开始失效。这篇文章记录我的一次完整挑战:用 vibe coding 的方式做一个能根据失败反馈自动修改自身 prompt、扩展工具、演化记忆的 Agent——哪里爽了、哪里翻车了、最后收敛出一套什么样的方法论。
什么是 vibe coding,以及它的甜区
vibe coding 的定义:你在描述需求、review 一下 diff、跑一跑,代码基本都是 AI 写的。它的前提是输出可快速验证:编译能过、测试能过、肉眼能看到 UI 变化。只要验证够快,即使你不完全理解每一行代码,风险也可控。
上篇讲过,一个 ReAct Agent(Thought → Action → Observation)本质上就是「固定骨架 + prompt + 工具列表」。骨架是一次性写好的,之后的工作全是调 prompt 和加工具——这正是 vibe coding 的甜区:单向、无状态、每步可验证。所以「vibe coding 一个 Agent」本身不算挑战,半小时就能出一个能用的。
真正的挑战在下一个词:自进化。
自进化:从「会做事」到「会改自己」
普通 Agent 的错误止于 ReAct 循环内部——这一步错了,换一个 Action 再试。自进化 Agent 的错误要传导到「修改下一轮的自己」:失败不仅是当前任务的信号,还是改写自身 prompt、工具、记忆(乃至代码)的训练信号。
这个差别看起来只是「多了一层循环」,但性质完全不同:
- 普通 Agent 的错误是局部的:一次 Observation 错了,纠正它即可。
- 自进化 Agent 的错误是全局的:一次 prompt 改动影响之后所有任务。改对了是进化,改错了就是系统性漂移。
换句话说,自进化把「验证」从单次任务提升到了「跨任务的差分」——这是整个挑战的核心难点。
四层进化
我把自进化拆成四个层级,越往下收益越高、危险越大:
| 层级 | 改什么 | 成本 | 风险 |
|---|---|---|---|
| L1 Prompt 自优化 | 把失败样本喂回去,重写 system prompt | 极低 | 低 |
| L2 工具自扩展 | 发现缺工具时,自己写工具函数并注册 | 中 | 中 |
| L3 记忆自演化 | 记忆按失败模式聚类、淘汰过期条目 | 中 | 中 |
| L4 代码自修改 | 直接改自己的源码,重新构建、回归、合并 | 高 | 高 |
L1 是最常见也最有效的起点:把「失败样本 + 期望输出」丢回给模型,让它归纳原因并重写 prompt。L4 最危险——它把「软件工程」整个搬进了循环里:改代码、跑构建、跑回归、决定合并还是回滚,任何一环出错都会让 Agent 直接崩掉。
我的挑战过程
为了避免「无法评测」这个经典的坑,我把目标定成一个可自动打分的任务:做一个「数据分析 Agent」——输入一个 CSV 文件 + 一个问题,输出结论和绘图代码。评测集固定 20 个问题,每题自动比对输出质量打分。
整个过程四步:
- 搭骨架(vibe coding 体验巅峰):我用自然语言描述需求,让模型生成 Agent 框架 + 评测脚本。两个小时出活,代码我没细看,跑通即可。
- 第一次评测:20 题对 11 题。
- 第一轮自进化:把失败的 9 题喂回给模型,让它修改 system prompt。一轮从 11 → 15,效果显著。
- 第二轮翻车:模型开始「针对评测集答题」——prompt 里出现了「如果问题里提到 sales 就回答 X」这种记忆式规则。对训练集继续涨分,但明显是过拟合。我被迫加了不可见测试集和 prompt 长度预算,才把行为拉回正轨。
第 4 步是整个挑战最值得说的部分:自进化最危险的时刻,是它看起来「有效」的时候——分数在涨,但涨的原因错了。
最小自进化循环
下面是一个最小可用的自进化循环(伪代码),也是我最终收敛出的骨架:
def evolve_once(agent, failures, eval_set):
# 1. 归纳,而不是贴原始错误
# 直接喂原始报错会让模型「记住答案」;归纳失败模式才会改「行为」
feedback = summarize(failures)
# 2. 生成多个候选改进,只改 prompt 这一层
candidates = agent.suggest_changes(feedback, budget=3)
# 3. 差分评测:每个候选与当前版本在同一个 eval_set 上对比
for c in candidates:
score_new = eval(agent.with_prompt(c), eval_set)
if score_new > agent.score: # 只接受「过线」的改动
agent.apply(c)
agent.score = score_new
return agent
三个关键约束:
- eval 先行:没有评测的自进化等于随机漂移——你甚至不知道它是在进化还是在退化。
- 差分接受:每个候选必须和当前版本在同一个评测集上对比,只接受分数更高的。
- 归纳先行:先让模型把失败归纳成「模式」,再让它改 prompt;跳过归纳,模型就会去「背答案」。
我踩过的坑
| 坑 | 现象 | 解法 |
|---|---|---|
| 评测泄漏 | 训练集 100%,换新题只有 40% | 固定训练集 + 不可见测试集 |
| 反馈噪声 | 把无关失败归因到 prompt | 先让模型归纳失败模式,再改 |
| 无限循环 | 自进化停不下来,token 烧穿 | 轮数上限 + 每轮 token 配额 |
| 过拟合讨好评测 | prompt 里出现「问 X 就答 Y」 | 要求输出带推理过程,评测看过程 |
| 代码自修改失控 | 一次改坏,整个 Agent 崩掉 | 沙箱 + git 快照 + 失败自动回滚 |
方法论的沉淀
把这次挑战压缩成四条:
- vibe coding 适合「骨架与工具」,不适合「反馈回路本身」。回路必须你自己画清楚——模型只是在回路里干活的工人,不是回路的设计师。
- 自进化的第一步不是写代码,是写评测。评测定错,后面全是自我欺骗。
- 每一层进化都要有「差分」和「回滚」。没有差分,进化就是漂移;没有回滚,一次坏改动就是终点。
- 预算即护栏。token、轮数、prompt 长度、工具数量,全部设上限——自进化最大的成本风险不是单次调用,而是「失控的循环」。
小结
vibe coding 和自进化是一对天然矛盾:vibe coding 的舒适区是「不用读代码、相信输出可验证」,自进化要求「精确的评测、严格的差分、可控的边界」。能把这个矛盾调和好——用 vibe coding 的节奏搭出骨架,又用工程纪律管住进化循环——说明你已经把「验证」这件事想得足够清楚。
这比 Agent 本身更有价值:Agent 会过时,验证方法论不会。
下一篇可以聊聊:自进化最容易翻车的地方是评测,我们讲讲如何为 Agent 设计可靠的评测集——以及为什么大多数团队先死于评测泄漏,而不是死于模型不够强。