本节摘要:作为全册起点,本节先把"智能体"的边界钉死:通过传感器感知环境、通过执行器作用于环境、以自主决策为分界线的实体。随后给出适航特性清单(必装与选装),把环境当作空域做四组属性分类,最后拆出本册通用的舱段划分——感知舱、规划舱、行动舱、黑匣子舱、外挂设备舱,为后续逐舱拆解钉好图纸。
回到控制论刚刚成名的年代,维纳在演讲里把"有目的的机器"当成一件正经事来讲:机器可以有自己的目标,可以根据行动的结果修正下一步。台下不少人当笑话听,后来自动驾驶、算法交易与仓储机器人把这个笑话变成了基础设施。笑话与基础设施之间隔着的,正是本节要办的手续——给这台机器一张适航登记证:它到底是不是智能体,具备哪些必装特性,要飞的那片空域是什么规格。图纸钉牢了,后面感知舱、规划舱、行动舱的每一项设计才有处可对。
工程上最省事也最经得起追问的定义来自罗素与诺维格的教科书:智能体是能够感知环境、并作用于环境的实体。这句话听着朴素,拆开来却有门槛。感知不是"有摄像头",而是把环境的物理变化转成内部可计算的读数;作用不是"有轮子",而是让环境的真实状态因为你的决策而发生偏移。两句合起来,才是智能体的完整闭环。
本册在工程层面再追加一层:智能体 = 感知 + 认知 + 行动的实时闭环系统。感知把世界变成读数,认知(规划舱与黑匣子舱的合称)把读数变成决策,行动把决策变成对世界的修改。用飞行器的话说:雷达进读数,计算机定航线,舵面动起来。
沿着这个定义画分界线,能排掉一批似是而非的候选:
判断口诀一句话:看世界的动作算不算感知,动世界的动作算不算行动,中间有没有自主决策把两者接起来。
经典教材给智能体列过一串特性清单,工程上值得按"适航标准"重新分级——必装项缺了就别出厂,选装项按空域配置。
必装特性决定了它是不是一架飞行器:
选装特性按空域加装:社会性(与其他智能体或人协作,需要通信协议与意图理解,多机编队时必装,深编队理论归 533 册);学习性(从经验修正自身参数,第 8 章机库改装的主题);适应性与容错(环境突变下维持性能,行动舱第 4 章的复飞程序)。选装不等于不重要——恰恰是这些项,决定了同一套驾驶舱能飞的空域范围。
环境不是背景板,它是飞行器的另一半。智能体与环境的标准交互模型是一个持续序列:环境给出感知输入,智能体依此选择动作,动作改变环境,环境再给出新的输入。把这个循环形式化,智能体的行为就是从感知历史到动作的映射——这句话是后面所有算法的总纲:设计智能体,就是在设计这个映射。
四组属性给空域定规格,每组都直接翻译成舱段配置:
| 属性 | 取值 | 对舱段配置的影响 | 典型空域 |
|---|---|---|---|
| 可观测性 | 完全 / 部分可观测 | 部分可观测必须加装状态估计(第 2 章)与信念状态,否则仪表读数只是盲区一角的快照 | 棋盘对局 / 夜航城市道路 |
| 确定性 | 确定 / 随机 | 随机空域的规划舱要做不确定性绕飞(第 3 章),行动舱要备复飞程序(第 4 章) | 仓库格路 / 人车混流 |
| 动态性 | 静态 / 动态 | 动态空域决定回路频率下限:环境在你思考时也在变,规划必须在窗口内完成 | 回合制棋 / 早高峰路口 |
| 离散性 | 离散 / 连续 | 连续空域的行动舱要做轨迹与控制(舵面平滑),离散空域可走符号规划 | 棋步与菜单 / 机械臂关节角 |
这组表在实战里最好用的地方是反向排错:仪表读数飘忽,先查可观测性是否被高估——很多"规划太笨"的病根,其实是空域比自己以为的更不可观测。空域属性判断错了,舱段配置就是刻舟求剑。
空域属性的判定也值得固化成代码——它是舱段配置的输入,错了后面全错:
from enum import Enum class AirspaceProfile(Enum): FULLY_OBSERVABLE = "完全可观测" PARTIALLY_OBSERVABLE = "部分可观测" def classify_airspace(env): """空域四属性判定:出厂前必须逐项填写。""" return { "observable": (AirspaceProfile.FULLY_OBSERVABLE if env.state_readable() else AirspaceProfile.PARTIALLY_OBSERVABLE), "deterministic": env.outcome_variance() < EPS, "dynamic": env.changes_during_thought(), # 思考期间会变吗 "discrete": env.state_space_is_finite(), } def interaction_loop(agent, env, max_steps): """标准交互循环:感知历史到动作的映射,全册总纲。""" history = [] for _ in range(max_steps): percept = env.give_percept() # 环境给输入 action = agent.choose(history, percept) # 映射出动作 env.apply(action) # 动作改变环境 history.append((percept, action)) return env.final_score()
定义与特性说清了,整机可以开箱了。本册把单个智能体拆成五个舱段,并在全册保持这套叫法:
这套划分与经典分类学能够对上:简单反射智能体是"只留行动舱直连感知"的退化机型;基于模型的智能体给感知舱加了内部状态;基于目标的智能体装上了规划舱;基于效用的智能体给规划舱换了评价函数;学习智能体则接通了机库(第 8 章)。反过来讲,舱段是分类学的工程投影——你给每个舱段选的配置,就定义了你造的是哪一级机型。
登记手续的最后一步是写代码骨架。一架最小但完整的飞行器,类声明长这样:
from dataclasses import dataclass, field from typing import Any @dataclass class FlightBoard: """飞行状态板:全机唯一的事实源,后续章节反复出现。""" belief: dict = field(default_factory=dict) # 信念状态:对环境的当前估计 goal: Any = None # 当前目标(可为目标栈) behavior: str = "idle" # 正在执行的行为名 class AgentCore: """五舱段最小骨架:只定义接缝,不定义实现。""" def __init__(self, perception, planning, action, memory, board): self.perception = perception # 感知舱:world -> reading self.planning = planning # 规划舱:reading+goal -> route self.action = action # 行动舱:route -> world changes self.memory = memory # 黑匣子舱:读写日志与状态 self.board = board # 状态板:单一事实源 def run_tick(self, world): reading = self.perception.sense(world) # 雷达扫描 self.memory.append("perception", reading) # 进航行日志 self.board.belief = self.perception.estimate( reading, self.board.belief) # 更新信念 route = self.planning.plan(self.board) # 定航线 self.board.behavior = route.current_step() self.action.execute(route.next_action(), world) # 动舵面 return self.board # 仪表回读
骨架里每个字段都会在对应章节撑开成整整一章,这里只需要记住接缝方向:读数从感知舱流向规划舱,指令从规划舱流向行动舱,而所有舱段读写同一块状态板。
模块章的五段式在整机层的对应物是空转联调:不接真实环境,先让每个舱段吃假数据跑通闭环。验机清单按数据流走——感知舱喂一段录制的读数,状态板更新是否正常;规划舱对着固定信念,航线是否稳定;行动舱收到假指令,执行是否在预算时间内返回。三段都绿,再接真实环境。
整机层最常见的误诊是张冠李戴:智能体反复撞墙,直觉怪规划舱"太笨",实测往往是感知舱的读数延迟超过了环境变化周期——规划舱拿的是旧地图,再聪明也躲不开新墙。排错口诀:先查数据流,再查算法。另一个高频误诊是把状态板当成普通变量随手改——某舱段绕过状态板直写内部状态,联调时两个舱段各执一份真相,故障表现为"时好时坏",极难复现。这类病根在第 1.3 节的单一事实源设计里根治。
⚠️ 常见坑:把"能演示"当成"闭环成立"。演示成功可能只是环境配合——空域恰好静态、感知恰好够用。验收前务必按四组空域属性重新核对一遍配置,尤其是动态性与可观测性这两项最容易高估。
下一节把通电开关推上去:这五段舱体接成的主回路,节拍怎么配、布线怎么选,才配叫"会飞"。