背景OpenSpec 是一个管理技术提案的系统核心想法很简单输入变更描述自动生成各种文档工件。proposal、design、specs、tasks这些都能自动生成。听起来挺美好的不是吗只是在实际使用中我们发现了一些问题。怎么说呢也不是什么大问题就是生成的东西不太对味儿。生成的design.md缺少必要的可视化元素——没有 Mermaid 流程图没有时序图更没有架构图。这样的设计文档技术团队看了直摇头毕竟谁愿意看一堆纯文字呢proposal.md也不尽如人意缺少代码变更表格没有界面原型。决策者看了半天还是不知道这变更到底改了些什么。更让人头疼的是tasks.md里面混入了各种 Git 操作任务。职责边界变得模糊不清开发人员看着这些任务不知道哪些该做、哪些不该做。这也有点无奈毕竟 AI 也不知道你的团队分工是怎么样的。不同文档级别的可视化要求也不明确。proposal 和 design 到底应该包含哪些图表这个问题一直困扰着团队。这些问题的根源在哪呢我们分析后发现了关键点提示词模板缺少明确的约束和指导。这也没什么好奇怪的毕竟模板本身就是通用的不可能完全适配每个团队的需求。关于 HagiCode本文分享的方案来自我们在 HagiCode 项目中的实践经验。HagiCode 是一个 AI 代码助手项目我们在开发过程中大量使用 OpenSpec 来管理技术提案。正是这些实际踩坑经历促成了这套改进方案的诞生。其实也没什么大不了的就是遇到问题解决问题罢了。分析提示词系统架构要解决问题先要理解系统。让我们看看 OpenSpec 的提示词系统是怎么工作的。OpenSpec 使用 Handlebars 模板系统每个提示词包含两个部分JSON 元数据文件定义参数、场景、版本信息Handlebars 模板文件包含实际的提示词内容Resources/Prompts/├── openspec-v1-ff.zh-CN.json # 元数据├── openspec-v1-ff.zh-CN.hbs # 模板内容├── openspec-v1-ff.en-US.json└── openspec-v1-ff.en-US.hbs这种分离设计的优点很明显元数据和内容分开管理便于维护和本地化。这也有点像写代码逻辑和表现分离大家都懂这个道理。FFFast Forward工作流是 OpenSpec 的核心生成流程用户输入变更描述创建变更目录获取工件构建顺序按依赖顺序创建工件检查规划方向要求验证工件完整性显示最终状态这个流程看起来很完美但问题出在规划方向要求这一步——它没有足够明确的指导。这也有点无奈毕竟系统设计的时候也不可能考虑到所有团队的具体需求。规划方向系统规划方向系统是 OpenSpec 的核心自定义机制允许用户选择不同的生成选项。HagiCode 项目中定义了以下方向方向 ID功能默认启用explore探索模式是change-map变更地图是flowchart交互流程图是prototypeUI 原型是architecture架构图是sequenceAPI 时序图是每个方向都定义了稳定的标识符、默认启用状态、显示标签以及中英文提示词片段。这个系统设计得很精巧但在 HagiCode 的实践中我们发现光有定义还不够——需要在提示词模板中明确使用这些方向。这也有点像人生中很多事情有了选项不等于会做出选择还是需要有人告诉你该怎么选。解决方案明确约束和示例我们的改进思路很直接在提示词模板中添加明确的约束和参考示例。其实也没什么特别的就是把话说清楚罢了。1. 添加文档可视化要求在openspec-v1-ff.zh-CN.hbs模板中我们添加了明确的内容范围约束### tasks.md 内容范围约束当创建 tasks.md 工件时必须遵守以下内容范围约束必须包含- 业务逻辑任务代码实现、功能开发- 技术实现任务组件集成、API 开发- 测试任务单元测试、集成测试- 文档任务更新文档、添加注释禁止包含- Git 提交操作git add、git commit、git push- 版本控制管理工作流- 部署和发布操作使用规范的必须/禁止语言而不是建议或可以这让 AI 能够更准确地理解约束。这也有点像教导孩子说什么就是什么不能有歧义。2. 为每个方向提供参考示例光说包含流程图还不够我们为每个启用的方向提供了具体的输出示例。毕竟光说不练假把式给个具体的例子AI 就能更好地理解。变更地图方向示例| 文件路径 | 变更类型 | 变更原因 | 影响范围 ||---------|---------|---------|---------|| Path/to/file | 新增 | 说明 | 模块名 |原型方向示例┌─────────────────────────────────────────┐│ 用户登录 [×] │├─────────────────────────────────────────┤│ 邮箱地址 * ││ ┌─────────────────────────────────────┐ ││ │ userexample.com │ ││ └─────────────────────────────────────┘ │└─────────────────────────────────────────┘流程图方向示例后端API登录界面用户后端API登录界面用户点击登录按钮POST /api/auth/login这些示例让 AI 能够准确理解期望的输出格式而不是自己发挥。这也有点像考试时给参考答案虽然不能完全一样但格式总要对吧。3. 使用规范语言明确要求对于不同文档类型的可视化要求我们用规范语言来约束对于 proposal.md- 必须包含代码变更表当启用 change-map 方向- 必须包含 UI 原型图当涉及 UI 变更且启用 prototype 方向- 禁止包含详细的架构图这些应在 design.md 中对于 design.md- 必须包含所有 proposal.md 的内容更详细版本- 必须包含架构图当启用 architecture 方向- 必须包含数据流图当启用 flowchart 方向这种明确的约束大大改善了生成质量。其实也没别的就是把话说清楚不要让 AI 去猜。实践代码实现理论说完了来看看 HagiCode 项目中是怎么实现的。定义规划方向在ProposalPlanningDirections.cs中定义规划方向public static class ProposalPlanningDirections{private static readonly ProposalPlanningDirectionDefinition[] Catalog [new(ChangeMapId,Change map,DefaultEnabled: true,EnglishPromptFragment:- Change map: include structured file-impact views...,ChinesePromptFragment:- 变更地图加入结构化的文件影响视图...),// ... 其他方向];public static string RenderInstructionBlock(IEnumerableProposalPlanningDirectionState directions,string? locale){var enabledDirections directions.Where(direction direction.Enabled).ToArray();if (enabledDirections.Length 0){return string.Empty;}var heading IsChineseLocale(locale)? 本次生成启用以下规划方向: Apply the following planning directions:;return string.Join(Environment.NewLine,[heading, .. enabledDirections.Select(d d.GetPromptFragment(locale))]);}}这段代码有几个值得注意的设计点使用数组而不是列表因为定义在运行时不会改变延迟渲染——只在有启用方向时才生成文本支持多语言根据 locale 选择合适的提示词片段其实也没什么特别的就是一些常规的代码设计罢了。模板参数化在 Handlebars 模板中使用条件语句{{#if planningDirectionInstructions}}## 本次生成的规划方向{{{planningDirectionInstructions}}}{{/if}}**步骤**1. **如果未提供输入使用合理的默认值**2. **创建变更目录**3. **获取工件构建顺序**4. **按顺序创建工件直到 apply-ready**a. 对于每个 ready 的工件- 获取说明- 阅读依赖文件- 创建工件文件
自定义 OpenSpec 步骤改进 AI 生成结果
发布时间:2026/6/26 8:49:44
背景OpenSpec 是一个管理技术提案的系统核心想法很简单输入变更描述自动生成各种文档工件。proposal、design、specs、tasks这些都能自动生成。听起来挺美好的不是吗只是在实际使用中我们发现了一些问题。怎么说呢也不是什么大问题就是生成的东西不太对味儿。生成的design.md缺少必要的可视化元素——没有 Mermaid 流程图没有时序图更没有架构图。这样的设计文档技术团队看了直摇头毕竟谁愿意看一堆纯文字呢proposal.md也不尽如人意缺少代码变更表格没有界面原型。决策者看了半天还是不知道这变更到底改了些什么。更让人头疼的是tasks.md里面混入了各种 Git 操作任务。职责边界变得模糊不清开发人员看着这些任务不知道哪些该做、哪些不该做。这也有点无奈毕竟 AI 也不知道你的团队分工是怎么样的。不同文档级别的可视化要求也不明确。proposal 和 design 到底应该包含哪些图表这个问题一直困扰着团队。这些问题的根源在哪呢我们分析后发现了关键点提示词模板缺少明确的约束和指导。这也没什么好奇怪的毕竟模板本身就是通用的不可能完全适配每个团队的需求。关于 HagiCode本文分享的方案来自我们在 HagiCode 项目中的实践经验。HagiCode 是一个 AI 代码助手项目我们在开发过程中大量使用 OpenSpec 来管理技术提案。正是这些实际踩坑经历促成了这套改进方案的诞生。其实也没什么大不了的就是遇到问题解决问题罢了。分析提示词系统架构要解决问题先要理解系统。让我们看看 OpenSpec 的提示词系统是怎么工作的。OpenSpec 使用 Handlebars 模板系统每个提示词包含两个部分JSON 元数据文件定义参数、场景、版本信息Handlebars 模板文件包含实际的提示词内容Resources/Prompts/├── openspec-v1-ff.zh-CN.json # 元数据├── openspec-v1-ff.zh-CN.hbs # 模板内容├── openspec-v1-ff.en-US.json└── openspec-v1-ff.en-US.hbs这种分离设计的优点很明显元数据和内容分开管理便于维护和本地化。这也有点像写代码逻辑和表现分离大家都懂这个道理。FFFast Forward工作流是 OpenSpec 的核心生成流程用户输入变更描述创建变更目录获取工件构建顺序按依赖顺序创建工件检查规划方向要求验证工件完整性显示最终状态这个流程看起来很完美但问题出在规划方向要求这一步——它没有足够明确的指导。这也有点无奈毕竟系统设计的时候也不可能考虑到所有团队的具体需求。规划方向系统规划方向系统是 OpenSpec 的核心自定义机制允许用户选择不同的生成选项。HagiCode 项目中定义了以下方向方向 ID功能默认启用explore探索模式是change-map变更地图是flowchart交互流程图是prototypeUI 原型是architecture架构图是sequenceAPI 时序图是每个方向都定义了稳定的标识符、默认启用状态、显示标签以及中英文提示词片段。这个系统设计得很精巧但在 HagiCode 的实践中我们发现光有定义还不够——需要在提示词模板中明确使用这些方向。这也有点像人生中很多事情有了选项不等于会做出选择还是需要有人告诉你该怎么选。解决方案明确约束和示例我们的改进思路很直接在提示词模板中添加明确的约束和参考示例。其实也没什么特别的就是把话说清楚罢了。1. 添加文档可视化要求在openspec-v1-ff.zh-CN.hbs模板中我们添加了明确的内容范围约束### tasks.md 内容范围约束当创建 tasks.md 工件时必须遵守以下内容范围约束必须包含- 业务逻辑任务代码实现、功能开发- 技术实现任务组件集成、API 开发- 测试任务单元测试、集成测试- 文档任务更新文档、添加注释禁止包含- Git 提交操作git add、git commit、git push- 版本控制管理工作流- 部署和发布操作使用规范的必须/禁止语言而不是建议或可以这让 AI 能够更准确地理解约束。这也有点像教导孩子说什么就是什么不能有歧义。2. 为每个方向提供参考示例光说包含流程图还不够我们为每个启用的方向提供了具体的输出示例。毕竟光说不练假把式给个具体的例子AI 就能更好地理解。变更地图方向示例| 文件路径 | 变更类型 | 变更原因 | 影响范围 ||---------|---------|---------|---------|| Path/to/file | 新增 | 说明 | 模块名 |原型方向示例┌─────────────────────────────────────────┐│ 用户登录 [×] │├─────────────────────────────────────────┤│ 邮箱地址 * ││ ┌─────────────────────────────────────┐ ││ │ userexample.com │ ││ └─────────────────────────────────────┘ │└─────────────────────────────────────────┘流程图方向示例后端API登录界面用户后端API登录界面用户点击登录按钮POST /api/auth/login这些示例让 AI 能够准确理解期望的输出格式而不是自己发挥。这也有点像考试时给参考答案虽然不能完全一样但格式总要对吧。3. 使用规范语言明确要求对于不同文档类型的可视化要求我们用规范语言来约束对于 proposal.md- 必须包含代码变更表当启用 change-map 方向- 必须包含 UI 原型图当涉及 UI 变更且启用 prototype 方向- 禁止包含详细的架构图这些应在 design.md 中对于 design.md- 必须包含所有 proposal.md 的内容更详细版本- 必须包含架构图当启用 architecture 方向- 必须包含数据流图当启用 flowchart 方向这种明确的约束大大改善了生成质量。其实也没别的就是把话说清楚不要让 AI 去猜。实践代码实现理论说完了来看看 HagiCode 项目中是怎么实现的。定义规划方向在ProposalPlanningDirections.cs中定义规划方向public static class ProposalPlanningDirections{private static readonly ProposalPlanningDirectionDefinition[] Catalog [new(ChangeMapId,Change map,DefaultEnabled: true,EnglishPromptFragment:- Change map: include structured file-impact views...,ChinesePromptFragment:- 变更地图加入结构化的文件影响视图...),// ... 其他方向];public static string RenderInstructionBlock(IEnumerableProposalPlanningDirectionState directions,string? locale){var enabledDirections directions.Where(direction direction.Enabled).ToArray();if (enabledDirections.Length 0){return string.Empty;}var heading IsChineseLocale(locale)? 本次生成启用以下规划方向: Apply the following planning directions:;return string.Join(Environment.NewLine,[heading, .. enabledDirections.Select(d d.GetPromptFragment(locale))]);}}这段代码有几个值得注意的设计点使用数组而不是列表因为定义在运行时不会改变延迟渲染——只在有启用方向时才生成文本支持多语言根据 locale 选择合适的提示词片段其实也没什么特别的就是一些常规的代码设计罢了。模板参数化在 Handlebars 模板中使用条件语句{{#if planningDirectionInstructions}}## 本次生成的规划方向{{{planningDirectionInstructions}}}{{/if}}**步骤**1. **如果未提供输入使用合理的默认值**2. **创建变更目录**3. **获取工件构建顺序**4. **按顺序创建工件直到 apply-ready**a. 对于每个 ready 的工件- 获取说明- 阅读依赖文件- 创建工件文件