OpenSpec规范驱动开发:AI时代可审计、可追溯的协作契约
2026/9/14 9:14:00 网站建设 项目流程

1. 为什么“规范驱动开发”在AI编程时代突然变得不可绕过?

OpenSpec 这个词最近在技术社区里出现的频率,已经快赶上“提示词工程”和“Agent编排”了。但很多人点开文档的第一反应是:这不就是个写 YAML 的格式规范吗?跟 AI 编程有啥关系?我用 Cursor 写代码、用 Dify 拖节点、用 ComfyUI 连工作流,不也挺好?——这种想法非常真实,我也这么想过,直到我在一个需要交付给客户、要被第三方审计、且必须支持三年以上维护周期的 AI 辅助设计系统里,连续踩了三次“看似无关紧要”的坑。

第一次是提示词版本失控。我们团队五个人,各自维护一套“生成电路板布局建议”的提示词,有人加了温度参数,有人删了约束条件,有人把“禁止跨层布线”写成“尽量避免”,结果模型输出的可制造性评估报告,在测试环境和生产环境里给出完全相反的结论。没人能说清哪一版是对的,因为没人记录过“这个提示词到底定义了什么业务规则”。

第二次是工作流逻辑漂移。我们用 n8n 搭建了一个简历初筛流程:PDF解析 → 关键词提取 → 岗位匹配度打分 → 邮件通知。上线两周后,HR 提出要把“Python 经验”权重从 0.3 调到 0.45,技术同学改完配置,发现打分模块的输入结构变了——原来传的是纯文本,现在前端加了个字段叫raw_content_hash,而打分脚本没做兼容,直接报错。没人知道这个字段是谁加的、为什么加、是否影响其他环节。

第三次最致命:合规审计失败。客户要求提供“AI决策链路的可追溯性证明”。我们拿出了所有日志、所有模型调用记录、所有工作流执行图……但审计方只问了一句话:“请指出,在‘岗位匹配度打分’这个环节中,‘Python 经验’权重为 0.45 这一业务规则,其来源、生效范围、变更审批记录,分别对应哪个可验证的、独立于代码的权威定义?” 我们哑口无言。那一刻我才明白,不是 AI 不够聪明,是我们没有给它一个“能被所有人共同理解、共同签署、共同遵守”的契约。

OpenSpec 就是这份契约。它不是又一个“AI 工具”,而是一种开发范式升级:把过去散落在 README、Confluence、口头约定、甚至开发者脑回沟里的业务规则、接口契约、流程边界、质量约束,全部收束到一份机器可读、人类可审、版本可控、变更可溯的规范文件里。OPSX(OpenSpec Execution)则是让这份契约真正活起来的执行引擎——它不写业务逻辑,它只负责确保所有参与方(人、模型、工具、服务)都严格按契约行事。就像建筑行业的施工图纸,图纸本身不盖楼,但没有它,钢筋工、水电工、监理方根本没法协同。OpenSpec 是 AI 时代的“施工图纸”,OPSX 是那个拿着图纸逐项核验的“现场监理”。

所以,“规范驱动开发”不是给程序员多加一道工序,而是把原本隐性的、高风险的、靠人肉对齐的协作成本,显性化、标准化、自动化。它解决的从来不是“怎么让 AI 更聪明”,而是“怎么让一群聪明的人和聪明的模型,不因为彼此理解偏差而集体翻车”。当你开始为一个需要长期演进、多人协作、对外交付的 AI 系统构建工作流时,OpenSpec 不是“可选项”,而是你规避系统性熵增的唯一安全阀。

2. OpenSpec 规范的本质:一份面向 AI 协作的“三方协议”

很多人把 OpenSpec 简单理解为“YAML 版本的 OpenAPI”,这是个危险的误解。OpenAPI 描述的是 HTTP 接口的请求/响应结构,它管的是“服务之间怎么通信”;而 OpenSpec 描述的是AI 协作单元之间的契约关系,它管的是“人、模型、工具之间,关于‘做什么’、‘做成什么样’、‘谁来保证’的共识”。

这份契约之所以必须存在,是因为 AI 编程引入了三个前所未有的变量:非确定性输出、能力黑箱化、执行主体多元化。一个 LLM 调用可能返回格式正确但语义错误的结果;一个图像生成模型的能力边界,远比 REST API 的 404 或 500 错误更模糊;而一个工作流里,可能同时混着 Python 脚本、Claude API、本地部署的 Stable Diffusion、甚至人工审核节点。OpenSpec 的核心价值,就在于为这三类变量建立可协商、可验证、可执行的锚点。

2.1 OpenSpec 文件的骨架:四个不可分割的“契约支柱”

一个最小可用的 OpenSpec 文件(.openspec.yaml),其结构绝非随意堆砌,而是由四个相互咬合的契约支柱构成:

  1. spec(规范元数据):这是契约的“法律效力声明”。它包含version(规范版本号,强制语义化版本)、title(人类可读的契约名称)、description(该契约要解决的核心业务问题,例如“确保所有简历筛选结果均基于客户最新版 JD 权重规则”)、owner(契约责任方,如hr-team@company.com)。这里的关键是owner字段——它明确指出了当契约被违反时,谁拥有最终解释权和修订权。这不是一个邮箱地址,而是一个组织承诺。

  2. inputs(输入契约):这是对“上游”提供的数据的精确约束。它不只是定义字段名和类型,更强调业务语义。例如:

    inputs: job_description: type: object description: "客户提供的、经 HR 主管签字确认的正式岗位说明书" required: [title, required_skills, experience_years] properties: title: type: string description: "岗位官方名称,需与内部职级体系完全一致" required_skills: type: array items: type: string description: "技能名称必须来自公司《技术栈白名单》v3.2" experience_years: type: number minimum: 2 maximum: 15 description: "最低要求年限,取整数,四舍五入"

    注意description里嵌套的业务规则(“白名单 v3.2”、“四舍五入”),以及minimum/maximum对数值边界的硬性规定。这比 JSON Schema 严格得多,因为它约束的是业务意图,而非仅仅是数据格式。

  3. outputs(输出契约):这是对“下游”可依赖结果的终极承诺。它定义的不是“模型可能返回什么”,而是“系统必须保证交付什么”。例如:

    outputs: screening_report: type: object description: "一份可供 HR 直接用于面试邀约决策的结构化报告" required: [candidate_id, overall_score, skill_match_scores, compliance_flag] properties: overall_score: type: number minimum: 0 maximum: 100 description: "加权综合得分,计算公式见附件《JD-Weighting-Logic-v2.1.pdf》" compliance_flag: type: boolean description: "true 表示报告完全符合当前生效的《AI 简历审核合规手册》第4.7条"

    这里compliance_flag是灵魂。它不是一个计算结果,而是一个可验证的担保声明。OPSX 执行引擎在生成报告后,必须调用一个独立的合规性校验器(可能是另一个 OpenSpec 定义的服务)来确认该标志位是否为true,否则整个工作流视为失败。这把抽象的“合规要求”,变成了一个可自动化的布尔值断言。

  4. workflow(工作流契约):这是对“执行过程”的刚性约束。它不描述具体实现(比如用 Python 还是 Node.js),而是定义状态转换的合法性。一个典型片段:

    workflow: start: parse_pdf states: parse_pdf: type: action input: {pdf_bytes: "$.raw_input.pdf"} output: {text_content: "$.result.text", page_count: "$.result.pages"} next: extract_keywords extract_keywords: type: action # 此处省略具体配置... next: score_matching score_matching: type: action # 此处省略具体配置... next: validate_compliance validate_compliance: type: action # 调用独立的合规校验服务 next: $default end: true

    关键在于next字段。它强制规定了状态流转的唯一合法路径。任何试图跳过validate_compliance直接进入end的行为,都会被 OPSX 引擎拦截并报错。这杜绝了“为了赶进度临时注释掉校验步骤”的灰色操作。

这四个支柱共同构成了一个闭环:spec定义契约身份,inputs约束入口,outputs承诺出口,workflow管控过程。它们缺一不可,共同回答了 AI 协作中最根本的三个问题:谁说了算?(spec);什么能进来?(inputs);什么才算完成?(outputs & workflow)。这才是 OpenSpec 区别于其他配置文件的底层逻辑。

3. OPSX 工作流引擎:如何让规范从纸面走向产线

理解 OpenSpec 规范的静态结构只是第一步。真正的挑战在于:如何让这份写在 YAML 里的“宪法”,变成每天在服务器上跑、在 IDE 里调试、在 CI/CD 流水线里卡点的“活的法律”?这就是 OPSX(OpenSpec Execution)引擎的核心使命。它不是另一个低代码平台,而是一个规范感知型的执行中间件。它的设计哲学很朴素:绝不替代你的代码,只负责确保你的代码在规范划定的轨道内运行。

3.1 OPSX 的三层执行模型:从“契约解析”到“行为仲裁”

OPSX 的执行并非线性流水,而是一个分层仲裁的过程,每一层都承担着不同的“守门人”职责:

第一层:契约解析与静态验证(Compile-Time Guardrail)
当你执行opsx validate --spec my-spec.yaml时,OPSX 并不做任何实际计算,它只做三件事:

  1. 语法与结构校验:检查 YAML 是否合法,spec/inputs/outputs/workflow四个顶级字段是否齐全,workflow.states中的next指向是否都存在于states列表中。这相当于编译器的语法检查。
  2. 语义一致性检查:这是关键。它会扫描inputs中定义的required_skills字段,然后去workflowparse_pdf状态的output中查找是否有$.result.skills这样的路径被声明为输出。如果inputs要求“必须提供技能列表”,而workflow的任何输出路径都无法产生这个列表,OPSX 就会报错:“Input requirement 'required_skills' has no corresponding output path in workflow.” 这种跨章节的关联性检查,是传统配置校验器做不到的。
  3. 版本兼容性检查:如果spec.version1.2.0,而你本地安装的 OPSX 引擎只支持1.0.x规范,它会明确拒绝执行,并提示你需要升级引擎。这保证了规范的演进不会导致旧系统无声崩溃。

第二层:运行时契约注入与上下文编织(Runtime Context Weaving)
opsx run --spec my-spec.yaml --input data.json启动时,OPSX 才真正开始工作。它做的第一件事,是将inputsoutputs的契约定义,动态注入到每一个工作流节点的执行环境中。以score_matching节点为例:

  • 它的 Python 脚本(假设叫scorer.py)本身并不知道什么是“客户最新版 JD 权重规则”。
  • OPSX 在调用scorer.py之前,会先读取my-spec.yamlinputs.job_description.required_skills的定义,并将其解析为一个带有元数据的对象(例如{skills: ['Python', 'SQL'], source: 'whitelist-v3.2'}),然后作为额外的、只读的上下文参数(--context)传递给脚本。
  • scorer.py的代码可以这样写:
    import sys, json # 从标准输入读取主数据 input_data = json.load(sys.stdin) # 从命令行参数读取 OPSX 注入的契约上下文 context = json.loads(sys.argv[1]) if len(sys.argv) > 1 else {} # 现在,脚本可以安全地使用 context['source'] 来决定加载哪个权重配置文件 weights_config = load_weights_from_source(context['source']) # e.g., 'whitelist-v3.2' result = calculate_score(input_data['resume_text'], weights_config) print(json.dumps(result))
    这种设计彻底解耦了业务逻辑与契约规则。scorer.py只关心“怎么算分”,而“用哪个规则来算分”这个决策权,交给了 OpenSpec 规范本身。这正是“规范驱动”的精髓——规则在 YAML 里,逻辑在代码里,两者通过 OPSX 无缝缝合。

第三层:契约履行仲裁与异常熔断(Execution Arbitration)
这是 OPSX 最体现“守门人”价值的一层。它全程监控工作流的每一步输出,并与outputs契约进行实时比对:

  • score_matching节点输出一个overall_score105时,OPSX 会立刻捕获这个违反maximum: 100的行为,并中断流程,抛出OutputContractViolationError: 'overall_score' (105) exceeds maximum allowed value (100)
  • validate_compliance节点返回{"compliance_flag": false}时,OPSX 不会简单地将这个false传给下游,而是触发预设的“熔断策略”——它可以自动发送告警邮件给spec.owner,或者将本次执行的完整 trace 数据存入审计数据库,或者直接回滚到上一个已知的合规状态。
  • 更重要的是,OPSX 会生成一份契约履行报告--report参数),其中清晰列出:哪些输入字段被成功验证、哪些输出字段被精确满足、哪些工作流状态被按契约执行、以及在哪个环节、因哪个具体契约条款被违反而导致了失败。这份报告,就是你向审计方提交的“可追溯性证明”的核心证据。

这三层模型,让 OPSX 成为了一个强大的“契约翻译器”和“行为裁判员”。它不关心你的scorer.py是用 PyTorch 还是 TensorFlow 写的,它只关心:你是否在契约允许的范围内,做出了契约所要求的输出。这种分离,正是大规模、高可靠性 AI 系统得以构建的基石。

4. 从零搭建一个真实场景:用 OpenSpec + OPSX 实现“MCU 固件需求变更影响分析”工作流

理论讲得再透,不如亲手搭一个能跑起来的实例。我们来做一个非常典型的工业场景:一家 MCU(微控制器)芯片公司的固件团队,需要快速评估一个新提出的硬件功能需求(比如“增加 USB-C 充电握手协议支持”)会对现有固件代码库产生哪些影响。过去,这需要资深工程师花 2-3 天手动 grep、阅读文档、咨询硬件同事。现在,我们用 OpenSpec 定义一个自动化工作流,目标是:输入一个自然语言需求描述,输出一份结构化的、带引用链接的影响分析报告,且报告中的每一项结论,都必须能追溯到具体的 OpenSpec 契约条款。

4.1 第一步:定义核心契约(.mcu-impact-analysis.openspec.yaml

我们先不写一行代码,只专注定义“这件事到底要达成什么共识”。根据前面的四个支柱,我们写出规范:

spec: version: 1.0.0 title: "MCU 固件需求变更影响分析服务" description: "自动化分析任意新增硬件功能需求对现有固件代码库、文档、测试用例的潜在影响范围" owner: firmware-arch@chipco.com inputs: hardware_requirement: type: object description: "由硬件架构师提交的、经评审会议纪要编号确认的需求描述" required: [text, meeting_minutes_id, hardware_block] properties: text: type: string description: "需求的自然语言描述,需包含明确的协议名称或标准号(如USB-C PD 3.1)" meeting_minutes_id: type: string pattern: "^MM-[0-9]{6}$" description: "评审会议纪要的唯一ID,格式为 MM-YYYYMM" hardware_block: type: string enum: ["USB", "BLE", "CAN", "SPI", "I2C"] description: "需求所涉及的硬件功能模块" outputs: impact_report: type: object description: "一份供固件负责人决策的结构化影响分析报告" required: [summary, code_impact, doc_impact, test_impact, confidence_score] properties: summary: type: string description: "一句话结论,必须包含'高/中/低'风险等级和'立即行动/观察/无需干预'建议" code_impact: type: array items: type: object required: [file_path, line_numbers, reason] properties: file_path: type: string description: "受影响源码文件的绝对路径,必须存在于 git 仓库中" line_numbers: type: array items: {type: integer} description: "具体受影响的行号范围,格式为 [start, end]" reason: type: string description: "影响原因,必须引用《固件架构指南》v4.2 第3.1节" confidence_score: type: number minimum: 0.0 maximum: 1.0 description: "分析结果的置信度,低于0.7需人工复核" workflow: start: parse_requirement states: parse_requirement: type: action input: {requirement_text: "$.hardware_requirement.text"} output: {parsed_protocol: "$.result.protocol", parsed_standard: "$.result.standard"} next: search_codebase search_codebase: type: action input: {protocol: "$.parsed_protocol", standard: "$.parsed_standard"} output: {code_matches: "$.result.matches"} next: analyze_doc_references analyze_doc_references: type: action input: {code_matches: "$.code_matches"} output: {doc_links: "$.result.links"} next: generate_report generate_report: type: action input: {code_matches: "$.code_matches", doc_links: "$.doc_links"} output: {report: "$.result.report"} next: validate_report validate_report: type: action # 调用一个独立的合规校验器,检查 report 是否满足 outputs 契约 next: $default end: true

这个规范文件,就是我们整个工作的“宪法”。它明确了:谁负责(owner)、输入必须是什么(inputs)、输出必须长什么样(outputs)、以及执行步骤的铁律(workflow)。注意outputs.code_impact[].reason的描述,它强制要求所有分析结论都必须引用《固件架构指南》,这确保了分析的权威性,而不是某个 AI 模型的主观臆断。

4.2 第二步:编写可插拔的节点逻辑(search-codebase.py

现在,我们为search_codebase这个状态编写具体的 Python 脚本。记住,它不需要知道整个规范,只需要处理 OPSX 注入的上下文:

#!/usr/bin/env python3 import sys, json, re, subprocess from pathlib import Path def main(): # 1. 读取 OPSX 注入的主输入(来自 workflow.input) try: input_data = json.load(sys.stdin) protocol = input_data.get('protocol', '') standard = input_data.get('standard', '') except Exception as e: print(f"ERROR: Invalid input JSON: {e}", file=sys.stderr) sys.exit(1) # 2. 读取 OPSX 注入的契约上下文(来自 --context 参数) # 这里我们假设上下文里包含了代码库根路径和搜索策略 context = {} if len(sys.argv) > 1: try: context = json.loads(sys.argv[1]) except Exception as e: print(f"ERROR: Invalid context JSON: {e}", file=sys.stderr) sys.exit(1) repo_root = context.get('repo_root', str(Path.cwd())) search_strategy = context.get('strategy', 'grep') # 3. 执行搜索逻辑(这里简化为 grep,实际可调用 ctags 或 LSP) matches = [] if search_strategy == 'grep': # 在固件源码目录下搜索协议关键词 for file_path in Path(repo_root).rglob("*.c"): try: with open(file_path, 'r', encoding='utf-8') as f: content = f.read() # 简单的正则匹配,实际应更复杂 if re.search(rf'\b{re.escape(protocol)}\b', content, re.I): # 找到匹配行号 lines = content.split('\n') for i, line in enumerate(lines, 1): if re.search(rf'\b{re.escape(protocol)}\b', line, re.I): matches.append({ "file_path": str(file_path.relative_to(repo_root)), "line_numbers": [i], "reason": "Protocol keyword found in source" }) except Exception as e: continue # 跳过无法读取的文件 # 4. 输出符合 outputs.code_impact 结构的 JSON # OPSX 会在后续步骤中验证这个输出是否满足契约 print(json.dumps({"matches": matches})) if __name__ == "__main__": main()

关键点在于:脚本本身不硬编码repo_rootstrategy,它们都来自 OPSX 的注入。这意味着,同一个search-codebase.py,可以在开发环境(repo_root=./firmware-dev)和生产环境(repo_root=/opt/firmware-prod)无缝切换,只需修改 OpenSpec 文件中的context配置即可。契约驱动了环境的可移植性。

4.3 第三步:集成与实测:一次真实的“USB-C 充电”需求分析

现在,我们准备一个真实的输入文件usb-c-req.json

{ "hardware_requirement": { "text": "为 MCU 增加对 USB-C 充电握手协议(USB Power Delivery 3.1)的支持,需兼容现有 Type-A 充电器。", "meeting_minutes_id": "MM-202405", "hardware_block": "USB" } }

然后执行完整的 OPSX 工作流:

# 1. 首先验证规范本身是否合法 opsx validate --spec .mcu-impact-analysis.openspec.yaml # 2. 运行工作流,注入必要的上下文(repo_root 和 strategy) opsx run \ --spec .mcu-impact-analysis.openspec.yaml \ --input usb-c-req.json \ --context '{"repo_root": "./firmware-src", "strategy": "grep"}' \ --report impact-report.json

几秒钟后,impact-report.json生成。打开它,你会看到类似这样的结构化输出:

{ "summary": "高风险。需立即行动:USB 协议栈核心文件存在多处硬编码依赖,需重构以支持 PD 3.1。", "code_impact": [ { "file_path": "src/usb/usb_core.c", "line_numbers": [142, 143], "reason": "Protocol keyword found in source" }, { "file_path": "src/power/charger_ctrl.c", "line_numbers": [88], "reason": "Protocol keyword found in source" } ], "confidence_score": 0.82 }

更重要的是,--report生成的审计报告会详细记录:code_impact[0].file_path的值"src/usb/usb_core.c"是如何被search-codebase.py的输出所产生,而这个输出又如何被outputs.code_impact.file_pathdescription(“必须存在于 git 仓库中”)所验证。整个链条,环环相扣,无可辩驳。

这个例子展示了 OpenSpec + OPSX 的威力:它没有发明新的 AI 模型,也没有取代工程师的思考。它只是把工程师的领域知识(《固件架构指南》)、团队的协作规则(会议纪要 ID 格式)、以及系统的物理约束(代码库路径),全部编码为一份机器可执行的契约。然后,OPSX 这个“守门人”,确保每一次自动化分析,都严格遵循这份契约。这才是 AI 时代,真正可持续、可审计、可信赖的“智能”。

5. 踩坑实录:那些 OpenSpec 新手必经的“顿悟时刻”

从一个 OpenSpec 的好奇者,到一个能用它构建生产级 AI 工作流的实践者,中间隔着的不是技术鸿沟,而是一系列“啊哈!原来如此!”的顿悟时刻。这些时刻往往伴随着一次失败的opsx run,一次被validate拦下的git push,或者一次审计会上尴尬的沉默。我把这些最痛、也最有价值的经验,浓缩成三个核心顿悟,它们比任何教程都更能帮你少走弯路。

5.1 顿悟一:不要在inputs里定义“你想让 AI 做什么”,而要定义“你必须提供什么”

这是新手最容易栽的第一个跟头。看着热词榜上“ai编程提示词”、“ai编程一些常用的skill”,很多人的第一反应是:我要把我的提示词模板,一股脑儿塞进 OpenSpec 的inputs里!于是写出这样的东西:

# ❌ 错误示范:把提示词当输入 inputs: prompt_template: type: string description: "用于生成代码的提示词模板" default: "你是一个资深嵌入式工程师,请基于以下需求生成 C 代码..."

这完全违背了 OpenSpec 的设计初衷。inputs外部世界向你的工作流提供的、不可变的、事实性数据。一个提示词模板,是你的工作流内部的“实现细节”,它应该藏在search-codebase.py这样的节点脚本里,或者作为context注入,而不是暴露为inputs。把它放进来,会导致两个灾难性后果:

  1. 契约污染prompt_template的任何微小改动(比如加个标点),都会导致spec.version必须升级,进而触发所有下游消费者(如 CI 流水线、监控系统)的重新适配。这把本该稳定的“输入契约”,变成了一个高频变动的“实现开关”。

  2. 责任错位:当模型输出错误时,你是该怪prompt_template写得不好,还是该怪inputs.hardware_requirement.text描述得不清晰?把提示词放进inputs,就等于把“如何解决问题”的责任,推给了输入方。而 OpenSpec 的哲学是:输入方只负责提供“问题是什么”,解决方案的质量,由工作流内部的outputs契约来保障。

正确的做法是:把提示词逻辑,下沉到具体的节点实现中。如果你真的需要多个提示词变体,应该用context来区分:

# ✅ 正确示范:用 context 控制提示词变体 workflow: states: generate_code: type: action input: {requirement: "$.hardware_requirement.text"} # 不在这里定义 prompt,而是在 context 里指定 next: validate_output

然后在运行时,通过--context '{"prompt_variant": "strict-mode"}'来切换。generate_code.py脚本内部,根据context['prompt_variant']加载不同的模板。这样,inputs保持了稳定和纯粹,而灵活性则由context和节点逻辑来承载。

5.2 顿悟二:outputsdescription不是注释,而是可执行的“验收测试用例”

很多新手写完outputs,就以为大功告成,觉得description里写清楚就行。直到他们第一次看到opsx run报出OutputContractViolationError,才恍然大悟:OPSX 真的会去“读”这些description,并把它翻译成代码级别的断言。

例如,你在outputs.impact_report.summarydescription里写了:“一句话结论,必须包含'高/中/低'风险等级和'立即行动/观察/无需干预'建议”。OPSX 引擎(或你集成的校验器)会把这个句子,自动解析为一个正则表达式断言:

# OPSX 内部可能执行的校验逻辑(示意) import re summary = report.get('summary', '') pattern = r'(高|中|低)风险.*?(立即行动|观察|无需干预)' if not re.search(pattern, summary): raise OutputContractViolationError("summary does not match required pattern")

所以,description的写作,本质上是在写自然语言版的单元测试用例。它必须是可形式化、可判定、无歧义的。像“内容要专业”、“表述要清晰”这种模糊描述,OPSX 是无法处理的,它只会让你的validate永远通过,而run永远失败。

实战技巧:写description时,强迫自己回答三个问题:

  • Q1:这个字段的值,是否可以用一个布尔表达式(==,in,re.match())来判断对错?
    如果答案是“否”,说明描述太模糊,需要重写。
  • Q2:这个字段的值,是否可以从输入数据中,通过一个确定性的函数计算出来?
    如果答案是“否”,说明这个字段可能不该放在outputs,而应该放在workflow的某个中间状态里。
  • Q3:如果这个字段的值错了,是否会导致下游消费者(人或系统)做出错误决策?
    如果答案是“否”,那它很可能只是一个日志信息,不该成为outputsrequired字段。

遵循这三个问题,你的outputs契约就会从一堆漂亮的文字,变成一张张坚不可摧的“质量防火墙”。

5.3 顿悟三:workflownext不是“下一步做什么”,而是“只有这一步才能做”

这是最深刻、也最常被忽视的顿悟。新手常常把workflow当成一个简单的执行顺序列表,认为next: validate_compliance只是告诉 OPSX “做完 A 就做 B”。但next的真正含义是:A状态成功完成后,B是唯一被允许的、合法的后续状态。任何其他状态(包括A自身、或C、或end)都是非法的,会被 OPSX 强制阻止。

这个特性,是 OpenSpec 实现“强一致性”的核心。它意味着,你不能在score_matching节点的代码里,偷偷加一个if condition: goto end的逻辑来跳过校验。OPSX 会像一个严厉的交通警察,只认路标(next),不认司机(你的代码)的任何借口。

因此,设计workflow的本质,是在绘制一张“状态机图”,而next就是图上的有向边。一个健壮的workflow,必须考虑所有可能的分支:

# ✅ 正确示范:显式处理分支 workflow: start: parse_requirement states: parse_requirement: type: action next: check_complexity check_complexity: type: action # 这里可以有条件分支 choices: - variable: "$.result.complexity_score" numeric: {greaterThan: 8} next: escalate_to_architect - variable: "$.result.complexity_score" numeric: {lessThanOrEqual: 8} next: search_codebase escalate_to_architect: type: action # 发送邮件给架构师 next: wait_for_approval wait_for_approval: type: wait # 等待人工审批 next: search_codebase search_codebase: type: action next: generate_report generate_report: type: action next: validate_report validate_report: type: action # 如果校验失败,回到等待审批,形成闭环 on_failure: wait_for_approval next: $default end: true

这个workflow显式地处理了“需求过于复杂”的情况,引入了人工审批环节,并且为校验失败提供了重试路径。它不再是线性的“流水线”,而是一个有反馈、有兜底、有决策点的“活的系统”。当你开始用这种思维去设计workflow时,你就真正理解了 OpenSpec 的力量——它不是在编排任务,而是在编排协作的规则

这三个顿悟,没有一个是关于“怎么安装”或“怎么写 YAML”的。它们全都是关于思维方式的切换:从“写代码”切换到“写契约”,从“做功能”切换到“定规则”,从“跑通流程”切换到“保障履约”。掌握了这些,你写的就不再是一个 OpenSpec 文件,而是一份能在 AI 时代,让团队、模型、系统真正高效、可信、可持续协作的“数字宪法”。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询