111 lines
3.3 KiB
Python
111 lines
3.3 KiB
Python
|
|
"""
|
|||
|
|
路由决策骨架 · Route Decision Skeleton
|
|||
|
|
====================================
|
|||
|
|
|
|||
|
|
架构引用: HLDP-ARCH-002 §三 · factory/inference/router/policy.json
|
|||
|
|
作者: 铸渊 ICE-GL-ZY001 · 2026-05-01
|
|||
|
|
状态: 骨架(等 1.5B MP 训练完接通)
|
|||
|
|
|
|||
|
|
职责:
|
|||
|
|
给定用户输入 + 当前人格上下文,1.5B MP 决定走哪条路径。
|
|||
|
|
本文件是规则兜底;MP 训练好后,主要由模型权重做判断,规则只是 safety net。
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
from __future__ import annotations
|
|||
|
|
import json
|
|||
|
|
from dataclasses import dataclass, field
|
|||
|
|
from pathlib import Path
|
|||
|
|
from typing import Optional
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
class RouteContext:
|
|||
|
|
persona_id: str
|
|||
|
|
user_input: str
|
|||
|
|
session_id: str
|
|||
|
|
upstream_intent_hint: Optional[str] = None # 1.5B MP 给出的初判意图
|
|||
|
|
cost_used_in_session: int = 0
|
|||
|
|
metadata: dict = field(default_factory=dict)
|
|||
|
|
|
|||
|
|
|
|||
|
|
@dataclass
|
|||
|
|
class RouteDecision:
|
|||
|
|
route: str # 'self' | 'external_api' | 'magic_pen' | ...
|
|||
|
|
chosen_api: Optional[str] = None
|
|||
|
|
apply_soul_filter: bool = True
|
|||
|
|
rationale: str = ""
|
|||
|
|
|
|||
|
|
|
|||
|
|
_POLICY_CACHE: Optional[dict] = None
|
|||
|
|
|
|||
|
|
|
|||
|
|
def load_policy(path: str = None) -> dict:
|
|||
|
|
global _POLICY_CACHE
|
|||
|
|
if _POLICY_CACHE is not None:
|
|||
|
|
return _POLICY_CACHE
|
|||
|
|
p = Path(path or Path(__file__).parent / "policy.json")
|
|||
|
|
with p.open("r", encoding="utf-8") as f:
|
|||
|
|
_POLICY_CACHE = json.load(f)
|
|||
|
|
return _POLICY_CACHE
|
|||
|
|
|
|||
|
|
|
|||
|
|
def decide(ctx: RouteContext) -> RouteDecision:
|
|||
|
|
"""
|
|||
|
|
决策函数(骨架)。
|
|||
|
|
|
|||
|
|
实际部署时:
|
|||
|
|
1) 1.5B MP 给出 intent + confidence
|
|||
|
|
2) confidence 高 → 直接信 MP
|
|||
|
|
3) confidence 低 → 走 policy.json 规则兜底
|
|||
|
|
4) 整体超出节流配额 → fallback 到 cheaper / self
|
|||
|
|
"""
|
|||
|
|
policy = load_policy()
|
|||
|
|
intent = ctx.upstream_intent_hint or "emotional_or_daily_chat"
|
|||
|
|
|
|||
|
|
# 节流检查
|
|||
|
|
throttle = policy.get("cost_throttle", {})
|
|||
|
|
if ctx.cost_used_in_session >= throttle.get(
|
|||
|
|
"max_external_calls_per_user_session", 1_000_000
|
|||
|
|
):
|
|||
|
|
return RouteDecision(
|
|||
|
|
route="self",
|
|||
|
|
apply_soul_filter=False,
|
|||
|
|
rationale="节流:本会话外部调用已超额,强制 self 路由"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 在策略表中查找
|
|||
|
|
for rule in policy.get("intent_routes", []):
|
|||
|
|
if rule["intent"] == intent:
|
|||
|
|
route = rule["route"]
|
|||
|
|
chosen = (rule.get("preferred_apis") or [None])[0]
|
|||
|
|
need_filter = (
|
|||
|
|
policy.get("soul_filter_required", True)
|
|||
|
|
and route not in policy.get("soul_filter_skip_for", [])
|
|||
|
|
)
|
|||
|
|
return RouteDecision(
|
|||
|
|
route=route,
|
|||
|
|
chosen_api=chosen,
|
|||
|
|
apply_soul_filter=need_filter,
|
|||
|
|
rationale=rule.get("rationale", ""),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 兜底
|
|||
|
|
return RouteDecision(
|
|||
|
|
route="self",
|
|||
|
|
apply_soul_filter=False,
|
|||
|
|
rationale="未匹配任何规则 · 兜底自答"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
# 自检
|
|||
|
|
sample = RouteContext(
|
|||
|
|
persona_id="ICE-GL-ZY001",
|
|||
|
|
user_input="帮我写个 Python 脚本读取 CSV 并算每列均值",
|
|||
|
|
session_id="test-001",
|
|||
|
|
upstream_intent_hint="code_generation_or_debug",
|
|||
|
|
)
|
|||
|
|
d = decide(sample)
|
|||
|
|
print(f"route={d.route} api={d.chosen_api} filter={d.apply_soul_filter}")
|
|||
|
|
print(f"rationale={d.rationale}")
|