基于产品/架构/流程/前端/后端五维度并行review,澄清并落地22项关键决策: 架构层:Governance按消费者归属拆散、MetaSchema独立模块、 Source传播改为事件驱动自治、去掉Candidate Decision Envelope 和needs_recheck中间状态、Neo4j决策为依赖RAGFlow GraphRAG 后端层:Entitlement统一为可变表+审计日志、API版本策略采用 X-API-Version Header、知识实体唯一键加scope字段 前端层:SSE实时通信(AI stream独立+事件统一)、正文持久化 IndexedDB安全网、Block粒度为场景/小节级 产品层:范围不变UX解决复杂度、知识确认默认自动+冲突时人工
18 KiB
专题-01:正文建议接受(Accept Suggestion)实现规范
- 版本:v5
- 更新日期:2026-05-23
- 目标读者:产品 / 架构 / 前端 / 后端 / 测试
- 阅读时间:20–35 分钟
- 边界说明:本文档只收束“接受建议”这条跨文档主链路:用户怎么把 AI 候选写入正文、关联知识草稿怎么保留或失效、正文来源归因怎么落点、事务边界怎么切、前端怎么反馈。精确 Schema、状态机和统一错误模型由后续后端阶段承接;当前阶段以
架构-02和架构-04为准。
1. 目标与范围
Accept Suggestion 是 AI 候选从待审层(Shadow)进入正文规范数据(Canonical)的唯一合法入口。
这个能力要同时解决四件事:
- 把候选文本安全写入目标 Block。
- 写入候选归档和必要的正文来源归因(Block Source Attribution)。
- 保持“接受正文”和“确认知识”两条用户决策分离,接受候选不写 Local KB。
- 在修改后合并时,让基于旧候选文本的知识草稿失效,并基于最终正文启动重新提取链路。
- 把正文、知识、历史与投影边界切干净,避免“看起来成功,其实系统已经脏了”。
1.1 In Scope
- 接受建议(原样接受、修改后合并)
- 拒绝建议
- 关联知识草稿的保留 / 失效语义
- 正文来源归因与授权快照落点
- 前端正文乐观更新、回滚与冲突处理
- 审计、归档、outbox 写入与最终一致刷新
1.2 Out of Scope
- 建议生成本身
- 知识提取算法本身
- 全书解析的章节批量确认
- 一致性检查面板本身
- AST 级精细 diff
2. 统一语义(先把话说死)
2.1 三条用户结果路径
| 路径 | 正文结果 | 知识草稿结果 | 历史结果 |
|---|---|---|---|
| 原样接受 | Suggestion 内容进入目标 Block | 与当前 Suggestion 绑定的草稿保持待确认;不得自动入 Local KB | Suggestion 归档为 accepted |
| 修改后合并 | contentOverride 进入目标 Block |
旧草稿立即失效;AFTER_COMMIT 重新提取新的草稿 | Suggestion 归档为 accepted,并保留 final_content 快照(如需要) |
| 拒绝 | 正文不变 | 关联草稿一起丢弃 | Suggestion 归档为 rejected |
2.2 为什么“修改后合并”不是新状态
- 用户决策仍然是“接受这条建议,只是我改了最终入正文的文本”。
- 它不应该发明新的 Active 状态,也不应该生成第二套历史状态机。
- 归档层统一记为
accepted,但必须保留“这是 modified merge”的审计语义。
2.3 Stale Draft 规则
只要源文本发生变化,旧知识草稿就必须被视为 stale:
- 不能继续确认旧草稿。
- 不能把旧草稿偷偷并入正式知识。
- 必须重新走提取 -> 校验 -> 风险分级链路,生成新的草稿。
即使源文本没有变化,接受候选也不等于确认知识草稿。知识草稿进入 Local KB 的唯一入口仍是用户在知识确认入口显式确认。正文保存可以触发后续提取、校验和知识治理流程,但不能直接写 Local KB。
3. 相关 SSOT
- 双轨模型:
架构-02-核心数据结构与双轨模型.md - 状态机与端点前后置条件:
架构-04-状态机与约束清单.md - 普通用户系统链路:
流程-02B-普通用户系统处理流程(系统视角).md - 普通用户操作链路:
流程-01B-普通用户操作流程(操作视角).md
本文档只做一件事:把这些分散约束收束成一条可落地的 Accept 链路。
4. 核心不变式
4.1 正文与建议
- Block 正文是正式正文的唯一真相。
- Block revision 是写入锚点。
- AI Suggestion 只保存待审对象;进入终态后必须进入候选归档。
- 如果候选使用了 AI、市场资产、外部知识或授权知识来源,写入正文 revision 时必须同步写正文来源归因(Block Source Attribution),保留来源链路、授权快照、许可限制和召回状态。
4.2 关联知识草稿
- 生成场景下的知识草稿可以关联到 AI Suggestion,但它仍是独立待审对象。
- 原样接受时,关联知识草稿保持待确认,不得自动写入 Local KB。
- 修改后合并时,基于旧候选文本的知识草稿统一失效,不允许继续沿用。
- 知识草稿确认必须另走知识确认入口,且必须重新校验来源状态、授权快照、source hash、目标版本和风险标记。
4.3 事务边界
- Accept 主事务内不得发起外部 AI / 提取 / 校验调用。
- 原样接受时,正文写入、候选归档、正文来源归因、关联草稿状态保留、change log、outbox 写入必须放在同一事务里完成。
- 修改后合并时,正文写入、Suggestion 归档、旧草稿失效与审计仍在主事务;重新提取只能走 AFTER_COMMIT 异步链路。
4.4 历史与投影
- Accept / Reject 后,Active 区不能再看到这条 Suggestion。
- 接受候选写入正文后,可以触发投影或重新提取 outbox;但投影和提取失败不得反向回滚正文。
- 投影失败不能反向打断已经成功的 Accept 主事务。
5. 决策命令语义合同
本节只定义产品层面的命令合同,不定义后端 endpoint、请求 JSON 或数据库字段。后续后端阶段可以按此语义设计 API,但不得改变这里的用户决策、幂等、来源和知识草稿边界。
5.1 Accept 命令
Accept 命令必须携带以下语义:
| 语义 | 要求 |
|---|---|
| commandId / idempotencyKey | 同一 actor、suggestion、command 和目标 revision 的重复提交必须返回同一结果,不得重复写正文、归档或 outbox |
| actor / work / targetBlock | 当前用户、作品和目标 Block |
| suggestion | 仍处于 Active / Shadow 的候选 |
| expectedRevision | 用户决策基于的目标 Block revision,必填 |
| acceptMode | accept_as_is 或 merge_after_edit |
| finalContent | 仅 merge_after_edit 需要,表示用户确认写入正文的最终内容 |
| decisionContext | UI 决策来源、候选版本、质量结果版本和必要审计摘要 |
| acceptPreconditionContext | 接受前置校验上下文,必须覆盖输出合规、静态检查、质量结果版本、来源状态、来源事件影响、Action Policy、授权快照、作品资产 feature gate、expectedRevision 和幂等结果;系统在接受时实时校验,不封装为独立对象 |
命令结果至少返回以下语义:
| 语义 | 原样接受 | 修改后合并 |
|---|---|---|
| blockOutcome | 目标 Block 写入成功,revision 递增 | 目标 Block 写入用户最终内容,revision 递增 |
| suggestionOutcome | Suggestion 离开 Active,进入 Archive,disposition=accepted | Suggestion 离开 Active,进入 Archive,disposition=accepted,并记录 modified merge 摘要 |
| knowledgeDraftOutcome | 关联草稿保持待确认,仍需单独进入知识确认入口 | 基于旧候选文本的草稿失效,不允许继续确认 |
| followupTask | 可触发投影刷新,不要求即时返回草稿数量 | AFTER_COMMIT 启动重新提取或投影刷新任务 |
5.2 Reject 命令
Reject 只做三件事:
- 迁出 Suggestion
- 丢弃关联草稿
- 写历史 / 审计
Reject 不得修改正文,不得触发新的提取。
5.3 幂等与重复提交
同一命令重复到达时:
- 已成功接受的命令必须返回同一 Block revision、Archive 结果和 followupTask 摘要。
- 已失败且可重试的命令必须说明失败原因和当前可恢复动作。
- 已失败且不可重试的命令不得创建新的正文 revision。
- 同一幂等键携带不同 actor、work、targetBlock、suggestion、
expectedRevision、授权快照或接受前置校验输入时,必须返回幂等冲突,不得复用旧结果。 - Archive、change log、audit log 和 outbox 必须能通过命令幂等语义去重。
6. 接受前置条件
Accept 在任何写正文动作前必须完成前置校验。前置校验失败时,候选不能被接受,正文不能写入。
服务端必须在接受时实时校验候选来源版本和授权状态;如果校验缺失、过期、质量结果版本不匹配、expectedRevision 不匹配、授权快照变化、来源状态变化、作品资产 feature gate 变化或幂等结果不可复用,必须在写正文前重算。重算结果不是提示文案,而是写 Canonical 的硬闸门。
| 校验 | 失败结果 |
|---|---|
| actor 对作品、Block、Suggestion 有操作权限 | PERMISSION_DENIED,不写正文 |
| Suggestion 仍处于 Active / Shadow,未过期、未失效 | SUGGESTION_NOT_ACCEPTABLE,不写正文 |
| expectedRevision 匹配目标 Block 当前 revision | REVISION_CONFLICT,进入显式冲突处理 |
| 接受前置校验通过(实时校验来源版本和授权状态),且覆盖输出合规、静态检查、质量结果版本、来源状态、授权快照、作品资产 feature gate、expectedRevision 和幂等结果 | 按校验结果阻断、需重验或要求显式确认 |
| 输出合规、语义安全围栏和静态检查通过 | OUTPUT_COMPLIANCE_BLOCKED 或 STATIC_CHECK_FAILED,不写正文 |
| 候选正文 lineage 中所有来源有有效 Authorization Snapshot | SOURCE_AUTH_INVALID,候选 invalidated / blocked |
| 候选正文 lineage 不含 revoked / recalled / delisted / blocked / owner_missing / unauthorized 来源 | SOURCE_BLOCKED,候选 invalidated / blocked |
候选使用市场作品资产时,存在有效 workAssetUsePrecheckId、owner 预检、授权快照、lineage 和 feature gate |
SOURCE_FEATURE_DISABLED 或 OWNER_PRECHECK_REQUIRED,候选不可接受 |
只有与正文无关的关联知识草稿出现 stale、需重验或不可确认时,才允许“正文接受成功、草稿需单独处理”。一旦问题来源参与了候选正文 lineage,就必须阻断正文写入,不能只把 Knowledge Draft 标记为不可确认。
7. 后端实现规范
7.1 原样接受事务
单个事务内完成:
- 加载 Active Suggestion 并校验归属、状态与过期时间。
- 加载目标 Block,并用
expectedRevision做并发保护。 - 实时校验候选来源版本和授权状态(校验清单:候选来源、授权快照、市场作品资产 feature gate、质量门控、输出合规、静态检查、质量结果版本、幂等结果和当前 Block revision)。
- 更新 Block 内容与 revision。
- 如果候选包含 AI、市场、外部知识或授权知识来源,写 Block Source Attribution。
- 将 Suggestion 迁入候选归档(disposition=accepted)。
- 保持关联知识草稿为待确认;仅当问题来源没有参与正文 lineage 时,才允许把草稿标记为不可确认或需重验。
- 写 change log / audit log。
- 写投影或后续提取 outbox。
任何一步失败,整笔事务回滚。
7.2 修改后合并事务
单个事务内完成:
- 加载 Active Suggestion 并校验归属、状态与过期时间。
- 加载目标 Block,并用
expectedRevision做并发保护。 - 实时校验候选来源版本和授权状态(校验清单:候选来源、授权快照、市场作品资产 feature gate、质量门控、输出合规、静态检查、质量结果版本、幂等结果和最终正文内容)。
- 用
contentOverride更新 Block 内容与 revision。 - 默认继承上游候选的 lineage、授权快照、许可限制、召回状态和风险标记,并写 Block Source Attribution。
- 将 Suggestion 迁入候选归档(disposition=accepted),必要时记录
final_content。 - 将旧知识草稿标记为失效,不允许继续确认。
- 写 change log / audit log,标记这是 modified merge。
- AFTER_COMMIT 发布重新提取事件或创建异步任务记录。
这里的关键不是任务名字,而是语义:重新提取只能发生在提交之后,不能把外部调用塞进正文主事务。
如果用户改写后的最终正文确实不再依赖某些授权来源,系统也不能只靠文本差异自动洗白。只有在单独的来源归因证明、原创性确认或人工决策记录成立时,才允许降低对应限制;该过程必须审计,并且不得让 revoked / recalled / delisted / blocked / owner_missing / unauthorized 来源通过改写绕过。
7.3 Reject 事务
单个事务内完成:
- 加载 Active Suggestion。
- 校验归属与状态。
- 迁入
suggestion_archive(disposition=rejected)。 - 丢弃关联知识草稿。
- 写
audit_log。
Reject 不得更新 Block,不得创建重新提取链路。
7.4 失败矩阵
| 失败类型 | 正文结果 | 用户可见恢复动作 |
|---|---|---|
| 无权限或作品不可访问 | 不写入 | 返回作品或权限提示 |
| Suggestion 已过期、已归档或已失效 | 不写入 | 重新生成或关闭候选 |
| 来源 revoked / recalled / delisted / blocked / owner_missing / unauthorized | 不写入,候选 invalidated / blocked | 查看来源摘要、重新生成 |
| 市场作品资产 feature gate 关闭 | 不写入 | 仅允许阅读、收藏或授权记录,不允许作为 AI 上下文 |
| owner 预检或 workAssetUsePrecheck 缺失 | 不写入 | 回到作品资产使用预检 |
| 质量门控 blocked 或 needs_recheck | 不写入 | 重验、重生成或修改后重新评估 |
| 输出合规或静态检查失败 | 不写入 | 修改输入或重新生成 |
| revision 冲突 | 不写入 | 基于最新 revision 重试或放弃 |
| 重复命令 | 不重复写入 | 返回既有结果 |
8. 前端实现规范
8.1 状态拥有
- 正文 Block:服务端 Block revision 是唯一真相;前端可以乐观展示,但必须能按服务端结果确认或回滚。
- Active Suggestion:待审区状态持有。
- 关联知识草稿提示与角标:以最终一致方式刷新,不把瞬时数字当真相。
8.2 Accept 成功反馈
- 原样接受:
已合并,关联知识草稿仍待确认 - 修改后合并:
已合并,旧知识草稿已失效,正在重新提取
禁止反馈:
- “已合并,发现 N 条草稿待审核”
- “已合并,草稿已经进入正式知识”
- “已合并,请稍后看系统是否成功”
8.3 冲突处理
当服务端返回 409 REVISION_CONFLICT:
- 停止当前乐观链路。
- 如果本地没有后续编辑,回滚到上一个稳定状态。
- 如果本地已经继续编辑,进入显式冲突处理态,禁止静默覆盖。
- 给用户清晰的下一步:放弃本次合并,或基于新 revision 重试。
8.4 成功后的刷新策略
- 成功后移除当前 Suggestion 卡片。
- 失效相关正文、知识、历史和角标查询。
- 原样接受优先刷新正文和待确认知识草稿提示;修改后合并优先进入“等待新草稿”状态。
9. 用户可观察流程
9.1 原样接受
- 用户点击“接受”。
- 正文进入乐观更新状态。
- 服务端完成主事务。
- 正文切换为已保存态。
- Suggestion 卡片从待审区移除。
- UI 显示“已合并,关联知识草稿仍待确认”。
- 知识视图与历史视图最终一致刷新,用户可进入知识确认入口单独处理草稿。
9.2 修改后合并
- 用户点击“修改”。
- 调整最终入正文的结构化内容。
- 点击“修改后合并”。
- 服务端完成正文主事务,并让旧草稿失效。
- UI 显示“已合并,旧知识草稿已失效,正在重新提取”。
- 前端进入等待新草稿状态。
9.3 Reject
- 用户点击“拒绝”。
- Suggestion 离开待审区。
- 正文无变化。
- 关联草稿一起丢弃。
10. Acceptance Criteria
Must-Have(P0)
- Accept 成功后,目标 Block 正确更新,revision 正确递增。
- Suggestion 成功迁入 Archive,不再留在 Active。
- 原样接受时,关联知识草稿不得写入 Local KB,只能保持待确认、需重验或不可确认状态。
- 修改后合并时,旧草稿立即失效,不允许继续确认。
- 修改后合并只启动重新提取异步链路,不在主事务里做外部调用。
- Reject 对正文零副作用。
- 409 冲突必须有显式恢复路径。
- 成功提示必须区分原样接受与修改后合并两条路径。
- 包含 AI、市场、外部知识或授权知识来源的正文 revision 必须写 Block Source Attribution。
- 候选正文 lineage 中存在 revoked、recalled、delisted、blocked、owner_missing、unauthorized 或无效授权快照时,Accept 必须失败。
- 候选使用市场作品资产时,必须经过作品资产使用预检和 feature gate;否则不能接受。
- 修改后合并默认继承上游 lineage 和许可限制,不能用
contentOverride洗白来源。 - Accept / Merge 写 Canonical 前必须实时校验来源版本和授权状态,校验清单必须覆盖输出合规、静态检查、质量结果版本、来源状态、授权快照、作品资产 feature gate、expectedRevision 和幂等结果。
Should-Have(P1)
- 成功后正文有短暂高亮反馈。
- 修改后合并能显示“等待新草稿”的明确状态。
- 同一 Block 下重复触发 Accept 时有临时互斥保护。
Nice-to-Have(P2)
- 更细粒度的对比视图。
- 建议卡片快捷键。
11. Test Plan
11.1 Manual
- 原样接受:正文更新,Suggestion 消失,知识视图可看到待确认草稿。
- 修改后合并:正文更新,旧草稿失效,系统稍后出现新草稿。
- Reject:正文不变,Suggestion 消失,知识不被污染。
- 409 冲突:前端进入可恢复状态,不覆盖用户新输入。
- 重复点击已接受对象:幂等,不重复污染正文与历史。
11.2 Automated
Backend Unit / Integration
- 原样接受正常路径
- 原样接受不确认知识草稿
- 候选正文来源 stale / revoked / recalled / delisted / blocked / owner_missing / unauthorized 时按决策规则阻断接受或要求重验;只有非正文关联草稿允许单独标记需重验
- Block Source Attribution 写入路径
- 市场作品资产缺 feature gate / owner 预检 /
workAssetUsePrecheckId时阻断接受 - 修改后合并触发旧草稿失效
- 修改后合并不能清空上游 lineage、授权快照和许可限制
- Reject 零正文副作用
- 409 冲突返回必要信息
- 投影失败不阻塞主事务
Frontend E2E
- 原样接受成功链路
- 修改后合并成功链路
- Reject 成功链路
- 409 冲突链路
- 本地脏状态下的失败恢复
12. 关联阅读
架构-02-核心数据结构与双轨模型.md架构-04-状态机与约束清单.md流程-02B-普通用户系统处理流程(系统视角).md流程-01B-普通用户操作流程(操作视角).md