在多 Agent 与智能体式系统设计中,常见一条原则:明确区分确定性层与不确定性层——控制流、数据流与安全相关部分应尽量确定、可验证,语义理解与创造性生成则可交给大模型。OpenProse 把大模型当作 DSL 的执行器,用「理解」替代「解析」来驱动执行。本文以它为例,分析这种设计为何导致「形式像程序、执行却不确定」,以及能提炼出哪些设计启示。更系统的范式讨论见《多 Agent 系统设计范式:从理论到实践的完整指南》。
OpenProse 简介
OpenProse 旨在提供一种「面向 AI 会话的编程语言」。其核心理念是:长期运行的 AI 会话本身即一台图灵完备的计算机,OpenProse 是为其设计的编程语言。
# 定义专门的智能体
agent researcher:
model: sonnet
prompt: "You are a research assistant"
agent writer:
model: opus
prompt: "You are a technical writer"
# 执行工作流
session: researcher
prompt: "Research recent developments in quantum computing"
session: writer
prompt: "Write a summary of the research findings"
设计取向与执行模式
OpenProse 的文档明确其设计原则:追求「理解」而非「解析」,虚拟机是「智能的」而非「机械的」。因此,它用大模型去理解并执行 DSL,而不是用传统解释器做词法、语法分析与确定性执行。
两种执行模式可概括为:
| 模式 | 流程 | 结果 |
|---|---|---|
| 传统 DSL | 代码 → 词法/语法分析 → 抽象语法树 → 解释器机械执行 | 确定性 |
| OpenProse | .prose 文件 → 大模型阅读理解 → 大模型按自身理解执行 | 不确定 |
根据其文档,会话同时扮演解释器与运行时,不依赖严格的形式匹配,而依赖对上下文与意图的理解。这带来两类现象:
-
语法作为「建议」而非「指令」
parallel: a = session "Task A" b = session "Task B"- 传统解释器:必须并行执行两个任务。
- OpenProse:大模型识别出「应并行」,但具体如何调度、是否真并行,由大模型决定。
-
执行逻辑内嵌于大模型
repeat 3: session "Improve the draft"- 传统解释器:严格重复 3 次,每次调用一致。
- OpenProse:大模型仅能识别出语法写的是「需重复 3 次」;是否真会执行 3 次、以及每次「Improve the draft」的具体行为,都由大模型自行决定,无法从机制上保证。
根本问题:用概率系统模拟确定性执行器
OpenProse 在概念上要求大模型充当符合规范的执行器,而大模型只能模拟该角色,无法从机制上保证与规范一致。
类比:若让演员「扮演计算器」计算「234 + 567」——多数时候会得到 801,但无法保证下次不会:因计算错误得到 800 或 802;因理解偏差将题目当作「估算」而给出约数;或因自行判断「问题无意义」而拒绝回答。
示例:对于按顺序的两个 session:
session: researcher
prompt: "Research quantum computing"
session: writer
prompt: "Write a summary of the research findings"
若按确定性语义理解,通常会期望:先完成 researcher,再启动 writer,并将前者输出传给后者。实践中,大模型有时会按此执行,也可能:将两个任务合并在同一 session;在中间插入自认为需要的验证步骤;误判 session 边界,把整段程序当作一次长对话;或因上下文截断而丢失部分状态。
要点:问题不在于个例出错,而在于即使语法结构是确定的(如顺序、重复、分支),也无法被确定性执行。
深层原因
DSL 的两面性
| 层面 | 设计意图 | 实际效果 |
|---|---|---|
| 语法层 | 提供结构化、明确的控制流 | 外表类似传统编程语言 |
| 执行层 | 依赖大模型理解并模拟执行 | 行为本质上是概率性的 |
开发者面对的是语法层给出的确定性表象,得到的却是执行层的概率性行为。
认知错位
形式化语法容易让人产生确定性错觉。例如:
for item in items:
result = session "Process {item}"
if **result is valid**:
output result
外表接近 Python、JavaScript 等确定性语言,实则:for 表示「由大模型理解要遍历」而非传统迭代;session 表示「启动子对话」而非固定语义的函数调用;if 表示「由大模型判断条件」而非确定性的分支。表象与机制不一致,易高估可预测性。
执行器的双重角色
OpenProse 的「虚拟机」即大模型本身,同时承担:
- 解释器:解析 DSL 语法、识别结构;
- 执行引擎:完成具体任务(如 research、write)。
二者在元层次上纠缠。对于 session "Review the code and identify bugs",模型既要识别这是 session 语句,又要执行「Review the code…」这一任务,并自行划分「哪是语法、哪是任务描述」。角色边界模糊,容易出现混淆与误判。
影响:适用场景与局限
原型与探索阶段的优势
- 学习成本低:如
session "Do A"、session "Do B",即使不熟悉编程也能推断大意。 - 便于快速表达意图:用自然语言描述任务即可,无需掌握复杂 API。
- 一定程度的「智能」行为:大模型可能识别隐含依赖、自行处理部分边缘情况。
- 容错与自我修正:可能自动纠正轻微语法问题或补全缺失上下文。
生产与标准化阶段的局限
- 执行不可复现:同一段代码多次运行,控制流可能不同(如
repeat 5有时执行 5 次、有时 3 次)。 - 难以可靠测试:既难以定义「正确」行为,也难以稳定地模拟或隔离大模型内部状态。
- 调试困难:失败时难以定位是语法理解、并行实现、结果传递还是任务语义导致。
- 版本与行为脱节:.prose 文件相同,行为仍可能随模型、对话历史、提示词而变,版本控制无法对应到稳定行为。
- 无法证明执行轨迹:难以证明「每次执行具体做了什么」。
可能的缓解方向
- 用真实解释器执行控制流:由传统编译器/解释器处理
repeat、parallel、if等,大模型只负责「任务内容」的生成与理解。 - 显式标出不确定性边界:在 DSL 中区分「确定性区域」与「智能体区域」。
- 提供验证与对照:编译时做语法检查,运行时记录实际控制流,便于与预期对照。
- 分离语言层次:例如第一层确定性控制流、第二层智能体配置、第三层自然语言任务描述。
对多 Agent 设计的启示
- 元层次边界:当「解释器」本身由大模型充当时,语法理解与任务执行的边界容易模糊,需在设计中显式划分。
- 形式与实现一致:若语法呈现传统程序般的确定性,就应由确定性解释器执行;若依赖大模型判断,应在语法或注释中显式标出(如
**...**)。设计方向应是用确定性引擎调用大模型,而不是用大模型模拟确定性执行器。 - 适用边界:OpenProse 式设计适合原型探索与快速表达,不适合要求可复现、可测试、可审计的生产环境。
更普适的设计原则
- 分离确定与不确定:在架构上明确哪些环节必须确定、可验证,哪些允许概率性。
- 表象与本质一致:本质若为概率性,表象就应有所体现,避免「形式确定、执行不确定」。
- 控制流不交给大模型解析:控制结构应由传统解释器解析与驱动,大模型只承担需要语义理解或生成的部分。
- 保留确定性路径:即使在智能体式系统中,也预留可选的、不经过大模型的执行路径,作为「逃生舱」。
结论
OpenProse 的核心矛盾在于:要求大模型「模拟」一个确定性执行器,而大模型本质上是概率系统。这类问题无法通过改进提示词或更换模型从根本上解决,而是设计范式的选择问题。