fix(design): 修复 Codex 审查发现的 5 项问题
- C1: 13 个 skill(非 14) - C2: factory 从 noop fallback 改为 fail-fast 校验 - I1: 新增 InfraSettings(BaseSettings) 工程配置模型 - I2: 显式 supersede 搜索模块设计的 prompt 路径约定 - I3: Protocol 返回类型精确化 - I4: dispatch 对缺失 session_id 显式 raise Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,7 +18,7 @@ created: 2026-07-09
|
||||
| `app/harness/deps_router.py` | 按 video_id 懒加载 InferenceDeps 的路由器 |
|
||||
| `app/ports.py` 扩展 | 新增 `ToolDispatchFactory` / `PromptBuilderFactory` Protocol |
|
||||
| `app/harness/runner.py` 小改 | `__init__` 注入 factory,替换 noop 占位 |
|
||||
| `store/skills/v1/` | 14 个 skill(从 TRM4 v1 精简 + 注入 TRM5 card 字段) |
|
||||
| `store/skills/v1/` | 13 个 skill(从 TRM4 v1 精简 + 注入 TRM5 card 字段) |
|
||||
| `store/prompts/v1/` | 目录重组(从 `store/prompts/` 扁平结构迁入) |
|
||||
| 配置变更 | concurrency=24, max_steps=40, breaker_threshold=48 |
|
||||
|
||||
@@ -100,43 +100,90 @@ class InferenceDepsRouter:
|
||||
|
||||
### 2.3 Runner 改动
|
||||
|
||||
`__init__` 新增 2 个可选参数(向后兼容):
|
||||
`__init__` 新增 2 个可选参数,按 mode 做 fail-fast 校验:
|
||||
|
||||
```python
|
||||
def __init__(self, config, *, llm, evolve_llm, vlm, telemetry,
|
||||
tool_dispatch_factory=None,
|
||||
prompt_builder_factory=None):
|
||||
# mode in {"infer", "eval", "train"} 时 factory 为 None → 立即 ValueError
|
||||
if config.mode in {"infer", "eval", "train"}:
|
||||
if tool_dispatch_factory is None or prompt_builder_factory is None:
|
||||
raise ValueError(
|
||||
f"mode={config.mode} 需要 tool_dispatch_factory 和 prompt_builder_factory"
|
||||
)
|
||||
```
|
||||
|
||||
`_make_tool_dispatch_fn` / `_make_prompt_builder` 优先用注入值,缺省保留 noop fallback。
|
||||
`_make_tool_dispatch_fn` / `_make_prompt_builder` 优先用注入值。测试场景可传 mock factory。
|
||||
|
||||
### 2.4 Protocol 定义
|
||||
|
||||
`app/ports.py` 新增:
|
||||
`app/ports.py` 新增精确类型的 Protocol:
|
||||
|
||||
```python
|
||||
class ToolDispatchFn(Protocol):
|
||||
"""工具调度函数签名。"""
|
||||
async def __call__(
|
||||
self, tool_name: str, args: dict[str, Any], *, context: dict[str, Any]
|
||||
) -> str: ...
|
||||
|
||||
class ToolDispatchFactory(Protocol):
|
||||
def __call__(self, *, skills_dir: Path | None = None) -> Callable[..., Any]: ...
|
||||
"""per-version 工具调度工厂。"""
|
||||
def __call__(self, *, skills_dir: Path | None = None) -> ToolDispatchFn: ...
|
||||
|
||||
class PromptBuilderFn(Protocol):
|
||||
"""Prompt 构建函数签名。"""
|
||||
def __call__(self, qa: GeneratedQuestion) -> tuple[str, str]: ...
|
||||
|
||||
class PromptBuilderFactory(Protocol):
|
||||
"""per-version prompt 构建工厂。"""
|
||||
def __call__(self, *, skills_dir: Path | None = None,
|
||||
prompts_dir: Path | None = None
|
||||
) -> Callable[[GeneratedQuestion], tuple[str, str]]: ...
|
||||
prompts_dir: Path | None = None) -> PromptBuilderFn: ...
|
||||
```
|
||||
|
||||
### 2.5 main.py 结构
|
||||
### 2.5 InferenceDepsRouter dispatch 防御
|
||||
|
||||
Router 的 dispatch 函数对缺失/未知 `session_id` 显式 raise 带诊断信息的 `KeyError`:
|
||||
|
||||
```python
|
||||
async def _dispatch(tool_name, args, *, context):
|
||||
session_id = context.get("session_id")
|
||||
if not session_id or session_id not in self._qid_to_vid:
|
||||
raise KeyError(
|
||||
f"未注册的 session_id={session_id!r},"
|
||||
f"已注册 {len(self._qid_to_vid)} 条映射"
|
||||
)
|
||||
...
|
||||
```
|
||||
|
||||
### 2.6 main.py 结构
|
||||
|
||||
使用 argparse(复用 `RunConfig` + `load_config()` 的 YAML/CLI 三层合并逻辑)。
|
||||
|
||||
适配器参数通过 `InfraSettings(BaseSettings)` 从 `.env` 加载(遵循 CLAUDE.md §4.5 pydantic-settings 规范),禁止 main.py 直接散读环境变量:
|
||||
|
||||
```python
|
||||
def _build_parser(): # CLI 参数定义,与 TRM4 main.py 保持一致
|
||||
def _build_adapters(): # 从 .env 构建全套 adapters,返回 NamedTuple
|
||||
def _log_result(): # 输出推理结果摘要
|
||||
def main(): # Composition Root:load_config → adapters → router → runner
|
||||
class InfraSettings(BaseSettings):
|
||||
"""工程配置(少变/敏感),从 .env 加载。"""
|
||||
search_llm_model: str
|
||||
search_llm_base_url: str
|
||||
search_llm_api_key: str
|
||||
vl_llm_model: str
|
||||
# ... 其余 LLM/VLM/Redis/OCR/timeout/breaker 字段
|
||||
model_config = SettingsConfigDict(env_file=".env")
|
||||
|
||||
def _build_adapters(settings: InfraSettings) -> _Adapters:
|
||||
# 从 settings 注入构建全套 adapters
|
||||
...
|
||||
|
||||
def _log_result(result): # 输出推理结果摘要
|
||||
def main(): # Composition Root:load_config → settings → adapters → router → runner
|
||||
```
|
||||
|
||||
本次只实现 `mode == "infer"` 分支,其余模式 `raise SystemExit("尚未实现")`。
|
||||
|
||||
> **Supersede 声明**:本设计的 `store/prompts/v1/` 版本化目录结构替代了 `2026-07-07-search-module-design.md` 中 `store/prompts/` 扁平结构的约定。`PromptManager(prompts_dir)` 今后总接收具体版本目录(`store/prompts/v1` 或 workspace 内 `prompts/vN`),不再接收 `store/prompts`。
|
||||
|
||||
## 3. 初始 Prompt 集
|
||||
|
||||
### 3.1 设计原则
|
||||
@@ -153,7 +200,7 @@ def main(): # Composition Root:load_config → adapters → rou
|
||||
| 类别 | 是否进化 | v1 来源 | 处理 |
|
||||
|------|---------|---------|------|
|
||||
| system.md | 微量 | TRM5 现有版本 | 保留(已含 card 字段说明,是基础设施) |
|
||||
| skills/v1/ (14个) | 主力 | TRM4 v1 精简 + TRM5 注入 | 见 §3.3 |
|
||||
| skills/v1/ (13个) | 主力 | TRM4 v1 精简 + TRM5 注入 | 见 §3.3 |
|
||||
| extract/verify (8个) | 不变 | TRM5 现有版本 | 保留(已适配 card 结构) |
|
||||
|
||||
### 3.3 Skills v1 内容策略
|
||||
@@ -209,7 +256,7 @@ store/
|
||||
view_node_children_extract.md
|
||||
view_node_children_verify.md
|
||||
skills/
|
||||
v1/ ← 新建(14 个文件)
|
||||
v1/ ← 新建(13 个文件)
|
||||
default-strategy.md
|
||||
action-reasoning.md
|
||||
action-recognition.md
|
||||
|
||||
Reference in New Issue
Block a user