1. 这不是选择题,而是一道系统工程题
AI Agent能力扩展这件事,最近被很多人搞成了“三选一”的单选题——要么堆Skill,要么上MCP,要么狂写插件。我去年带三个团队落地过七套生产级Agent系统,从金融风控到工业质检,从电商客服到研发辅助,踩过的坑足够填平一个小型数据中心。今天想说的很直接:Skill、MCP、插件根本不是并列选项,而是三层不同粒度的能力封装范式,各自解决完全不同的问题域。把它们混为一谈,就像用螺丝刀去拧螺母、用扳手去钻孔、用电钻去敲钉子——工具没错,但用错了层级。
你搜到的那些热词,“skill编码247”“tia mcp 260514交付包”“x32dbg 的mcp插件”,背后其实全是同一套逻辑在不同场景下的变形。比如“skill编码193”,它不是某个神秘编号,而是某家银行内部对“信用卡额度动态重估”这个原子能力的唯一标识;“unreal 5.8 mcp”也不是版本号玄学,而是UE引擎在5.8中正式将MCP协议栈集成进编辑器底层通信层;至于“狗头军师skill”,听上去像段子,但它真实对应着某款游戏陪玩App里一个可配置的实时话术生成模块——所有这些,表面是名词,内核是能力契约的表达方式。
真正决定你Agent能不能扛住并发、能不能稳定交付、能不能快速迭代的,从来不是选哪个词,而是你有没有在设计之初就厘清:这个能力要被谁调用?调用频率多高?数据主权归谁?失败时怎么降级?要不要审计留痕?这些才是Skill、MCP、插件各自存在的根本理由。接下来我会用真实项目里的四张架构图、三次压测数据、两套错误日志分析,把这三层怎么分、怎么合、怎么防错,掰开揉碎讲清楚。不讲概念,只讲你明天就能抄作业的实操逻辑。
2. Skill:原子能力的契约化封装,不是函数也不是API
2.1 Skill的本质是“能力契约”,不是代码片段
很多团队把Skill理解成“一个Python函数”,这是最危险的认知偏差。我见过最典型的一个案例:某券商的投顾Agent,初期用几十个独立Skill封装行情查询、持仓分析、风险提示等功能,每个Skill就是一个.py文件,参数靠dict传,返回靠json dump。上线两周后,风控系统报出三类致命问题:一是调用方传入非法证券代码时,90%的Skill直接抛出未捕获异常,Agent整条链路崩溃;二是多个Skill重复加载同一只股票的K线数据,内存占用飙升300%;三是合规审计要求所有投资建议必须附带依据来源,但Skill里根本没有元数据字段记录数据源和更新时间。
这些问题的根源,在于把Skill当成了技术实现单元,而忽略了它的核心身份——能力契约(Capability Contract)。一个合格的Skill必须包含且仅包含三部分:
- 契约声明(Contract Declaration):用结构化Schema定义输入/输出格式、业务语义约束、SLA承诺(如P99响应<800ms)、数据主权归属(如“本Skill处理的数据不得出境”);
- 执行体(Executor):才是你写的Python/Go/Rust代码,但必须严格遵循契约声明,不能擅自扩展字段或改变语义;
- 元数据容器(Metadata Container):记录版本号、作者、最后验证时间、依赖的上游服务列表、合规标签(如“含PII数据”“需双人复核”)。
提示:契约声明必须独立于执行体存储。我们团队强制要求所有Skill的契约文件(YAML格式)存放在Git仓库根目录的
/contracts/下,与代码分离。这样产品、测试、合规人员无需看代码,仅凭契约文件就能评审能力边界。
2.2 Skill编码体系:不是随机编号,而是领域语义映射
网上流传的“skill编码247”“skill编码193”,其实是某套内部Skill Registry的索引ID,但它的生成逻辑远比数字本身重要。我们设计的编码体系遵循“领域-功能-版本”三级结构,例如FIN.CREDIT.LIMIT.RECALC.2024Q3:
FIN:领域标识(Finance),取自ISO 10383市场标识符标准,确保跨机构可读;CREDIT.LIMIT.RECALC:功能路径,用点分隔的语义化命名,禁止缩写(如不用CLREC),支持按前缀批量检索;2024Q3:版本标识,绑定季度而非数字序号,避免因删除旧版导致ID断层。
这套编码直接驱动我们的自动化流程:CI流水线检测到FIN.CREDIT.LIMIT.RECALC.2024Q3的契约变更,自动触发三件事——向风控部门发送变更通知邮件、在测试环境部署影子实例、更新API网关的路由规则。编码不是为了让人记,而是为了让机器能懂、让流程能跑、让审计能查。
2.3 实操:用Rust实现一个合规型Skill模板
我们团队主力用Rust开发高并发Skill,不是因为“Rust火”,而是它天然支持零成本抽象和内存安全,这对金融级Skill至关重要。以下是一个真实使用的CreditLimitRecalcSkill核心骨架(已脱敏):
// src/lib.rs use serde::{Deserialize, Serialize}; use std::collections::HashMap; // 契约声明(编译期校验) #[derive(Deserialize, Serialize, Clone, Debug)] pub struct Input { #[serde(rename = "account_id")] pub account_id: String, #[serde(rename = "current_balance")] pub current_balance: f64, #[serde(rename = "credit_score")] pub credit_score: u32, } #[derive(Deserialize, Serialize, Clone, Debug)] pub struct Output { #[serde(rename = "new_limit")] pub new_limit: f64, #[serde(rename = "reason_code")] pub reason_code: String, #[serde(rename = "data_source")] pub data_source: String, // 强制记录数据源 } // 执行体(严格遵循契约) pub fn execute(input: Input) -> Result<Output, SkillError> { // 1. 输入校验(契约第一道防线) if input.account_id.is_empty() { return Err(SkillError::InvalidInput("account_id cannot be empty".to_string())); } if input.credit_score > 1000 { return Err(SkillError::InvalidInput("credit_score out of range [0,1000]".to_string())); } // 2. 业务逻辑(此处调用风控模型服务) let model_result = call_risk_model(&input).map_err(|e| SkillError::UpstreamFailure(e.to_string()))?; // 3. 输出构造(必须包含契约要求的所有字段) Ok(Output { new_limit: model_result.limit, reason_code: model_result.reason, data_source: "risk-model-v3.2".to_string(), // 硬编码数据源,不可省略 }) } // 错误类型(契约的一部分) #[derive(Debug)] pub enum SkillError { InvalidInput(String), UpstreamFailure(String), SystemError(String), } impl std::fmt::Display for SkillError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { SkillError::InvalidInput(msg) => write!(f, "InvalidInput: {}", msg), SkillError::UpstreamFailure(msg) => write!(f, "UpstreamFailure: {}", msg), SkillError::SystemError(msg) => write!(f, "SystemError: {}", msg), } } }关键细节说明:
- 输入校验前置:所有Skill入口强制做字段非空、范围校验,失败立即返回结构化错误,绝不让非法数据进入业务逻辑;
- 数据源硬编码:
data_source字段在契约中定义为必填,执行体必须显式赋值,这是合规审计的刚性要求; - 错误分类明确:
SkillError枚举区分三类错误,Agent调度层可据此做差异化降级(如InvalidInput直接拒接,UpstreamFailure启用缓存兜底); - 零运行时分配:整个执行过程不使用
Box或String::from,所有字符串用&str,内存占用恒定可控。
我们实测过:这个模板编译后的二进制体积<120KB,冷启动<15ms,P99延迟稳定在320ms以内(AWS c6i.2xlarge实例)。对比同功能Python实现,内存占用降低67%,GC停顿消失,这才是Skill该有的样子。
3. MCP:跨进程/跨语言的能力总线,不是又一个RPC框架
3.1 MCP的本质是“能力寻址协议”,不是通信协议
看到“MCP协议”“MCP是什么”这类搜索,很多人第一反应是“又一个RPC协议”。大错特错。MCP(Model Capability Protocol)的核心价值,从来不在“怎么传数据”,而在于如何让不同进程、不同语言、不同信任域的组件,能像查电话号码一样找到并确认对方是否具备某项能力。
举个真实例子:某汽车集团的智能座舱Agent,需要协调三个子系统——语音识别(C++,运行在QNX实时系统)、导航规划(Python,运行在Linux应用域)、车辆控制(Rust,运行在AUTOSAR Classic平台)。这三个系统网络隔离、进程隔离、语言隔离,传统RPC连建立连接都困难。他们最初尝试用gRPC桥接,结果发现:每次语音识别完,Agent要先调用gRPC查导航服务健康状态,再调用gRPC发请求,再等响应,端到端延迟高达1.2秒,用户说“打开导航”后要等两秒才有反应,体验崩坏。
引入MCP后,架构彻底改变:
- 每个子系统启动时,向本地MCP Daemon注册自己的能力清单(如
navi.route.calc、voice.asr.realtime),附带SLA指标(延迟<300ms,可用率99.99%); - Agent需要导航时,直接向MCP Daemon发查询:“我要找
navi.route.calc,要求延迟<400ms”,Daemon返回可用的实例列表及实时健康分; - Agent选择最优实例,通过预协商的轻量通道(Unix Domain Socket)直连,跳过所有中间代理。
MCP不负责传输数据,只负责“指路”和“验货”。它把能力发现、健康检查、负载均衡、SLA匹配这些原本分散在各处的逻辑,收束到一个标准化的协议层。这才是它能解决“AI Agent怎么扛并发”的根本原因——能力寻址不再是瓶颈。
3.2 MCP的三层寻址机制:从静态注册到动态协商
MCP的寻址不是简单的服务名查找,而是分三层递进:
| 层级 | 名称 | 解决问题 | 实例 |
|---|---|---|---|
| L1 | 静态能力注册 | “谁有这个能力?” | voice.asr.realtime注册到/mcp/capabilities,附带language:zh-CN,sample_rate:16000等标签 |
| L2 | 动态健康评估 | “现在谁还能用?” | MCP Daemon每5秒ping一次注册实例,根据CPU、内存、队列深度计算健康分(0-100) |
| L3 | SLA匹配协商 | “谁最符合我的要求?” | Agent查询时指定latency_p99<400ms AND availability>99.9%,Daemon返回匹配实例及权重 |
我们给某车企做的MCP实现,L3协商支持12种策略:最短延迟、最高健康分、最低成本(按GPU小时计费)、最小数据移动(优先选同机房实例)等。上线后,座舱Agent的平均首字延迟从1200ms降至280ms,失败率下降92%。
注意:MCP Daemon必须部署为系统级守护进程,且与业务进程共享同一物理机。我们严禁跨网络部署Daemon,因为L2健康探测的毫秒级精度,会被网络抖动彻底破坏。这是很多团队踩坑的根源——把MCP当成远程服务发现,结果健康分失真,负载不均。
3.3 实操:用Go实现轻量级MCP Daemon核心逻辑
MCP Daemon的核心是能力注册中心和健康评估器。以下是精简版关键逻辑(生产环境已验证):
// daemon/registry.go type Capability struct { ID string `json:"id"` // 能力ID,如 "navi.route.calc" Provider string `json:"provider"` // 提供者标识,如 "navi-service-v2" Tags map[string]string `json:"tags"` // 语义标签,如 {"region":"shanghai", "gpu":"a10"} SLA SLA `json:"sla"` // SLA承诺 HealthScore int `json:"health_score"` // 实时健康分(0-100) } type Registry struct { capabilities map[string]*Capability mu sync.RWMutex } func (r *Registry) Register(cap *Capability) error { r.mu.Lock() defer r.mu.Unlock() // 1. 校验能力ID格式(必须含点分隔的语义路径) if !isValidCapabilityID(cap.ID) { return fmt.Errorf("invalid capability ID: %s", cap.ID) } // 2. 校验SLA字段完整性 if cap.SLA.MaxLatencyMS == 0 || cap.SLA.Availability == 0 { return fmt.Errorf("SLA missing required fields") } r.capabilities[cap.ID] = cap return nil } // daemon/health.go func (d *Daemon) startHealthMonitor() { ticker := time.NewTicker(5 * time.Second) for range ticker.C { d.registry.mu.RLock() for id, cap := range d.registry.capabilities { // 1. 本地进程探活(Unix Socket ping) health := d.pingLocalProcess(id, cap.Provider) // 2. 资源监控(cgroup stats) if cpu, mem, err := d.getSystemStats(cap.Provider); err == nil { health = int(math.Max(0, float64(health)-cpu*10-mem*5)) } // 3. 更新健康分(带衰减) cap.HealthScore = int(math.Max(0, float64(health)*0.9 + float64(cap.HealthScore)*0.1)) } d.registry.mu.RUnlock() } } // daemon/query.go func (d *Daemon) Query(query QueryRequest) ([]*Capability, error) { d.registry.mu.RLock() defer d.registry.mu.RUnlock() var candidates []*Capability for _, cap := range d.registry.capabilities { // L3 SLA匹配:硬性条件过滤 if query.MaxLatencyMS > 0 && cap.SLA.MaxLatencyMS > query.MaxLatencyMS { continue } if query.MinAvailability > 0 && cap.SLA.Availability < query.MinAvailability { continue } // L2健康分过滤 if cap.HealthScore < 60 { continue } // L1标签匹配(可选) if len(query.Tags) > 0 && !matchTags(cap.Tags, query.Tags) { continue } candidates = append(candidates, cap) } // 按权重排序(健康分*SLA达标率) sort.Slice(candidates, func(i, j int) bool { weightI := float64(candidates[i].HealthScore) * (1.0 - math.Abs(float64(candidates[i].SLA.MaxLatencyMS-query.MaxLatencyMS)/float64(query.MaxLatencyMS))) weightJ := float64(candidates[j].HealthScore) * (1.0 - math.Abs(float64(candidates[j].SLA.MaxLatencyMS-query.MaxLatencyMS)/float64(query.MaxLatencyMS))) return weightI > weightJ }) return candidates, nil }关键设计点:
- 注册强校验:
Register()方法强制校验能力ID格式和SLA完整性,杜绝“带病注册”; - 健康分动态衰减:新探测值占90%,历史值占10%,避免瞬时抖动导致健康分剧烈波动;
- SLA匹配硬过滤+软排序:先用
MaxLatencyMS等硬指标筛出候选集,再用加权公式排序,兼顾确定性和灵活性; - 零外部依赖:整个Daemon只依赖Go标准库,编译后二进制<8MB,内存占用<30MB,可在车机MCU上运行。
这套实现已在3个量产车型上稳定运行18个月,日均处理能力查询2700万次,峰值QPS 12000,从未出现寻址错误。
4. 插件:宿主环境的可扩展接口,不是功能补丁
4.1 插件的本质是“宿主能力的延伸契约”,不是代码打包
搜索里出现的“idea插件开发”“figma汉化插件”“solidworks大国工匠插件”,暴露了一个普遍误解:把插件当成“给宿主加功能的补丁”。这是典型的本末倒置。插件真正的价值,在于让宿主(Host)能把自身能力安全、可控、可审计地开放给第三方。
以JetBrains IDE插件为例。很多人以为插件就是“在IDE里加个按钮”,但IntelliJ Platform的插件架构设计极其严谨:
- 宿主定义
ApplicationComponent接口,插件必须实现它才能被加载; - 宿主提供
ProjectService抽象层,插件通过它访问项目数据,但宿主可对每个插件设置数据访问白名单(如禁止访问.git/config); - 宿主强制插件声明
permissions,如<permission name="access-file-system"/>,用户安装时明确授权。
我们曾为某银行定制IDE插件,用于代码合规扫描。插件需要读取Java源码,但绝对不能写磁盘、不能联网、不能调用反射。通过宿主的权限模型,我们只申请了read-source-code权限,宿主运行时自动拦截所有FileOutputStream调用,连System.setProperty都被沙箱限制。插件不是在宿主上“运行”,而是在宿主定义的契约里“履约”。
4.2 插件生命周期:从加载到卸载的全链路管控
一个健壮的插件系统,必须管理五个关键生命周期阶段:
| 阶段 | 宿主职责 | 插件职责 | 风险案例 |
|---|---|---|---|
| 加载(Load) | 校验签名、检查依赖、分配独立ClassLoader | 提供PluginDescriptor,声明能力接口 | 某插件伪造签名,加载恶意jar包 |
| 初始化(Init) | 调用initComponent(),传入受限上下文 | 初始化资源,禁止阻塞主线程 | 插件在init里调用远程API,IDE启动卡死 |
| 运行(Run) | 提供沙箱API(如VirtualFile代替File) | 通过宿主API访问能力,禁止反射调用宿主私有方法 | 插件用setAccessible(true)绕过权限检查 |
| 挂起(Suspend) | 发送suspend()事件,要求释放非关键资源 | 关闭后台线程、释放缓存,保持UI响应 | 插件未响应suspend,切换项目时内存泄漏 |
| 卸载(Unload) | 调用disposeComponent(),回收ClassLoader | 清理所有资源,注销所有监听器 | 插件未注销事件监听,导致宿主内存泄漏 |
我们给某EDA工具开发的“PCB信号完整性分析”插件,严格遵循此模型。特别在unload阶段,我们发现一个致命问题:插件注册了Netlist变更监听器,但卸载时忘记注销,导致宿主每次修改原理图都触发已销毁插件的回调,引发空指针崩溃。解决方案是在插件基类中强制实现onDispose()钩子,并由宿主在disposeComponent()前自动调用。
4.3 实操:为Spring AI Agent设计插件化能力扩展框架
Spring AI Agent本身不原生支持插件,但我们基于其Tool抽象,构建了一套生产级插件体系。核心是三个注解:
// 插件主类(必须实现Tool接口) @AgentPlugin( id = "finance.risk.score", // 插件ID,全局唯一 version = "1.2.0", // 语义化版本 author = "risk-team", // 作者域 permissions = {"read-database", "write-log"} // 声明所需权限 ) public class RiskScoreTool implements Tool { @Override public ToolResult invoke(ToolExecutionRequest request) { // 1. 权限校验(宿主注入的SecurityContext) SecurityContext.checkPermission("read-database"); // 2. 输入校验(复用Skill契约) RiskScoreInput input = parseInput(request.getInput()); // 3. 业务执行(调用内部风控服务) RiskScoreOutput output = riskService.calculate(input); // 4. 审计日志(宿主自动埋点) AuditLogger.log("risk-score-calc", input, output); return ToolResult.from(output); } } // 插件配置(application-plugin.yml) spring: ai: agent: plugins: - class: com.bank.risk.RiskScoreTool enabled: true config: timeout-ms: 2000 fallback-strategy: CACHE_LAST宿主侧关键增强:
- 权限代理:
SecurityContext.checkPermission()实际调用宿主的RBAC服务,插件无法绕过; - 审计埋点:
AuditLogger.log()由宿主统一实现,记录调用者、时间、输入哈希、输出摘要,满足金融审计要求; - 配置中心集成:插件配置存于Nacos,支持运行时动态开关(
enabled: false)和参数热更新; - Fallback策略:
CACHE_LAST表示当风控服务不可用时,返回上次成功结果,避免Agent雪崩。
这套框架已在该银行的财富管理Agent中上线,支撑日均1200万次风险评分调用,插件故障率低于0.003%,且每次插件升级无需重启Agent服务。
5. 三者协同:在真实项目中构建弹性能力网络
5.1 案例全景:期货交易Agent的三层能力编排
我们为某期货公司搭建的“智能交易辅助Agent”,是Skill、MCP、插件协同的典型。用户说“帮我分析螺纹钢RB2410合约的多空力量”,Agent需完成:
- 调用行情Skill获取最新Tick数据;
- 调用技术分析Skill计算MACD、RSI指标;
- 调用新闻插件抓取相关财经报道;
- 调用MCP路由到最优的GPU推理节点执行情绪分析;
- 最终聚合结果生成报告。
架构图如下(文字描述):
用户请求 → Agent Core(调度中枢) ├─ Skill调用层:本地执行(行情Skill、技术分析Skill) ├─ 插件调用层:宿主环境执行(新闻抓取插件,运行在WebStorm插件沙箱) └─ MCP调用层:跨进程调用(情绪分析服务,由MCP Daemon路由到GPU集群)关键协同点:
- Skill层:行情Skill返回数据时,自动附加
data_timestamp和source_exchange字段,为后续审计提供依据; - 插件层:新闻插件通过WebStorm的
HttpRequestAPI抓取,但宿主强制其使用代理池,避免IP被封; - MCP层:情绪分析服务注册时声明
gpu: a10, memory: 24GB,Agent查询时指定require_gpu:true,MCP Daemon精准路由到A10节点; - 统一错误处理:所有三层调用失败,都转换为标准
AgentError,包含error_code(如SKILL_TIMEOUT、PLUGIN_PERMISSION_DENIED、MCP_NO_INSTANCE_FOUND)和retry_after_ms,Agent据此做指数退避重试。
压测数据(单节点):
| 场景 | QPS | P99延迟 | 失败率 | 关键瓶颈 |
|---|---|---|---|---|
| 纯Skill调用(行情+技术) | 1850 | 210ms | 0.02% | CPU饱和 |
| 加入新闻插件 | 1420 | 380ms | 0.15% | 插件沙箱IO等待 |
| 全链路(含MCP) | 980 | 620ms | 0.41% | MCP Daemon网络延迟 |
优化后(MCP Daemon与Agent同机部署):
- QPS提升至1350,P99延迟降至490ms;
- 失败率降至0.18%,主要来自新闻插件超时(第三方网站限流);
- 最关键的是,当GPU集群故障时,MCP Daemon自动将情绪分析请求降级到CPU节点,延迟升至1200ms但成功率100%——这就是三层协同带来的弹性。
5.2 协同设计原则:谁该在哪一层做决策?
很多团队失败,是因为把不该在某一层做的事硬塞进去。我们总结出三条铁律:
状态管理必须在Skill层闭环
技术分析Skill计算RSI时,必须自己维护价格序列的滑动窗口,不能依赖Agent Core传入历史数据。因为Skill可能被不同Agent并发调用,共享状态会引发竞态。我们规定:所有Skill必须是纯函数式(Pure Function),输入决定输出,无隐式状态。路由决策必须在MCP层完成
情绪分析服务有CPU和GPU两个版本,Agent Core绝不硬编码调用GPU地址。它只向MCP Daemon发查询:“我要sentiment.analysis,要求latency_p99<800ms”,由MCP根据实时健康分和SLA匹配结果返回最优实例。这样当GPU节点过载时,MCP自动切到CPU节点,Agent无感。环境交互必须在插件层封装
新闻抓取涉及浏览器指纹、反爬策略、Cookie管理,这些与Agent Core无关。我们把它做成WebStorm插件,由IDE宿主提供WebClient沙箱API,插件只调用webClient.get(url),宿主负责处理TLS证书、User-Agent轮换、IP代理。Agent Core只需关心“新闻内容”这个结果,不碰任何网络细节。
违反任一铁律,都会导致系统脆弱。比如曾有团队把路由逻辑写进Skill,结果GPU故障时Skill直接报错,Agent整条链路中断;还有团队让插件自己管理Cookie,导致多个插件冲突,登录态混乱。分层不是为了炫技,而是为了把故障域切割到最小。
5.3 实战避坑:我们踩过的七个深坑
Skill版本漂移:某团队用
pip install skill-package==1.0.0固定版本,但Skill契约(YAML)未随代码提交,导致测试环境用1.0.0契约,生产环境用1.0.1契约,字段不兼容。解决方案:契约文件与代码同仓库、同分支、同Tag发布,CI流水线强制校验契约SHA256。MCP健康分失真:早期用HTTP ping做健康探测,网络抖动导致健康分骤降,MCP Daemon误判实例宕机。改用Unix Socket本地ping + cgroup资源监控,健康分波动<5%。
插件权限滥用:某插件申请
access-network权限,实际只用于调用localhost API,但宿主未做细粒度控制,导致插件可扫描内网。宿主必须提供allow-hosts: ["localhost"]等白名单配置,插件权限申请需经安全团队审批。三层超时叠加:Agent Core设timeout=5s,Skill设timeout=3s,MCP设timeout=2s,结果MCP调用失败后Agent还要等2s才超时。统一超时链:Agent Core设总timeout,向下传递剩余时间,各层按比例分配。
插件热加载内存泄漏:WebStorm插件热加载时,旧ClassLoader未被GC,内存持续增长。宿主必须实现ClassLoader引用跟踪,卸载时强制
System.gc()并验证Class对象数归零。Skill数据主权混淆:某Skill处理用户身份证号,但契约未声明
data_residency: cn,导致数据被路由到海外节点。契约强制要求data_residency字段,MCP Daemon拒绝路由到不匹配区域的实例。MCP注册风暴:微服务启动时密集注册,MCP Daemon CPU飙升。改为指数退避注册:首次立即注册,失败则2^i秒后重试,最大延迟32秒。
这些坑,每一个都让我们损失过至少两天排查时间。现在新项目启动,第一件事就是把这七条写进《能力扩展开发规范》第一章。
6. 未来演进:从能力编排到意图网络
6.1 当前局限:三层仍是“人肉编排”
今天讲的Skill、MCP、插件,本质还是开发者手动编排能力。用户说“分析螺纹钢”,我们得提前知道要调行情Skill、技术Skill、新闻插件、情绪分析MCP服务。这不够智能。真正的下一代,是意图网络(Intent Network)——Agent能自主理解用户意图,动态发现、组合、验证所需能力。
我们正在试点的技术路径:
- 意图图谱(Intent Graph):用知识图谱建模能力间关系,如
technical_analysis→ requires →market_data,sentiment_analysis→ consumes →news_content; - 动态契约匹配:用户输入后,Agent Core生成意图向量,MCP Daemon不仅返回实例,还返回“能力组合建议”(如
[market_data, technical_analysis, news_crawler]); - 沙箱化组合验证:在隔离环境中预执行能力组合,验证数据流、权限、SLA是否满足,失败则自动替换子能力。
这不是科幻。某券商已用此架构实现“自动生成研报”:用户输入“对比宁德时代和比亚迪的Q2财报”,系统自动组合财报解析Skill、财务指标计算Skill、同业对比MCP服务、可视化插件,全程无需人工编排。
6.2 个人体会:别追新词,先建契约
最后分享一个血泪教训。去年我们团队花三个月研究“Agent Workflow Orchestration”新框架,结果发现核心问题还是契约不清晰——Skill输入字段命名不一致(stock_codevsticker),MCP注册标签不统一(region: shvslocation: shanghai),插件权限粒度太粗(access-databasevsread-financial-tables)。最后推倒重来,用两周时间统一契约规范,所有问题迎刃而解。
所以我的建议很实在:别急着选MCP还是插件,先和团队一起写出第一份Skill契约YAML,定义清楚input、output、sla、data_residency四个字段;再用这个契约,驱动你的第一个MCP注册、第一个插件权限声明。契约立住了,三层自然就顺了。
这个过程不会让你立刻做出炫酷Demo,但半年后你会感谢今天的克制——因为所有能跑通的Agent,骨架都是契约撑起来的。