zhenxun_bot/zhenxun/plugins/bym_ai/call_tool.py
2025-07-01 16:56:34 +08:00

104 lines
3.2 KiB
Python

from inspect import Parameter, signature
from typing import ClassVar
import uuid
import nonebot
from nonebot import get_loaded_plugins
from nonebot.utils import is_coroutine_callable
import ujson as json
from zhenxun.configs.utils import AICallableTag, PluginExtraData
from zhenxun.services.log import logger
from .config import FunctionParam, Tool, base_config
driver = nonebot.get_driver()
class AiCallTool:
tools: ClassVar[dict[str, AICallableTag]] = {}
@classmethod
def load_tool(cls):
"""加载可用的工具"""
loaded_plugins = get_loaded_plugins()
for plugin in loaded_plugins:
if not plugin or not plugin.metadata or not plugin.metadata.extra:
continue
extra_data = PluginExtraData(**plugin.metadata.extra)
if extra_data.smart_tools:
for tool in extra_data.smart_tools:
if tool.name in cls.tools:
raise ValueError(f"Ai智能工具工具名称重复: {tool.name}")
cls.tools[tool.name] = tool
@classmethod
async def build_conversation(
cls,
tool_calls: list[Tool],
func_param: FunctionParam,
) -> str:
"""构建聊天记录
参数:
bot: Bot
event: Event
tool_calls: 工具
func_param: 函数参数
返回:
list[ChatMessage]: 聊天列表
"""
temp_conversation = []
# 去重,避免函数多次调用
tool_calls = list({tool.function.name: tool for tool in tool_calls}.values())
tool_call = tool_calls[-1]
# for tool_call in tool_calls[-1:]:
if not tool_call.id:
tool_call.id = str(uuid.uuid4())
func = tool_call.function
tool = cls.tools.get(func.name)
tool_result = ""
if tool and tool.func:
func_sign = signature(tool.func)
parsed_args = func_param.to_dict()
if args := func.arguments:
parsed_args.update(json.loads(args))
func_params = {
key: parsed_args[key]
for key, param in func_sign.parameters.items()
if param.kind
in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY)
and key in parsed_args
}
try:
if is_coroutine_callable(tool.func):
tool_result = await tool.func(**func_params)
else:
tool_result = tool.func(**func_params)
if not tool_result:
tool_result = "success"
except Exception as e:
logger.error(f"调用Ai智能工具 {func.name}", "BYM_AI", e=e)
tool_result = str(e)
# temp_conversation.append(
# ChatMessage(
# role="tool",
# tool_call_id=tool_call.id,
# content=tool_result,
# )
# )
return tool_result
@driver.on_startup
def _():
if base_config.get("BYM_AI_CHAT_SMART"):
AiCallTool.load_tool()
logger.info(
f"加载Ai智能工具完成, 成功加载 {len(AiCallTool.tools)} 个AI智能工具"
)