Files
Aether/_deprecated_py_src/services/capability/resolver.py
fawney19 1d9c77522a refactor: 移除 Python 后端源码,全面迁移至 Rust gateway 架构
- 删除全部 Python 源码 (src/) 及 Alembic 迁移脚本,归档至 _deprecated_py_src/
- 重构 Rust gateway ai_pipeline: 拆分 planner/finalize 模块,新增 contracts/adaptation 层
- 重组 handlers 模块为 admin/public/proxy/internal/shared 子模块结构
- 新增 executor 模块,引入 Rust 原生数据库迁移 (aether-data/migrations)
- 简化 CI/Docker 构建流程,移除 base image 二级构建,统一为单一 app image
- 移除 Python 相关基础设施文件 (entrypoint.sh, gunicorn_conf.py, Dockerfile.base)
2026-04-03 16:26:16 +08:00

175 lines
6.6 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.
"""
能力需求解析器
负责从各种来源解析请求的能力需求:
1. 用户模型级配置 (User.model_capability_settings)
2. 用户 API Key 强制配置 (ApiKey.force_capabilities)
3. 请求头 X-Require-Capability显式声明
4. Adapter 的 detect_capability_requirements如 Claude 的 anthropic-beta
5. 显式传入 (用于重试升级)
"""
from collections.abc import Callable
from typing import Any
from src.core.api_format import get_header_value
from src.core.key_capabilities import (
CAPABILITY_DEFINITIONS,
CapabilityConfigMode,
get_user_configurable_capabilities,
)
from src.core.logger import logger
# Adapter 检测器类型:接受 headers 和可选的 request_body返回能力需求字典
type AdapterDetectorType = Callable[[dict[str, str], dict[str, Any] | None], dict[str, bool]]
class CapabilityResolver:
"""能力需求解析器"""
@staticmethod
def resolve_requirements(
user: Any | None = None,
user_api_key: Any | None = None,
model_name: str | None = None,
request_headers: dict[str, str] | None = None,
request_body: dict[str, Any] | None = None,
explicit_requirements: dict[str, bool] | None = None,
adapter_detector: AdapterDetectorType | None = None,
) -> dict[str, bool]:
"""
解析请求的能力需求
来源优先级(后者覆盖前者):
1. 用户模型级配置 (User.model_capability_settings)
2. 用户 API Key 强制配置 (ApiKey.force_capabilities)
3. 请求头 X-Require-Capability显式声明
4. Adapter 的 detect_capability_requirements如 Claude 的 anthropic-beta
5. 显式传入的 explicit_requirements用于重试升级
Args:
user: User 对象
user_api_key: 用户 ApiKey 对象
model_name: 模型名称(用于查找模型级配置)
request_headers: 请求头
request_body: 请求体(可选,部分 Adapter 可能需要)
explicit_requirements: 显式传入的需求(重试时使用)
adapter_detector: Adapter 的能力检测方法
Returns:
能力需求字典,如 {"cache_1h": True, "context_1m": False}
"""
requirements: dict[str, bool] = {}
# 1. 从用户模型级配置获取(仅用户可配置型能力)
if user and model_name:
model_settings = getattr(user, "model_capability_settings", None) or {}
model_caps = model_settings.get(model_name, {})
if model_caps:
for cap_name, cap_value in model_caps.items():
cap_def = CAPABILITY_DEFINITIONS.get(cap_name)
if cap_def and cap_def.config_mode == CapabilityConfigMode.USER_CONFIGURABLE:
requirements[cap_name] = bool(cap_value)
logger.debug(
f"[CapabilityResolver] 从用户模型配置获取 {cap_name}={cap_value} "
f"(model={model_name})"
)
# 2. 从用户 API Key 强制配置获取(覆盖模型级配置)
if user_api_key:
force_caps = getattr(user_api_key, "force_capabilities", None) or {}
if force_caps:
for cap_name, cap_value in force_caps.items():
cap_def = CAPABILITY_DEFINITIONS.get(cap_name)
if cap_def and cap_def.config_mode == CapabilityConfigMode.USER_CONFIGURABLE:
requirements[cap_name] = bool(cap_value)
logger.debug(
f"[CapabilityResolver] 从 API Key 强制配置获取 {cap_name}={cap_value}"
)
# 3. 从请求头 X-Require-Capability 获取(显式声明)
if request_headers:
header_caps = get_header_value(request_headers, "X-Require-Capability")
if header_caps:
for cap in header_caps.split(","):
cap = cap.strip()
if not cap:
continue
if cap.startswith("-"):
# -cache_1h 表示不需要
cap_name = cap[1:]
requirements[cap_name] = False
else:
requirements[cap] = True
logger.debug(
f"[CapabilityResolver] 从请求头获取 {cap_name if cap.startswith('-') else cap}"
)
# 4. 从 Adapter 的 detect_capability_requirements 获取
if adapter_detector and request_headers:
detected = adapter_detector(request_headers, request_body)
for cap_name, cap_value in detected.items():
# 只有尚未设置的能力才从 Adapter 检测
if cap_name not in requirements:
requirements[cap_name] = cap_value
logger.debug(f"[CapabilityResolver] 从 Adapter 检测到 {cap_name}={cap_value}")
# 5. 显式覆盖(重试时使用)
if explicit_requirements:
for cap_name, cap_value in explicit_requirements.items():
requirements[cap_name] = cap_value
logger.debug(f"[CapabilityResolver] 显式覆盖 {cap_name}={cap_value}")
return requirements
@staticmethod
def get_default_requirements_for_model(
user: Any | None = None,
model_name: str | None = None,
) -> dict[str, bool]:
"""
获取用户对特定模型的默认能力需求
仅返回用户可配置型能力的配置。
Args:
user: User 对象
model_name: 模型名称
Returns:
能力需求字典
"""
requirements: dict[str, bool] = {}
if not user or not model_name:
return requirements
model_settings = getattr(user, "model_capability_settings", None) or {}
model_caps = model_settings.get(model_name, {})
for cap_def in get_user_configurable_capabilities():
if cap_def.name in model_caps:
requirements[cap_def.name] = bool(model_caps[cap_def.name])
return requirements
@staticmethod
def merge_requirements(
base: dict[str, bool] | None,
override: dict[str, bool] | None,
) -> dict[str, bool]:
"""
合并两个能力需求字典
Args:
base: 基础需求
override: 覆盖需求
Returns:
合并后的需求
"""
result = dict(base or {})
if override:
result.update(override)
return result