issue #133: 反思闭环样本补全——周期触发级一打分+群聊追问结局接入 #139
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/133-reflection-cycle-sample-completion"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #133
实现内容
反思闭环反坍缩护栏(hit-rate + offset)在两处收不到该收的样本,本 PR 补齐。
一、周期触发级一打分(让 offset 真正生效)
_evaluate_drive_tick_chat此前调用统一门控从不传level1_score,恒吃gating.EVENT_TRIGGER_LEVEL1_SCORE(+inf)——反思闭环抬高的 offset 拦不住任何周期候选,护栏本身开路。
proactive_reconnect.periodic_significance_score(trigger_path, *, subject_familiarity, base_weight, timing_override_bonus_weight, familiarity_weight)——不是字面仿tier2_significance_score的"二元代理+熟悉度"两项:tier2 的outcome二元分量默认权重0.6 已经让大多数候选独立跨过默认阈值;周期候选没有天然二元信号(drive_tick/
immediate_followup 到达该函数前都已过零 LLM 粗筛,粗筛结果对两条路径恒真,不能当区分量用)。
改为三项:
base_weight(两条路径共享基线,默认 0.6,保证familiarity=0时默认仍跨过默认阈值 0.5——不让新分数默默让 drive-tick 变得默认永不生效,e2e 测试实测钉住)+
timing_override_bonus_weight(只在 immediate_followup 时加成,默认 0.1——措辞明确不代表"模型显式意图",因为
RecallTimingOverride到期可能来自expects_reply也可能来自对方上线状态变化)+
familiarity_weight(默认 0.3)_evaluate_drive_tick_chat在熔断闸检查之后、门控调用之前接入打分并传level1_score=gating.py模块文档/EVENT_TRIGGER_LEVEL1_SCORE/progressive_unlock_scale/evaluate_gatedocstring、agent_loop_breaker.py、config.py、gate_pipeline.py均已同步措辞
proceed,推到 ceiling 后变silent_level1——不止测纯函数,钉住链路真的通了progressive_unlock_scale"消费者集合为空"论证对 drive-tick/私聊即刻追问不再完全成立(这两条路径现在也是
level1_score真实消费者,但没有类似 tier-2 的解锁门槛)——本票不解决,只标注,ADR-0011 补了对应更新节
二、群聊追问结局接入反思闭环
_run_group_followup_check此前全程不调record_proactive_attempt。接入前先修两个隐藏坑:reflection.py::_apply_outcome的chat_id.removesuffix(".p")对群聊 chat_id 是静默 no-op,会把整个群 id 当
user_id写出假的 per-user 慢情感态。改为按is_private_chat_id(chat_id)分流:私聊读写("user", user_id)不变;群聊快层锚点改读("group", chat_id)(只读不写,同delta.py::_apply_interaction_polarity既有先例逐字一致),完全跳过 per-user 慢层写(AC 给定的二选一框架下唯一没有引入错误归因的答案)
run_reflection_cycle判"是否已回应"恒用get_reconnect_cooldown(attempt.chat_id)——私聊有效,但群聊的冷却记录按裸
sender_id存(服务的是"距上次交互"文本这件完全不同的事),查询恒落空、结局恒判
fell-flat。新增chat_activity.py(ChatActivityStoragePort,per-chat_id 一行,结构同
TypingStatusState先例):_debounced_flush在去抖批次 flush之后(早于门控判定)双写,不取代
_last_group_chat_activity那份进程内 dict(继续服务_run_group_followup_check/_human_is_active两个高频消费者);私聊场景不写_run_group_followup_check接入record_proactive_attempt,群聊即刻追问结局第一次真正计入 hit-rate
proactive_attempt.py模块文档作用域声明已更新测试与验证
scope 都未 seed 时读哪个都退回同一中性零点,无法区分"读对了"还是"巧合看起来正确")——已补
一条显式 seed 两个 scope 为不同值的回归测试,重新变异验证确认现在能抓住
storage.py那两条经行号偏移核对(+30 行,与本票新增代码量吻合)是 issue #127 就已存在的旧噪音
两轴 review
Standards 维度发现并经对抗校验确认两处真实的文档不一致(均非功能性 bug):
proactive_attempt.py::attempt_status()自己的 docstring 没有随模块级文档一起更新群聊来源;gate_pipeline.py::_evaluate_unified_gate()(level1_score编排层入口,本票 diff 完全没碰这个文件)的 docstring 仍只提 tier-2 消费者。已在本 PR 内以单独 fix commit 修正。
文档
docs/adr/0006-agency-and-drive.md/docs/adr/0011-technology-selection.md已补更新节(docs 分支本地提交,按约定不推送)。CONTEXT.md/design.md 核实后确认无需改动——既有描述在
实现前就准确描述了目标状态。
🤖 Generated with Claude Code
一、周期触发级一打分(让offset真正生效): - 新增 proactive_reconnect.periodic_significance_score(三项加权: base_weight共享基线+timing_override_bonus_weight短窗口追问加成+ familiarity_weight连续熟悉度),配套三个config权重项 - _evaluate_drive_tick_chat 接线 level1_score=,此前恒吃 +inf 默认值, 反思闭环抬高的offset拦不住任何周期候选——现在真正生效 - 公式不是字面仿tier2的"二元代理+熟悉度"两项:tier2的outcome二元分量 是"是否非噪声"的粗筛代理,默认权重0.6已让大多数候选独立跨过默认阈值; 周期候选没有这样一个天然二元信号(drive_tick/immediate_followup到达 本函数前都已过零LLM粗筛,粗筛结果对两条路径恒真,不能当区分量用), 改为base_weight是两条路径共享基线(默认0.6,保证familiarity=0时默认 仍跨过默认阈值0.5,不让新分数默默让drive_tick变得默认永不生效—— e2e测试实测钉住这条:offset默认0.0时候选照常proceed,推到ceiling后 才变silent_level1) - gating.py/config.py/agent_loop_breaker.py 补文档措辞("周期触发默认 满分直通"已成过去式);发现的premise缺口(progressive_unlock_scale的 "消费者集合为空"论证对drive_tick/私聊即刻追问不再完全成立)已标注 但不在本票展开,留后续ticket评估 二、群聊追问结局接入反思闭环(先修两个隐藏坑): - bug1: reflection.py::_apply_outcome 的 chat_id.removesuffix(".p") 对 群聊静默no-op会把整个群id当user_id写出假的per-user慢情感态——改为 按is_private_chat_id(chat_id)分流:私聊读写("user",user_id)不变; 群聊快层锚点改读("group",chat_id)(同delta.py:: _apply_interaction_polarity既有先例,只读不写),完全跳过per-user 慢层写(AC给定的二选一框架下唯一没有引入错误归因的答案) - bug2: run_reflection_cycle 判"是否已回应"对群聊恒用 get_reconnect_cooldown(attempt.chat_id)——群聊冷却记录按裸sender_id 存,key对不上,永远查不到、恒判cold。新增 chat_activity.py 持久化port(双写,不取代_last_group_chat_activity那份进程内dict—— _run_group_followup_check/_human_is_active两个高频消费者继续用它), _debounced_flush在去抖批次flush后写入,run_reflection_cycle群聊分支 改读这份持久化信号 - entry_reactive.py::_run_group_followup_check 接入 record_proactive_attempt,群聊即刻追问结局第一次真正计入hit-rate - proactive_attempt.py 模块文档范围声明同步更新 三、变异测试+全量测试+ruff均已在实现过程中反复验证,全量1793 passing。 ADR-0006/0011/0014更新节待补(docs分支,另行提交)。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>