Code as Worlds:用可执行程序构建智能体的世界模型
这次我们来看一个偏研究向、但工程味道很浓的题目Code as Worlds智能体发现可执行世界表征。一句话解释它不是让智能体多写几段代码而是让智能体把“对世界的理解”编码成可运行的程序再通过与真实环境的交互不断修正这套程序。这种“可执行世界表征”能跑、能验证、能回滚比纯文本记忆更接近一个真正可复用的世界模型。文章的实操主线会围绕一套最小原型展开用 LLM 生成代码 - 在沙盒中执行 - 把执行结果反馈给模型 - 模型更新自己的“世界推测”。这套流程跑通后你能直观看到智能体如何用 Code 建立、验证并修正对任务环境的认知。适合正在研究 Agent 架构、评估 Claude Code / OpenCode / Kimi Code 等编程智能体或者想自己做世界模型原型的开发者。先给结论这个方向不需要动辄 8 卡 A100 才能试。很多关键实验用 API 模型加一个 Docker 沙盒就能完成。下面直接拆解概念、原型、测试和排错。1. 核心能力速览能力项说明项目类型研究性方法论 / Agent 架构范式核心思想智能体用代码表达对世界的理解代码即可执行的世界表征关键技术世界模型、代码生成、沙盒执行、观察反馈循环主要功能环境建模、任务推演、代码级记忆、可验证决策最小环境Python 3.10、Docker、一个可调用的 LLM API 或本地模型服务硬件门槛纯 API 模式几乎不占本机 GPU本地模型模式取决于模型规模启动方式命令行脚本 / 轻量 HTTP 服务是否支持 API可以封装成 HTTP 接口是否支持批量任务可以但需要任务队列与失败重试适合读者Agent 开发者、LLM 应用研究者、编程智能体深度用户合规重点代码执行必须在沙盒内进行数据使用需符合授权范围2. 什么是可执行世界表征“世界表征”这个概念最早来自认知科学和强化学习中的 world model指的是智能体对内外部环境形成的结构性理解。传统做法是用向量、图结构或自然语言记忆来表达这种理解但问题是向量不可读图结构难维护自然语言容易含糊。Code as Worlds 的思路很直接把世界理解写成代码。代码本身就是一种高度结构化的“可执行文本”满足三个关键性质可执行智能体可以运行代码得到可观测的输出。可验证执行结果与真实环境采样的结果能直接对比。可修正对比失败时智能体可以重写代码形成闭环迭代。用这种范式看智能体它的核心循环变成观测环境状态。用代码建模当前状态或预测下一步状态。在沙盒中执行代码得到预测结果。与环境真实反馈对比。根据差异修正代码更新世界模型。这里的“世界”不一定是物理世界也可以是一个游戏、一个数据库、一个 API 服务、一段业务规则。只要是可观测、可交互的环境理论上都能用 Code 做表征。从工程视角看这个范式最大的价值是把智能体的推理过程变成可回放、可审计的产物。普通对话型 Agent 说什么就忘了但代码型世界表征留下来的是一个可运行的模型文件任何人拿到都能复现它的认知状态。3. 适用场景与使用边界3.1 适合谁用做 AI Agent 框架的开发者想给智能体增加“可运行记忆”的能力。研究世界模型、模型预测控制、强化学习环境建模的算法工程师。重度使用 Claude Code、OpenCode、Codex、Kimi Code 等编程智能体的用户想理解这类工具背后“代码即计划”的底层逻辑。需要把 Agent 决策过程审计化的企业团队。3.2 能解决什么问题解决纯文本记忆“说得通但不可靠”的问题。解决 Agent 在复杂环境中重复犯同一个错误的问题。解决多步任务中推理链过长、容易丢失上下文的问题。让 Agent 具备“先推演再行动”的能力而不是直接调 API。3.3 不适合什么场景对实时性要求极高的场景例如毫秒级交易代码生成和执行的开销太大。环境本身不可观测或不允许程序化交互的场景。团队没有沙盒执行条件时不建议直接让 LLM 生成的代码在宿主机上运行。3.4 使用边界与合规提醒Code as Worlds 涉及让模型生成代码并执行安全边界必须提前划清楚所有模型生成的代码必须在 Docker 等沙盒环境中执行不要直接跑在宿主机上。沙盒应删除网络权限除非任务明确需要访问外部服务。处理业务数据时要确认数据使用授权不能把未脱敏的私有数据直接发给外部模型服务。代码产物如果用于生产要有代码评审和测试门禁不能完全信任模型输出。4. 技术架构与最小原型设计下面不引入现成框架直接设计一个最小可运行的原型。目的是把“智能体发现可执行世界表征”这条链路拆开每个人都能看懂、能改。4.1 参考架构整个原型包含四个角色模块职责技术选型控制器调度 Agent 循环维护任务状态Python 脚本推理通道调用 LLM 生成代码与世界推测OpenAI 兼容 API 或本地模型沙盒执行器安全运行生成的代码Docker 容器反馈记录器保存执行结果、对比差异、写入日志JSON 文件核心流程是控制器拿到任务描述 - 调用 LLM 生成一段 Python 代码作为“世界模型候选” - 沙盒执行 - 控制器收集执行结果 - 把结果和任务约束一起交给 LLM要求修正或确认。4.2 世界模型候选示例假设任务环境是一个“奇数偶数判断器”智能体需要从少量样本中学会规则。先让模型生成一段候选代码# candidate_world_model.py # 这是 LLM 生成的世界模型候选代码 def predict(input_data): # 当前假设所有输入都返回 unknown return unknown if __name__ __main__: test_inputs [1, 2, 3, 4] for item in test_inputs: print(item, -, predict(item))执行结果全是 unknown反馈到 LLM 后模型会意识到自己的世界模型太粗糙于是重写规则。经过几轮迭代最终可能生成# candidate_world_model.py def predict(input_data): return even if input_data % 2 0 else odd if __name__ __main__: test_inputs [1, 2, 3, 4] for item in test_inputs: print(item, -, predict(item))这就是一个最简单的“可执行世界表征”智能面对同一世界不断提交可运行的程序用执行结果校准自己的判断。5. 环境准备与前置条件5.1 依赖清单推荐环境如下具体版本以本机测试为准依赖说明Python3.10 及以上版本Docker用于沙盒执行避免宿主机被污染LLM API Key需要可正常访问的模型服务账号requests调用 API 使用Flask 或 FastAPI封装 HTTP 接口时使用检查本机环境python --version docker --version5.2 目录规划建议按下面的结构管理文件code-as-worlds-lab/ ├── agent_loop.py ├── server.py ├── config.json ├── logs/ └── worlds/ ├── candidate_world_model.py └── observed_feedback.jsonworlds 目录用于存放智能体每次生成的世界模型代码logs 目录用于存放执行日志。把输入、中间产物、输出分开批量任务时会省很多麻烦。6. 安装部署与启动6.1 配置模型与沙盒参数创建 config.json{ model_api: { base_url: https://your-model-service.example.com/v1, api_key: your-api-key-here, model_name: your-model-name }, sandbox: { image: python:3.11-slim, network_enabled: false }, task: { prompt: 根据观测数据写一个 Python 函数 predict输入是整数输出是 odd 或 even。, max_iterations: 5, timeout_seconds: 30 } }提醒这里的 base_url 和 model_name 需要按你实际可用的模型服务填写。如果服务账号没有对应区域的访问权限需要先确认账号状态而不是绕过限制。6.2 启动入口脚本写一个最小控制器 agent_loop.pyimport json import subprocess import time import requests def run_in_sandbox(code_path): cmd [ docker, run, --rm, --network, none, -v, f{code_path}:/app/world_model.py, python:3.11-slim, python, /app/world_model.py ] result subprocess.run(cmd, capture_outputTrue, textTrue, timeout60) return result.stdout.strip(), result.stderr.strip() def call_llm(config, messages): url config[model_api][base_url] /chat/completions headers {Authorization: fBearer {config[model_api][api_key]}} payload { model: config[model_api][model_name], messages: messages, temperature: 0.2 } resp requests.post(url, jsonpayload, headersheaders, timeout120) resp.raise_for_status() return resp.json()[choices][0][message][content] def main(): with open(config.json, r, encodingutf-8) as f: config json.load(f) messages [ {role: system, content: 你是一个世界模型发现算法。你的任务是根据观测数据编写可执行的 Python 代码来预测环境输出。}, {role: user, content: config[task][prompt]} ] for i in range(config[task][max_iterations]): print(fiteration {i 1}: 调用 LLM 生成候选世界模型) code call_llm(config, messages) with open(worlds/candidate_world_model.py, w, encodingutf-8) as f: f.write(code) stdout, stderr run_in_sandbox(worlds/candidate_world_model.py) print(执行输出:, stdout) print(执行错误:, stderr) messages.append({role: assistant, content: code}) messages.append({ role: user, content: f执行结果如下\nstdout:\n{stdout}\nstderr:\n{stderr}\n如果预测正确回复 DONE否则重写代码。 }) if DONE in stdout or DONE in stderr: print(世界模型已收敛) break time.sleep(1) if __name__ __main__: main()启动方式python agent_loop.py跑通后可以看到智能体不断生成候选代码沙盒执行再反馈给模型直到输出 DONE。7. 功能测试与效果验证原型跑通后建议用三个不同难度的任务验证“可执行世界表征”是否真的有效。7.1 测试一规则发现任务输入整数输出奇数或偶数。验证方式运行 agent_loop.py看最终生成的候选模型代码是否为取模判断逻辑。预期结果模型在 1 到 3 轮内收敛输出 DONE。判断标准候选代码不包含“unknown”或“maybe”这类模糊分支所有测试输入都有明确输出。7.2 测试二状态推演任务给定一个队列的当前元素列表预测执行 pop 操作后的状态。这个过程更接近“世界模型”的实质因为智能体需要用代码模拟一个状态转移关系。建议扩展提示词请写一个 Python 函数 simulate(queue, action) - 输入 queue 是列表action 是字符串 pop - 返回执行 pop 操作后的列表和弹出的值 要求代码必须可运行并在 if __name__ __main__ 中输出示例。验证要点模拟结果是否与真实 Python 列表行为一致。模型是否主动处理空列表的边界情况。多次执行结果是否稳定。7.3 测试三多步规划任务给定一个 4x4 迷宫的起点和终点让智能体生成一个可执行寻路函数并用沙盒里的广度优先搜索路径输出。预期结果智能体不仅写出寻路函数还能在代码里输出可视化路径例如用字符串矩阵展示。验证思路把模型生成的代码放入沙盒运行检查输出路径是否连通起点与终点。判断成功的标准只有一个代码在沙盒中能跑输出结果与实际环境一致并且这个代码可以被下次任务直接复用。满足这三点就说明智能体确实产出了可执行的世界表征。8. 接口 API 与批量任务原型验证通过后可以把 agent_loop 封装成 HTTP 服务便于接到自己的工具链里。8.1 启动 HTTP 服务用 Flask 写一个简单服务from flask import Flask, request, jsonify import json import subprocess app Flask(__name__) app.route(/api/discover, methods[POST]) def discover(): data request.get_json() task_prompt data.get(prompt) # 这里把 task_prompt 写入临时配置并调用 agent_loop 的主逻辑 # 实际项目建议把 agent_loop 拆成可导入的函数 return jsonify({status: ok, message: 任务已提交}) if __name__ __main__: app.run(host127.0.0.1, port8000)调用示例curl -X POST http://127.0.0.1:8000/api/discover \ -H Content-Type: application/json \ -d {prompt: 根据观测数据写一个 Python 函数 predict输入是整数输出是 odd 或 even。}8.2 批量任务设计批量跑多个世界发现任务时不要直接开一堆子进程。更稳的做法是按目录批量提交inputs/ ├── task_01.json ├── task_02.json └── task_03.json每份 JSON 包含独立的 task_prompt 和 max_iterations。批量脚本按顺序读取、执行、记录结果。线上环境建议把每个任务的日志单独存放命名规则为 task_id 时间戳。{ task_id: task_03, prompt: 写一个 Python 函数模拟一个栈的 push 和 pop。, max_iterations: 5 }批量任务的关键设计是“失败不阻塞队列”单个任务超时只记录 error继续下一个。每个任务执行前重新加载配置避免前面任务的代码被执行器缓存污染。每个任务结束后清理沙盒容器。9. 资源占用与性能观察9.1 本机资源使用 API 模型时本机主要开销集中在沙盒执行和代码 IO几乎不消耗 GPU。以 python:3.11-slim 容器为例每个容器内存开销通常在几十 MB 到几百 MB 之间取决于代码运行时的实际负载。如果使用本地推理模型则显存取决于模型规模。一个 7B 量级的量化模型通常需要至少 6GB 以上显存但具体占用要看量化方式和推理框架。这里不做硬性断言以你本机实际测试为准。9.2 如何观察资源占用执行批量任务时可以观察 Docker 资源统计docker stats --no-stream重点看 CONTAINER ID、MEM USAGE、CPU % 三项。如果某个容器内存暴增说明 LLM 生成的代码存在无界循环或大数组分配需要在沙盒层面增加内存限制。Docker 启动命令中可以追加资源限制docker run --rm \ --network none \ --memory 256m \ --cpus 0.5 \ -v /path/to/world_model.py:/app/world_model.py \ python:3.11-slim \ python /app/world_model.py这样即使智能体写出死循环或超大内存分配也不会拖垮宿主机。9.3 影响性能的主要因素LLM 推理延迟API 模式主要看服务端响应时间本地模式看 GPU 算力。迭代轮数max_iterations 越大总耗时线性增长。代码执行时间候选代码本身的计算复杂度需要沙盒超时兜底。Token 消耗每一轮都会把历史消息重新发送给模型迭代多了 token 成本会明显上升。一个实用的建议第一轮测试时把 max_iterations 设小一点比如 3先把流程跑通再加大迭代次数。10. 常见问题与排查方法问题现象可能原因排查方式解决方案API 返回 401 unauthorizedAPI Key 错误或未设置检查请求头 Authorization核对 API Key确保证书与账号状态正常API 返回 unsupported country region territory当前环境不在服务支持范围检查响应错误码与账号区域确认当前账号和服务在允许范围内或换用合规可用的服务Docker 启动失败Docker 未启动或镜像未拉取执行 docker ps检查镜像列表启动 Docker先执行 docker pull python:3.11-slim沙盒执行超时生成的代码存在死循环查看容器日志增加 docker run 的 timeout或加内存和 CPU 限制模型一直不输出 DONE提示词约束不够清晰查看每轮生成代码的差异在提示词中明确要求“不要输出模糊结果必须给出可执行代码”批量任务中途卡住某任务等待模型响应过久查看日志文件和进程状态为每个任务增加独立超时超时后强制跳过token 消耗增长过快历史消息重复发送打印请求 payload 大小蒸馏历史信息只保留最近几轮的代码与结果11. 最佳实践与使用建议11.1 从玩具环境开始不要第一个实验就跑到真实业务系统里。先用奇偶数、队列、迷宫这类规则明确的环境验证“执行 - 反馈 - 修正”闭环再逐步增加复杂度。11.2 保留“最小可运行配置”我建议把 config.json、agent_loop.py、Docker 启动命令存成模板。后面每次实验只改 task.prompt其他不动。这样可以快速对比不同模型、不同提示词对世界模型发现效果的影响。11.3 每一次代码产物都是资产LLM 生成的候选世界模型文件要按版本保存。即使某一次迭代最终没有收敛中间某轮代码也可能包含正确片段。建议把 worlds 目录纳入 git 管理提交信息写清楚任务和迭代轮次。11.4 日志比输出更重要可执行世界表征的调试难点在于“模型怎么改代码”的过程不可见。除了保存 stdout 和 stderr还要记录每一轮 LLM 返回的完整代码和修改理由。可以这样设计日志结构logs/ ├── 20250101_120000_task01_iter1_code.py ├── 20250101_120000_task01_iter1_feedback.json └── 20250101_120000_task01_iter2_code.py11.5 涉及敏感数据时先做脱敏如果世界表征任务涉及具体业务数据特别是用户信息、订单信息、财务数据必须遵守“最小化”原则。能脱敏就脱敏能聚合就聚合不要让模型接触完整原始数据。11.6 代码来源与供应链风险任何由 LLM 生成的代码都不应该直接进入生产环境。更稳的流程是沙盒内执行验证。人工或静态扫描工具审查代码。通过单元测试后才合并。12. 总结与下一步Code as Worlds 这个方向最值得尝试的点是它把智能体的“理解”从不可验证的文本变成了可运行、可回放、可修正的代码产物。你不需要先搭一套复杂框架一个 Python 脚本加一个 Docker 沙盒就能跑通最小闭环。建议你最先验证的是“规则发现”任务给模型一个奇数偶数判断任务看它能否在几次迭代内生成正确代码并输出 DONE。这个实验成本低、反馈快、现象直观。最容易踩的坑有两个一是 LLM 生成代码不遵守“必须可执行”的约束输出解释性文本导致沙盒运行失败二是忘记设置沙盒资源限制出现死循环时整个批量任务被拖住。后续可以继续扩展的方向包括把“世界模型”保存为独立模块供多个任务共享复用。在反馈中加入更多环境观测维度例如执行耗时、边界输入、随机种子。把 Code as Worlds 与主流智能体开发平台结合看能不能用代码型记忆替换向量数据库的一部分功能。引入代码覆盖率测试用测试结果判断世界模型对环境的覆盖程度。这个方向还不成熟但核心思想足够稳能给智能体一个“可以运行的世界观”它就能在复杂环境里少踩很多重复的坑。建议收藏后续可以按本文的原型逐步扩展自己的实验。