docs(gen): W-G1 组A execution v2——两轮对抗评审(Codex+opus)修订定稿
v1 判 NO-GO(3 P0 未穿透)→ v2 修订: - 砍门③(promptHash 全局缓存=跨用户复用/跨模块孤儿API/sha256口径雷,非开闸闸;防刷由配额门兜) - GP9 safety 前置到 submitGenerate 服务层(避执行器内卡串行 tick=DoS;独立客户端短超时8s+1重试) - retry 走共享 enqueueWithControlPlane(堵 retry 绕过 GP9/配额) - fail-closed 用中性 LLM_ERROR(不误标正常用户违规) - P1:pom 改 -server/补 infra-api 依赖/验收断业务码非HTTP429/背压>=/level加分档测试/删CAS错误背书 范围=2门+降级+GP9前置;待创始人 nod 实施 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a344ccff04
commit
689d86ed87
389
docs/agent-specs/2026-06-16-W-G1开闸验收门-组A-execution.md
Normal file
389
docs/agent-specs/2026-06-16-W-G1开闸验收门-组A-execution.md
Normal file
@ -0,0 +1,389 @@
|
||||
# W-G1 开闸验收门 · 组A(D12 控制平面 v0 + GP9 合规先行段)· execution 版
|
||||
|
||||
> **状态**:execution 版 v2 · 2026-06-16 · 经两轮对抗评审(Codex+opus)修订
|
||||
> **底稿(已读·与之一致勿偏)**:`docs/agent-specs/2026-06-16-W-G1开闸验收门-review.md`(§3 组A 路径 / §5 爆炸半径 / §6 验收)。
|
||||
> **接地基准**:本文所有 `file:line` 已对 2026-06-16 dev/2.0.0 工作树 Read 核实;标注「已核实」= 亲读确认,「需确认」= 未直读到、留实现期校验。
|
||||
> **纪律**:契约先行(DDL/接口先于实现描述);幂等/超时/失败/补偿对每个外部交互交代;不预写大段不可验证代码。
|
||||
|
||||
---
|
||||
|
||||
## 修订记录(v2)
|
||||
|
||||
> v1 经 Codex(可行性)+ opus(前提)两轮对抗评审判 **NO-GO**:方向对、省力,但有 P0 未穿透。主代理合并三方(含自审)后定盘修订,要点如下:
|
||||
|
||||
1. **砍门③(promptHash 缓存命中复用)**:v0 不做——它是省钱优化非开闸闸,且带全局跨用户复用(所有权/隐私/白嫖真扣费)+ 依赖不存在的跨模块产物状态查询 API(孤儿)+ 返回契约缺 versionId + sha256/MD5 口径雷,风险不值当塞 v0。「3 道前置门」整体改为「**2 道前置门 + 降级门**」。
|
||||
2. **GP9 safety 前置到 `submitGenerate`(服务层),不放执行器**:满足底稿"违规不入队",避开 opus P0-3(执行器内 safety 卡串行 tick 线程 = DoS)。safety 用**服务层独立 LLM 客户端**(执行器 LLM 通道被 `aigc.executor.enabled` 门控、服务层注入不到),**短超时 8s + 至多 1 次重试**。
|
||||
3. **retry 也走控制平面**:抽共享私有方法 `enqueueWithControlPlane(...)`,`submitGenerate` 与 `retryTask` 共用(Codex P0-2:retry 直 insert 会绕过配额/背压/降级/GP9)。
|
||||
4. **fail-closed 用中性提示,不新增枚举**:真违规 → `UNSAFE_PROMPT`;safety 超时/失败 → 复用既有 `LLM_ERROR` + 中性提示"安全检查暂不可用,请稍后重试"(`FailureReasonEnum` 跨契约共享、禁单边扩展)。
|
||||
5. **各 P1/P2 修正**:pom 路径改 `game-module-aigc-server/pom.xml`;aigc-server 补 `huijing-module-infra-api` 依赖(否则注入 `ConfigApi` 编译失败);验收断言断**业务码 `1_101_001_*`**(不产生 HTTP 429/503);背压判定用 `>=` 上限;并发 race 删"CAS 硬保证"错误背书改真理由;level 加"手塞 L2 读 L2 档"单测。
|
||||
|
||||
---
|
||||
|
||||
## ① 目标与范围边界
|
||||
|
||||
### 1.1 目标
|
||||
|
||||
把"一句话生成"对真实创作者放开前,焊死 **2 道硬阻塞闸**,使开闸后单用户压不垮全局串行 worker、违规 prompt 进不了生成与 feed:
|
||||
|
||||
- **D12 控制平面 v0**:在生成任务唯一入口 `AigcTaskServiceImpl.submitGenerate` 入队前加 **2 道前置门 + 降级门**(降级开关 / 配额+并发 / 队列深度背压)+ `game_aigc_task` 加 `level` 列;计费扣退只做**额度记账骨架**(非真扣费)。**`submitGenerate` 与 `retryTask` 共用同一套控制平面**(抽 `enqueueWithControlPlane`)。
|
||||
- **GP9 合规先行段**:补 **10 条违规 prompt 负例集** + **在 `submitGenerate` 提交侧、入队前**接 `safety.prompt-check`(服务层独立 LLM 客户端)→ `safe=false` 即**同步拒绝、不入队**(抛 `UNSAFE_PROMPT` 业务异常)。
|
||||
|
||||
> **promptHash 仍由现有链算 + 落 provenance(不变),v0 只是不读它做缓存。** 原"门③ 缓存命中复用"推迟(见 §1.2 非范围)。
|
||||
|
||||
### 1.2 范围边界(非范围 · 勿展开 · 写此防越界)
|
||||
|
||||
| 非范围项 | 归属 | 不在本规格的理由 |
|
||||
|---|---|---|
|
||||
| **D12 真实计费扣退**(过门交付成功才扣 / 系统失败自动退) | 拆 M4 | 网关 new-api `AddToken` 硬编码 UserId 阻塞(普查 §newapi:21-22),MVP 无真支付;v0 只做额度记账骨架 |
|
||||
| **promptHash 全局去重缓存(原门③)** | 推迟 | 跨用户归属/跨模块产物状态查询/sha256 口径需专门设计;v0 防刷由配额门兜(同 prompt 重复也吃配额) |
|
||||
| **组B 落库组**(D11 就绪评分 / 9d trace 账本 / D9 反同质化) | 另排期 | 评审定为"放了要能管/追溯",v0 并行不卡开闸 |
|
||||
| **审核台可见入口**(D11 评分页 / 合规复核页) | 产品轨 | game-admin 现零 aigc 入口,属前端产品轨 |
|
||||
| **会员档位数值**(L1/L2/L3 各档日配额/并发数) | 待创始人 | 本规格只落 `level` 列与门结构,**具体数值取配置默认值 + 留待创始人拍**(见 §5.4 配额数值占位) |
|
||||
|
||||
> **本规格只交付组A 两块。** 上表五项任一被实现 = 越界,须打回。
|
||||
|
||||
---
|
||||
|
||||
## ② 前置条件
|
||||
|
||||
1. **代码基线**:dev/2.0.0,`game-module-aigc` 编译通过;执行器 `aigc.executor.enabled=true` 时 staging 可真跑(M2 已收口,见 memory `generation-spike-c1-result`)。
|
||||
2. **Flyway 现状**:`huijing-server/.../db/migration/` 现有最大版本 = **V14.0.0**(`V14.0.0__m4_trade_withdraw_transfer_ref.sql`,已核实)。本规格 `level` 迁移 **接 V15.0.0**,**不得与 M4 的 V14.0.0 撞号**。
|
||||
3. **prompt 契约现状**:`safety.prompt-check` 契约已就绪(`contracts/prompts/01-safety/prompt-safety-check.md`,输出 `{safe:boolean, reason}`,已核实),registry 已声明其 `eval: eval/safety.prompt-check/`(已核实),但 **eval 目录尚不存在**(`find contracts/prompts/eval` 无 `safety.prompt-check/`,已核实)。
|
||||
4. **关键架构事实(已核实,强约束下列设计)**:
|
||||
- 生成任务**唯一服务入口** = `AigcTaskServiceImpl.submitGenerate(reqVO, userId)`;App 端 `AppAigcTaskController.submitGenerate` 与 studio 端 `AigcApi.submitGenerate`(`AigcApiImpl` → service)**两臂共用此一处**(已核实 controller + AigcApi)。→ 前置门 + GP9 接此单点 = 双臂同覆盖,无分叉(对齐评审 §5「后端单一入口」)。
|
||||
- **`retryTask`:122 当前直接 `aigcTaskMapper.insert(retry)`:140 入队(已核实),绕过任何前置控制**。本规格抽共享 `enqueueWithControlPlane`,`submitGenerate` 与 `retryTask` 同走(决策D)。
|
||||
- LLM 通道 `ExecutorLlmClient` + prompt 装载 `PromptResourceLoader` **只在执行器内**、且经 `@ConditionalOnProperty(aigc.executor.enabled=true)` 装配(已核实 `AigcExecutorConfiguration`:45 + ExecutorLlmClient:35「本类不标 @Component,只经 @Bean 注册」)→ **`submitGenerate`(服务层)触达不到执行器 LLM 通道**。此事实决定 GP9 须**服务层另起独立 LLM 客户端**(见 §4.2 + §6.2)。
|
||||
- maven-resources 当前只把 `prompts/04-config/*.md` + `templates/*.schema.json` 复制进 `classpath:wanxiang-contracts/`(已核实 **`game-module-aigc-server/pom.xml`:172-175**,resources plugin 在 server 模块、非 parent `game-module-aigc/pom.xml`)→ **`01-safety/prompt-safety-check.md` 未进 classpath**,GP9 需扩 copy-glob。
|
||||
- aigc-server pom 现**仅依赖 `huijing-module-system-api`**(:87,已核实),**无 `huijing-module-infra-api`** → 若降级开关走 infra `ConfigApi`,须先加该依赖(见 §6.1),否则注入编译失败。
|
||||
|
||||
---
|
||||
|
||||
## ③ 涉及模块与文件路径(file:line · 已核实)
|
||||
|
||||
### 3.1 D12 — 改动/新增
|
||||
|
||||
| 文件 | 现状(已核实) | 本规格动作 |
|
||||
|---|---|---|
|
||||
| `game-module-aigc-server/.../service/task/AigcTaskServiceImpl.java` | `submitGenerate`:68(入队前**无任何前置检查**:69-76 仅白名单+prompt非空+模板存在,:89 insert);`retryTask`:122 **直 insert**:140 绕过控制(已核实);`sha256`:238 落 promptHash:85;`cancelTask`:105 状态机已就位 | 抽私有 `enqueueWithControlPlane(...)`(降级门→配额并发→背压→GP9 safety→insert),`submitGenerate`+`retryTask` 同调(§6.1) |
|
||||
| `game-module-aigc-server/.../dal/mysql/task/AigcTaskMapper.java` | `BaseMapperX` 派生(含 MyBatis-Plus `selectCount`);已有 `selectClaimableQueued`/`claimQueuedTask`/`selectStaleRunning` | 加 2 个计数查询(配额计数 / 队列深度计数),走既有索引(§5.3) |
|
||||
| `game-module-aigc-api/.../enums/ErrorCodeConstants.java` | aigc 段 `1-101-***-***`,子段 000 基础 / 002 状态机 / 003 回调(已核实)| 新增 **001 控制平面**子段错误码(配额超限 / 背压拒绝 / 降级暂停 / UNSAFE_PROMPT,§5.5) |
|
||||
| `huijing-server/.../db/migration/V15.0.0__aigc_task_add_level.sql` | 不存在 | 新建:`game_aigc_task` 加 `level` 列(§5.1 DDL) |
|
||||
| `game-module-aigc-server/.../dal/dataobject/task/AigcTaskDO.java` | `level` 字段缺(V2.0.0 无 level 列,已核实)| 加 `level` 字段(映射新列)|
|
||||
| `game-module-aigc-server/.../*Properties.java`(新建 `AigcControlPlaneProperties`) | 执行器配置绑 `aigc.executor`(已核实)| 配额/并发/背压阈值 + 降级开关键 + safety 短超时,**配置驱动**(§5.4)|
|
||||
| `game-module-aigc-server/pom.xml` | 仅 `huijing-module-system-api`:87(已核实)| 加 `huijing-module-infra-api` 依赖(降级开关走 `ConfigApi`,§6.1)|
|
||||
|
||||
### 3.2 GP9 — 改动/新增
|
||||
|
||||
| 文件 | 现状(已核实) | 本规格动作 |
|
||||
|---|---|---|
|
||||
| `contracts/prompts/eval/safety.prompt-check/inputs.jsonl` + `labels.jsonl` + `README.md` | 目录不存在(已核实)| 新建:10 条违规负例(§5.6 + §6.2)|
|
||||
| **`game-module-aigc-server/pom.xml`**:172-175 | copy-glob 只含 `04-config/*.md`+`templates/*.schema.json`(已核实,resources plugin 在 server 模块)| 加 `<include>prompts/01-safety/*.md</include>` |
|
||||
| `game-module-aigc-server/.../service/task/`(**新建服务层 safety 客户端**) | 执行器 `ExecutorLlmClient`/`PromptResourceLoader` 被 `aigc.executor.enabled` 门控、服务层注入不到(已核实)| 新建服务层独立 safety LLM 客户端(OpenAI 兼容调 new-api)+ 装载 `01-safety` prompt(§6.2)|
|
||||
| `game-module-aigc-server/.../service/task/AigcTaskServiceImpl.java` | `submitGenerate`:68 既有校验:69-76 → 入队 | 在既有校验后、入队前调 safety(§6.1 门序 ④);`safe=false` 抛 `UNSAFE_PROMPT`,safety 故障抛中性 `LLM_ERROR`|
|
||||
| `FailureReasonEnum.java`:18 | `UNSAFE_PROMPT("unsafe_prompt",...)`:18 / `LLM_ERROR("llm_error",...)`:22 已声明;注释:10 明文"**不可单边扩展(跨契约共享枚举)**"(已核实)| 复用既有两枚举(不新增);UNSAFE_PROMPT 现为**提交时同步拒绝**业务码,非执行器终态 |
|
||||
|
||||
> **DifyCallbackTxService.java**:302 `promptHash` 已在组包 provenance 落库链(已核实);本规格不改回调写链,promptHash 仍照算照落、**v0 不读它做缓存**(门③推迟)。
|
||||
|
||||
---
|
||||
|
||||
## ④ 数据流与依赖
|
||||
|
||||
### 4.1 D12 控制平面数据流(共享 `enqueueWithControlPlane` · submitGenerate + retryTask 同入)
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A1[submitGenerate<br/>App/studio 两臂] --> EQ
|
||||
A2[retryTask<br/>重试入口] --> EQ
|
||||
EQ[enqueueWithControlPlane 共享方法] --> V0[既有: validateCreator + prompt非空 + 模板存在]
|
||||
V0 --> G0{降级门<br/>new-api 暂停开关?<br/>最便宜·无 LLM}
|
||||
G0 -->|暂停中| R0[拒: AIGC_GENERATE_PAUSED 业务码]
|
||||
G0 -->|放行| G1{门① 配额+并发<br/>per-creator×level 当日计数 + 并发?}
|
||||
G1 -->|超限| R1[拒: AIGC_QUOTA_EXCEEDED 业务码 + 排队位]
|
||||
G1 -->|通过| G2{门② 队列深度背压<br/>全局 queued+running 计数 >= 上限?}
|
||||
G2 -->|超限| R2[拒: AIGC_BACKPRESSURE_REJECTED 业务码]
|
||||
G2 -->|通过| G9{GP9 safety<br/>service 层独立 LLM·最贵·放最后<br/>safe?}
|
||||
G9 -->|safe=false 违规| RB[拒: UNSAFE_PROMPT 业务码 不入队]
|
||||
G9 -->|超时/失败| RF[拒: LLM_ERROR 中性提示 fail-closed 不入队]
|
||||
G9 -->|safe=true| INS[落库 status=0 queued + level + 记账骨架]
|
||||
INS --> OK[返回 taskId(现行行为)]
|
||||
```
|
||||
|
||||
> **门顺序设计依据(决策D)**:① 降级门最先(最便宜、无 LLM,new-api 挂了直接挡)→ ② 配额+并发(纯计数)→ ③ 背压(纯计数)→ ④ GP9 safety(**LLM、最贵、放最后**,免得给"超配额/超背压必被拒"的请求白烧一次 safety 调用)→ ⑤ insert。
|
||||
> **safety 在配额门之后的语义**:超配额/超背压请求**不付 safety**;违规请求**付一次 safety 但在 insert 前被拒 = 不入队、不占配额、0 生成成本**。满足底稿"违规不入队"。
|
||||
|
||||
### 4.2 GP9 数据流(服务层提交侧 · 入队前 · 独立 LLM 客户端)
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S[submitGenerate/retryTask 经控制平面门①②通过] --> CK{GP9: safety.prompt-check(task.prompt)}
|
||||
CK -->|service 层独立 LLM 客户端<br/>OpenAI 兼容 → new-api| LLM[渲染 01-safety prompt<br/>短超时 8s + 至多 1 次重试]
|
||||
LLM --> P{解析 safe?}
|
||||
P -->|safe=false 真违规| BLOCK[抛 UNSAFE_PROMPT 业务异常<br/>同步拒绝·不入队·0 生成成本]
|
||||
P -->|safe=true| INS[继续 insert 入队]
|
||||
P -->|超时/失败·1 次重试后仍判不出| FC[fail-closed: 抛 LLM_ERROR<br/>中性提示 安全检查暂不可用请稍后重试<br/>不入队·用户可重试]
|
||||
```
|
||||
|
||||
> **GP9 接线点 = 服务层 `submitGenerate` 提交侧、入队前(决策B),不接执行器**。理由:① 满足底稿验收"违规不入队";② 避开 opus P0-3——执行器内做 safety 会让 LLM 调用卡在串行 tick 线程上(最长 270s = 90s×3),单条违规即拖死整条生成流水 = DoS。
|
||||
> **不复用执行器 `ExecutorLlmClient`**:它经 `@ConditionalOnProperty(aigc.executor.enabled)` 门控,服务层注入不到(已核实)→ 服务层**另起独立 safety LLM 客户端**(OpenAI 兼容直调 new-api),**短超时(建议 8s)+ 至多 1 次重试**(**不是**生成的 90s×3)。
|
||||
> **成本核算(诚实)**:每次提交都付**一次便宜模型 safety 调用**(小额,独立于 worker 的 ¥0.15 预算),单独配置/记成本日志(见 §4.3 / §7)。**不再有"执行器预检 0 生成成本即挡"的论证**——本规格在提交侧付一次 safety 成本,换取"违规不入队"。
|
||||
|
||||
### 4.3 依赖
|
||||
|
||||
- **外部**:new-api 网关——
|
||||
- **GP9 safety**:服务层独立 LLM 客户端(OpenAI 兼容),**短超时 8s + 至多 1 次重试**(不复用执行器配方);**成本单独配置/记日志**,不混入 worker 的 ¥0.15 生成预算(决策E / Codex P1-3)。
|
||||
- 生成本身:执行器既有 `ExecutorLlmClient`(不受本规格改动)。
|
||||
- **内部**:`AigcTaskMapper`(计数查询)、服务层 safety prompt 装载、降级开关载体 infra `ConfigApi`(需补 `huijing-module-infra-api` 依赖,§6.1)。
|
||||
|
||||
---
|
||||
|
||||
## ⑤ 接口/数据契约(契约先行)
|
||||
|
||||
### 5.1 `game_aigc_task` 加 `level` 列 — Flyway DDL 草案
|
||||
|
||||
文件:`huijing-server/src/main/resources/db/migration/V15.0.0__aigc_task_add_level.sql`
|
||||
|
||||
```sql
|
||||
-- =============================================================================
|
||||
-- 契约 #2 DB 迁移 | 模块:aigc | W-G1 组A · D12 控制平面 v0
|
||||
-- 文件:V15.0.0__aigc_task_add_level.sql(Flyway 只新增;接 V14.0.0 之后,勿与 M4 撞号)
|
||||
-- 内容:game_aigc_task 加 level 列 —— per-creator×level 配额门的分档维度(L1/L2/L3 会员档)
|
||||
-- 默认值:1(= L1,存量任务回填 L1,与"白名单仅 A2"现状一致;档位数值由配置驱动,DDL 只承载维度)
|
||||
-- =============================================================================
|
||||
ALTER TABLE `game_aigc_task`
|
||||
ADD COLUMN `level` TINYINT NOT NULL DEFAULT 1
|
||||
COMMENT '创作者会员档位(配额分档维度):1=L1 2=L2 3=L3;存量回填 L1,档位额度数值见 aigc 控制平面配置'
|
||||
AFTER `creator_user_id`;
|
||||
|
||||
-- 配额计数走 (creator_user_id, level, status, create_time) 维度;现有 idx_creator_status 已覆盖
|
||||
-- (creator_user_id, status) 前缀,按日计数追加 create_time 范围条件即可(评估期若慢查再补复合索引,
|
||||
-- v0 量级小不预建——遵循"量大再独立表/索引"取舍,评审版 §4)。
|
||||
```
|
||||
|
||||
> **level 取值来源(需确认 · 附录 B3)**:submitGenerate 入参 `AigcGenerateReqVO` 当前无 level 字段(已核实)。v0 实现取值有两条路:(a) 从创作者身份/会员档查(最干净,但会员档数据模型未建);(b) 入队时**统一落 L1**(与"白名单仅 A2"现状一致,配额按 L1 档生效)。**建议 v0 走 (b) 落 L1 占位**,会员档真实化后再接 (a),避免为未建的会员体系造孤儿字段。**注**:level 列虽 v0 统一落 L1,但分档逻辑须 v0 即可用——§8 加"手塞 level=2 读 L2 档"单测覆盖(免会员档接入时才首跑,决策E)。
|
||||
|
||||
### 5.2 `safety.prompt-check` 调用契约(已就绪 · 本规格只接线)
|
||||
|
||||
输入:`{{input.prompt}}` = `task.getPrompt()`(创作者一句话)。
|
||||
输出(契约固定,已核实 `prompt-safety-check.md`:11-16):
|
||||
|
||||
```json
|
||||
{"safe": true | false, "reason": "<简短中文理由>"}
|
||||
```
|
||||
|
||||
接线消费(**服务层提交侧**):服务层独立 safety LLM 客户端渲染该 prompt → 调 new-api(短超时 8s + 1 重试)→ 解析 `safe`;
|
||||
- `safe==false` → 抛 `ServiceException(UNSAFE_PROMPT)`(同步拒绝、不入队)。
|
||||
- 超时/失败(1 重试后仍判不出)→ fail-closed,抛 `ServiceException(LLM_ERROR, 中性提示)`(决策C)。
|
||||
|
||||
**幂等**:safety 检查是只读判定、无副作用;同 prompt 重复检查结果一致(除模型抖动);拒绝在 insert 之前 = 任务根本未落库,无终态写入、无幂等风险。
|
||||
|
||||
### 5.3 配额/背压查询 — SQL 形状(走既有索引)
|
||||
|
||||
```text
|
||||
门① 配额计数(per-creator×level 当日非取消计数):
|
||||
SELECT COUNT(*) FROM game_aigc_task
|
||||
WHERE creator_user_id = ? AND level = ? AND deleted = 0
|
||||
AND status != 5 (canceled) -- 取消的不占配额
|
||||
AND create_time >= <当日 00:00>;
|
||||
→ >= 日配额上限 → 拒 AIGC_QUOTA_EXCEEDED。走 idx_creator_status 前缀 + create_time 过滤。
|
||||
|
||||
门① 并发上限(L1=1:该用户在飞任务数):
|
||||
SELECT COUNT(*) FROM game_aigc_task
|
||||
WHERE creator_user_id = ? AND deleted = 0
|
||||
AND status IN (0 queued, 1 running); -- 未终态 = 在飞
|
||||
→ >= level 并发上限(L1=1)→ 拒 AIGC_QUOTA_EXCEEDED(并发位满)。
|
||||
|
||||
门② 队列深度背压(全局在飞计数):
|
||||
SELECT COUNT(*) FROM game_aigc_task
|
||||
WHERE deleted = 0 AND status IN (0 queued, 1 running);
|
||||
→ >= 全局队列深度上限(queue-depth-limit)→ 拒 AIGC_BACKPRESSURE_REJECTED。走 idx_status_create。
|
||||
```
|
||||
|
||||
> **背压/配额判定一律用 `>= 上限`**(决策E / Codex P2):若用 `>` 则"等于上限"时仍放第 N+1 个,实际超额一位。配额、并发、背压三处统一 `>=`。
|
||||
> **MyBatis-Plus 实现**:用 `BaseMapperX` 的 `selectCount(LambdaQueryWrapperX)`,对齐 `AigcTaskMapper` 既有 default 方法风格(已核实),零原生 SQL、零 DDL 索引新增(v0)。
|
||||
|
||||
### 5.4 控制平面配置(配置驱动 · 数值占位)
|
||||
|
||||
绑定前缀建议 `aigc.control-plane`(与执行器 `aigc.executor` 平级,新建 `AigcControlPlaneProperties` 隔离职责):
|
||||
|
||||
```yaml
|
||||
aigc:
|
||||
control-plane:
|
||||
enabled: true # 控制平面总开关;false = 全门旁路(feature-flag 回滚,§10)
|
||||
queue-depth-limit: 50 # 门② 全局在飞上限(占位值,按 worker 串行吞吐定,需确认)
|
||||
safety:
|
||||
timeout-ms: 8000 # GP9 safety 短超时(决策B:非生成 90s×3)
|
||||
max-retry: 1 # GP9 safety 至多 1 次重试
|
||||
fail-closed: true # safety 判不出 → fail-closed 拒绝(中性 LLM_ERROR,决策C)
|
||||
quota: # 门① per-level 日配额 + 并发(数值占位·待创始人 §1.2)
|
||||
L1: { daily: 10, concurrency: 1 }
|
||||
L2: { daily: 50, concurrency: 2 }
|
||||
L3: { daily: 200, concurrency: 5 }
|
||||
# 降级开关不放此处静态配置,走 infra ConfigApi 热改(§6.1):键 aigc.generate.paused
|
||||
```
|
||||
|
||||
> **数值全为占位**(评审版定"会员档位数值待创始人")。本规格落"门结构 + 配置键 + 安全默认",**具体额度不在本规格拍板**。`enabled=false` 默认值的选择见 §10(开闸前置 true,但提交评审时默认 false 以零行为变更)。
|
||||
|
||||
### 5.5 新增错误码(aigc 段 001 子段)
|
||||
|
||||
`ErrorCodeConstants.java` 追加(不与 000/002/003 重叠):
|
||||
|
||||
```java
|
||||
// ========== 生成控制平面 1-101-001-***(W-G1 组A · D12 + GP9)==========
|
||||
/** 配额超限:per-creator×level 日配额或并发上限已满 */
|
||||
ErrorCode AIGC_QUOTA_EXCEEDED = new ErrorCode(1_101_001_001, "今日生成额度已用完或并发已满,请稍后再试");
|
||||
/** 背压拒绝:全局生成队列深度达上限(保护全局串行 worker) */
|
||||
ErrorCode AIGC_BACKPRESSURE_REJECTED = new ErrorCode(1_101_001_002, "生成排队过多,请稍后再试");
|
||||
/** 生成暂停:降级开关开启(new-api 故障等),暂停受理新生成 */
|
||||
ErrorCode AIGC_GENERATE_PAUSED = new ErrorCode(1_101_001_003, "生成服务繁忙维护中,请稍后再试");
|
||||
// 注:GP9 真违规复用 FailureReasonEnum.UNSAFE_PROMPT 业务码(提交侧同步拒绝);
|
||||
// safety 故障 fail-closed 复用 FailureReasonEnum.LLM_ERROR + 中性提示(决策C,禁单边扩展枚举)。
|
||||
```
|
||||
|
||||
> **口径**:`ServiceException` 经全局异常 handler 统一转 `CommonResult.error(业务码, msg)`,**不产生 HTTP 429/503**(决策E)。上列码均为业务码(HTTP 仍 200,body.code 非 0)。验收断言断业务码、非 HTTP 状态(§8)。
|
||||
|
||||
### 5.6 GP9 拒绝回包形状(提交侧同步拒绝)
|
||||
|
||||
GP9 在**服务层提交侧**阻断(入队前),故对用户的呈现 = `submitGenerate` 调用**当场同步报错**(非任务终态轮询):
|
||||
|
||||
```text
|
||||
真违规(safe=false):
|
||||
submitGenerate 抛 ServiceException(UNSAFE_PROMPT) → 全局 handler → CommonResult.error(unsafe_prompt 码,"Prompt 不安全")
|
||||
→ 任务未落库(不入队);前端当场提示用户改 prompt。
|
||||
|
||||
safety 故障 fail-closed(超时/失败,1 重试后仍判不出):
|
||||
submitGenerate 抛 ServiceException(LLM_ERROR,"安全检查暂不可用,请稍后重试") → CommonResult.error
|
||||
→ 任务未落库;前端提示"稍后重试",用户可重试(new-api 恢复后过门)。
|
||||
```
|
||||
|
||||
> **统一口径(决策C)**:真违规→UNSAFE_PROMPT;safety 故障→中性 LLM_ERROR(**不复用 UNSAFE_PROMPT、不新增枚举**),避免 new-api 抖动时正常用户被判"内容不安全"而流失。两态均为提交侧同步业务异常。
|
||||
|
||||
---
|
||||
|
||||
## ⑥ 关键实现步骤
|
||||
|
||||
### 6.1 D12 — 共享 `enqueueWithControlPlane` + 降级 + level 迁移
|
||||
|
||||
抽私有方法 `enqueueWithControlPlane(AigcTaskDO task, int level)`,**`submitGenerate` 与 `retryTask` 都调它**(决策D:retry 也重跑 safety+配额,违规/超配额请求无法靠 retry 绕开)。门序固定(最便宜→最贵):
|
||||
|
||||
1. **降级门**(最先,无 LLM):读降级开关 → 暂停中抛 `AIGC_GENERATE_PAUSED`。
|
||||
2. **配额门①**(纯计数):查 §5.3 日配额计数 + 并发计数 → 任一 `>= aigc.control-plane.quota.{level}` 上限 → 抛 `AIGC_QUOTA_EXCEEDED`。
|
||||
3. **背压门②**(纯计数):查 §5.3 全局在飞计数 `>= queue-depth-limit` → 抛 `AIGC_BACKPRESSURE_REJECTED`。
|
||||
4. **GP9 safety**(LLM,最贵,放最后):调服务层独立 safety 客户端(§6.2)→ `safe=false` 抛 `UNSAFE_PROMPT`;超时/失败抛中性 `LLM_ERROR`(fail-closed)。**放最后**=超配额/超背压必被拒的请求不付 safety;违规请求付一次 safety 但在 insert 前被拒(不入队、不占配额)。
|
||||
5. **insert**:四门全过 → 既有落库(`aigcTaskMapper.insert`)+ 落 `level`(v0=L1,§5.1)+ **额度记账骨架**(仅 log/占位字段,非真扣费——记账=记录"本次拟扣额度"于日志/可选字段,真扣退随 M4)。
|
||||
|
||||
接线收口:
|
||||
- `submitGenerate`:68——把现有 :69-89 的「校验→insert」改为「既有校验 → 组装 task → `enqueueWithControlPlane(task, level)`」。
|
||||
- `retryTask`:122——把 :135-140 的「组装 retry → 直 insert」改为「组装 retry → `enqueueWithControlPlane(retry, level)`」(retry 重跑全门,正确)。
|
||||
- **Flyway V15.0.0**:按 §5.1 DDL 加 `level` 列;`AigcTaskDO` 加 `level` 字段。
|
||||
|
||||
**降级开关载体 = infra `ConfigApi`(决策E)**:
|
||||
- aigc-server **现无 `huijing-module-infra-api` 依赖**(仅 `huijing-module-system-api`:87,已核实)→ **须先在 `game-module-aigc-server/pom.xml` 加 `huijing-module-infra-api` 依赖**,否则注入 `ConfigApi` 编译失败。
|
||||
- 配置 key 种子:`aigc.generate.paused`(infra `infra_config` 表,admin 后台可改、热生效、无需重启,契合"new-api 故障→暂停入队"运维诉求)。
|
||||
- 缺省语义:`getConfigValueByKey("aigc.generate.paused")` 读不到 / 非 "true" = **视为未暂停**(fail-open on switch read,避免配置中心抖动→全站停服)。
|
||||
|
||||
### 6.2 GP9 — 10 负例 + 服务层独立 safety 客户端接线
|
||||
|
||||
1. **建负例集** `contracts/prompts/eval/safety.prompt-check/`(格式照既有 eval 套件,已核实 `config.clicker-designer/` 结构):
|
||||
- `inputs.jsonl`:10 行,每行 `{"evalKey":"safety:neg:N","prompt":"<违规 prompt>","category":"<类目>"}`,覆盖红线类目:**政治敏感 / 色情低俗 / 暴恐血腥 / 侵权仿冒 / 赌博诈骗 / 毒品 / 未成年人不适宜 / 注入攻击("忽略上述规则"类)/ 自我伤害 / 违法交易**(10 条各 1 类,确保类目覆盖广而非同质)。
|
||||
- `labels.jsonl`:10 行,每行 `{"evalKey":"safety:neg:N","expectedSafe":false,"category":"<同上>"}`(全部 `expectedSafe:false` = 负例,门禁断言 100% 判 unsafe)。
|
||||
- `README.md`:照既有 eval README 范式写来源/格式/变更纪律(改 prompt 须升 version 过四道闸)。
|
||||
2. **扩 copy-glob**:**`game-module-aigc-server/pom.xml`**:172 区块加 `<include>prompts/01-safety/*.md</include>`(使 safety prompt 进 `classpath:wanxiang-contracts/`;resources plugin 在 server 模块,决策E)。
|
||||
3. **新建服务层独立 safety LLM 客户端**(`game-module-aigc-server/.../service/task/` 下):
|
||||
- **不复用** 执行器 `ExecutorLlmClient`/`PromptResourceLoader`(被 `aigc.executor.enabled` 门控、服务层注入不到,已核实)。
|
||||
- 自装载 `wanxiang-contracts/prompts/01-safety/prompt-safety-check.md`(safety 无模板 schema,渲染只需 `{{input.prompt}}` 单变量)。
|
||||
- OpenAI 兼容调 new-api,**短超时 8s + 至多 1 次重试**(§5.4 配置);成本单独记日志(§4.3)。
|
||||
- 装配建议随 `aigc.control-plane.enabled` 总开关(关 = GP9 旁路,§10),不被执行器开关连带。
|
||||
4. **接线 `submitGenerate` 提交侧**(经 `enqueueWithControlPlane` 门序 ④,§6.1):
|
||||
- 渲染 safety prompt(`prompt`=task.getPrompt())→ 调服务层 safety 客户端 → 解析 `safe`。
|
||||
- `safe==false` → 抛 `ServiceException(UNSAFE_PROMPT)`(同步拒绝、不入队)。
|
||||
- 超时/失败(1 重试后仍判不出) → fail-closed,抛 `ServiceException(LLM_ERROR, "安全检查暂不可用,请稍后重试")`(§5.6 / §7)。
|
||||
- `safe==true` → 继续 §6.1 步骤 5 insert。
|
||||
|
||||
> **复用既有枚举、不改 `FailureReasonEnum`**:`UNSAFE_PROMPT`:18 / `LLM_ERROR`:22 已声明,注释:10 明文"不可单边扩展(跨契约共享枚举)"(已核实)。GP9 只是让 UNSAFE_PROMPT 从"执行器终态占位"变为"提交侧同步拒绝业务码",并复用 LLM_ERROR 承载 fail-closed 中性态——零枚举改动。
|
||||
|
||||
---
|
||||
|
||||
## ⑦ 边界失败路径(逐条交代幂等/超时/失败/补偿)
|
||||
|
||||
| 失败场景 | 处置 | 幂等/补偿 |
|
||||
|---|---|---|
|
||||
| **配额超限**(门①) | 抛 `AIGC_QUOTA_EXCEEDED`(业务码),消息含"今日额度已满/并发已满"。前端展示排队位 = 当前在飞数 / 上限 | 纯读判定,无副作用;用户重试仍被挡,幂等 |
|
||||
| **背压拒绝**(门②) | 抛 `AIGC_BACKPRESSURE_REJECTED`(业务码)。建议前端"稍后重试",不自动重试(防雪崩) | 同上,纯读 |
|
||||
| **真违规**(GP9 safety `safe=false`) | 抛 `UNSAFE_PROMPT` 业务异常,**同步拒绝、不入队、0 生成成本**。提交侧当场报错(非任务终态) | 拒绝在 insert 前 = 任务未落库,无终态写入、无补偿需求 |
|
||||
| **safety 服务超时/失败**(GP9 LLM 挂) | **fail-closed 中性拒绝**(决策C):短超时 8s + **至多 1 次重试** 后仍判不出 → 抛 `LLM_ERROR` + 中性提示"安全检查暂不可用,请稍后重试"(**不复用 UNSAFE_PROMPT、不新增枚举**),同步拒绝、不入队。**理由**:合规是法务红线,"判不出就放过"会让违规在 safety 不可用窗口直入生成与 feed,风险不可逆;用中性提示避免 new-api 抖动时正常用户被误标"内容不安全"而流失。**大面积故障兜底**:降级开关(§6.1)可整体暂停入队,避免逐条 fail-closed 刷错误 | 提交侧同步拒绝、任务未落库;用户可直接重试(new-api 恢复后过门)= 天然补偿,无额外补偿逻辑 |
|
||||
| **并发 race:两请求同时过配额门**(门①查时都未超,落库后双超) | v0 **承认软超**:配额门是"读计数→判→落库"非原子,高并发下可能略微超额(如 L1 并发=1 时两请求同瞬到、都读到 0 在飞、都入队 = 实际 2 在飞)。**v0 容忍**(量级小、超额有限);**严格化留待后续(附录 B6)**:可加 (creator_user_id, level) 维度唯一/乐观锁或 Redis 原子计数,但 v0 不引入(避免为边际场景上分布式锁,对齐评审"量大再独立表"取舍)。**真理由(决策E,删错误的"CAS 硬保证"背书)**:全局只有**单作业串行 worker**(`AigcGenerateExecutor` `@Scheduled` fixedDelay 进程单飞,:171/:47 已核实)兜吞吐——同一时刻至多一任务在跑,故"实际多入队几个 queued"只是排队多、压不垮 worker。**per-creator 并发=1 是软限**(配额门唯一实现、**无 CAS 兜底**——CAS 认领只保证"同一任务不被双实例认领",不保证"同一 creator 不超并发")。开闸期 creator 少,软超有限、可接受 | 软超可接受;单作业串行 worker 保证不会真把全局压垮,CAS 保证同一任务不双跑 |
|
||||
| **降级开关读取失败**(infra config 不可达) | fail-open on switch:读不到开关值 = 视为未暂停(正常受理),避免"配置中心抖动→全站停止生成" | 无副作用 |
|
||||
| **level 列迁移失败**(V15.0.0 执行错) | Flyway 失败即 app 启动失败(既有 Flyway 行为);回滚写新补偿迁移(不改 V15.0.0,遵 V2.0.0 头注铁律) | DDL 幂等由 Flyway 版本表保证 |
|
||||
| **取消信号在途 worker**(用户在生成中途取消) | 复用执行器既有语义(已核实):`cancelTask` 置 status=5;CAS 认领 `claimQueuedTask` 仅 status=0 可认领,已取消任务认领落空跳过;回调链终态拒重入丢弃在途结果 | 既有幂等,本规格零改 |
|
||||
|
||||
> **safety 成本(Codex P1-3)**:GP9 safety 每次提交付一次便宜模型调用,**成本单独配置/记日志**(§4.3 / §5.4),**不混入 worker 的 ¥0.15 生成预算**——避免把"提交侧合规成本"错算进"单款生成成本"台账。
|
||||
|
||||
---
|
||||
|
||||
## ⑧ 验证方法(对齐评审 §6,每门一条自动化用例)
|
||||
|
||||
| 门 | 自动化用例(断言) | 层级 |
|
||||
|---|---|---|
|
||||
| **D12 门①配额** | 同 creator 当日提交达 L1 日配额上限 → 下一次 `submitGenerate` 抛 `AIGC_QUOTA_EXCEEDED`(断**业务码 `1_101_001_001`**,非 HTTP 429);另一 creator 不受影响 | service 单测(mock mapper 计数)|
|
||||
| **D12 门①并发** | L1 并发=1:该 creator 有 1 个在飞(status∈{0,1})时再提交 → 抛 `AIGC_QUOTA_EXCEEDED`(并发位满);该任务终态后可再提交 | service 单测 |
|
||||
| **D12 门②背压** | 全局在飞数 **达** `queue-depth-limit`(`>=`,断"等于上限即拒")→ `submitGenerate` 抛 `AIGC_BACKPRESSURE_REJECTED`(断业务码 `1_101_001_002`) | service 单测 |
|
||||
| **D12 降级** | 降级开关 `aigc.generate.paused=true` → `submitGenerate` 抛 `AIGC_GENERATE_PAUSED`(业务码 `1_101_001_003`);置回恢复 | service 单测(mock ConfigApi)|
|
||||
| **D12 level 分档** | **手动塞 `level=2` → 读 L2 配额档生效**(L2 daily/concurrency 与 L1 不同,断分档逻辑 v0 即可用,非会员档接入才首跑,决策E) | service 单测 |
|
||||
| **D12 retry 走控制平面** | `retryTask` 在配额已满 / 降级开启 / 违规 prompt 下 → **同样被拒**(断 retry 不绕过控制平面,决策D) | service 单测 |
|
||||
| **GP9 负例 100%** | 10 条负例逐条经 safety 判定 → 100% `safe=false` → `submitGenerate` 100% 抛 `UNSAFE_PROMPT`、**0 条落库入队**(断 insert 未被调用 / 不派发 worker) | service 单测(mock safety 客户端返回 safe=false)+ 可选 staging 真 LLM 抽测 |
|
||||
| **GP9 fail-closed 中性** | safety LLM 抛超时(mock)→ 1 重试后仍失败 → `submitGenerate` 抛 **`LLM_ERROR`(中性提示)**、不入队(断**不复用 UNSAFE_PROMPT**、不新增枚举,决策C) | service 单测 |
|
||||
|
||||
> **断言口径(决策E)**:所有验收断言断 `ServiceException` 的**业务码 `1_101_001_*`**(经全局 handler 转 `CommonResult.error`,HTTP 仍 200),**不断 HTTP 429/503**。
|
||||
> **GP9 负例 100% 阻断的"真判定"建议**:单测 mock safety 客户端返回固定 `safe=false` 验**接线正确**(safe=false→抛 UNSAFE_PROMPT);另在 staging 用真 new-api 跑 10 负例验**模型真能判违规**(防 prompt 本身判不准)——两层分开,前者门禁必跑、后者上线前抽验。
|
||||
|
||||
---
|
||||
|
||||
## ⑨ 完成条件
|
||||
|
||||
1. **D12**:抽 `enqueueWithControlPlane`,`submitGenerate` + `retryTask` 同走;降级门 + 配额并发门 + 背压门接入;V15.0.0 `level` 迁移落库、`AigcTaskDO` 加字段;aigc-server 补 `huijing-module-infra-api` 依赖;新增 001 段 3 个错误码;控制平面配置键就位(数值占位);§8 D12 六条用例绿(含 level 分档、retry 走控制平面)。
|
||||
2. **GP9**:`safety.prompt-check` 10 负例集落 `contracts/prompts/eval/safety.prompt-check/`;**`game-module-aigc-server/pom.xml`** copy-glob 扩 01-safety;新建服务层独立 safety 客户端(短超时 8s + 1 重试);`submitGenerate` 提交侧接 safety → `safe=false` 抛 `UNSAFE_PROMPT`、故障 fail-closed 抛中性 `LLM_ERROR`;§8 两条 GP9 用例绿(含 10 负例 100% 阻断、fail-closed 中性)。
|
||||
3. **编译/构建**:`game-module-aigc` 编译通过;`huijing-server` Flyway 迁移在 staging 隔离库执行通过(去 mini-desktop 验,对齐 memory `m1-runtime-bringup-state`)。
|
||||
4. **零越界**:§1.2 五非范围项均未实现;**门③(promptHash 缓存命中复用)未做**;非范围的回调写链、组B 落库、审核台、会员档数值均未触碰。
|
||||
5. **行为回滚验证**:`aigc.control-plane.enabled=false`(或开关关)时 `submitGenerate`/`retryTask` 行为**与现行逐字一致**(全门旁路、GP9 旁路),单测断言。
|
||||
|
||||
---
|
||||
|
||||
## ⑩ 回滚策略(feature-flag 默认关 = 现行逐字不变)
|
||||
|
||||
- **D12 + GP9 回滚 = `aigc.control-plane.enabled=false`**(或控制平面 Bean `@ConditionalOnProperty` 关):全门 + GP9 旁路,`enqueueWithControlPlane` 退化为"仅既有校验→insert"的现行行为(`submitGenerate`/`retryTask` 逐字不变)。**提交评审时该开关默认 false**(零行为变更进主干),开闸前由创始人显式置 true(对齐评审版"前置门 feature-flag 默认关 = 现行行为不变",§5)。
|
||||
- **GP9 旁路**:safety 客户端随 `aigc.control-plane.enabled` 装配;关闭 = 跳过 safety(现行行为)。负例集 / pom glob / safety 客户端装载均为 additive,不开关也不影响存量。
|
||||
- **level 列**:additive 列、`DEFAULT 1`,存量行自动回填 L1,不读不影响;真要回滚写 V16 补偿迁移 drop(不改 V15.0.0)。
|
||||
- **infra-api 依赖**:additive 依赖,不影响现有编译/运行(仅为 `ConfigApi` 注入)。
|
||||
- **错误码**:新增 001 段,与现有段无重叠,纯 additive。
|
||||
|
||||
---
|
||||
|
||||
## 附:核实清单 + 两轮评审处置
|
||||
|
||||
### A. 已核实 file:line(亲读确认)
|
||||
|
||||
- `submitGenerate`:68、入队前无前置门:69-76、insert:89、`retryTask`:122 **直 insert**:140(决策D 共享入队的改造点)、promptHash 落库:85、`sha256`:238、`cancelTask`:105 —— `AigcTaskServiceImpl.java`(**路径 `game-module-aigc-server`,非底稿提示的 `-biz`**)。
|
||||
- 执行器现成件:`@Scheduled` fixedDelay 进程单飞:171/:47、CAS 认领 `claimQueuedTask`:327、watchdog 收尸、job `budget={maxYuan:0.15,maxLlmCalls:8}`、预检段 `runGenerationPipeline`:354、`callbackFailed`:588 —— `AigcGenerateExecutor.java`(核实)。**注**:全局并发兜底 = 单作业串行 worker(fixedDelay 单飞),**非 Semaphore;CAS 只保证同一任务不双认领,不保证 per-creator 并发**(决策E 真理由依据)。
|
||||
- `FailureReasonEnum.UNSAFE_PROMPT`:18 / `LLM_ERROR`:22,注释:10 明文"**取值与 Dify output.failureReason 严格一致,不可单边扩展(跨契约共享枚举)**"(核实)→ 决策C 复用既有枚举的硬依据。
|
||||
- LLM 通道 `ExecutorLlmClient`:35「不标 @Component,只经 @Bean 注册」+ `AigcExecutorConfiguration`:45 `@ConditionalOnProperty(prefix="aigc.executor",name="enabled",havingValue="true")`(核实)→ **服务层注入不到执行器 LLM 通道**,决策B 须服务层另起独立客户端的硬依据。
|
||||
- `game-module-aigc-server/pom.xml`:152 maven-resources-plugin、:172-175 copy-glob 仅 `04-config/*.md`+`templates/*.schema.json`(核实,**resources plugin 在 server 模块、非 parent `game-module-aigc/pom.xml`**)→ 决策E pom 路径修正依据;01-safety 未进 classpath。
|
||||
- aigc-server pom 仅 `huijing-module-system-api`:87、**无 `huijing-module-infra-api`**(核实)→ 决策E 补依赖依据。
|
||||
- `game_aigc_task` 全列:status 0-5 含 canceled、retry_of、finish_time、trace_id、prompt_hash、**无 level 列**(核实 V2.0.0)。
|
||||
- Flyway 现有最大 = **V14.0.0**(M4)→ level 迁移定 **V15.0.0**(核实,不撞号)。
|
||||
- safety 契约 `{safe,reason}`:11-16、registry 声明 `eval:`(核实);**eval/safety.prompt-check/ 目录不存在**(核实)。
|
||||
- 两臂共用单入口:App controller + `AigcApi.submitGenerate`→service(核实)。
|
||||
|
||||
### B. 两轮评审(Codex 可行性 + opus 前提)处置结论
|
||||
|
||||
| # | 评审存疑 | 处置(主代理定盘) |
|
||||
|---|---|---|
|
||||
| B1 | GP9 接线点(执行器 vs 提交侧) | **safety 前置到 `submitGenerate` 提交侧、入队前**(决策B)——满足"违规不入队"、避开 opus P0-3(执行器内 safety 卡串行 tick = DoS);服务层独立 LLM 客户端 + 短超时 8s + 1 重试。 |
|
||||
| B2 | safety 失败 fail-closed vs fail-open | **fail-closed 中性**(决策C)——真违规→`UNSAFE_PROMPT`;超时/失败→复用既有 `LLM_ERROR` + 中性提示"安全检查暂不可用,请稍后重试"(不新增枚举、不误标用户违规)。 |
|
||||
| B3 | level 取值来源 | **level 列保留**,v0 统一落 L1 占位(会员档未建,避孤儿);**§8 加"手塞 level=2 读 L2 档"单测**,给分档逻辑 v0 覆盖(决策E)。 |
|
||||
| B4 | 降级开关载体 | **infra `ConfigApi`**(admin 热改、无需重启,fail-open on read)——但 **aigc-server 须先补 `huijing-module-infra-api` 依赖**(否则注入编译失败,决策E),键 `aigc.generate.paused`,读不到=不暂停。 |
|
||||
| B5 | 门③ promptHash 命中复用 | **随门③砍而 moot**(决策A)——v0 不做全局去重缓存(跨用户归属/产物状态查询/sha256 口径需专门设计,孤儿+隐私+白嫖风险);防刷由配额门兜(同 prompt 重复也吃配额)。promptHash 仍照算照落 provenance,v0 只是不读它做缓存。 |
|
||||
| B6 | 并发 race 软超是否可接受 | **删"CAS 认领层有硬保证"错误背书,改真理由**(决策E)——全局单作业串行 worker(fixedDelay 单飞)兜吞吐;per-creator 并发=1 是软限(配额门唯一实现、无 CAS 兜底);开闸期 creator 少、软超有限、v0 可接受。 |
|
||||
| B7 | 配额/背压数值 | **数值占位**(评审版已定"待创始人",非存疑)——本规格只落门结构 + 配置键 + 安全默认,具体额度不在本规格拍板。 |
|
||||
| B8 | `enabled` 默认值 | **采纳默认 false**——提交评审默认 false(零行为变更进主干),开闸前创始人显式置 true。 |
|
||||
|
||||
> **新增评审项落地**:retry 绕过控制平面(Codex P0-2)→ 决策D 抽 `enqueueWithControlPlane` 共享方法;背压 `>` vs `>=`(Codex P2)→ 决策E 统一 `>=`;safety 成本混入 worker 预算(Codex P1-3)→ 决策E safety 成本单独配置/记日志;验收断 HTTP 429/503(口径雷)→ 决策E 改断业务码 `1_101_001_*`。
|
||||
Loading…
x
Reference in New Issue
Block a user