零运行依赖的自修改编程运行时
开源项目 Runesmith 使用 Python 3.11 标准库组织规划、编码、检查和修复流程,可对接云端模型、本地模型或手动聊天。它将固定内核与可修改部分分开,并要求自修改方案在未见任务上胜出才保留。
完整中文译文
让 AI 修改自己的代码,难点不只是改得对,还要知道它动了哪里、有没有越权,以及新版本是否真的更好。Runesmith 团队为此做了一个选择:整个运行时只用 Python 3.11 标准库,项目配置里的 dependencies = []。
作者想证明的不是标准库能替代所有框架,而是:缩小需要信任的代码范围,可以让自修改系统更容易审查。这个项目也给出了改进实验,但证据边界很清楚:局部修复能力有过提升,持续自我进化尚未得到验证。
为什么允许自修改,反而要减少依赖
Runesmith 是一个开源 AI 编程运行时,负责组织规划、写代码、检查和修复。它可以调用 Gemini、Groq,通过 Ollama 使用本地模型,也能让用户在聊天窗口里手动复制请求和答案。
它把程序分成两部分。固定内核负责身份、账本、版本代际、工具路由、预算和运行限制;外围的功能模块称为 organ,例如 organs/repair.py。自改进循环 Kaizen 可以重写这些模块,但不能随意替换内核。
候选版本要依次通过静态检查、受限冒烟测试、留出任务回放,再与当前版本做实际试运行。留出任务就是生成修改时没有见过的题目,用来减少针对已知案例优化造成的误判。
零依赖的价值,是减少审查自修改行为时需要追踪的外部代码。
作者认为,如果内核依赖三十个包,审查者就必须同时考虑这些项目的行为和发布变化。集中在一个仓库里,更容易追问每条权限从哪里来。不过,这仍然建立在信任 CPython 和操作系统的前提上,不能理解成全部可信代码都在项目仓库里。
标准库怎样把修改关进可检查的流程
第一道门是 AST,也就是把源码解析成语法树,再检查其中的结构。下面这段原始实现限制模块大小、检查入口,并审核导入:
ALLOWED_IMPORTS = frozenset({
"__future__", "ast", "bisect", "collections", "copy", "dataclasses", "difflib", "enum", "fnmatch",
"functools", "hashlib", "heapq", "io", "itertools", "json", "keyword", "math", "operator", "re",
"statistics", "string", "textwrap", "time", "tokenize", "typing",
})
def static_check(source: str) -> list[str]:
problems = []
if len(source.encode("utf-8")) > 200_000:
problems.append("module larger than 200 KB")
try:
tree = ast.parse(source)
except SyntaxError as error:
return [f"syntax error: {error}"]
if not any(isinstance(node, ast.FunctionDef) and node.name == "run" for node in tree.body):
problems.append("no top-level run(view, cockpit)")
for node in ast.walk(tree):
names = []
if isinstance(node, ast.Import):
names = [alias.name.split(".")[0] for alias in node.names]
elif isinstance(node, ast.ImportFrom):
names = [(node.module or "").split(".")[0]]
for name in names:
if name not in ALLOWED_IMPORTS:
problems.append(f"import of {name!r} is not allowed")
return problems
关键是 if name not in ALLOWED_IMPORTS:列表没有 os、socket、subprocess、urllib,模块需要调用模型、运行测试或写日志时,应经过内核控制的 cockpit,并计入预算。但这段代码只检查了顶层是否存在名为 run 的函数,并没有验证参数确实是 view, cockpit;导入白名单也不能独立证明文件和进程访问已经被封死。
后续隔离因此很重要。模块通过 python -I -B organ_child.py 在独立进程执行,环境中不放密钥,并安装 PEP 578 审计钩子。拦截范围包括网络、进程启动,以及可能扩大访问能力的 gc.、signal. 等事件前缀。操作系统层再用 Windows Job Object 或 POSIX setrlimit 施加资源限制。
作者明确承认:审计钩子只是纵深防御,不是坚固的沙箱。不信任的模块仍建议放进容器或 VM。
另一条线是记录证据。每次决策写入只追加的 JSON Lines 账本,记录包含 seq、utc、kind、data、prev 和自身哈希。序列化采用 json.dumps(value, sort_keys=True, ensure_ascii=True, separators=(",", ":")),摘要使用 SHA-256;写入后执行 flush() 和 os.fsync(),跨进程锁使用 POSIX fcntl.flock 或 Windows msvcrt.locking。
运行 python -m runesmith ledger 可以检查链条是否一致。但哈希链提供的是一致性检查;原文没有说明是否存在外部可信锚点,不能据此认定整份历史无法被重算替换。
不装依赖省了安装,也接下了维护工作
模型通信集中在基于 urllib.request 的 http_json 函数里,通过 Request、urlopen 和 HTTPError 处理请求。支持范围包括 Gemini、Groq、NVIDIA、OpenRouter、Mistral、DeepSeek、OpenAI、Anthropic 的 OpenAI-compatible 层、Together,以及其他兼容服务。测试时直接替换这个函数,返回预设状态码,无需 HTTP mocking 库。
免费额度处理比请求代码更有参考价值。对 429/503,系统解析 Retry-After 和服务商错误正文;遇到 429,会把限流状态记在 home 目录,保留到额度重置。免费层每次调用最多重试一次。按作者使用的 Groq 免费窗口,每分钟 8,000 tokens,过大的请求会在发送前转向该角色的下一个模型。
Gemini 的「每个模型每天约 20 次请求」来自他们测试时收到的拒绝信息,作者也说明 Google 没有公布固定免费额度。它是当时的观测值,不能当成稳定承诺。
项目扫描使用 os.scandir,跳过 .git、node_modules、虚拟环境和缓存,不跟随符号链接或 Windows junction,最多扫描 20,000 个文件,再用名称、大小和修改时间生成 SHA-256 指纹。Windows 下目录枚举同时带回大小和修改时间,可以少做额外查询。浏览器界面 Runesmith Studio 也由标准库提供服务,只监听 127.0.0.1,静态 HTML、CSS、JavaScript 放在 runesmith/app/static,没有 Node.js 构建步骤。
代价是团队自己维护重试退避、小模型输出的宽容 JSON 提取、限流解析、跨平台锁和换行符。仓库统一 LF,因为内核与模块摘要按字节计算。他们还实现了 Bernoulli CUSUM 漂移检测,在性能下降时,把自改进工作占比从常态 15% 提升到 25%、40%。
零依赖没有消灭复杂度,只是把维护责任收回了仓库。
我的判断
这个项目最有价值的是把「自改进」拆成了能检查的步骤,而且公布了不理想的结果。
SR7 实验中,Kaizen 生成的修复步骤 C7 在 162 次尝试里修复 57 次,前代为 35 次,精确单侧检验 p = 0.000845。但任务是合成的单行错误,使用便宜的修复模型。
第二个封闭实验 LOC1,在三个大型公开仓库中新植入错误,C7 修复 42/168 个会话,随项目发布的步骤修复 17/168,p = 0.00278。然而,人工编写、利用 trace 信息的规则修复了 65/168,超过 C7。早期 SR5 也没有展示出改进,结果是 36 对 50,共 180 次尝试。
现有证据支持某个生成版本在特定任务上变好,不支持系统能够连续多代变强。
对一般团队,我赞成学习它的权限划分和验收流程,不建议照搬「零依赖」作为硬指标。作者没有提供与成熟框架在开发工时、维护成本或安全性上的对照数据,零依赖更容易审查仍是有理由的工程判断,尚不是比较实验结论。人工规则的成绩也提醒我们:先把明确规则做好,再判断是否需要自修改。
能拿来做什么
- 给日常 AI 编程工具划出固定权限层,把模型调用、测试执行、日志和预算集中管理,让生成代码通过明确接口请求能力。
- 评估自动修复时保留一批生成阶段看不到的任务,同时对比当前版本和人工规则,避免只凭几个成功案例决定上线。
- 在 Node 或其他语言的项目里借鉴它的限流策略:记录额度重置时间、限制重试次数,并在发送前判断请求是否超出预算;具体额度以实际服务为准。
- 想观察完整流程,可以在项目目录运行下面的离线演示。
pytest是运行测试套件或修复现有 Python 项目时才需要安装的额外包。
python -m pip install pytest
python -m runesmith --home .runesmith demo --kaizen
要看清第二行的 demo --kaizen:它使用脚本模拟模型,展示自改进流程怎样运转,不证明生成修改有实际收益。