Skip to main content
最终版标准轨道
字段
SEP1303
标题输入验证错误作为工具执行错误
状态最终版
类型标准轨道
创建日期2025-08-05
作者@fredericbarthelet
赞助人
PR#1303

摘要

本 SEP 提议将工具输入验证错误视为工具执行错误,而不是协议错误。这一变更将使语言模型能够在其上下文窗口中接收验证错误反馈,允许它们自我纠正并成功完成任务而无需人工干预,显著提高任务完成率。

动机

语言模型可以从工具输入验证错误消息中学习,并相应地重试带有修正参数的 tools/call,但前提是它们在其上下文窗口中接收到错误反馈。协议错误由 MCP 客户端在应用层捕获。只有工具执行错误才会作为 JSON-RPC 响应转发回模型。根据当前规范,模型无法看到这些错误消息,因此无法自我纠正,导致重复失败和糟糕的用户体验。

问题陈述

考虑一个使用以下 zod 验证架构验证出发日期的航班预订工具:
departureDate: z.string()
  .regex(/^\d{2}\/\d{2}\/\d{4}$/, "date must be in dd/mm/yyyy format")
  .superRefine((dateStr, ctx) => {
    const date = parseDateFr(dateStr);
    if (date.getTime() < Date.now()) {
      ctx.addIssue({
        code: z.ZodIssueCode.custom,
        message:
          "Dates must be in the future. Current date is " +
          formatDateFr(new Date()),
      });
    }
    return true;
  })
  .describe("Departure date in dd/mm/yyyy format");
工具预期的输入 JSON 架构只能描述正则语句。实际的日期在过去的时间编程检查无法在此处表示为 JSON 架构。 即使模型提供了语法正确且通过 JSON 架构验证的日期,也无法保证它在未来。当验证错误被引发并作为协议错误返回时:
  1. 模型没有收到解释日期为何被拒绝的错误消息
  2. 模型多次重复同样的错误(例如,当用户只指定日和月或相对日期时,Cursor 通常一致地发送 2024 年的日期,并重复相同的 tools/call 请求 3 次,而没有获得任何关于工具调用为何失败的信息)
  3. 尽管模型在获得适当反馈的情况下能够自我纠正,但任务仍然失败
  4. 用户感到沮丧并且必须手动干预

本提案的好处

  1. 更高的任务完成率:模型无需人工干预即可自我纠正验证错误
  2. 更好的用户体验:减少失败并加快任务完成
  3. 利用模型能力:现代大语言模型擅长理解和响应错误消息
  4. 减少 API 调用:随着模型在第一个错误上自我纠正,重试尝试减少

规范

当前行为

工具错误规范 目前提供了模糊的指导:
  • “无效参数”应被视为协议错误
  • “无效输入数据”应被视为工具执行错误
这种模糊性导致不一致的实现,其中有价值的错误反馈丢失。

提议的变更

通过以下变更澄清规范:
  1. 协议错误 中移除“无效参数”类别。
  2. 工具执行错误 应用于所有工具参数验证失败(将 无效参数无效输入数据 合并到新的 输入验证错误 类别下)

规范文本变更

更新错误处理部分以包括:
## 错误处理

工具使用两种错误报告机制:

1. **协议错误**:用于以下问题的标准 JSON-RPC 错误:

   - 未知工具
   - 服务器错误

2. **工具执行错误**:在工具结果中报告,带有 `isError: true`:
   - API 失败
   - 输入验证错误
   - 业务逻辑错误

实现

之前(协议错误)

// 模型提交过去的日期
request: {
  ...
  method: "tools/call",
  params: {
    name: "book_flight",
    arguments: {
      departureDate: "12/12/2024"  // 过去的日期
    }
  }
}

// 服务器返回协议错误
response: {
  ...
  error: {
    code: -32602,
    message: "Invalid params"
  }
}

// 模型盲目地用另一个过去的日期重试
// 此循环重复直到失败

之后(工具执行错误)

// 模型提交过去的日期
request: {
  ...
  method: "tools/call",
  params: {
    name: "book_flight",
    arguments: {
      departureDate: "12/12/2024"  // 过去的日期
    }
  }
}

// 服务器返回工具执行错误(对模型可见)
response: {
  ...
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Dates must be in the future. Current date is 08/08/2025"
      }
    ],
    "isError": true
  }
}

// 模型理解错误并自我纠正
request: {
  method: "tools/call",
  params: {
    name: "book_flight",
    arguments: {
      departureDate: "12/12/2025"  // 未来的日期
    }
  }
}

向后兼容性

此变更是向后兼容的,因为它:
  • 不改变协议结构
  • 仅澄清现有的模糊行为
  • 维持所有现有的错误类型和格式
  • 在不破坏现有实现的情况下改进行为
实施澄清行为的服务器将提供更好的模型自我恢复,同时继续与所有现有客户端一起工作。

参考资料