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
This commit is contained in:
@@ -37,6 +37,40 @@ def build_sense_routers(cfg: SenseConfig) -> List[APIRouter]:
|
||||
return {"enabled": cfg.enabled, "mode": cfg.mode,
|
||||
"embedder": cfg.embedder.base_url}
|
||||
|
||||
@v1.post("/v1/route", tags=["sense"])
|
||||
async def route_v1(request: Request):
|
||||
"""分级决策:{query|messages, consumer, domain?} -> TierDecision 视图。
|
||||
|
||||
D-G6:不落 query 原文(观察表只存哈希可关联 id + 特征 + int8 向量)。
|
||||
mode=collect/shadow:tier 为决策值,执行仍走消费方现状;
|
||||
mode=live:消费方按 tier 分流(D-G7)。
|
||||
"""
|
||||
from gateway.sense.grader import Grader
|
||||
try:
|
||||
body = await request.json()
|
||||
except Exception:
|
||||
body = {}
|
||||
query = (body or {}).get("query")
|
||||
messages = (body or {}).get("messages")
|
||||
consumer = str((body or {}).get("consumer") or "proxy")
|
||||
domain = str((body or {}).get("domain") or "")
|
||||
payload = messages if messages else (query or "")
|
||||
grader = Grader(cfg, store,
|
||||
get_observer(store) if cfg.mode != "collect" else None)
|
||||
d = await grader.decide(payload, consumer, domain)
|
||||
probs_total = sum(d.probs.values()) or 1.0
|
||||
return {
|
||||
"tier": d.tier if cfg.mode == "live" else d.tier,
|
||||
"probs": {k: round(v / probs_total, 4) for k, v in d.probs.items()},
|
||||
"confidence": round(max(d.probs.values()) / probs_total, 4)
|
||||
if d.probs else 0.0,
|
||||
"thresholds_version": d.thresholds_version,
|
||||
"head_version": d.head_version,
|
||||
"mode": d.mode,
|
||||
"fallback": d.fallback,
|
||||
"hard_gates": d.hard_gates,
|
||||
}
|
||||
|
||||
@v1.post("/v1/embeddings", tags=["sense"])
|
||||
async def embeddings(request: Request):
|
||||
"""OpenAI 兼容透传 embedder(客户端/代理共用)。"""
|
||||
|
||||
Reference in New Issue
Block a user