feat(core/evolution): protocols.py + types.py 基础层 — 18 个 dataclass + 3 个 Protocol

TRM4 诊断/进化/门控数据类型迁移至 TRM5 Clean Architecture 内核。
逐字段比对 TRM4 的 eprocess.py、diagnose.py、evolve.py 保真迁移。

types.py (18 个 dataclass):
- Gate: GateParams, GateVerdict (frozen, 原样迁移)
- 诊断: SpanMetrics, SkillStepAdherence, QuestionMetrics,
  ErrorAttribution, CaseSample, SkillCasePack, SystemCasePack,
  ToolCasePack, DiagnosisResult (全部 frozen=True)
- 进化: EvolutionRecord (mutable), RejectedEdit (frozen),
  EvolutionResult (frozen, 移除 skills_version/prompts_version)
- 新增: PairResult, QuadrantClassification (块验证纯决策输出)
- 新增: DiagnosePrompts, EvolvePrompts (模板束, frozen)

protocols.py (3 个只读 Protocol):
- SkillStore, PromptStore (同步文件读取)
- RunLog (异步日志查询, 隔离 SQL)

变更理由:
- QuestionMetrics 由 TRM4 mutable 改为 frozen (一次性构造)
- ErrorAttribution 由 TRM4 mutable 改为 frozen (构造时填入全部字段)
- EvolutionResult 移除版本管理字段 (app/ 职责)

涉及算法: #5(CE-Gate), #8(诊断瀑布), #9(进化引擎)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-07 09:34:04 -04:00
parent 09100dcbd4
commit 9d4d52dac5
3 changed files with 964 additions and 0 deletions
+106
View File
@@ -0,0 +1,106 @@
"""core/evolution/ 子包的只读 Protocol 定义。
三个 Protocol 均为只读——core/ 返回结果 dataclass,写入由 app/ 持久化。
SkillStore / PromptStore 为同步(文件读取量小且快),RunLog 为异步
(隔离 SQLite 查询,core/ 不写 SQL)。
"""
from __future__ import annotations
from typing import Any, Protocol, runtime_checkable
@runtime_checkable
class SkillStore(Protocol):
"""版本化技能读取端口。
实现方解析 manifest 指针,core/ 不感知版本号。
"""
def read_skill(self, filename: str) -> str:
"""读取指定 skill 文件的全文内容。
参数:
filename: skill 文件名,如 'temporal-reasoning.md'
返回:
文件全文内容。
"""
...
def list_skill_files(self) -> list[str]:
"""列出当前版本所有 skill 文件名。
返回:
文件名列表。
"""
...
@runtime_checkable
class PromptStore(Protocol):
"""版本化提示词读取端口。
覆盖 system.md 和 tool extract/verify 文件。
"""
def read_prompt(self, filename: str) -> str:
"""读取指定 prompt 文件的全文内容。
参数:
filename: prompt 文件名,如 'system.md'
返回:
文件全文内容。
"""
...
def list_prompt_files(self) -> list[str]:
"""列出当前版本所有 prompt 文件名。
返回:
文件名列表。
"""
...
@runtime_checkable
class RunLog(Protocol):
"""实验日志查询端口。
隔离 SQLite 实现细节,core/ 不写 SQL。
"""
async def get_predictions(
self,
run_id: str,
*,
question_ids: list[str] | None = None,
) -> list[dict[str, Any]]:
"""查询指定 run 的预测记录。
参数:
run_id: 运行标识。
question_ids: 可选的题目 ID 过滤列表。
返回:
预测记录字典列表。
"""
...
async def get_traces(
self,
run_id: str,
*,
question_ids: list[str] | None = None,
) -> list[dict[str, Any]]:
"""查询指定 run 的推理轨迹。
参数:
run_id: 运行标识。
question_ids: 可选的题目 ID 过滤列表。
返回:
轨迹记录字典列表。
"""
...
+484
View File
@@ -0,0 +1,484 @@
"""core/evolution 子包的数据类型定义。
自进化循环中 gate、diagnose、evolve、validate 共用的 dataclass。
所有输出类型默认 frozen=True(一次性构造、不可变),唯一例外是
EvolutionRecord(构建过程中需要多次修改状态)。
不依赖 app/ 或 adapters/。
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Any
# =========================================================================
# 1. Gate 决策类型
# =========================================================================
@dataclass(frozen=True)
class GateParams:
"""CE-Gate 判据阈值组(从实验配置构造)。
属性:
e_confirm: CONFIRMED 接受的 e 值门槛(1/alpha20 对应 alpha=5%)。
e_provisional: 题尽暂定接受门槛,同时是 futility 出口的代数界。
w_net_min: 题尽暂定接受要求的最小净胜 W-L。
delta_min: 接受要求的最小点估计效应量 (W-L)/n_used。
lambda_dir: Wald 方向游走的拒绝阈值(负数)。
e_rollback: 试用期结算的对称回滚 e 值门槛(1/alpha'10 对应 10%)。
"""
e_confirm: float
e_provisional: float
w_net_min: int
delta_min: float
lambda_dir: float
e_rollback: float
@dataclass(frozen=True)
class GateVerdict:
"""一次块间判定的完整结果(判定 + 全部诊断量)。
属性:
decision: 判定结果,取值为 continue / accept_confirmed /
reject_directional / reject_futility / accept_provisional /
reject_inertia 之一。
e_value: 当前 e 值。
wald_lambda: 当前 Wald 方向游走值。
delta_hat: 点估计效应量 (W-L)/n_usedn_used=0 时为 0。
delta_shrunk: 收缩点估计 (W-L)/(n_used+4),仅观测用。
"""
decision: str
e_value: float
wald_lambda: float
delta_hat: float
delta_shrunk: float
# =========================================================================
# 2. 诊断类型
# =========================================================================
@dataclass(frozen=True)
class SpanMetrics:
"""单次工具调用的输出质量指标。
属性:
step: 工具调用所在的步骤编号。
tool_name: 本次调用使用的工具名称。
extraction_completeness: 信息提取完整度。
hallucination_rate: 幻觉内容占比。
missed_info_tags: 未提取信息的标签列表。
hallucination_tags: 幻觉内容的标签列表。
"""
step: int
tool_name: str
extraction_completeness: float
hallucination_rate: float
missed_info_tags: list[str] = field(default_factory=list)
hallucination_tags: list[str] = field(default_factory=list)
@dataclass(frozen=True)
class SkillStepAdherence:
"""单个 skill step 的遵循判定。
属性:
step_label: 被判定的步骤标签。
adhered: 该步骤是否被遵循。
description: 对遵循情况的文字说明。
"""
step_label: str
adhered: bool
description: str
@dataclass(frozen=True)
class QuestionMetrics:
"""单题的完整指标,即 Stage 1 输出。
包含 7 个规则指标和 5 类 judge 指标(span / missed / adherence /
bias / sufficiency)。frozen=True 保证构造后不可变。
属性:
question_id: 题目唯一标识。
video_id: 对应视频唯一标识。
task_type: 题目任务类型。
correct: 该题最终是否答对。
format_compliance: 输出格式遵循程度。
budget_usage: 预算使用比例。
confidence_calibration: 置信度校准结论。
repeat_visit_rate: 重复访问节点的比例。
search_keyword_repetition: 搜索关键词重复率。
level_jump_pattern: 层级跳转模式描述。
tool_usage: 各工具的调用次数统计。
span_metrics: 该题全部工具调用的片段级质量指标。
missed_nodes: 该题遗漏的节点列表。
skill_adherence: 该题对 skill 步骤的遵循情况。
confirmation_bias: 是否出现确认偏误。None 表示 judge 不可用。
evidence_sufficient: 当前证据是否充足。None 表示 judge 不可用。
degraded: 是否为降级指标(judge 解析失败时生成)。
"""
question_id: str
video_id: str
task_type: str
correct: bool
format_compliance: float
budget_usage: float
confidence_calibration: str
repeat_visit_rate: float
search_keyword_repetition: float
level_jump_pattern: str
tool_usage: dict[str, int]
span_metrics: list[SpanMetrics]
missed_nodes: list[str]
skill_adherence: list[SkillStepAdherence]
confirmation_bias: bool | None
evidence_sufficient: bool | None
degraded: bool = False
@dataclass(frozen=True)
class ErrorAttribution:
"""D1 错误归因。
属性:
question_id: 发生错误归因的题目唯一标识。
error_type: 错误的主要类别。
reasoning_failure_type: 推理失败类型;若不适用则为 None。
cause_category: C3 病因:'defect'/'lapse';正确题/INFRA/未判为 None。
lapse_note: LAPSE 提醒文本(供 appendix 路由);非 LAPSE 为 None。
"""
question_id: str
error_type: str
reasoning_failure_type: str | None
cause_category: str | None = None
lapse_note: str | None = None
@dataclass(frozen=True)
class CaseSample:
"""单个案例样本,进化模块的最小输入单元。
属性:
question_id: 题目唯一标识。
video_id: 对应视频唯一标识。
task_type: 题目任务类型。
question: 题目文本。
options: 选项列表。
answer: 正确答案。
prediction: Agent 预测答案。
correct: 是否答对。
error_type: 错误类型;正确题为 None。
selection_reason: 被选为案例的原因说明。
metrics: QuestionMetrics 的关键字段子集。
trace: 完整推理轨迹,不截断。
"""
question_id: str
video_id: str
task_type: str
question: str
options: list[str]
answer: str
prediction: str | None
correct: bool
error_type: str | None
selection_reason: str
metrics: dict[str, Any]
trace: list[dict[str, Any]]
@dataclass(frozen=True)
class SkillCasePack:
"""单个 task_type 的案例包,服务于 Skill 进化。
属性:
task_type: 题目任务类型。
target_file: 对应 skill 文件名,如 'temporal-reasoning.md'
stats: 从 D3/D4 提取的该题型统计。
failure_cases: 失败案例列表。
success_cases: 成功案例列表。
lapse_notes: C3 LAPSE 提醒文本列表(路由进 appendix 受保护区)。
"""
task_type: str
target_file: str
stats: dict[str, Any]
failure_cases: list[CaseSample] = field(default_factory=list)
success_cases: list[CaseSample] = field(default_factory=list)
lapse_notes: list[str] = field(default_factory=list)
@dataclass(frozen=True)
class SystemCasePack:
"""跨题型行为模式案例包,服务于 System Prompt 进化。
属性:
stats: 从 D5 提取的行为模式统计。
failure_cases: 失败案例列表。
success_cases: 成功案例列表。
"""
stats: dict[str, Any]
failure_cases: list[CaseSample] = field(default_factory=list)
success_cases: list[CaseSample] = field(default_factory=list)
@dataclass(frozen=True)
class ToolCasePack:
"""单个 tool_name 的案例包,服务于 Tool Prompt 进化。
属性:
tool_name: 工具名称。
target_files: 对应 prompt 文件名列表。
stats: 从 D2 提取的工具质量统计。
failure_spans: 失败 span 案例列表。
success_spans: 成功 span 案例列表。
"""
tool_name: str
target_files: list[str]
stats: dict[str, Any]
failure_spans: list[dict[str, Any]] = field(default_factory=list)
success_spans: list[dict[str, Any]] = field(default_factory=list)
@dataclass(frozen=True)
class DiagnosisResult:
"""完整诊断报告,即两阶段诊断管线的最终输出。
属性:
run_id: 本次诊断运行的唯一标识。
filter_summary: 筛选条件与筛选结果摘要。
error_attributions: 错误归因结果列表。
attribution_distribution: 各归因类别的分布统计。
reasoning_failure_types: 各推理失败类型的分布统计。
tool_quality: 按工具聚合的质量分析结果。
search_effectiveness: 搜索有效性的聚合统计。
skill_compliance: 技能遵循情况的聚合统计。
decision_patterns: 决策模式与行为模式摘要。
skill_case_packs: 按题型组织的 Skill 进化案例包。
system_case_pack: 跨题型行为模式案例包;无系统性问题时为 None。
tool_case_packs: 按工具名组织的 Tool Prompt 进化案例包。
infra_excluded_count: C3:被 stop_reason 排除的题数。
infra_excluded_ratio: INFRA 占总题数比例。
infra_question_ids: 被排除题 question_id 列表。
defect_count: 进入诊断池错题中判为 DEFECT 的数量。
lapse_count: 进入诊断池错题中判为 LAPSE 的数量。
degraded_count: judge 解析失败而降级的题数。
degraded_question_ids: 降级题的 question_id 列表。
"""
run_id: str
filter_summary: dict[str, Any] = field(default_factory=dict)
error_attributions: list[ErrorAttribution] = field(default_factory=list)
attribution_distribution: dict[str, int] = field(default_factory=dict)
reasoning_failure_types: dict[str, int] = field(default_factory=dict)
tool_quality: dict[str, dict[str, Any]] = field(default_factory=dict)
search_effectiveness: dict[str, dict[str, Any]] = field(default_factory=dict)
skill_compliance: dict[str, dict[str, Any]] = field(default_factory=dict)
decision_patterns: dict[str, Any] = field(default_factory=dict)
skill_case_packs: dict[str, SkillCasePack] = field(default_factory=dict)
system_case_pack: SystemCasePack | None = None
tool_case_packs: dict[str, ToolCasePack] = field(default_factory=dict)
infra_excluded_count: int = 0
infra_excluded_ratio: float = 0.0
infra_question_ids: list[str] = field(default_factory=list)
defect_count: int = 0
lapse_count: int = 0
degraded_count: int = 0
degraded_question_ids: list[str] = field(default_factory=list)
# =========================================================================
# 3. 进化类型
# =========================================================================
@dataclass
class EvolutionRecord:
"""单个目标文件的一次进化记录。
构建过程中需要多次修改状态(如 status、result_version),
因此是唯一不使用 frozen=True 的类型。
属性:
target_file: 目标文件名,如 'temporal-reasoning.md'
target_type: 目标类型: 'skill' / 'system' / 'tool'
original_content: 改写前原文。
evolved_content: 改写后内容;rejected 时与 original_content 相同。
reason: 状态说明。
status: 'accepted' / 'rejected' / 'skipped'
source_version: 改写前版本号,如 'v1'
result_version: 改写后版本号;rejected/skipped 时为 None。
suggestions: LLM 输出的改动建议列表。
attempts: 每次 LLM 调用的原始响应摘要。
validation_errors: 验证失败的具体原因。
edits: LLM 输出的补丁列表。
apply_report: 补丁逐条应用状态。
clip_info: 超预算裁剪信息。
"""
target_file: str
target_type: str
original_content: str
evolved_content: str
reason: str
status: str
source_version: str
result_version: str | None = None
suggestions: list[dict[str, Any]] = field(default_factory=list)
attempts: list[dict[str, Any]] = field(default_factory=list)
validation_errors: list[str] = field(default_factory=list)
edits: list[dict[str, Any]] = field(default_factory=list)
apply_report: list[dict[str, Any]] = field(default_factory=list)
clip_info: dict[str, Any] = field(default_factory=lambda: {"triggered": False, "clipped": 0})
@dataclass(frozen=True)
class RejectedEdit:
"""已在验证阶段证明无效的历史改法摘要。
属性:
target_file: 目标文件名,如 'temporal-reasoning.md'
target_type: 目标类型: 'skill' / 'system' / 'tool'
change_summary: 被验证为无效的改法摘要。
delta: 该改法对应候选相对基线的准确率变化。
source_version: 该改法来源的版本号,如 'v2'
epoch: 该改法所属的进化轮次。
gate_w: CE-Gate 证据:配对翻转 W(基线错到候选对)。
gate_l: CE-Gate 证据:配对翻转 L(基线对到候选错)。
gate_e_value: CE-Gate 证据:终态 e 值。
gate_delta_shrunk: CE-Gate 证据:收缩效应量(观测用)。
"""
target_file: str
target_type: str
change_summary: str
delta: float
source_version: str
epoch: int
gate_w: int | None = None
gate_l: int | None = None
gate_e_value: float | None = None
gate_delta_shrunk: float | None = None
@dataclass(frozen=True)
class EvolutionResult:
"""一次整体进化流程的汇总结果。
由 app/harness/ 编排层组装。不含 skills_version / prompts_version
(版本管理是 app/ 职责,不属于 core/ 决策内核)。
属性:
records: 所有目标的进化记录。
accepted_count: 通过验证的改写数。
rejected_count: 未通过验证的改写数。
skipped_count: 因无失败案例而跳过的目标数。
"""
records: list[EvolutionRecord] = field(default_factory=list)
accepted_count: int = 0
rejected_count: int = 0
skipped_count: int = 0
# =========================================================================
# 4. 验证辅助类型
# =========================================================================
@dataclass(frozen=True)
class PairResult:
"""块验证配对比对结果。
属性:
w: 基线错、候选对的翻转数。
l: 基线对、候选错的翻转数。
observed: 每题的 (基线是否正确, 候选是否正确) 记录。
"""
w: int
l: int # noqa: E741 — 数学记号 W/Lwin/loss),与 gate.py 一致
observed: dict[str, tuple[bool, bool]]
@dataclass(frozen=True)
class QuadrantClassification:
"""块验证四象限分类。
属性:
improvements: 基线错、候选对的题目 ID 列表。
regressions: 基线对、候选错的题目 ID 列表。
persistent_fails: 两臂均错的题目 ID 列表。
stable_successes: 两臂均对的题目 ID 列表。
"""
improvements: list[str]
regressions: list[str]
persistent_fails: list[str]
stable_successes: list[str]
# =========================================================================
# 5. Prompt 模板束
# =========================================================================
@dataclass(frozen=True)
class DiagnosePrompts:
"""诊断管线所需的全部固定模板束。
由调用方加载后以 frozen dataclass 传入,避免 core/ 依赖文件系统。
属性:
defect_vs_lapse: defect/lapse 病因判别模板。
reasoning_sub: 推理失败子分类模板。
span_eval_system: span 评估系统提示模板。
span_eval_user: span 评估用户提示模板。
missed_nodes: 遗漏节点检测模板。
skill_adherence: 技能遵循判定模板。
confirmation_bias: 确认偏误检测模板。
evidence_sufficiency: 证据充足性判定模板。
"""
defect_vs_lapse: str
reasoning_sub: str
span_eval_system: str
span_eval_user: str
missed_nodes: str
skill_adherence: str
confirmation_bias: str
evidence_sufficiency: str
@dataclass(frozen=True)
class EvolvePrompts:
"""进化引擎所需的全部固定模板束。
由调用方加载后以 frozen dataclass 传入,避免 core/ 依赖文件系统。
属性:
evolve_skill: Skill 进化提示模板。
evolve_system: System Prompt 进化提示模板。
evolve_tool: Tool Prompt 进化提示模板。
evolve_rank: 编辑排序提示模板。
consolidate_system: appendix 压缩系统提示。
"""
evolve_skill: str
evolve_system: str
evolve_tool: str
evolve_rank: str
consolidate_system: str