惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
A
About on SuperTechFans
博客园 - Franky
Engineering at Meta
Engineering at Meta
Recent Announcements
Recent Announcements
云风的 BLOG
云风的 BLOG
B
Blog
Microsoft Security Blog
Microsoft Security Blog
L
LangChain Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
U
Unit 42
Martin Fowler
Martin Fowler
Y
Y Combinator Blog
Stack Overflow Blog
Stack Overflow Blog
博客园 - 叶小钗
Vercel News
Vercel News
Apple Machine Learning Research
Apple Machine Learning Research
The Cloudflare Blog
Last Week in AI
Last Week in AI
腾讯CDC
Microsoft Azure Blog
Microsoft Azure Blog
爱范儿
爱范儿
V
V2EX
G
Google Developers Blog

博客园 - 唐宋元明清2188

Electron 桌面客户端 ASAR 热更新:替换一个文件完成版本切换 .NET Win32设置只读未对齐,导致NTFS文件系统识别异常 SDD基于规范编程-OpenSpec及SuperPowers .NET 磁盘BitLocker加密-技术选型 .NET Win32磁盘动态卷触发“函数不正确”问题排查 .NET SqlSugar多线程下SqlSugarClient 的线程安全陷阱 .NET 本地Db数据库-技术方案选型 .NET 磁盘Bitlocker加密-Powershell操作 .NET 磁盘管理-技术方案选型 .NET 记录Amazon上传S3异常问题 .NET 记录多框架下的Json序列化属性标记问题 .NET 阻止Windows关机以及阻止失败的一些原因 网络虚拟存储 Iscsi实现方案 Windows 网络存储ISCSI介绍 Windows 本地虚拟磁盘Vhdx .NET 数据拷贝方案选择 .NET 窗口置于最顶层 如何做好软件架构师 .NET开发一些书箱推荐 Windows应用开发-常用工具 WPF 记录鼠标、触摸多设备混合输入场景问题 .NET Bios相关数据读写
SDD-skills执行遗漏问题
唐宋元明清2188 · 2026-04-18 · via 博客园 - 唐宋元明清2188

背景

我们团队基于 SDD(Spec-Driven Development)模式做多仓库协同开发,用公司内部的 Agent 工具来执行工作流。工作流中有一套 Skill 机制——每个命令(比如 apply、archive)对应一份完整的执行指令文档(SKILL.md),Agent 调用 use_skill 加载后按步骤执行。

最近连续两次出现 Agent 跳步的情况,具体表现是:明明 SKILL.md 里写了完整的后续流程,Agent 执行到一半就结束了。排查后发现问题不在文档本身,而是 Agent 压根没加载那份完整文档。

问题现象

现象 1:apply 命令跳过了收尾步骤

执行 /opsx:apply 时,这个变更涉及子仓库。按照完整 Skill 流程,确认子仓库任务完成后还要走 Phase C(总参仓库收尾):发 GitLab Issue 评论、更新 Label、commit + push、创建 MR。

实际表现是 Agent 把上游 tasks 勾完就停了,后面的 Issue 评论、MR 创建一个都没做。

现象 2:archive 命令的交互方式不对

执行 /opsx:archive 时,SKILL.md 明确写着用一个「是/否」确认来决定是否 commit + push。结果 Agent 弹了个 5 选项的多选框出来,把操作拆得很碎。

两次问题的共同点:Agent 没有调用 use_skill 加载完整的 SKILL.md

原理:Skill 的两层加载机制

要理解这个问题,先得搞清楚 Agent 工具中 Skill 的加载流程。它其实分两层:

第一层:系统消息中的精简描述(自动注入)

Agent 工具启动时,会把所有注册的 Skill 的描述信息注入到系统消息(System Prompt)中。大概长这样:

<skills>
Available skills:
  - "openspec-apply-change": Implement tasks from an OpenSpec change.
    Use when the user wants to start implementing...

  - "openspec-archive-change": Archive a completed change in the
    experimental workflow. Use when the user wants to finalize...
</skills>

这段内容的作用是意图识别——告诉 Agent "有这些 Skill 可用,遇到匹配的用户意图时去调用"。每个 Skill 的描述大概 20~40 行,包含基本的步骤概要和输出格式。

第二层:SKILL.md 完整指令(主动加载)

当 Agent 识别到用户意图后,应该调用 use_skill("openspec-archive-change"),这会读取并返回对应的 SKILL.md 文件——通常有 300~500 行,包含:

  • 每个步骤的详细执行逻辑和条件分支
  • 多仓库场景的级联处理流程
  • 交互方式的精确定义(弹几个选项、怎么措辞)
  • 各种异常场景的处理方式
  • 6 种以上的输出模板

问题出在哪

正常流程应该是:

用户输入 /opsx:archive
    → Agent 看到系统消息里的精简描述,识别意图
    → Agent 调用 use_skill("openspec-archive-change")
    → 拿到 SKILL.md 完整内容(430+ 行)
    → 按完整指令逐步执行

实际发生的是:

用户输入 /opsx:archive
    → Agent 看到系统消息里的精简描述(~30 行)
    → 觉得"这里已经有步骤了,够用了"
    → 直接按精简版执行        ← 没调 use_skill
    → 精简版里没有的步骤全部跳过

核心矛盾:精简版里有步骤编号、有输出模板,看起来就像一份完整指令。LLM 没有能力判断"这 30 行是摘要"还是"这 30 行就是全部"。

精简版 vs 完整版的内容差异

拿 archive 命令举例,精简版和完整版的覆盖范围差距很大:

内容精简版(~30 行)完整版 SKILL.md(430+ 行)
基础归档流程 Step 1-5 ✅ 有 ✅ 有
downstream 级联归档 Step 6a-6e ❌ 无 ✅ 有
提交推送确认 Step 7(是/否) ❌ 无 ✅ 有
Issue Label 更新 Step 7.5 ❌ 无 ✅ 有
6 种场景的输出模板 ❌ 只有 2 种 ✅ 全部
Guardrails 约束条件 ❌ 无 ✅ 有

Agent 拿着精简版执行,自然就把 Step 6 以后的内容全丢了。

为什么 Agent 不主动加载完整版

本质上是 LLM 的行为特性——当上下文中已有"看起来足够"的信息时,它不会主动去获取更多信息。具体来说:

  1. 上下文里有了就不找了——system prompt 里已经有一段步骤指令,从 token 效率角度 LLM 倾向于直接用,不会额外花一次 tool call 去"确认是否有更完整的版本"
  2. 精简版的"诱导性"——它包含步骤编号、输出模板这些结构化元素,长得太像正式指令了
  3. 缺少显式阻断——精简版里没写"这不是完整指令,你必须调 use_skill",LLM 没有被明确告知需要再做一步

这不是某个特定 Agent 工具的 bug,而是所有基于 LLM 的 Agent 平台都可能遇到的问题。只要架构里存在"系统消息注入摘要 + 运行时加载详情"这种两层设计,就有这个风险:

平台/工具两层机制
公司内部 Agent 工具 <skills> 注入描述 + use_skill 加载完整版
Cursor .cursorrules 注入上下文 + tool call 取详细指令
Claude (MCP) System prompt 摘要 + MCP tool 取完整文档
GitHub Copilot Instructions 文件 + 扩展命令加载

解决方案

方案 1:在 always-apply 规则中强制要求加载

我们的 Agent 工具支持 alwaysApply: true 的规则文件——每次会话启动时自动注入系统消息。在这里写一条硬性约束:

## ⛔ Skill 加载强制规则(MUST 级别)

以下命令在执行时,必须调用 use_skill 加载完整的 SKILL.md 指令,
不得依赖系统消息中的内联精简版:
- /opsx:apply   → use_skill("openspec-apply-change")
- /opsx:archive → use_skill("openspec-archive-change")

> 曾多次发生 Agent 按内联精简版执行、跳过关键步骤的事故。
> 精简版仅用于意图识别,不包含完整执行流程。

因为这条规则每次会话都会出现在系统消息中,Agent 在执行这几个命令时会被强制提醒"你得先调 use_skill"。相当于在它工作台上贴了张便利贴。

方案 2:在 SKILL.md 分支点内联后续步骤清单

还有一种情况:Agent 确实加载了完整 SKILL.md,但 400 多行的文档它未必每行都看。执行到某个条件分支时,如果跳转目标写得太简略,它可能直接忽略后续内容。

解决办法是在分支点把后续步骤"剧透"出来:

// 修改前
If all done: suggest archive

// 修改后
If all done AND .openspec.yaml contains `downstream`:
  MUST immediately proceed to Phase C — 包含:
  C1(子仓库验证)→ C1.5(Issue 评论 + Label)→
  C2(勾选上游 tasks)→ C3(commit + push + MR)

把子步骤名称直接写在跳转处,这样即使 Agent 没翻到 Phase C 的详细段落,也能知道"后面还有 4 件事要做"。

修复验证

加上这两个修复后重新跑了一轮完整流程(apply → archive),Agent 行为符合预期:

  • ✅ 执行 apply 时调用了 use_skill,Phase C 完整执行(Issue 评论、Label 更新、MR 创建)
  • ✅ 执行 archive 时调用了 use_skill,用单个是/否确认而非多选框
  • ✅ 后续多次执行均未复现跳步问题

小结

这个问题的根因可以一句话概括:Agent 拿到了一份残缺的指令,却当作完整版来用

底层原因是 LLM 的行为特性——上下文里有了就不再主动获取更多。这不是 bug,改不了,只能在工程层面绕过去。几个实操要点:

  • 关键命令必须在 always-apply 规则里写死 use_skill 的调用要求
  • 长流程的分支跳转点要把后续步骤名称列出来,别给 Agent 留"不知道后面还有活儿"的空间
  • 每次出现跳步行为就补一条规则——规则文件是跨会话持久化的,对话历史不是

以上是最近踩坑的记录,主要想说明一个点:用 Agent 跑复杂工作流时,Skill 的加载机制值得多花点心思设计。指令写得再完整,Agent 不加载也白搭。