|
|
@@ -0,0 +1,1335 @@
|
|
|
+# 智能创作构建系统技术方案
|
|
|
+
|
|
|
+> 文档定位:基于当前 `agent` 通用框架,把上一代固定 Workflow 脚本构建迁移为由主 Agent 动态规划、专业 Worker 执行、独立 Validator 验收的业务 Host 技术方案
|
|
|
+> 对应产品方案:`智能创作构建系统产品方案.md`
|
|
|
+> 事实基线:2026-07-18 的当前仓库、上一代真实代码、只读数据库样本和线上只读接口
|
|
|
+> 实施边界:本文规定后端、数据、工具、Agent 角色、验证、发布与恢复;HTML 仅作语义参考,不实施前端
|
|
|
+> 目标代码位置:当前仓库新增独立业务包 `script_build_host/`,不得把脚本领域对象写进 `agent/agent/orchestration`
|
|
|
+
|
|
|
+## 0. 结论和不可变约束
|
|
|
+
|
|
|
+### 0.1 目标
|
|
|
+
|
|
|
+新系统对业务方继续接收上一代相同的选题、人设、策略和数据源输入,继续产出上一代可读取的正式结构化脚本。变化的是生成过程:固定 Round、Branch 和预编排 Workflow 退出控制面,主 Agent 根据宏观 Root 目标持续检查任务树、动态拆任务、派发专业 Worker、读取 Validator 报告并决定接受、返修、重试、修订或阻塞。
|
|
|
+
|
|
|
+系统最终必须同时满足三类正确性:
|
|
|
+
|
|
|
+1. **业务合同正确**:旧输入可以启动,旧详情接口可以读到正式 Paragraph、Element 和关联。
|
|
|
+2. **Agent 因果正确**:父 Attempt 只消费创建时冻结的子任务 ACCEPT Decision,所有正式结果都能闭合到验证和证据。
|
|
|
+3. **发布正确**:Root ACCEPT 只代表候选完成;只有正式结果发布到 `branch_id=0` 且旧读取链路回读校验成功,`script_build_record.status` 才能变成 `success`。
|
|
|
+
|
|
|
+### 0.2 硬约束
|
|
|
+
|
|
|
+- `TaskLedger` 是 Mission 状态唯一真源,不复制 Root、Task、Attempt、Validation 或 Decision 状态到业务表。
|
|
|
+- 框架的 `FileSystemTaskStore`、`FileSystemArtifactStore`、`FileSystemTraceStore` 长期保留;首版部署限定单机、单活 Agent Host。本文不规划 SQL TaskStore。
|
|
|
+- MySQL 只保存旧脚本业务对象、冻结输入、候选正文版本和发布记录。
|
|
|
+- `ArtifactSnapshot` 只保存清单、引用和摘要,不保存大段脚本正文;正文由业务 Artifact Repository 保存。
|
|
|
+- 上一代工具通过 Adapter/Gateway 复用,不把旧项目模块直接导入新业务包。
|
|
|
+- Planner 不直接创作正文,不替代 Validator,不写正式结果。
|
|
|
+- Worker 不创建嵌套 Agent;四类取数能力是 Planner 派发的专业 Worker preset。
|
|
|
+- Validator 不修改候选,不进行未冻结的外部取数,只检查当前 Attempt 的固定 Snapshot。
|
|
|
+- 模型不能选择或伪造 `script_build_id`、`branch_id`、`root_trace_id`、`task_id`、`attempt_id` 和 `spec_version`;这些身份来自受保护运行上下文。
|
|
|
+- `branch_id=0` 只允许 Host Publisher 写入,任何 Agent 工具都不能直接发布。
|
|
|
+- 不新增 Script、Workflow、Round、Branch、页面节点等通用框架领域对象。
|
|
|
+- 本期不改 HTML 和 visualization;现有 HTML 只用于校正交互语义。
|
|
|
+
|
|
|
+## 1. 事实基线与证据边界
|
|
|
+
|
|
|
+### 1.1 上一代代码
|
|
|
+
|
|
|
+上一代真实代码位于:
|
|
|
+
|
|
|
+```text
|
|
|
+/home/sam/image_article_comprehension/aiddit/pattern/patter_from_global_and_build
|
|
|
+```
|
|
|
+
|
|
|
+审查基线为分支 `script_build_refactor_0709`、提交 `cc0e2a5`。真实业务入口、Prompt、工具、ORM、模板和静态脚本均来自该目录;本文不根据工具 Schema 数量猜测运行能力。
|
|
|
+
|
|
|
+上一代的核心运行逻辑是:
|
|
|
+
|
|
|
+```text
|
|
|
+创建 ScriptBuildRecord
|
|
|
+ → 拼接初始用户消息
|
|
|
+ → 主 Agent 读取 Topic/Persona/Strategy
|
|
|
+ → 模型自行生成 script_direction
|
|
|
+ → 固定轮次/分支/任务计划推进
|
|
|
+ → Implementer 写 Paragraph/Element/Link
|
|
|
+ → Evaluator/决策逻辑迭代
|
|
|
+ → branch 结果合并到 branch_id=0
|
|
|
+ → status=success
|
|
|
+```
|
|
|
+
|
|
|
+需要保留的是输入、工具能力和输出合同,不保留固定执行骨架。
|
|
|
+
|
|
|
+### 1.2 真实数据库样本:Script Build 454
|
|
|
+
|
|
|
+通过上一代只读数据库会话核验,`@@session.tx_read_only=1`。样本 454 的事实如下:
|
|
|
+
|
|
|
+| 项目 | 真实值 |
|
|
|
+|---|---:|
|
|
|
+| script_build_id | 454 |
|
|
|
+| execution_id | 401 |
|
|
|
+| topic_build_id | 1189 |
|
|
|
+| topic_id | 1352 |
|
|
|
+| status | success |
|
|
|
+| paragraph_count | 5 |
|
|
|
+| element_count | 11 |
|
|
|
+| script_direction 字符数 | 1827 |
|
|
|
+| build_workflow | NULL |
|
|
|
+| Paragraph 行数 | 5 |
|
|
|
+| Element 行数 | 11 |
|
|
|
+| Paragraph-Element 关联行数 | 13 |
|
|
|
+| Round 行数 | 2 |
|
|
|
+| Branch 行数 | 4 |
|
|
|
+| DataDecision 行数 | 4 |
|
|
|
+| MultipathDecision 行数 | 0 |
|
|
|
+| TaskPlanStep 行数 | 20 |
|
|
|
+| DomainInfo 行数 | 3 |
|
|
|
+| Event 行数 | 194 |
|
|
|
+
|
|
|
+样本说明:旧系统即使最终只交付 5 个段落和 11 个元素,过程也产生大量 Round、Branch、PlanStep 和 Event。新系统不照搬这些过程表,而用通用 Ledger 表达任务、尝试、验证和决策;旧 Paragraph/Element/Link 仍作为正式业务输出。
|
|
|
+
|
|
|
+Run 454 的两个 Round 目标也验证了旧过程的典型阶段性:第一轮建立整体段落结构并解释“毛驴效应/隐性亏损”,第二轮补行动指引、完成剩余段落并吸收候选分支优势。新系统允许 Planner 得出相似任务,也允许根据证据缺口选择不同顺序或省略无必要步骤。
|
|
|
+
|
|
|
+### 1.3 真实创作方向
|
|
|
+
|
|
|
+旧详情接口中,Run 454 的方向包含三类目标:
|
|
|
+
|
|
|
+1. 认知重构深度;
|
|
|
+2. 实用指引落地性;
|
|
|
+3. 人设风格一致性。
|
|
|
+
|
|
|
+这类方向不是后端确定性函数的输出。上一代 Prompt 要求主 Agent 先调用 `get_topic_detail`,按需调用 `get_account_script_persona_points`,再由模型生成 1–3 个方向目标和可选领域标准,最后调用 `save_script_direction`。新系统不能把旧 `script_direction` 当作初始 Root objective;它必须成为独立 Direction Task 的结构化、可验证、可版本化产物。
|
|
|
+
|
|
|
+### 1.4 安全事实
|
|
|
+
|
|
|
+上一代源码存在硬编码数据库或第三方访问凭据的风险。本文不记录任何凭据值。迁移前必须完成:
|
|
|
+
|
|
|
+- 轮换所有曾进入源码、日志或历史配置的凭据;
|
|
|
+- 使用环境注入或 Secret Manager;
|
|
|
+- 数据库读写账号分离;
|
|
|
+- 日志与 Trace 字段脱敏;
|
|
|
+- 外部 Endpoint allowlist、超时、响应大小限制与 SSRF 防护;
|
|
|
+- 禁止把 token、连接串或请求头写入 Artifact、Evidence、Event 和错误摘要。
|
|
|
+
|
|
|
+该项是阶段一上线前的 P0 门禁。
|
|
|
+
|
|
|
+## 2. 旧输入合同与冻结规则
|
|
|
+
|
|
|
+### 2.1 启动输入
|
|
|
+
|
|
|
+新业务入口保持旧调用合同,核心身份字段为:
|
|
|
+
|
|
|
+```text
|
|
|
+execution_id
|
|
|
+topic_build_id
|
|
|
+topic_id
|
|
|
+strategy selections
|
|
|
+data_source_url(若旧调用提供)
|
|
|
+model/role configuration
|
|
|
+```
|
|
|
+
|
|
|
+也继续支持旧的 Topic JSON 解析和导入入口。接口给出的 ID 只是定位信息,不能作为 Mission 运行期间的稳定输入;Host 必须在启动时组装并冻结完整内容。
|
|
|
+
|
|
|
+### 2.2 选题输入不是标题字符串
|
|
|
+
|
|
|
+`ScriptBuildInputSnapshotV1.topic` 至少包含:
|
|
|
+
|
|
|
+```text
|
|
|
+TopicBuildRecord 的 demand、demand_constraints、personal_config、origin 等核心字段
|
|
|
+Topic 的 id、topic_direction、inspiration_evaluation_config、result、status、failure_reason
|
|
|
+Points[]
|
|
|
+CompositionItems[]
|
|
|
+Relations[]
|
|
|
+Sources[]
|
|
|
+输入更新时间与来源标识
|
|
|
+```
|
|
|
+
|
|
|
+点、组成项、关系和来源必须保留原 ID 以及规范化内容,供 EvidenceRef 回指。Source 还要保存 `derivation_type` 和 `dataset_from`。对于缺失关系或空 sources,快照要显式保存空数组,不能在执行中再次读取“最新值”补齐。
|
|
|
+
|
|
|
+快照不能只调用旧 `get_topic_detail`,因为该工具的 Source projection 不返回 source row ID、`derivation_type`、`dataset_from`,也不包含 TopicBuildRecord 的 demand、constraints 和 personal_config。Host 启动时通过只读 Repository 联查:
|
|
|
+
|
|
|
+```text
|
|
|
+TopicBuildRecord
|
|
|
+ → TopicBuildTopic
|
|
|
+ → TopicBuildPoint
|
|
|
+ → TopicBuildPointItemRelation
|
|
|
+ → TopicBuildCompositionItem
|
|
|
+ → TopicBuildItemRelation
|
|
|
+ → TopicBuildItemSource
|
|
|
+```
|
|
|
+
|
|
|
+每层校验 execution/build/topic 归属和 active 语义。`get_topic_detail` 继续作为 Agent 兼容读取工具及交叉核验入口,不是 InputSnapshot 的唯一数据源。
|
|
|
+
|
|
|
+### 2.3 人设输入
|
|
|
+
|
|
|
+上一代运行时的人设并不等于单张 `account_persona` 表:
|
|
|
+
|
|
|
+- 初始消息从 `personal_config` 取得账号名称;
|
|
|
+- Persona Point 来自账号本地数据目录中的 `point_records.json`;
|
|
|
+- Section Pattern 来自账号对应的 section pattern 文件;
|
|
|
+- 主 Agent 可按需调用 `get_account_script_persona_points`。
|
|
|
+
|
|
|
+新快照统一为:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "account": {"account_name": "每天心理学", "source": "personal_config"},
|
|
|
+ "persona_points": [],
|
|
|
+ "section_patterns": [],
|
|
|
+ "source_versions": {},
|
|
|
+ "content_sha256": "sha256:..."
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+不得因未来有统一 Persona DB 就假定当前旧数据已在那里;Adapter 应允许文件源和数据库源并存,并在快照中记录实际来源。
|
|
|
+
|
|
|
+### 2.4 策略、Prompt 和模型配置
|
|
|
+
|
|
|
+冻结内容包括:
|
|
|
+
|
|
|
+- always-on 策略全文;
|
|
|
+- on-demand 策略摘要、ID、版本和内容 hash;
|
|
|
+- 主 Agent、Worker、Validator 的 preset 名称与 Prompt 版本;
|
|
|
+- 实际解析到的 Prompt 来源、`biz_type`、版本和 SHA-256;
|
|
|
+- 模型名、关键采样配置以及数据源配置版本。
|
|
|
+
|
|
|
+上一代 Prompt 存在 DB 优先、文件回退以及同步命名漂移。新系统每次 Mission 必须冻结“实际使用版本”,不能只记录期望的文件路径。
|
|
|
+
|
|
|
+### 2.5 输入快照对象
|
|
|
+
|
|
|
+```python
|
|
|
+@dataclass(frozen=True)
|
|
|
+class ScriptBuildInputSnapshotV1:
|
|
|
+ snapshot_id: str
|
|
|
+ script_build_id: int
|
|
|
+ execution_id: int
|
|
|
+ topic_build_id: int
|
|
|
+ topic_id: int
|
|
|
+ topic: dict
|
|
|
+ account: dict
|
|
|
+ persona_points: tuple[dict, ...]
|
|
|
+ section_patterns: tuple[dict, ...]
|
|
|
+ strategies: tuple[dict, ...]
|
|
|
+ prompt_manifest: tuple[dict, ...]
|
|
|
+ datasource_manifest: dict
|
|
|
+ model_manifest: dict
|
|
|
+ canonical_sha256: str
|
|
|
+ created_at: datetime
|
|
|
+```
|
|
|
+
|
|
|
+规范化规则:UTF-8、对象键排序、数组保持业务顺序、时间转 ISO 8601、空值和空数组不互换、浮点采用稳定字符串表示。`canonical_sha256` 对规范化 JSON 计算。业务对象和 Wire 引用使用 `sha256:<64位小写hex>`;MySQL `CHAR(64)` 列只保存裸 hex。Repository 是唯一转换边界,必须拒绝算法非 sha256、大小写异常和长度错误,避免同一 digest 出现两种比较语义。
|
|
|
+
|
|
|
+## 3. 输出合同
|
|
|
+
|
|
|
+### 3.1 正式业务输出
|
|
|
+
|
|
|
+对业务方仍只有一个正式脚本,即 `branch_id=0` 的活动记录:
|
|
|
+
|
|
|
+- `script_build_record`:构建概况、方向、计数、状态;
|
|
|
+- `script_build_paragraph`:段落层级、名称、内容/描述、排序和活动状态;
|
|
|
+- `script_build_element`:元素名称、类型、描述、内容及已有扩展字段;
|
|
|
+- `script_build_paragraph_element`:段落和元素关系;
|
|
|
+- 旧详情/日志接口需要的兼容投影。
|
|
|
+
|
|
|
+旧写工具未覆盖 Element 表所有扩展字段。产品输出合同已把 commonality、topic_support、weight 和 support elements 列为最低正式输出,因此阶段二必须补齐候选模型、Adapter 写入、freeze、正式发布和旧详情 readback;不得把这些字段降级为“不可写兼容字段”。数据库存在列不代表已有工具可写,阶段二验收以真实 create/update/readback 黑盒测试为准。
|
|
|
+
|
|
|
+旧 `GET /api/pattern/script_builds/{id}` 还必须兼容 `build_workflow`、`topic`、`decision_traces`、`post_datas`、`script_datas`,以及 Paragraph 内嵌的 `linked_element_ids`、`linked_elements`、`sub_paragraphs`。这些是旧响应合同,不代表新 Mission 模型重新引入 Workflow/Round/Page 对象。
|
|
|
+
|
|
|
+### 3.2 方向产物
|
|
|
+
|
|
|
+```python
|
|
|
+@dataclass(frozen=True)
|
|
|
+class ScriptDirectionArtifactV1:
|
|
|
+ goals: tuple[DirectionGoal, ...] # 1..3
|
|
|
+ criteria: tuple[Criterion, ...]
|
|
|
+ domain_criteria: tuple[Criterion, ...]
|
|
|
+ topic_refs: tuple[str, ...]
|
|
|
+ persona_refs: tuple[str, ...]
|
|
|
+ strategy_refs: tuple[str, ...]
|
|
|
+ evidence_refs: tuple[str, ...]
|
|
|
+ legacy_markdown: str
|
|
|
+ canonical_sha256: str
|
|
|
+```
|
|
|
+
|
|
|
+`legacy_markdown` 是面向旧 `script_direction` 字段的投影,不是结构化真源。Direction Task 经 Validator passed 且 Planner ACCEPT 后,Host 才把已接受版本标记为 active direction;普通工具不得任意覆盖。
|
|
|
+
|
|
|
+### 3.3 证据产物
|
|
|
+
|
|
|
+```python
|
|
|
+@dataclass(frozen=True)
|
|
|
+class EvidenceRecordV1:
|
|
|
+ evidence_id: str
|
|
|
+ source_type: str
|
|
|
+ tool_name: str
|
|
|
+ query: dict
|
|
|
+ source_refs: tuple[str, ...]
|
|
|
+ raw_artifact_ref: str | None
|
|
|
+ summary: str
|
|
|
+ supports: tuple[str, ...]
|
|
|
+ confidence: str
|
|
|
+ limitations: tuple[str, ...]
|
|
|
+ content_sha256: str
|
|
|
+ created_at: datetime
|
|
|
+```
|
|
|
+
|
|
|
+证据摘要不能替代原始引用。涉及图片、外部网页或长文本时,原始内容进入受控对象存储/文件 Artifact;EvidenceRecord 保存引用、摘要和 digest。
|
|
|
+
|
|
|
+### 3.4 整稿产物
|
|
|
+
|
|
|
+```python
|
|
|
+@dataclass(frozen=True)
|
|
|
+class StructuredScriptArtifactV1:
|
|
|
+ direction_ref: str
|
|
|
+ paragraphs: tuple[dict, ...]
|
|
|
+ elements: tuple[dict, ...]
|
|
|
+ paragraph_element_links: tuple[dict, ...]
|
|
|
+ source_artifact_refs: tuple[str, ...]
|
|
|
+ evidence_refs: tuple[str, ...]
|
|
|
+ acceptance_notes: tuple[str, ...]
|
|
|
+ canonical_sha256: str
|
|
|
+```
|
|
|
+
|
|
|
+它是 Root Worker 提交的不可变候选,不等同于旧表中可变的“当前 branch”。Validator 和 Publisher 必须读取该版本固定的 canonical JSON。
|
|
|
+
|
|
|
+## 4. 总体架构
|
|
|
+
|
|
|
+```text
|
|
|
+Legacy-compatible HTTP API
|
|
|
+ │
|
|
|
+ ▼
|
|
|
+script_build_host/
|
|
|
+ ScriptMissionService ── InputSnapshotService
|
|
|
+ │ │
|
|
|
+ │ └── Legacy DB / files / prompt adapters
|
|
|
+ ▼
|
|
|
+ current agent framework
|
|
|
+ Planner → Task → Worker → Snapshot → Validator → Decision
|
|
|
+ │ │
|
|
|
+ │ └── LegacyScriptToolGateway
|
|
|
+ │ │
|
|
|
+ │ ├── four retrieval services
|
|
|
+ │ └── candidate Paragraph/Element/Link writes
|
|
|
+ ▼
|
|
|
+ ScriptArtifactRepository (MySQL business versions + candidate branches)
|
|
|
+ │
|
|
|
+ Root ACCEPT
|
|
|
+ ▼
|
|
|
+ ScriptPublisher ── transaction publish to branch_id=0
|
|
|
+ │
|
|
|
+ legacy readback + digest verification
|
|
|
+ ▼
|
|
|
+ script_build_record.status = success
|
|
|
+```
|
|
|
+
|
|
|
+### 4.1 通用框架与业务 Host 分工
|
|
|
+
|
|
|
+框架提供:
|
|
|
+
|
|
|
+- Root objective、TaskSpec、Task 树和焦点;
|
|
|
+- Attempt、固定 child Decision 输入;
|
|
|
+- ArtifactSnapshot、Validation、Planner Decision;
|
|
|
+- capability 权限边界;
|
|
|
+- Operation、Event、Trace 和 V2 读取接口;
|
|
|
+- `FileSystemTaskStore` 的 revision/CAS、文件锁和原子替换,以及 `FileSystemArtifactStore` 的文件锁/first-write-wins;TraceStore 不具同等级跨进程写保证。
|
|
|
+
|
|
|
+业务 Host 提供:
|
|
|
+
|
|
|
+- 从旧 ID 组装稳定输入;
|
|
|
+- 创建 Root TaskSpec 和 Planner 初始消息;
|
|
|
+- 脚本角色 preset 和业务工具;
|
|
|
+- 候选正文持久化、冻结和 digest;
|
|
|
+- 验证规则和证据读取;
|
|
|
+- Root ACCEPT 后的正式发布;
|
|
|
+- 旧 API 和状态兼容。
|
|
|
+
|
|
|
+### 4.2 部署约束
|
|
|
+
|
|
|
+框架 Store 目录必须位于持久盘:
|
|
|
+
|
|
|
+```text
|
|
|
+{agent_data_root}/{root_trace_id}/orchestration/ledger.json
|
|
|
+{agent_data_root}/{root_trace_id}/orchestration/artifacts/*.json
|
|
|
+{agent_data_root}/{trace_id}/meta.json
|
|
|
+{agent_data_root}/{trace_id}/messages/
|
|
|
+```
|
|
|
+
|
|
|
+同一 `root_trace_id` 只能被一个活动 Host 进程驱动。文件锁保护 Ledger 提交,但 `OperationRuntime` 和正在执行的模型调用仍是进程内对象,因此不能把共享盘上的多个进程当作分布式调度器。进程重启后执行显式 recovery:对旧 RUNNING Attempt 不猜测、不接管模型上下文,按框架规则失败/重新规划。
|
|
|
+
|
|
|
+## 5. `script_build_host/` 模块设计
|
|
|
+
|
|
|
+```text
|
|
|
+script_build_host/
|
|
|
+ api/
|
|
|
+ routes.py
|
|
|
+ schemas.py
|
|
|
+ dependencies.py
|
|
|
+ application/
|
|
|
+ mission_service.py
|
|
|
+ mission_factory.py
|
|
|
+ input_snapshot_service.py
|
|
|
+ publisher.py
|
|
|
+ recovery_service.py
|
|
|
+ legacy_detail_projection_service.py
|
|
|
+ domain/
|
|
|
+ input_snapshot.py
|
|
|
+ direction.py
|
|
|
+ evidence.py
|
|
|
+ structured_script.py
|
|
|
+ publication.py
|
|
|
+ errors.py
|
|
|
+ agents/
|
|
|
+ presets.py
|
|
|
+ prompts/
|
|
|
+ validation_policy.py
|
|
|
+ deterministic_checks.py
|
|
|
+ tools/
|
|
|
+ registry.py
|
|
|
+ gateway.py
|
|
|
+ topic_adapter.py
|
|
|
+ persona_adapter.py
|
|
|
+ strategy_adapter.py
|
|
|
+ pattern_adapter.py
|
|
|
+ decode_adapter.py
|
|
|
+ external_adapter.py
|
|
|
+ knowledge_adapter.py
|
|
|
+ candidate_write_adapter.py
|
|
|
+ repositories/
|
|
|
+ mission_binding_repository.py
|
|
|
+ input_snapshot_repository.py
|
|
|
+ artifact_repository.py
|
|
|
+ publication_repository.py
|
|
|
+ legacy_script_repository.py
|
|
|
+ infrastructure/
|
|
|
+ db.py
|
|
|
+ config.py
|
|
|
+ canonical_json.py
|
|
|
+ secrets.py
|
|
|
+ migrations/
|
|
|
+ composition.py
|
|
|
+```
|
|
|
+
|
|
|
+依赖方向为 `api → application → domain/ports`,Infrastructure 实现 Port,Agent 工具只能调用 application/gateway,禁止直接持有 ORM Session。
|
|
|
+
|
|
|
+### 5.1 核心 Port 与函数合同
|
|
|
+
|
|
|
+| 组件/函数 | 输入 | 输出 | 事务与失败语义 |
|
|
|
+|---|---|---|---|
|
|
|
+| `ScriptInputSnapshotService.assemble` | execution/topic IDs、策略选择、data source、principal | `ScriptBuildInput` | 只读装配;任一归属不一致即 `INPUT_RELATION_MISMATCH` |
|
|
|
+| `ScriptInputSnapshotService.freeze` | assembled input | `ScriptBuildInputSnapshotV1` | 单事务按 build+hash 幂等写入;同版本异 hash 冲突 |
|
|
|
+| `ScriptInputSnapshotService.get` | snapshot ID + authorized build | frozen snapshot | 不存在/跨 build 统一 404 |
|
|
|
+| `ScriptMissionFactory.build_root_task_spec` | frozen snapshot | Root Task draft `dict` | 纯函数;字段仅 objective/acceptance_criteria/context_refs |
|
|
|
+| `ScriptMissionFactory.build_planner_message` | binding + snapshot refs | 初始消息 | 只放引用和合同摘要,不嵌固定任务序列 |
|
|
|
+| `ScriptMissionFactory.build_run_config` | binding | `RunConfig` | 强制 explicit validation、preset、root spec |
|
|
|
+| `ScriptArtifactRepository.create_workspace` | build/task/attempt/spec | draft version/workspace | 单事务按 attempt 唯一;先取 version ID 再作 branch ID |
|
|
|
+| `ScriptArtifactRepository.freeze` | workspace/attempt | frozen version + ArtifactRef | 同事务 canonical 化并拒绝后续写;重复 freeze 同 hash 幂等 |
|
|
|
+| `ScriptArtifactRepository.read_by_ref` | authorized ArtifactRef | immutable business artifact | 校验 build/task/attempt/type/digest;不解析任意文件 URI |
|
|
|
+| `ScriptArtifactRepository.verify_digest` | ArtifactRef | bool/detail | 只读;算法/格式/归属错误视为 protocol violation |
|
|
|
+| `LegacyScriptToolGateway.execute_read` | tool、args、protected context | normalized result | 从 snapshot/accepted refs 读取;禁止 live 漂移 |
|
|
|
+| `LegacyScriptToolGateway.execute_retrieval` | tool、query、context | EvidenceRecord | 受 capability、timeout、outbound policy 控制 |
|
|
|
+| `LegacyScriptToolGateway.execute_candidate_write` | tool、args、context | write result | 只写 Attempt workspace;每个工具调用短事务 |
|
|
|
+| `LegacyScriptToolGateway.snapshot_workspace` | attempt context | canonical candidate | 一致性读,供 freeze;缺引用即失败 |
|
|
|
+| `resolve_attempt_workspace` | protected context | CandidateWorkspace | 身份全部来自 Host context,拒绝模型传 branch |
|
|
|
+| `ensure_legacy_task_plan` | workspace/task | legacy PlanStep projection | 同 branch 首次结构写前幂等 upsert |
|
|
|
+| `normalize_tool_result` | legacy string/dict/error | typed result | 不把“错误:”文本误判为成功 |
|
|
|
+| `collect_evidence_refs` | child Decisions + tool results | ordered EvidenceRefs | 验证 Decision 闭合、去重并保持业务顺序 |
|
|
|
+| `ScriptPublisher.publish` | Root ACCEPT + ArtifactRef | PublicationResult | 单活锁 + 单事务 branch0 投影/readback/digest/状态 |
|
|
|
+| `LegacyDetailProjectionService.project` | authorized build + DB Session | 旧详情响应 | 可在 Publisher 同一事务中读取;稳定顺序、空值合同 |
|
|
|
+
|
|
|
+Repository 的领域错误统一映射为稳定代码,例如 `BUILD_NOT_FOUND`、`MISSION_ALREADY_OWNED`、`INPUT_HASH_CONFLICT`、`ATTEMPT_WORKSPACE_FROZEN`、`ARTIFACT_DIGEST_MISMATCH`、`CHILD_DECISION_INVALID`、`PUBLICATION_READBACK_MISMATCH`。错误摘要可观测,内部 SQL、文件路径和 secret 不出边界。
|
|
|
+
|
|
|
+### 5.2 Legacy Detail Projection
|
|
|
+
|
|
|
+```python
|
|
|
+class LegacyDetailProjectionService:
|
|
|
+ async def project(
|
|
|
+ self,
|
|
|
+ script_build_id: int,
|
|
|
+ *,
|
|
|
+ session: AsyncSession,
|
|
|
+ principal: Principal,
|
|
|
+ ) -> LegacyScriptBuildDetail: ...
|
|
|
+```
|
|
|
+
|
|
|
+字段映射:
|
|
|
+
|
|
|
+| 旧响应字段 | 新系统来源 | 规则 |
|
|
|
+|---|---|---|
|
|
|
+| build 概况/方向/计数/status | `script_build_record` + accepted/published pointers | success 时必须与 branch0 一致 |
|
|
|
+| `build_workflow` | 原记录兼容值 | 新 Agentic Mission 不生成新的固定 Workflow;无旧值返回旧合同规定的 null |
|
|
|
+| `topic` | frozen InputSnapshot 的 topic projection | 不读取 Mission 中途更新后的 live topic |
|
|
|
+| `decision_traces` | 已接受业务 Decision/Evidence 的兼容投影 | 稳定按发生时间+ID;不暴露 command fingerprint |
|
|
|
+| `post_datas` | accepted Evidence 中的参考帖子 | 以引用 ID 为 key 的 object/map;缺失为 `{}`,不改成数组 |
|
|
|
+| `script_datas` | accepted Evidence 中的参考脚本 | 以引用 ID 为 key 的 object/map;缺失为 `{}`,不混入未接受候选 |
|
|
|
+| Paragraph 列表 | branch0 active Paragraph | 按旧 sort/layer/ID 规则稳定排序 |
|
|
|
+| `linked_element_ids` | branch0 ParagraphElement | 与 `linked_elements` 顺序一致 |
|
|
|
+| `linked_elements` | branch0 ParagraphElement link projection | 每项严格为 `{element_id, link_id}`;完整 Element 只在顶层 `elements` |
|
|
|
+| `sub_paragraphs` | branch0 parent-child relation | 递归组装但防环;无子项为空数组 |
|
|
|
+
|
|
|
+所有 object/数组的空值、ID 类型、展示顺序和嵌套结构由旧 Run 详情 fixture 固化。Publisher 事务内调用同一 Projection Service 生成 canonical readback;普通 GET 也调用它,避免发布校验和线上响应使用两套拼装逻辑。
|
|
|
+
|
|
|
+## 6. Mission 生命周期与主要函数
|
|
|
+
|
|
|
+### 6.1 服务接口
|
|
|
+
|
|
|
+```python
|
|
|
+class ScriptMissionService:
|
|
|
+ async def start(
|
|
|
+ self, request: StartScriptBuildRequest
|
|
|
+ ) -> ScriptMissionStartResult: ...
|
|
|
+
|
|
|
+ async def run(self, script_build_id: int) -> None: ...
|
|
|
+
|
|
|
+ async def stop(self, script_build_id: int) -> StopResult: ...
|
|
|
+
|
|
|
+ async def resume(self, script_build_id: int) -> ResumeResult: ...
|
|
|
+
|
|
|
+ async def finalize_accepted_root(
|
|
|
+ self, script_build_id: int, root_trace_id: str
|
|
|
+ ) -> PublicationResult: ...
|
|
|
+```
|
|
|
+
|
|
|
+### 6.2 `start()`
|
|
|
+
|
|
|
+事务外读取和校验:
|
|
|
+
|
|
|
+1. 校验 execution、topic build、topic 的归属关系;
|
|
|
+2. 解析旧 API 的策略选择和 data source;
|
|
|
+3. 调 `ScriptInputSnapshotService.assemble()`;
|
|
|
+4. 规范化、计算 hash,并冻结输入;
|
|
|
+5. 调 `ScriptMissionFactory.build_root_task_spec()`;
|
|
|
+6. 预分配 Planner 主 Trace ID;该 ID 同时就是 `root_trace_id`,不建立第二个 Planner 身份;
|
|
|
+7. 事务内插入/复用 mission binding,保证一个 build 只有一个 active Mission;
|
|
|
+8. 返回旧接口可识别的 build ID/status,并在后台启动 `run()`。
|
|
|
+
|
|
|
+若同一 `script_build_id` 内的 Mission 创建命令以同一幂等键重复到达,必须返回已有 binding;若该 build 的输入 hash 不同,则拒绝隐式复用。旧 HTTP start/retry 本身仍按第 13.1 节每次创建新 build。
|
|
|
+
|
|
|
+### 6.3 Root TaskSpec
|
|
|
+
|
|
|
+```python
|
|
|
+def build_root_task_spec(snapshot: ScriptBuildInputSnapshotV1) -> dict:
|
|
|
+ topic_summary = normalize_topic_summary(
|
|
|
+ snapshot.topic.get("result")
|
|
|
+ or snapshot.topic.get("topic_direction")
|
|
|
+ or snapshot.topic["id"]
|
|
|
+ )
|
|
|
+ return {
|
|
|
+ "objective": (
|
|
|
+ f"为账号「{snapshot.account['account_name']}」基于选题"
|
|
|
+ f"「{topic_summary}」构建一份满足选题、人设、策略、"
|
|
|
+ "证据与旧结构化脚本输出合同的正式脚本候选"
|
|
|
+ ),
|
|
|
+ "acceptance_criteria": [
|
|
|
+ {"criterion_id": "input-consistency", "description": "全部创作可追溯到冻结输入", "hard": True},
|
|
|
+ {"criterion_id": "direction-accepted", "description": "使用已验证并接受的创作方向", "hard": True},
|
|
|
+ {"criterion_id": "structure-complete", "description": "段落、元素、关系完整且引用有效", "hard": True},
|
|
|
+ {"criterion_id": "evidence-closure", "description": "事实表达有证据且创作表达不伪装成事实", "hard": True},
|
|
|
+ {"criterion_id": "persona-consistency", "description": "语言和观点符合冻结人设", "hard": True},
|
|
|
+ {"criterion_id": "legacy-readable", "description": "能规范化投影为旧详情合同", "hard": True},
|
|
|
+ ],
|
|
|
+ "context_refs": [f"script-build://inputs/{snapshot.snapshot_id}"],
|
|
|
+ }
|
|
|
+```
|
|
|
+
|
|
|
+Root objective 描述总交付,不预先钉死“必须几轮、几个分支、按什么顺序”。创作方向由 Direction Task 生成。Root revise 只通过框架修订 TaskSpec,不更新第二套 mission 字段。
|
|
|
+
|
|
|
+真实 `TopicBuildTopic` 没有 `title` 字段。`normalize_topic_summary()` 只能从冻结的 `result` 或 `topic_direction` 生成有限长度摘要;账号从冻结的 `TopicBuildRecord.personal_config.account_name` 派生。若缺账号则使用明确的“未指定账号”策略并调整 persona criterion,不能虚构字段。
|
|
|
+
|
|
|
+### 6.4 `run()`
|
|
|
+
|
|
|
+```python
|
|
|
+async def run(self, script_build_id: int) -> None:
|
|
|
+ binding = await self.bindings.require(script_build_id)
|
|
|
+ config = self.factory.build_run_config(binding)
|
|
|
+ try:
|
|
|
+ await self.runner.run_result(
|
|
|
+ messages=[{
|
|
|
+ "role": "user",
|
|
|
+ "content": self.factory.build_planner_message(binding),
|
|
|
+ }],
|
|
|
+ config=config,
|
|
|
+ )
|
|
|
+ completion = await self.coordinator.root_completion(
|
|
|
+ binding.root_trace_id
|
|
|
+ )
|
|
|
+ if completion["status"] == "completed":
|
|
|
+ await self.finalize_accepted_root(
|
|
|
+ script_build_id, binding.root_trace_id
|
|
|
+ )
|
|
|
+ else:
|
|
|
+ await self.status_projector.project_non_success(completion)
|
|
|
+ except Exception as exc:
|
|
|
+ await self.status_projector.project_runtime_failure(exc)
|
|
|
+ raise
|
|
|
+```
|
|
|
+
|
|
|
+`AgentRunner.run()` 是 async iterator,不能直接 `await`;服务模式使用 `run_result()` 消费完整事件流,若需要流式投影则显式 `async for`。`RunConfig` 必须使用 `explicit_validation`、`script_planner` preset 和 Root Task draft dict。当前 `wire_orchestration()` 尚未暴露 validation policy、deterministic validator、evidence provider 等全部 Coordinator 参数;阶段一可在 composition root 直接构造 `TaskCoordinator`,设置 `LocalAgentExecutor` 与 `runner.task_coordinator`,或先做向后兼容 wiring 扩展,不能假定参数已经被装配。
|
|
|
+
|
|
|
+### 6.5 stop/resume/recovery
|
|
|
+
|
|
|
+`stop()`:
|
|
|
+
|
|
|
+1. 读取一次 Mission Snapshot;
|
|
|
+2. 先把旧业务状态投影为 `stopping`;
|
|
|
+3. 持久化 stop intent,停止 running/pending Operation,并通知当前 OwnerLease 对应的 Planner runtime;
|
|
|
+4. 轮询所有相关 Operation 和 Planner Trace;全部进入终态后才投影为 `stopped`;
|
|
|
+5. 超时则保持 `stopping`,记录脱敏、可恢复原因,不能假称已停止;
|
|
|
+6. 保留 Ledger、Trace、候选和发布记录,且 stop 路径不得执行发布。
|
|
|
+
|
|
|
+`resume()`:
|
|
|
+
|
|
|
+1. 获取 build/root 的单活所有权锁;锁冲突返回稳定 `409 MISSION_ALREADY_OWNED`;
|
|
|
+2. 若旧业务状态已是 `success`,验证 publication/digest 后幂等返回,绝不重开 Planner;
|
|
|
+3. 若 Root 已 completed 而 publication 为 pending/failed,只调用 `finalize_accepted_root()` 重试同一 accepted Artifact,绝不向 Planner 追加消息;
|
|
|
+4. 只有 Root 未完成且业务状态为 stopped/partial/failed 时,才调用框架 operation recovery 对齐 durable 状态;
|
|
|
+5. 对不可安全续跑的旧 RUNNING Attempt 按下述生产 Operation 规则恢复;
|
|
|
+6. 向同一未完成的 Planner Trace 追加恢复消息;
|
|
|
+7. 不 rewind,不猜测未提交结果,不扫描“当前最新子任务”作为输入。
|
|
|
+
|
|
|
+恢复分支要区分:
|
|
|
+
|
|
|
+- Ledger 有 Operation:`recover_operations()` 只对齐持久状态。未安全启动的 pending 可保留;已启动但进程丢失的 stage 归一为 stopped/expired/failed,不能自动调用模型;
|
|
|
+- 前台遗留 Attempt 无 Operation 且 `started_at is None`:尚未启动 Worker,才允许安全 `advance_cycle()`;
|
|
|
+- 前台遗留 Attempt 无 Operation 且 `started_at is not None`:禁止重跑同一 Attempt,避免重复外部副作用。当前框架没有公开的 foreground orphan 原子恢复命令,因此生产 Script preset 必须排除同步 `dispatch_tasks`,只开放 Host 包装的 `dispatch_script_tasks`;该工具内部使用 `start_operation()` 创建 durable BackgroundOperation 并等待/轮询。若未来保留前台路径,须先新增通用 Coordinator recovery command,原子将 Attempt 标为 stopped/failed、Task 转 needs_replan;
|
|
|
+- `accepted_child_decision_ids=None`:遗留协议未知,仍由现有 `advance_cycle()` 走 `PROTOCOL_VIOLATION`,不得猜测子输入;
|
|
|
+- `resume_operation()` 只允许框架判断为未安全启动的 stage;已启动后停止的模型 stage 返回 `resume_not_safe`,交给 Planner retry/replan;
|
|
|
+- Root completed:不调用上述模型恢复,只走同一 Artifact 的 Publisher 重试。
|
|
|
+
|
|
|
+### 6.6 单机单活所有权
|
|
|
+
|
|
|
+FileStore 自带的 Ledger 文件锁只保护单次 commit,不等于 Mission 运行所有权。Host 另设以 `script_build_id + root_trace_id` 为键的 `OwnerLease`(进程锁文件 + owner token):
|
|
|
+
|
|
|
+- 顶层 `run`/`resume` 在任何调度前获取一次;`start` 创建 binding 后把已获取 token 原子交接给后台 `run`,不存在两个 owner 的窗口;
|
|
|
+- `run()` 内调用 `finalize_accepted_root()` 时传递并复用同一个 owner token,禁止嵌套二次加锁;独立 publication recovery 才新获取 OwnerLease;
|
|
|
+- `stop()` 不争抢正在持有的独占 OwnerLease,只持久化 stop intent 并通过 runtime signal 通知当前 owner,且不能执行发布;
|
|
|
+- 锁文件写 owner PID、Host instance ID、root、获取时间,不写 secret;
|
|
|
+- 持有进程以文件描述符锁持续占有,不能仅靠可过期文本时间戳;
|
|
|
+- 正常结束或异常退出由 OS 释放,进程启动时核对 binding 和 Ledger 决定恢复;
|
|
|
+- 获取失败返回 `409 MISSION_ALREADY_OWNED`,不得启动第二个 Planner;
|
|
|
+- 发布过程与 Planner 运行使用同一所有权域和 token,避免 stop/resume/finalize 交叉执行。
|
|
|
+
|
|
|
+该机制只保证同一主机。跨机部署不在本方案范围。
|
|
|
+
|
|
|
+## 7. Agent 角色与权限
|
|
|
+
|
|
|
+### 7.1 Planner
|
|
|
+
|
|
|
+职责:检查 Ledger、识别缺口、创建/修订任务、调度 Worker、读取验证、做 Decision、推动 Root 收敛。
|
|
|
+
|
|
|
+只开放:
|
|
|
+
|
|
|
+```text
|
|
|
+read/task_control capability
|
|
|
+inspect_tasks
|
|
|
+create_tasks / revise_task
|
|
|
+dispatch_script_tasks(Host 的 BackgroundOperation 包装;排除同步 dispatch_tasks)
|
|
|
+decide_task
|
|
|
+必要的只读输入摘要
|
|
|
+```
|
|
|
+
|
|
|
+不得开放候选正文写工具和正式发布工具。Planner 可以决定是否需要 Pattern、Decode、External 或 Knowledge,不把四类取数写成固定顺序。
|
|
|
+
|
|
|
+### 7.2 专业取数 Worker
|
|
|
+
|
|
|
+注册四个 preset:
|
|
|
+
|
|
|
+| Preset | 老能力 | 工具白名单 |
|
|
|
+|---|---|---|
|
|
|
+| `script_pattern_retrieval_worker` | 结构/套路问答 | `get_script_snapshot`, `query_pattern_qa`, `submit_attempt` |
|
|
|
+| `script_decode_retrieval_worker` | 历史脚本/账号解码检索 | `get_script_snapshot`, `search_script_decode_case`, `submit_attempt` |
|
|
|
+| `script_external_retrieval_worker` | 外部资料与图片 | `get_script_snapshot`, `external_search_case`, `load_images`, `submit_attempt` |
|
|
|
+| `script_knowledge_retrieval_worker` | 内部知识库 | `search_knowledge`, `submit_attempt` |
|
|
|
+
|
|
|
+它们由 Planner 创建独立 Task 并调度,不由创作 Worker 在内部 spawn。结果统一为 EvidenceRecord Artifact;失败或低质量证据由 Validator 报告,Planner 决定重试、换源、修订查询或接受限制。
|
|
|
+
|
|
|
+### 7.3 创作 Worker
|
|
|
+
|
|
|
+建议 preset:
|
|
|
+
|
|
|
+```text
|
|
|
+script_direction_worker
|
|
|
+script_structure_worker
|
|
|
+script_paragraph_worker
|
|
|
+script_element_worker
|
|
|
+script_candidate_compare_worker
|
|
|
+script_root_worker
|
|
|
+```
|
|
|
+
|
|
|
+Worker 只能读取当前 TaskSpec、冻结输入、`accepted_child_decision_ids` 所引用的子结果,以及自己的 Attempt workspace。它不能读取另一个未接受候选作为“最新正确结果”。
|
|
|
+
|
|
|
+Planner 负责宏观连续性;整稿写作上下文由 `script_root_worker` 或专门的 whole-script Worker 承担,而不是要求 Planner 在长上下文中持续写正文。
|
|
|
+
|
|
|
+### 7.4 Validator
|
|
|
+
|
|
|
+```text
|
|
|
+script_retrieval_validator
|
|
|
+script_candidate_validator
|
|
|
+script_root_validator
|
|
|
+```
|
|
|
+
|
|
|
+Validator capability 上限为 read + validation_submit。它对固定 Snapshot 给出逐 criterion 的结构化报告,不修改 Artifact,不发布,不创建 Task。
|
|
|
+
|
|
|
+当前一次 ValidationPlan 只能选择 Agent 或 Deterministic 模式,不能宣称原生同时跑两者。实施选择:普通任务使用 Agent Validator,并向其开放受控的确定性检查工具;若必须保留两个独立报告,则拆成两个 Task。Root Validator 在综合判断前可调用 schema/digest/reference 等只读预检工具。
|
|
|
+
|
|
|
+本业务的 Retrieval、Candidate、Root 综合验证默认使用 **Agent mode**,因此会产生真实 Validator Sub-Trace;纯 schema/digest 预检若单独采用 deterministic mode,只产生独立 Validation record 和 validator execution identity,不产生模型 Trace。E2E 的“闭合到 Trace”只要求 Agent-mode 验证;deterministic 报告按 Validation record 闭合。
|
|
|
+
|
|
|
+### 7.5 完整 preset 隔离
|
|
|
+
|
|
|
+capability 只限制工具效果类别,不提供文件路径或数据库行级 ACL。所有 `script_*` preset 必须使用精确 `allowed_tools`,显式排除默认通用 `read_file`、`write_file`、`bash_command`、任意数据库客户端和通用网络工具。需要文件或数据库能力时,只注册下列 ownership-aware wrapper:
|
|
|
+
|
|
|
+```text
|
|
|
+read_input_snapshot
|
|
|
+read_accepted_artifact
|
|
|
+read_attempt_workspace
|
|
|
+write_attempt_workspace
|
|
|
+query_allowlisted_retrieval_service
|
|
|
+submit_attempt / submit_validation
|
|
|
+```
|
|
|
+
|
|
|
+wrapper 从 protected context 解析 build/root/task/attempt/snapshot 并执行行级归属检查;模型参数不能覆盖这些身份。Schema 过滤和执行前授权都必须通过,防止工具名白名单与实际执行策略漂移。
|
|
|
+
|
|
|
+## 8. 上一代工具能力盘点与 Adapter 合同
|
|
|
+
|
|
|
+### 8.1 实际能力数量
|
|
|
+
|
|
|
+上一代目录中有 57 个 JSON Schema 工具资产,但这不代表任一 Agent 同时拥有 57 个工具。口径固定为:57 个 Schema 中进入当前静态角色白名单的业务工具去重为 37 个;再加非 Schema 的 `load_images` 后,静态白名单并集为 38 个;存在 on-demand 策略时再加入 `load_strategy`,为 39 个。动态框架能力 `agent`/`implement_paths` 另算,不属于业务工具并集。新系统必须以 preset 白名单和 capability 为准,不以 Schema 文件总数授权。
|
|
|
+
|
|
|
+### 8.2 输入与当前结果读取
|
|
|
+
|
|
|
+至少适配:
|
|
|
+
|
|
|
+```text
|
|
|
+get_topic_detail
|
|
|
+get_account_script_persona_points
|
|
|
+load_strategy(若旧调用使用)
|
|
|
+get_script_snapshot / current script detail
|
|
|
+reference post/script detail readers
|
|
|
+```
|
|
|
+
|
|
|
+这些工具优先读取冻结 InputSnapshot 或明确 ArtifactRef。只有构建前组装阶段可以读取 live 输入表;Mission 运行期间不能悄悄切换成更新后的 Topic/Persona。
|
|
|
+
|
|
|
+### 8.3 Pattern Agent
|
|
|
+
|
|
|
+旧逻辑:
|
|
|
+
|
|
|
+```text
|
|
|
+query_pattern_qa
|
|
|
+POST /pattern-qa/tasks
|
|
|
+轮询 GET task result
|
|
|
+轮询间隔约 3 秒
|
|
|
+总超时约 600 秒
|
|
|
+```
|
|
|
+
|
|
|
+新 Adapter:
|
|
|
+
|
|
|
+```python
|
|
|
+class PatternRetrievalAdapter:
|
|
|
+ async def query(self, request: PatternQuery) -> EvidenceRecordV1: ...
|
|
|
+```
|
|
|
+
|
|
|
+要求:保存 query、任务 ID、响应 digest 和限制;Operation/Event 只表达 dispatch/Task 的高层状态变化。当前通用 Event 没有业务轮询 progress 事件,每次约 3 秒 poll 的明细进入脱敏业务日志,或由 Host 显式注入外部 Event Sink,不能复制进 Ledger。超时提交失败原因,不能返回伪空结果。
|
|
|
+
|
|
|
+### 8.4 Decode Agent
|
|
|
+
|
|
|
+旧工具签名:
|
|
|
+
|
|
|
+```python
|
|
|
+search_script_decode_case(
|
|
|
+ return_field,
|
|
|
+ keyword="",
|
|
|
+ account_name=None,
|
|
|
+ match_fields=None,
|
|
|
+ top_k=3,
|
|
|
+)
|
|
|
+```
|
|
|
+
|
|
|
+`return_field` 是必填首参,`top_k` 的真实约束为 1..5。真实本地索引审查值为 115 posts、45,972 chunks、323,632 tokens;有 keyword 时使用外部 embedding 服务生成向量。Adapter 必须固定索引版本、账号、字段、top_k、返回字段和 embedding 模型版本,并把命中文档 ID/score 作为 source refs,不能只保留模型摘要。
|
|
|
+
|
|
|
+### 8.5 External Agent 与图片
|
|
|
+
|
|
|
+旧工具:
|
|
|
+
|
|
|
+```python
|
|
|
+external_search_case(keyword, platform_channel, max_count)
|
|
|
+load_images(image_urls)
|
|
|
+```
|
|
|
+
|
|
|
+旧图片加载约束包括最多 12 张、单体/响应大小约束和 30 秒级超时。新 Adapter 必须:
|
|
|
+
|
|
|
+- 只允许配置中的协议和域名;
|
|
|
+- 解析 DNS/重定向后仍阻止内网地址;
|
|
|
+- 限制图片数、单文件大小、总大小、MIME 和超时;
|
|
|
+- 原图存 Artifact,只把安全摘要和引用传给模型;
|
|
|
+- 不在 Validator 阶段重新搜索网络。
|
|
|
+
|
|
|
+外部请求 capability 标为 `external_send`;已冻结资料读取标为 `read`。
|
|
|
+
|
|
|
+调用方提供的 `data_source_url`、Pattern 服务地址、External 搜索地址、图片 URL 及全部重定向统一经过 OutboundPolicy:仅允许配置好的 HTTPS endpoint;每次 DNS 解析和重定向后重验目标地址;拒绝 loopback、link-local、RFC1918、云 metadata 和非预期端口;限制连接/读取超时、响应字节和 content type。业务请求不得用任意 `data_source_url` 绕过 External Adapter 的 SSRF 防线。
|
|
|
+
|
|
|
+### 8.6 Knowledge Agent
|
|
|
+
|
|
|
+旧 `search_knowledge` 数据源审查到 16 条知识记录。新 Adapter 冻结知识库版本、查询、命中 ID、内容 hash 和排名。知识库规模变化时,已有 Mission 仍按旧证据版本验证。
|
|
|
+
|
|
|
+### 8.7 结构化写工具
|
|
|
+
|
|
|
+复用范围包括 Paragraph、Element、Paragraph-Element relation、方向、领域信息、数据决策、参考记录等能力。所有写调用先经过:
|
|
|
+
|
|
|
+```python
|
|
|
+async def execute_candidate_write(
|
|
|
+ tool_name: str,
|
|
|
+ args: dict,
|
|
|
+ context: ProtectedAgentContext,
|
|
|
+) -> ToolResult:
|
|
|
+ workspace = await resolve_attempt_workspace(context)
|
|
|
+ await ensure_legacy_task_plan(workspace, context.task_id)
|
|
|
+ normalized = normalize_tool_args(tool_name, args)
|
|
|
+ result = await legacy_adapter.execute(
|
|
|
+ tool_name,
|
|
|
+ normalized,
|
|
|
+ script_build_id=workspace.script_build_id,
|
|
|
+ branch_id=workspace.branch_id,
|
|
|
+ )
|
|
|
+ return normalize_tool_result(result)
|
|
|
+```
|
|
|
+
|
|
|
+上一代 Implementer 对 `branch_id>0` 的第一次 Paragraph/Element 写入要求先有 `record_task_plan`。Adapter 自动创建 Task→PlanStep 兼容投影,不能把该历史门禁交给模型记忆。它只是旧表兼容记录,不成为新系统控制面。
|
|
|
+
|
|
|
+### 8.8 创作角色的只读工具矩阵
|
|
|
+
|
|
|
+| Preset | 允许的旧只读能力 | 产物/用途 | 禁止项 |
|
|
|
+|---|---|---|---|
|
|
|
+| Direction Worker | topic detail、persona points、accepted evidence、strategy snapshot | `ScriptDirectionArtifactV1` | live 输入、正式写入、外部搜索 |
|
|
|
+| Structure Worker | accepted direction、topic composition、section patterns、script snapshot | 段落结构候选 | 跨 Attempt branch、发布 |
|
|
|
+| Paragraph Worker | accepted direction/structure/evidence、persona points、reference detail | Paragraph 候选 | 未接受检索结果、其他候选最新值 |
|
|
|
+| Element Worker | 当前 Attempt Paragraph、accepted evidence、关系读取 | Element/Link 候选,含 commonality/topic_support/weight/support elements | branch0、状态更新 |
|
|
|
+| Compare Worker | 明确列出的 frozen candidate refs | 比较报告 | 自动合并、候选改写 |
|
|
|
+| Root Worker | `accepted_child_decision_ids` 闭合后的 frozen refs、输入快照 | `StructuredScriptArtifactV1` | 任意 latest 查询、正式发布 |
|
|
|
+
|
|
|
+产品方案附录列出的 57 个 Schema 资产要在实现前建立机器可读清单,逐项记录 `legacy_name → adapter_name → preset allowlist → capability → input schema → output schema → timeout → evidence/ref policy → implemented/tested`。未进入某一 preset 白名单的 Schema 即使文件存在也不可调用;当前约 38 个业务工具运行并集不是授权默认值。
|
|
|
+
|
|
|
+## 9. Attempt 候选隔离和因果绑定
|
|
|
+
|
|
|
+### 9.1 工作区分配
|
|
|
+
|
|
|
+```python
|
|
|
+async def resolve_attempt_workspace(context) -> CandidateWorkspace:
|
|
|
+ assert context.role == "worker"
|
|
|
+ binding = await binding_repo.require_by_root(context.root_trace_id)
|
|
|
+ version = await artifact_repo.get_or_create_for_attempt(
|
|
|
+ script_build_id=binding.script_build_id,
|
|
|
+ task_id=context.task_id,
|
|
|
+ attempt_id=context.attempt_id,
|
|
|
+ spec_version=context.spec_version,
|
|
|
+ )
|
|
|
+ return CandidateWorkspace.from_version(version)
|
|
|
+```
|
|
|
+
|
|
|
+不使用 `SELECT MAX(branch_id)+1`。先插入 `script_build_artifact_version` 获得数据库全局自增 ID,再把该 ID 作为 `branch_id>0`,从而并发无冲突。
|
|
|
+
|
|
|
+### 9.2 固定子任务输入
|
|
|
+
|
|
|
+框架在 Attempt 创建时写入:
|
|
|
+
|
|
|
+- `None`:升级前 Attempt 未记录,因果未知;
|
|
|
+- `()`:新 Attempt 明确没有直接子任务输入;
|
|
|
+- 非空 tuple:按直接子任务 `display_path` 顺序冻结其 ACCEPT Decision ID。
|
|
|
+
|
|
|
+业务 Worker 解析每个 Decision 时必须闭合:
|
|
|
+
|
|
|
+```text
|
|
|
+Decision 唯一且 action=ACCEPT
|
|
|
+→ Decision.task_id 是父 Task 的直接子 Task
|
|
|
+→ Decision.attempt_id 存在且归属正确
|
|
|
+→ Attempt.submission 存在
|
|
|
+→ Validation passed 且绑定同一 Attempt/Snapshot
|
|
|
+→ ArtifactSnapshot.sha256 与提交一致
|
|
|
+→ ArtifactRef 指向 frozen 业务版本且 digest 一致
|
|
|
+```
|
|
|
+
|
|
|
+字段为 `None` 的遗留 RUNNING Attempt 不允许扫描“当前子任务最新状态”猜输入,按 `PROTOCOL_VIOLATION` 进入正常 replan/retry。
|
|
|
+
|
|
|
+### 9.3 冻结
|
|
|
+
|
|
|
+Worker 调用 `submit_attempt` 前,Gateway 执行:
|
|
|
+
|
|
|
+1. 读 Attempt branch 的 Paragraph/Element/Link;
|
|
|
+2. 规范化为对应业务 Artifact;
|
|
|
+3. 校验内部 ID、排序和引用;
|
|
|
+4. 将 canonical JSON 写入 `script_build_artifact_version`;
|
|
|
+5. 计算 hash,状态改为 frozen;
|
|
|
+6. 构造 ArtifactRef 和 EvidenceRef;
|
|
|
+7. 再提交框架 Attempt manifest。
|
|
|
+
|
|
|
+freeze 后所有写 Adapter 必须拒绝该 attempt。repair/retry 创建新 Attempt 和新 version;即使框架允许 repair 续用 Worker Trace,也不能写旧 branch。
|
|
|
+
|
|
|
+框架提交顺序是先 freeze ArtifactSnapshot 再提交 Ledger,CAS/所有权失败时可能留下未绑定的 orphan Snapshot;业务侧同理可能先形成 frozen version、随后 `submit_attempt` 失败。Reconciler 以 `attempt_id + digest` 检查 Ledger:已绑定则保持 frozen;Attempt 仍可安全重试提交则只重放同一 manifest;Attempt 已终止或归属丢失则标记 business version 为 discarded。绝不把 orphan 自动挂到“最新 Attempt”,定期清理也必须保留审计期。
|
|
|
+
|
|
|
+## 10. MySQL 数据设计
|
|
|
+
|
|
|
+### 10.1 原则
|
|
|
+
|
|
|
+保留旧业务表,新增恰好四类业务表。使用编号、可回滚、带 checksum 的 SQL migration;不在运行时 `create_all()`。字符集、时区和引擎继承现有库规范。
|
|
|
+
|
|
|
+### 10.2 `script_build_mission_binding`
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE script_build_mission_binding (
|
|
|
+ id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|
|
+ script_build_id BIGINT NOT NULL,
|
|
|
+ root_trace_id VARCHAR(128) NOT NULL,
|
|
|
+ input_snapshot_id BIGINT NOT NULL,
|
|
|
+ active_direction_artifact_version_id BIGINT NULL,
|
|
|
+ accepted_root_artifact_version_id BIGINT NULL,
|
|
|
+ engine_version VARCHAR(64) NOT NULL,
|
|
|
+ schema_version VARCHAR(32) NOT NULL,
|
|
|
+ created_at DATETIME(6) NOT NULL,
|
|
|
+ updated_at DATETIME(6) NOT NULL,
|
|
|
+ UNIQUE KEY uq_binding_build (script_build_id),
|
|
|
+ UNIQUE KEY uq_binding_root (root_trace_id)
|
|
|
+);
|
|
|
+```
|
|
|
+
|
|
|
+该表只保存业务关联和当前正式指针,不保存 root_status、focused_task、pending count 或 Decision 副本。
|
|
|
+
|
|
|
+explicit 模式中的 Planner 主 Trace ID 就是 `root_trace_id`;不另存 `planner_trace_id`,避免制造双身份。Worker/Validator 子 Trace 通过框架 parent/root 关联查询。
|
|
|
+
|
|
|
+### 10.3 `script_build_input_snapshot`
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE script_build_input_snapshot (
|
|
|
+ id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|
|
+ script_build_id BIGINT NOT NULL,
|
|
|
+ version INT NOT NULL,
|
|
|
+ canonical_json JSON NOT NULL,
|
|
|
+ canonical_sha256 CHAR(64) NOT NULL,
|
|
|
+ prompt_manifest_json JSON NOT NULL,
|
|
|
+ schema_version VARCHAR(32) NOT NULL,
|
|
|
+ created_at DATETIME(6) NOT NULL,
|
|
|
+ UNIQUE KEY uq_input_version (script_build_id, version),
|
|
|
+ UNIQUE KEY uq_input_hash (script_build_id, canonical_sha256)
|
|
|
+);
|
|
|
+```
|
|
|
+
|
|
|
+### 10.4 `script_build_artifact_version`
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE script_build_artifact_version (
|
|
|
+ id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|
|
+ script_build_id BIGINT NOT NULL,
|
|
|
+ task_id VARCHAR(128) NOT NULL,
|
|
|
+ attempt_id VARCHAR(128) NOT NULL,
|
|
|
+ spec_version INT NOT NULL,
|
|
|
+ artifact_type VARCHAR(64) NOT NULL,
|
|
|
+ legacy_branch_id BIGINT NULL,
|
|
|
+ base_revision BIGINT NULL,
|
|
|
+ parent_artifact_version_id BIGINT NULL,
|
|
|
+ canonical_json JSON NULL,
|
|
|
+ canonical_sha256 CHAR(64) NULL,
|
|
|
+ state VARCHAR(16) NOT NULL,
|
|
|
+ created_at DATETIME(6) NOT NULL,
|
|
|
+ frozen_at DATETIME(6) NULL,
|
|
|
+ published_at DATETIME(6) NULL,
|
|
|
+ UNIQUE KEY uq_artifact_attempt (attempt_id),
|
|
|
+ UNIQUE KEY uq_artifact_branch (script_build_id, legacy_branch_id),
|
|
|
+ KEY ix_artifact_task (script_build_id, task_id)
|
|
|
+);
|
|
|
+```
|
|
|
+
|
|
|
+状态仅允许 `draft/frozen/published/discarded`。`canonical_json` 在 draft 可为空,freeze 后不可变。它保存候选正文版本,不复制框架 Task 状态。
|
|
|
+
|
|
|
+### 10.5 `script_build_publication`
|
|
|
+
|
|
|
+```sql
|
|
|
+CREATE TABLE script_build_publication (
|
|
|
+ id BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|
|
+ script_build_id BIGINT NOT NULL,
|
|
|
+ publication_type VARCHAR(16) NOT NULL,
|
|
|
+ accept_decision_id VARCHAR(128) NOT NULL,
|
|
|
+ artifact_version_id BIGINT NOT NULL,
|
|
|
+ expected_sha256 CHAR(64) NOT NULL,
|
|
|
+ state VARCHAR(16) NOT NULL,
|
|
|
+ attempt_count INT NOT NULL DEFAULT 0,
|
|
|
+ publication_revision BIGINT NOT NULL DEFAULT 0,
|
|
|
+ last_error_code VARCHAR(64) NULL,
|
|
|
+ last_error_summary VARCHAR(1000) NULL,
|
|
|
+ created_at DATETIME(6) NOT NULL,
|
|
|
+ updated_at DATETIME(6) NOT NULL,
|
|
|
+ published_at DATETIME(6) NULL,
|
|
|
+ UNIQUE KEY uq_publication_decision (accept_decision_id),
|
|
|
+ KEY ix_publication_build (script_build_id, publication_type, state)
|
|
|
+);
|
|
|
+```
|
|
|
+
|
|
|
+`publication_type` 为 `direction` 或 `final`。`last_error_summary` 必须脱敏。唯一 Decision 约束使重试幂等地发布同一 Artifact。
|
|
|
+
|
|
|
+## 11. 验证设计
|
|
|
+
|
|
|
+### 11.1 Retrieval Validator
|
|
|
+
|
|
|
+检查:
|
|
|
+
|
|
|
+- 工具和数据源与 Task 匹配;
|
|
|
+- query、账号、索引/知识版本记录完整;
|
|
|
+- source refs 可读取、digest 匹配;
|
|
|
+- summary 没有超出来源的确定性断言;
|
|
|
+- limitations 和空结果被如实表达;
|
|
|
+- 每个硬性 criterion 有结论和证据。
|
|
|
+
|
|
|
+### 11.2 Candidate Validator
|
|
|
+
|
|
|
+方向任务检查目标数量、选题引用、人设和策略依据、目标是否可验收;结构/段落任务检查层级、顺序、内容职责、元素关系、事实证据、重复与冲突;比较任务检查候选独立性和比较维度,不自动合并。
|
|
|
+
|
|
|
+### 11.3 Root Validator
|
|
|
+
|
|
|
+顺序:
|
|
|
+
|
|
|
+1. schema、digest、ID 和关系确定性预检;
|
|
|
+2. 确认 Root Attempt 绑定的直接 child ACCEPT Decisions;
|
|
|
+3. 检查 accepted direction 版本;
|
|
|
+4. 检查选题覆盖、叙事完整性、段落分工、元素落位;
|
|
|
+5. 检查事实/表达分离和证据闭合;
|
|
|
+6. 检查人设、风格、实用性和合规性;
|
|
|
+7. 运行旧详情 canonical projection dry-run;
|
|
|
+8. 输出逐 criterion 报告。
|
|
|
+
|
|
|
+Validator passed 仍不自动完成 Task;Planner 必须调用 ACCEPT Decision。
|
|
|
+
|
|
|
+## 12. 正式发布
|
|
|
+
|
|
|
+### 12.1 Publisher 接口
|
|
|
+
|
|
|
+```python
|
|
|
+class ScriptPublisher:
|
|
|
+ async def publish(
|
|
|
+ self,
|
|
|
+ root_trace_id: str,
|
|
|
+ accept_decision_id: str,
|
|
|
+ artifact_ref: ArtifactRef,
|
|
|
+ ) -> PublicationResult: ...
|
|
|
+
|
|
|
+ async def readback_and_verify(
|
|
|
+ self,
|
|
|
+ script_build_id: int,
|
|
|
+ expected_digest: str,
|
|
|
+ ) -> bool: ...
|
|
|
+```
|
|
|
+
|
|
|
+### 12.2 发布算法
|
|
|
+
|
|
|
+1. 一次读取 Mission Snapshot,定位 Root 最终 ACCEPT;
|
|
|
+2. 验证 Decision→Attempt→Validation→ArtifactSnapshot 闭合;
|
|
|
+3. 要求 Snapshot 恰有一个正式整稿 ArtifactRef;
|
|
|
+4. 从业务表读取 frozen version 并验证 digest;
|
|
|
+5. 检查 durable stop intent/execution epoch;已请求停止则不进入 publication;
|
|
|
+6. 插入或锁定 `script_build_publication`;
|
|
|
+7. 若已 published 且 digest 相同,直接返回成功;
|
|
|
+8. 复用 Mission OwnerLease,在 MySQL 事务中 `SELECT ... FOR UPDATE` 锁定 build/publication;
|
|
|
+9. 锁定后再次读取 stop intent/execution epoch;命中则 rollback,publication 保持 pending/failed,build 保持 stopping;
|
|
|
+10. 只替换该 `script_build_id + branch_id=0` 的 Paragraph/Element/Link,并更新计数、正式指针和 publication revision;
|
|
|
+11. **在同一事务、同一 Session 中**复用旧详情 repository 做 canonical readback 并比对 hash;
|
|
|
+12. mismatch 或读取异常立即 rollback,未验证正文不得对旧 GET 可见;
|
|
|
+13. digest 一致后、commit 前最后重检 stop intent/execution epoch;若发生变化,rollback 全部 branch0、digest、pointer 和 revision 写入;
|
|
|
+14. 无 stop 时在同一事务将 publication 标为 published、Artifact 标为 published、build 标为 success,然后 commit;
|
|
|
+15. commit 后再通过正常旧 HTTP/独立只读 Session 做健康读回;若此处异常,告警并进入一致性修复,不能生成新正文或新 ACCEPT;
|
|
|
+16. 后续重试永远使用同一 accept Decision 和 frozen version。
|
|
|
+
|
|
|
+本方案锁定“事务内 branch0 投影 + 同 Session 回读 + digest 门禁”实现,不在首版引入 shadow/active 双表方案。替换前精确锁定单个 build;任何删除都必须带显式 `script_build_id` 和 `branch_id=0` 条件,禁止 unresolved 变量、宽范围条件和跨 build 操作。
|
|
|
+
|
|
|
+### 12.3 状态映射
|
|
|
+
|
|
|
+```text
|
|
|
+Mission active → build running
|
|
|
+Stop 已请求、Operation 尚未终止 → build stopping
|
|
|
+Stop 已完成 → build stopped
|
|
|
+达到预算但存在经验证的可用结果 → build partial(必须写 error_message/剩余问题)
|
|
|
+Root 暂时 blocked、仍可恢复 → build running(阻塞原因放 summary/detail)
|
|
|
+Root 终局 blocked 或不可恢复失败 → build failed(blocked_reason 投影到 error_message)
|
|
|
+Root completed、publication 进行中 → build running;内部状态仅在 publication 表表达
|
|
|
+Publication failed → build failed,绝不是 success
|
|
|
+事务内 readback verified → build success
|
|
|
+```
|
|
|
+
|
|
|
+`ScriptBuildRecord.status` 只使用旧枚举 `running/stopping/success/failed/partial/stopped`。`pending/publishing/published/failed` 等发布细分只属于 `script_build_publication.state` 或 API detail,不扩展旧 status 字段。
|
|
|
+
|
|
|
+## 13. HTTP 与 SDK
|
|
|
+
|
|
|
+### 13.1 保持旧路由
|
|
|
+
|
|
|
+精确保留当前代码中的路由:
|
|
|
+
|
|
|
+| Method | Path | 兼容职责 |
|
|
|
+|---|---|---|
|
|
|
+| POST | `/api/pattern/script_builds` | 标准启动 |
|
|
|
+| POST | `/api/pattern/script_builds/parse_topic_json` | 解析上传 Topic JSON |
|
|
|
+| POST | `/api/pattern/script_builds/from_topic_json` | 从解析结果启动 |
|
|
|
+| POST | `/api/pattern/script_builds/{id}/retry` | 旧失败构建重试入口 |
|
|
|
+| GET | `/api/pattern/script_builds/{id}/prefill` | 取得重试/复制预填内容 |
|
|
|
+| DELETE | `/api/pattern/script_builds/{id}` | 软删除 |
|
|
|
+| PATCH | `/api/pattern/script_builds/{id}/favorite` | 收藏状态 |
|
|
|
+| GET | `/api/pattern/script_builds` | 列表 |
|
|
|
+| GET | `/api/pattern/script_builds/{id}` | 旧正式详情 |
|
|
|
+| GET | `/api/pattern/script_builds/{id}/log` | 旧日志投影 |
|
|
|
+| POST | `/api/pattern/script_builds/{id}/stop` | 请求停止,先进入 stopping |
|
|
|
+| POST | `/api/pattern/script_builds/{id}/resume` | 按 Root/publication 状态分支恢复 |
|
|
|
+| GET | `/api/pattern/script_builds/{id}/trace_messages` | 旧 Trace 消息投影 |
|
|
|
+| GET | `/api/pattern/script_builds/overview/{topic_build_id}` | Topic Build 下的概览 |
|
|
|
+| GET | `/script_build_detail/{id}` | 旧详情 HTML 入口,仅兼容、不在本期改 UI |
|
|
|
+
|
|
|
+请求和响应字段以旧黑盒 contract test 固化,新字段只能兼容追加。旧 start 和 retry 默认每次调用都创建新的 `script_build_record`,即使 body 相同也不能按 fingerprint 合并;同一个 `script_build_id` 内的 Mission 创建/命令仍按框架 request fingerprint 幂等。只有调用方显式提供可选 `Idempotency-Key` 时,HTTP 层才在该 endpoint/principal/有效期内复用响应。stop/resume 对同状态重复调用幂等;retry 重复调用默认仍是两次新构建。稳定错误为:请求/状态不合法 `400/409`,未认证 `401`,无权访问 `403`,不存在或为防枚举隐藏 `404`,内部执行错误 `500`;响应错误体包含稳定 `error_code`,不暴露路径、连接串和上游 token。
|
|
|
+
|
|
|
+### 13.2 新业务观测路由
|
|
|
+
|
|
|
+```http
|
|
|
+GET /api/pattern/script_builds/{id}/mission
|
|
|
+GET /api/pattern/script_builds/{id}/mission/events?after=&limit=
|
|
|
+GET /api/pattern/script_builds/{id}/tasks/{task_id}
|
|
|
+GET /api/pattern/script_builds/{id}/artifacts/{artifact_version_id}
|
|
|
+GET /api/pattern/script_builds/{id}/publication
|
|
|
+```
|
|
|
+
|
|
|
+这些接口通过 binding 查 `root_trace_id`,再用 `OrchestrationClient`/Coordinator 读取,不直接解析 ledger.json。Artifact 接口返回业务 canonical 内容时必须校验 build 归属,禁止任意 URI 文件读取。
|
|
|
+
|
|
|
+### 13.3 统一认证授权
|
|
|
+
|
|
|
+旧业务路由、新 Mission 路由、通用 V2、Trace detail 和 WebSocket 必须经过同一个 AuthN/AuthZ middleware:
|
|
|
+
|
|
|
+1. 验证调用主体并得到 principal/tenant;
|
|
|
+2. 先用 principal 校验 `script_build_id` 的读取或控制权限;
|
|
|
+3. 再从受权 binding 解析 `root_trace_id`;禁止调用方仅凭 root/task/trace ID 越权;
|
|
|
+4. task、attempt、validation、snapshot、artifact 和 trace 必须反向闭合到同一 build/root;
|
|
|
+5. WebSocket 在 upgrade 前鉴权,并在长连接期间执行权限撤销/过期策略;
|
|
|
+6. 审计允许/拒绝结果但不记录 credential。
|
|
|
+
|
|
|
+`root_trace_id`、`task_id` 和 Artifact URI 都不是权限凭证。黑盒测试必须覆盖未登录 401、跨租户 403/隐藏 404、跨 build Artifact/Trace、伪造 WebSocket 订阅和合法同 build 读取。
|
|
|
+
|
|
|
+### 13.4 通用 V2 路由
|
|
|
+
|
|
|
+Host composition 必须显式挂载当前框架的:
|
|
|
+
|
|
|
+```text
|
|
|
+/api/v2/capabilities
|
|
|
+/api/v2/roots/{root_trace_id}/snapshot
|
|
|
+/api/v2/roots/{root_trace_id}/completion
|
|
|
+/api/v2/roots/{root_trace_id}/snapshots/{snapshot_id}
|
|
|
+/api/v2/roots/{root_trace_id}/events
|
|
|
+Task / Attempt / Validation / Operation detail
|
|
|
+Trace query/detail/websocket
|
|
|
+```
|
|
|
+
|
|
|
+当前根 `agent/api_server.py` 不会自动挂载 orchestration router;必须在业务 Host 的 composition root `include_router(create_orchestration_router(coordinator))`。V2 Operation API 只能控制已存在 Task,不负责启动 Planner Mission,所以旧 start 路由仍由 `ScriptMissionService` 实现。
|
|
|
+
|
|
|
+### 13.5 客户端读取原则
|
|
|
+
|
|
|
+观测消费者优先调用:
|
|
|
+
|
|
|
+```python
|
|
|
+await client.get_mission_snapshot(root_trace_id)
|
|
|
+await client.get_root_completion(root_trace_id)
|
|
|
+await client.get_artifact_snapshot(root_trace_id, snapshot_id)
|
|
|
+await client.list_events(root_trace_id, cursor=cursor)
|
|
|
+await client.list_correlated_traces(
|
|
|
+ root_trace_id=root_trace_id,
|
|
|
+ task_id=task_id,
|
|
|
+ attempt_id=attempt_id,
|
|
|
+)
|
|
|
+```
|
|
|
+
|
|
|
+不得分别读取多个列表后自行假设属于同一 Ledger revision;完整状态用原子 Mission Snapshot。
|
|
|
+
|
|
|
+## 14. 一个真实输入驱动的 Agentic 示例
|
|
|
+
|
|
|
+### 14.1 启动
|
|
|
+
|
|
|
+以真实样本链路为参照,旧 `POST /api/pattern/script_builds` 的请求合同是:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "execution_id": 401,
|
|
|
+ "topic_build_id": 1189,
|
|
|
+ "topic_id": 1352,
|
|
|
+ "agent_type": "AigcAgent",
|
|
|
+ "agent_config": {"model_name": "<configured-model>"},
|
|
|
+ "data_source_url": "<configured-allowlisted-endpoint>",
|
|
|
+ "strategies_always_on": [],
|
|
|
+ "strategies_on_demand": []
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+`account_name` 不在旧 POST body 中;Host 从 `TopicBuildRecord.personal_config` 派生出真实账号“每天心理学”。Host 通过只读 Repository 读取完整 Topic/Points/Composition/Relations/Sources、人设点、Section Pattern、策略和 Prompt 实际版本,冻结 `input-454-v1`。Root objective 使用 `topic.result/topic_direction` 的规范摘要,只描述“为该账号和选题构建兼容正式结构化脚本”。
|
|
|
+
|
|
|
+### 14.2 动态规划
|
|
|
+
|
|
|
+Planner 首次检查输入后可能创建:
|
|
|
+
|
|
|
+```text
|
|
|
+T1 Decode:检索该账号关于损失厌恶/拖延决策的历史表达
|
|
|
+T2 Knowledge:核验“毛驴效应”定义和适用边界
|
|
|
+T3 Direction:综合选题、人设、策略与已接受证据形成方向
|
|
|
+```
|
|
|
+
|
|
|
+这只是一次可能决策,不是编码在后端的固定 Workflow。若 Topic 本身已有充分证据,Planner 可以不创建 External Task;若定义存在争议,可以再创建 Pattern 或 External Task。
|
|
|
+
|
|
|
+### 14.3 失败、修订、接受
|
|
|
+
|
|
|
+T1 v1 的 Decode 查询过窄,Validator 判定只找到弱相关片段。Planner 选择 revise:扩大 match_fields 并调整 keyword。T1 v2 返回可追溯命中,Validator passed,Planner ACCEPT。T3 Attempt 创建时冻结 T1 v2 和 T2 的 ACCEPT Decision ID;随后即使 T1 又产生实验版本,T3 也不会漂移。
|
|
|
+
|
|
|
+Direction Worker 输出三类结构化目标,可与旧样本的认知深度、实用落地、人设一致性对应。Validator 核对选题、人设、证据和可验收性,Planner ACCEPT 后 Host 发布 legacy markdown 投影到方向字段。
|
|
|
+
|
|
|
+### 14.4 创作与 Root
|
|
|
+
|
|
|
+Planner 根据方向建立结构/段落/元素任务;每个 Worker 写独立 Attempt branch。某段 Validator 发现“心理学概念被写成无条件事实”,Planner repair 该段而不是重跑整条流水线。已接受局部结果由综合任务吸收;Root Worker 只消费冻结的直接 child Decisions,产出 5 Paragraph、11 Element、13 Link 的候选只是示例,不是硬编码数量。
|
|
|
+
|
|
|
+Root Validator 通过后,Planner ACCEPT。Publisher 将同一 frozen Artifact 投影到 `branch_id=0`,旧详情回读得到相同 canonical digest 后才把状态设为 success。最终业务输出与旧版相同,过程不再依赖 Round 1/2 和 4 个固定 Branch。
|
|
|
+
|
|
|
+## 15. 三阶段实施计划
|
|
|
+
|
|
|
+### 阶段一:输入、Root、方向和取数闭环
|
|
|
+
|
|
|
+实现:
|
|
|
+
|
|
|
+- `script_build_host/` composition 和配置;
|
|
|
+- 四张业务表的 migration 基础版本;
|
|
|
+- InputSnapshotService 和真实旧数据 Adapter;
|
|
|
+- MissionFactory、MissionService.start/run/stop;
|
|
|
+- `script_planner`、Direction Worker、四个 Retrieval Worker;
|
|
|
+- Retrieval/Direction Validator;
|
|
|
+- Pattern、Decode、External、Knowledge、图片工具 Adapter;
|
|
|
+- 显式挂载 V2 Mission/Trace API;
|
|
|
+- 凭据轮换、读写账号分离、日志脱敏。
|
|
|
+
|
|
|
+暂不实现:Paragraph/Element 正式写入、正式发布、页面。
|
|
|
+
|
|
|
+验收:真实旧输入启动;输入 hash 稳定;Decode v1 fail→revise→v2 pass→ACCEPT;Direction Attempt 只消费固定 Decision;Root objective 可 revise;无 Round/multipath 固定计划;Worker 无法创建 Agent 或调用未授权写工具。
|
|
|
+
|
|
|
+### 阶段二:候选结构化创作
|
|
|
+
|
|
|
+实现:
|
|
|
+
|
|
|
+- ArtifactRepository 和 Attempt→version→branch 绑定;
|
|
|
+- Paragraph/Element/Link 等旧写工具 Adapter;
|
|
|
+- `record_task_plan` 自动兼容;
|
|
|
+- Structure/Paragraph/Element/Compare Worker;
|
|
|
+- Candidate Validator;
|
|
|
+- freeze、canonical JSON、digest 和 ArtifactRef;
|
|
|
+- repair/retry/revise 的新版本策略;
|
|
|
+- 业务 Artifact/Task 只读 API。
|
|
|
+
|
|
|
+验收:并行 Attempt 分配不同 branch;freeze 后不可写;repair 新建 version;Validator 只能读绑定 version;重复/乱序/跨任务/非 ACCEPT child Decision 被拒绝;旧 Element 扩展字段能力边界有测试。
|
|
|
+
|
|
|
+### 阶段三:Root、发布与恢复
|
|
|
+
|
|
|
+实现:
|
|
|
+
|
|
|
+- Root Worker 和 Root Validator;
|
|
|
+- ScriptPublisher 与 publication 幂等状态;
|
|
|
+- `branch_id=0` 事务投影、旧详情读回和 digest 门禁;
|
|
|
+- success 状态投影;
|
|
|
+- stop/resume/recover;
|
|
|
+- 单机单活锁与启动自检;
|
|
|
+- 全链路 Event/Trace 关联;
|
|
|
+- 旧 API 黑盒兼容 E2E。
|
|
|
+
|
|
|
+验收:Root ACCEPT 后模拟首次发布失败,状态不为 success;重试只发布同一 Artifact;读回一致后 success;Decision→Attempt→Validation→Snapshot→ArtifactVersion→Publication→Trace 全闭合;进程重启不猜测遗留 RUNNING Attempt。
|
|
|
+
|
|
|
+## 16. 测试方案
|
|
|
+
|
|
|
+### 16.1 单元测试
|
|
|
+
|
|
|
+- canonical JSON 和 digest 稳定;
|
|
|
+- Topic/Persona/Strategy/Prompt 快照完整;
|
|
|
+- Root TaskSpec 不包含固定 Workflow;
|
|
|
+- Gateway 身份从 protected context 获取;
|
|
|
+- branch ID 并发唯一;
|
|
|
+- frozen version 拒写;
|
|
|
+- ArtifactRef/build/task/attempt 归属检查;
|
|
|
+- Direction 和 StructuredScript schema;
|
|
|
+- Validator criterion 覆盖;
|
|
|
+- Publisher 幂等和 readback mismatch;
|
|
|
+- OwnerLease token 交接、嵌套 finalize 不重入加锁、重复 start/resume/finalize 的稳定 409;
|
|
|
+- 旧六状态映射,尤其 stopping、partial、Root completed+publication failed;
|
|
|
+- Legacy Detail Projection 的 topic/decision_traces/post_datas/script_datas/build_workflow 和 Paragraph 内嵌关系;
|
|
|
+- principal→build/root/task/artifact/trace 权限闭合与 401/403/404;
|
|
|
+- 日志脱敏、URL allowlist 和图片限制。
|
|
|
+
|
|
|
+### 16.2 集成测试
|
|
|
+
|
|
|
+- MySQL migration 前进/回滚/checksum;
|
|
|
+- 旧 Topic/Persona 文件和 DB 混合读取;
|
|
|
+- Pattern polling timeout;
|
|
|
+- Decode 索引版本和空命中;
|
|
|
+- External redirect/SSRF/超限;
|
|
|
+- Knowledge 版本冻结;
|
|
|
+- Attempt branch 写、freeze、repair;
|
|
|
+- FileStore reload 和 operation recovery;
|
|
|
+- `stop` 与 active run/finalize 竞态:先 stopping、只发 intent,不争夺 lease;Publisher 三次检查 intent/epoch,命中后 branch0、digest、publication revision 均不变化;
|
|
|
+- 生产 Planner 只能通过 `dispatch_script_tasks` 创建 durable Operation,同步 dispatch 工具不可见;
|
|
|
+- 旧详情 canonical readback,包括 Element 扩展字段和全部辅助字段;
|
|
|
+- 同事务 branch0 projection+readback mismatch rollback;
|
|
|
+- frozen business version/ArtifactSnapshot orphan reconcile;
|
|
|
+- V2/Trace/WebSocket 共用授权策略。
|
|
|
+
|
|
|
+### 16.3 黑盒 E2E
|
|
|
+
|
|
|
+1. 只通过旧公开入口提交真实格式输入;
|
|
|
+2. Host 冻结选题、人设、策略和 Prompt;
|
|
|
+3. Planner 动态创建取数任务;
|
|
|
+4. Child v1 验证失败并 revise;
|
|
|
+5. Child v2 通过并 ACCEPT;
|
|
|
+6. Root objective revise;
|
|
|
+7. 创作 Worker 写 Attempt 专属候选;
|
|
|
+8. Root Worker 消费冻结的 Child ACCEPT Decisions;
|
|
|
+9. Root Validator 通过,Planner ACCEPT;
|
|
|
+10. 第一次发布故障不产生 success;
|
|
|
+11. 同一 Artifact 重试发布;
|
|
|
+12. 旧详情返回 Paragraph/Element/Link、Element 扩展字段、topic、decision_traces、post_datas、script_datas、build_workflow 和 Paragraph 内嵌关系;
|
|
|
+13. 消费端只使用公开 API/SDK 读取 Mission、Completion、Artifact、Event 和 Trace;
|
|
|
+14. 未认证、跨 tenant、跨 build Artifact/Trace/WS 被拒绝;
|
|
|
+15. 响应中无业务之外的 Script Workflow/Round/Page 通用节点。
|
|
|
+
|
|
|
+### 16.4 真实基线回归
|
|
|
+
|
|
|
+以 Run 454 的 5 Paragraph、11 Element、13 Link 作为“旧详情可表达性”样本,而不是新模型必须逐字复现的金标。回归比较:
|
|
|
+
|
|
|
+- 输入字段覆盖率;
|
|
|
+- 输出 schema 和关系可读性;
|
|
|
+- 方向三类目标的可表示性;
|
|
|
+- 事实引用闭合率;
|
|
|
+- 人设/选题/策略 criterion 覆盖;
|
|
|
+- 旧接口和状态兼容;
|
|
|
+- Agentic 失败修订和因果冻结。
|
|
|
+
|
|
|
+## 17. 运行、观测与告警
|
|
|
+
|
|
|
+默认 Event 真源是 TaskStore durable journal,不默认写重复 `orchestration/events.jsonl`。业务告警基于 Event cursor 和 publication 状态:
|
|
|
+
|
|
|
+```text
|
|
|
+Attempt/Validation 超时
|
|
|
+连续 repair/retry 超预算
|
|
|
+Root 长时间无进展
|
|
|
+Artifact digest mismatch
|
|
|
+publication failed
|
|
|
+legacy readback mismatch
|
|
|
+FileStore revision conflict
|
|
|
+外部取数超时/被安全策略拒绝
|
|
|
+```
|
|
|
+
|
|
|
+Trace 查询必须带 `root_trace_id`,可进一步按 `agent_role`、`task_id`、`attempt_id`、`validation_id`、`operation_id` 过滤。详情和 WebSocket 使用过滤后 limit,不能先截 1000 条再查目标。
|
|
|
+
|
|
|
+## 18. 明确不做
|
|
|
+
|
|
|
+- 不实现 SQL TaskStore、SQL ArtifactSnapshot Store 或分布式 Operation Queue;
|
|
|
+- 不让多个 Host 并发驱动同一 Root;
|
|
|
+- 不修改通用模型加入脚本字段;
|
|
|
+- 不复制 Ledger 到业务状态表;
|
|
|
+- 不让 Agent 直接写 `branch_id=0` 或 status=success;
|
|
|
+- 不保留固定 Round/Branch/multipath 作为控制流程;
|
|
|
+- 不把 57 个 Schema 全量授权给任一角色;
|
|
|
+- 不把 Planner 当长文本共同写作者;
|
|
|
+- 不在本期修改 HTML、visualization 或新增页面;
|
|
|
+- 不把真实凭据写入配置、文档、Trace 或测试 fixture。
|
|
|
+
|
|
|
+## 19. 交付定义
|
|
|
+
|
|
|
+阶段三结束时,业务团队获得的是一个可装配的 Agentic Script Host:输入、取数和正式输出仍兼容上一代;主 Agent 持续围绕 Root 宏观目标规划;专业 Worker 只在受控工作区执行;Validator 独立核验固定版本;Planner 对报告做正式决策;Root 接受后由确定性 Publisher 发布并回读。任何一层失败都有可恢复状态和可追踪证据,而不会通过扫描“最新数据”或复用未验证结果掩盖因果缺口。
|
|
|
+
|
|
|
+这套方案以当前已完成的通用 Agent 框架为控制内核,以旧业务数据和工具 Adapter 为能力面,以四张 MySQL 业务表为冻结与发布边界,以 FileStore 单机单活为明确运行前提。它替换的是 Workflow,不替换业务输入输出,也不建立第二套 Mission 真相。
|