三权分立式 Agent 架构:为什么“感知、规划、执行”必须彼此制衡?(第4期)
专栏:《大模型落地之道:智能体生态卷》
作者:Valhalla Matrix治理实验室
文章类型:原创技术实践与方法论总结
适用读者:技术负责人、架构师、AI 产品负责人、研发管理者
摘要:当智能体从“回答问题”走向“修改文件、调用接口、执行运维任务”时,最大的风险往往不是模型不会规划,而是感知结论、行动计划与实际执行权限被放进了同一条信任链。本文提出一种“三权分立式 Agent”架构:将感知、规划、执行拆分为三个职责边界,并通过结构化决策内存、独立授权、风险分级和不可抵赖审计实现相互制衡。文章包含架构设计、Python 示例、风险控制清单与落地建议,适合企业智能体、Agent 平台和 AI 安全工程实践。
阅读提示:本文是工程方法论与参考实现,不代表任何特定系统已经完成安全认证或生产验证。示例代码用于说明设计思想,正式上线前仍需结合业务权限、威胁模型和合规要求进行测试。
一、Agent 真正危险的地方,不是“会犯错”,而是“犯错后能直接行动”
传统聊天机器人答错一个问题,通常只会造成信息质量下降;但企业 Agent 一旦拥有以下能力,风险性质就发生了变化:
- 修改配置文件;
- 删除云资源或数据库记录;
- 发布代码、创建工单;
- 发送邮件、消息或付款指令;
- 调用内部系统 API;
- 读取包含个人信息、密钥或商业机密的数据。
这时,一次错误的感知可能被模型写进计划,计划再被执行器当成授权,最终变成真实的破坏性操作。
例如,用户说:“把仓库清理一下。”
Agent 可能经历这样的链路:
扫描文件
-> 判断哪些内容“可以清理”
-> 生成删除计划
-> 调用文件删除工具
-> 修改真实系统状态
问题在于:
因此,Agent 安全不能只靠一句系统提示词,也不能只依赖模型“自觉谨慎”。更可靠的方向是:
让不同阶段承担不同职责,让每个高风险动作都必须重新验证,而不是沿用上游结论。
二、三权分立:感知 ≠ 规划 ≠ 执行
“三权分立”不是把一个 Agent 简单拆成三个函数,而是拆分三种不同的信任边界。
| 感知权 | 观察外部世界、读取数据、提取事实 | 文件、接口、日志、用户输入 | 看到的信息可靠吗?是否完整、过期? |
| 规划权 | 将目标转化为步骤,比较可选方案 | 用户目标、感知事实、约束条件 | 这个计划是否合理、必要、可回滚? |
| 执行权 | 调用工具并改变外部状态 | 已审批计划、明确授权、工具参数 | 这个动作是否被授权?能否安全执行? |
三者之间最重要的关系不是流水线,而是后一个环节不能盲信前一个环节:
┌──────────────────────┐
│ 策略中心 / 授权中心 │
└──────────┬───────────┘
│ 独立授权
┌────────┐ 事实快照 ┌────────┐ 计划草案 ┌────────┐
│ 感知层 │ ─────────> │ 规划层 │ ─────────> │ 执行层 │
└───┬────┘ └───┬────┘ └───┬────┘
│ │ │
└────────────── 决策内存 / 审计链 ──────────┘
这里有一条必须坚持的原则:
规划可以提出行动建议,但不能自动获得执行权限;执行器可以执行已授权动作,但不能自行扩大授权范围。
三、为什么只拆模块还不够?关键是拆分“信任依据”
很多系统看起来有感知模块、规划模块和执行模块,但实际上仍然存在以下问题:
- 三个模块共享一份可以被模型任意修改的上下文;
- 规划输出直接作为执行参数;
- 执行器只检查“格式正确”,不检查“权限正确”;
- 没有记录每次决策依赖了哪些事实;
- 出现问题后无法判断是感知、规划还是执行出了错。
所以,真正需要隔离的不是函数名,而是以下内容:
四、结构化决策内存:让后续环节“看见结论,但不继承信任”
可以设计一个只保存阶段产物的决策内存。它不保存一段无限增长的聊天上下文,而是保存可验证的结构化对象:
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Any
import hashlib
import json
def digest(data: Any) –> str:
payload = json.dumps(data, ensure_ascii=False, sort_keys=True).encode()
return hashlib.sha256(payload).hexdigest()
@dataclass(frozen=True)
class DecisionRecord:
stage: str # perception / planning / execution
task_id: str
payload: dict[str, Any]
source_ids: tuple[str, ...] = ()
risk_level: str = "low"
created_at: str = field(
default_factory=lambda: datetime.now(timezone.utc).isoformat()
)
@property
def record_id(self) –> str:
return digest({
"stage": self.stage,
"task_id": self.task_id,
"payload": self.payload,
"source_ids": self.source_ids,
"risk_level": self.risk_level,
"created_at": self.created_at,
})
感知层输出的应该更接近事实:
{
"stage": "perception",
"task_id": "task-20260822-001",
"payload": {
"path": "./workspace",
"candidates": [
{
"name": "cache.tmp",
"reason": "匹配临时文件规则",
"last_modified": "2026-08-20T10:00:00Z"
}
],
"unknowns": ["未确认该文件是否被定时任务依赖"]
},
"risk_level": "medium"
}
注意其中的 unknowns。一个成熟系统不仅要记录“知道什么”,还要明确记录“还不知道什么”。
规划层读取这份事实快照后,重新判断:
{
"stage": "planning",
"task_id": "task-20260822-001",
"source_ids": ["perception-record-id"],
"payload": {
"objective": "降低工作区临时文件占用",
"steps": [
{
"action": "list",
"target": "./workspace",
"mode": "read_only"
},
{
"action": "request_approval",
"target": "cache.tmp",
"mode": "delete_after_confirmation"
}
],
"rollback": "保留回收站副本 7 天"
},
"risk_level": "medium"
}
规划层不能把“候选文件”直接升级成“允许删除”。它只能提出一个需要审批的计划。
五、执行权前的最后一道墙:独立授权与策略判定
执行器的设计目标不是“尽可能聪明”,而是“严格执行边界”。
一个最小化的策略判断示例如下:
from dataclasses import dataclass
@dataclass(frozen=True)
class Authorization:
allowed: bool
reason: str
requires_human: bool = False
class PolicyEngine:
DESTRUCTIVE_ACTIONS = {"delete", "overwrite", "publish", "send", "transfer"}
def authorize(self, *, actor: str, action: str,
target: str, risk_level: str,
approved: bool = False) –> Authorization:
if action in self.DESTRUCTIVE_ACTIONS and not approved:
return Authorization(
allowed=False,
reason="破坏性动作必须经过明确审批",
requires_human=True,
)
if target.startswith("/system/"):
return Authorization(
allowed=False,
reason="目标位于受保护路径",
)
if risk_level == "high" and actor != "human-approved-agent":
return Authorization(
allowed=False,
reason="高风险动作需要人工授权身份",
requires_human=True,
)
return Authorization(allowed=True, reason="通过策略检查")
执行前至少应检查:
动作是否在允许列表中?
目标资源是否在授权范围内?
当前身份是否有权限?
计划是否仍然有效、未过期?
事实快照是否发生变化?
是否属于高风险动作?
是否需要人工确认?
是否具备回滚方案?
特别要避免这种危险设计:
# 不推荐:把模型输出直接交给工具
result = tool.execute(planner_output)
更稳妥的执行链路应该是:
plan = planner.create_plan(observation)
auth = policy.authorize(
actor=actor,
action=plan.action,
target=plan.target,
risk_level=plan.risk_level,
approved=human_approved,
)
if not auth.allowed:
raise PermissionError(auth.reason)
result = executor.execute(plan, authorization=auth)
audit_log.write(plan=plan, authorization=auth, result=result)
**默认拒绝(fail closed)**应当成为高风险 Agent 的基本原则:授权服务不可用、证据不完整、状态冲突或审批过期时,应暂停执行,而不是“先做了再说”。
六、风险分级:不是所有动作都需要同样的审批成本
如果每次读取文件都要求人工确认,系统会变得难以使用;如果删除、发布和转账也走自动快通道,系统又会失去安全边界。
可以采用分级策略:
| 低风险 | 查询公开信息、读取普通日志 | 自动执行,记录审计 |
| 中风险 | 修改非生产配置、创建测试资源 | 沙箱执行或用户确认 |
| 高风险 | 删除数据、发布代码、发送外部消息 | 强制人工审批、最小权限、可回滚 |
| 极高风险 | 资金划转、权限提升、生产破坏性变更 | 双人审批或禁止 Agent 直接执行 |
风险分级不应只由模型自行决定。模型可以提出风险判断,但最终级别应由策略引擎根据动作类型、资源敏感度、环境和身份共同计算。
例如:
同样是“修改配置”:
测试环境 + 非敏感配置 = 中风险
生产环境 + 鉴权配置 = 高风险
核心支付系统 + 权限配置 = 极高风险
动作风险来自动作、目标、环境和后果的组合,不能只看动作名称。
七、审计链:没有记录,就没有真正的分权
三权分立的价值之一,是出了问题以后能够回答:
- 感知层当时看到了什么?
- 数据来自哪里,是否已经过期?
- 规划层为什么选择这个方案?
- 哪条策略允许了执行?
- 最终调用了什么工具、修改了什么资源?
- 是否经过人工审批?
- 能否恢复到变更前状态?
因此,每个执行事件至少应记录:
{
"task_id": "task-20260822-001",
"actor": "agent-runtime",
"action": "delete",
"target": "./workspace/cache.tmp",
"observation_id": "obs-123",
"plan_id": "plan-456",
"policy_version": "policy-2026-08-22",
"approval_id": "approval-789",
"authorization": "allowed",
"before_hash": "…",
"after_hash": "…",
"rollback_ref": "backup-001",
"timestamp": "2026-08-22T10:00:00Z"
}
审计日志应尽量满足:
八、三个常见误区
误区一:三个函数就是三权分立
如果三个函数共享同一个可变上下文,并且规划结果能直接调用工具,那么只是代码分层,不是信任分层。
改进方式:使用结构化产物、独立策略判定和显式授权令牌。
误区二:所有动作都强制人工确认
这会让 Agent 失去效率,也会导致用户形成“无脑点击批准”的习惯。
改进方式:低风险动作自动化,高风险动作审批,极高风险动作禁止或采用双人复核。
误区三:只看成功率,不看副作用
如果 Agent 通过跳过困难任务来提升成功率,指标看起来变好,真实能力却可能下降。
改进方式:同时定义收益指标、失败条件和副作用指标,例如:
任务成功率提升
且跳过率不升高
且越权尝试为 0
且回滚成功率达到目标
且长尾延迟不超过上限
一个不满足硬性安全条件的版本,即使业务指标更高,也不应自动发布。
九、如何从零落地一套三权分立式 Agent?
建议按以下顺序推进,而不是一开始就追求复杂的多 Agent 系统。
第一步:先盘点工具和动作
建立工具清单,标记每个工具的:
- 读/写属性;
- 目标资源;
- 是否可逆;
- 最大影响范围;
- 所需身份;
- 是否允许自动执行。
第二步:把自然语言输出改成结构化协议
不要让规划模型直接输出一段供执行器解析的自然语言。应使用严格 Schema,例如:
{
"action": "update_config",
"target": "test-service",
"parameters": {
"key": "timeout",
"value": 30
},
"risk_level": "medium",
"rollback": "restore-config-version-17"
}
服务端仍需重新校验字段、类型、范围和目标权限,不能因为格式符合 Schema 就自动放行。
第三步:建立策略中心
将授权规则从 Prompt 和业务代码中抽离出来,集中管理:
- 允许的动作;
- 资源范围;
- 用户与 Agent 身份;
- 环境限制;
- 审批要求;
- 频率限制;
- 策略版本和生效时间。
第四步:为高风险动作设计回滚
如果动作不可逆,就不应轻易交给自动执行器。能回滚的动作,也必须先验证回滚方案确实可用,而不是只在文档里写一句“支持回滚”。
第五步:先在沙箱中验证
第一阶段建议限制为:
只读工具
测试环境
虚拟资源
固定数据集
短生命周期凭证
完整审计
经过一段时间的异常样本积累后,再逐步扩大授权范围。
十、一个可执行的上线检查清单
架构层
- 感知、规划、执行是否有明确职责边界?
- 执行器是否不信任模型直接给出的权限结论?
- 是否存在独立策略判定?
- 高风险动作是否默认拒绝?
数据层
- 是否记录事实来源和时间戳?
- 是否区分事实、推断和未知项?
- 是否防止提示词注入内容直接成为授权依据?
- 敏感数据是否经过最小化和脱敏?
执行层
- 工具参数是否进行服务端校验?
- 是否限制目标资源范围?
- 是否设置超时、限流和幂等机制?
- 是否支持预览、模拟执行和回滚?
治理层
- 是否保留完整审计链?
- 是否可以定位到策略版本和审批人?
- 是否定义了失败条件和停止条件?
- 是否进行了异常、越权和故障恢复演练?
十一、总结:优秀的 Agent,不是更敢做,而是更知道何时不能做
当 Agent 只有问答能力时,提示词和模型效果可能是主要关注点;当 Agent 开始操作真实系统时,权限、审计、隔离、回滚和策略就必须成为一等公民。
“三权分立式 Agent”并不是要求每个系统都部署三个独立模型,而是要求系统在架构上明确区分:
- 感知层负责提供事实,不负责授予权限;
- 规划层负责提出方案,不负责直接执行;
- 执行层负责落实动作,但必须重新验证授权。
最终可以用一句话概括这套方法:
让能力可以演进,让权限不能漂移;让决策可以加速,让高风险动作必须留下证据。
Agent 的成熟度,不只体现在它能完成多少任务,也体现在它能否在证据不足、权限不明、状态冲突或风险超限时,稳定地选择“暂停”。
这不是 Agent 的退缩,而是企业级智能体真正可靠的开始。
网硕互联帮助中心




评论前必须登录!
注册