二步工具与action
This commit is contained in:
@@ -38,6 +38,14 @@ class BaseTool(ABC):
|
||||
semantic_cache_query_key: Optional[str] = None
|
||||
"""用于语义缓存的查询参数键名。如果设置,将使用此参数的值进行语义相似度搜索"""
|
||||
|
||||
# 二步工具调用相关属性
|
||||
is_two_step_tool: bool = False
|
||||
"""是否为二步工具。如果为True,工具将分两步调用:第一步展示工具信息,第二步执行具体操作"""
|
||||
step_one_description: str = ""
|
||||
"""第一步的描述,用于向LLM展示工具的基本功能"""
|
||||
sub_tools: List[Tuple[str, str, List[Tuple[str, ToolParamType, str, bool, List[str] | None]]]] = []
|
||||
"""子工具列表,格式为[(子工具名, 子工具描述, 子工具参数)]。仅在二步工具中使用"""
|
||||
|
||||
def __init__(self, plugin_config: Optional[dict] = None):
|
||||
self.plugin_config = plugin_config or {} # 直接存储插件配置字典
|
||||
|
||||
@@ -48,10 +56,64 @@ class BaseTool(ABC):
|
||||
Returns:
|
||||
dict: 工具定义字典
|
||||
"""
|
||||
if not cls.name or not cls.description or not cls.parameters:
|
||||
raise NotImplementedError(f"工具类 {cls.__name__} 必须定义 name, description 和 parameters 属性")
|
||||
if not cls.name or not cls.description:
|
||||
raise NotImplementedError(f"工具类 {cls.__name__} 必须定义 name 和 description 属性")
|
||||
|
||||
return {"name": cls.name, "description": cls.description, "parameters": cls.parameters}
|
||||
# 如果是二步工具,第一步只返回基本信息
|
||||
if cls.is_two_step_tool:
|
||||
return {
|
||||
"name": cls.name,
|
||||
"description": cls.step_one_description or cls.description,
|
||||
"parameters": [("action", ToolParamType.STRING, "选择要执行的操作", True, [sub_tool[0] for sub_tool in cls.sub_tools])]
|
||||
}
|
||||
else:
|
||||
# 普通工具需要parameters
|
||||
if not cls.parameters:
|
||||
raise NotImplementedError(f"工具类 {cls.__name__} 必须定义 parameters 属性")
|
||||
return {"name": cls.name, "description": cls.description, "parameters": cls.parameters}
|
||||
|
||||
@classmethod
|
||||
def get_step_two_tool_definition(cls, sub_tool_name: str) -> dict[str, Any]:
|
||||
"""获取二步工具的第二步定义
|
||||
|
||||
Args:
|
||||
sub_tool_name: 子工具名称
|
||||
|
||||
Returns:
|
||||
dict: 第二步工具定义字典
|
||||
"""
|
||||
if not cls.is_two_step_tool:
|
||||
raise ValueError(f"工具 {cls.name} 不是二步工具")
|
||||
|
||||
# 查找对应的子工具
|
||||
for sub_name, sub_desc, sub_params in cls.sub_tools:
|
||||
if sub_name == sub_tool_name:
|
||||
return {
|
||||
"name": f"{cls.name}_{sub_tool_name}",
|
||||
"description": sub_desc,
|
||||
"parameters": sub_params
|
||||
}
|
||||
|
||||
raise ValueError(f"未找到子工具: {sub_tool_name}")
|
||||
|
||||
@classmethod
|
||||
def get_all_sub_tool_definitions(cls) -> List[dict[str, Any]]:
|
||||
"""获取所有子工具的定义
|
||||
|
||||
Returns:
|
||||
List[dict]: 所有子工具定义列表
|
||||
"""
|
||||
if not cls.is_two_step_tool:
|
||||
return []
|
||||
|
||||
definitions = []
|
||||
for sub_name, sub_desc, sub_params in cls.sub_tools:
|
||||
definitions.append({
|
||||
"name": f"{cls.name}_{sub_name}",
|
||||
"description": sub_desc,
|
||||
"parameters": sub_params
|
||||
})
|
||||
return definitions
|
||||
|
||||
@classmethod
|
||||
def get_tool_info(cls) -> ToolInfo:
|
||||
@@ -79,8 +141,68 @@ class BaseTool(ABC):
|
||||
Returns:
|
||||
dict: 工具执行结果
|
||||
"""
|
||||
# 如果是二步工具,处理第一步调用
|
||||
if self.is_two_step_tool and "action" in function_args:
|
||||
return await self._handle_step_one(function_args)
|
||||
|
||||
raise NotImplementedError("子类必须实现execute方法")
|
||||
|
||||
async def _handle_step_one(self, function_args: dict[str, Any]) -> dict[str, Any]:
|
||||
"""处理二步工具的第一步调用
|
||||
|
||||
Args:
|
||||
function_args: 包含action参数的函数参数
|
||||
|
||||
Returns:
|
||||
dict: 第一步执行结果,包含第二步的工具定义
|
||||
"""
|
||||
action = function_args.get("action")
|
||||
if not action:
|
||||
return {"error": "缺少action参数"}
|
||||
|
||||
# 查找对应的子工具
|
||||
sub_tool_found = None
|
||||
for sub_name, sub_desc, sub_params in self.sub_tools:
|
||||
if sub_name == action:
|
||||
sub_tool_found = (sub_name, sub_desc, sub_params)
|
||||
break
|
||||
|
||||
if not sub_tool_found:
|
||||
available_actions = [sub_tool[0] for sub_tool in self.sub_tools]
|
||||
return {"error": f"未知的操作: {action}。可用操作: {available_actions}"}
|
||||
|
||||
sub_name, sub_desc, sub_params = sub_tool_found
|
||||
|
||||
# 返回第二步工具定义
|
||||
step_two_definition = {
|
||||
"name": f"{self.name}_{sub_name}",
|
||||
"description": sub_desc,
|
||||
"parameters": sub_params
|
||||
}
|
||||
|
||||
return {
|
||||
"type": "two_step_tool_step_one",
|
||||
"content": f"已选择操作: {action}。请使用以下工具进行具体调用:",
|
||||
"next_tool_definition": step_two_definition,
|
||||
"selected_action": action
|
||||
}
|
||||
|
||||
async def execute_step_two(self, sub_tool_name: str, function_args: dict[str, Any]) -> dict[str, Any]:
|
||||
"""执行二步工具的第二步
|
||||
|
||||
Args:
|
||||
sub_tool_name: 子工具名称
|
||||
function_args: 工具调用参数
|
||||
|
||||
Returns:
|
||||
dict: 工具执行结果
|
||||
"""
|
||||
if not self.is_two_step_tool:
|
||||
raise ValueError(f"工具 {self.name} 不是二步工具")
|
||||
|
||||
# 子类需要重写此方法来实现具体的第二步逻辑
|
||||
raise NotImplementedError("二步工具必须实现execute_step_two方法")
|
||||
|
||||
async def direct_execute(self, **kwargs: dict[str, Any]) -> dict[str, Any]:
|
||||
"""直接执行工具函数(供插件调用)
|
||||
通过该方法,插件可以直接调用工具,而不需要传入字典格式的参数
|
||||
|
||||
Reference in New Issue
Block a user