这次我们来看一个偏研究向、但工程味道很浓的题目: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 依赖清单
推荐环境如下,具体版本以本机测试为准:
| 依赖 | 说明 |
|---|---|
| Python | 3.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.py:
import 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_output=True, text=True, timeout=60) return result.stdout.strip(), result.stderr.strip() def call_llm(config, messages): url = config["model_api"]["base_url"] + "/chat/completions" headers = {"Authorization": f"Bearer {config['model_api']['api_key']}"} payload = { "model": config["model_api"]["model_name"], "messages": messages, "temperature": 0.2 } resp = requests.post(url, json=payload, headers=headers, timeout=120) resp.raise_for_status() return resp.json()["choices"][0]["message"]["content"] def main(): with open("config.json", "r", encoding="utf-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(f"iteration {i + 1}: 调用 LLM 生成候选世界模型") code = call_llm(config, messages) with open("worlds/candidate_world_model.py", "w", encoding="utf-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(host="127.0.0.1", port=8000)调用示例:
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 unauthorized | API 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 与主流智能体开发平台结合,看能不能用代码型记忆替换向量数据库的一部分功能。
- 引入代码覆盖率测试,用测试结果判断世界模型对环境的覆盖程度。
这个方向还不成熟,但核心思想足够稳:能给智能体一个“可以运行的世界观”,它就能在复杂环境里少踩很多重复的坑。建议收藏,后续可以按本文的原型逐步扩展自己的实验。