自定义 OpenSpec 步骤改进生成结果
自定义 OpenSpec 步骤改进 AI 生成结果
在使用 OpenSpec 管理技术提案时,我们遇到了 AI 生成文档质量不稳定的问题。其实也没别的办法,只能自己动手改提示词模板了。这篇文章就是那段日子的记录。
背景
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这种分离设计的优点很明显:元数据和内容分开管理,便于维护和本地化。这也有点像写代码,逻辑和表现分离,大家都懂这个道理。
FF(Fast Forward)工作流是 OpenSpec 的核心生成流程:
flowchart TD A[用户输入变更描述] --> B[创建变更目录] B --> C[获取工件构建顺序] C --> D[按依赖顺序创建工件] D --> E[检查规划方向要求] E --> F[验证工件完整性] F --> G[显示最终状态]这个流程看起来很完美,但问题出在”规划方向要求”这一步——它没有足够明确的指导。
这也有点无奈,毕竟系统设计的时候,也不可能考虑到所有团队的具体需求。
规划方向系统
规划方向系统是 OpenSpec 的核心自定义机制,允许用户选择不同的生成选项。HagiCode 项目中定义了以下方向:
| 方向 ID | 功能 | 默认启用 |
|---|---|---|
explore | 探索模式 | 是 |
change-map | 变更地图 | 是 |
flowchart | 交互流程图 | 是 |
prototype | UI 原型 | 是 |
architecture | 架构图 | 是 |
sequence | API 时序图 | 是 |
每个方向都定义了稳定的标识符、默认启用状态、显示标签,以及中英文提示词片段。
这个系统设计得很精巧,但在 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 | 新增 | 说明 | 模块名 |原型方向示例:
┌─────────────────────────────────────────┐│ 用户登录 [×] │├─────────────────────────────────────────┤│ 邮箱地址 * ││ ┌─────────────────────────────────────┐ ││ │ user@example.com │ ││ └─────────────────────────────────────┘ │└─────────────────────────────────────────┘流程图方向示例:
sequenceDiagram participant U as 用户 participant UI as 登录界面 participant API as 后端API U->>UI: 点击登录按钮 UI->>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( IEnumerable<ProposalPlanningDirectionState> 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 的工件: - 获取说明 - 阅读依赖文件 - 创建工件文件注意那个 {{{planningDirectionInstructions}}}——三个花括号表示不转义 HTML,这样可以保留 Mermaid 代码块等格式。
这也有点像生活中的妥协,有时候需要保留一些原始的东西,不能什么都转义。
提示词加载实现
通过 FilePromptProvider 实现提示词的参数化加载:
public async Task<string> GetOpenspecV1FfPromptAsync( string changeName, string changeDescription, string locale = "en-US", string? planningDirectionInstructions = null, CancellationToken cancellationToken = default){ var parameters = new Dictionary<string, object> { { "planningDirectionInstructions", ResolvePlanningDirectionInstructions(locale, planningDirectionInstructions) } };
if (!string.IsNullOrWhiteSpace(changeName)) { parameters["changeName"] = changeName; }
return await GetPromptWithParametersAsync( PromptScenario.OpenspecV1Ff, locale, cancellationToken, parameters) ?? string.Empty;}这个设计很灵活:planningDirectionInstructions 是可选的,如果不提供,系统会使用默认配置。
毕竟谁也不希望每次都传入一堆参数,有个默认值总是好的。
验证和测试
实现后,HagiCode 团队进行了全面的验证:
启用特定方向时
- 检查生成的 proposal.md 是否包含代码变更表
- 检查生成的 design.md 是否包含架构图
- 验证 tasks.md 不包含 Git 操作任务
禁用特定方向时
- 验证不会生成对应的可视化内容
- 确保不影响其他方向的输出
边界情况
- 所有方向都禁用时的行为
- 无效的方向 ID 时的错误处理
这些测试确保了系统的稳定性和可预测性——这对团队采用新工具至关重要。
其实也没什么特别的,就是该测的都要测到,毕竟谁也不希望上线之后出问题。
注意事项
在实施这套方案时,有几个坑要避开:
模板同步:修改模板时注意与上游保持同步。HagiCode 团队就遇到过一次模板冲突,花了半天时间才解决。这也有点无奈,毕竟升级总是会带来一些兼容性问题。
双语一致性:确保中英文模板的结构和约束一致。我们曾经遇到过中文版本有约束、英文版本没有的情况,导致生成的文档质量不一致。这也有点尴尬,毕竟谁知道用户会用哪种语言呢。
性能影响:规划方向的渲染应在微秒级完成。如果渲染时间过长,会影响用户体验。毕竟谁愿意等半天才能看到结果呢。
向后兼容:保留对旧版本 API 的支持。比如 enableExploreMode 参数,虽然我们现在用规划方向系统,但旧代码还在用。这也有点无奈,毕竟不能总是要求所有人都升级。
清晰的表达:使用规范语言(MUST/SHALL)而非建议性语言。这一点在 HagiCode 的实践中得到了充分验证。其实也没什么别的,就是把话说清楚罢了。
总结
通过自定义 OpenSpec 提示词步骤,我们成功改进了 AI 生成文档的质量。关键改进点包括:
- 在提示词模板中添加明确的约束条件
- 为每个规划方向提供具体的输出示例
- 使用规范语言(MUST/MUST NOT)来约束 AI 行为
- 通过代码实现灵活的提示词参数化加载
这套方案在 HagiCode 项目中得到了验证,生成的文档质量明显提升:设计文档包含了完整的可视化元素,提案文档有清晰的代码变更表,任务清单职责明确。
其实也没什么大不了的,就是把问题解决了罢了。
如果你也在使用类似的 AI 辅助文档生成系统,希望这些经验对你有帮助。记住:清晰的约束和具体的示例,是获得高质量输出的关键。
毕竟有些事情,还是说清楚比较好…
参考资料
开始使用 HagiCode
一次安装,几分钟上手
HagiCode for Windows 在 Microsoft Store 免费提供。打开商店即可安装并保持更新;也可以先对比各版本与定价,再决定从哪个渠道开始。