From 3d15ec36707de59008d88da0f9fd42f5af36898b Mon Sep 17 00:00:00 2001 From: z30057876 Date: Mon, 17 Nov 2025 19:20:38 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E8=A1=A5=E5=85=85=E6=9B=B4=E5=A4=9APrompt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 + data/prompts/system/mcp/gen_agent_name.en.md | 54 +++++++++++++ data/prompts/system/mcp/gen_agent_name.zh.md | 54 +++++++++++++ data/prompts/system/mcp/gen_step.en.md | 79 ++++++++++++++++++++ data/prompts/system/mcp/gen_step.zh.md | 79 ++++++++++++++++++++ data/prompts/system/mcp/is_param_error.en.md | 66 ++++++++++++++++ data/prompts/system/mcp/is_param_error.zh.md | 66 ++++++++++++++++ data/prompts/system/mcp/mcp_select.en.md | 32 ++++++++ data/prompts/system/mcp/mcp_select.zh.md | 32 ++++++++ data/prompts/system/mcp/risk_evaluate.en.md | 71 ++++++++++++++++++ data/prompts/system/mcp/risk_evaluate.zh.md | 71 ++++++++++++++++++ 11 files changed, 607 insertions(+) create mode 100644 data/prompts/system/mcp/gen_agent_name.en.md create mode 100644 data/prompts/system/mcp/gen_agent_name.zh.md create mode 100644 data/prompts/system/mcp/gen_step.en.md create mode 100644 data/prompts/system/mcp/gen_step.zh.md create mode 100644 data/prompts/system/mcp/is_param_error.en.md create mode 100644 data/prompts/system/mcp/is_param_error.zh.md create mode 100644 data/prompts/system/mcp/mcp_select.en.md create mode 100644 data/prompts/system/mcp/mcp_select.zh.md create mode 100644 data/prompts/system/mcp/risk_evaluate.en.md create mode 100644 data/prompts/system/mcp/risk_evaluate.zh.md diff --git a/.gitignore b/.gitignore index c62e334e6..87296ef9c 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,6 @@ logs .ruff_cache/ config uv.lock +node_modules/ +package-lock.json +package.json \ No newline at end of file diff --git a/data/prompts/system/mcp/gen_agent_name.en.md b/data/prompts/system/mcp/gen_agent_name.en.md new file mode 100644 index 000000000..542ac20e3 --- /dev/null +++ b/data/prompts/system/mcp/gen_agent_name.en.md @@ -0,0 +1,54 @@ +# Agent Name Generation Task + +## Role + +You are a professional Agent name generation assistant, capable of generating accurate, concise, and descriptive Agent names based on user goals. + +## Generation Requirements + +1. **Accuracy**: Accurately express the core process of achieving the user's goal +2. **Conciseness**: Keep the length under 20 characters, be brief and to the point +3. **Descriptiveness**: Include key operational steps (e.g., "Scan", "Analyze", "Optimize", etc.) +4. **Clarity**: Use easy-to-understand language, avoiding overly technical terms + +## Tools + +You can call the following tools to complete the Agent name generation task. + +{% raw %}{% if use_xml_format %}{% endraw %} +When calling tools, use XML-style tags for formatting. The format specification is as follows: + +```xml + +Agent Name + +``` + +{% raw %}{% endif %}{% endraw %} + +### generate_agent_name + +Description: Generate a descriptive Agent name based on the user's goal + +Parameters: + +- name: Agent name + +Usage example: + +- User goal: I need to scan the current mysql database, analyze performance bottlenecks, and tune it +- Name should be: Scan MySQL database, analyze performance bottlenecks, and tune + +{% raw %}{% if use_xml_format %}{% endraw %} + +```xml + +Scan MySQL database, analyze performance bottlenecks, and tune + +``` + +{% raw %}{% endif %}{% endraw %} + +--- + +**User Goal**: {{goal}} diff --git a/data/prompts/system/mcp/gen_agent_name.zh.md b/data/prompts/system/mcp/gen_agent_name.zh.md new file mode 100644 index 000000000..671dd37a5 --- /dev/null +++ b/data/prompts/system/mcp/gen_agent_name.zh.md @@ -0,0 +1,54 @@ +# Agent名称生成任务 + +## 角色 + +你是一个专业的Agent名称生成助手,能够根据用户目标生成准确、简洁且具有描述性的Agent名称。 + +## 生成要求 + +1. **准确性**:准确表达达成用户目标的核心过程 +2. **简洁性**:长度控制在20字以内,言简意赅 +3. **描述性**:包含关键操作步骤(如"扫描"、"分析"、"调优"等) +4. **易懂性**:使用通俗易懂的语言,避免过于专业的术语 + +## 工具 + +你可以调用以下工具来完成Agent名称生成任务。 + +{% raw %}{% if use_xml_format %}{% endraw %} +调用工具时,采用XML风格标签进行格式化。格式规范如下: + +```xml + +Agent名称 + +``` + +{% raw %}{% endif %}{% endraw %} + +### generate_agent_name + +描述:根据用户目标生成描述性的Agent名称 + +参数: + +- name:Agent名称 + +用法示例: + +- 用户目标:我需要扫描当前mysql数据库,分析性能瓶颈,并调优 +- 名称应为:扫描MySQL数据库并分析性能瓶颈,进行调优 + +{% raw %}{% if use_xml_format %}{% endraw %} + +```xml + +扫描MySQL数据库并分析性能瓶颈,进行调优 + +``` + +{% raw %}{% endif %}{% endraw %} + +--- + +**用户目标**:{{goal}} diff --git a/data/prompts/system/mcp/gen_step.en.md b/data/prompts/system/mcp/gen_step.en.md new file mode 100644 index 000000000..3e3df5c2c --- /dev/null +++ b/data/prompts/system/mcp/gen_step.en.md @@ -0,0 +1,79 @@ +# Step Planning Task + +## Role + +You are a professional workflow planning assistant who can intelligently plan the next execution step based on user goals and conversation history. + +## Task Objective + +Analyze the conversation history and user goal, then call the `create_next_step` function to plan the next execution step. + +## Planning Requirements + +1. **Accuracy**: Plan based on the results of executed steps in the conversation history +2. **Relevance**: Select the most appropriate tool for the current stage +3. **Clarity**: Step description should be concise and clear, explaining specific operations +4. **Completeness**: Ensure each step is independent and complete, directly executable + +## Available Tools List + +{% for tool in tools %} +- **Tool Name**: `{{tool.toolName}}` + **Description**: {{tool.description}} +{% endfor %} + +## Tools + +You can call the following tools to complete the step planning task. + +{% raw %}{% if use_xml_format %}{% endraw %} +When calling tools, use XML-style tags for formatting. The format specification is as follows: + +```xml + +Tool Name +Step Description + +``` + +{% raw %}{% endif %}{% endraw %} + +### create_next_step + +Description: Create the next execution step + +Parameters: + +- tool_name: Tool name, must be selected from the available tools list above +- description: Step description, clearly explain what this step will do + +Calling Specifications: + +- **Fixed function name**: Must call `create_next_step`, do not use tool names as function names +- **tool_name value**: Must be one of the tool names from the available tools list above +- **description value**: Describe the specific operations of this step +- **When task completes**: If the user goal is achieved, set `tool_name` parameter to `Final` + +Usage Example: + +- Scenario: User goal is "Analyze MySQL database performance", conversation history shows database connection established, need to perform performance analysis +- Next step should be: Call performance analysis tool to retrieve database performance metrics + +{% raw %}{% if use_xml_format %}{% endraw %} + +```xml + +mysql_analyzer +Retrieve slow query logs and performance metrics from the database + +``` + +{% raw %}{% endif %}{% endraw %} + +--- + +## Current Task + +**User Goal**: {{goal}} + +Now begin responding to user instructions, call the `create_next_step` function to plan the next step based on the results of executed steps in the conversation history above. diff --git a/data/prompts/system/mcp/gen_step.zh.md b/data/prompts/system/mcp/gen_step.zh.md new file mode 100644 index 000000000..91e149f59 --- /dev/null +++ b/data/prompts/system/mcp/gen_step.zh.md @@ -0,0 +1,79 @@ +# 步骤规划任务 + +## 角色 + +你是一个专业的工作流程规划助手,能够根据用户目标和对话历史,智能规划下一个执行步骤。 + +## 任务目标 + +分析对话历史和用户目标,然后调用 `create_next_step` 函数来规划下一个执行步骤。 + +## 规划要求 + +1. **准确性**:基于对话历史中已执行步骤的结果进行规划 +2. **针对性**:选择最适合当前阶段的工具 +3. **清晰性**:步骤描述简洁明确,说明具体操作内容 +4. **完整性**:确保每个步骤独立完整,可直接执行 + +## 可用工具列表 + +{% for tool in tools %} +- **工具名**: `{{tool.toolName}}` + **功能描述**: {{tool.description}} +{% endfor %} + +## 工具 + +你可以调用以下工具来完成步骤规划任务。 + +{% raw %}{% if use_xml_format %}{% endraw %} +调用工具时,采用XML风格标签进行格式化。格式规范如下: + +```xml + +工具名称 +步骤描述 + +``` + +{% raw %}{% endif %}{% endraw %} + +### create_next_step + +描述:创建下一个执行步骤 + +参数: + +- tool_name: 工具名称,必须从上述可用工具列表中选择 +- description: 步骤描述,清晰说明本步骤要做什么 + +调用规范: + +- **函数名固定**: 必须调用 `create_next_step`,不要使用工具名作为函数名 +- **tool_name的值**: 必须是上述可用工具列表中的某个工具名称 +- **description的值**: 描述本步骤的具体操作内容 +- **任务完成时**: 如果用户目标已经完成,将 `tool_name` 参数设为 `Final` + +用法示例: + +- 场景:用户目标是"分析MySQL数据库性能",对话历史显示已连接到数据库,需要进行性能分析 +- 下一步应为:调用性能分析工具,获取数据库的性能指标 + +{% raw %}{% if use_xml_format %}{% endraw %} + +```xml + +mysql_analyzer +获取数据库的慢查询日志和性能指标 + +``` + +{% raw %}{% endif %}{% endraw %} + +--- + +## 当前任务 + +**用户目标**: {{goal}} + +现在开始响应用户指令,根据上方对话历史中已执行步骤的结果,调用 `create_next_step` 函数规划下一步。 diff --git a/data/prompts/system/mcp/is_param_error.en.md b/data/prompts/system/mcp/is_param_error.en.md new file mode 100644 index 000000000..67a6f4c6e --- /dev/null +++ b/data/prompts/system/mcp/is_param_error.en.md @@ -0,0 +1,66 @@ +# Parameter Error Judgment Task + +## Role + +You are a professional error diagnosis assistant capable of accurately determining whether tool execution failures are caused by parameter errors. + +## Judgment Criteria + +1. **Parameter errors**: missing required parameters, incorrect parameter values, parameter format/type errors, etc. +2. **Non-parameter errors**: permission issues, network failures, system exceptions, business logic errors, etc. + +## Tools + +You can call the following tools to complete the parameter error judgment task. + +{% raw %}{% if use_xml_format %}{% endraw %} +When calling tools, use XML-style tags for formatting. The format specification is as follows: + +```xml + +whether it is a parameter error + +``` + +{% raw %}{% endif %}{% endraw %} + +### check_parameter_error + +Description: Determine whether the tool execution failure is caused by parameter errors + +Parameters: + +- is_param_error: Boolean value, true indicates parameter error, false indicates non-parameter error + +Usage example: + +- Scenario: mysql_analyzer tool input is {"host": "192.0.0.1", ...}, error message is "host is not correct" +- Analysis: The error explicitly indicates the host parameter value is incorrect, which is a parameter error +- Judgment result: true + +{% raw %}{% if use_xml_format %}{% endraw %} + +```xml + +true + +``` + +{% raw %}{% endif %}{% endraw %} + +--- + +## Current Task Context + +**User Goal**: {{goal}} + +**Current Failed Step** (Step {{step_id}}): + +- Tool: {{step_name}} +- Goal: {{step_goal}} +- Input: {{input_params}} +- Error: {{error_message}} + +--- + +Now begin responding to the user instruction. Based on the error message and context, make a comprehensive judgment and call the `check_parameter_error` tool to return the result: diff --git a/data/prompts/system/mcp/is_param_error.zh.md b/data/prompts/system/mcp/is_param_error.zh.md new file mode 100644 index 000000000..cffb4c179 --- /dev/null +++ b/data/prompts/system/mcp/is_param_error.zh.md @@ -0,0 +1,66 @@ +# 参数错误判断任务 + +## 角色 + +你是一个专业的错误诊断助手,能够准确判断工具执行失败是否由参数错误导致。 + +## 判断标准 + +1. **参数错误**:缺失必需参数、参数值不正确、参数格式/类型错误等 +2. **非参数错误**:权限问题、网络故障、系统异常、业务逻辑错误等 + +## 工具 + +你可以调用以下工具来完成参数错误判断任务。 + +{% raw %}{% if use_xml_format %}{% endraw %} +调用工具时,采用XML风格标签进行格式化。格式规范如下: + +```xml + +是否参数错误 + +``` + +{% raw %}{% endif %}{% endraw %} + +### check_parameter_error + +描述:判断工具执行失败是否由参数错误导致 + +参数: + +- is_param_error: 布尔值,true表示参数错误,false表示非参数错误 + +用法示例: + +- 场景:mysql_analyzer工具入参为 {"host": "192.0.0.1", ...},报错"host is not correct" +- 分析:错误明确指出host参数值不正确,属于参数错误 +- 判断结果:true + +{% raw %}{% if use_xml_format %}{% endraw %} + +```xml + +true + +``` + +{% raw %}{% endif %}{% endraw %} + +--- + +## 当前任务上下文 + +**用户目标**:{{goal}} + +**当前失败步骤**(步骤{{step_id}}): + +- 工具:{{step_name}} +- 目标:{{step_goal}} +- 入参:{{input_params}} +- 报错:{{error_message}} + +--- + +现在开始响应用户指令,基于报错信息和上下文综合判断,调用 `check_parameter_error` 工具返回判断结果: diff --git a/data/prompts/system/mcp/mcp_select.en.md b/data/prompts/system/mcp/mcp_select.en.md new file mode 100644 index 000000000..acb018b40 --- /dev/null +++ b/data/prompts/system/mcp/mcp_select.en.md @@ -0,0 +1,32 @@ +## Task Description + +You are an expert MCP (Model Context Protocol) selector. +Your task is to analyze the reasoning result and select the most appropriate MCP server ID. + +## Reasoning Result + +Below is the reasoning result that needs to be analyzed: + +``` +{{ reasoning_result }} +``` + +## Available MCP Servers + +List of available MCP server IDs: + +{% for mcp_id in mcp_ids %} +- `{{ mcp_id }}` +{% endfor %} + +## Selection Requirements + +Please analyze the reasoning result carefully and select the MCP server that best matches the requirements. Focus on: + +1. **Capability Matching**: Align the capability requirements described in the reasoning with the MCP server functions +2. **Scenario Fit**: Ensure the MCP server is suitable for the current application scenario +3. **Optimal Choice**: Select the most appropriate server ID from the available list + +## Output Format + +Please use the `select_mcp` tool to make your selection by providing the chosen MCP server ID. diff --git a/data/prompts/system/mcp/mcp_select.zh.md b/data/prompts/system/mcp/mcp_select.zh.md new file mode 100644 index 000000000..cd5bee14e --- /dev/null +++ b/data/prompts/system/mcp/mcp_select.zh.md @@ -0,0 +1,32 @@ +## 任务描述 + +你是一个专业的 MCP (Model Context Protocol) 选择器。 +你的任务是分析推理结果并选择最合适的 MCP 服务器 ID。 + +## 推理结果 + +以下是需要分析的推理结果: + +``` +{{ reasoning_result }} +``` + +## 可用的 MCP 服务器 + +可选的 MCP 服务器 ID 列表: + +{% for mcp_id in mcp_ids %} +- `{{ mcp_id }}` +{% endfor %} + +## 选择要求 + +请仔细分析推理结果,选择最符合需求的 MCP 服务器。重点关注: + +1. **能力匹配**:推理中描述的能力需求与 MCP 服务器功能的对应关系 +2. **场景适配**:MCP 服务器是否适合当前应用场景 +3. **最优选择**:从可用列表中选择最合适的服务器 ID + +## 输出格式 + +请使用 `select_mcp` 工具进行选择,提供选中的 MCP 服务器 ID。 diff --git a/data/prompts/system/mcp/risk_evaluate.en.md b/data/prompts/system/mcp/risk_evaluate.en.md new file mode 100644 index 000000000..f957fc85d --- /dev/null +++ b/data/prompts/system/mcp/risk_evaluate.en.md @@ -0,0 +1,71 @@ +# Tool Risk Assessment Task + +## Role + +You are a professional security risk assessment expert, capable of accurately evaluating the security risk level and potential impacts of tool execution. + +## Assessment Requirements + +1. **Risk Level**: Choose from `low`, `medium`, or `high` +2. **Risk Analysis**: Explain potential security risks, performance impacts, or operational concerns +3. **Recommendations**: Provide safe execution guidance if necessary + +## Tools + +You can call the following tools to complete the risk assessment task. + +{% raw %}{% if use_xml_format %}{% endraw %} +When calling tools, use XML-style tags for formatting. The format specification is as follows: + +```xml + +medium +This tool may increase database load + +``` + +{% raw %}{% endif %}{% endraw %} + +### evaluate_tool_risk + +Description: Evaluate the risk level and safety concerns of executing a specific tool with given parameters + +Parameters: + +- risk: Risk level, must be one of `low`, `medium`, or `high` +- reason: Explanation of the risk assessment + +Usage Example: + +- Tool: MySQL performance analysis tool (`mysql_analyzer`) +- Description: This tool will connect to a production database (MySQL 8.0.26) and perform performance analysis +- Input Parameters: {"host": "192.168.0.1", "port": 3306, "user": "root"} +- Analysis: Since the tool uses root user to connect to the production database to execute queries and statistical operations, there are significant security risks and potential privilege abuse, which may cause unintended impacts on the database. Therefore, the risk level is **medium**. It is recommended to use a read-only account with limited privileges and execute this operation during off-peak business hours. + +{% raw %}{% if use_xml_format %}{% endraw %} + +```xml + +medium +Using root user to connect to production database poses significant security risks and potential privilege abuse, which may cause unintended impacts on the database. It is recommended to use a read-only account with limited privileges and execute during off-peak hours + +``` + +{% raw %}{% endif %}{% endraw %} + +--- + +## Tool Information + +**Name**: {{tool_name}} +**Description**: {{tool_description}} + +## Input Parameters + +```json +{{input_param}} +``` + +--- + +Now begin responding to user instructions, call the `evaluate_tool_risk` tool to complete the risk assessment: diff --git a/data/prompts/system/mcp/risk_evaluate.zh.md b/data/prompts/system/mcp/risk_evaluate.zh.md new file mode 100644 index 000000000..4fa689c12 --- /dev/null +++ b/data/prompts/system/mcp/risk_evaluate.zh.md @@ -0,0 +1,71 @@ +# 工具风险评估任务 + +## 角色 + +你是一个专业的安全风险评估专家,能够准确评估工具执行的安全风险等级和潜在影响。 + +## 评估要求 + +1. **风险等级**:从 `low` (低)、`medium` (中)、`high` (高) 中选择 +2. **风险分析**:说明可能的安全隐患、性能影响或操作风险 +3. **建议**:如有必要,提供安全执行建议 + +## 工具 + +你可以调用以下工具来完成风险评估任务。 + +{% raw %}{% if use_xml_format %}{% endraw %} +调用工具时,采用XML风格标签进行格式化。格式规范如下: + +```xml + +风险等级 +风险原因 + +``` + +{% raw %}{% endif %}{% endraw %} + +### evaluate_tool_risk + +描述:评估工具执行的风险等级和安全问题 + +参数: + +- risk: 风险等级,可选值为 `low`、`medium`、`high` +- reason: 风险评估的原因说明 + +用法示例: + +- 工具:MySQL性能分析工具 (`mysql_analyzer`) +- 描述:该工具将连接到生产环境数据库 (MySQL 8.0.26) 并执行性能分析 +- 输入参数:{"host": "192.168.0.1", "port": 3306, "user": "root"} +- 分析:由于使用 root 用户连接生产数据库执行查询和统计操作,存在较高的安全风险和权限滥用隐患,可能对数据库造成意外影响,因此风险等级为**中等**。建议使用权限受限的只读账户,并在业务低峰期执行此操作。 + +{% raw %}{% if use_xml_format %}{% endraw %} + +```xml + +medium +使用 root 用户连接生产数据库存在较高的安全风险和权限滥用隐患,可能对数据库造成意外影响。建议使用权限受限的只读账户,并在业务低峰期执行 + +``` + +{% raw %}{% endif %}{% endraw %} + +--- + +## 工具信息 + +**名称**: {{tool_name}} +**描述**: {{tool_description}} + +## 输入参数 + +```json +{{input_param}} +``` + +--- + +现在开始响应用户指令,调用 `evaluate_tool_risk` 工具完成风险评估: -- Gitee From ad33e3c6cd8281a27370ac87b58b28c8e7c2f68c Mon Sep 17 00:00:00 2001 From: z30057876 Date: Mon, 17 Nov 2025 19:21:17 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/scheduler/executor/agent.py | 2 +- apps/scheduler/mcp/base.py | 33 ++++ apps/scheduler/mcp/host.py | 26 ++- apps/scheduler/mcp/plan.py | 6 +- apps/scheduler/mcp/prompt.py | 77 -------- apps/scheduler/mcp/select.py | 10 +- apps/scheduler/mcp_agent/plan.py | 47 ++--- apps/scheduler/mcp_agent/prompt.py | 298 ----------------------------- 8 files changed, 70 insertions(+), 429 deletions(-) create mode 100644 apps/scheduler/mcp/base.py diff --git a/apps/scheduler/executor/agent.py b/apps/scheduler/executor/agent.py index 05bef2639..310bfe807 100644 --- a/apps/scheduler/executor/agent.py +++ b/apps/scheduler/executor/agent.py @@ -257,7 +257,7 @@ class MCPAgentExecutor(BaseExecutor): _logger.error(err) raise RuntimeError(err) - confirm_message = await self._planner.get_tool_risk(self._current_tool, self._current_input, "") + confirm_message = await self._planner.get_tool_risk(self._current_tool, self._current_input) # 先更新状态 self.task.state.executorStatus = ExecutorStatus.WAITING diff --git a/apps/scheduler/mcp/base.py b/apps/scheduler/mcp/base.py new file mode 100644 index 000000000..ad1746bf6 --- /dev/null +++ b/apps/scheduler/mcp/base.py @@ -0,0 +1,33 @@ +# Copyright (c) Huawei Technologies Co., Ltd. 2023-2025. All rights reserved. +"""MCP节点基类""" + +import logging + +from anyio import Path + +from apps.llm import LLM +from apps.models import LanguageType + +logger = logging.getLogger(__name__) + + +class MCPNodeBase: + """MCP节点基类""" + + def __init__(self, llm: LLM, language: LanguageType = LanguageType.CHINESE) -> None: + """初始化MCP节点基类""" + self._llm = llm + self._language = language + + async def _load_prompt(self, prompt_id: str) -> str: + """ + 从Markdown文件加载提示词 + + :param prompt_id: 提示词ID,例如 "mcp_select", "gen_params" 等 + :return: 提示词内容 + """ + # 组装Prompt文件路径: prompt_id.language.md (例如: mcp_select.zh.md) + filename = f"{prompt_id}.{self._language.value}.md" + prompt_dir = Path(__file__).parent.parent.parent / "data" / "prompts" / "system" / "mcp" + prompt_file = prompt_dir / filename + return await prompt_file.read_text(encoding="utf-8") diff --git a/apps/scheduler/mcp/host.py b/apps/scheduler/mcp/host.py index 420193bba..8740070d1 100644 --- a/apps/scheduler/mcp/host.py +++ b/apps/scheduler/mcp/host.py @@ -18,19 +18,20 @@ from apps.scheduler.pool.mcp.pool import mcp_pool from apps.schemas.mcp import MCPContext, MCPPlanItem from apps.services.mcp_service import MCPServiceManager +from .base import MCPNodeBase + logger = logging.getLogger(__name__) -class MCPHost: +class MCPHost(MCPNodeBase): """MCP宿主服务""" def __init__(self, user_id: str, task_id: uuid.UUID, llm: LLM, language: LanguageType) -> None: """初始化MCP宿主""" + super().__init__(llm, language) self._task_id = task_id self._user_id = user_id self._context_list = [] - self._language = language - self._llm = llm self._env = SandboxedEnvironment( loader=BaseLoader(), autoescape=False, @@ -131,11 +132,13 @@ class MCPHost: async def _fill_params(self, tool: MCPTools, query: str) -> dict[str, Any]: """填充工具参数""" # 使用Jinja2模板生成查询 - template = self._env.from_string(FILL_PARAMS_QUERY[self._language]) + template = self._env.from_string(await self._load_prompt("gen_params")) llm_query = template.render( - instruction=query, + current_goal=query, + goal=query, # 当前实现中,总体目标和当前目标相同 tool_name=tool.toolName, tool_description=tool.description, + input_schema=json.dumps(tool.inputSchema, ensure_ascii=False), ) function_definition = { @@ -144,18 +147,13 @@ class MCPHost: "parameters": tool.inputSchema, } - # 获取历史对话记录并添加当前查询 memory_conversation = await self.assemble_memory() - conversation = [ - *memory_conversation, - {"role": "user", "content": llm_query}, - ] - - # 使用全局json_generator实例 return await json_generator.generate( function=function_definition, - conversation=conversation, - language=self._language, + conversation=[ + *memory_conversation, + ], + prompt=llm_query, ) diff --git a/apps/scheduler/mcp/plan.py b/apps/scheduler/mcp/plan.py index 3c16e0c41..50a153350 100644 --- a/apps/scheduler/mcp/plan.py +++ b/apps/scheduler/mcp/plan.py @@ -11,15 +11,17 @@ from apps.llm import LLM, json_generator from apps.models import LanguageType, MCPTools from apps.schemas.mcp import MCPPlan +from .base import MCPNodeBase from .prompt import CREATE_MCP_PLAN_FUNCTION, CREATE_PLAN, FINAL_ANSWER _logger = logging.getLogger(__name__) -class MCPPlanner: +class MCPPlanner(MCPNodeBase): """MCP 用户目标拆解与规划""" def __init__(self, user_goal: str, language: LanguageType, llm: LLM) -> None: """初始化MCP规划器""" + super().__init__(llm, language) self._user_goal = user_goal self._env = SandboxedEnvironment( loader=BaseLoader, @@ -27,8 +29,6 @@ class MCPPlanner: trim_blocks=True, lstrip_blocks=True, ) - self._language = language - self._llm = llm async def create_plan(self, tool_list: list[MCPTools], max_steps: int = 6) -> MCPPlan: diff --git a/apps/scheduler/mcp/prompt.py b/apps/scheduler/mcp/prompt.py index 1c97ad28b..bd4d07ab7 100644 --- a/apps/scheduler/mcp/prompt.py +++ b/apps/scheduler/mcp/prompt.py @@ -417,83 +417,6 @@ MEMORY_TEMPLATE: dict[str, str] = { ), } -MCP_FUNCTION_SELECT: dict[LanguageType, str] = { - LanguageType.CHINESE: dedent( - r""" - ## 任务描述 - - 你是一个专业的 MCP (Model Context Protocol) 选择器。 - 你的任务是分析推理结果并选择最合适的 MCP 服务器 ID。 - - ## 推理结果 - - 以下是需要分析的推理结果: - - ``` - {{ reasoning_result }} - ``` - - ## 可用的 MCP 服务器 - - 可选的 MCP 服务器 ID 列表: - - {% for mcp_id in mcp_ids %} - - `{{ mcp_id }}` - {% endfor %} - - ## 选择要求 - - 请仔细分析推理结果,选择最符合需求的 MCP 服务器。重点关注: - - 1. **能力匹配**:推理中描述的能力需求与 MCP 服务器功能的对应关系 - 2. **场景适配**:MCP 服务器是否适合当前应用场景 - 3. **最优选择**:从可用列表中选择最合适的服务器 ID - - ## 输出格式 - - 请使用 `select_mcp` 工具进行选择,提供选中的 MCP 服务器 ID。 - """, - ), - LanguageType.ENGLISH: dedent( - r""" - ## Task Description - - You are an expert MCP (Model Context Protocol) selector. - Your task is to analyze the reasoning result and select the most appropriate MCP server ID. - - ## Reasoning Result - - Below is the reasoning result that needs to be analyzed: - - ``` - {{ reasoning_result }} - ``` - - ## Available MCP Servers - - List of available MCP server IDs: - - {% for mcp_id in mcp_ids %} - - `{{ mcp_id }}` - {% endfor %} - - ## Selection Requirements - - Please analyze the reasoning result carefully and select the MCP server that best matches the \ -requirements. Focus on: - - 1. **Capability Matching**: Align the capability requirements described in the reasoning with the MCP \ -server functions - 2. **Scenario Fit**: Ensure the MCP server is suitable for the current application scenario - 3. **Optimal Choice**: Select the most appropriate server ID from the available list - - ## Output Format - - Please use the `select_mcp` tool to make your selection by providing the chosen MCP server ID. - """, - ), -} - SELECT_MCP_FUNCTION: dict[LanguageType, dict] = { LanguageType.CHINESE: { "name": "select_mcp", diff --git a/apps/scheduler/mcp/select.py b/apps/scheduler/mcp/select.py index 372ac399a..ef83b9105 100644 --- a/apps/scheduler/mcp/select.py +++ b/apps/scheduler/mcp/select.py @@ -14,18 +14,18 @@ from apps.models import LanguageType, MCPTools from apps.schemas.mcp import MCPSelectResult from apps.services.mcp_service import MCPServiceManager -from .prompt import MCP_FUNCTION_SELECT, SELECT_MCP_FUNCTION +from .base import MCPNodeBase +from .prompt import SELECT_MCP_FUNCTION logger = logging.getLogger(__name__) -class MCPSelector: +class MCPSelector(MCPNodeBase): """MCP选择器""" def __init__(self, llm: LLM, language: LanguageType = LanguageType.CHINESE) -> None: """初始化MCP选择器""" - self._llm = llm - self._language = language + super().__init__(llm, language) self._env = SandboxedEnvironment( loader=BaseLoader, autoescape=True, @@ -52,7 +52,7 @@ class MCPSelector: function["parameters"]["properties"]["mcp_id"]["enum"] = mcp_ids # 使用jinja2格式化模板 - template = self._env.from_string(MCP_FUNCTION_SELECT[self._language]) + template = self._env.from_string(await self._load_prompt("mcp_select")) user_prompt = template.render( reasoning_result=reasoning_result, mcp_ids=mcp_ids, diff --git a/apps/scheduler/mcp_agent/plan.py b/apps/scheduler/mcp_agent/plan.py index 70a6715eb..9df24d284 100644 --- a/apps/scheduler/mcp_agent/plan.py +++ b/apps/scheduler/mcp_agent/plan.py @@ -16,14 +16,9 @@ from apps.scheduler.mcp_agent.prompt import ( CREATE_NEXT_STEP_FUNCTION, EVALUATE_TOOL_RISK_FUNCTION, FINAL_ANSWER, - GEN_STEP, - GENERATE_FLOW_NAME, GET_FLOW_NAME_FUNCTION, GET_MISSING_PARAMS, - GET_MISSING_PARAMS_FUNCTION, - IS_PARAM_ERROR, IS_PARAM_ERROR_FUNCTION, - RISK_EVALUATE, ) from apps.scheduler.slot.slot import Slot from apps.schemas.llm import LLMChunk @@ -49,7 +44,7 @@ class MCPPlanner(MCPBase): async def get_flow_name(self) -> FlowName: """获取当前流程的名称""" - template = _env.from_string(GENERATE_FLOW_NAME[self._language]) + template = _env.from_string(await self._load_prompt("gen_agent_name")) prompt = template.render(goal=self._goal) result = await json_generator.generate( @@ -58,13 +53,13 @@ class MCPPlanner(MCPBase): {"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": prompt}, ], - language=self._language, + prompt=prompt, ) return FlowName.model_validate(result) async def create_next_step(self, tools: list[MCPTools], task: TaskData) -> Step: """创建下一步的执行步骤""" - template = _env.from_string(GEN_STEP[self._language]) + template = _env.from_string(await self._load_prompt("gen_step")) prompt = template.render(goal=self._goal, tools=tools) function = deepcopy(CREATE_NEXT_STEP_FUNCTION[self._language]) @@ -72,16 +67,13 @@ class MCPPlanner(MCPBase): history = await self.assemble_memory(task) - conversation = [ - {"role": "system", "content": "You are a helpful assistant."}, - *history, - {"role": "user", "content": prompt}, - ] - step = await json_generator.generate( function=function, - conversation=conversation, - language=self._language, + conversation=[ + {"role": "system", "content": "You are a helpful assistant."}, + *history, + ], + prompt=prompt, ) logger.info("[MCPPlanner] 创建下一步的执行步骤: %s", step) return Step.model_validate(step) @@ -90,24 +82,21 @@ class MCPPlanner(MCPBase): self, tool: MCPTools, input_param: dict[str, Any], - additional_info: str = "", ) -> ToolRisk: """获取MCP工具的风险评估结果""" - template = _env.from_string(RISK_EVALUATE[self._language]) + template = _env.from_string(await self._load_prompt("risk_evaluate")) prompt = template.render( tool_name=tool.toolName, tool_description=tool.description, input_param=input_param, - additional_info=additional_info, ) risk = await json_generator.generate( function=EVALUATE_TOOL_RISK_FUNCTION[self._language], conversation=[ {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": prompt}, ], - language=self._language, + prompt=prompt, ) return ToolRisk.model_validate(risk) @@ -121,7 +110,7 @@ class MCPPlanner(MCPBase): input_params: dict[str, Any], ) -> IsParamError: """判断错误信息是否是参数错误""" - tmplate = _env.from_string(IS_PARAM_ERROR[self._language]) + tmplate = _env.from_string(await self._load_prompt("is_param_error")) prompt = tmplate.render( goal=self._goal, step_id=tool.toolName, @@ -130,19 +119,15 @@ class MCPPlanner(MCPBase): input_params=input_params, error_message=error_message, ) - history = await self.assemble_memory(task) - conversation = [ - {"role": "system", "content": "You are a helpful assistant."}, - *history, - {"role": "user", "content": prompt}, - ] - is_param_error = await json_generator.generate( function=IS_PARAM_ERROR_FUNCTION[self._language], - conversation=conversation, - language=self._language, + conversation=[ + {"role": "system", "content": "You are a helpful assistant."}, + *history, + ], + prompt=prompt, ) return IsParamError.model_validate(is_param_error) diff --git a/apps/scheduler/mcp_agent/prompt.py b/apps/scheduler/mcp_agent/prompt.py index e18dee973..694bff67d 100644 --- a/apps/scheduler/mcp_agent/prompt.py +++ b/apps/scheduler/mcp_agent/prompt.py @@ -5,47 +5,6 @@ from textwrap import dedent from apps.models import LanguageType -GENERATE_FLOW_NAME: dict[LanguageType, str] = { - LanguageType.CHINESE: dedent( - r""" - ## 任务 - 根据用户目标生成描述性的工作流程名称。 - - ## 要求 - - **简洁明了**:准确表达达成目标的过程,长度控制在20字以内 - - **包含关键操作**:体现核心步骤(如"扫描"、"分析"、"调优"等) - - **通俗易懂**:避免过于专业的术语 - - ## 示例 - **用户目标**:我需要扫描当前mysql数据库,分析性能瓶颈,并调优 - - **输出**:扫描MySQL数据库并分析性能瓶颈,进行调优 - - --- - **用户目标**:{{goal}} - """, - ).strip("\n"), - LanguageType.ENGLISH: dedent( - r""" - ## Task - Generate a descriptive workflow name based on the user's goal. - - ## Requirements - - **Concise and clear**: Accurately express the process, keep under 20 words - - **Include key operations**: Reflect core steps (e.g., "scan", "analyze", "optimize") - - **Easy to understand**: Avoid overly technical terminology - - ## Example - **User Goal**: I need to scan the current MySQL database, analyze performance bottlenecks, and optimize it. - - **Output**: Scan MySQL database, analyze performance bottlenecks, and optimize - - --- - **User Goal**: {{goal}} - """, - ).strip("\n"), -} - GET_FLOW_NAME_FUNCTION: dict[LanguageType, dict] = { LanguageType.CHINESE: { "name": "get_flow_name", @@ -61,11 +20,6 @@ GET_FLOW_NAME_FUNCTION: dict[LanguageType, dict] = { }, "required": ["flow_name"], }, - "examples": [ - { - "flow_name": "扫描MySQL数据库并分析性能瓶颈,进行调优", - }, - ], }, LanguageType.ENGLISH: { "name": "get_flow_name", @@ -81,11 +35,6 @@ GET_FLOW_NAME_FUNCTION: dict[LanguageType, dict] = { }, "required": ["flow_name"], }, - "examples": [ - { - "flow_name": "Scan MySQL database, analyze performance bottlenecks, and optimize", - }, - ], }, } @@ -108,12 +57,6 @@ CREATE_NEXT_STEP_FUNCTION: dict[LanguageType, dict] = { }, "required": ["tool_name", "description"], }, - "examples": [ - { - "tool_name": "mcp_tool_1", - "description": "扫描ip为192.168.1.1的MySQL数据库,端口为3306,用户名为root,密码为password的数据库性能", - }, - ], }, LanguageType.ENGLISH: { "name": "create_next_step", @@ -136,109 +79,9 @@ CREATE_NEXT_STEP_FUNCTION: dict[LanguageType, dict] = { }, "required": ["tool_name", "description"], }, - "examples": [ - { - "tool_name": "mcp_tool_1", - "description": "Scan MySQL database performance at 192.168.1.1:3306 with user root", - }, - ], }, } -GEN_STEP: dict[LanguageType, str] = { - LanguageType.CHINESE: dedent( - r""" - 你的任务是分析对话历史和用户目标,然后**调用`create_next_step`函数**来规划下一个执行步骤。 - - ## 重要提醒 - **你必须且只能调用名为`create_next_step`的函数**,该函数接受两个参数: - 1. `tool_name`: 从下方可用工具列表中选择一个工具名称 - 2. `description`: 清晰描述本步骤要完成的具体任务 - - ## 可用工具列表 - {% for tool in tools %} - - **工具名**: `{{tool.toolName}}` - **功能描述**: {{tool.description}} - {% endfor %} - - ## 调用规范 - - **函数名固定**: 必须调用`create_next_step`,不要使用工具名作为函数名 - - **tool_name的值**: 必须是上述可用工具列表中的某个工具名称 - - **description的值**: 描述本步骤的具体操作内容 - - **任务完成时**: 如果用户目标已经完成,将`tool_name`参数设为`Final` - - ## 错误示例❌(严禁模仿) - ``` - # 错误:直接使用工具名作为函数名或返回工具名的字典 - {'Final': '{"description": "任务完成"}'} - ``` - - ## 正确示例✅ - ``` - # 正确:调用create_next_step函数,tool_name参数的值才是工具名称 - create_next_step( - tool_name="Final", - description="已完成所有分析任务,可以结束流程" - ) - ``` - - --- - ## 当前任务 - **用户目标**: {{goal}} - - 请根据上方对话历史中已执行步骤的结果,**调用`create_next_step`函数**规划下一步。 - 记住:函数名必须是`create_next_step`,`tool_name`参数的值才是具体的工具名称。 - """, - ).strip(), - LanguageType.ENGLISH: dedent( - r""" - Your task is to analyze the conversation history and user goal, then **call the `create_next_step` \ -function** to plan the next execution step. - - ## Important Reminder - **You must and can only call the function named `create_next_step`**, which accepts two parameters: - 1. `tool_name`: Select a tool name from the available tools list below - 2. `description`: Clearly describe the specific task this step will accomplish - - ## Available Tools List - {% for tool in tools %} - - **Tool Name**: `{{tool.toolName}}` - **Description**: {{tool.description}} - {% endfor %} - - ## Calling Specifications - - **Fixed function name**: Must call `create_next_step`, do not use tool names as function names - - **tool_name value**: Must be one of the tool names from the available tools list above - - **description value**: Describe the specific operations of this step - - **When task completes**: If the user goal is achieved, set `tool_name` parameter to `Final` - - ## Incorrect Examples ❌ (Strictly Forbidden) - ``` - # Error: Using tool name as function name or returning a dictionary with tool name as key - {'Final': '{"description": "Task completed"}'} - ``` - - ## Correct Examples ✅ - ``` - # Correct: Call create_next_step function, the tool_name parameter value is the tool name - create_next_step( - tool_name="Final", - description="All analysis tasks completed, workflow can be ended" - ) - ``` - - --- - ## Current Task - **User Goal**: {{goal}} - - Please **call the `create_next_step` function** to plan the next step based on the results of \ -executed steps in the conversation history above. - Remember: The function name must be `create_next_step`, and the `tool_name` parameter value is \ -the specific tool name. - """, - ).strip(), -} - EVALUATE_TOOL_RISK_FUNCTION: dict[LanguageType, dict] = { LanguageType.CHINESE: { "name": "evaluate_tool_risk", @@ -259,15 +102,6 @@ EVALUATE_TOOL_RISK_FUNCTION: dict[LanguageType, dict] = { }, "required": ["risk", "reason"], }, - "examples": [ - { - "risk": "medium", - "reason": ( - "当前工具将连接到MySQL数据库并分析性能,可能会对数据库性能产生一定影响。" - "请确保在非生产环境中执行此操作。" - ), - }, - ], }, LanguageType.ENGLISH: { "name": "evaluate_tool_risk", @@ -291,85 +125,9 @@ EVALUATE_TOOL_RISK_FUNCTION: dict[LanguageType, dict] = { }, "required": ["risk", "reason"], }, - "examples": [ - { - "risk": "medium", - "reason": ( - "This tool will connect to a MySQL database and analyze performance, " - "which may impact database performance. This operation should only be " - "performed in a non-production environment." - ), - }, - ], }, } -RISK_EVALUATE: dict[LanguageType, str] = { - LanguageType.CHINESE: dedent( - r""" - 评估以下工具执行的安全风险等级,并说明风险原因。 - - ## 评估要求 - - **风险等级**: 从 `low` (低)、`medium` (中)、`high` (高) 中选择 - - **风险分析**: 说明可能的安全隐患、性能影响或操作风险 - - **建议**: 如有必要,提供安全执行建议 - - ### 示例 - 假设评估MySQL性能分析工具(`mysql_analyzer`),该工具将连接到生产环境数据库(MySQL 8.0.26)并执行性能分析。 - 由于工具会执行查询和统计操作,可能短暂增加数据库负载,因此风险等级为**中等**。建议在业务低峰期执行此操作,避免影响生产服务的正常运行。 - - --- - - ## 工具信息 - **名称**: {{tool_name}} - **描述**: {{tool_description}} - - ## 输入参数 - ```json - {{input_param}} - ``` - - {% if additional_info %} - ## 上下文信息 - {{additional_info}} - {% endif %} - """, - ), - LanguageType.ENGLISH: dedent( - r""" - Evaluate the security risk level for executing the following tool and explain the reasons. - - ## Assessment Requirements - - **Risk Level**: Choose from `low`, `medium`, or `high` - - **Risk Analysis**: Explain potential security risks, performance impacts, or operational concerns - - **Recommendations**: Provide safe execution guidance if necessary - - ### Example - Consider evaluating a MySQL performance analysis tool (`mysql_analyzer`) that will connect to a production \ -database (MySQL 8.0.26) and perform performance analysis. - Since the tool will execute queries and statistical operations, it may temporarily increase database load, \ -resulting in a **medium** risk level. It is recommended to execute this operation during off-peak business hours to \ -avoid impacting normal production services. - - --- - - ## Tool Information - **Name**: {{tool_name}} - **Description**: {{tool_description}} - - ## Input Parameters - ```json - {{input_param}} - ``` - - {% if additional_info %} - ## Context Information - {{additional_info}} - {% endif %} - """, - ), -} - IS_PARAM_ERROR_FUNCTION: dict[LanguageType, dict] = { LanguageType.CHINESE: { "name": "check_parameter_error", @@ -403,62 +161,6 @@ IS_PARAM_ERROR_FUNCTION: dict[LanguageType, dict] = { }, } -IS_PARAM_ERROR: dict[LanguageType, str] = { - LanguageType.CHINESE: dedent( - r""" - 判断以下工具执行失败是否由参数错误导致,并调用 check_parameter_error 工具返回结果。 - - **判断标准**: - - **参数错误**:缺失必需参数、参数值不正确、参数格式/类型错误等 - - **非参数错误**:权限问题、网络故障、系统异常、业务逻辑错误等 - - **示例**:当mysql_analyzer工具入参为 {"host": "192.0.0.1", ...},报错"host is not correct"时, - 错误明确指出host参数值不正确,属于**参数错误**,应调用工具返回 {"is_param_error": true} - - --- - - **用户目标**:{{goal}} - - **当前失败步骤**(步骤{{step_id}}): - - 工具:{{step_name}} - - 目标:{{step_goal}} - - 入参:{{input_params}} - - 报错:{{error_message}} - - 请基于报错信息和上下文综合判断,调用 check_parameter_error 工具返回判断结果。 - """, - ), - LanguageType.ENGLISH: dedent( - r""" - Determine whether the following tool execution failure is caused by parameter errors, and call the \ -check_parameter_error tool to return the result. - - **Judgment Criteria**: - - **Parameter errors**: missing required parameters, incorrect parameter values, parameter format/type \ -errors, etc. - - **Non-parameter errors**: permission issues, network failures, system exceptions, business logic \ -errors, etc. - - **Example**: When the mysql_analyzer tool has input {"host": "192.0.0.1", ...} and error "host is not \ -correct", the error explicitly indicates the host parameter value is incorrect, which is a **parameter error**, \ -should call the tool to return {"is_param_error": true} - - --- - - **User Goal**: {{goal}} - - **Current Failed Step** (Step {{step_id}}): - - Tool: {{step_name}} - - Goal: {{step_goal}} - - Input: {{input_params}} - - Error: {{error_message}} - - Please make a comprehensive judgment based on the error message and context, and call the \ -check_parameter_error tool to return the result. - """, - ), -} - # 获取缺失的参数的json结构体 GET_MISSING_PARAMS: dict[LanguageType, str] = { LanguageType.CHINESE: dedent( -- Gitee