十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

可执行世界表征:智能体开发从提示词工程走向环境工程

可执行世界表征:智能体开发从提示词工程走向环境工程 智能体开发做久了你会发现一个很反常的现象模型越来越强、框架越来越多但 Agent 依然经常做出“看起来合理、实际上完全跑不通”的决策。原因往往不在模型而在 Agent 眼前那个“世界”。如果你给 Agent 的世界只是一大段自然语言规则它就只能靠语言推理去猜。猜 10 次可能对 5 次剩下 5 次暴露出来的不是模型笨而是世界本身不可执行。这个问题在 Agent 开发里比想象中更底层更值得先想清楚。所以我想认真聊一个概念Code as Worlds——智能体发现可执行世界表征。它不只是一句口号而是一套把环境、规则、状态和反馈全部变成可运行代码的 Agent 设计思路。看完这篇文章你会理解可执行世界表征和自然语言提示词的区别能自己搭一个最小可执行环境并知道如何让智能体在真实反馈里收敛到可靠的动作策略。1. 为什么智能体开发会卡在“世界”这一层从 Dify、Coze 到自研 Agent 框架智能体开发的热度已经持续很久了。很多人入门的路径很相似先调一个模型 API再定义一堆工具函数然后把“你是谁、你能做什么”写进系统提示词最后运行一个循环让模型反复调用工具。这个流程看起来没什么问题但真正放到业务里你会碰上一堆说不清的失败模型明明知道某操作会触发校验错误却还是反复尝试同一个非法动作Agent 选了工具也传了参数但因为没有收到足够细的反馈它无法判断自己到底做没做对多个 Agent 共享同一个环境状态时互相覆盖数据整个流程直接崩溃你改了一版 promptAgent 行为发生很大变化但你不知道变化来自规则措辞还是模型随机性。这些问题的共同根源是 Agent 所面对的世界太过“模糊”。如果世界只是文字Agent 的推理就没有可靠的锚点。它只能根据上下文猜而猜出来的决策当然不稳定。一个更工程化的思路是把世界从“一段描述”升级为“一套可执行的代码”。让 Agent 的每一个动作都能改变状态返回明确的结果产生有意义的反馈。只有当 Agent 经历的不是文本而是真实反馈时它才有可能形成对世界结构和边界的内部模型也就是可执行世界表征。这也是为什么现在智能体框架越来越多但环境设计反而成为新的瓶颈。Dify、Coze 这类平台解决的是“Agent 工作流怎么编排”的问题却很难帮你回答“你的业务世界到底应该暴露哪些状态和动作”。这个设计议题更适合放在实际代码里展开。2. Code as Worlds可执行世界表征到底是什么2.1 先从“表征”这个词说起在 AI 领域表征representation指的是系统对输入信息的内部建模方式。图片分类模型会在层与层之间形成视觉特征表征对话模型会在上下文里形成对话状态表征。那 Agent 的“世界表征”是什么简单说就是 Agent 对“我身处的环境现在是什么状态、动作会带来什么变化”的理解。如果 Agent 的世界只有一个系统提示词它唯一能依赖的表征就是语言的语义。一旦世界内部有复杂规则——比如库存不能超过上限、商品缺货不能发货、多个订单之间相互影响——语言描述的模糊性就会变成 Agent 的错误源头。可执行世界表征的思路是完全不同的它不依赖 Agent 从语言里猜世界而是把世界定义成一段可执行代码。状态是数据结构动作是函数反馈是函数返回值。Agent 每一次行动都相当于在真实世界里做了一次测试然后从测试结果里更新自己对世界的认知。2.2 为什么“可执行”比“可描述”更重要自然语言是压缩率很高的表达方式但代价是丢失精确性。你说“库存不足时不能下单”模型听起来很明白但真到动作那一层它可能需要知道不足的阈值是多少是下单入口被拒绝还是后续流程回滚扣减库存和实际发货之间有没有延迟在可执行世界里这些边界不需要用语言解释。Agent 发出一个order动作世界返回一个具体的错误“当前库存为 0无法创建发货单”。Agent 试一次就知道边界在哪里。再试一次它就能把这条经验写进后续决策。所以 Code as Worlds 的核心判断是Agent 的能力上限取决于它能否在一个可执行、可观测、可验证的世界里不断试错。可执行世界表征是 Agent 从“会聊天”走向“能做事”的分水岭。2.3 和强化学习环境的关系熟悉强化学习的读者应该已经发现了这个思路和 RL 环境的设定非常接近。RL 里的env.step(action)返回next_state, reward, done, info本质上就是一个可执行世界的最小接口。但 Code as Worlds 不局限于经典 RL。它强调智能体尤其是 LLM Agent可以直接在这个环境里做推理和规划而不是从零开始学习策略。Agent 仍然是一个大模型只是它不再靠提示词硬撑而是靠环境的真实反馈来修正自己的下一步。这样一来Agent 的每一次运行都会产出一条可审计的轨迹状态、动作、反馈、再状态。这些轨迹就是最宝贵的训练数据可以让 Agent 做后续的提示词优化、微调甚至在真实系统里做多智能体协作。3. 可执行世界 vs 自然语言世界一个直观对比对比维度自然语言世界可执行世界Code as Worlds状态表达写在提示词里模型靠上下文理解由代码数据结构显式定义随时可读取动作边界凭模型推测由函数和参数校验定义非法动作直接报错反馈粒度模糊的文本建议具体的返回值、错误信息、状态变更可测试性很难自动化断言可以写单元测试和集成测试可回滚性改 prompt 后无法自动回滚代码有版本管理错误可以回滚多 Agent 协作容易互相抢状态环境状态集中管理可以做到原子变更学习潜力只能靠示例和语言推理能产生轨迹数据支持进一步训练从表里能看出可执行世界不是在某个单项上更优而是在工程可靠性上全面碾压。它把“Agent 应该怎么做”的问题从 prompt 工程问题变成了软件工程问题。这也是我能给从事智能体开发的人最直接的建议少花时间反复调提示词多花时间把环境写扎实。当然自然语言也不是完全没有位置。它是 Agent 和人类之间沟通的界面适合描述目标、解释策略、展示推理过程。但真正决定 Agent 能否稳定行动的仍然是底层的可执行世界。4. 环境准备与基础配置下面会用一个最小可执行环境来演示。为了让思路能直接落地我选 Python 作为主要语言不需要额外的重型依赖。具体版本以你的实际项目为准本文重点演示通用思路。4.1 基础运行环境建议环境如下操作系统Windows / macOS / Linux 均可Python3.10 及以上版本以实际项目为准环境管理venv 或 conda核心依赖json、typing、copy 等标准库即可如果只跑演示代码不需要安装第三方库。如果要接入真实的大模型 API请按你所用模型服务商的 SDK 文档安装依赖并把密钥配置到环境变量中例如export LLM_API_KEYyour_api_key_here export LLM_BASE_URLhttps://your-model-endpoint.example.com不要把密钥写进代码仓库更不要提交到公共仓库里。4.2 是否需要使用 Agent 框架Dify、Coze 等平台能帮你快速搭建智能体工作流但在做“可执行世界表征”实验时我建议先从纯代码入手。原因很简单你需要完全掌握状态、反馈和轨迹三个核心环节平台层会把这些细节封装掉反而不利于你理解问题。当你跑通最小闭环之后再移植到 Dify、Coze 或自研智能体框架都会轻松很多。如果你的团队已经选了低代码 Agent 平台也可以用同样的思路来设计平台的“工具接口”让每个工具返回结构化反馈而不是一段自然语言描述。平台只是载体可执行世界才是真正的核心。4.3 项目目录结构我们用一个非常简单的目录来组织代码code-as-worlds-demo/ ├── world.py # 可执行世界定义 ├── agent_core.py # Agent 循环骨架 ├── world_config.json # 世界初始配置 ├── logs/ │ └── run_round_001.jsonl # 轨迹日志 └── README.md这个结构刻意精简方便你复制后直接运行。真实项目里可以把 world、agent、evaluation 分成不同模块。5. 核心流程拆解从世界定义到 Agent 循环搭建可执行世界表征本质上是在做四件事定义状态、定义动作、定义反馈、定义循环。这也是整个智能体开发里真正值得深思的部分。5.1 定义状态状态是 Agent 观察世界的窗口。每个状态字段都应该有明确含义库存有多少、订单有多少、当前回合数、累计收入等。Agent 在每个回合开始时调用observe()方法拿到一份 JSON 序列化的状态快照。这里容易犯的错误是把状态和内部实现混在一起。比如直接把 Python 对象的私有字段暴露给 Agent字段名不统一、类型不稳定模型很难形成稳定的世界表征。正确做法是先定义对外状态 Schema再让世界内部实现去适配。5.2 定义动作动作是 Agent 改变世界的方式。设计最小动作集比设计一个大而全的动作集更重要。每个动作对应一个函数参数必须明确。非法参数绝不静默忽略而是返回错误反馈。这里的一个常见坑是动作函数内部逻辑耦合导致 Agent 无法预测动作边界。比如order动作既要改库存又要改订单表还要改状态字段某个环节失败时前面已经改了一半状态世界陷入不一致。这个问题在真实业务里非常常见解决思路是让世界具有事务性至少保证状态变更在动作失败时可以回滚。5.3 定义反馈反馈是 Agent 学习的核心信号。自然语言世界里的反馈可以是“操作失败”但在可执行世界里反馈应该更结构化错误类型、错误信息、当前状态、建议字段。这样 Agent 才能在上一次失败中定位真正原因。反馈不应该直接告诉 Agent 应该怎么做而是提供足够信息让 Agent 自己推断。也就是说世界不要成为 Agent 的“提示词机器”。5.4 定义 Agent 循环Agent 循环是串联状态、动作和反馈的骨架。流程如下Agent 获取当前状态Agent 根据历史轨迹和当前状态生成一个动作智能体向可执行世界提交动作世界执行动作并返回反馈和下一个状态Agent 把反馈追加到历史轨迹循环直到达到最大回合数或任务完成这个循环可以应用到任何智能体框架本质上就是 Dify、Coze 里“工具调用 工作流编排”的底层模型。6. 完整示例一个可执行库存世界下面用一个“库存管理”的简化场景来演示完整实现。这个场景足够小但包含了状态、动作、反馈边界和循环非常适合理解 Code as Worlds 的核心。6.1 示例 1可执行世界定义# 文件路径world.py 一个极简的可执行库存世界。 设计思路 1. 世界状态通过 observe() 序列化为 JSONAgent 只能看到可观察字段。 2. 所有动作都通过 step(action) 入口执行返回结构化反馈。 3. 非法动作不静默忽略而是返回明确的错误信息。 import copy from typing import Any, Dict class InventoryWorld: def __init__(self, config: Dict[str, Any]): self.stock: Dict[str, int] copy.deepcopy(config.get(stock, {})) self.max_capacity: int config.get(max_capacity, 100) self.total_orders: int 0 self.total_revenue: float 0.0 self.rounds: int 0 def observe(self) - Dict[str, Any]: 返回当前世界的可观察快照。 return { round: self.rounds, stock: copy.deepcopy(self.stock), total_orders: self.total_orders, total_revenue: self.total_revenue, max_capacity: self.max_capacity, } def step(self, action: Dict[str, Any]) - Dict[str, Any]: 统一动作入口返回反馈信息。 self.rounds 1 action_type action.get(action) if action_type query: return { ok: True, message: 查询成功, state: self.observe(), } if action_type order: product action.get(product) quantity int(action.get(quantity, 0)) if not product or product not in self.stock: return { ok: False, message: f未知商品: {product}, state: self.observe(), } if quantity 0: return { ok: False, message: 下单数量必须大于 0, state: self.observe(), } if self.stock[product] quantity self.max_capacity: return { ok: False, message: ( f{product} 库存将超出最大容量 {self.max_capacity} f当前库存 {self.stock[product]} ), state: self.observe(), } self.stock[product] quantity self.total_orders 1 return { ok: True, message: f下单成功{product} 当前库存 {self.stock[product]}, state: self.observe(), } return { ok: False, message: f未知动作: {action_type}, state: self.observe(), }这段代码的关键点有三个observe()方法显式控制 Agent 能看到的字段避免泄露内部实现细节step()是动作的唯一入口所有校验都集中在世界内部每个反馈都携带ok、message、state让 Agent 能同时获得结果判断和最新状态。6.2 示例 2世界初始配置世界初始配置放在 JSON 文件里便于修改和版本管理。{ stock: { apple: 10, banana: 0, orange: 5 }, max_capacity: 100 }这个配置文件在启动时被读入InventoryWorld用来初始化世界状态。把初始状态从代码中抽出来好处是后续可以做单元测试和回归测试针对不同初始状态验证 Agent 策略。6.3 示例 3Agent 循环骨架Agent 循环负责把大模型和世界连接起来。下面这段代码不绑定特定模型厂商只给出通用骨架。# 文件路径agent_core.py 一个不绑定具体模型厂商的 Agent 循环骨架。 你可以把 call_llm 替换成任何模型服务商的接口。 import json from world import InventoryWorld SYSTEM_PROMPT 你是一个库存管理 Agent。你只能执行两种动作 - {action: order, product: 商品名, quantity: 数量} - {action: query} 每次你会收到世界状态、上一步执行反馈。 你的目标把库存补到不低于 20但不要超出 max_capacity。 请根据反馈做出下一步动作只输出 JSON不要输出多余文字。 .strip() def call_llm(messages): 接入你的模型服务。 这里留空由实际项目实现。 可以使用 OpenAI SDK、Anthropic SDK也可以是本地部署模型。 raise NotImplementedError(请替换为你的模型调用代码) def run_agent(world, max_rounds10): history [] for r in range(max_rounds): state world.observe() history.append({ role: user, content: f世界状态: {json.dumps(state, ensure_asciiFalse)}, }) # 截断历史避免上下文过长。这里按最近 4 条消息处理。 messages [{role: system, content: SYSTEM_PROMPT}] messages.extend(history[-4:]) raw call_llm(messages) action json.loads(raw) result world.step(action) history.append({role: assistant, content: raw}) history.append({ role: user, content: f反馈: {result[message]}, }) print(f回合 {r 1}: action{action}, feedback{result[message]}) if result.get(done): break return historycall_llm函数需要你在实际项目中接入模型服务。例如使用 OpenAI SDK 时可以这样替换def call_llm(messages): from openai import OpenAI client OpenAI() response client.chat.completions.create( modelgpt-4o-mini, messagesmessages, temperature0.2, ) return response.choices[0].message.content具体接口名称和参数以你的模型 SD K 文档为准。重点是循环结构不变状态 → 动作 → 反馈 → 历史 → 下一步。6.4 示例 4运行入口与轨迹记录为了让过程可审计建议把每一轮轨迹写入 JSONL 文件方便后续分析或微调。# 文件路径main.py import json from world import InventoryWorld from agent_core import run_agent def load_config(path: str): with open(path, r, encodingutf-8) as f: return json.load(f) def save_history(history, path: str): with open(path, w, encodingutf-8) as f: for message in history: f.write(json.dumps(message, ensure_asciiFalse) \n) if __name__ __main__: config load_config(world_config.json) world InventoryWorld(config) history run_agent(world, max_rounds5) save_history(history, logs/run_round_001.jsonl) print(最终状态:, world.observe())运行前先创建logs目录mkdir -p logs python main.py运行成功后logs/run_round_001.jsonl会记录 Agent 每个回合的完整轨迹。这就是 Agent 后续学习所需要的“过程数据”。7. 运行结果与效果验证当你接入真实模型后运行main.py会得到类似下面的输出具体内容取决于模型选择和历史截断策略回合 1: action{action: query}, feedback查询成功 回合 2: action{action: order, product: banana, quantity: 20}, feedback下单成功banana 当前库存 20 回合 3: action{action: order, product: banana, quantity: 20}, feedback下单成功banana 当前库存 40 回合 4: action{action: order, product: apple, quantity: 10}, feedback下单成功apple 当前库存 20 最终状态: {round: 4, stock: {apple: 20, banana: 40, orange: 5}, total_orders: 3, total_revenue: 0.0}判断实验成功至少要看三点Agent 是否根据反馈修正动作如果第一次返回“未知商品”下一次不应再尝试同一商品名。状态是否按预期变化每个动作执行后world.observe()中的stock字段要与反馈一致。轨迹日志是否完整logs/run_round_001.jsonl中每个回合都有完整的 user/assistant/user 消息链。如果 Agent 输出不是合法 JSONjson.loads(raw)会直接抛错。此时建议在call_llm返回后增加 JSON 解析和修复逻辑比如提取第一个{和最后一个}之间的内容。如果 Agent 反复下单导致库存暴涨可以进一步在world.py中加入“单商品最大入库量”校验验证 Agent 是否能根据新边界调整策略。这也是可执行世界的好处改完代码就知道模型有没有真的理解规则。8. 常见问题与排查思路问题现象可能原因排查方式解决方案模型输出非 JSON提示词约束不足、模型不稳定打印模型原始输出观察实际格式在 prompt 中强调“只输出 JSON”增加 JSON 修复层Agent 重复执行相同动作反馈信息不够丰富无法判断失败原因检查 step() 返回的 message 和 state在反馈中增加“当前状态”和“已执行动作”的完整字段世界状态被多个 Agent 互相污染多个智能体共享同一个 world 实例检查并发模型下 world 是否被多线程修改每次运行创建新 World或使用线程隔离 状态快照动作执行后状态部分更新动作函数没有事务性检查 action 内对 state 的多处修改先校验再一次性提交状态变更轨迹日志过大历史消息未截断查看 history 长度和日志大小使用最近 N 条消息策略或做消息摘要模型忽略反馈继续做不合法动作模型对动作空间理解弱检查系统提示词是否明确列出合法动作在系统提示词中显式声明“只允许两个动作非法动作无效”并加入少量示例这些排查思路看起来简单但在真实 Agent 项目里很实用。尤其是“状态被污染”和“轨迹日志过大”往往是多智能体协作和生产环境部署时最先暴露的问题。9. 最佳实践与工程建议9.1 世界状态和动作 Schema 先行在写任何 Agent 代码之前先定义世界状态 Schema 和动作 Schema。这相当于给 Agent 提供了一本“世界操作手册”远胜于在提示词里写几百字描述。状态字段统一使用小写和下划线命名动作参数尽量简单避免嵌套复杂对象为字段和参数补充注释让模型更好理解所有状态变更尽量做到可序列化。9.2 反馈必须结构化建议每个世界动作都返回统一结构{ ok: true, message: 状态变更描述, state: {} }这样做的好处是 Agent 可以稳定地从ok字段判断成败从state字段读取最新状态从message字段理解失败原因。如果反馈格式每次都不一样模型就要花大量推理能力去理解反馈而不是思考下一步动作。9.3 用版本管理维护世界代码可执行世界和普通业务代码一样需要版本管理。不要只保存“旧提示词”而要保存“旧世界代码”。当 Agent 行为回归时第一件事就是查看世界代码变更记录。建议把世界配置也纳入版本管理比如world_config.json。通过对比不同配置下 Agent 的行为差异可以更快定位问题。9.4 保证动作的幂等性和事务性真实业务环境里同一个动作可能因为网络超时被重复提交。建议在step()入口为每个动作生成唯一request_id并判断是否已经执行过。这样可以避免重复入库、重复扣库存等灾难性后果。如果动作涉及多个状态字段变更务必先完成所有预校验再一次性提交变更。否则中途失败会导致状态不一致。9.5 让 Agent 的每一步都可审计无论 Agent 是在模拟世界还是真实系统里运行都必须记录完整轨迹。轨迹里至少要包含时间戳、世界状态、模型输出、执行结果、延迟、异常堆栈。这些数据不仅是调试依据更是后续做模型微调和策略评估的核心资产。9.6 安全边界与权限控制如果 Agent 最终要操作真实系统可执行世界就是最后一道安全闸门。建议先在沙箱或测试环境验证全部动作再逐步开放生产权限。涉及删除、覆盖、资金操作等高风险动作时可以增加“人工确认”环节。任何时候都要遵守最小权限原则不给 Agent 超出任务范围的能力。10. 总结与后续学习方向Code as Worlds 真正改变的地方是把 Agent 开发的重心从“提示词怎么写”转移到“世界怎么做才能被 Agent 精准感知和操作”。在这个思路下智能体不再是被动接受文本指令的对话模型而是在一个可执行环境里通过反馈不断校准行动策略的问题求解者。如果你接下来想继续深入可以从这几个方向展开多智能体环境让多个 Agent 共享同一个可执行世界观察它们如何协作或竞争世界模型学习利用轨迹日志训练一个预测模型让 Agent 不只是反应而是能预演未来状态评测体系设计为可执行世界编写自动化测试用例稳定评估 Agent 每次改动的效果平台化整合把本文的最小世界封装成 Dify、Coze 或自研智能体框架里的工具接口用同样方法结构化反馈。先把一个最小可执行世界跑通再评估 Agent 是否真的在“按照反馈修整行为”这个过程比盲目堆工具和框架更有价值。建议把文章里的示例代码保存下来后续做 Agent 项目时直接套用这个模式会少踩很多坑。
返回列表