摘要:慎思式智能体内置世界模型,按"感知—建模—规划—行动"行事;其代表架构 BDI 用信念(我以为)、愿望(我想要)、意图(我承诺)三件套刻画实践推理。本节拆解 BDI 解释器循环、意图的承诺机制与三种承诺策略,并实现一个能跑的最小 BDI 快递镇民。
「BDI」是镇民茶馆里出现频率最高的黑话,全称 Belief-Desire-Intention。上一节的反应式镇民只有反射弧,摔不坏也想不远;慎思式镇民反过来,脑中先挂一张世界地图,凡事掂量因果再动手。BDI 则是慎思阵营里最长寿的工程方案——它把哲学家布赖特曼关于"意图"的思辨,熬成了能写进代码的解释器循环。这一节是全章的主菜,第 3 章里那些会投标、会守约的镇民,内核都是它。
慎思式镇民的工作流是"感知—建模—规划—行动"四部曲:感知进来先更新内部世界模型(一套符号化的状态描述),随后规划器在世界模型上搜索行动序列,选中一条就逐步执行。它的底气是预测力——模型准,就能推演"如果我这么做,世界会怎样",从而绕远路、做权衡、推迟满足。代价也明摆着:建模与规划都慢,模型会过时,维护成本高。反应式与慎思式的争斗没有胜负,只有分工。
单纯用"信念加愿望"解释理性行动有个漏洞:愿望可以无穷多且互相打架(既想环游世界又想存钱),只靠愿望推不出稳定行为。布赖特曼的洞见是:理性智能体需要对某些愿望承诺,被选中的愿望升级为意图,意图具备三重品格——它约束未来推理(有此意图就别整天重新盘算)、驱动手段推理(定下目标就去找路)、且不轻易放弃(半途而废比绕路更贵)。愿望是菜单,意图是下的单。
三件套的分工于是清晰:
| 心智状态 | 通俗说法 | 形式化角色 | 可能出错吗 |
|---|---|---|---|
| 信念 Belief | 我以为世界是这样 | 信息状态,可能不完整或错误 | 会——以为在下雨其实没下 |
| 愿望 Desire | 我希望世界变成那样 | 选项的池子,允许冲突 | 无对错,只有多少 |
| 意图 Intention | 我承诺让世界变成那样 | 被筛选后持续追求的目标栈 | 会——承诺错了方向 |
从愿望到意图的筛选叫慎思(deliberation),从意图到手段的落地叫手段—目的推理(means-end reasoning),查的是计划库——一组"目标+上下文条件+执行体"的计划模板。
经典 BDI 解释器每 tick 走这么一遭:感知环境,用新观察修订信念;信念触发事件生成候选愿望;慎思筛选,把若干愿望提升为意图;为意图在计划库里匹配计划并压入意图栈;执行栈顶计划的一步;最后在合适的时机 reconsider——要不要重新想想?这最后一问引出承诺策略:盲目承诺(打死不回头)、单心思承诺(目标不变换路径)、开放承诺(环境一变就重选)。工程上单心思承诺最常用:认死理但肯换路。

理论齐了,落成代码。场景:快递镇民在小镇送件。信念用字典存,愿望是待办目标,意图是带计划的目标栈;计划库按"触发目标+上下文条件"匹配。每个循环走一遍修订信念、生成愿望、筛选意图、执行一步的标准流程。
class MiniBDI: """最小 BDI 快递镇民:信念-愿望-意图 三件套加计划库。""" def __init__(self): self.beliefs = {"at": "depot", "raining": False, "parcels": [], "road_blocked": False} self.desires = [] # 愿望池 self.intentions = [] # 意图栈(栈顶最先执行) self.plans = [] # 计划库:触发目标+条件+步骤 def add_plan(self, goal, context, steps): self.plans.append({"goal": goal, "when": context, "steps": steps}) def perceive(self, obs): self.beliefs.update(obs) # 信念修订:照单全收(简化) def generate_options(self): for p in self.parcel_events: # 外部事件冒出愿望 self.desires.append(("deliver", p)) self.parcel_events = [] # 事件消费掉,避免无限重复接单 def deliberate(self): """慎思:愿望可行且未在意图里,就提升为意图并配计划。""" for goal, arg in list(self.desires): plan = self.find_plan(goal) if plan and all(i[0] != goal or i[1] != arg for i in self.intentions): self.intentions.append((goal, arg, iter(plan["steps"]))) self.desires.remove((goal, arg)) def find_plan(self, goal): for p in self.plans: if p["goal"] == goal and p["when"](self.beliefs): return p return None parcel_events = [] # 简化:到货事件队列 def post_parcel(self, dest): self.parcel_events.append(dest) def step(self, world): self.generate_options() self.deliberate() if not self.intentions: return "idle" goal, arg, steps = self.intentions[-1] try: act = next(steps) result = world.execute(self.beliefs, act, arg) print(f"[{goal}:{arg}] {act} -> {result}") return act except StopIteration: # 计划执行完,意图出栈 self.intentions.pop() return "done" bdi = MiniBDI() bdi.add_plan("deliver", lambda b: not b["road_blocked"], # 上下文:路没封 ["pick_up", "ride_to_dest", "hand_over"]) bdi.add_plan("deliver", lambda b: b["road_blocked"], # 备选计划:路封了绕行 ["pick_up", "detour_ride", "hand_over"]) bdi.post_parcel("bakery") class World: def execute(self, beliefs, act, arg): if act == "ride_to_dest": beliefs["at"] = arg return f"当前位置 {beliefs['at']}" world = World() for _ in range(5): bdi.step(world)
计划库放了两条同名计划,靠上下文条件分流——路通走直达,路封走绕行。这正是 BDI 处理环境突变的钥匙:不是删除旧计划,而是让条件不满足时自动落到备选计划。把 road_blocked 翻成 True 再跑,镇民会自己改道,意图(送达面包坊)纹丝不动,这就是单心思承诺。
再看 reconsider 的时机。下面的对比实验演示两种承诺策略在"路被封两次"的倒霉日子里各表现如何。
import random def delivery_day(reconsider_goal, seed=3): """送三个包裹;路上随机封路。reconsider_goal=True 时目标也可放弃。""" random.seed(seed) goals = ["bakery", "school", "clinic"] done, aborted, detours_total = [], [], 0 for g in goals: detours = 0 while True: if random.random() < 0.6: # 又封路了(倒霉的雨季) detours += 1 if detours >= 3: # 连续碰壁到上限 if reconsider_goal: aborted.append(g); break else: detours = 1 # 单心思:认死理,继续绕 else: done.append(g); detours_total += detours; break return done, aborted, detours_total print("单心思承诺:", delivery_day(reconsider_goal=False)) print("开放承诺 :", delivery_day(reconsider_goal=True))
单心思版把全部包裹送到了手,代价是合计绕行多次;开放版在连续碰壁后弃掉部分订单,绕行少、完成率也掉。哪个好取决于弃单代价与绕路代价的比值——急救药品必须单心思,传单可以开放。承诺策略不是参数调优,是业务价值观的代码化。
💡 关键直觉:BDI 常被吹成"拟人心智",它的真正贡献其实是工程上的——用意图栈把"目标持久性"这个推理难题变成了数据结构问题。想理解它在学术谱系里的位置,可以把它看成决策论(效用最大化)在有限算力下的实用近似:不追求最优,追求"够好且跟得上环境"。
BDI 的形式语义有完整的模态逻辑体系(信念愿望意图各有算子与公理),工程血统则从 PRS 一路传到 dMARS、JACK,直到用 AgentSpeak 语言实现的 Jason 平台(第 8 章工坊会再遇到它)。它的甜区是"目标明确、环境多变、反应要快"的半结构化任务:应急响应、空域管理、宇航调度。它的短板同样清楚:计划库要人写(知识工程瓶颈)、学习成分原生缺失(第 7 章学堂来补)、跨镇民的社会推理不在三件套射程内(第 3 章邮政局来接)。
把 BDI 镇民放回沙盘:它是镇上的快递员,脑中揣着一张可能过时的地图(信念),口袋里塞满想赚的运费(愿望),今天真正认下的三单(意图)写在小本上。下雨改道、客户改约,它换路径不换承诺;除非接连碰壁到上限,才撕单重来。下一节的混合式镇民要做的,是给这样的慎思内核再垫一层毫秒级反射——让火警响起的瞬间,先由脊髓刹车,再由大脑规划逃生路线。