接手“闪学it-Agent Skills”这个项目之前,我原本没太把多平台接入当回事。Agent 跑通单个平台容易,真正难的是同一套技能在消息群、任务后台、知识库、数据看板里都能稳定复用。这几个平台各有各的接口风格、权限模型和超时限制,稍不注意就会出现“换个平台就失灵”的尴尬局面。这篇文章想把我在这套 Agent Skills 多平台应用实战中的核心设计、对接细节和踩坑经过整理出来,给正在做智能体落地的团队一个能直接参考的路线图。
我们的内部项目代号就叫“闪学it-Agent Skills”,定位很朴素:把散落在各个业务系统里的 AI 能力,封装成可注册、可调用、可审计的“技能”,一次开发,多平台复用。下面讲的内容,更多是方案层面的取舍和实战中的经验,不是那种“照着文档点下一步”的教程。
1. 为什么非要统一封装一套Agent Skills,而不是每个平台单独做
1.1 多平台接入 Agent 的三种常见姿势
我在早期见过三种做法,也分别吃过它们的亏。
第一种是“墙内开花墙内香”。每个平台都直接内嵌一套提示词,A 平台有 A 平台的话术,B 平台有 B 平台的逻辑。短期看着简单,但一旦业务流程调整,就要到各个平台分别改代码,改完还容易漏,用户在不同平台得到不一致的回复。
第二种是“共享模型,各写各的业务逻辑”。所有平台共用同一个大模型服务,但平台侧各自拼参数、各自处理结果。这个稍微好一点,可依然没有解决“能力复用”的问题。比如两个平台都需要做“客户意向分类”,A 平台写了一套规则,B 平台又写一套,重复造轮子,而且两套规则会逐渐漂移。
第三种是“把 Agent 当中央调度器,所有平台只做消息转发”。这种架构对 Agent 的压力很大,而且一旦 Agent 服务挂了,所有平台全线瘫痪。平台侧没有兜底,也没有可观测性,出了问题只能靠用户截图反馈。
经过这些折腾后,我们才意识到,多平台接入的核心不是“让每个平台都能调用 AI”,而是“让 AI 能力成为一套标准化的企业服务,由平台连接器负责适配”。闪学it-Agent Skills 就是在这个背景下立项的。
1.2 踩过的坑:提示词复制粘贴式复用为什么必崩
你可能觉得,把同一段提示词复制到不同平台不就行了?我一开始也是这么干的,结果第一周就翻车。
同一段提示词,在消息平台上表现很好,到了任务管理平台就出现格式错乱;在知识库里能正确引用文档,到了数据看板平台就开始胡说。原因不是模型傻,而是平台给 Agent 的上下文、触发方式和输出约束完全不同。消息平台有对话历史,任务平台传过来的是结构化工单数据,知识库平台拼接的是长文本片段,数据看板平台希望得到的是图表配置而不是自然语言。
复制粘贴提示词,等于忽略了平台差异。后来我们才总结出:真正该复用的不是提示词文本,而是“技能定义”——包括技能描述、参数 Schema、执行规则、回调接口。提示词只是技能定义在某个平台适配后的一种渲染结果。
这也是“闪学it-Agent Skills”名字的由来:Agent 的本事,不是某一段 Prompt,而是一整套能被不同平台识别的“技能动作”。
1.3 闪学it的定位:把离散能力变成可注册、可编排、可观测的“技能”
我们最后确定的定位:每个 Agent 能力都被封装成一个 Skill。Skill 包含三件事:会干什么、需要什么输入、执行完怎么回写结果。再把 Skill 注册到一个统一的技能注册表里,平台侧通过连接器查询注册表、按需加载技能。
这套设计带来最直观的好处是:新增一个平台时,不用重新开发 AI 逻辑,只要写一个适配层,告诉这个平台“有哪些技能可以调用、参数怎么传、结果怎么展示”就行。后续迭代 AI 能力时,也只需要更新 Skill 本身,所有平台自动生效。
2. Agent Skills 的核心抽象:技能注册表与执行协议
2.1 每个技能由哪几部分组成
我们定义了一个最小有效的 Skill 结构,四个部分缺一不可:技能元信息、运行时提示词、输入输出 Schema、校验与回调配置。
技能元信息主要包括技能唯一标识(skill_id)、名称、描述、版本号和可见范围。这里面最容易被忽略的是描述质量。描述不是给人看的,而是给模型看的。模型在做意图识别时,就是靠这段描述来判断“当前用户请求是否应该命中这个技能”。如果你的描述写得太抽象,比如“处理客户问题”,模型什么都可能命中;如果写得太具体,比如“仅处理三个月以上老客户的退款申请”,又容易漏召回。
我们的经验是:描述里要包含触发场景、典型请求、边界条件三部分。触发场景说明什么时候用,典型请求给模型一个匹配样本,边界条件告诉模型什么时候坚决不能用。
输入输出 Schema 是技能和平台之间的契约。我们用 JSON Schema 描述输入参数的类型、必填项和取值范围,输出也做严格结构化。这样消息平台可以把它渲染成表单,任务平台可以直接映射字段,数据看板平台可以拿到干净的统计数据。
2.2 技能注册表与版本管理
技能注册表相当于一个“能力仓库”。所有技能上线前要提交注册表,包含一个测试用例文件,里面是“输入→预期输出”的黄金样本。每次修改技能,必须跑一遍回归测试,黄金样本通过率低于 100% 就不能发布。
版本管理上,我们没有追求复杂的语义化版本,只分 Draft、Stable、Deprecated 三种状态。新技能先标记为 Draft,只对内部用户开放;跑两周没问题转 Stable,所有平台可调用;被新版本替代后标记为 Deprecated,保留三个月再下线。这个策略简单有效,我们的学习成本很低。
有一点要提醒:技能注册表本身必须是平台无关的。不能把某个平台的接口细节写进技能定义里。比如“从消息平台 @ 机器人触发”这种描述就不合格,因为任务平台根本不存在 @ 动作。我们统一用“用户请求触发”这样的抽象描述,平台层的差异交给连接器处理。
2.3 执行协议的四个关键阶段
每次技能执行,都会走四个阶段:意图识别、参数抽取、权限校验、执行回写。
意图识别发生在平台连接器内部。连接器把用户输入交给一个轻量级分类器,分类器根据技能注册表里的描述,输出命中概率最高的技能。这里考虑到成本,我们没有每次都用大模型做分类,而是先用关键词规则快速过滤,再把候选集缩小到三个以内,最后交给大模型做精确匹配。
参数抽取阶段,模型结合用户输入和 Schema 提取结构化参数。最常见的坑是模型漏填必填项。我们不让模型直接返回“我帮你默认填了”,而是让模型把缺省项列为待确认清单,返回给用户确认后再进入执行。虽然多了一轮交互,但有效避免了数据污染。
权限校验是很多人容易漏掉的一步。我们规定:任何技能执行前,必须调用统一权限服务,确认“当前用户”是否有权调用该技能、是否有权操作目标资源。这个校验不能放在平台侧,因为不同平台的权限模型不一样,只有统一收口才能保持一致。
执行回写同样关键。技能执行完成后,要把结果回写到起始平台。比如用户在知识库平台调用了“生成摘要”技能,执行结果要能自动粘贴到当前文档下方;用户在消息平台调用了“查询订单”技能,结果要渲染成卡片而不是纯文本。回写协议里定义了不同平台支持的渲染类型,连接器再映射成具体格式。
3. 多平台接入实战:从消息协同到业务后台
3.1 消息协同平台:会话上下文与 @ 触发方式
消息协同平台是我们接入的第一个平台,也是最容易出效果、最容易暴露问题的平台。
用户触发方式上,我们支持两种:群聊 @ 机器人和私聊直接发消息。群聊场景有个隐藏问题:如果用户在群里直接说了一句跟 Agent 无关的正常讨论,很可能被误触发。所以我们给连接器加了一个“触发置信度阈值”,命中技能置信度低于阈值时,机器人保持沉默,不给任何回应。这个阈值需要反复调,调太低会打扰群聊,调太高会漏召回。
上下文管理是消息平台的重点。早期我们直接把整段会话历史塞进模型,结果群聊里信息太多,Agent 分不清当前到底在说哪件事。后来改为“引用消息 + 最近五条消息 + 当前消息”三者组合,把上下文窗口压缩到可控范围。如果消息平台支持消息 ID 引用,一定要用上,这能极大减少歧义。
消息平台的输出形式也值得单独说。我们的连接器支持文本、卡片、列表三种渲染格式。技能注册表里会标明默认渲染类型,比如“创建任务”技能默认返回卡片,“生成摘要”技能默认返回文本。如果用户明确说“用列表形式发给我”,连接器会覆盖默认值。
3.2 任务管理平台:把“创建需求单”变成标准动作
接入任务管理平台时,我们面对的最大挑战不是模型能力,而是字段映射。任务平台里的任务卡片有几十个字段,但 Agent 不可能每次都把所有字段填满。我们的做法是只要求必填字段,并通过 Schema 里的“依赖关系”字段管理联动逻辑。
举个例子,“创建需求单”技能里,如果用户选择了“紧急”这个优先级,就必须同时填写“紧急原因说明”;如果选择了“普通”,则原因说明可填可不填。这类依赖关系没法靠模型自觉,必须在 Schema 里显式声明,然后在参数抽取阶段做校验。模型抽取完参数后,连接器会做二次校验,不通过就让用户补填。
任务平台还有一个特点是“回写即创建”。我们直接让技能执行结果调用任务平台的 API,创建一个真实的任务卡片,然后把任务链接回传给用户。这里有个安全细节:Agent 创建的任务卡默认是不能直接指定处理人的,只能指定团队或角色。原因是跨部门协作时,个人姓名映射经常出错,而团队角色映射更稳定。这个设计后来帮我们避免了很多错误分配的问题。
3.3 知识库与文档平台:技能调用检索、摘要与审核流程
知识库平台是另一个完全不同的场景。用户在这里的诉求不是“创建东西”,而是“快速找到信息并整理”。我们封装了两个核心技能:知识检索和文档摘要。
知识检索技能看起来简单,实际难在“引用来源”。模型很容易把多个文档的内容混在一起,生成一个看似合理、实际出处不明的回答。我们的解决方案:检索结果必须带段落级引用 ID,模型生成回答时,每个断言都要关联至少一个引用 ID,回答底部自动生成来源列表。如果某个断言找不到引用,连接器会将该断言标记为“待核实”,而不是直接删除或保留。
文档摘要技能踩过一个比较深的坑:摘要结果直接改成只读共享文档,会有权限边界问题。用户可能只对当前文档有查看权,但摘要功能却把内容写到了另一个团队可见的空间。后来我们统一在技能调用的权限校验阶段,强制要求“目标写入空间”必须在用户有权限的范围内,否则拒绝执行并提示用户选择其他位置。
3.4 数据看板类平台:以只读技能为主,限制执行边界
数据看板平台是我们最谨慎接入的一类。这里的 Agent 技能必须默认只读,不能执行删除、修改、写入等危险操作。并不是技术做不到,而是这类操作一旦出错,影响面是全局性的,而且很难回滚。
我们在数据看板平台封装的是“数据查询解释”和“异常归因”两个技能。前者接收用户的自然语言问题,翻译成查询条件并执行,然后把结果转成通俗解释;后者接收某个异常指标,自动从维度拆解、时间对比、关联指标三个方向生成归因报告。
数据看板平台的技能执行频率往往很高,因此我们对输出做了一定程度的缓存。同一个查询条件在五分钟内重复触发时,直接返回缓存结果,不再消耗模型调用。缓存只在满足租户隔离的前提下生效,天然避免跨用户串数据。
4. 平台适配层:连接器、身份映射与超时容错
4.1 连接器设计:平台 API 差异如何被消化
多平台接入最繁琐的,永远是接口差异。消息平台是 webhook 下发事件,任务平台是 REST API 拉取任务,知识库平台走对象存储加全文检索,数据看板平台则是 BI 服务自带的查询协议。我们不打算让核心的 Agent 引擎去适配这些差异,就写了一个“平台连接器”中间层。
每个连接器实现统一接口:接收平台 Webhook、解析事件、提取用户身份、组装技能请求、适配返回格式。任何新平台接入时,开发只需要关注这个连接器内部的映射逻辑,不碰技能注册表和执行协议。
这样做还有一个额外好处:可以针对不同平台定制不同的限流策略。比如消息平台请求量波动大,连接器层做令牌桶限流;任务平台调用频率稳定,就做固定窗口限流。核心执行引擎的负载被连接器挡掉了一大半。
4.2 跨平台用户身份统一的关键:不要只信显示名
这是整个项目里我印象最深的一个坑,也是后来我们专门写进接入规范的一条。
最初我们让各平台连接器直接上报用户的显示名,比如“张三”“lisi”“张工”,然后以这个名字去查权限。结果同一个真实用户在三个平台有三个不同昵称,权限系统根本没法准确判断身份。
正确的做法是:每个平台连接器必须将平台侧的用户唯一 ID 映射到统一身份域。映射关系存一份独立的用户映射表,早期人工维护,后期接入企业统一登录体系后自动同步。在身份映射完成之前,技能调用一律默认拒绝,而不是默认放行。这个策略确实保守,但它保证了我们不会因为显示名撞车而出现越权操作。
4.3 不同平台的超时与重试策略
大模型调用天然有延迟波动,但不同平台对响应时间的要求完全不同。消息平台通常能容忍 5 到 10 秒的等待,知识库平台可以接受 20 秒左右的异步处理,而数据看板平台的前端操作往往要求 3 秒内给反馈,否则用户就刷新页面了。
我们给每个平台连接器配置了独立的超时时间和降级策略。消息平台用“同步等待 + 超时转异步通知”,任务平台用“全异步回调”,知识库平台用“同步等待但提高模型并发度”,数据看板平台则做了“快速失败转静态帮助文档”的兜底。超时后的重试次数统一控制在一次,超过就进入人工处理队列,不无限重试。无限重试容易引发幂等性问题,比如一个“创建任务”请求被重试两次,就会创建出两个重复任务。
5. 从 Demo 到稳定运行必须处理的三个细节
5.1 权限隔离与技能级服务鉴权
很多团队做 Agent Demo 时,根本不做权限隔离,因为数据量小、用户范围小,感觉不到问题。一旦多平台同时接入,用户会通过消息平台、任务平台、知识库平台任意入口调用技能,如果不隔离,A 平台用户可能通过某些参数绕过限制,碰到他本不该看到的数据。
我们在技能调用链路上做了两层鉴权。第一层是用户级鉴权:用户必须拥有技能本身的调用权限。第二层是数据级鉴权:用户必须拥有目标资源(如任务、文档、数据集)的访问权限。两层鉴权都通过后,技能才开始执行。这里强调一下:数据级鉴权不能用平台侧的权限结果代替,必须让技能执行服务基于统一权限服务校验,因为平台侧提供的信息不一定可靠。
5.2 每次技能执行都能追溯:日志与插桩
Agent 技能执行像是一个黑盒子,如果出错了,你不能只靠用户说“它回答不对”来排查。我们要做到的是:每一次执行请求都有完整链路记录,包含入参、命中技能、参数抽取中间结果、权限校验结果、模型输出、回写内容。
插桩时注意别只记录成功请求。失败请求的价值往往更高。我们把失败分了几类:参数缺失、权限不足、模型输出非法、平台接口超时、回写失败。分类之后,每周都能看到不同平台的失败趋势,定位问题的速度提高了很多。有一次知识库平台的失败率突然升高,就是因为连接器读取一个新文档格式时抛了异常,日志里定位只花了不到半小时。
5.3 灰度发布:按用户维度逐步放开
因为多平台是并行接线的,不能让所有平台同时全量发布一个新技能。我们的做法是:按用户维度灰度。先让内部种子用户使用 Draft 版技能,跑一个周期没问题后,再把 Stable 版开放给某个平台的白名单用户,最后逐步扩大到全量。
灰度发布和技能注册表的“状态”机制配合得很好。连接器在查询技能列表时,会根据当前用户是否在白名单内,决定返回 Draft 版还是 Stable 版。这个逻辑在连接器层做,核心引擎无感知,也避免了一次全量发布导致线上事故。
6. 实测结果与避坑清单
6.1 一组可以量化参考的数据
我们接入消息协同平台、任务管理平台、知识库平台和数据看板平台以后,做了三个月的持续观测。以下数据来自内部测试环境,仅作参考。
技能执行平均耗时:消息平台 4.8 秒,任务平台 7.2 秒(异步回调占大头),知识库平台 6.5 秒,数据看板平台 2.9 秒。任务创建类技能的字段一次命中率从最初的 62% 提升到了 89%,主要归功于 Schema 依赖校验和缺省字段确认机制。知识检索技能的引用覆盖率从 71% 提升到 96%,因为我们对“无引用断言”做了强制待核实处理。
另一个比较意外的收益是人力成本。原本需要专人在多个平台间手工搬运信息的活儿,现在通过技能直接跨平台触发,每周大约能省出 12 小时的人工整理时间。这个数字不大,但已经让团队愿意继续投入迭代。
6.2 避坑清单:把这些坑记住,基本能少走一半弯路
| 坑 | 现象 | 解法 |
|---|---|---|
| 提示词复制到各平台 | 换平台就失灵 | 改为技能定义复用,提示词只做适配渲染 |
| 只信用户显示名 | 权限错乱、越权操作 | 用平台唯一 ID 映射统一身份域,映射前默认拒绝 |
| 不写技能描述边界条件 | 意图识别乱命中 | 描述包含触发场景、典型请求、边界条件三部分 |
| 缺少依赖字段校验 | 任务卡必填项缺失 | 在 Schema 中声明字段依赖,执行前二次校验 |
| 超时后无限重试 | 重复创建数据 | 限制重试次数,第一次失败转人工处理队列 |
| 输出没有引用来源 | 知识库回答出处不明 | 回答断言绑定引用 ID,无引用的标记待核实 |
| 平台接口差异直接写进技能 | 注册表被平台绑架 | 抽象平台无关的技能定义,差异交给连接器 |
6.3 一个印象最深的收尾经验
按理说文章到这里该收尾了,但我还是想再分享一个具体场景。我们上线数据看板平台那周,内部测试群里突然有人反馈“异常归因这个技能总说我的指标数据有问题”。排查后发现,连接器在解析查询条件时,把用户输入里的“近 7 天”硬生生映射成了一个固定日期,而不是相对日期窗口。结果每次跑出来的数据都不一样,用户当然觉得不对。
修这个问题的过程中我们才发现,不同平台对“时间表达”的默认语义差异巨大。消息平台用户说“昨天”通常指自然日,任务平台说“近三天”通常指工作日,数据看板平台说“本月”往往指财月。只靠技能执行引擎本身,根本无法判断哪个语义才对。最终我们在参数抽取阶段增加了一个“时间语义归属”字段,由平台连接器按当前平台规则注入,问题才算彻底解决。
这也是我做完闪学it-Agent Skills 最大的一点体会:多平台应用的难点,从来不在模型能力本身,而在每一个看似细小的语义缝隙里。把这些缝隙一个个填平,Agent 才真正从一个实验品,变成团队日常离不开的生产力工具。