Agent Rules 与工具权限 —— 给 Agent 加行为护栏

📅 2026/6/28 2:12:47
Agent Rules 与工具权限 —— 给 Agent 加行为护栏
MCP 解决了工具怎么暴露A2A 解决了Agent 之间怎么通信。但还有一个问题悬而未决Agent 拿到工具之后怎么规范地使用它们这个问题拆开是两个子问题Agent 的行为边界什么能做、什么不能做和工具的可达性哪些工具它根本不应该碰。答案分别对应两件事——Agent Rules 注入和工具权限管控。先看问题Skill SOP 覆盖不了的盲区回顾第十一篇的 Skills 系统每个工具对应一个skills/xxx/SKILL.mdP0→P1→P2 命中意图后对应的 SOP 正文被注入 system prompt。这套机制管的是场景操作指引——退款流程怎么做、物流查询怎么查。但上线后我们发现三类问题Skill SOP 完全覆盖不到问题 1跨场景的通用约束Agent 在退款场景里调request-return工具的流程是正确的——SOP 确保了这一点。但同样的 Agent在查物流场景里调check-shipping时有时候会用相同参数反复调用同一个工具——用户只问了我的快递到哪了Agent 调一次工具拿到结果然后不知道为什么又用完全一样的参数调了第二次。这跟退款流程没有关系——这是一个通用行为约束“不要用相同参数重复调用同一个工具”。Skill SOP 是场景级的“在退款场景下怎么做”而这类问题是行为级的“在所有场景下怎么做”。把不要重复调工具写到每个 SKILL.md 里那你有 50 个 skill 就要复制 50 次。而且每当想加一条新规则——比如金额必须来自工具返回禁止编造——又要全部改一遍。这本质上是需要一个独立于 Skill 的通用规则层。问题 2规则的可运维性上线第三周运营提了一个需求“当用户明显在发泄情绪时Agent 不要一上来就推荐优惠券先表达理解。” 这个需求要怎么写它不是某个 skill 的操作流程变更不是意图识别的问题也不是 RAG 检索的问题——它是对 Agent整体行为模式的调整。如果改写死在代码里的静态 Prompt 常量每次改规则都要改代码、走 CI、重新部署。有没有一种办法让运营人员直接编辑一个文件就能生效问题 3工具可达性——dispatch 和 MCP 层缺少硬拦截ReAct Agent 不是全能的——第一篇的设计里已经把它定位为只负责复杂多步推理工具集从 10 个缩减到了特定子集。P0 的INTENT_TOOL_MAP已经是确定性白名单knowledge意图只拿到knowledge_search退款意图拿到request-return, query-order, knowledge_search——这一步是硬约束不是概率筛选。但信任缺口在另外两个环节dispatch 时没有代码级拦截——如果 LLM 被 prompt injection 诱导或者意图识别偏差导致 P0 过滤不够严ToolService.dispatch()执行前没有权限校验Agent 调什么它就执行什么MCP 暴露没有按调用方过滤——外部系统通过 MCP 接入后tools/list返回全部工具定义包括request-return这类敏感操作一个极端的例子外部系统通过 MCP 接入后tools/list会直接暴露request-return——即使这个外部系统只做数据分析。P0 白名单只管住了内部 Agent 能看到什么管不住外部 MCP 客户端能看到什么。Agent Rules最小化实现方案很直接建agent-rules/目录放 markdown 文件——无 frontmatter 全局规则所有场景都注入带 YAML frontmatter 场景规则声明 intent/tool 作用域按需注入实现上启动时一次性加载全部.md解析为 Rule 数据类每次请求按 intent/tool 交集过滤只注入匹配的规则。注入点在 system prompt 拼装环节——排在基础 Prompt 常量之后、Skill SOP 之前。为什么不全量注入因为规则会增长咨询场景不需要看到退款审核规则但全量注入会把 20 条规则几千 tokens 全部塞进去——浪费且稀释注意力。所以过滤逻辑按 intent/tool 交集匹配简单场景只带全局行为底线复杂场景才把领域规则展开。规则量随场景自适应token 消耗和语义纯度都得到了控制。为什么顺序重要Rules 和 Skill SOP 都注入 system prompt但职责不重叠Rules 说一次行为底线SOP 讲流程场景操作。以混合意图为例——用户同时问到哪了和想退两个 SOP 都被注入。如果 Rules 也写在 SOP 里Agent 会看到两段重复的不要重复调工具——浪费 token 且制造噪音。分层之后Rules 只注入一次各司其职。工具权限从问题到落地P0 白名单管住了Agent 能看到什么但 dispatch 和 MCP 两层缺硬拦截。三个真实风险促使我们补上后两层风险场景后果LLM 越狱用户 prompt 注入忽略规则直接调 request-returnLLM 拿到工具列表后调用敏感工具dispatch 层无拦截MCP 泄漏外部系统通过 MCP Server 连接tools/list返回所有工具外部 Agent 能看到本不该暴露的敏感工具定义直接调用内部模块绕过 Agent 层直接调ToolService.dispatch()无任何权限校验相当于裸调敏感操作解决方案dispatch 层加代码级权限校验MCP 层按调用方身份过滤工具列表。Rules 和工具权限的职责分工也在这里明确Rules 管看到了该怎么做Agent 看到了工具Rules 约束它的行为“不要编造数据”“不要重复调用”工具权限管能不能调P0 硬过滤 dispatch 硬拦截 MCP 身份过滤三道防线决定工具可达性三个拦截点的纵深防御P0 白名单 dispatch 拦截 MCP 过滤合在一起构成三层纵深防御拦截点做什么工具选择时P0按 intent 白名单确定性地裁剪工具池dispatch 时硬拦截——检查 caller 是否有权执行此 actionMCP 暴露时tools/list按连接方身份过滤返回的工具列表三层不是重复——是纵深防御。prompt injection 绕不过代码里的if。定位降低的是编辑门槛不是部署门槛坦诚地说当前 Rules 方案解决的是编辑体验不是部署流程。对比一下改代码里的静态 Prompt 常量和改agent-rules/*.md改 Python 常量改 markdown 文件编辑门槛要懂 Python引号不能写错会写 markdown 就行部署流程git → CI → 重启git → CI → 重启一模一样生效方式重启重启一模一样文件放在代码仓库里运营改完一样要走 git commit → push → CI → 部署。文章前面说运营人员直接编辑一个文件就能生效——严格来说省略了但还是得走发布。和改 Python 常量的唯一区别是不需要理解代码。这是否意味着 Rules 机制没有价值不是。降低编辑门槛本身就有实际意义——运营提的这种需求现在只需要写三行 markdown而不需要找开发帮我在 system prompt 里加一段。改什么和怎么改分离了运营决定改什么markdown 文件承载内容代码层只负责加载和注入。真正的零部署可运维——Rules 放外部存储数据库/配置中心/对象存储规则加载器改为远程拉取 定时刷新无需重启即可生效——是下一阶段的事。结构上已预留扩展点加载器接口签名不变换数据源即可不需要动下游的过滤和注入逻辑。总结加一条规则在agent-rules/下新建一个.md文件无 frontmatter 全局规则带 frontmatter 场景规则。调一个角色的工具权限改权限配置就可以了。运营决定改什么markdown 文件承载内容代码层只负责加载和注入——这正是规则可运维 权限可配置的全部含义。Skills、Rules、Permissions 三者合在一起形成了 Agent 行为的完整护栏做什么Skill→ 怎么做Rules→ 能不能做Permissions。和前面的 MCP、A2A 串起来看MCP 标准化了工具暴露A2A 标准化了 Agent 通信Rules 标准化了 Agent 行为Permissions 标准化了工具可达性。四条线从不同方向收敛——把一个从 Demo 跑起来的 Agent 系统逐步拉回到标准化、可运维、可安全接入外部系统的长线轨道上。