微信扫码
添加专属顾问
我要投稿
得物技术团队分享如何通过工程化思维解决组件复用难题,让AI开发更高效规范。核心内容: 1. 组件复用问题的根源与工程化解决思路 2. AGENTS.md+Hook+Skill三层架构设计详解 3. AI流程化开发的三大核心原则与实践价值
目录
一、背景:为什么要做这个 Skill
二、想解决的不是搜索问题,而是"思考顺序"问题
三、核心设计思路:AgentS.md + Hook + Skill(三层结构)
1.AGENTS.md:放基础上下文(常驻)
2.Hook:做路由增强(提高触发概率)
3.Skill:提供流程和工具(真正执行)
四、这套 Skill 在源码里是怎么落地的(我的实现)
1.先把"入口"收敛成一个:find-component.js
2.不是"全仓库乱搜",而是"当前应用 + 根级共享"优先
3.匹配不是纯关键字:我做了"多因素加权"
4.把"索引构建"做成可复用流水线,而不是一次性脚本
5.让 Skill 不只是"搜索器",还是"反馈回路"
五、这次实现里,总结出"让 AI 流程化"的 3 条原则
1.原则 1:把基础上下文放进 AGENTS.md(或用 Hook 注入)
2.原则 2:Skill 需要直接提供工具函数给 AI 调
3.原则 3:显式告诉 AI 调哪些函数,并把分散逻辑聚合到一个入口
六、这次实践里一个很重要的认知转变
七、这套方案当前的价值
八、结语:让 AI 少一点"即兴发挥",多一点"工程纪律"
做这个 Skill 的初衷很直接,也很现实:功能开发时容易"顺手新建一个",而不是先复用已有组件,造成组件库越来越臃肿。这件事对团队的伤害其实是复利型的:
重复组件越来越多;
维护成本越来越高;
UI/交互一致性越来越差;
AI 生成代码时也更容易继续复制混乱。
所以做这个 Skill 的目标不是"帮 AI 搜索一下",而是:把"复用优先"的思考过程流程化,让 AI 在写代码前先走一遍"查索引 → 判断是否复用 → 命不中再新建"的路径。
一开始很容易把问题理解成:"做个组件搜索工具给 AI 用就好了"。但实际落地后发现,真正的问题不是工具有没有,而是:
AI 会不会主动用;
AI 什么时候用;
AI 用完之后是否还能回到项目上下文;
AI 能不能稳定走同一条流程。
这和 Vercel 在他们的 agent 评测里观察到的现象很像:skills 本身不是没用,而是 agent 往往不会稳定触发;而把基础知识放进 AGENTS.md 这种"被动上下文"后,稳定性反而更高。Vercel 的实验里,默认 skill 触发并没有提升通过率,加入显式指令后才明显改善,而 AGENTS.md 文档索引方案表现更稳定。这给了我一个很关键的设计方向:先解决 AI 的"决策点"问题,再解决 AI 的"能力"问题。
最终采用的是三层结构:
AGENTS.md:放基础上下文(常驻)
把"组件复用优先"的规则、组件索引入口、扫描后需要做的事情,放进 AGENTS.md(或同类常驻上下文机制)里。目的不是塞满文档,而是让 AI 每轮都知道:
这个仓库有组件复用机制;
默认应该先查可复用组件;
查不到再考虑新建;
扫描后还有描述补全流程需要继续执行。
这层解决的是:AI 根本不知道你有这套机制。不写进去,AI 主动使用 skill 的概率确实会很低(这点我踩过坑)。
Hook:做路由增强(提高触发概率)
如果运行环境支持 hooks(例如 Claude Code 的 UserPromptSubmit 支持在用户 prompt 处理前注入额外上下文),就可以做一层"意图路由增强":在用户提到"组件复用 / 是否有现成组件 / 封装组件 / 查组件"等语义时,给 AI 注入提示,让它优先走组件复用流程。Claude 的文档明确写了 UserPromptSubmit 会在处理前触发,并且可通过 additionalContext 注入上下文。这层解决的是:AI 知道有 skill,但不一定想起来用。
Skill:提供流程和工具(真正执行)
Skill 不是只写说明文档,而是要提供:
明确的调用入口;
稳定的输出格式;
可执行脚本;
失败时的兜底逻辑。
OpenAI 的 Codex Skills 文档里提到 skills 是"渐进披露"机制:运行时先看到 skill 的元信息(尤其是 description),只有决定使用时才加载完整 SKILL.md;而且隐式触发高度依赖 description。这也是为什么 skill 的触发边界和描述要写得非常清楚。这层解决的是:AI 想用了,但执行过程不稳定。
下面是我这次组件复用 Skill 的几个关键实现点:
先把"入口"收敛成一个:find-component.js
我在 SKILL.md 里明确规定:Agent 必须调用统一入口find-component.js。这样做的原因很简单:
避免 AI 在多个脚本之间犹豫(scan-components、match-component、resolve-scope……);
避免 AI 漏掉前置步骤(比如索引不存在时先扫描);
避免 AI 调用路径不一致导致结果不稳定。
统一入口做了几件事(都在 find-component.js 里):接收查询词(query)、仓库根路径(repoRoot)、当前聚焦路径(startDir)。
如果 components.csv 缺失,内部自动触发run-scan.js;
调用 resolve-scope 计算当前应用和允许搜索范围;
调用 match-component 做匹配排序;
命中时记录使用(用于后续加权);
按固定 JSON 协议返回结果(成功/失败/无匹配/是否触发扫描等)。
这一步本质上是把分散逻辑聚合成"一个业务动作":"查一下有没有可复用组件",而不是"先算 scope,再查 CSV,再排序,再补扫,再记 usage"。这对 AI 很关键。
不是"全仓库乱搜",而是"当前应用 + 根级共享"优先
在 monorepo 场景里,组件复用很容易踩两个坑:
只搜当前 app,漏掉根级共享组件;
全仓乱搜,结果太多太噪音。
所以我在 resolve-scope.js 里做了一个比较工程化的范围解析策略:
读取 pnpm-workspace.yaml 解析 workspace 包;
根据当前聚焦文件/目录反推 currentAppRoot;
再结合 root_scope_patterns(例如 apps/_share/、packages/ 等)构建允许范围;
最终形成一个搜索集合:当前应用 + 根作用域共享包。
如果没有聚焦子项目(比如 startDir 就是 repo root),则切换为全量 scope。这个设计很像人类工程师的查找策略:先看"我这个业务应用里有没有",再看"全局共享有没有",而不是直接在整个 monorepo 海里捞针。
匹配不是纯关键字:我做了"多因素加权"
组件匹配如果只做字符串包含,很快就会变成垃圾召回器。我在 match-component.js + fuzzy-match.js 里做了一个组合评分,核心包括:
名称精确/包含匹配;
模糊匹配(编辑距离);
Token 重叠;
首字母缩写匹配(例如 dlp 匹配 DateLinkPicker);
当前应用加权(当前 app 的组件优先);
使用频率加权(常用组件更靠前);
来源质量加权(README 推断质量高于纯 inferred);
存在性校验(文件不存在则降权/过滤);
记录类型权重(组件优先于依赖)。
这一步的目标不是追求"算法先进",而是让排序更符合团队真实使用习惯:"更可能被复用的组件排在前面"。此外我还加了一个低分阈值(NO_MATCH_SCORE_THRESHOLD):
如果最高分太低,就认为是噪音命中;
可以触发一次扫描后再查;
还是低分则按"无匹配"返回,不把噪音结果塞给 AI。
这个点很重要,因为 AI 一旦拿到一些低质量候选,很容易"将错就错"。
把"索引构建"做成可复用流水线,而不是一次性脚本
很多类似方案停在“扫一遍生成 CSV”,然后就过时了。我这次把扫描做成了 run-scan.js -> index-manager -> enrich 的流水线,核心考虑是持续维护:
run-scan.js 负责编排流程
resolve-scope;
updateIndex;
自动触发 autoEnrich(可配置)。
index-manager.js 负责索引更新策略
保留历史记录并合并;
根据 source_hash 跳过未变化组件;
记录 last-scan-changed-ids.json;
支持并行扫描(包数量较多时启用);
对缺失文件支持标记 exists=0(在查找阶段也会回写)。
扫描后进入 Agent 富化(enrich)流程
读取 agent-enrich-prompts.json;
找出 summary 占位符项;
按 id 回到 components.csv;
读取源码/README;
生成 summary + keywords;
再通过 update-component-summary.js 写回。
更关键的是在配置里启用了:
agent_mode_no_fallback = true。
也就是说,在 Agent 模式下不走规则引擎降级,而是要求 Agent 必须完成这一步。这其实就是"流程化思考"的精髓:不是建议,而是纳入主流程。
让 Skill 不只是"搜索器",还是"反馈回路"
一个很容易被忽视的点是:查找命中后,我还记录了使用行为(usage-tracker)。这意味着系统不是静态的,它会逐步学习团队偏好:
哪些组件经常被复用;
哪些组件在某个 app 里更常出现;
哪些结果应该在排序中更靠前。
这是一种很轻量但非常实用的反馈机制——不需要搞复杂训练,也能提升 AI 下一次推荐质量。
这也是我最想分享的部分:
原则 1:把基础上下文放进 AGENTS.md(或用 Hook 注入)
如果不这样做,AI 主动使用 skill 的概率很低。原因不是 AI 笨,而是 agent 的执行是有"决策成本"的:
它要先意识到有 skill;
再判断该不该用;
再决定什么时候用。
而把基础上下文放进 AGENTS.md 或通过 hook 提前注入,本质上是在减少决策点。Vercel 的评测结果说明了这种"被动上下文"在某些场景下会更稳定。
原则 2:Skill 需要直接提供工具函数给 AI 调
只写一堆说明文档不够。AI 在工程任务里最需要的是:
一个可以直接执行的入口;
明确的参数;
稳定的返回结构。
所以我把 find-component.js 做成统一入口,并定义了固定 JSON 输出(ok / matches / noMatch / scanTriggered / hint / error 等),这会明显提升 AI 的执行稳定性。
原则 3:显式告诉 AI 调哪些函数,并把分散逻辑聚合到一个入口
这是最容易被忽略、也是最影响稳定性的一点。如果给 AI 暴露一堆脚本:
resolve-scope.js;
match-component.js;
run-scan.js;
scan-components.js;
index-manager.js。
它理论上能拼起来,但实践里很容易漏步骤、顺序错、参数错。所以我在 Skill 里显式规定:
查找时用 find-component.js;
构建时用 run-scan.js;
更新描述时用 update-component-summary.js。
把复杂系统收敛成几个明确入口,AI 才容易稳定执行。
我原来以为"写 skill"是在给 AI 增加能力。现在更像是在做:给 AI 增加"默认工作方式"。换句话说,skill 不只是能力包(capability bundle),也是流程控制器(workflow controller)。
AGENTS.md 负责"告诉 AI 世界观";
Hook 负责"提醒 AI 现在该用哪套流程";
Skill 负责"把动作做完,并且做得稳定";
日志/CSV/usage 负责"让系统可观测、可迭代"。
这套思路不只适用于组件复用,后面也可以迁移到:
任务优化闭环;
日志分析标准化;
策略诊断流程;
代码规范治理。
AI 开发前先查可复用组件,而不是直接新建;
monorepo 下按"当前应用 + 共享组件"范围检索;
索引缺失自动扫描;
组件描述富化进入主流程;
匹配质量有加权与反馈回路;
整体流程有明确入口和输出协议。
这次组件复用 Skill 的开发过程,对我最大的启发不是"AI 能帮我写多少代码",而是:AI 其实非常适合被放进一套清晰流程里工作。只要把下面三件事做好:
基础上下文(AGENTS.md / hooks);
可执行入口(工具函数);
明确流程边界(统一入口 + 输出协议)。
AI 就不会只是"一个会说话的代码补全器",而会更像一个遵守团队规范的工程协作者。而这,才是我做这个 Skill 真正想要的结果。
引用文档: https://vercel.com/blog/agents-md-outperforms-skills-in-our-agent-evals
往期回顾
文 /魏无涯
关注得物技术,每周一、三更新技术干货
要是觉得文章对你有帮助的话,欢迎评论转发点赞~
未经得物技术许可严禁转载,否则依法追究法律责任。
“
扫码添加小助手微信
如有任何疑问,或想要了解更多技术资讯,请添加小助手微信:
53AI,企业落地大模型首选服务商
产品:场景落地咨询+大模型应用平台+行业解决方案
承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业
2026-04-13
人人都在造 Skill,谁来保障安全运行?
2026-04-13
Hermes Agent 如何解决Skill爆炸
2026-04-13
PIG AI 更新:Skills 再升级,企业 API 秒变 Agent
2026-04-13
快速搞懂 CLI 并拥有一个自己专属 CLI
2026-04-12
蒸馏:全员skill的职场恐怖故事
2026-04-12
花一天时间把工作 Skill 化,开始享受 AI 时代的复利
2026-04-09
一文读懂滴滴OpenClaw专属打车Skill
2026-04-09
Skill 的机会不在单点,在编排:一种你可能还没想过的架构能力
2026-03-03
2026-04-05
2026-03-03
2026-03-04
2026-03-17
2026-03-10
2026-03-17
2026-03-05
2026-03-05
2026-03-26