fix(ai): 拆解原型无需求ID任务

This commit is contained in:
Script Generator
2026-07-01 13:33:04 +08:00
parent 24e8635a94
commit 756621d366
23 changed files with 371 additions and 45 deletions

View File

@@ -24,14 +24,17 @@ export const DECOMPOSE_SYSTEM_PROMPT = `你是 FTB 项目管理系统的产品
- 第二优先级:没有需求编号时,再用需求 title / description需求概述与原型批注或文本做语义匹配
- 有 QY 编号时prototype_note 引用只能使用真实存在的 QY 编号
- 没有 QY 编号但文本已命中需求编号或需求概述时,不要因为缺少 QY 就丢弃;可只引用 requirement并在 matched.noteIds 返回空数组
- 只有既匹配不到需求编号,也匹配不到需求概述语义的原型批注,才放入 noteOnly 或 ambiguous
- 既匹配不到需求编号,也匹配不到需求概述语义,但能形成明确功能名称和任务/用例范围的原型批注,必须进入 prototypeOnly 无需求ID分组并继续拆解
- 只有无法形成稳定任务/用例的含糊批注才进入 ambiguous
3. 任务来源限定
- 只为以下情况拆任务:
a) 同时被需求和原型 QY 命中
b) 需求编号或需求概述在原型文本中命中,但没有 QY 编号
c) 仅需求命中(原型未涉及,按需求文字拆,但工时设小,标记需要后期补充)
- 仅 QY 命中、需求未提的批注,不拆任务,只在 noteOnly 报告里列出
d) 原型 QY 批注明确可拆,但没有匹配到任何关联需求
- d) 必须生成无需求ID草案report.prototypeOnly 记录 requirementName/noteIds/taskCount草案不带 requirement 引用,但必须带 requirementName 和至少 1 条 prototype_note 引用
- 无需求ID草案不创建 Requirement不加入需求池不加入版本关联需求列表只写入 DevTask/TestCase 的 requirementName 作为展示分组名
4. 颗粒度(细颗粒)
- 一条 QY 涉及前后端时,前端任务和后端任务必须分开
@@ -79,13 +82,14 @@ export const DECOMPOSE_SYSTEM_PROMPT = `你是 FTB 项目管理系统的产品
【对账报告要求】
- matched: 完美对应(哪条需求 ↔ 哪些 QY ↔ 拆出多少任务)
- reqOnly: 需求里有但原型未见 → 列出需求 ID
- noteOnly: 原型里有但需求未提 → 列出 QY 编号
- prototypeOnly: 原型里有明确功能但没有匹配到关联需求 → 列出 requirementName、QY 编号和拆出任务数
- ambiguous: QY 描述含糊无法转化 → 列出 QY 编号 + 含糊原因
【特殊情况】
- 若原型内容里看不到任何 QY 编号或类似的批注编号,但能匹配到需求编号或需求概述 → 仍按命中的需求拆解matched.noteIds 返回空数组
- 若原型内容里看不到任何 QY 编号或类似的批注编号,也匹配不到任何需求编号或需求概述 → ambiguous 列表里标注"原型内容无可识别的批注,可能不是 PRD/原型文档"devTaskDrafts/testCaseDrafts 返回空数组
- 若原型完全无法解析 → 同上处理
- 若草案没有 requirement 引用,必须有 requirementNamerequirementName 使用该批注的稳定功能名称,例如"预入职人员支持"
【输出通道强制要求】
- 第一块响应内容必须是 submit_decompose 的 tool_use
@@ -116,7 +120,18 @@ export const DECOMPOSE_TOOL_INPUT_SCHEMA = {
},
},
reqOnly: { type: 'array', items: { type: 'string' } },
noteOnly: { type: 'array', items: { type: 'string' } },
prototypeOnly: {
type: 'array',
items: {
type: 'object',
properties: {
requirementName: { type: 'string' },
noteIds: { type: 'array', items: { type: 'string' } },
taskCount: { type: 'integer' },
},
required: ['requirementName', 'noteIds', 'taskCount'],
},
},
ambiguous: {
type: 'array',
items: {
@@ -129,7 +144,7 @@ export const DECOMPOSE_TOOL_INPUT_SCHEMA = {
},
},
},
required: ['matched', 'reqOnly', 'noteOnly', 'ambiguous'],
required: ['matched', 'reqOnly', 'prototypeOnly', 'ambiguous'],
},
devTaskDrafts: {
type: 'array',
@@ -154,6 +169,7 @@ export const DECOMPOSE_TOOL_INPUT_SCHEMA = {
},
priority: { type: 'string', enum: ['P0', 'P1', 'P2', 'P3'] },
aiEstimateHours: { type: 'number' },
requirementName: { type: 'string' },
recommendedAssigneeName: { type: 'string' },
recommendedAssigneeReason: { type: 'string' },
references: {
@@ -198,6 +214,7 @@ export const DECOMPOSE_TOOL_INPUT_SCHEMA = {
},
priority: { type: 'string', enum: ['P0', 'P1', 'P2', 'P3'] },
aiEstimateHours: { type: 'number' },
requirementName: { type: 'string' },
recommendedAssigneeName: { type: 'string' },
recommendedAssigneeReason: { type: 'string' },
references: {