Revert "fix(cheap-gen): 死圈修复 fix①-B 便宜档畸形参数纠偏——n=5 收敛环坐实 heritage 死圈复现"

This reverts commit 26f94f1f0b9137b342c0d37c1f7583d0f03e4369.
This commit is contained in:
lili 2026-07-08 16:48:59 -07:00 committed by lili
parent 3c0c105aeb
commit e4e4e23564
3 changed files with 0 additions and 131 deletions

View File

@ -30,11 +30,9 @@ def build_cheap_breaker(**overrides) -> CircuitBreakerMiddleware:
"""
overrides.pop("rmb_hard_limit", None)
overrides.pop("soft_budget", None)
overrides.pop("enable_malformed_correction", None)
return CircuitBreakerMiddleware(
enable_rmb_gate=True,
rmb_hard_limit=cheap_soft_limit(), # 软停线 ¥10(soft 档语义;硬地板 = ×1.5 middleware 内派生)
soft_budget=True, # 两段式:越软停线只许收尾、越硬地板 fail-closed(裁决)
enable_malformed_correction=True, # fix①-B:便宜档畸形参数纠偏(漏 path 撞满 stuck 前追加补参提示;tier2 不开)
**overrides,
)

View File

@ -1,81 +0,0 @@
"""test_malformed_correction.py — fix①-B 便宜档畸形参数纠偏(2026-07-08 n=5 收敛环坐实 heritage 死圈复现)。
守的不变量:
· cheap(enable_malformed_correction=True):write 类工具的漏必填参结果被追加补参纠偏提示(催补 path / edit_file);
· tier2(默认 False):on_acting 该分支不进,工具结果逐字节不变(共享中间件对 tier2 零行为变化);
· 漏参的正常结果 / write 类工具:不追加(纠偏只打漏参不误伤);
· 不重置 stuck 计数(纠偏不动 _fail_repeat,仍漏就照常撞熔断本测只验追加行为,计数不变由代码保证)
:cheap-worker/.venv/bin/python -m pytest tier2/gen-worker/tests/test_malformed_correction.py -q(cwd=tier2/gen-worker)
"""
import asyncio
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1])) # → tier2/gen-worker/
from worker.middleware import CircuitBreakerMiddleware # noqa: E402
from agentscope.tool import ToolResponse # noqa: E402
from agentscope.message import TextBlock # noqa: E402
_MISSING = "Input validation failed for tool 'write_file': 'path' is a required property"
class _TC: # mock tool_call(只需 .name)
def __init__(self, name):
self.name = name
def _resp(text):
return ToolResponse(content=[TextBlock(text=text)])
def _text_of(resp):
return "".join(str(getattr(b, "text", "") or "") for b in (resp.content or []))
def _drive(mw, tool_name, resp):
"""跑 on_acting(mock tool_call + next_handler 吐 resp),收集 yield 的 items。soft_budget 默认 False → 直进 fix①-B 分支。"""
async def next_handler(**kwargs):
yield resp
async def run():
out = []
async for item in mw.on_acting(None, {"tool_call": _TC(tool_name)}, next_handler):
out.append(item)
return out
return asyncio.run(run())
def test_cheap_augments_missing_param_error():
mw = CircuitBreakerMiddleware(enable_malformed_correction=True)
out = _drive(mw, "write_file", _resp(_MISSING))
assert len(out) == 1
txt = _text_of(out[0])
assert _MISSING in txt # 原错误保留
assert "path" in txt and "edit_file" in txt # 追加了补参 + 催 edit_file 短载荷
assert "重发本次调用" in txt
def test_tier2_does_not_augment():
mw = CircuitBreakerMiddleware() # 默认 enable_malformed_correction=False
out = _drive(mw, "write_file", _resp(_MISSING))
assert _text_of(out[0]) == _MISSING # 逐字节不变(tier2 零行为变化)
def test_cheap_no_augment_on_normal_result():
mw = CircuitBreakerMiddleware(enable_malformed_correction=True)
out = _drive(mw, "write_file", _resp("write ok bytes=123"))
assert _text_of(out[0]) == "write ok bytes=123" # 非漏参不追加
def test_cheap_no_augment_on_non_write_tool():
mw = CircuitBreakerMiddleware(enable_malformed_correction=True)
out = _drive(mw, "read_file", _resp(_MISSING))
assert _text_of(out[0]) == _MISSING # 非 write 类工具不进纠偏分支
if __name__ == "__main__":
import pytest
sys.exit(pytest.main([__file__, "-q"]))

View File

@ -177,38 +177,6 @@ DEFAULT_RMB_HARD_LIMIT = genconfig.get("budget", "rmb_hard_limit", 50.0) # 富
# scaffold_init(重开工程)。read/list 零成本只读、check/build/run_gates/finish 是收尾链本体,均放行。
DEFAULT_SOFT_STOP_BLOCKED_TOOLS = frozenset({"write_file", "edit_file", "write_source", "scaffold_init"})
# ── fix①-B:便宜档畸形参数纠偏(2026-07-08 n=5 收敛环坐实 heritage 死圈复现)──
# 根因:MiniMax 在长工具调用参数下会漏 write_file/edit_file 的必填 path,AgentScope schema 校验拒 →
# 「Input validation failed: 'path' is a required property」;agent 收到默认校验错常不理会、反复漏同参 →
# 连撞 stuck_repeat_threshold(默认4)→ stuck 终态杀,九门从未跑、ok=False(fix①-A 给了 edit 替代但没阻止
# agent 选 write_file 漏 path)。本纠偏在【非软停态】给这类「漏必填参」的工具结果追加一条比默认校验错更贴脸的
# 补参提示(并催改用 edit_file 短载荷),让 agent 在撞满 stuck 阈值前补齐参数出圈。cheap-only
# (enable_malformed_correction=True 才开;tier2 默认关、零行为变化);不重置 stuck 计数(仍漏就照常熔断,
# 上界由现有 stuck 阈值天然封死、不新增无界重试面,与 fix①-A edit 工具叠加)。
_MALFORMED_PARAM_MARKERS = ("is a required property", "input validation failed")
_MALFORMED_CORRECTION_TEXT = (
"你这次工具调用漏了必填参数(通常是 path)。工具参数必须一次给全:write_file 必须同时给 {path, content}、"
"edit_file 必须给 {path, old, new}。请【立即重发本次调用、带齐全部参数】。"
"小改优先用 edit_file(只发变化的几行、载荷短、最不易漏参),别对整文件 write_file(长内容最容易把 path 漏掉)。"
)
def _is_missing_param_error(resp) -> bool:
"""判 ToolResponse 是否是「漏必填参数」的 schema 校验错(fix①-B 纠偏触发条件)。best-effort:抽不到文本返 False。"""
try:
content = getattr(resp, "content", None)
text = ""
if isinstance(content, list):
for b in content:
text += str(getattr(b, "text", "") or "")
elif isinstance(content, str):
text = content
low = text.lower()
return any(m in low for m in _MALFORMED_PARAM_MARKERS)
except Exception: # noqa: BLE001 —— 判定失败按「非漏参」放行,绝不因此中断工具结果
return False
# ── 软停后「finish 逼近」递进升压(工单 c)──
# 软停(budget_soft_tripped)已由 on_system_prompt 注入「立即 finish」强提醒 + on_acting 拦新增生成类工具,
# 但这是被动系统提示;A1 T8 实测 M3 可能烧推理不理会,80011 生产实录也是「软停触发后仍烧到 step_cap/硬地板才停」。
@ -267,7 +235,6 @@ class CircuitBreakerMiddleware(MiddlewareBase):
group_ratio: float | None = None,
soft_budget: bool = False, # ¥ 越限行为档位(False=hard 单段 fail-closed;True=soft 两段式:软停+硬地板)
soft_stop_blocked_tools: Optional[frozenset] = None, # 软停后拦截的「新增生成面」工具名集(None=默认集)
enable_malformed_correction: bool = False, # fix①-B:便宜档畸形参数纠偏(True 才开;tier2 默认关、零变化)
) -> None:
"""
Args:
@ -338,8 +305,6 @@ class CircuitBreakerMiddleware(MiddlewareBase):
self._soft_stop_blocked_tools = (
soft_stop_blocked_tools if soft_stop_blocked_tools is not None
else DEFAULT_SOFT_STOP_BLOCKED_TOOLS)
# fix①-B:便宜档畸形参数纠偏总开关(cheap 熔断工厂置 True;tier2 默认 False = on_acting 该分支不进、零行为变化)。
self._malformed_correction = enable_malformed_correction
self.group_ratio = group_ratio
self._pricing_params = pricing_params # {pricing, qpu, usd_rate} 或 None(惰性取价后填)
self._pricing_fetch_tried = pricing_params is not None # 已有则不再去取
@ -630,19 +595,6 @@ class CircuitBreakerMiddleware(MiddlewareBase):
escalate = None # _acting 仅一个终态 ToolResponse;附加一次即可,防御性置空避免重复
yield item
return
# fix①-B(cheap-only):非软停态下,给「漏必填参」的 write 类工具结果追加补参纠偏提示(催补 path / 改 edit_file
# 短载荷),让 agent 在撞满 stuck 阈值前出圈。tier2(_malformed_correction=False)不进本分支、逐字节零行为变化。
if self._malformed_correction:
tool_call = input_kwargs.get("tool_call") if isinstance(input_kwargs, dict) else None
name = getattr(tool_call, "name", None)
if name in self._soft_stop_blocked_tools:
async for item in next_handler(**input_kwargs):
if isinstance(item, ToolResponse) and _is_missing_param_error(item):
self._augment_toolresponse(item, _MALFORMED_CORRECTION_TEXT)
print(f"[tier2-circuit] 便宜档畸形参数纠偏:{name} 漏必填参 → 追加补参提示"
f"(催补 path / 改 edit_file 短载荷,趁 stuck 阈值前出圈)。", flush=True)
yield item
return
async for item in next_handler(**input_kwargs):
yield item