212 lines
6.0 KiB
Python
212 lines
6.0 KiB
Python
"""
|
|
AIAdapter AI适配器基类
|
|
统一不同AI类型的接口
|
|
"""
|
|
from abc import ABC, abstractmethod
|
|
from typing import Dict, Any, Optional
|
|
import asyncio
|
|
import time
|
|
|
|
|
|
class AIAdapter(ABC):
|
|
"""
|
|
AI 适配器基类
|
|
所有AI实现必须继承此类
|
|
"""
|
|
|
|
def __init__(self, ai_type: str, config: Optional[Dict] = None):
|
|
self.ai_type = ai_type
|
|
self.config = config or {}
|
|
self.last_call_time: Optional[float] = None
|
|
self.total_calls = 0
|
|
self.total_latency = 0.0
|
|
|
|
@abstractmethod
|
|
async def make_decision(self, game_state: Dict[str, Any],
|
|
available_actions: list,
|
|
player_context: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""
|
|
AI 做出决策
|
|
|
|
Args:
|
|
game_state: 完整游戏状态
|
|
available_actions: 可用操作列表
|
|
player_context: 玩家上下文(手牌、角色等)
|
|
|
|
Returns:
|
|
{
|
|
'action': str, # 操作类型
|
|
'data': Dict, # 操作数据
|
|
'reasoning': str, # 决策理由(可选)
|
|
'confidence': float # 置信度 0-1
|
|
}
|
|
"""
|
|
pass
|
|
|
|
@abstractmethod
|
|
def get_name(self) -> str:
|
|
"""获取AI名称"""
|
|
pass
|
|
|
|
def record_call(self, latency_ms: float):
|
|
"""记录调用统计"""
|
|
self.last_call_time = time.time()
|
|
self.total_calls += 1
|
|
self.total_latency += latency_ms
|
|
|
|
@property
|
|
def average_latency(self) -> float:
|
|
"""平均延迟"""
|
|
if self.total_calls == 0:
|
|
return 0.0
|
|
return self.total_latency / self.total_calls
|
|
|
|
def to_dict(self) -> Dict[str, Any]:
|
|
"""序列化信息"""
|
|
return {
|
|
'ai_type': self.ai_type,
|
|
'name': self.get_name(),
|
|
'total_calls': self.total_calls,
|
|
'average_latency_ms': round(self.average_latency, 2)
|
|
}
|
|
|
|
|
|
class RuleBasedAdapter(AIAdapter):
|
|
"""
|
|
基于规则的AI适配器
|
|
适合简单的决策逻辑
|
|
"""
|
|
|
|
def __init__(self, config: Optional[Dict] = None):
|
|
super().__init__('rule', config)
|
|
self.rule_engine = None # 在子类中实现
|
|
|
|
async def make_decision(self, game_state: Dict[str, Any],
|
|
available_actions: list,
|
|
player_context: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""
|
|
基于规则的决策
|
|
子类需要重写具体逻辑
|
|
"""
|
|
start_time = time.time()
|
|
|
|
# 默认实现:选择第一个可用操作
|
|
result = {
|
|
'action': available_actions[0] if available_actions else 'pass',
|
|
'data': {},
|
|
'reasoning': '默认规则选择',
|
|
'confidence': 0.5
|
|
}
|
|
|
|
latency = (time.time() - start_time) * 1000
|
|
self.record_call(latency)
|
|
|
|
return result
|
|
|
|
def get_name(self) -> str:
|
|
return "规则AI"
|
|
|
|
|
|
class LLMAdapter(AIAdapter):
|
|
"""
|
|
大语言模型AI适配器
|
|
支持 DeepSeek / OpenAI 等
|
|
"""
|
|
|
|
def __init__(self, model: str = 'deepseek-chat', api_key: str = '',
|
|
api_url: str = '', config: Optional[Dict] = None):
|
|
super().__init__('llm', config)
|
|
self.model = model
|
|
self.api_key = api_key
|
|
self.api_url = api_url
|
|
self.timeout = config.get('timeout', 30) if config else 30
|
|
|
|
async def make_decision(self, game_state: Dict[str, Any],
|
|
available_actions: list,
|
|
player_context: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""
|
|
调用大模型API做决策
|
|
子类需要实现具体调用逻辑
|
|
"""
|
|
start_time = time.time()
|
|
|
|
# TODO: 实现具体的API调用
|
|
# 这里先返回占位符
|
|
result = {
|
|
'action': 'pass',
|
|
'data': {},
|
|
'reasoning': '大模型响应占位符',
|
|
'confidence': 0.8
|
|
}
|
|
|
|
latency = (time.time() - start_time) * 1000
|
|
self.record_call(latency)
|
|
|
|
return result
|
|
|
|
def get_name(self) -> str:
|
|
return f"LLM({self.model})"
|
|
|
|
|
|
class MinimaxAdapter(AIAdapter):
|
|
"""
|
|
Minimax算法AI适配器
|
|
适用于象棋等完全信息博弈
|
|
"""
|
|
|
|
def __init__(self, depth: int = 3, config: Optional[Dict] = None):
|
|
super().__init__('minimax', config)
|
|
self.depth = depth
|
|
self.evaluator = None # 在子类中实现
|
|
|
|
async def make_decision(self, game_state: Dict[str, Any],
|
|
available_actions: list,
|
|
player_context: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""
|
|
Minimax决策
|
|
子类需要实现具体算法
|
|
"""
|
|
start_time = time.time()
|
|
|
|
# TODO: 实现 Minimax + Alpha-Beta
|
|
result = {
|
|
'action': available_actions[0] if available_actions else 'pass',
|
|
'data': {},
|
|
'reasoning': f'Minimax depth={self.depth}',
|
|
'confidence': 0.9
|
|
}
|
|
|
|
latency = (time.time() - start_time) * 1000
|
|
self.record_call(latency)
|
|
|
|
return result
|
|
|
|
def get_name(self) -> str:
|
|
return f"Minimax(depth={self.depth})"
|
|
|
|
|
|
class AIAdapterFactory:
|
|
"""
|
|
AI适配器工厂
|
|
用于创建不同类型的AI
|
|
"""
|
|
|
|
_adapters = {
|
|
'rule': RuleBasedAdapter,
|
|
'llm': LLMAdapter,
|
|
'minimax': MinimaxAdapter,
|
|
}
|
|
|
|
@classmethod
|
|
def register(cls, ai_type: str, adapter_class: type):
|
|
"""注册新的AI类型"""
|
|
cls._adapters[ai_type] = adapter_class
|
|
|
|
@classmethod
|
|
def create(cls, ai_type: str, config: Optional[Dict] = None) -> Optional[AIAdapter]:
|
|
"""创建AI适配器"""
|
|
adapter_class = cls._adapters.get(ai_type)
|
|
if adapter_class:
|
|
return adapter_class(config)
|
|
return None
|