让 Agent 会干活不难,难的是让它干得安全、可控、有迹可循。prompt 约束是软的,Agent 一旦"自信"起来就会绕过;真正的安全边界,要靠工程架构来保障。

图片

一、架构总览:MCP、Skills、Hooks 三者的关系

MCP 为 Agent 接入平台能力——以 tools 的形式,让 Agent 按接口定义发送请求、调用后端。

但单个工具调用凑不成完整流程。工具之间如何协作、按什么顺序串联,需要 Skills 来编排——Skills 与业务紧密绑定,定义"先做什么、再做什么、失败怎么办"。

即便有了流程,Agent 在调用时仍会出问题:参数一多就丢字段,复杂嵌套就误填,偶尔还擅自调用高风险工具造成意外伤害。Hooks 正是在 Agent 发起工具调用(以及 Skills 内脚本执行)时进行规则拦截,保障安全运行;同时记录审计日志,让每次调用有迹可循。

二、MCP 设计:Agent 需要一个应用市场

2.1 MCP 协议原理解析:Tools、Resources、Prompts 三原语

MCP(Model Context Protocol)协议中,Server 暴露给 Client 三种核心原语:ToolsResourcesPrompts。要理解 Agent 插件怎么设计,先要理解这三种原语在 Agent 运行时分别是如何被加载和使用的。

Tools:启动时批量注册,注入 system prompt

Agent 启动时,CodeBuddy 框架向所有已配置的 MCP Server 发送 tools/list 请求,拿到完整的工具清单。每个工具是一个结构体:name(工具名)、description(功能描述)、inputSchema(参数的 JSON Schema)。这些定义会被注入到 LLM 的 system prompt 中——LLM "看到"的不是函数指针,而是一段文本描述:"你可以调用 workflow_create,它接受 name(必填, string)、spaceId(必填, int64)……"

Resources:惰性拉取,Agent 按需查询

Resources 不像 Tools 那样启动时一次性拉取。它们的加载是惰性的——Agent 在对话中根据需求主动发起 resources/read 请求。

比如 MCP Server 暴露了 150+ 张数据表作为 Resources(starrocks://tables/...的 URI)。Agent 不会在启动时把所有表的 schema 都拿到,而是等用户说"查一下 ODS 层的员工表有哪些字段"时,才去请求对应的 Resource URI,拿到字段名、类型、注释。这套按需加载机制避免了启动时的通信风暴,也避免了 system prompt 被大量无用信息填满。

Prompts:Server 端预定义的提示词模板

Prompts 是 MCP Server 上预定义的、可参数化的提示词模板。Agent 通过 prompts/list 查看可用模板,通过 prompts/get 获取具体模板并填入参数。与 Tools 不同,Prompts 没有副作用,纯粹是帮助 Agent 更好地理解"在特定场景下该怎么做"。

图片

三种原语的多维对比

维度

Tools

Resources

Prompts

数据流向

双向(参数入 → 结果出)

单向(Server → Client,只读)

单向(Server → Client)

读写

读写

只读

只读

加载策略

启动时批量注册,注入 system prompt

惰性按需拉取,可缓存

惰性按需获取,可缓存

适合场景

CRUD、部署、启停等需要"动手"的操作

表 schema、数据字典、配置文档等大量结构化参考数据

需要标准化引导的重复性任务

核心优势

唯一能修改外部状态的通道

量大不占 prompt 空间,按需加载

可复用、可参数化,保持行为一致

不适合

纯信息查询(用 Resource 更高效)

实时计算任务(应走 Tool)

动态决策(模板会限制推理灵活性)

实战中用好这三种类型的原语,能够提高 agent 调用效率和 token 的使用效率。MCP 协议计划在 2026 年 7 月 28 日发布一次重大更新(当前为候选版),主要是从原来的有状态连接变成无状态连接,这对后续高性能的 MCP 集成是一次重大的进步,MCP 逐渐会成为 Agent 更坚实的基础设施。具体的内容可以参考这个博客。

(https://blog.modelcontextprotocol.io/posts/2026-07-28-release-candidate/)

2.2 自建 MCP Server 的实践与反思

最初方案是自建一个 Spring Boot MCP Server——在 Agent 和 DES 后端之间架一套中间代理(Agent → MCP → des-mcp-server → REST → DES Backend)。

自建的好处是自由度极高——工具注册策略、参数校验逻辑、错误处理方式都可以自己控制,比如可以按业务域灵活分级部署工具。但真正上手之后,两个核心问题逐渐暴露:

  • 架构取舍:如果新建一套 AiController 并直接调用 Service 层来绕过原 Controller,那么原 Controller 上设计的 AOP 切面、并发控制、异常处理等逻辑全部需要在新 AiController 中重做一遍——不是简单的"调用转发",而是整套横切关注点的二次实现。

  • 部署运维:MCP Server 作为一套独立的 Java 服务,构建、部署、监控、扩缩容都需要额外维护——它和服务本身不在同一个交付单元里,版本同步、依赖管理、线上排错都多了一层。

这些本质上不是"做不出来"的问题,而是"值不值得单独维护一个中间代理层"的问题。正是这个判断,让我们把目光转向了部门内已有的基础设施。

2.3 选择 SA-Market:拥抱平台化解决方案

SA-Market 是部门内已有的 MCP 市场,原生支持将 REST API 自动注册为 MCP 工具——上传 Swagger/OpenAPI 规范(后也支持 MCP Json),平台自动解析出 tool schema,无需写一行 MCP 适配代码。架构上同样是一层路由(Agent → MCP 协议 → SA-Market → REST → DES Backend),但省掉了自建中间服务的所有维护成本。这更像是应用市场,能够有一个中心化的平台路由分发各个项目接入的能力,集中管理和维护。

对比自建方案,SA-Market 省掉了两块最大的开销:

  • 不用自建中间服务:2.2 中提到的架构取舍和部署运维问题直接不存在了——不用纠结 AiController 的复用策略,也不用维护独立 Java 服务的构建部署链路

  • 不用手写适配代码:Tool 的 inputSchema 和后端接口入参之间的耦合是绕不开的——自建方案里这份映射靠人工维护,SA-Market 则是上传一份 OpenAPI/JSON 规范,平台自动解析出 MCP 工具定义,省去了手写和维护映射逻辑的工作

图片

三、Skills 设计:用 Mermaid 可视化 SOP,让 Agent 按规矩办事

3.1 多步骤操作的编排困境

MCP 工具就位后,一个完整的业务流程往往要调用多个工具,而且工具的使用有顺序依赖和注意事项。

比如部署一个工作流:

导入 JSON → 保存草稿 → 调试运行 → 修复问题 → 更新 → 发布上线

这不是一个单步 MCP 调用,而是 5-6 个步骤组成的有向无环图。如果靠 LLM "自由发挥"来编排,会出现:

  • 跳步:没调试就直接发布上线,带着 bug 跑

  • 乱序:先 publish 再 save draft —— 状态机冲突

  • 遗漏错误处理:debug_run 失败了不知道怎么修,卡在半路

MCP 工具层解决了"能调用什么",但没有解决"怎么组合调用才是正确的"——这个编排问题,需要 Skills 层来解决。

3.2 Mermaid SOP:用流程图替代文字步骤列表

但是 SOP 类型的 Skill 一旦步骤长、分叉多,纯文本写下来既冗长又难理解。引入 Mermaid 后,几行就能描述一个分支复杂的完整流程。

deploy-workflow Skill 为例,它的 mermaid SOP 大致结构是:

图片

相比于纯文本的步骤列表,Mermaid 的视觉表达让 Agent 能更准确地理解:

  • 哪些步骤是顺序依赖的(A→B→C)

  • 哪里有条件分支(成功→继续,失败→诊断修复)

  • 失败后的回退路径是什么(回到上一步重试)

虽然没有进行量化实验对照,但实际使用效果可以感觉到,Agent 跳步、乱序的问题显著减少,因为 Mermaid 能够在有限的篇幅传达高密度的信息。

3.3 强制走链规则:先走流程,后调工具

除了 SOP 编排,Skills 层还有一条硬约束:某些 MCP 写工具必须先走完对应 Skill 才能调用。例如:

  • 调用 workflow_import tool 前必须先走 des-generator skill —— 确保 JSON 是标准化流程生成的、经过字段校验的

  • 调用 dqc_rule_create tool 前必须先走 dqc-workflow-generator skill → create-dqc skill —— 确保规则参数完整、合规

这条规则在 context.md 中定义为行为规范约束,Agent 在执行写操作前会检查依赖链并引导用户先走 Skill 流程。它不依赖 Hook 层的代码拦截(Hook 层负责的是安全分级),而是在 Agent 的推理层面建立"先走流程、后调工具"的纪律。

图片

四、多平台设计:双平台实战与单源管理

多平台设计:设计规则"在哪里生效"

5.1 双平台实战演示

DES 插件需要覆盖两类用户:

  • CodeBuddy IDE 用户

  • iMate 用户

des-agent-plugin在这两个平台的 Hook 脚本实现语言不同(Python vs JavaScript),但需要一致的安全规则和行为规范

第四章从代码层面拆解了 Hook 引擎的 9 步流水线和 tier 条件链。下面从各平台的实际运行效果来展示拦截和校验在真实对话中长什么样:

CodeBuddy IDE

以下是发布工作流的场景,在用户提到发布工作流时会加载deploy-workflow Skill,发布前会向用户确认当前工作流的信息和状态。

图片

图片

用户确认继续后会进入到下一个阶段,这里的workflow_save_draft是保存草稿,但是其中集成了对工作流的合法性校验,在Skill中定义了在发布前需要执行校验的步骤。在agent调用工具的时候,如果传入的请求体字段不满足hook中约束的字段规则,会执行deny拒绝掉本次调用,并返回所缺少的字段。agent会根据提示信息重新发起一次调用,字段满足后会调起hook弹窗。

用户确认后会按照Skill中定义好的mermaid流程图,进入到下一阶段,这里是在流程图的节点中声明,在调试阶段需要询问用户是否需要调试,这里是要求Agent调用AskUserQuestion工具,这样就能够出现如图的弹窗供用户选择。

图片

iMate 平台

在iMate平台的网页版和企微机器人实现了同样的插件机制,这里展示的是hook弹窗。这里因为iMate在调度mcp的时候使用的是mcporter,调用的命令的形式和CodeBuddy不完全一致,在hook脚本中进行调用匹配的逻辑上做了一些适配。

图片

图片

这里是企微机器人的场景。

图片

5.2 Symlink 单源管理

要适配多平台,又想要在同一个仓库中维护管理插件,解决思路是 Monorepo + Symlink

des-agent-plugin/├── shared/                              ← 唯一的配置源│   ├── rules.json                       (18段, 28KB)│   ├── rules-error-patterns.json        (错误模式库)│   └── context.md                       (Agent行为规范)├── plugins/des-platform/                ← CodeBuddy IDE 插件│   └── hooks/│       ├── rules.json ──⛓── ../../shared/rules.json           (symlink)│       ├── rules-error-patterns.json ──⛓── ../../shared/...   (symlink)│       └── context.md ──⛓── ../../shared/context.md           (symlink)└── platforms/imate/                     ← iMate/OpenClaw 插件    └── src/        ├── rules/rules.json ──⛓── ../../../shared/rules.json     (symlink)        ├── rules/rules-error-patterns.json ──⛓── ../../../...    (symlink)        └── config/context.md ──⛓── ../../../shared/context.md    (symlink)

5.3 Symlink 是怎么工作的

流程很简单:

  1. 如果仓库中已经构建好了软链接,那么git clone获取仓库——Linux/macOS 下 git 原生保留 symlink,clone 后自动生效;Windows 需开启开发者模式并设置 git config core.symlinks true

  2. 若上述条件不满足(如 Windows 未配置),需要运行提前写好的脚本 init-platforms.sh,执行 6 条 ln -sf命令重建 symlink,如果软链接实在无法构建,脚本中还有直接复制过去的fallback

  3. 之后修改 shared/rules.json→ symlink 自动跟随 → 双平台同时生效

对代码本身来说,symlink 是透明的:

  • Python 侧:common.py:load_rules()os.path.dirname(__file__)相对路径读取,文件系统自动解析为 shared/下的实际文件

  • JS 侧:import rules from "../rules/rules.json"中 Node.js 的模块解析自动跟随 symlink

图片

五、规则配置体系:从外化配置到自动化生成

6.1 rules.json:18 段配置的完整体系

所有安全规则、字段校验、DDL 模式、环境映射全部外化到 rules.json 中——不在 pre_tool_guard.py 中硬编码任何规则。

18 段配置的结构从简单到复杂渐进:

#

段名

内容

复杂度

0

version

配置版本号

1

des_servers

MCP URL → 环境名称映射

2

blocked

5 个不可逆删除工具

3

warned

31 个高风险写工具

4

dangerous_scripts

3 个高危 Python 脚本

5

dangerous_ddl_patterns

8 种 DDL 危险语句检测

6

audit

40 个静默审计工具

7

experience_ttl_days

经验闭环 TTL=30天

8

querydata_tools

12 个分页查询工具

9

diagnostic_tools

6 个诊断工具

10

recent_categories

9 条记忆分类映射

11

failure_tips

5 条失败重试指引

12

body_check_tools

14 工具字段完整性(tiers + _array_check 叠加)

13

body_check_ask_user_guides

弹窗引导文案

14

task_property_check_tools

6 个 taskProperties 校验工具

15

task_type_field_checks

4 种 TaskType 分层 tier

16

auto_fill_fields

自动补全默认值

17

diff_tools

3 个差异对比工具

这里的外化相当于将配置文件和代码逻辑进行解耦,便于长期维护。以上的规则配置这里只是给出一个参考的实践方式,具体还可以有更多的发挥空间。

6.2 Agent Plugin Factory:从"做插件"到"做做插件的工具"

在完成 DES 插件之后,我们考虑把设计和开发经验固化为一个元工具:Agent Plugin Factory——给一个 Swagger/OpenAPI 规范,自动生成完整的平台 Agent 插件。目前这套流程还在开发验证阶段,因为不同的系统的具体情况不一样,这里提供一种可参考的方法论,具体的实施和测试环节需要根据具体的情况再进行一些适配上的工作。

四阶段流水线:Swagger/OpenAPI

    ↓Stage 1: Parse — parse_swagger.py 解析所有 API endpoint,提取 path/method/params/schema    ↓Stage 2: Classify — classify_tools.py 按 HTTP 方法自动安全分级:  DELETE / delete → blocked  POST / create|update|import → warned  GET / list|get|query → audit  其他 → pass-through    ↓Stage 3: Detect — detect_querydata.py 检测哪些接口返回 list/rows,标记为 querydata_tools    ↓Stage 4: Generate  ├─ generate_all.py: SA-Market JSON 脚本生成 + 三层校验(语法/语义/集成)  ├─ AI Agent 理解需求并填充 config.yaml → Jinja2 模板引擎渲染 17 文件一键生成  └─ 输出: CodeBuddy 插件 (.mcp.json + hooks + context.md + 8 Skills)         + iMate 插件 (openclaw.plugin.json + JS Hooks)         + SA-Market 注册文件

这里设想着不再只为 DES 这一个平台解决问题,而是把"如何给任意 API 服务生成安全可控的 Agent 插件"的方法论固化为工具,成为能够高自动化将项目转化为集成MCP、Skills、Hooks的Agent插件。

图片

六、总结与展望:构建安全可控的Agent操作框架

回头看这四层设计,每一层解决的是 Agent 操作平台的不同维度问题:

  • MCP 层定义"能操作什么"——72 个工具,4 个环境统一,1 份 Swagger 规范即注册。经验:与其自建中间代理,不如用好已有的基础设施。

  • Skills 层定义"怎么操作才对"——8 个 Skill,Mermaid SOP 可视化,强制走链。经验:让 Agent 按规矩办事,比让它"更聪明"更可靠。

  • Hooks 层定义"被允许怎么操作"——四级分级,9 步流水线,18 段外化规则,170KB 拦截逻辑。经验:安全边界不靠 prompt 保证,靠工程架构保障。

  • 多平台层定义"规则在哪生效"——6 个 symlink,双平台原生 170KB+73KB,不改代码就能同步规则。经验:不做抽象层,用文件系统级的一致性保证逻辑一致。

这四层叠在一起,构建了一个让 Agent 有能力、有规矩、有底线、有一致性的操作框架。

今天的模型能力已经跃过了一道门槛,理解意图、生成代码、自主推理不再是瓶颈。但模型不会自动解决工程问题:安全边界在哪里、操作流程怎么规范、规则怎么在多平台同步。对于Coding Agent的工程化,有人说会是这样的发展链路:

Prompt Engineering -> Context Engineering -> Harness Engineering -> Loop Engineering -> Graph Engineering

但是我在想,这里所设计的工程,也是人类的集体的智慧围绕着大模型搭建起的护栏,那么对于 Agent 本身,我们能否使其涌现出群体的智慧,我们是否知道 Agent 知道多少,Agent 自己本身是否知道自己知道多少,我们到底应该如何定义 Agent 呢?这里也许还需要着长期的探索。

原文链接

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐