沙盒方法详解
沙盒方法是 Nekro Agent 插件向 AI 提供功能和交互能力的主要途径。AI 在其沙盒环境中执行代码时,可以通过调用这些方法来获取信息、执行操作或请求进一步的处理。理解沙盒方法的机制、类型和编写规范对于开发有效的插件至关重要。
什么是沙盒方法?
当 AI 需要执行某些超出其自身能力范围的操作时(例如,访问外部 API、读写文件、执行复杂计算),它会生成一段代码,这段代码通常会调用插件提供的特定函数。这些被插件暴露给 AI 调用的函数,我们就称之为"沙盒方法"。
核心特点:RPC 执行机制
一个非常重要的概念是,尽管这些方法被 AI 在"沙盒"环境中调用,但它们的实际执行发生在 Nekro Agent 的主服务进程中,而不是在隔离的沙盒内。这种通信是通过 RPC(远程过程调用)实现的。
- AI 在沙盒中发起调用请求。
- Nekro Agent 核心系统接收请求,并在主进程中找到并执行对应的插件沙盒方法。
- 方法的执行结果通过 RPC 返回给沙盒环境,供 AI 后续使用。
这种机制的优势在于插件方法可以访问主服务环境的所有资源(如数据库连接、核心服务 API 等),同时保持沙盒环境的隔离性和安全性。但也需要开发者注意两者环境的差异,尤其是在处理文件路径等问题时(详见文件交互章节)。
注册沙盒方法
沙盒方法通过 @plugin.mount_sandbox_method()
装饰器注册到插件实例上。
from nekro_agent.api.plugin import SandboxMethodType
from nekro_agent.api.schemas import AgentCtx
@plugin.mount_sandbox_method(
method_type=SandboxMethodType.TOOL,
name="calculate_sum",
description="计算两个数字的和。"
)
async def my_sum_function(_ctx: AgentCtx, num1: int, num2: int) -> int:
"""计算并返回两个整数的和。
Args:
num1 (int): 第一个加数。
num2 (int): 第二个加数。
Returns:
int: 两个数字的和。
"""
return num1 + num2
装饰器参数:
method_type
(SandboxMethodType): 指定沙盒方法的类型,这决定了 AI 如何使用该方法以及框架如何处理其返回值。详见下一节。name
(str): 用于在前端展示给用户的方法名称 命名应简洁并能准确描述方法功能。它不必与 Python 函数名相同。description
(str): 对该方法的详细描述,将在前端展示给用户。
沙盒方法类型 (SandboxMethodType
)
SandboxMethodType
是一个枚举类型,定义了沙盒方法的不同行为模式。选择正确的类型对于插件与 AI 的顺畅交互至关重要。
1. SandboxMethodType.TOOL
(工具方法)
用途:提供特定的、可直接使用的工具或功能,AI 调用后可以直接利用其返回结果进行后续的思考或生成响应。这类方法通常执行计算、数据检索、简单操作等。
返回值:可以是任何 Python 内置的可序列化类型(如
str
,int
,float
,bool
,list
,dict
等),或者可以被pickle
序列化的自定义对象。框架会将返回值直接传递给沙盒中调用该方法的代码。AI 交互:AI 调用后,会等待方法执行完毕并获取返回值,然后基于返回值继续执行其任务。通常不直接触发 AI 的新一轮回复。
示例:数学计算、文本翻译、单位转换、从特定数据源获取结构化信息、检查系统状态等。
python@plugin.mount_sandbox_method(SandboxMethodType.TOOL, "get_current_time", "获取当前的日期和时间。") async def get_time(_ctx: AgentCtx) -> str: import datetime return datetime.datetime.now().isoformat()
2. SandboxMethodType.AGENT
(代理方法)
用途:用于执行需要 AI 进一步处理或解释的操作,或者提供需要 AI 进行迭代思考的信息。这类方法通常涉及到与外部世界的主动交互(如网络搜索)、复杂信息的生成或需要 AI 根据结果生成新一轮对话的场景。
返回值:必须是字符串 (
str
) 类型。这个字符串通常是对所执行操作的结果的描述,或者需要 AI 理解并据此生成回复的信息。AI 交互:方法返回的字符串会被添加到当前的对话上下文中,并立即触发 AI 进行新一轮的思考和回复。AI 会将这个返回的字符串视为一个新的观察结果或信息输入。
示例:执行网络搜索并返回摘要、调用外部知识库、生成一段复杂的文本内容供 AI 润色、需要用户进一步确认的操作等。
python@plugin.mount_sandbox_method(SandboxMethodType.AGENT, "search_knowledge_base", "根据关键词搜索内部知识库并返回相关信息。") async def search_kb(_ctx: AgentCtx, query: str) -> str: # 假设 search_internal_db 是一个执行实际搜索的函数 results = await search_internal_db(query) if not results: return f"在知识库中没有找到与 '{query}' 相关的信息。" return f"关于 '{query}' 的知识库搜索结果如下:\n{results}"
3. SandboxMethodType.BEHAVIOR
(行为方法)
用途:用于执行某些操作或修改系统状态,AI 需要知道操作的结果,但这个结果本身不应该直接触发 AI 的新一轮回复。通常用于执行一些"副作用"操作。
返回值:必须是字符串 (
str
) 类型。这个字符串是对行为执行结果的描述。AI 交互:方法返回的字符串会被作为一条系统消息添加到当前的聊天记录中,供 AI 和用户参考。但是,与
AGENT
类型不同,它不会立即触发 AI 的新一轮回复。AI 可能会在后续的思考中参考这条信息。示例:发送消息/邮件(返回发送状态)、设置定时器(返回设置成功的消息)、修改某个配置项(返回修改结果)、在用户无感知的情况下执行一些后台任务并记录结果。
pythonfrom nekro_agent.api import message @plugin.mount_sandbox_method(SandboxMethodType.BEHAVIOR, "send_channel_message", "向当前会话发送一条消息。") async def send_chat_message(_ctx: AgentCtx, text_to_send: str) -> str: try: await message.send_text(_ctx.from_chat_key, text_to_send, _ctx) return f"消息 '{text_to_send[:30]}...' 已成功发送。" except Exception as e: return f"发送消息失败: {e}"
4. SandboxMethodType.MULTIMODAL_AGENT
(多模态代理方法)
用途:与
AGENT
类型类似,但专门用于处理和返回多模态内容(如图像、音频等),并需要 AI 对这些多模态内容进行理解和回应。返回值:必须是符合特定结构的多模态消息段(通常是 OpenAI 定义的消息格式,例如包含图像 URL 或 base64 数据的消息对象)。
AI 交互:返回的多模态消息段会被添加到当前的对话上下文中,并立即触发 AI 进行新一轮的思考和回复,AI 应能处理和理解这些多模态内容。
示例:生成一张图片并返回给 AI、将文本转换为语音并让 AI 播放、分析一张用户上传的图片并返回分析结果的图文结合消息。
python# 伪代码示例,实际结构取决于 Nekro Agent 对多模态消息的处理 @plugin.mount_sandbox_method(SandboxMethodType.MULTIMODAL_AGENT, "generate_image_and_comment", "生成一张关于特定主题的图片,并附带一句评论。") async def generate_image_with_comment(_ctx: AgentCtx, topic: str) -> List[Dict[str, Any]]: # 返回值类型可能是一个dict image_url = await generate_image_service(topic) # 假设这是一个生成图片的服务 comment = f"这是一张关于 '{topic}' 的图片。" # 返回符合 OpenAI 或 Nekro Agent 内部规范的多模态消息结构 return [ { "type": "text", "text": comment }, { "type": "image_url", "image_url": { "url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA..." # (图片的Base64编码数据) } }, ]
选择合适的类型:
需求场景 | 推荐类型 |
---|---|
AI 需要直接使用方法返回的数据进行后续处理 | TOOL |
AI 需要根据方法的文本输出进行新一轮对话 | AGENT |
AI 执行操作后,只需记录结果,不立即对话 | BEHAVIOR |
AI 需要根据方法返回的多模态内容进行新一轮对话 | MULTIMODAL_AGENT |
编写沙盒方法:规范与最佳实践
为了确保 AI 能够正确、高效地使用你的沙盒方法,请遵循以下规范:
清晰的函数签名与类型注解:
- 所有沙盒方法都必须是异步函数 (
async def
)。 - 第一个参数必须是
_ctx: AgentCtx
,它提供了会话上下文信息。 - 为所有参数和返回值添加明确的 Python 类型注解。这不仅有助于代码维护,也是 AI 理解参数类型的重要依据。
- 所有沙盒方法都必须是异步函数 (
详细且结构化的文档字符串 (Docstring): 这是 AI 理解和使用你的沙盒方法的最重要信息来源之一!文档字符串应该遵循一定的格式(如 Google 风格、Numpy 风格),并至少包含:
- 简洁的摘要行:清晰说明方法的功能。
- 详细描述 (可选):如果需要,可以进一步阐述方法的工作方式、限制或注意事项。
Args:
部分:列出所有参数(除了_ctx
),说明每个参数的名称、类型和含义。Returns:
部分:说明返回值的类型和含义。Example:
部分 (强烈推荐):提供一个或多个 AI 可以理解和模仿的 Python 调用示例。这对于复杂方法尤其有用。
python@plugin.mount_sandbox_method(SandboxMethodType.TOOL, "get_user_preference", "获取指定用户的特定偏好设置。") async def get_user_preference(_ctx: AgentCtx, user_id: str, preference_key: str) -> Optional[str]: """获取用户的偏好设置值。 根据用户ID和偏好键名,从插件存储中检索对应的偏好设置值。 Args: user_id (str): 用户的唯一标识符。 preference_key (str): 需要查询的偏好设置的键名 (例如:"theme", "language")。 Returns: Optional[str]: 如果找到偏好设置,则返回其字符串值;如果未找到,则返回 None。 Example: ```python # 获取用户 'user_123' 的 'theme' 偏好设置 theme = get_user_preference(user_id="user_123", preference_key="theme") if theme: print(f"用户的主题是: {theme}") else: print("未找到用户的主题偏好设置。") ``` """ # ... 实现逻辑 ... stored_value = await plugin.store.get(user_key=user_id, store_key=preference_key) return stored_value
适当的命名:
- 沙盒方法的
name
参数(暴露给 AI 的名称)应使用清晰、简洁、符合 AI 调用习惯的命名方式(通常是下划线snake_case
或驼峰camelCase
,具体看 AI 的偏好,但保持插件内一致性)。 - Python 函数名可以更具描述性。
- 沙盒方法的
错误处理:
- 在方法内部妥善处理可能发生的异常(如 API 调用失败、文件未找到、数据格式错误等)。
- 尽量不要让未捕获的异常直接抛给 AI。如果可以,将错误信息以友好的方式包含在返回值中(特别是对于
TOOL
类型),或者记录详细日志。 - 对于
AGENT
或BEHAVIOR
类型,如果发生严重错误,可以在返回的描述字符串中说明错误情况。
返回值处理:
- 严格遵守所选
SandboxMethodType
对返回值的类型要求。 - 确保返回的数据是 AI 可理解和处理的。
- 严格遵守所选
上下文 (
AgentCtx
) 的正确使用:AgentCtx
对象 (_ctx
) 包含了当前会话的关键信息,如_ctx.from_chat_key
(会话标识)、ctx.from_user_id
(用户标识)等。按需使用这些信息,例如用于区分不同会话的数据存储、获取消息发送者等。
通过遵循这些规范,你可以创建出 AI 更易于理解、更乐于使用、也更不容易出错的强大沙盒方法。