Coverage for src\genesis\qa\guardrails.py: 100%

27 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-26 14:20 +0800

1from __future__ import annotations 

2 

3from dataclasses import dataclass, field 

4from typing import Any 

5 

6# QA 校验反馈循环的最大轮次上限(OV6:防止「QA→Writer修正→重新QA」无限循环) 

7DEFAULT_MAX_QA_ROUNDS = 3 

8 

9 

10def resolve_qa_model(models: Any | None) -> str | None: 

11 """解析 QA 校验应使用的模型名。 

12 

13 OV6 修复:QA 校验必须走 fallback 模型(独立模型族),避免「主模型自校验盲区」 

14 (如 DeepSeek 生成、DeepSeek 校验 → 同族模型盲点,难以发现自身偏误)。 

15 

16 返回 fallback 模型名;若无 fallback 配置则返回 None,迫使调用方显式指定 

17 一个独立于生成模型的校验模型(而非静默回退到 primary)。 

18 """ 

19 if models is None: 

20 return None 

21 fallback = getattr(models, "fallback", None) 

22 if fallback is not None: 

23 name = getattr(fallback, "name", None) 

24 if name: 

25 return name 

26 return None 

27 

28 

29@dataclass 

30class QALoopController: 

31 """QA 反馈循环护栏:约束「QA校验→Writer修正→重新校验」的最大轮次。 

32 

33 防止 OV6 指出的无边界循环风险:超过 max_rounds 后必须停止循环, 

34 转为上报人工或降级处理,不得无限重试。 

35 """ 

36 

37 max_rounds: int = DEFAULT_MAX_QA_ROUNDS 

38 _round: int = field(default=0, init=False) 

39 

40 @property 

41 def round(self) -> int: 

42 """当前已执行的轮次(0 表示尚未开始)。""" 

43 return self._round 

44 

45 def can_continue(self) -> bool: 

46 """是否还能进入下一轮 QA 校验。""" 

47 return self._round < self.max_rounds 

48 

49 def advance(self) -> int: 

50 """推进一轮,返回推进后的当前轮次(从 1 开始计数)。""" 

51 self._round += 1 

52 return self._round 

53 

54 def is_exhausted(self) -> bool: 

55 """已达上限:必须停止循环并上报,禁止继续重试。""" 

56 return self._round >= self.max_rounds