Skip to content

采样

让您的服务器从 LLM 请求完成

采样是一项强大的 MCP 功能,它允许服务器通过客户端请求 LLM 完成,从而在维护安全性和隐私性的同时实现复杂的代理行为。

image-20250306214605601

一、采样的工作原理

采样流程遵循以下步骤:

  1. 服务器向客户端发送 sampling/createMessage 请求
  2. 客户端查看请求,并可以对其进行修改
  3. 客户端调用 LLM 生成消息(sample,一次生成尝试)
  4. 客户端审核 LLM 生成的消息内容
  5. 客户端将最终结果返回给服务器

这种人机交互流程确保上层能够对 LLM 所接收的输入和最终输出保持完全控制。

特别注释

sampling是比较坑爹的命名啊,《模型上下文协议中文网》需要做特别附注。

概念

正常的人机交互流程,是LLM先推理决策,再通过客户端向MCP服务端发出请求。但是特殊的情况下,被访问的MCP服务端,在执行任务的过程中,反过来有需要LLM先帮助解决问题,最后才能交答案。

工作原理

简言之,它是一种“反向请求”机制,其中服务器通过向客户端发送请求,并让客户端从 LLM 中采样内容。

场景举例
  1. 服务器向客户端发送请求:比如,服务器可能请求客户端直接利用其他MCP服务,或让客户端调用 LLM 执行某种任务(例如,生成 Git 提交信息、删除某个文件)。
  2. 客户端审查并修改请求:客户端接收到请求后,查看并可以根据需要修改请求内容。
  3. 客户端从 LLM 进行采样:客户端将修改后的内容输入 LLM,得到一个响应。
  4. 客户端审查结果:客户端再次检查 LLM 返回的结果,并决定是否合适。
  5. 客户端将最终结果返回服务器:如果客户端对 LLM 的生成内容满意,最终结果将被发送回服务器。
设计原理

注意,我重点标注了修改。

sampling是一个核心交互流程的过程概念,定义的是一个标准的三角(MCP客户端MCP服务端LLM)交互步骤流程。但为什么要采用这么一个复杂流程?

  • 人机回圈设计:这种设计确保客户端和 LLM 之间的交互是透明且可控的,代表用户的Agent产品(MCP客户端),始终掌握对话的控制权。

  • 提高控制度与准确度:通过这种方式,客户端可以避免自动生成的内容偏离预期,并且在用户需求不清晰的情况下,可以向 LLM 请求逐步精细的修正输出。

别的不说,如果不需要用户确认即删除本地文件,甚至无知情权反显,则无安全性可言。所以,本质上,这是安全可控消息生成与审订流程概念。精简命名成采样确实是有误导性的。特此长文注释。

二、消息格式

采样请求使用标准化的消息格式:

typescript
{
  messages: [
    {
      role: "user" | "assistant",  
      // 消息的角色,"user" 表示用户输入,"assistant" 表示模型或 AI 回复。
      content: {
        type: "text" | "image",  // 消息内容的类型
        text?: string,  // 仅在type为 "text" 时有效。
        data?: string,  // 图片的 base64 编码数据,仅在type为 "image" 时有效。
        mimeType?: string  // 图片的 MIME 类型(例如 "image/png" 或 "image/jpeg"),用于描述资源格式。
      }
    }
  ],

  modelPreferences?: {
    // 模型偏好设置,给模型调用方的建议配置(非强制)。
    hints?: [ 
      {
        name?: string  // 推荐的模型名称或模型家族名称(例如 "gpt-4", "claude" 等)
      }
    ],
    costPriority?: number,  // 控制成本优先级,取值 0 到 1,数值越高越倾向于选择低成本模型。
    speedPriority?: number,  // 控制速度优先级,取值 0 到 1,数值越高越倾向于低延迟快速响应的模型。
    intelligencePriority?: number  // 控制智能优先级,取值 0 到 1,数值越高越倾向于选择能力更强的模型。
  },

  systemPrompt?: string,  
  // 给模型的系统级提示词,通常用于设定对话背景或指导模型行为。

  includeContext?: "none" | "thisServer" | "allServers",  
  // 上下文包含范围设置:
  // - "none": 不包含上下文;
  // - "thisServer": 仅包含当前服务的上下文;
  // - "allServers": 包含所有关联服务的上下文。

  temperature?: number,  
  // 控制生成文本的随机性,通常取值范围 0-2。
  // 数值越高越随机,越低越确定性强。

  maxTokens: number,  
  // 生成回复的最大 token 数量上限,用于控制输出长度。

  stopSequences?: string[],  
  // 停止序列,指定一个或多个字符串,如果模型生成的内容出现这些序列,则停止输出。

  metadata?: Record<string, unknown>  
  // 附加元数据,可以包含任何结构的额外信息,便于日志、追踪或业务扩展。
}

三、请求参数

《模型上下文协议中文网》附注:标准的请求参数我已经在消息格式中做了直观的翻译。

下面的细节,你可以快速略过,主要掌握一级结构所代表的基础要素,都是围绕上下文和人机回圈设计这个核心。

1、Messages

该数组包含要发送到 LLM 的会话历史记录。每条消息都有:messages

  • role: “user” 或 “assistant”

  • content:消息内容,可以是:

    • 带有字段的文本内容text
    • 具有 (base64) 和字段的图像内容data``mimeType

2、模型偏好设置

该对象允许服务器指定其模型选择首选项:modelPreferences

  • hints:客户端可用于选择适当模型的模型名称建议数组:
    • name:可以匹配完整或部分模型名称的字符串(例如“claude-3”、“sonnet”)
    • 客户端可以将 hint 映射到来自不同提供商的等效模型
    • 按首选项顺序评估多个提示
  • 优先级值(0-1 标准化):
    • costPriority: 降低成本的重要性
    • speedPriority: 低延迟响应的重要性
    • intelligencePriority:高级模型功能的重要性

客户根据这些首选项及其可用模型进行最终模型选择。

3、系统提示符

可选字段允许服务器请求特定的系统提示符。客户端可以修改或忽略这一点。systemPrompt

4、上下文包含

该参数指定要包含的 MCP 上下文:includeContext

  • "none":无其他上下文
  • "thisServer":包括来自请求服务器的上下文
  • "allServers":包括来自所有连接的 MCP 服务器的上下文

客户端控制实际包含的上下文。

5、采样参数

使用以下方法微调 LLM 采样:

  • temperature:控制随机性(0.0 到 1.0)
  • maxTokens:要生成的最大令牌数
  • stopSequences:停止生成的序列数组
  • metadata:其他特定于提供程序的参数

四、响应格式

客户端返回一个完成结果:

typescript
{
  model: string,  // 所使用的大语言模型(LLM)名称,例如 "gpt-4"、"llama-2" 等,方便标识消息由哪个模型生成
  stopReason?: "endTurn" | "stopSequence" | "maxTokens" | string,   
  // (可选)消息生成停止的原因:
  // - "endTurn": 表示对话轮次正常结束
  // - "stopSequence": 碰到指定的停止符序列而终止
  // - "maxTokens": 达到最大 token 限制
  // - string: 其他自定义停止原因

  role: "user" | "assistant",    
  // 消息的角色身份:
  // - "user": 表示由用户发出的消息
  // - "assistant": 表示由 LLM(助手)生成的消息

  content: {
    type: "text" | "image",   
    // 消息内容的类型:
    // - "text": 文本消息
    // - "image": 图片消息(例如 Base64 编码图片或 URL)

    text?: string,  
    // (可选)文本消息内容,当 type 为 "text" 时有效

    data?: string,  
    // (可选)二进制数据的字符串表示形式(如 Base64 编码),
    // 一般用于存储图片等非文本内容,当 type 为 "image" 时使用

    mimeType?: string  
    // (可选)数据的 MIME 类型,标识 data 字段的格式
    // 例如:
    // - "image/png": 表示 PNG 格式的图片
    // - "image/jpeg": 表示 JPEG 格式的图片
    // - "text/plain": 纯文本(一般用于 text 字段,不常用于 data)
  }
}

五、示例请求

以下是向客户端请求采样的示例:

json
{
  "method": "sampling/createMessage",  
  // 请求方法名称,表示调用 "sampling/createMessage",用于让客户端基于上下文与 LLM 进行采样生成回复。
  "params": {
    // 请求参数部分
    "messages": [
      {
        "role": "user",  
        // 消息角色,"user" 表示用户发起的消息。
        "content": {
          "type": "text",  
          // 消息内容的类型,这里是纯文本。
          "text": "当前目录中有哪些文件?"  
          // 用户实际输入的文本内容,询问目录下的文件列表。
        }
      }
    ],

    "systemPrompt": "您是文件系统的得力助手.",  
    // 系统提示词,用于为 LLM 设定角色或行为约束,在本次对话中扮演文件系统助手的角色。
    "includeContext": "当前服务",  
    // 上下文包含范围,指明是否包含当前服务的相关上下文信息,以便于生成更相关的回复。
    // 示例值:"当前服务",表示只包含当前服务内的上下文。
    "maxTokens": 100  
    // LLM 回复生成的最大 token 数量上限,用于限制输出长度,防止回复过长或超出资源限制。
  }
}

其他

《模型上下文协议中文网》附注:下面部分新手可先不关注

1、最佳实践

实施采样时:

  1. 始终提供清晰、结构良好的提示
  2. 适当地处理文本和图像内容
  3. 设置合理的令牌限制
  4. 通过以下方式包含相关上下文includeContext
  5. 在使用响应之前验证响应
  6. 优雅地处理错误
  7. 考虑对采样请求进行速率限制
  8. 记录预期的采样行为
  9. 使用各种模型参数进行测试
  10. 监控采样成本

2、人机交互控制

采样在设计时考虑了人工监督:

对于提示

  • 客户端应向用户显示建议的提示
  • 用户应该能够修改或拒绝提示
  • 可以过滤或修改系统提示
  • 上下文包含由客户端控制

对于完成

  • 客户端应向用户显示完成情况
  • 用户应该能够修改或拒绝完成
  • 客户可以筛选或修改完成
  • 用户控制使用哪个模型

3、安全注意事项

实施采样时:

  • 验证所有消息内容
  • 清理敏感信息
  • 实施适当的速率限制
  • 监控采样使用情况
  • 加密传输中的数据
  • 处理用户数据隐私
  • 审计采样请求
  • 控制成本风险
  • 实施超时
  • 优雅地处理模型错误

4、常见模式

代理工作流

采样支持代理模式,例如:

  • 读取和分析资源
  • 根据上下文做出决策
  • 生成结构化数据
  • 处理多步骤任务
  • 提供交互式帮助

上下文管理

上下文的最佳实践:

  • 请求最少的必要上下文
  • 清晰地构建上下文
  • 处理上下文大小限制
  • 根据需要更新上下文
  • 清理过时的上下文

错误处理

健壮的错误处理应该:

  • 捕获采样失败
  • 处理超时错误
  • 管理速率限制
  • 验证响应
  • 提供回退行为
  • 适当地记录错误

5、局限性

请注意以下限制:

  • 采样取决于客户端功能
  • 用户控制采样行为
  • 上下文大小有限制
  • 速率限制可能适用
  • 应考虑成本
  • 型号可用性不尽相同
  • 响应时间各不相同
  • 并非所有内容类型都受支持