终身学习智能体根本不需要每次学新东西都重新训练整个大脑,只需要在已有的技能库里不断叠加新代码,像搭积木一样越搭越高,而且永远不会出现学了新招就忘老招的灾难性遗忘。
整个系统就靠三层循环堆在黑盒GPT-4上面,模型权重一丁点都不动,纯靠代码技能库当长期记忆,每次遇到新任务就从库里翻找合适的旧技能组合一下,或者写个新技能加进去,就像一个玩了几千个小时游戏的老玩家,面对新关卡的时候翻自己的招式本子,看一眼就知道该用哪几招连起来打。
五步法
这篇论文的运行逻辑就五步:自己给自己定个任务,写一段代码技能,扔进环境里跑,跑崩了就根据报错自己改,改到通过就把这招存进技能库。
五步蓝图是这样的:
- 自动课程表,模型根据自己现在的状态、手头有啥工具、之前失败过哪些任务,自己给自己出下一道题,逼着自己去探索,从最基础的挖矿一点点往上垒。
- 技能就是代码,行为直接写成可执行代码,不是那些低级动作指令,所以每一招你都能看懂它在干啥,还能跟其他技能拼在一起用。
- 迭代式调代码,代码扔进环境里跑,报错信息和环境反馈全塞回给提示词,智能体就一圈一圈地重写代码直到跑通。
- 自己验证,另设一道检查关卡确认任务真的完成了,才把技能放进记忆里。
- 技能库,所有成功的技能存进一个不断变大的库,每条技能都配好描述和索引,以后遇到新任务直接翻出来用,能力就这么一层层叠上去,完全不用重新训练。
关键洞察是,这个智能体完全不需要动模型权重,一个不断增长的代码技能库就是它的长期记忆,也是它对抗学了新招就忘老招的秘密武器。整套系统就靠在黑盒GPT-4上面跑三层循环,模型权重一丁点都不动。
Voyager:GPT-4驱动,终身学习智能体代码技能库
原文期刊/发表日期: arXiv / 2023年5月25日
原文标题: Voyager: An Open-Ended Embodied Agent with Large Language Models
作者单位背景: NVIDIA、加州理工学院、德克萨斯大学奥斯汀分校、斯坦福大学、威斯康星大学麦迪逊分校
公开页面和代码仓库地址如下:
- 论文原文页面 (arXiv):https://arxiv.org/abs/2305.16291
- 项目官网与开源代码库:https://voyager.minedojo.org/
Loop Engineering(循环工程)是2026年由OpenClaw创始人Peter Steinberger正式提出的AI工程新范式。其核心主张是:你不应该再给编程Agent写提示词,而应该设计一套让Agent自主迭代的循环系统。
调参案例
打游戏卡关的时候你会一遍遍试同一个boss,试到第十次你连自己刚才用了什么技能都忘了。
调参也是这副德行,对着文本块大小发呆,换向量嵌入模型像换装备,加个重排序器跟换宠物似的,跑完一轮评估看一眼召回率就忘了刚才那个配置是啥。
根据“终身学习智能体”写个自动调优脚本,让代码自己在配置空间里跑搜索来调检索增强生成系统,预算控制帮你守住钱包,留出验证帮你揪出过拟合,整个过程就叫循环Loop工程。把调参交给自动脚本,就像打游戏把重复刷怪交给挂机,省下的时间够你刷三集番了。
调参为什么适合交给循环
循环工程的核心规则是:只有当存在一个能自动给出判决的检查时,循环才有意义。RAG调参完美符合这个条件。检查点就是评估集上的recall@k,这是一个赤裸裸的数字,高于阈值就是过了,低于就是没过,没有任何扯皮的空间,跟单元测试变绿一样直白。循环永远知道自己是否达成了目标,这种度量指标天生就适合自动化。
调参本质上是在配置空间里做搜索,而搜索正是循环碾压人类的地方。循环不会疲劳,不会丢失记录,会按部就班地迭代并记住已经试过什么。人类跑到第十轮就开始犯迷糊,满脑子都是“我好像试过800加100加这个embedding?不对好像是600加200”。循环可不会这样,它老老实实把每次尝试都记在日志里,比你的备忘录靠谱一万倍。
起跑线:你得先有个东西能调
循环不负责从零搭RAG,它负责调优一个已经存在的系统。所以出发前你手里必须捏着三样东西。第一个是一个能跑的RAG流水线,参数得能改:chunk size、overlap、embedding模型、候选数k、reranker开不开。第二个是一套评估集,三十到五十个问题,每个问题都得配好一个正确答案所在的源chunk。没有这个评估集,循环就是个瞎子。第三个是一个能跑评估并返回recall@k的函数,这是循环的裁判。
python
# eval.py — 循环的裁判,对某个配置返回recall@k
def evaluate(config, eval_set):
pipeline = build_rag(config) # 用这些参数搭建RAG
hits = 0
for case in eval_set:
retrieved = pipeline.retrieve(case["question"], k=config["k"])
retrieved_ids = {c["id"] for c in retrieved}
if case["gold_chunk_id"] in retrieved_ids:
hits += 1
return hits / len(eval_set)
第一步:划定搜索地盘
循环搜索配置,你得先明确它具体能拧哪些旋钮,以及拧到什么范围。不是无限空间,而是一套确实会影响recall的参数组合。这个搜索空间已经不小了,全量组合有648种,一个个试过去既费钱又犯傻。循环不会做全量扫描,它会更聪明地走,这是后面的事。
python
# search_space.py — 循环要搜索的范围
SEARCH_SPACE = {
"chunk_size": [400, 600, 800, 1200],
"chunk_overlap":[0, 100, 200],
"embedding": ["text-embedding-3-small", "bge-large", "e5-large"],
"k": [5, 10, 20],
"reranker": [None, "bge-reranker", "cohere-rerank"],
"hybrid": [False, True], # 纯向量 或 向量加BM25
}
第二步:一个骗不了的检查
这是循环的心脏。评估集上的recall是个好检查,但发射前得堵上两个坑。第一个坑是对评估集过拟合。循环在评估集上搜配置搜到recall涨了,可能只是恰好在你这四十个问题上表现好,上了生产环境就露馅。这跟代码里的reward hacking是一个道理,只不过这里的度量是个数字。防御手段是把评估集拆成两份,循环只优化其中一份训练集,最终配置在另一份循环没见过的留出集上做验证。
python
import random
def split_eval(eval_set, holdout_frac=0.3, seed=42):
random.Random(seed).shuffle(eval_set)
n = int(len(eval_set) * (1 - holdout_frac))
return eval_set[:n], eval_set[n:] # 前一份给循环调优,后一份留给你做最终验证
train_set, holdout_set = split_eval(eval_set)
第二个坑是测量噪声。只有三十个问题时,recall 0.87和0.90的差异可能纯属随机波动,不是真进步。循环如果对改善阈值设得太小,就会去追这些噪声。防御手段是只把超过合理阈值比如0.02的改善算作有效,否则循环就会在随机波动上瞎折腾,今天调高明天调低,永远不消停。
第三步:带脑子的搜索循环
全量扫648种组合又贵又没必要。循环采用贪心策略,一次只动一个参数:固定其他参数,把当前参数的所有取值都试一遍,挑最好的锁死,然后换下一个参数。这叫坐标下降法,几十次运行就能找到好配置,而不是几百次。
import json |
注意这里的目标检查是每次运行后都做:一旦达到target_recall,立刻退出,不浪费剩余的运行次数。max_evals是保险丝,没有它循环会在不幸运的空间里扫完所有组合。0.02的阈值是防追噪声的护盾。日志写入jsonl,你事后能清楚看到每个参数带来了什么变化。
第四步:刹车片,因为跑一次要花钱
每次评估都是跑一遍完整的RAG,涉及几十个问题的查询嵌入,还有reranker和LLM调用。这既花时间也烧钱。没有刹车的循环能悄无声息地把预算烧光,尤其是搜索空间里混着昂贵的配置组合,比如大k值加上cohere-reranker在每个问题上都跑一遍。
python
def tune_rag_safe(search_space, train_set, target_recall=0.9,
max_evals=40, max_budget_usd=15):
config = default_config()
best_recall = evaluate(config, train_set)
spent = estimate_cost(config, len(train_set))
evals_used = 1
log =
for param, values in search_space.items():
best_value = config[param]
for value in values:
if value == config[param]:
continue
trial = dict(config, {param: value})
trial_cost = estimate_cost(trial, len(train_set))
if spent + trial_cost > max_budget_usd:
print(f"预算${max_budget_usd}已用完,停止在{evals_used}次运行")
save_log(log)
return config, best_recall, evals_used
if evals_used >= max_evals:
save_log(log)
return config, best_recall, evals_used
recall = evaluate(trial, train_set)
spent += trial_cost
evals_used += 1
log.append({"config": trial, "recall": recall,
"spent": round(spent, 2), "eval": evals_used})
if recall > best_recall + 0.02:
best_recall = recall
best_value = value
if best_recall >= target_recall:
config[param] = best_value
save_log(log)
return config, best_recall, evals_used
config[param] = best_value
save_log(log)
return config, best_recall, evals_used
def estimate_cost(config, n_questions):
cost = n_questions * 0.00002
if config["reranker"] == "cohere-rerank":
cost += n_questions * config["k"] * 0.000001
return cost
这里两个刹车分别是max_evals运行次数上限和max_budget_usd金钱上限。预算刹车在实际运行前就做检查,如果下一次评估会超限,循环会提前停下,而不是等钱烧完了才反应过来。这是资产和意外账单之间的区别。
第五步:发射,然后用留出集验货
在训练集上跑循环,然后务必用循环没见过的留出集验证找到的配置。
python
if name == "main":
train_set, holdout_set = split_eval(eval_set)
config, train_recall, n = tune_rag_safe(
SEARCH_SPACE, train_set, target_recall=0.9, max_evals=40
)
print(f"跑了{n}次找到。训练集recall: {train_recall:.2f}")
print(f"配置: {config}")
holdout_recall = evaluate(config, holdout_set)
print(f"留出集recall: {holdout_recall:.2f}")
gap = train_recall - holdout_recall
if gap > 0.1:
print("警告:训练集和留出集差距过大,循环对评估集过拟合了,配置不可信")
else:
print("差距很小,配置能泛化,可以上线")
留出集验证不是走过场,这是区分真进步和对评估集过拟合的分水岭。训练集recall 0.92但留出集只有0.79,说明循环找到的不是一个更好的RAG,而是一套恰好讨好了你那二十八个训练问题的组合。这个差距就是警报器。
循环是怎么死的
任何循环都会死,调参循环也不例外。追噪声是最常见的死法,循环在随机recall波动上反复横跳,永远不收敛。病因是改善阈值太小或者评估集太小,药方是0.02阈值加至少四十个问题。过拟合评估集是另一种死法,训练集recall涨了但生产环境没变好,病因是循环针对特定问题做了优化,药方是留出集验证,差距会报警。预算失控也常见,循环搜了昂贵配置烧光钱,病因是没有预算刹车或者搜索空间里混了高价组合,药方是运行前检查max_budget_usd。
无尽循环则是目标在当前空间里根本达不到,循环把组合都扫了一遍还差得远,病因是target_recall设得比空间天花板还高,药方是max_evals兜底,再不行就扩空间或者降目标。
你最后得到什么
最终你拿到的不仅是一个调好的RAG,而是一套可复现的流程。jsonl日志清楚记录每个参数的效果,留出集验证告诉你该不该信它,数据和模型变了之后一键重新跑调优就行。这就是循环工程在真实任务上的应用。不是什么花哨的agent魔法调参,而是一条工程化的循环:一个骗不了的检查、对过拟合的防御、预算刹车、可审查的日志。拿上你的RAG和评估集,把调参过程包进这样的循环里,做一次,然后这辈子都不用亲手拧chunk size那个旋钮了。
真正会调参的人不是在拧旋钮,是在造拧旋钮的机器人。而那个机器人最擅长的,就是让你忘记自己曾经亲手拧过。
人一辈子都学不会把知识变成工具箱,AI却靠五步做到了。你最骄傲的学习能力,在它面前活像个笨手笨脚的新手。