Tool 组件
@Tool 是 MaiBot 插件系统中最核心的组件类型。它允许插件向 LLM 暴露可调用的工具函数,使 LLM 能够在推理过程中主动调用外部能力——例如搜索知识库、查询数据库、调用外部 API 等。
Tool vs Action
@Action 是旧版装饰器,SDK 内部会自动将其转换为 @Tool 声明。新插件应直接使用 @Tool,不再使用 @Action。详见 Action 组件(Legacy)。
装饰器签名
from maibot_sdk import Tool
from maibot_sdk.types import ToolParameterInfo, ToolParamType
@Tool(
name: str, # 工具名称(必填)
description: str = "", # 工具描述,作为备选描述字段
brief_description: str = "", # 简要描述,优先级高于 description
detailed_description: str = "", # 详细描述,可包含参数说明等
parameters: list[ToolParameterInfo] | dict | None = None, # 参数定义
**metadata, # 额外元数据
)参数说明
namestr— 工具名称,需在插件内唯一。LLM 通过此名称调用工具descriptionstr— 工具备选描述。当brief_description为空时使用此字段brief_descriptionstr— 工具主描述(优先使用)。传给 LLM 的工具描述摘要,帮助 LLM 判断是否需要调用detailed_descriptionstr— 详细描述,可包含参数使用说明、注意事项等。SDK 会自动合并参数 Schema 生成完整描述parameterslist | dict | None— 工具参数定义,支持两种格式(见下文)
描述字段约定:
description:关于工具的描述,包括使用方法,使用情景,注意事项。当brief_description为空时,description会作为回退描述。brief_description:给主程序或小模型快速判断"这个工具是做什么的"的简要描述detailed_description:描述参数、必填项、可选项和调用约束的详细描述
参数定义
方式一:结构化参数(推荐)
使用 ToolParameterInfo 列表声明参数,SDK 会自动生成 JSON Schema:
from maibot_sdk import Tool, MaiBotPlugin
from maibot_sdk.types import ToolParameterInfo, ToolParamType
class MyPlugin(MaiBotPlugin):
@Tool(
"search",
brief_description="搜索互联网获取信息",
detailed_description="使用搜索引擎查找相关信息。参数说明:\n- query:string,必填。搜索关键词。\n- limit:integer,可选。返回结果数量上限。",
parameters=[
ToolParameterInfo(
name="query",
param_type=ToolParamType.STRING,
description="搜索关键词",
required=True,
),
ToolParameterInfo(
name="limit",
param_type=ToolParamType.INTEGER,
description="返回结果数量上限",
required=False,
default=5,
),
],
)
async def handle_search(self, query: str, limit: int = 5, **kwargs):
results = await self._do_search(query, limit)
return {"results": results}方式二:dict 参数(兼容旧式声明)
直接传入 JSON Schema 风格的字典:
class MyPlugin(MaiBotPlugin):
@Tool(
"search",
brief_description="搜索互联网获取信息",
parameters={
"query": {"type": "string", "description": "搜索关键词"},
"limit": {"type": "integer", "description": "返回结果数量上限", "default": 5},
},
)
async def handle_search(self, query: str, limit: int = 5, **kwargs):
results = await self._do_search(query, limit)
return {"results": results}ToolParameterInfo 字段
namestr— 参数名称param_typeToolParamType— 参数类型枚举descriptionstr— 参数描述requiredbool· 默认True— 是否必填enum_valueslist | None— 可选枚举值列表defaultAny— 默认值items_schemadict | None— 数组元素 Schema(当param_type=ARRAY时使用)propertiesdict | None— 对象属性定义(当param_type=OBJECT时使用)required_propertieslist[str]— 对象内部必填字段additional_propertiesbool | dict | None— 是否允许额外字段
ToolParamType 枚举
STRING→ JSON Schemastring— 字符串INTEGER→ JSON Schemainteger— 整数NUMBER→ JSON Schemanumber— 数字(整数或浮点数)FLOAT→ JSON Schemanumber— 浮点数(等价于 NUMBER)BOOLEAN→ JSON Schemaboolean— 布尔值ARRAY→ JSON Schemaarray— 数组OBJECT→ JSON Schemaobject— 对象
处理函数
Tool 处理函数是插件类上的异步方法,接收与参数名对应的具名参数和 **kwargs:
@Tool("greet", description="向用户打招呼",
parameters=[
ToolParameterInfo(name="stream_id", param_type=ToolParamType.STRING,
description="当前聊天流 ID", required=True),
])
async def handle_greet(self, stream_id: str, **kwargs):
await self.ctx.send.text("你好!", stream_id)
return {"success": True, "message": "已回复"}返回值
Tool 处理函数的返回值会作为工具执行结果返回给 LLM。返回值可以是:
dict:推荐,LLM 可以理解结构化数据str:简单文本结果- 其他可序列化的值
LLM 会根据返回值决定下一步操作(如向用户回复、调用其他工具等)。
返回图片和其他媒体
如果 Tool 需要把图片交给 Maisaka 继续观察或推理,不要把图片 base64 直接塞进 content。推荐返回 dict,将给 LLM 阅读的文字放在 content,将图片本体放在 content_items:
from base64 import b64encode
async def handle_draw(self, prompt: str, **kwargs):
image_bytes = await self._draw_image(prompt)
return {
"success": True,
"content": "图片已生成,请查看索引对应的图片内容。",
"content_items": [
{
"type": "image",
"data": b64encode(image_bytes).decode("ascii"),
"mime_type": "image/png",
"name": "result.png",
"description": "根据提示词生成的图片",
}
],
}也可以使用 data URL:
return {
"success": True,
"content": "图片已生成。",
"content_items": [
{
"type": "image",
"uri": f"data:image/png;base64,{b64encode(image_bytes).decode('ascii')}",
"mime_type": "image/png",
"name": "result.png",
}
],
}content_items 中常用字段如下:
type/content_typestr— 内容类型。图片使用image;也支持audio、resource_link、resource、binarydata/base64str— 媒体二进制的 base64 字符串,推荐图片直接使用这个字段uristr— 媒体 URI。图片可使用data:image/...;base64,...mime_typestr— MIME 类型,例如image/png、image/jpeg、image/webpnamestr— 文件名或展示名称descriptionstr— 对媒体内容的简短说明metadatadict— 额外元数据
Maisaka 会把这类返回拆成两种上下文消息:第一条仍是纯文本 Tool Result,其中包含类似 tool_result:<tool_call_id>:1 的媒体索引;随后追加一条普通 user message,里面放入同一索引和真实图片组件。这样可以兼容不支持在 tool result 中直接回传图片的模型 API,同时让支持视觉输入的模型按普通图片消息观察图片。
视图逻辑
拆出来的图片在 LLM 输入和 Prompt 预览里会走普通 ImageComponent 的展示逻辑,和真实收到的图片消息基本一致。区别是它的来源会标记为 tool_result_media,消息 ID 是工具媒体索引,不会被当作真实用户发来的平台消息。
kwargs 中常见的额外参数
stream_idstr— 当前聊天流 ID,可用于ctx.send.text()等发送消息messagedict— 触发此工具调用的原始消息
stream_id
stream_id 是 Tool 组件中最重要的参数之一,它标识了当前对话流。使用 ctx.send.text("消息", stream_id) 可以将消息发送到对应的聊天流中。
描述生成规则
SDK 会自动为工具生成完整的描述信息,优先级如下:
brief_description:优先使用(如果提供)description:降级回退(brief_description为空时使用)detailed_description:如果提供了,SDK 会将其与参数 Schema 合并生成完整描述- 自动生成:如果上述字段都未提供,SDK 会使用
"工具 {name}"作为描述
自动生成的参数说明格式为:
参数说明:
- query:string,必填。搜索关键词
- limit:integer,可选。返回结果数量上限。默认值:5完整示例
from typing import Any
from maibot_sdk import MaiBotPlugin, Tool
from maibot_sdk.types import ToolParameterInfo, ToolParamType
class SearchPlugin(MaiBotPlugin):
async def on_load(self) -> None:
self.ctx.logger.info("搜索插件已加载")
async def on_unload(self) -> None:
pass
async def on_config_update(self, scope: str, config_data: dict, version: str) -> None:
pass
@Tool(
"search_web",
description="搜索互联网获取信息",
parameters=[
ToolParameterInfo(
name="query",
param_type=ToolParamType.STRING,
description="搜索关键词",
required=True,
),
ToolParameterInfo(
name="limit",
param_type=ToolParamType.INTEGER,
description="返回结果数量上限",
required=False,
default=5,
),
],
)
async def search(self, query: str, limit: int = 5, **kwargs):
"""搜索互联网"""
results = await self._do_search(query, limit)
return {"results": results, "count": len(results)}
@Tool(
"get_weather",
description="获取指定城市的天气信息",
parameters=[
ToolParameterInfo(
name="city",
param_type=ToolParamType.STRING,
description="城市名称",
required=True,
),
],
)
async def get_weather(self, city: str, **kwargs):
"""查询天气"""
weather = await self._fetch_weather(city)
return {"city": city, "weather": weather}
async def _do_search(self, query: str, limit: int) -> list:
# 实际搜索逻辑
return []
async def _fetch_weather(self, city: str) -> dict:
# 实际天气查询逻辑
return {}
def create_plugin():
return SearchPlugin()与旧版 Action 的关系
@Action 装饰器在 SDK 2.0 中已废弃,内部会自动转换为 @Tool 声明:
action_parameters→ 转换为 Tool 的parametersSchema(所有参数类型统一为string)activation_type/activation_keywords→ 作为 Tool 的metadata保留- 使用
@Action时会触发DeprecationWarning
新插件应直接使用 @Tool,享受更丰富的参数类型支持和更规范的 Schema 生成。