261 lines
13 KiB
Markdown
261 lines
13 KiB
Markdown
# Agent 规范
|
||
|
||
本文件是 FTB 系统中所有 AI Agent 的**唯一权威定义**。任何对 agent 的能力、职责、权限、协作方式的修改,必须先在本文件落地,再同步到 architecture / decisions / workflow / roadmap / glossary。
|
||
|
||
## 何时更新本文件
|
||
|
||
1. **新增 agent**:新建一个独立 agent
|
||
2. **agent 职责变化**:输入/输出/调用条件变了
|
||
3. **agent 权限变化**:可读哪些数据、可写哪些数据变了
|
||
4. **多 agent 协作方式变化**:编排顺序、依赖关系、出错回退策略变了
|
||
|
||
不影响以上四类的 prompt 微调、模型版本切换、性能优化不需要更新本文件。
|
||
|
||
## 全局原则
|
||
|
||
1. **AI 不直接动数据,先生草案,用户确认**
|
||
- 所有写入实体(DevTask / TestCase)必须带 `aiDraft: true` 标记
|
||
- 用户编辑保存后,标记自动清除(在 `useDevTaskStore.updateTask` / `useTestCaseStore.updateTestCase` 里实现)
|
||
|
||
2. **每条产物强制带引用**
|
||
- DevTask / TestCase 必须有 `references: Reference[]`,至少 1 条
|
||
- 引用类型:`requirement` / `prototype_note` / `external`
|
||
- 不带引用的草案不允许写入
|
||
|
||
3. **AI 输出必须有"对账报告"**
|
||
- 拆解任务前,先输出三段对账:
|
||
- ✅ 完美对应(需求 ↔ 原型注释 ↔ 任务)
|
||
- ⚠️ 仅需求未见原型 / 仅原型未见需求
|
||
- ❓ 注释含糊无法转化
|
||
- 对账报告先呈现给用户,用户审核后才执行写入
|
||
|
||
4. **AI 预估不等于执行人预估**
|
||
- AI 只能输出 `aiEstimateHours`
|
||
- `estimateHours` 留给负责人/执行人确认后填写
|
||
- AI 不输出预计开始/截止时间,排期由负责人后续维护
|
||
|
||
5. **AI 可推荐负责人,但不自动分配**
|
||
- AI 只能从当前版本成员 `members[].name` 中输出可选的 `recommendedAssigneeName`
|
||
- 推荐只作为采纳弹窗里的辅助信息,默认不写入 `assigneeId`
|
||
- 用户勾选“采纳推荐负责人”后,前端再次校验推荐姓名属于当前版本成员,才写入 DevTask/TestCase
|
||
- 没有明确匹配成员时不输出推荐字段
|
||
|
||
6. **历史版本不强制存储**
|
||
- 系统不要求历史原型 URL 作为基准
|
||
- 拆偏问题靠"对账报告"暴露给用户,由人工补救
|
||
- 这条决定见 decisions.md #17
|
||
|
||
## Agent 列表
|
||
|
||
### Agent 1:Prototype Decompose Agent(原型拆解)
|
||
|
||
**目的**:把"产品方案原型 + 关联需求"拆解成开发任务草案 + 测试用例草案。
|
||
|
||
**输入**:
|
||
- 当前版本「产品方案」类型 + status=completed 的 VersionPlan,取其 `resultUrl` 作为**原型链接**(约定:产品方案的成果即原型)
|
||
- 当前版本关联需求列表(已被加进 Version 的 Requirement[])
|
||
- 版本成员清单(带角色:前端/后端/UI/测试)
|
||
|
||
**调用入口**:版本详情页 → 产品方案 Tab → 计划状态 = completed 后,按钮「AI 拆解开发任务」或「AI 拆解测试用例」
|
||
|
||
**触发条件**:
|
||
- 当前版本至少有 1 条 type=product 的 VersionPlan 处于 `completed` 且 resultUrl 非空(提交了原型)
|
||
- 当前版本至少关联 1 条需求
|
||
|
||
**输出**:
|
||
- 对账报告(结构化文本,含"完美对应/单边/含糊"三段)
|
||
- DevTask 草案数组(每条带 `aiDraft: true` + `references[]` + `aiEstimateHours`,可选 `recommendedAssigneeName` / `recommendedAssigneeReason`)
|
||
- TestCase 草案数组(每条带 `aiDraft: true` + `references[]` + `aiEstimateHours`,可选 `recommendedAssigneeName` / `recommendedAssigneeReason`)
|
||
- `target = dev_tasks` 时 `testCaseDrafts` 必须为空数组;`target = test_cases` 时 `devTaskDrafts` 必须为空数组
|
||
|
||
**原型与需求匹配规则**:
|
||
- 优先按需求编号匹配:原型批注或文本出现 `requirement.id` / `requirement.code` 时,必须优先判定为该需求命中。
|
||
- 编号未出现时,再按需求标题和需求概述(`title` / `description`)做语义匹配。
|
||
- 有 QY 编号时,`prototype_note` 引用只能使用真实存在的 QY 编号。
|
||
- 没有 QY 编号但原型文本已命中需求编号或需求概述时,不应丢弃;可只引用 `requirement`,并在 `matched.noteIds` 返回空数组。
|
||
- 只有既匹配不到需求编号,也匹配不到需求概述语义的原型批注,才进入 `noteOnly` 或 `ambiguous`。
|
||
|
||
**测试用例拆解粒度**:
|
||
- TestCase 要按功能点、UI 交互、表单校验、接口、数据一致性、权限、异常、边界、状态流转、兼容性和回归点拆细。
|
||
- 不允许用一条“验证 XX 完整流程”覆盖多个交互、多个接口或多个规则。
|
||
- 一条 QY 若同时涉及 UI、接口、数据、异常和状态变化,通常应拆出 3-8 条 TestCase。
|
||
- 测试用例 `categoryCode` 可使用:`test_functional`、`test_ui_interaction`、`test_form_validation`、`test_api`、`test_data_consistency`、`test_permission`、`test_exception`、`test_boundary`、`test_state_flow`、`test_compatibility`、`test_regression`。
|
||
|
||
**写入**:
|
||
- 用户确认后,调用 `useDevTaskStore.createTask` 和 `useTestCaseStore.createTestCase`
|
||
- 打开采纳弹窗前,前端先过滤当前版本已采纳过的重复 DevTask/TestCase 草案
|
||
- 写入字段中 `aiDraft: true`、`aiDraftAt: ISO时间戳`
|
||
- 写入 `aiEstimateHours`,不写入执行人预估 `estimateHours`
|
||
- DevTask 草案不写预计开始/截止时间,负责人后续排期时再填写
|
||
- 只有用户在采纳弹窗勾选“采纳推荐负责人”时,才把已校验的 `recommendedAssigneeName` 写入 `assigneeId`
|
||
|
||
**权限**:
|
||
- 读:Version, Requirement, VersionPlan, Member
|
||
- 写:DevTask(仅 aiDraft 草案)、TestCase(仅 aiDraft 草案)
|
||
- 不得修改:Requirement、Version、VersionPlan、Member、Bug
|
||
|
||
**失败回退**:
|
||
- 原型 URL 不可达 → 报告"原型无法访问",不写入任何数据
|
||
- 没有已完成的产品方案计划 → 报告"请先完成产品方案并提交原型成果",不写入
|
||
- 关联需求为空 → 报告"无关联需求,无法对照",不写入
|
||
- 对账报告全是 ❓ → 报告"原型注释含糊度过高,建议人工拆解",不写入
|
||
|
||
**MVP 阶段限制**(V3.1):
|
||
- 只生成 DevTask 和 TestCase 草案
|
||
- 不自动分配 assignee;AI 只提供可选推荐,用户确认采纳后才写入
|
||
- 不做"上一版基准 diff"
|
||
|
||
### Agent 2:Risk Watch Agent(小宝预警解读)
|
||
|
||
**目的**:解释小宝预警规则引擎输出的版本发版风险结果,生成项目经理可读的风险原因、延期预测、建议发版窗口和处理动作。
|
||
|
||
**输入**:
|
||
- 版本上下文:产品、项目、版本、期望发版日期。
|
||
- 规则风险结果:`riskScore`、`riskLevel`、`forecastReleaseDate`、`delayDays`、`confidence`、风险信号。
|
||
- 趋势和快照:风险分变化、连续上升/下降、关键 Bug、失败用例、阻塞和静默风险变化。
|
||
- 日报与工作活动证据:今日交付、今日进展、今日风险、进展备注、需要补充进展的事项。
|
||
|
||
**触发**:
|
||
- `on_track` 不触发。
|
||
- `at_risk`、`likely_delayed`、`blocked` 自动触发。
|
||
- `attention` 在风险分明显上升、趋势连续上升、关键 Bug 增加、失败用例增加、阻塞增加、静默风险增加、置信度下降或预测发版日延后时触发。
|
||
|
||
**输出**:`summary`、`why[]`、`forecast`、`recommendedReleaseWindow`、`suggestedActions[]`、`ownerHints[]`。
|
||
|
||
**权限**:读规则结果和压缩证据;写 `xiaobao-risk-insights` 缓存。不修改 Version、Requirement、DevTask、TestCase、Bug、Member。
|
||
|
||
**失败回退**:AI 不可用时保留规则预警,前端显示“规则预警已生成,AI 解读会在触发条件满足时自动补充”。AI 失败不影响快照保存和规则风险展示。
|
||
|
||
### Agent 3:Schedule Suggest Agent(排期建议)— 待规划
|
||
|
||
仅占位,正式规划见 roadmap.md V3.2。
|
||
|
||
## 多 Agent 协作(V3.2 规划)
|
||
|
||
当前 V3.1 只有 Prototype Decompose Agent 单独运行。
|
||
未来 Risk Watch / Schedule Suggest 引入后,编排策略另行设计。
|
||
|
||
## 实现位置
|
||
|
||
V3.1 起,所有 Agent **走 NestJS 后端**(不走 Next.js API Route),原因:
|
||
- 与现有 `product` / `requirement` 模块架构一致
|
||
- 共享 Prisma 实例便于后续 AiLog 持久化
|
||
- 多 Agent 引入时统一在 `AiGateway` 管理 prompt / 降级 / 重试
|
||
|
||
代码位置:
|
||
```
|
||
apps/server/src/modules/
|
||
├── ai/
|
||
│ ├── ai.module.ts
|
||
│ ├── ai.controller.ts # POST /api/v1/ai/decompose
|
||
│ ├── ai.service.ts # 抓原型 + 调 LLM + 解析
|
||
│ ├── ai-gateway.service.ts # Anthropic 客户端单例(懒加载,key 改了重建)
|
||
│ ├── prompts/decompose.ts # System Prompt + Tool Schema
|
||
│ └── dto/decompose.dto.ts # 入参校验
|
||
└── config/
|
||
├── config.module.ts
|
||
├── ai-config.controller.ts # GET/PATCH /api/v1/config/ai, POST /test
|
||
├── ai-config.service.ts # 读写 data/ai-config.json
|
||
└── dto/update-ai-config.dto.ts
|
||
```
|
||
|
||
共享类型:`packages/shared/src/agent.ts`(前后端通用)
|
||
|
||
## 配置管理
|
||
|
||
**多提供商支持(V3.1.5 起)**:系统支持配置任意数量的 AI 提供商,每个独立的 baseURL / apiKey / model,运行时切换激活。
|
||
|
||
**支持的 API 格式**:
|
||
- `anthropic` — Anthropic 官方 + 兼容 Anthropic Messages API 格式的中转站(如 ikuncode 的 anthropic 端点)
|
||
- `openai` — OpenAI 官方 + 兼容 OpenAI Chat Completions 格式的中转站
|
||
|
||
**API Key 优先级**:当前激活提供商的 apiKey → 环境变量 `ANTHROPIC_API_KEY`(兜底,仅 anthropic 格式可用)
|
||
|
||
**前端配置入口**:`/admin/ai-config`,仅超管(`role.permissions` 含 `'*'`)可见
|
||
|
||
**字段(每个 Provider)**:
|
||
- `id`:用户自定义唯一 ID(如 `ikuncode`)
|
||
- `name`:显示名
|
||
- `format`:`anthropic` / `openai`
|
||
- `baseURL`:完整 API endpoint
|
||
- `apiKey`:完整 Key 仅在服务端持有;前端只能拿到 mask 视图
|
||
- `model`:该提供商上使用的模型 ID
|
||
- `remark`:可选备注
|
||
|
||
**全局字段**:
|
||
- `activeProviderId`:当前激活哪个 provider
|
||
- `updatedAt` / `updatedBy`:审计
|
||
|
||
**测试连接**:`POST /api/v1/config/ai/test` 带 `{ id }`,用 16 token 极简调用验证目标 provider 可用性
|
||
|
||
**激活**:`POST /api/v1/config/ai/activate` 带 `{ id }`,切换激活 provider;AiGateway 缓存自动失效,下次调用重新构建客户端
|
||
|
||
**安全约束**:
|
||
- 配置文件路径在 .gitignore 里(`apps/server/data/`),不进入版本控制
|
||
- 前端 GET 接口永远不返回完整 Key
|
||
- 修改 Key 只能从前端 PATCH 上传新值,不支持读出旧值
|
||
- 编辑提供商时若不传 apiKey,则保留原值
|
||
|
||
**数据迁移**:旧版(V3.1)的 `{ anthropicApiKey, model }` 单 key 结构,自动迁移为多 providers 结构(id 为 `anthropic-official`,自动激活)。
|
||
|
||
## 数据契约
|
||
|
||
### Reference 类型
|
||
|
||
```ts
|
||
interface Reference {
|
||
type: 'requirement' | 'prototype_note' | 'external';
|
||
id: string; // REQ-008 / QY0007 / 自由文本
|
||
label: string; // 展示用
|
||
url?: string; // 可选跳转链接
|
||
}
|
||
```
|
||
|
||
### AI 草案标记
|
||
|
||
```ts
|
||
// DevTask 和 TestCase 共有
|
||
aiDraft?: boolean;
|
||
aiDraftAt?: string; // ISO 时间戳
|
||
references?: Reference[];
|
||
aiEstimateHours?: number; // AI 预估耗时,单位小时
|
||
```
|
||
|
||
### Agent 输入预期
|
||
|
||
```ts
|
||
interface DecomposeInput {
|
||
version: VersionWithContext; // 上下文(不含 prototypeUrl,原型从产品方案成果取)
|
||
prototypeUrl: string; // 从产品方案 completed 计划的 resultUrl 派生
|
||
requirements: Requirement[]; // 当前版本所属项目下已采纳、可用于本次拆解的需求
|
||
members: VersionMember[]; // 该版本参与人员(带角色)
|
||
target?: 'all' | 'dev_tasks' | 'test_cases';
|
||
}
|
||
```
|
||
|
||
要求:`requirements` 不能从产品级全量需求池直接取,必须经过项目维度和已采纳状态过滤。
|
||
|
||
### Agent 输出预期
|
||
|
||
```ts
|
||
interface DecomposeOutput {
|
||
report: {
|
||
matched: Array<{ reqId: string; noteIds: string[]; taskCount: number }>;
|
||
reqOnly: string[]; // 需求 ID 列表
|
||
noteOnly: string[]; // 原型注释 ID 列表
|
||
ambiguous: Array<{ noteId: string; reason: string }>;
|
||
};
|
||
devTaskDrafts: Array<{ title: string; description?: string; categoryCode: string; priority: Priority; aiEstimateHours: number; recommendedAssigneeName?: string; recommendedAssigneeReason?: string; references: Reference[] }>;
|
||
testCaseDrafts: Array<{ title: string; description: string; categoryCode: string; priority: Priority; aiEstimateHours: number; recommendedAssigneeName?: string; recommendedAssigneeReason?: string; references: Reference[] }>;
|
||
}
|
||
```
|
||
|
||
要求:AI 不输出数据库 `categoryId`,只输出稳定 `categoryCode`。前端确认写入时按 `TaskCategory.code` 映射成 `categoryId`;映射失败时使用对应分组的默认类型兜底。AI 不输出 `estimateHours`、预计开始或预计截止。
|
||
|
||
## 视觉规范
|
||
|
||
AI 草案在 DevTask / TestCase 列表中的视觉区分:
|
||
- 整行加 `border-l-2 border-l-purple-400 bg-purple-50/30`
|
||
- 标题旁紫色徽章「AI 草案」(`bg-purple-100 text-purple-600`)
|
||
- 用户在详情抽屉里编辑保存任意字段后,徽章和左边线自动消失
|