mirror of
https://github.com/FuQuan233/nonebot-plugin-llmchat.git
synced 2026-05-12 19:42:50 +00:00
✨ 定时任务触发时,有必要支持调用mcp
This commit is contained in:
parent
b8cf6ea152
commit
bd16c6de8c
1 changed files with 93 additions and 15 deletions
|
|
@ -67,7 +67,12 @@ class SchedulerTools:
|
||||||
- daily: 每天指定时间提醒,需提供 hour (0-23) 和 minute (0-59)
|
- daily: 每天指定时间提醒,需提供 hour (0-23) 和 minute (0-59)
|
||||||
- weekly: 每周指定天提醒,需提供 hour, minute, day_of_week (0=周一, 1=周二...6=周日)
|
- weekly: 每周指定天提醒,需提供 hour, minute, day_of_week (0=周一, 1=周二...6=周日)
|
||||||
- yearly: 每年指定日期提醒,需提供 month (1-12), day (1-31), hour, minute
|
- yearly: 每年指定日期提醒,需提供 month (1-12), day (1-31), hour, minute
|
||||||
- once: 一次性提醒,需提供 minutes_later 表示几分钟后触发 (1-525600)""",
|
- once: 一次性提醒,需提供 minutes_later 表示几分钟后触发 (1-525600)
|
||||||
|
|
||||||
|
重要提示:
|
||||||
|
- description 字段非常重要,它将在任务触发时用于生成提醒信息
|
||||||
|
- 如果任务需要获取实时信息(如天气、新闻等),请在描述中明确说明,触发时AI会调用相应工具获取最新数据
|
||||||
|
- 如果用户没有提供完整信息(如查天气但没说城市),可以先创建任务,然后询问用户,得到答案后用 scheduler__update_task 更新描述""",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -160,7 +165,11 @@ class SchedulerTools:
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
"name": "scheduler__update_task",
|
"name": "scheduler__update_task",
|
||||||
"description": "更新定时任务的描述",
|
"description": """更新定时任务的描述。重要提示:
|
||||||
|
- 当用户在后续对话中补充了与已创建定时任务相关的信息时(如地点、具体要求、人名等),你应该主动调用此工具更新任务描述
|
||||||
|
- 例如:用户创建了"提醒我明天天气"的任务,后来告诉你他在"北京",你应该更新描述为"提醒我北京明天的天气"
|
||||||
|
- 任务描述应包含执行任务所需的所有关键信息,因为触发时AI会根据描述来生成提醒或执行操作
|
||||||
|
- 如果不确定最近创建的任务ID,可以先调用 scheduler__list_tasks 查看""",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -170,7 +179,7 @@ class SchedulerTools:
|
||||||
},
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "新的任务描述"
|
"description": "新的任务描述,应包含执行任务所需的所有关键信息"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["task_id", "description"]
|
"required": ["task_id", "description"]
|
||||||
|
|
@ -568,7 +577,7 @@ class SchedulerManager:
|
||||||
await self.save_tasks()
|
await self.save_tasks()
|
||||||
|
|
||||||
async def _generate_ai_reminder(self, task: ScheduledTask, plugin_config) -> str:
|
async def _generate_ai_reminder(self, task: ScheduledTask, plugin_config) -> str:
|
||||||
"""调用AI生成提醒信息"""
|
"""调用AI生成提醒信息,支持调用MCP工具获取实时信息"""
|
||||||
max_retry = plugin_config.scheduler_max_retry
|
max_retry = plugin_config.scheduler_max_retry
|
||||||
default_reminder = plugin_config.scheduler_default_reminder.format(description=task.description)
|
default_reminder = plugin_config.scheduler_default_reminder.format(description=task.description)
|
||||||
|
|
||||||
|
|
@ -600,10 +609,12 @@ class SchedulerManager:
|
||||||
system_prompt = f"""你是一个友好的提醒助手。用户设置了一个定时提醒任务,现在任务触发了。
|
system_prompt = f"""你是一个友好的提醒助手。用户设置了一个定时提醒任务,现在任务触发了。
|
||||||
请根据任务描述生成一条简短、友好的提醒消息。
|
请根据任务描述生成一条简短、友好的提醒消息。
|
||||||
要求:
|
要求:
|
||||||
|
- 如果任务描述中涉及需要获取实时信息的内容(如天气、新闻、股票等),你应该先使用相应的工具获取最新信息,然后基于获取到的信息生成提醒
|
||||||
- 消息要简洁,不要太长
|
- 消息要简洁,不要太长
|
||||||
- 语气要友好、亲切
|
- 语气要友好、亲切
|
||||||
- 可以适当使用语气词或颜文字
|
- 可以适当使用语气词或颜文字
|
||||||
- 不要有多余的解释,直接发送提醒内容"""
|
- 不要有多余的解释,直接发送提醒内容
|
||||||
|
- 如果使用了工具获取信息,请将关键信息整合到提醒消息中"""
|
||||||
|
|
||||||
user_prompt = f"任务描述:{task.description}"
|
user_prompt = f"任务描述:{task.description}"
|
||||||
|
|
||||||
|
|
@ -622,19 +633,86 @@ class SchedulerManager:
|
||||||
timeout=plugin_config.request_timeout,
|
timeout=plugin_config.request_timeout,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# 获取可用工具(如果预设支持MCP)
|
||||||
|
available_tools = None
|
||||||
|
mcp_client = None
|
||||||
|
if preset.support_mcp:
|
||||||
|
try:
|
||||||
|
from .mcpclient import MCPClient
|
||||||
|
mcp_client = MCPClient.get_instance(plugin_config.mcp_servers)
|
||||||
|
# 获取MCP工具,但不包含OneBot工具和定时任务工具(避免在提醒时创建新任务)
|
||||||
|
await mcp_client.init_tools_cache()
|
||||||
|
available_tools = mcp_client._tools_cache.copy() if mcp_client._tools_cache else []
|
||||||
|
logger.debug(f"定时任务触发时可用工具数: {len(available_tools)}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"获取MCP工具列表失败: {e}")
|
||||||
|
available_tools = None
|
||||||
|
|
||||||
|
messages = [
|
||||||
|
{"role": "system", "content": system_prompt},
|
||||||
|
{"role": "user", "content": user_prompt}
|
||||||
|
]
|
||||||
|
|
||||||
for attempt in range(max_retry):
|
for attempt in range(max_retry):
|
||||||
try:
|
try:
|
||||||
response = await client.chat.completions.create(
|
# 构建请求参数
|
||||||
model=preset.model_name,
|
request_params = {
|
||||||
max_tokens=256,
|
"model": preset.model_name,
|
||||||
temperature=0.7,
|
"max_tokens": 512, # 增加token限制以支持工具调用
|
||||||
messages=[
|
"temperature": 0.7,
|
||||||
{"role": "system", "content": system_prompt},
|
"messages": messages
|
||||||
{"role": "user", "content": user_prompt}
|
}
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
content = response.choices[0].message.content
|
# 如果有可用工具,添加到请求中
|
||||||
|
if available_tools:
|
||||||
|
request_params["tools"] = available_tools
|
||||||
|
|
||||||
|
response = await client.chat.completions.create(**request_params)
|
||||||
|
message = response.choices[0].message
|
||||||
|
|
||||||
|
# 处理工具调用
|
||||||
|
while available_tools and mcp_client and message and message.tool_calls:
|
||||||
|
logger.info(f"定时任务触发时AI调用工具: {[tc.function.name for tc in message.tool_calls]}")
|
||||||
|
|
||||||
|
# 添加assistant消息
|
||||||
|
messages.append({
|
||||||
|
"role": "assistant",
|
||||||
|
"tool_calls": [tool_call.model_dump() for tool_call in message.tool_calls]
|
||||||
|
})
|
||||||
|
|
||||||
|
# 处理每个工具调用
|
||||||
|
for tool_call in message.tool_calls:
|
||||||
|
tool_name = tool_call.function.name
|
||||||
|
tool_args = json.loads(tool_call.function.arguments)
|
||||||
|
|
||||||
|
logger.debug(f"调用工具: {tool_name}, 参数: {tool_args}")
|
||||||
|
|
||||||
|
# 调用MCP工具(使用简化的参数,因为这里不需要群操作)
|
||||||
|
try:
|
||||||
|
result = await mcp_client.call_tool(
|
||||||
|
tool_name,
|
||||||
|
tool_args,
|
||||||
|
group_id=task.context_id if task.is_group else None,
|
||||||
|
bot_id=None,
|
||||||
|
user_id=task.creator_id,
|
||||||
|
is_group=task.is_group
|
||||||
|
)
|
||||||
|
result_str = str(result) if result else "工具调用成功但无返回结果"
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"工具调用失败: {e}")
|
||||||
|
result_str = f"工具调用失败: {e}"
|
||||||
|
|
||||||
|
messages.append({
|
||||||
|
"role": "tool",
|
||||||
|
"tool_call_id": tool_call.id,
|
||||||
|
"content": result_str
|
||||||
|
})
|
||||||
|
|
||||||
|
# 再次调用AI处理工具结果
|
||||||
|
response = await client.chat.completions.create(**request_params)
|
||||||
|
message = response.choices[0].message
|
||||||
|
|
||||||
|
content = message.content
|
||||||
if content:
|
if content:
|
||||||
logger.debug(f"AI生成提醒成功: {content[:50]}...")
|
logger.debug(f"AI生成提醒成功: {content[:50]}...")
|
||||||
return content.strip()
|
return content.strip()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue