Files
projectAIpopular/gateway/sense/features.py
T
tzt 4575025056 feat(sense): T-G5 Grader 决策组合(特征门×概率×conformal + /v1/route + 三态 mode)
- features.py:gate() 纯函数——轮数/字符估算/意图黑名单/仓库级信号/长度门
  -> t1_hard_ok(任一硬门不过即 False,D-G1)
- grader.py:Grader.decide §8 时序(embed 降级检查 -> 特征门 -> LinearHead 概率
  -> conformal 阈值:p1>=τ1 且 t1_hard_ok->T1,p3>=τ3 或 repo_signals->T3,
  其余 T2 默认;collect/shadow 只写观察 executed=现行为,live 决策即执行;
  全模式 observer.log);工件/阈值缓存 + invalidate;D-G4 规则门退化
- routes:/v1/route 契约(D-G6 不落 query 原文)
- fix(observer):embedding list -> BLOB 转换(修 sqlite 绑定)
- 测试 +6(门矩阵/shadow 不改流/live 决策/降级/保守阈值/写观察),全量 405 passed
2026-09-05 14:17:44 +08:00

55 lines
2.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""特征门(T-G5):单轮/长度/意图黑名单/仓库级信号(纯函数)。
D-G1t1_hard_ok=False 时禁止判 T1(硬门);repo_signals=True 时倾向 T3。
"""
from __future__ import annotations
import re
from dataclasses import dataclass
from typing import Any, Dict, List, Optional
from gateway.sense.config import SenseConfig
_REPO_SIGNALS = ("多文件", "仓库", "项目结构", "跨模块", "架构", "脚手架",
"migration", "refactor", "scaffold", "repository")
@dataclass
class Features:
turns: int = 1 # 非 system 消息数
est_tokens: int = 0 # 字符/3 估算(中文友好近似)
single_turn: bool = True
intent_blocked: bool = False # 命中意图黑名单
repo_signals: bool = False # 仓库级/多文件信号
over_length: bool = False # 超出 t1 长度门
t1_hard_ok: bool = True # 任一 T1 硬门不过即 False
def _to_text_and_turns(text_or_messages) -> tuple[str, int]:
if isinstance(text_or_messages, str):
return text_or_messages, 1
msgs = [m for m in (text_or_messages or []) if isinstance(m, dict)]
non_system = [m for m in msgs if str(m.get("role")) != "system"]
text = "\n".join(str(m.get("content") or "") for m in non_system)
return text, max(1, len(non_system))
def gate(text_or_messages, consumer: str, cfg: SenseConfig) -> Features:
"""特征门(§7 签名):返回门特征 + t1_hard_ok。"""
text, turns = _to_text_and_turns(text_or_messages)
est_tokens = len(text) // 3
single_turn = turns <= 1
blocked = any(word in text for word in cfg.intent_blacklist)
repo = any(word in text for word in _REPO_SIGNALS)
over_length = est_tokens > cfg.t1_max_tokens
multi_turn = turns > cfg.t1_max_turns
t1_hard_ok = single_turn and not over_length and not blocked and not repo \
and not multi_turn
return Features(
turns=turns, est_tokens=est_tokens, single_turn=single_turn,
intent_blocked=blocked, repo_signals=repo,
over_length=over_length, t1_hard_ok=t1_hard_ok)