From bb68ee0858d2b701cc8f64fe1a0a96b3ac9c4417 Mon Sep 17 00:00:00 2001 From: z30057876 Date: Tue, 18 Nov 2025 20:41:52 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=92=8C=E4=BF=AE=E6=AD=A3?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E8=AF=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/llm/generator.py | 117 ++--- apps/scheduler/call/core.py | 5 +- apps/scheduler/mcp/host.py | 2 +- apps/scheduler/mcp/plan.py | 2 +- apps/scheduler/mcp/prompt.py | 454 -------------------- apps/scheduler/mcp/select.py | 3 +- apps/scheduler/mcp_agent/host.py | 1 - apps/scheduler/mcp_agent/plan.py | 1 - data/prompts/system/mcp/create_plan.en.md | 42 ++ data/prompts/system/mcp/create_plan.zh.md | 103 +++++ data/prompts/system/mcp/evaluate_plan.en.md | 40 ++ data/prompts/system/mcp/evaluate_plan.zh.md | 40 ++ data/prompts/system/mcp/gen_step.en.md | 22 +- data/prompts/system/mcp/gen_step.zh.md | 22 +- data/prompts/system/mcp/mcp_select.en.md | 57 ++- data/prompts/system/mcp/mcp_select.zh.md | 59 ++- 16 files changed, 409 insertions(+), 561 deletions(-) create mode 100644 data/prompts/system/mcp/create_plan.en.md create mode 100644 data/prompts/system/mcp/create_plan.zh.md create mode 100644 data/prompts/system/mcp/evaluate_plan.en.md create mode 100644 data/prompts/system/mcp/evaluate_plan.zh.md diff --git a/apps/llm/generator.py b/apps/llm/generator.py index 7ae83eba5..5d6c3e684 100644 --- a/apps/llm/generator.py +++ b/apps/llm/generator.py @@ -35,7 +35,6 @@ class JsonGenerator: def __init__(self, llm: LLM | None = None) -> None: """创建JsonGenerator实例""" - # Jinja2环境,可以复用 self._env = SandboxedEnvironment( loader=BaseLoader(), autoescape=False, @@ -43,7 +42,6 @@ class JsonGenerator: lstrip_blocks=True, extensions=["jinja2.ext.loopcontrols"], ) - # 初始化时设为None,调用init后设置 self._llm: LLM | None = llm self._support_function_call: bool = False if llm is not None: @@ -67,52 +65,66 @@ class JsonGenerator: self, prompt: str, conversation: list[dict[str, str]], + retry_messages: list[dict[str, str]] | None = None, ) -> list[dict[str, str]]: - """构建messages,使用传入的prompt替换最后一条用户消息""" - if conversation[-1]["role"] == "user": - # 验证最后一项是用户消息 - pass - else: - err = "[JSONGenerator] 对话历史中最后一项必须是用户消息" - raise RuntimeError(err) + """ + 构建messages,拼接顺序:真实对话记录 - Prompt - 重试记录 + + Args: + prompt: 当前的prompt + conversation: 真实的对话记录 + retry_messages: 重试过程中产生的记录(不会被裁剪) - messages = [*conversation[:-1], {"role": "user", "content": prompt}] + Returns: + 拼接后的消息列表 + + """ + retry_messages = retry_messages or [] + + messages = [*conversation, {"role": "user", "content": prompt}] - # 计算Token数量 if self._llm is not None: token_count = token_calculator.calculate_token_length(messages) + retry_token_count = token_calculator.calculate_token_length(retry_messages) if retry_messages else 0 ctx_length = self._llm.config.ctxLength - # 进行消息裁剪 - if token_count > ctx_length: + available_ctx = ctx_length - retry_token_count + + if token_count > available_ctx: _logger.warning( - "[JSONGenerator] 当前对话 Token 数量 (%d) 超过模型上下文长度 (%d),进行消息裁剪", + "[JSONGenerator] 当前对话 Token 数量 (%d) 超过可用上下文长度 (%d)," + "进行消息裁剪(重试记录 Token: %d)", token_count, - ctx_length, + available_ctx, + retry_token_count, ) - trimmed_conversation = list(conversation[:-1]) + while len(messages) > 1 and token_count > available_ctx: + deleted = False + for i, msg in enumerate(messages): + if msg["role"] in ("user", "assistant"): + messages = messages[:i] + messages[i + 1:] + deleted = True + break + + if not deleted: + err = ( + f"[JSONGenerator] 无法裁剪消息以满足上下文长度限制," + f"当前 Token 数量: {token_count},可用上下文长度: {available_ctx}" + ) + raise RuntimeError(err) - while trimmed_conversation and token_count > ctx_length: - if len(trimmed_conversation) >= 2 and \ - trimmed_conversation[0]["role"] == "user" and \ - trimmed_conversation[1]["role"] == "assistant": # noqa: PLR2004 - trimmed_conversation = trimmed_conversation[2:] - elif trimmed_conversation: - trimmed_conversation = trimmed_conversation[1:] - else: - break - - # 重新构建 messages 并计算 token,添加原始最后一条用户消息以保持完整对话 - messages = [*trimmed_conversation, conversation[-1], {"role": "user", "content": prompt}] token_count = token_calculator.calculate_token_length(messages) _logger.info( - "[JSONGenerator] 裁剪后对话 Token 数量: %d,移除了 %d 条消息", + "[JSONGenerator] 裁剪后对话 Token 数量: %d(重试记录 Token: %d,总计: %d)", token_count, - len(conversation) - len(trimmed_conversation) - 1, + retry_token_count, + token_count + retry_token_count, ) + messages.extend(retry_messages) + return messages async def _single_trial( @@ -120,6 +132,7 @@ class JsonGenerator: function: dict[str, Any], prompt: str, conversation: list[dict[str, str]], + retry_messages: list[dict[str, str]] | None = None, ) -> dict[str, Any]: """单次尝试,包含校验逻辑;function使用OpenAI标准Function格式""" if self._llm is None: @@ -129,15 +142,17 @@ class JsonGenerator: schema = function["parameters"] validator = Draft7Validator(schema) - # 执行生成 if self._support_function_call: - # 如果支持FunctionCall - result = await self._call_with_function(function, prompt, conversation) + use_xml_format = False + template = self._env.from_string(prompt) + formatted_prompt = template.render(use_xml_format=use_xml_format) + result = await self._call_with_function(function, formatted_prompt, conversation, retry_messages) else: - # 如果不支持FunctionCall - result = await self._call_without_function(function, prompt, conversation) + use_xml_format = True + template = self._env.from_string(prompt) + formatted_prompt = template.render(use_xml_format=use_xml_format) + result = await self._call_without_function(function, formatted_prompt, conversation, retry_messages) - # 校验结果 try: validator.validate(result) except Exception as err: @@ -145,7 +160,6 @@ class JsonGenerator: err_info = err_info.split("\n\n")[0] _logger.info("[JSONGenerator] 验证失败:%s", err_info) - # 创建带结果的验证异常 validation_error = JsonValidationError(err_info, result) raise validation_error from err else: @@ -156,13 +170,14 @@ class JsonGenerator: function: dict[str, Any], prompt: str, conversation: list[dict[str, str]], + retry_messages: list[dict[str, str]] | None = None, ) -> dict[str, Any]: """使用FunctionCall方式调用""" if self._llm is None: err = "[JSONGenerator] 未初始化,请先调用init()方法" raise RuntimeError(err) - messages = self._build_messages(prompt, conversation) + messages = self._build_messages(prompt, conversation, retry_messages) tool = LLMFunctions( name=function["name"], @@ -183,25 +198,23 @@ class JsonGenerator: async def _call_without_function( self, - function: dict[str, Any], + _function: dict[str, Any], prompt: str, conversation: list[dict[str, str]], + retry_messages: list[dict[str, str]] | None = None, ) -> dict[str, Any]: """不使用FunctionCall方式调用""" if self._llm is None: err = "[JSONGenerator] 未初始化,请先调用init()方法" raise RuntimeError(err) - messages = self._build_messages(prompt, conversation) + messages = self._build_messages(prompt, conversation, retry_messages) - # 使用LLM的call方法获取响应 full_response = "" async for chunk in self._llm.call(messages, include_thinking=False, streaming=False): if chunk.content: full_response += chunk.content - # 从响应中提取JSON - # 查找第一个 { 和最后一个 } json_match = re.search(r"\{.*\}", full_response, re.DOTALL) if json_match: return json.loads(json_match.group(0)) @@ -220,18 +233,19 @@ class JsonGenerator: err = "[JSONGenerator] 未初始化,请先调用init()方法" raise RuntimeError(err) - # 检查schema格式是否正确 schema = function["parameters"] Draft7Validator.check_schema(schema) count = 0 - retry_conversation = conversation.copy() if conversation else [] + retry_messages: list[dict[str, str]] = [] + if conversation is None: + conversation = [] + while count < JSON_GEN_MAX_TRIAL: count += 1 try: - # 如果_single_trial没有抛出异常,直接返回结果,不进行重试 - return await self._single_trial(function, prompt, retry_conversation) + return await self._single_trial(function, prompt, conversation, retry_messages) except JsonValidationError as e: _logger.exception( "[JSONGenerator] 第 %d/%d 次尝试失败", @@ -239,20 +253,18 @@ class JsonGenerator: JSON_GEN_MAX_TRIAL, ) if count < JSON_GEN_MAX_TRIAL: - # 将错误信息添加到retry_conversation中,模拟完整的对话流程 err_info = str(e) err_info = err_info.split("\n\n")[0] - # 模拟assistant调用了函数但失败,包含实际获得的参数 function_name = function["name"] result_json = json.dumps(e.result, ensure_ascii=False) - retry_conversation.append({ + + retry_messages.append({ "role": "assistant", "content": f"I called function {function_name} with parameters: {result_json}", }) - # 模拟user要求重新调用函数并给出错误原因 - retry_conversation.append({ + retry_messages.append({ "role": "user", "content": ( f"The previous function call failed with validation error: {err_info}. " @@ -271,5 +283,4 @@ class JsonGenerator: return {} -# 全局单例实例 json_generator = JsonGenerator() diff --git a/apps/scheduler/call/core.py b/apps/scheduler/call/core.py index 9c5372565..8628af9fd 100644 --- a/apps/scheduler/call/core.py +++ b/apps/scheduler/call/core.py @@ -14,6 +14,7 @@ from typing import TYPE_CHECKING, Any, ClassVar, Self from pydantic import BaseModel, ConfigDict, Field from pydantic.json_schema import SkipJsonSchema +from apps.common.config import config from apps.models import ExecutorHistory, LanguageType, NodeInfo from apps.schemas.enum_var import CallOutputType from apps.schemas.scheduler import ( @@ -90,12 +91,10 @@ class CoreCall(BaseModel): :param prompt_id: 提示词ID,例如 "domain", "facts" 等 :return: 提示词内容 """ - # 自动获取language language = self._sys_vars.language.value - # 组装Prompt文件路径: prompt_id.language.md (例如: domain.en.md) filename = f"{prompt_id}.{language}.md" - prompt_dir = Path(__file__).parent.parent.parent / "data" / "prompts" / "call" + prompt_dir = Path(config.deploy.data_dir) / "prompts" / "call" prompt_file = prompt_dir / filename return prompt_file.read_text(encoding="utf-8") diff --git a/apps/scheduler/mcp/host.py b/apps/scheduler/mcp/host.py index 8740070d1..63a2bf392 100644 --- a/apps/scheduler/mcp/host.py +++ b/apps/scheduler/mcp/host.py @@ -12,7 +12,7 @@ from mcp.types import TextContent from apps.llm import LLM, json_generator from apps.models import LanguageType, MCPTools -from apps.scheduler.mcp.prompt import FILL_PARAMS_QUERY, MEMORY_TEMPLATE +from apps.scheduler.mcp.prompt import MEMORY_TEMPLATE from apps.scheduler.pool.mcp.client import MCPClient from apps.scheduler.pool.mcp.pool import mcp_pool from apps.schemas.mcp import MCPContext, MCPPlanItem diff --git a/apps/scheduler/mcp/plan.py b/apps/scheduler/mcp/plan.py index 50a153350..8f87ec607 100644 --- a/apps/scheduler/mcp/plan.py +++ b/apps/scheduler/mcp/plan.py @@ -12,7 +12,7 @@ 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 +from .prompt import CREATE_MCP_PLAN_FUNCTION, FINAL_ANSWER _logger = logging.getLogger(__name__) diff --git a/apps/scheduler/mcp/prompt.py b/apps/scheduler/mcp/prompt.py index bd4d07ab7..8867fc8e1 100644 --- a/apps/scheduler/mcp/prompt.py +++ b/apps/scheduler/mcp/prompt.py @@ -5,352 +5,6 @@ from textwrap import dedent from apps.models import LanguageType -MCP_SELECT: dict[LanguageType, str] = { - LanguageType.CHINESE: dedent( - r""" - 你是一个计划生成器。 - 请分析用户的目标,并生成一个计划。你后续将根据这个计划,一步一步地完成用户的目标。 - - # 一个好的计划应该: - 1. 能够成功完成用户的目标 - 2. 计划中的每一个步骤必须且只能使用一个工具。 - 3. 计划中的步骤必须具有清晰和逻辑的步骤,没有冗余或不必要的步骤。 - 4. 计划中的最后一步必须是Final工具,以确保计划执行结束。 - 5.生成的计划必须要覆盖用户的目标,不能遗漏任何用户目标中的内容。 - - # 生成计划时的注意事项: - - 每一条计划包含3个部分: - - 计划内容:描述单个计划步骤的大致内容 - - 工具ID:必须从下文的工具列表中选择 - - 工具指令:改写用户的目标,使其更符合工具的输入要求 - - 必须按照如下格式生成计划,不要输出任何额外数据: - - ```json - { - "plans": [ - { - "content": "计划内容", - "tool": "工具ID", - "instruction": "工具指令" - } - ] - } - ``` - - - 在生成计划之前,请一步一步思考,解析用户的目标,并指导你接下来的生成。\ - 思考过程应放置在 XML标签中。 - - 计划内容中,可以使用"Result[]"来引用之前计划步骤的结果。例如:"Result[3]"表示引用第三条计划执行后的结果。 - - 计划不得多于{{ max_num }}条,且每条计划内容应少于150字。 - - # 工具 - 你可以访问并使用一些工具,这些工具将在 XML标签中给出。 - - - {% for tool in tools %} - - {{ tool.toolName }}{{tool.toolName}};{{ tool.description }} - {% endfor %} - - Final结束步骤,当执行到这一步时,\ - 表示计划执行结束,所得到的结果将作为最终结果。 - - - # 样例 - ## 目标 - 在后台运行一个新的alpine:latest容器,将主机/root文件夹挂载至/data,并执行top命令。 - - ## 计划 - - 1. 这个目标需要使用Docker来完成,首先需要选择合适的MCP Server - 2. 目标可以拆解为以下几个部分: - - 运行alpine:latest容器 - - 挂载主机目录 - - 在后台运行 - - 执行top命令 - 3. 需要先选择MCP Server,然后生成Docker命令,最后执行命令 - - - ```json - { - "plans": [ - { - "content": "选择一个支持Docker的MCP Server", - "tool": "mcp_selector", - "instruction": "需要一个支持Docker容器运行的MCP Server" - }, - { - "content": "使用Result[0]中选择的MCP Server,生成Docker命令", - "tool": "command_generator", - "instruction": "生成Docker命令:在后台运行alpine:latest容器,挂载/root到/data,执行top命令" - }, - { - "content": "在Result[0]的MCP Server上执行Result[1]生成的命令", - "tool": "command_executor", - "instruction": "执行Docker命令" - }, - { - "content": "任务执行完成,容器已在后台运行,结果为Result[2]", - "tool": "Final", - "instruction": "" - } - ] - } - ``` - - # 现在开始生成计划: - ## 目标 - {{goal}} - - # 计划 - """, - ), - LanguageType.ENGLISH: dedent( - r""" - You are a helpful intelligent assistant. - Your task is to select the most appropriate MCP server based on your current goals. - - ## Things to note when selecting an MCP server: - 1. Ensure you fully understand your current goals and select the most appropriate MCP server. - 2. Please select from the provided list of MCP servers; do not generate your own. - 3. Please provide the rationale for your choice before making your selection. - 4. Your current goals will be listed below, along with the list of MCP servers. - Please include your thought process in the "Thought Process" section and your selection in the \ -"Selection Results" section. - 5. Your selection must be in JSON format, strictly following the template below. Do not output any \ -additional content: - - ```json - { - "mcp": "The name of your selected MCP server" - } - ``` - - 6. The following example is for reference only. Do not use it as a basis for selecting an MCP server. - - ## Example - ### Goal - I need an MCP server to complete a task. - - ### MCP Server List - - **mcp_1**: "MCP Server 1"; Description of MCP Server 1 - - **mcp_2**: "MCP Server 2"; Description of MCP Server 2 - - ### Think step by step: - Because the current goal requires an MCP server to complete a task, select mcp_1. - - ### Select Result - ```json - { - "mcp": "mcp_1" - } - ``` - - ## Let's get started! - ### Goal - {{goal}} - - ### MCP Server List - {% for mcp in mcp_list %} - - **{{mcp.id}}**: "{{mcp.name}}"; {{mcp.description}} - {% endfor %} - - ### Think step by step: - """, - ), -} - -CREATE_PLAN: dict[str, str] = { - LanguageType.CHINESE: dedent( - r""" - ## 任务 - 分析用户目标并生成执行计划,用于后续逐步完成目标。 - - ## 计划要求 - 1. **每步一工具**:每个步骤仅使用一个工具 - 2. **逻辑清晰**:步骤间有明确依赖关系,无冗余 - 3. **目标覆盖**:不遗漏用户目标的任何内容 - 4. **步骤上限**:不超过 {{ max_num }} 条,每条不超过150字 - 5. **必须结束**:最后一步使用 `Final` 工具 - - ## 计划结构 - 每条计划包含三要素: - - **content**:步骤描述,可用 `Result[i]` 引用前序结果 - - **tool**:工具ID(从工具列表中选择) - - **instruction**:针对工具的具体指令 - - ## 工具列表 - {% for tool in tools %} - - **{{ tool.toolName }}**: {{tool.toolName}};{{ tool.description }} - {% endfor %} - - **Final**: 结束步骤,标志计划执行完成 - - ## 示例 - 假设用户目标是:在后台运行 alpine:latest 容器,挂载 /root 到 /data,执行 top 命令 - - 首先分析这个目标: - - 这需要 Docker 支持,因此第一步应该选择一个支持 Docker 的 MCP Server - - 接着需要生成符合要求的 Docker 命令,包括容器镜像、目录挂载、后台运行和命令执行 - - 然后执行生成的命令 - - 最后标记任务完成 - - 基于这个分析,可以生成以下计划: - - 第一步:选择支持 Docker 的 MCP Server,使用 mcp_selector 工具,\ -指令是"需要支持 Docker 容器运行的 MCP Server" - - 第二步:基于 Result[0] 生成 Docker 命令,使用 command_generator 工具,\ -指令是"生成命令:后台运行 alpine:latest,挂载 /root 至 /data,执行 top" - - 第三步:在 Result[0] 上执行 Result[1] 的命令,使用 command_executor 工具,指令是"执行 Docker 命令" - - 第四步:容器已运行,输出 Result[2],使用 Final 工具,指令为空 - - ## 用户目标 - {{goal}} - - ## 请生成计划 - 先分析目标,理清思路,然后生成结构化的执行计划。 - """, - ), - LanguageType.ENGLISH: dedent( - r""" - ## Task - Analyze the user's goal and generate an execution plan to accomplish the goal step by step. - - ## Plan Requirements - 1. **One Tool Per Step**: Each step uses only one tool - 2. **Clear Logic**: Steps have explicit dependencies, no redundancy - 3. **Complete Coverage**: Don't miss any part of the user's goal - 4. **Step Limit**: Maximum {{ max_num }} steps, each under 150 words - 5. **Must End**: Final step must use the `Final` tool - - ## Plan Structure - Each plan contains three elements: - - **content**: Step description, can reference previous results with `Result[i]` - - **tool**: Tool ID (selected from tool list) - - **instruction**: Specific instruction for the tool - - ## Tool List - {% for tool in tools %} - - **{{ tool.toolName }}**: {{tool.toolName}}; {{ tool.description }} - {% endfor %} - - **Final**: End step, marks plan execution complete - - ## Example - Suppose the user's goal is: Run alpine:latest container in background, mount /root to /data, \ -execute top command - - First, analyze this goal: - - This requires Docker support, so the first step should select an MCP Server with Docker capability - - Next, need to generate a Docker command that meets the requirements, including container image, \ -directory mount, background execution, and command execution - - Then execute the generated command - - Finally, mark the task as complete - - Based on this analysis, the following plan can be generated: - - Step 1: Select MCP Server with Docker support, using mcp_selector tool, \ -instruction is "Need MCP Server supporting Docker container operation" - - Step 2: Generate Docker command based on Result[0], using command_generator tool, \ -instruction is "Generate command: run alpine:latest in background, mount /root to /data, execute top" - - Step 3: Execute Result[1] command on Result[0], using command_executor tool, \ -instruction is "Execute Docker command" - - Step 4: Container running, output Result[2], using Final tool, instruction is empty - - ## User Goal - {{goal}} - - ## Please Generate Plan - First analyze the goal and clarify your thinking, then generate a structured execution plan. - """, - ), -} - -EVALUATE_PLAN: dict[LanguageType, str] = { - LanguageType.CHINESE: dedent( - r""" - 你是一个计划评估器。 - 请根据给定的计划,和当前计划执行的实际情况,分析当前计划是否合理和完整,并生成改进后的计划。 - - # 一个好的计划应该: - 1. 能够成功完成用户的目标 - 2. 计划中的每一个步骤必须且只能使用一个工具。 - 3. 计划中的步骤必须具有清晰和逻辑的步骤,没有冗余或不必要的步骤。 - 4. 计划中的最后一步必须是Final工具,以确保计划执行结束。 - - # 你此前的计划是: - {{ plan }} - - # 这个计划的执行情况是: - 计划的执行情况将放置在 XML标签中。 - - - {{ memory }} - - - # 进行评估时的注意事项: - - 请一步一步思考,解析用户的目标,并指导你接下来的生成。思考过程应放置在 XML标签中。 - - 评估结果分为两个部分: - - 计划评估的结论 - - 改进后的计划 - - 请按照以下JSON格式输出评估结果: - - ```json - { - "evaluation": "评估结果", - "plans": [ - { - "content": "改进后的计划内容", - "tool": "工具ID", - "instruction": "工具指令" - } - ] - } - ``` - - # 现在开始评估计划: - """, - ), - LanguageType.ENGLISH: dedent( - r""" - You are a plan evaluator. - Based on the given plan and the actual execution of the current plan, analyze whether the current plan is \ -reasonable and complete, and generate an improved plan. - - # A good plan should: - 1. Be able to successfully achieve the user's goal. - 2. Each step in the plan must use only one tool. - 3. The steps in the plan must have clear and logical steps, without redundant or unnecessary steps. - 4. The last step in the plan must be a Final tool to ensure the completion of the plan execution. - - # Your previous plan was: - {{ plan }} - - # The execution status of this plan is: - The execution status of the plan will be placed in the XML tags. - - - {{ memory }} - - - # Notes when conducting the evaluation: - - Please think step by step, analyze the user's goal, and guide your subsequent generation. The thinking \ -process should be placed in the XML tags. - - The evaluation results are divided into two parts: - - Conclusion of the plan evaluation - - Improved plan - - Please output the evaluation results in the following JSON format: - - ```json - { - "evaluation": "Evaluation results", - "plans": [ - { - "content": "Improved plan content", - "tool": "Tool ID", - "instruction": "Tool instructions" - } - ] - } - ``` - - # Start evaluating the plan now: - """, - ), -} FINAL_ANSWER: dict[str, str] = { LanguageType.CHINESE: dedent( r""" @@ -448,59 +102,6 @@ SELECT_MCP_FUNCTION: dict[LanguageType, dict] = { }, } -FILL_PARAMS_QUERY: dict[LanguageType, str] = { - LanguageType.CHINESE: dedent( - r""" - ## 当前目标 - - {{ instruction }} - - ## 可用工具 - - 你可以使用 `{{ tool_name }}` 工具来完成上述目标。 - - ### 工具信息 - - **工具名称**: `{{ tool_name }}` - - **工具描述**: {{ tool_description }} - - ## 说明 - - 请调用上述工具来完成当前目标。注意事项: - - 1. 仔细分析目标的具体要求,确保工具调用能达成预期结果 - 2. 参考上下文信息,合理使用已有的结果和数据 - 3. 提供所有必需信息,可选信息根据需要补充 - 4. 必须至少选择1个工具进行调用 - 5. 不要编造或假设不存在的信息 - """, - ), - LanguageType.ENGLISH: dedent( - r""" - ## Current Objective - - {{ instruction }} - - ## Available Tool - - You can use the `{{ tool_name }}` tool to accomplish the above objective. - - ### Tool Information - - **Tool Name**: `{{ tool_name }}` - - **Tool Description**: {{ tool_description }} - - ## Instructions - - Please invoke the above tool to complete the current objective. Key points: - - 1. Carefully analyze the objective requirements to ensure the tool invocation achieves the expected results - 2. Reference contextual information and reasonably use existing results and data - 3. Provide all required information, supplement optional information as needed - 4. Must invoke at least 1 tool - 5. Do not fabricate or assume non-existent information - """, - ), -} - CREATE_MCP_PLAN_FUNCTION: dict[LanguageType, dict] = { LanguageType.CHINESE: { "name": "create_mcp_plan", @@ -542,32 +143,6 @@ CREATE_MCP_PLAN_FUNCTION: dict[LanguageType, dict] = { "required": ["plans"], "additionalProperties": False, }, - "examples": [ - { - "plans": [ - { - "content": "选择支持 Docker 的 MCP Server", - "tool": "mcp_selector", - "instruction": "需要支持 Docker 容器运行的 MCP Server", - }, - { - "content": "基于 Result[0] 生成 Docker 命令", - "tool": "command_generator", - "instruction": "生成命令:后台运行 alpine:latest,挂载 /root 至 /data,执行 top", - }, - { - "content": "在 Result[0] 上执行 Result[1] 的命令", - "tool": "command_executor", - "instruction": "执行 Docker 命令", - }, - { - "content": "容器已运行,输出 Result[2]", - "tool": "Final", - "instruction": "", - }, - ], - }, - ], }, LanguageType.ENGLISH: { "name": "create_mcp_plan", @@ -617,34 +192,5 @@ CREATE_MCP_PLAN_FUNCTION: dict[LanguageType, dict] = { "required": ["plans"], "additionalProperties": False, }, - "examples": [ - { - "plans": [ - { - "content": "Select MCP Server with Docker support", - "tool": "mcp_selector", - "instruction": "Need MCP Server supporting Docker container operation", - }, - { - "content": "Generate Docker command based on Result[0]", - "tool": "command_generator", - "instruction": ( - "Generate command: run alpine:latest in background, " - "mount /root to /data, execute top" - ), - }, - { - "content": "Execute Result[1] command on Result[0]", - "tool": "command_executor", - "instruction": "Execute Docker command", - }, - { - "content": "Container running, output Result[2]", - "tool": "Final", - "instruction": "", - }, - ], - }, - ], }, } diff --git a/apps/scheduler/mcp/select.py b/apps/scheduler/mcp/select.py index ef83b9105..f2f3f5d4f 100644 --- a/apps/scheduler/mcp/select.py +++ b/apps/scheduler/mcp/select.py @@ -63,9 +63,8 @@ class MCPSelector(MCPNodeBase): function=function, conversation=[ {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": user_prompt}, ], - language=self._language, + prompt=user_prompt, ) try: diff --git a/apps/scheduler/mcp_agent/host.py b/apps/scheduler/mcp_agent/host.py index 3474ffd2a..632e07db8 100644 --- a/apps/scheduler/mcp_agent/host.py +++ b/apps/scheduler/mcp_agent/host.py @@ -62,7 +62,6 @@ class MCPHost(MCPBase): function=function, conversation=[ {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": prompt}, {"role": "user", "content": llm_query}, ], prompt=prompt, diff --git a/apps/scheduler/mcp_agent/plan.py b/apps/scheduler/mcp_agent/plan.py index 9df24d284..6e37acac0 100644 --- a/apps/scheduler/mcp_agent/plan.py +++ b/apps/scheduler/mcp_agent/plan.py @@ -51,7 +51,6 @@ class MCPPlanner(MCPBase): function=GET_FLOW_NAME_FUNCTION[self._language], conversation=[ {"role": "system", "content": "You are a helpful assistant."}, - {"role": "user", "content": prompt}, ], prompt=prompt, ) diff --git a/data/prompts/system/mcp/create_plan.en.md b/data/prompts/system/mcp/create_plan.en.md new file mode 100644 index 000000000..b3f97e24c --- /dev/null +++ b/data/prompts/system/mcp/create_plan.en.md @@ -0,0 +1,42 @@ +## Task +Analyze the user's goal and generate an execution plan to accomplish the goal step by step. + +## Plan Requirements +1. **One Tool Per Step**: Each step uses only one tool +2. **Clear Logic**: Steps have explicit dependencies, no redundancy +3. **Complete Coverage**: Don't miss any part of the user's goal +4. **Step Limit**: Maximum {{ max_num }} steps, each under 150 words +5. **Must End**: Final step must use the `Final` tool + +## Plan Structure +Each plan contains three elements: +- **content**: Step description, can reference previous results with `Result[i]` +- **tool**: Tool ID (selected from tool list) +- **instruction**: Specific instruction for the tool + +## Tool List +{% for tool in tools %} +- **{{ tool.toolName }}**: {{tool.toolName}}; {{ tool.description }} +{% endfor %} +- **Final**: End step, marks plan execution complete + +## Example +Suppose the user's goal is: Run alpine:latest container in background, mount /root to /data, execute top command + +First, analyze this goal: +- This requires Docker support, so the first step should select an MCP Server with Docker capability +- Next, need to generate a Docker command that meets the requirements, including container image, directory mount, background execution, and command execution +- Then execute the generated command +- Finally, mark the task as complete + +Based on this analysis, the following plan can be generated: +- Step 1: Select MCP Server with Docker support, using mcp_selector tool, instruction is "Need MCP Server supporting Docker container operation" +- Step 2: Generate Docker command based on Result[0], using command_generator tool, instruction is "Generate command: run alpine:latest in background, mount /root to /data, execute top" +- Step 3: Execute Result[1] command on Result[0], using command_executor tool, instruction is "Execute Docker command" +- Step 4: Container running, output Result[2], using Final tool, instruction is empty + +## User Goal +{{goal}} + +## Please Generate Plan +First analyze the goal and clarify your thinking, then generate a structured execution plan. diff --git a/data/prompts/system/mcp/create_plan.zh.md b/data/prompts/system/mcp/create_plan.zh.md new file mode 100644 index 000000000..95c662e47 --- /dev/null +++ b/data/prompts/system/mcp/create_plan.zh.md @@ -0,0 +1,103 @@ +# 计划生成任务 + +## 角色 + +你是一个专业的任务规划助手,能够分析用户目标并生成结构化的执行计划。 + +## 计划要求 + +1. **每步一工具**:每个步骤仅使用一个工具 +2. **逻辑清晰**:步骤间有明确依赖关系,无冗余 +3. **目标覆盖**:不遗漏用户目标的任何内容 +4. **步骤上限**:不超过 {{ max_num }} 条,每条不超过150字 +5. **必须结束**:最后一步使用 `Final` 工具 + +## 工具 + +你可以调用以下工具来完成计划生成任务。 + +{% raw %}{% if use_xml_format %}{% endraw %} +调用工具时,采用XML风格标签进行格式化。格式规范如下: + +```xml + + + 第一步的步骤描述 + 第一步所需的工具ID + 第一步给工具的具体指令 + + + 第二步的步骤描述 + 第二步所需的工具ID + 第二步给工具的具体指令 + + +``` + +{% raw %}{% endif %}{% endraw %} + +### create_mcp_plan + +描述:生成结构化的MCP计划以实现用户目标 + +参数: + +- plans: 计划步骤列表,每个步骤包含: + - content: 步骤描述,可用 `Result[i]` 引用前序结果 + - tool: 工具ID(从工具列表中选择) + - instruction: 针对工具的具体指令 + +可用工具列表: + +{% for tool in tools %} +- **{{ tool.toolName }}**: {{ tool.description }} +{% endfor %} +- **Final**: 结束步骤,标志计划执行完成 + +用法示例: + +- 用户目标:在后台运行 alpine:latest 容器,挂载 /root 到 /data,执行 top 命令 +- 计划应为: + 1. 选择支持 Docker 的 MCP Server,使用 mcp_selector 工具,指令是"需要支持 Docker 容器运行的 MCP Server" + 2. 基于 Result[0] 生成 Docker 命令,使用 command_generator 工具,指令是"生成命令:后台运行 alpine:latest,挂载 /root 至 /data,执行 top" + 3. 在 Result[0] 上执行 Result[1] 的命令,使用 command_executor 工具,指令是"执行 Docker 命令" + 4. 容器已运行,输出 Result[2],使用 Final 工具,指令为空 + +{% raw %}{% if use_xml_format %}{% endraw %} + +```xml + + + 选择支持 Docker 的 MCP Server + mcp_selector + 需要支持 Docker 容器运行的 MCP Server + + + 基于 Result[0] 生成 Docker 命令 + command_generator + 生成命令:后台运行 alpine:latest,挂载 /root 至 /data,执行 top + + + 在 Result[0] 上执行 Result[1] 的命令 + command_executor + 执行 Docker 命令 + + + 容器已运行,输出 Result[2] + Final + + + +``` + +{% raw %}{% endif %}{% endraw %} + +--- + +## 用户目标 + +{{goal}} + +--- + +现在开始响应用户指令,调用 `create_mcp_plan` 工具完成计划生成。 diff --git a/data/prompts/system/mcp/evaluate_plan.en.md b/data/prompts/system/mcp/evaluate_plan.en.md new file mode 100644 index 000000000..1bdcf02bc --- /dev/null +++ b/data/prompts/system/mcp/evaluate_plan.en.md @@ -0,0 +1,40 @@ +You are a plan evaluator. +Based on the given plan and the actual execution of the current plan, analyze whether the current plan is reasonable and complete, and generate an improved plan. + +# A good plan should: +1. Be able to successfully achieve the user's goal. +2. Each step in the plan must use only one tool. +3. The steps in the plan must have clear and logical steps, without redundant or unnecessary steps. +4. The last step in the plan must be a Final tool to ensure the completion of the plan execution. + +# Your previous plan was: +{{ plan }} + +# The execution status of this plan is: +The execution status of the plan will be placed in the XML tags. + + + {{ memory }} + + +# Notes when conducting the evaluation: +- Please think step by step, analyze the user's goal, and guide your subsequent generation. The thinking process should be placed in the XML tags. +- The evaluation results are divided into two parts: + - Conclusion of the plan evaluation + - Improved plan +- Please output the evaluation results in the following JSON format: + +```json +{ + "evaluation": "Evaluation results", + "plans": [ + { + "content": "Improved plan content", + "tool": "Tool ID", + "instruction": "Tool instructions" + } + ] +} +``` + +# Start evaluating the plan now: diff --git a/data/prompts/system/mcp/evaluate_plan.zh.md b/data/prompts/system/mcp/evaluate_plan.zh.md new file mode 100644 index 000000000..4be1ca262 --- /dev/null +++ b/data/prompts/system/mcp/evaluate_plan.zh.md @@ -0,0 +1,40 @@ +你是一个计划评估器。 +请根据给定的计划,和当前计划执行的实际情况,分析当前计划是否合理和完整,并生成改进后的计划。 + +# 一个好的计划应该: +1. 能够成功完成用户的目标 +2. 计划中的每一个步骤必须且只能使用一个工具。 +3. 计划中的步骤必须具有清晰和逻辑的步骤,没有冗余或不必要的步骤。 +4. 计划中的最后一步必须是Final工具,以确保计划执行结束。 + +# 你此前的计划是: +{{ plan }} + +# 这个计划的执行情况是: +计划的执行情况将放置在 XML标签中。 + + + {{ memory }} + + +# 进行评估时的注意事项: +- 请一步一步思考,解析用户的目标,并指导你接下来的生成。思考过程应放置在 XML标签中。 +- 评估结果分为两个部分: + - 计划评估的结论 + - 改进后的计划 +- 请按照以下JSON格式输出评估结果: + +```json +{ + "evaluation": "评估结果", + "plans": [ + { + "content": "改进后的计划内容", + "tool": "工具ID", + "instruction": "工具指令" + } + ] +} +``` + +# 现在开始评估计划: diff --git a/data/prompts/system/mcp/gen_step.en.md b/data/prompts/system/mcp/gen_step.en.md index 3e3df5c2c..a511d8327 100644 --- a/data/prompts/system/mcp/gen_step.en.md +++ b/data/prompts/system/mcp/gen_step.en.md @@ -15,23 +15,16 @@ Analyze the conversation history and user goal, then call the `create_next_step` 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 +## Functions -{% 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. +You can call the following functions 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 +Function Name Step Description ``` @@ -44,13 +37,16 @@ Description: Create the next execution step Parameters: -- tool_name: Tool name, must be selected from the available tools list above +- tool_name: External tool name, must be selected from the following list + {% for tool in tools %} + - `{{tool.toolName}}`: {{tool.description}} + {% endfor %} - 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 +- **Fixed function name**: Must use `create_next_step`, do not use external tool names as function names +- **tool_name value**: Must be one of the tool names from the external tools list - **description value**: Describe the specific operations of this step - **When task completes**: If the user goal is achieved, set `tool_name` parameter to `Final` diff --git a/data/prompts/system/mcp/gen_step.zh.md b/data/prompts/system/mcp/gen_step.zh.md index 91e149f59..9848dddd0 100644 --- a/data/prompts/system/mcp/gen_step.zh.md +++ b/data/prompts/system/mcp/gen_step.zh.md @@ -15,23 +15,16 @@ 3. **清晰性**:步骤描述简洁明确,说明具体操作内容 4. **完整性**:确保每个步骤独立完整,可直接执行 -## 可用工具列表 +## 函数 -{% for tool in tools %} -- **工具名**: `{{tool.toolName}}` - **功能描述**: {{tool.description}} -{% endfor %} - -## 工具 - -你可以调用以下工具来完成步骤规划任务。 +你可以调用以下函数来完成步骤规划任务。 {% raw %}{% if use_xml_format %}{% endraw %} 调用工具时,采用XML风格标签进行格式化。格式规范如下: ```xml -工具名称 +函数名称 步骤描述 ``` @@ -44,13 +37,16 @@ 参数: -- tool_name: 工具名称,必须从上述可用工具列表中选择 +- tool_name: 外置工具名称,必须从以下列表中选择 + {% for tool in tools %} + - `{{tool.toolName}}`: {{tool.description}} + {% endfor %} - description: 步骤描述,清晰说明本步骤要做什么 调用规范: -- **函数名固定**: 必须调用 `create_next_step`,不要使用工具名作为函数名 -- **tool_name的值**: 必须是上述可用工具列表中的某个工具名称 +- **函数名固定**: 必须使用 `create_next_step`,不要使用外置工具名作为函数名 +- **tool_name的值**: 必须是外置工具列表中的某个工具名称 - **description的值**: 描述本步骤的具体操作内容 - **任务完成时**: 如果用户目标已经完成,将 `tool_name` 参数设为 `Final` diff --git a/data/prompts/system/mcp/mcp_select.en.md b/data/prompts/system/mcp/mcp_select.en.md index acb018b40..751e61794 100644 --- a/data/prompts/system/mcp/mcp_select.en.md +++ b/data/prompts/system/mcp/mcp_select.en.md @@ -1,13 +1,14 @@ -## Task Description +# MCP Server Selection Task -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. +## Role + +You are a professional MCP (Model Context Protocol) selector, capable of accurately selecting the most appropriate MCP server based on reasoning results. ## Reasoning Result Below is the reasoning result that needs to be analyzed: -``` +```text {{ reasoning_result }} ``` @@ -21,12 +22,50 @@ List of available MCP server IDs: ## 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 +1. **Capability Matching**: Align the capability requirements described in the reasoning with 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 +4. **Accuracy**: Ensure the selected server ID exists in the available list + +## Tools + +You can invoke the following tools to complete the MCP server selection task. + +{% raw %}{% if use_xml_format %}{% endraw %} +When invoking tools, use XML-style tags for formatting. The format specification is as follows: + +```xml + +Server ID + +``` + +{% raw %}{% endif %}{% endraw %} + +### select_mcp + +Description: Select the most appropriate MCP server + +Parameters: + +- mcp_id: MCP server ID + +Usage Example: + +- Reasoning result: Requires file system operation capabilities +- Available servers: ["filesystem", "database", "web_search"] +- Should select: filesystem + +{% raw %}{% if use_xml_format %}{% endraw %} + +```xml + +filesystem + +``` + +{% raw %}{% endif %}{% endraw %} -## Output Format +--- -Please use the `select_mcp` tool to make your selection by providing the chosen MCP server ID. +Now begin responding to user instructions, invoke the `select_mcp` tool to complete MCP server selection: diff --git a/data/prompts/system/mcp/mcp_select.zh.md b/data/prompts/system/mcp/mcp_select.zh.md index cd5bee14e..d8fbc483b 100644 --- a/data/prompts/system/mcp/mcp_select.zh.md +++ b/data/prompts/system/mcp/mcp_select.zh.md @@ -1,13 +1,14 @@ -## 任务描述 +# MCP 服务器选择任务 -你是一个专业的 MCP (Model Context Protocol) 选择器。 -你的任务是分析推理结果并选择最合适的 MCP 服务器 ID。 +## 角色 + +你是一个专业的 MCP (Model Context Protocol) 选择器,能够根据推理结果准确选择最合适的 MCP 服务器。 ## 推理结果 以下是需要分析的推理结果: -``` +```text {{ reasoning_result }} ``` @@ -21,12 +22,50 @@ ## 选择要求 -请仔细分析推理结果,选择最符合需求的 MCP 服务器。重点关注: +1. **能力匹配**:推理中描述的能力需求与 MCP 服务器功能的对应关系 +2. **场景适配**:MCP 服务器是否适合当前应用场景 +3. **最优选择**:从可用列表中选择最合适的服务器 ID +4. **准确性**:确保选择的服务器 ID 在可用列表中 + +## 工具 + +你可以调用以下工具来完成 MCP 服务器选择任务。 + +{% raw %}{% if use_xml_format %}{% endraw %} +调用工具时,采用XML风格标签进行格式化。格式规范如下: + +```xml + +服务器ID + +``` + +{% raw %}{% endif %}{% endraw %} + +### select_mcp + +描述:选择最合适的 MCP 服务器 + +参数: + +- mcp_id: MCP 服务器 ID + +用法示例: + +- 推理结果:需要文件系统操作能力 +- 可用服务器:["filesystem", "database", "web_search"] +- 应选择:filesystem + +{% raw %}{% if use_xml_format %}{% endraw %} + +```xml + +filesystem + +``` -1. **能力匹配**:推理中描述的能力需求与 MCP 服务器功能的对应关系 -2. **场景适配**:MCP 服务器是否适合当前应用场景 -3. **最优选择**:从可用列表中选择最合适的服务器 ID +{% raw %}{% endif %}{% endraw %} -## 输出格式 +--- -请使用 `select_mcp` 工具进行选择,提供选中的 MCP 服务器 ID。 +现在开始响应用户指令,调用 `select_mcp` 工具完成 MCP 服务器选择: -- Gitee