refactor(chat): 异步化聊天系统并重构兴趣值计算机制
将同步调用改为异步调用以提升性能,重构兴趣值计算流程以支持更灵活的组件化架构。主要改进包括: - 异步化ChatManager相关方法,避免阻塞主线程 - 重构兴趣值计算系统,从插件内部计算改为通过兴趣管理器统一处理 - 新增should_act字段支持更细粒度的动作决策 - 优化初始化逻辑,避免构造函数中的异步操作 - 扩展插件系统支持兴趣计算器组件注册 - 更新数据库模型以支持新的兴趣值相关字段 这些改进提升了系统的响应性能和可扩展性,同时保持了API的向后兼容性。
This commit is contained in:
@@ -16,11 +16,11 @@ from src.config.config import global_config
|
||||
logger = get_logger("cross_context_api")
|
||||
|
||||
|
||||
def get_context_groups(chat_id: str) -> list[list[str]] | None:
|
||||
async def get_context_groups(chat_id: str) -> list[list[str]] | None:
|
||||
"""
|
||||
获取当前聊天所在的共享组的其他聊天ID
|
||||
"""
|
||||
current_stream = get_chat_manager().get_stream(chat_id)
|
||||
current_stream = await get_chat_manager().get_stream(chat_id)
|
||||
if not current_stream:
|
||||
return None
|
||||
|
||||
@@ -59,7 +59,7 @@ async def build_cross_context_normal(chat_stream: ChatStream, other_chat_infos:
|
||||
limit=5, # 可配置
|
||||
)
|
||||
if messages:
|
||||
chat_name = get_chat_manager().get_stream_name(stream_id) or chat_raw_id
|
||||
chat_name = await get_chat_manager().get_stream_name(stream_id) or chat_raw_id
|
||||
formatted_messages, _ = await build_readable_messages_with_id(messages, timestamp_mode="relative")
|
||||
cross_context_messages.append(f'[以下是来自"{chat_name}"的近期消息]\n{formatted_messages}')
|
||||
except Exception as e:
|
||||
@@ -100,7 +100,7 @@ async def build_cross_context_s4u(
|
||||
user_messages = [msg for msg in messages if msg.get("user_id") == user_id][-5:]
|
||||
|
||||
if user_messages:
|
||||
chat_name = get_chat_manager().get_stream_name(stream_id) or chat_raw_id
|
||||
chat_name = await get_chat_manager().get_stream_name(stream_id) or chat_raw_id
|
||||
user_name = (
|
||||
target_user_info.get("person_name") or target_user_info.get("user_nickname") or user_id
|
||||
)
|
||||
@@ -167,7 +167,7 @@ async def get_chat_history_by_group_name(group_name: str) -> str:
|
||||
limit=5, # 可配置
|
||||
)
|
||||
if messages:
|
||||
chat_name = get_chat_manager().get_stream_name(stream_id) or chat_raw_id
|
||||
chat_name = await get_chat_manager().get_stream_name(stream_id) or chat_raw_id
|
||||
formatted_messages, _ = await build_readable_messages_with_id(messages, timestamp_mode="relative")
|
||||
cross_context_messages.append(f'[以下是来自"{chat_name}"的近期消息]\n{formatted_messages}')
|
||||
except Exception as e:
|
||||
|
||||
@@ -167,7 +167,7 @@ async def _send_to_target(
|
||||
logger.debug(f"[SendAPI] 发送{message_type}消息到 {stream_id}")
|
||||
|
||||
# 查找目标聊天流
|
||||
target_stream = get_chat_manager().get_stream(stream_id)
|
||||
target_stream = await get_chat_manager().get_stream(stream_id)
|
||||
if not target_stream:
|
||||
logger.error(f"[SendAPI] 未找到聊天流: {stream_id}")
|
||||
return False
|
||||
@@ -420,7 +420,7 @@ async def adapter_command_to_stream(
|
||||
logger.debug(f"[SendAPI] 自动生成临时stream_id: {stream_id}")
|
||||
|
||||
# 查找目标聊天流
|
||||
target_stream = get_chat_manager().get_stream(stream_id)
|
||||
target_stream = await get_chat_manager().get_stream(stream_id)
|
||||
if not target_stream:
|
||||
# 如果是自动生成的stream_id且找不到聊天流,创建一个临时的虚拟流
|
||||
if stream_id.startswith("adapter_temp_"):
|
||||
|
||||
220
src/plugin_system/base/base_interest_calculator.py
Normal file
220
src/plugin_system/base/base_interest_calculator.py
Normal file
@@ -0,0 +1,220 @@
|
||||
"""兴趣值计算组件基类
|
||||
|
||||
提供兴趣值计算的标准接口,确保只能有一个兴趣值计算组件实例运行
|
||||
"""
|
||||
|
||||
import time
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from src.common.data_models.database_data_model import DatabaseMessages
|
||||
|
||||
from src.common.logger import get_logger
|
||||
from src.plugin_system.base.component_types import ComponentType, InterestCalculatorInfo
|
||||
|
||||
logger = get_logger("base_interest_calculator")
|
||||
|
||||
|
||||
class InterestCalculationResult:
|
||||
"""兴趣值计算结果"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
success: bool,
|
||||
message_id: str,
|
||||
interest_value: float,
|
||||
should_take_action: bool = False,
|
||||
should_reply: bool = False,
|
||||
should_act: bool = False,
|
||||
error_message: str | None = None,
|
||||
calculation_time: float = 0.0
|
||||
):
|
||||
self.success = success
|
||||
self.message_id = message_id
|
||||
self.interest_value = max(0.0, min(1.0, interest_value)) # 确保在0-1范围内
|
||||
self.should_take_action = should_take_action
|
||||
self.should_reply = should_reply
|
||||
self.should_act = should_act
|
||||
self.error_message = error_message
|
||||
self.calculation_time = calculation_time
|
||||
self.timestamp = time.time()
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""转换为字典格式"""
|
||||
return {
|
||||
"success": self.success,
|
||||
"message_id": self.message_id,
|
||||
"interest_value": self.interest_value,
|
||||
"should_take_action": self.should_take_action,
|
||||
"should_reply": self.should_reply,
|
||||
"should_act": self.should_act,
|
||||
"error_message": self.error_message,
|
||||
"calculation_time": self.calculation_time,
|
||||
"timestamp": self.timestamp
|
||||
}
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (f"InterestCalculationResult("
|
||||
f"success={self.success}, "
|
||||
f"message_id={self.message_id}, "
|
||||
f"interest_value={self.interest_value:.3f}, "
|
||||
f"should_take_action={self.should_take_action}, "
|
||||
f"should_reply={self.should_reply}, "
|
||||
f"should_act={self.should_act})")
|
||||
|
||||
|
||||
class BaseInterestCalculator(ABC):
|
||||
"""兴趣值计算组件基类
|
||||
|
||||
所有兴趣值计算组件都必须继承此类,并实现 execute 方法
|
||||
系统确保只能有一个兴趣值计算组件实例运行
|
||||
"""
|
||||
|
||||
# 子类必须定义这些属性
|
||||
component_name: str = ""
|
||||
component_version: str = ""
|
||||
component_description: str = ""
|
||||
enabled_by_default: bool = True # 是否默认启用
|
||||
|
||||
def __init__(self):
|
||||
self._enabled = False
|
||||
self._last_calculation_time = 0.0
|
||||
self._total_calculations = 0
|
||||
self._failed_calculations = 0
|
||||
self._average_calculation_time = 0.0
|
||||
|
||||
# 验证必须定义的属性
|
||||
if not self.component_name:
|
||||
raise ValueError("子类必须定义 component_name 属性")
|
||||
if not self.component_version:
|
||||
raise ValueError("子类必须定义 component_version 属性")
|
||||
if not self.component_description:
|
||||
raise ValueError("子类必须定义 component_description 属性")
|
||||
|
||||
@abstractmethod
|
||||
async def execute(self, message: "DatabaseMessages") -> InterestCalculationResult:
|
||||
"""执行兴趣值计算
|
||||
|
||||
Args:
|
||||
message: 数据库消息对象
|
||||
|
||||
Returns:
|
||||
InterestCalculationResult: 计算结果
|
||||
"""
|
||||
pass
|
||||
|
||||
async def initialize(self) -> bool:
|
||||
"""初始化组件
|
||||
|
||||
Returns:
|
||||
bool: 初始化是否成功
|
||||
"""
|
||||
try:
|
||||
self._enabled = True
|
||||
return True
|
||||
except Exception as e:
|
||||
self._enabled = False
|
||||
return False
|
||||
|
||||
async def cleanup(self) -> bool:
|
||||
"""清理组件资源
|
||||
|
||||
Returns:
|
||||
bool: 清理是否成功
|
||||
"""
|
||||
try:
|
||||
self._enabled = False
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_enabled(self) -> bool:
|
||||
"""组件是否已启用"""
|
||||
return self._enabled
|
||||
|
||||
def get_statistics(self) -> dict:
|
||||
"""获取组件统计信息"""
|
||||
return {
|
||||
"component_name": self.component_name,
|
||||
"component_version": self.component_version,
|
||||
"enabled": self._enabled,
|
||||
"total_calculations": self._total_calculations,
|
||||
"failed_calculations": self._failed_calculations,
|
||||
"success_rate": 1.0 - (self._failed_calculations / max(1, self._total_calculations)),
|
||||
"average_calculation_time": self._average_calculation_time,
|
||||
"last_calculation_time": self._last_calculation_time
|
||||
}
|
||||
|
||||
def _update_statistics(self, result: InterestCalculationResult):
|
||||
"""更新统计信息"""
|
||||
self._total_calculations += 1
|
||||
if not result.success:
|
||||
self._failed_calculations += 1
|
||||
|
||||
# 更新平均计算时间
|
||||
if self._total_calculations == 1:
|
||||
self._average_calculation_time = result.calculation_time
|
||||
else:
|
||||
alpha = 0.1 # 指数移动平均的平滑因子
|
||||
self._average_calculation_time = (
|
||||
alpha * result.calculation_time +
|
||||
(1 - alpha) * self._average_calculation_time
|
||||
)
|
||||
|
||||
self._last_calculation_time = result.timestamp
|
||||
|
||||
async def _safe_execute(self, message: "DatabaseMessages") -> InterestCalculationResult:
|
||||
"""安全执行计算,包含统计和错误处理"""
|
||||
if not self._enabled:
|
||||
return InterestCalculationResult(
|
||||
success=False,
|
||||
message_id=getattr(message, 'message_id', ''),
|
||||
interest_value=0.0,
|
||||
error_message="组件未启用"
|
||||
)
|
||||
|
||||
start_time = time.time()
|
||||
try:
|
||||
result = await self.execute(message)
|
||||
result.calculation_time = time.time() - start_time
|
||||
self._update_statistics(result)
|
||||
return result
|
||||
except Exception as e:
|
||||
result = InterestCalculationResult(
|
||||
success=False,
|
||||
message_id=getattr(message, 'message_id', ''),
|
||||
interest_value=0.0,
|
||||
error_message=f"计算执行失败: {str(e)}",
|
||||
calculation_time=time.time() - start_time
|
||||
)
|
||||
self._update_statistics(result)
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def get_interest_calculator_info(cls) -> "InterestCalculatorInfo":
|
||||
"""从类属性生成InterestCalculatorInfo
|
||||
|
||||
遵循BaseCommand和BaseAction的设计模式,从类属性自动生成组件信息
|
||||
|
||||
Returns:
|
||||
InterestCalculatorInfo: 生成的兴趣计算器信息对象
|
||||
"""
|
||||
name = getattr(cls, 'component_name', cls.__name__.lower().replace('calculator', ''))
|
||||
if "." in name:
|
||||
logger.error(f"InterestCalculator名称 '{name}' 包含非法字符 '.',请使用下划线替代")
|
||||
raise ValueError(f"InterestCalculator名称 '{name}' 包含非法字符 '.',请使用下划线替代")
|
||||
|
||||
return InterestCalculatorInfo(
|
||||
name=name,
|
||||
component_type=ComponentType.INTEREST_CALCULATOR,
|
||||
description=getattr(cls, 'component_description', cls.__doc__ or "兴趣度计算器"),
|
||||
enabled_by_default=getattr(cls, 'enabled_by_default', True),
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (f"{self.__class__.__name__}("
|
||||
f"name={self.component_name}, "
|
||||
f"version={self.component_version}, "
|
||||
f"enabled={self._enabled})")
|
||||
@@ -1,11 +1,20 @@
|
||||
from abc import abstractmethod
|
||||
|
||||
from src.common.logger import get_logger
|
||||
from src.plugin_system.base.component_types import ActionInfo, CommandInfo, EventHandlerInfo, PlusCommandInfo, ToolInfo
|
||||
from src.plugin_system.base.component_types import (
|
||||
ActionInfo,
|
||||
CommandInfo,
|
||||
ComponentType,
|
||||
EventHandlerInfo,
|
||||
InterestCalculatorInfo,
|
||||
PlusCommandInfo,
|
||||
ToolInfo,
|
||||
)
|
||||
|
||||
from .base_action import BaseAction
|
||||
from .base_command import BaseCommand
|
||||
from .base_events_handler import BaseEventHandler
|
||||
from .base_interest_calculator import BaseInterestCalculator
|
||||
from .base_tool import BaseTool
|
||||
from .plugin_base import PluginBase
|
||||
from .plus_command import PlusCommand
|
||||
@@ -21,6 +30,72 @@ class BasePlugin(PluginBase):
|
||||
- Command组件:处理命令请求
|
||||
- 未来可扩展:Scheduler、Listener等
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _get_component_info_from_class(cls, component_class: type, component_type: ComponentType):
|
||||
"""从组件类自动生成组件信息
|
||||
|
||||
Args:
|
||||
component_class: 组件类
|
||||
component_type: 组件类型
|
||||
|
||||
Returns:
|
||||
对应类型的ComponentInfo对象
|
||||
"""
|
||||
if component_type == ComponentType.COMMAND:
|
||||
if hasattr(component_class, 'get_command_info'):
|
||||
return component_class.get_command_info()
|
||||
else:
|
||||
logger.warning(f"Command类 {component_class.__name__} 缺少 get_command_info 方法")
|
||||
return None
|
||||
|
||||
elif component_type == ComponentType.ACTION:
|
||||
if hasattr(component_class, 'get_action_info'):
|
||||
return component_class.get_action_info()
|
||||
else:
|
||||
logger.warning(f"Action类 {component_class.__name__} 缺少 get_action_info 方法")
|
||||
return None
|
||||
|
||||
elif component_type == ComponentType.INTEREST_CALCULATOR:
|
||||
if hasattr(component_class, 'get_interest_calculator_info'):
|
||||
return component_class.get_interest_calculator_info()
|
||||
else:
|
||||
logger.warning(f"InterestCalculator类 {component_class.__name__} 缺少 get_interest_calculator_info 方法")
|
||||
return None
|
||||
|
||||
elif component_type == ComponentType.PLUS_COMMAND:
|
||||
# PlusCommand的get_info逻辑可以在这里实现
|
||||
logger.warning("PlusCommand的get_info逻辑尚未实现")
|
||||
return None
|
||||
|
||||
elif component_type == ComponentType.TOOL:
|
||||
# Tool的get_info逻辑可以在这里实现
|
||||
logger.warning("Tool的get_info逻辑尚未实现")
|
||||
return None
|
||||
|
||||
elif component_type == ComponentType.EVENT_HANDLER:
|
||||
# EventHandler的get_info逻辑可以在这里实现
|
||||
logger.warning("EventHandler的get_info逻辑尚未实现")
|
||||
return None
|
||||
|
||||
else:
|
||||
logger.error(f"不支持的组件类型: {component_type}")
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_component_info(cls, component_class: type, component_type: ComponentType):
|
||||
"""获取组件信息的通用方法
|
||||
|
||||
这是一个便捷方法,内部调用_get_component_info_from_class
|
||||
|
||||
Args:
|
||||
component_class: 组件类
|
||||
component_type: 组件类型
|
||||
|
||||
Returns:
|
||||
对应类型的ComponentInfo对象
|
||||
"""
|
||||
return cls._get_component_info_from_class(component_class, component_type)
|
||||
@abstractmethod
|
||||
def get_plugin_components(
|
||||
self,
|
||||
@@ -30,6 +105,7 @@ class BasePlugin(PluginBase):
|
||||
| tuple[PlusCommandInfo, type[PlusCommand]]
|
||||
| tuple[EventHandlerInfo, type[BaseEventHandler]]
|
||||
| tuple[ToolInfo, type[BaseTool]]
|
||||
| tuple[InterestCalculatorInfo, type[BaseInterestCalculator]]
|
||||
]:
|
||||
"""获取插件包含的组件列表
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ class ComponentType(Enum):
|
||||
SCHEDULER = "scheduler" # 定时任务组件(预留)
|
||||
EVENT_HANDLER = "event_handler" # 事件处理组件
|
||||
CHATTER = "chatter" # 聊天处理器组件
|
||||
INTEREST_CALCULATOR = "interest_calculator" # 兴趣度计算组件
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value
|
||||
@@ -229,6 +230,17 @@ class ChatterInfo(ComponentInfo):
|
||||
self.component_type = ComponentType.CHATTER
|
||||
|
||||
|
||||
@dataclass
|
||||
class InterestCalculatorInfo(ComponentInfo):
|
||||
"""兴趣度计算组件信息(单例模式)"""
|
||||
|
||||
enabled_by_default: bool = True # 是否默认启用
|
||||
|
||||
def __post_init__(self):
|
||||
super().__post_init__()
|
||||
self.component_type = ComponentType.INTEREST_CALCULATOR
|
||||
|
||||
|
||||
@dataclass
|
||||
class EventInfo(ComponentInfo):
|
||||
"""事件组件信息"""
|
||||
|
||||
@@ -8,6 +8,7 @@ from src.plugin_system.base.base_action import BaseAction
|
||||
from src.plugin_system.base.base_chatter import BaseChatter
|
||||
from src.plugin_system.base.base_command import BaseCommand
|
||||
from src.plugin_system.base.base_events_handler import BaseEventHandler
|
||||
from src.plugin_system.base.base_interest_calculator import BaseInterestCalculator
|
||||
from src.plugin_system.base.base_tool import BaseTool
|
||||
from src.plugin_system.base.component_types import (
|
||||
ActionInfo,
|
||||
@@ -16,6 +17,7 @@ from src.plugin_system.base.component_types import (
|
||||
ComponentInfo,
|
||||
ComponentType,
|
||||
EventHandlerInfo,
|
||||
InterestCalculatorInfo,
|
||||
PluginInfo,
|
||||
PlusCommandInfo,
|
||||
ToolInfo,
|
||||
@@ -162,8 +164,13 @@ class ComponentRegistry:
|
||||
assert isinstance(component_info, ChatterInfo)
|
||||
assert issubclass(component_class, BaseChatter)
|
||||
ret = self._register_chatter_component(component_info, component_class)
|
||||
case ComponentType.INTEREST_CALCULATOR:
|
||||
assert isinstance(component_info, InterestCalculatorInfo)
|
||||
assert issubclass(component_class, BaseInterestCalculator)
|
||||
ret = self._register_interest_calculator_component(component_info, component_class)
|
||||
case _:
|
||||
logger.warning(f"未知组件类型: {component_type}")
|
||||
ret = False
|
||||
|
||||
if not ret:
|
||||
return False
|
||||
@@ -311,6 +318,38 @@ class ComponentRegistry:
|
||||
logger.debug(f"已注册Chatter组件: {chatter_name}")
|
||||
return True
|
||||
|
||||
def _register_interest_calculator_component(
|
||||
self, interest_calculator_info: "InterestCalculatorInfo", interest_calculator_class: type["BaseInterestCalculator"]
|
||||
) -> bool:
|
||||
"""注册InterestCalculator组件到特定注册表"""
|
||||
calculator_name = interest_calculator_info.name
|
||||
|
||||
if not calculator_name:
|
||||
logger.error(f"InterestCalculator组件 {interest_calculator_class.__name__} 必须指定名称")
|
||||
return False
|
||||
if not isinstance(interest_calculator_info, InterestCalculatorInfo) or not issubclass(interest_calculator_class, BaseInterestCalculator):
|
||||
logger.error(f"注册失败: {calculator_name} 不是有效的InterestCalculator")
|
||||
return False
|
||||
|
||||
# 创建专门的InterestCalculator注册表(如果还没有)
|
||||
if not hasattr(self, "_interest_calculator_registry"):
|
||||
self._interest_calculator_registry: dict[str, type["BaseInterestCalculator"]] = {}
|
||||
if not hasattr(self, "_enabled_interest_calculator_registry"):
|
||||
self._enabled_interest_calculator_registry: dict[str, type["BaseInterestCalculator"]] = {}
|
||||
|
||||
interest_calculator_class.plugin_name = interest_calculator_info.plugin_name
|
||||
# 设置插件配置
|
||||
interest_calculator_class.plugin_config = self.get_plugin_config(interest_calculator_info.plugin_name) or {}
|
||||
self._interest_calculator_registry[calculator_name] = interest_calculator_class
|
||||
|
||||
if not interest_calculator_info.enabled:
|
||||
logger.warning(f"InterestCalculator组件 {calculator_name} 未启用")
|
||||
return True # 未启用,但是也是注册成功
|
||||
self._enabled_interest_calculator_registry[calculator_name] = interest_calculator_class
|
||||
|
||||
logger.debug(f"已注册InterestCalculator组件: {calculator_name}")
|
||||
return True
|
||||
|
||||
# === 组件移除相关 ===
|
||||
|
||||
async def remove_component(self, component_name: str, component_type: "ComponentType", plugin_name: str) -> bool:
|
||||
|
||||
@@ -51,16 +51,28 @@ class ToolExecutor:
|
||||
chat_id: 聊天标识符,用于日志记录
|
||||
"""
|
||||
self.chat_id = chat_id
|
||||
self.chat_stream = get_chat_manager().get_stream(self.chat_id)
|
||||
self.log_prefix = f"[{get_chat_manager().get_stream_name(self.chat_id) or self.chat_id}]"
|
||||
# chat_stream 和 log_prefix 将在异步方法中初始化
|
||||
self.chat_stream = None # type: ignore
|
||||
self.log_prefix = f"[{chat_id}]"
|
||||
|
||||
self.llm_model = LLMRequest(model_set=model_config.model_task_config.tool_use, request_type="tool_executor")
|
||||
|
||||
# 二步工具调用状态管理
|
||||
self._pending_step_two_tools: dict[str, dict[str, Any]] = {}
|
||||
"""待处理的第二步工具调用,格式为 {tool_name: step_two_definition}"""
|
||||
self._log_prefix_initialized = False
|
||||
|
||||
logger.info(f"{self.log_prefix}工具执行器初始化完成")
|
||||
# logger.info(f"{self.log_prefix}工具执行器初始化完成") # 移到异步初始化中
|
||||
|
||||
async def _initialize_log_prefix(self):
|
||||
"""异步初始化log_prefix和chat_stream"""
|
||||
if not self._log_prefix_initialized:
|
||||
from src.chat.message_receive.chat_stream import get_chat_manager
|
||||
self.chat_stream = await get_chat_manager().get_stream(self.chat_id)
|
||||
stream_name = await get_chat_manager().get_stream_name(self.chat_id)
|
||||
self.log_prefix = f"[{stream_name or self.chat_id}]"
|
||||
self._log_prefix_initialized = True
|
||||
logger.info(f"{self.log_prefix}工具执行器初始化完成")
|
||||
|
||||
async def execute_from_chat_message(
|
||||
self, target_message: str, chat_history: str, sender: str, return_details: bool = False
|
||||
@@ -77,6 +89,8 @@ class ToolExecutor:
|
||||
如果return_details为False: Tuple[List[Dict], List[str], str] - (工具执行结果列表, 空, 空)
|
||||
如果return_details为True: Tuple[List[Dict], List[str], str] - (结果列表, 使用的工具, 提示词)
|
||||
"""
|
||||
# 初始化log_prefix
|
||||
await self._initialize_log_prefix()
|
||||
|
||||
# 获取可用工具
|
||||
tools = self._get_tool_definitions()
|
||||
|
||||
Reference in New Issue
Block a user