docs: 20-task-type-architecture.md v2.0 - 新增 §11-§13 PromptSection 模式
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: "TaskTypeRegistry + Handler 架构重构"
|
||||
created: 2026-06-10
|
||||
version: v1.0
|
||||
version: v2.0
|
||||
---
|
||||
|
||||
# §1 现状分析
|
||||
@@ -121,6 +121,14 @@ class TaskTypeHandler(Protocol):
|
||||
def check_completion(self, task_id: str, db_path: Path) -> bool:
|
||||
"""检查任务是否已完成(如 mail 的回复检查)。"""
|
||||
...
|
||||
|
||||
def get_sections(self) -> list['PromptSection']:
|
||||
"""返回此 handler 的 prompt section 列表。
|
||||
|
||||
返回有序的 PromptSection 列表,由 PromptComposer 统一拼装。
|
||||
build_prompt 可使用此列表自动拼装,也可 override 做自定义(向后兼容)。
|
||||
"""
|
||||
...
|
||||
```
|
||||
|
||||
**设计原则**:
|
||||
@@ -319,41 +327,42 @@ for vp in TaskTypeRegistry.virtual_projects():
|
||||
|
||||
按风险从低到高排列,每步完成后跑 `pytest -m "not e2e"` 全量回归测试。
|
||||
|
||||
### Step 1:注册表基础设施
|
||||
### Step 1:注册表 + PromptComposer 基础设施
|
||||
|
||||
- 新建 `src/daemon/task_type_registry.py`
|
||||
- 定义 `TaskTypeHandler` Protocol
|
||||
- 定义 `TaskTypeRegistry` 类
|
||||
- 编写单元测试验证注册/查询机制
|
||||
- 新建 `src/daemon/task_type_registry.py`:`TaskTypeHandler` Protocol + `TaskTypeRegistry`
|
||||
- 新建 `src/daemon/prompt_composer.py`:`PromptSection` Protocol + `PromptContext` + `PromptComposer`
|
||||
- 编写单元测试验证:注册/查询、section 排序/去重/条件过滤
|
||||
- **风险**:极低,纯新增文件,不改动现有代码
|
||||
|
||||
### Step 2:TaskHandler
|
||||
|
||||
- 新建 `src/daemon/task_handler.py`
|
||||
- 从 spawner/dispatcher 的 default 分支封装 handler 方法
|
||||
- 实现 5 个 section(TaskContext / PriorOutputs / RoleSkill / TaskApi / TaskConstraints)
|
||||
- `build_prompt` 内部用 PromptComposer 拼装
|
||||
- 注册到 TaskTypeRegistry
|
||||
- 运行全量回归测试,验证普通任务路径不变
|
||||
- **风险**:低,只是把现有逻辑包一层,不改行为
|
||||
- **风险**:低,现有 BootstrapBuilder 逻辑包一层
|
||||
|
||||
### Step 3:ToolchainHandler
|
||||
|
||||
- 新建 `src/daemon/toolchain_handler.py`
|
||||
- 全新实现,无迁移成本
|
||||
- 实现 3 个 section(ToolchainContext / ToolchainApi / ToolchainConstraints)
|
||||
- 注册到 TaskTypeRegistry
|
||||
- **风险**:低,全新代码,不影响现有路径
|
||||
- **风险**:低,全新代码
|
||||
|
||||
### Step 4:MailHandler
|
||||
|
||||
- 新建 `src/daemon/mail_handler.py`
|
||||
- 实现 3 个 section(MailContext / MailApi / MailConstraints)
|
||||
- 从 dispatcher / spawner / ticker 三处迁移 mail 逻辑
|
||||
- 注册到 TaskTypeRegistry
|
||||
- 重点回归测试 mail 路径:发送、回复、重试、幻觉门控
|
||||
- **风险**:中,逻辑从三处集中,需确保行为一致
|
||||
- **风险**:中
|
||||
|
||||
### Step 5:引擎清理
|
||||
|
||||
- 删除 dispatcher / spawner / ticker 中的旧 if/else 分支
|
||||
- 统一走 handler 路径
|
||||
- 删除或保留 BootstrapBuilder(作为 TaskContextSection 的内部实现)
|
||||
- 全量回归测试 + 手工验证
|
||||
- **风险**:中,删除代码需确保无遗漏
|
||||
|
||||
@@ -408,15 +417,221 @@ for vp in TaskTypeRegistry.virtual_projects():
|
||||
|
||||
---
|
||||
|
||||
# §11 Prompt 构建现状分析
|
||||
|
||||
当前系统的 prompt 构建有四条独立路径,散落在三个文件中:
|
||||
|
||||
| 路径 | 位置 | 结构 | 服务对象 |
|
||||
|------|------|------|----------|
|
||||
| BootstrapBuilder 4 段 | `bootstrap.py` | 任务上下文 → 前序产出 → 角色规范(Skill全文) → 硬约束 | 普通任务 |
|
||||
| Mail inform 模板 | `spawner.py` MAIL_INFORM_TEMPLATE | from/to/title/text 纯文本 | mail 通知 |
|
||||
| Mail request 模板 | `spawner.py` MAIL_REQUEST_TEMPLATE | from/to/title/text + API 指令 | mail 请求 |
|
||||
| Toolchain 模板 | `toolchain_templates.py` + `templates/toolchain/*.md` | 5 个 md 文件占位符渲染 | 工具链事件 |
|
||||
|
||||
此外 `_build_api_section` 在 spawner 中为所有路径拼 API 操作指令,但 success_status 不同(mail="done",其他="review")。
|
||||
|
||||
**问题**:
|
||||
|
||||
1. **四条路径完全独立**,共性逻辑(API 指令、约束注入)重复实现
|
||||
2. **新增 task type 需要理解所有路径**才能加入
|
||||
3. **没有统一的 token 预算管理**
|
||||
4. **段的顺序硬编码**在各自的拼装逻辑中
|
||||
|
||||
---
|
||||
|
||||
# §12 PromptSection 模式
|
||||
|
||||
基于知识库优秀实践(Hermes 10层有序注入、Microsoft 三层中间件、我们自己的四层加载架构),引入 PromptSection 模式。
|
||||
|
||||
## 核心思想
|
||||
|
||||
把 prompt 拆成有序的 section 列表,handler 声明自己需要哪些 section,PromptComposer 统一拼装。
|
||||
|
||||
## PromptSection 协议
|
||||
|
||||
```python
|
||||
class PromptSection(Protocol):
|
||||
"""一个 prompt 段"""
|
||||
name: str # 段名(去重用,同名覆盖)
|
||||
priority: int # 排序优先级(小数字=靠前)
|
||||
|
||||
def render(self, context: PromptContext) -> str:
|
||||
"""渲染此段的文本内容
|
||||
|
||||
Args:
|
||||
context: 包含 task_id, title, description, must_haves,
|
||||
project_id, agent_id, task, role 等信息的上下文对象
|
||||
Returns:
|
||||
此段的文本内容(可以为空字符串表示不注入)
|
||||
"""
|
||||
...
|
||||
|
||||
def should_include(self, context: PromptContext) -> bool:
|
||||
"""是否注入此段(默认 True,条件段可覆盖)
|
||||
|
||||
例如:前序产出段只在有 depends_on 时注入
|
||||
"""
|
||||
return True
|
||||
```
|
||||
|
||||
## PromptContext 数据对象
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class PromptContext:
|
||||
"""Prompt 渲染的统一上下文"""
|
||||
task_id: str
|
||||
title: str
|
||||
description: str
|
||||
must_haves: str
|
||||
project_id: str
|
||||
agent_id: str
|
||||
task: Optional[Dict] = None
|
||||
role: str = "executor"
|
||||
spawn_type: str = "executor"
|
||||
# mail 专用
|
||||
from_agent: str = ""
|
||||
mail_type: str = "" # inform / request
|
||||
# toolchain 专用
|
||||
event_type: str = "" # ci_failure / review_request / ...
|
||||
event_data: Dict = field(default_factory=dict)
|
||||
# 前序产出
|
||||
depends_on_outputs: Optional[List] = None
|
||||
```
|
||||
|
||||
## PromptComposer 拼装器
|
||||
|
||||
```python
|
||||
class PromptComposer:
|
||||
"""有序拼装 prompt sections"""
|
||||
|
||||
def __init__(self):
|
||||
self._sections: List[PromptSection] = []
|
||||
|
||||
def add(self, section: PromptSection) -> None:
|
||||
"""添加一个 section(同名覆盖)"""
|
||||
self._sections = [s for s in self._sections if s.name != section.name]
|
||||
self._sections.append(section)
|
||||
|
||||
def add_many(self, sections: List[PromptSection]) -> None:
|
||||
"""批量添加"""
|
||||
for s in sections:
|
||||
self.add(s)
|
||||
|
||||
def compose(self, context: PromptContext) -> str:
|
||||
"""拼装最终 prompt
|
||||
|
||||
1. 过滤 should_include=False 的段
|
||||
2. 按 priority 排序
|
||||
3. 逐段 render
|
||||
4. 用分隔符连接
|
||||
5. Token 预算警告(不截断)
|
||||
"""
|
||||
active = [s for s in self._sections if s.should_include(context)]
|
||||
active.sort(key=lambda s: s.priority)
|
||||
parts = [s.render(context) for s in active]
|
||||
parts = [p for p in parts if p.strip()] # 过滤空段
|
||||
return "\n\n---\n\n".join(parts)
|
||||
```
|
||||
|
||||
## Section 优先级约定
|
||||
|
||||
| 优先级范围 | 用途 | 示例 |
|
||||
|------------|------|------|
|
||||
| 10-19 | 任务上下文 | 任务标题/描述、Mail 内容、Toolchain 事件 |
|
||||
| 20-29 | 前序信息 | depends_on 产出、handoff comment |
|
||||
| 30-39 | 角色规范 | Skill 全文注入、工具链行为指引 |
|
||||
| 40-49 | API 操作指令 | 状态回写、curl 示例 |
|
||||
| 50-59 | 硬约束 | 安全红线、禁止行为 |
|
||||
| 60-69 | 扩展段 | 保留给未来使用 |
|
||||
|
||||
---
|
||||
|
||||
# §13 三个 Handler 的 Section 注册
|
||||
|
||||
每个 handler 通过 `get_sections()` 声明自己需要的 section 列表。
|
||||
|
||||
## TaskHandler sections
|
||||
|
||||
```python
|
||||
def get_sections(self) -> list[PromptSection]:
|
||||
return [
|
||||
TaskContextSection(priority=10), # BootstrapBuilder 段 1
|
||||
PriorOutputsSection(priority=20), # BootstrapBuilder 段 2(有 depends_on 时)
|
||||
RoleSkillSection(priority=30), # BootstrapBuilder 段 3(Skill 全文)
|
||||
TaskApiSection(priority=40), # API 操作指令,success_status="review"
|
||||
TaskConstraintsSection(priority=50), # 硬约束
|
||||
]
|
||||
```
|
||||
|
||||
| Section | 来源 | 共性/个性 |
|
||||
|---------|------|------------|
|
||||
| TaskContextSection | BootstrapBuilder 段 1 | 个性:title/desc/must_haves 格式 |
|
||||
| PriorOutputsSection | BootstrapBuilder 段 2 | 个性:只有 task 有 depends_on |
|
||||
| RoleSkillSection | BootstrapBuilder 段 3 | 个性:只有 task 读 Skill 全文 |
|
||||
| TaskApiSection | spawner `_build_api_section` | **共性基础 + 个性参数**(success_status) |
|
||||
| TaskConstraintsSection | BootstrapBuilder 段 4 | 个性:每种 task 约束不同 |
|
||||
|
||||
## MailHandler sections
|
||||
|
||||
```python
|
||||
def get_sections(self) -> list[PromptSection]:
|
||||
return [
|
||||
MailContextSection(priority=10), # from/to/title/text,区分 inform/request
|
||||
MailApiSection(priority=40), # API 操作指令,success_status="done"
|
||||
MailConstraintsSection(priority=50), # 硬约束(禁止状态转换命令等)
|
||||
]
|
||||
```
|
||||
|
||||
| Section | 来源 | 共性/个性 |
|
||||
|---------|------|------------|
|
||||
| MailContextSection | MAIL_INFORM_TEMPLATE / MAIL_REQUEST_TEMPLATE | 个性:邮件格式 |
|
||||
| MailApiSection | spawner `_build_api_section` 变体 | **共性基础 + 个性参数**(success_status="done",含 Mail API 指令) |
|
||||
| MailConstraintsSection | 模板中的 ⚠️ 约束 | 个性 |
|
||||
|
||||
## ToolchainHandler sections
|
||||
|
||||
```python
|
||||
def get_sections(self) -> list[PromptSection]:
|
||||
return [
|
||||
ToolchainContextSection(priority=10), # 事件类型 + 事件详情
|
||||
ToolchainApiSection(priority=40), # API 操作指令,success_status="done"
|
||||
ToolchainConstraintsSection(priority=50), # 硬约束
|
||||
]
|
||||
```
|
||||
|
||||
| Section | 来源 | 共性/个性 |
|
||||
|---------|------|------------|
|
||||
| ToolchainContextSection | toolchain_templates.py + md 文件 | 个性:事件格式 |
|
||||
| ToolchainApiSection | spawner `_build_api_section` 变体 | **共性基础 + 个性参数** |
|
||||
| ToolchainConstraintsSection | 新增 | 个性 |
|
||||
|
||||
## Section 复用分析
|
||||
|
||||
| Section | task | mail | toolchain | 是否可复用 |
|
||||
|---------|------|------|-----------|-------------|
|
||||
| *ContextSection | ✅ | ✅ | ✅ | ❌ 格式完全不同,各自实现 |
|
||||
| *ApiSection | ✅ | ✅ | ✅ | ⚠️ 基础框架可复用(BaseApiSection),success_status 参数化 |
|
||||
| *ConstraintsSection | ✅ | ✅ | ✅ | ❌ 约束内容不同,各自实现 |
|
||||
| PriorOutputsSection | ✅ | ❌ | ❌ | 仅 task |
|
||||
| RoleSkillSection | ✅ | ❌ | ❌ | 仅 task |
|
||||
|
||||
**结论**:ApiSection 可以抽一个 BaseApiSection(curl 模板 + success_status 参数),其余 section 各自实现。
|
||||
|
||||
---
|
||||
|
||||
## 附录:文件结构预览
|
||||
|
||||
```
|
||||
src/daemon/
|
||||
├── task_type_registry.py # §3 + §4:Protocol + Registry
|
||||
├── task_handler.py # §5 TaskHandler
|
||||
├── mail_handler.py # §5 MailHandler
|
||||
├── toolchain_handler.py # §5 ToolchainHandler
|
||||
├── dispatcher.py # §6 改动:handler 查询替代 if/else
|
||||
├── spawner.py # §6 改动:handler 查询替代 if/else
|
||||
└── ticker.py # §6 改动:自动发现虚拟项目
|
||||
├── prompt_composer.py # §12 PromptSection + PromptContext + PromptComposer
|
||||
├── task_handler.py # §13 TaskHandler + 5 sections
|
||||
├── mail_handler.py # §13 MailHandler + 3 sections
|
||||
├── toolchain_handler.py # §13 ToolchainHandler + 3 sections
|
||||
├── dispatcher.py # §6 改动
|
||||
├── spawner.py # §6 改动
|
||||
├── ticker.py # §6 改动
|
||||
├── bootstrap.py # 保留,TaskContextSection 内部调用
|
||||
└── toolchain_templates.py # 保留,ToolchainContextSection 内部调用
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user