什么是MCP采样
采样是MCP的一个强大功能,它允许MCP服务器通过客户端向大语言模型请求文本补全。这种设计模式支持复杂的智能体工作流,同时保持人工监督和控制。
核心设计理念
采样功能采用"人工参与循环"(Human-in-the-loop)设计,确保用户始终保持对LLM交互的控制权:
- 用户可控性:用户可以审查、修改或拒绝提示和完成内容
- 安全性:所有采样请求都经过客户端验证和过滤
- 隐私性:敏感信息可以在客户端被过滤或修改
- 透明性:用户可以看到服务器请求的具体内容
技术架构与工作流程
采样工作流程
服务器 → 客户端 → LLM → 客户端 → 服务器
↓ ↓ ↓ ↓ ↓
发送请求 审查请求 生成 审查结果 接收结果
可修改 内容 可修改
具体步骤:
- 服务器发送请求:服务器发送
sampling/createMessage
请求到客户端 - 客户端审查:客户端审查请求,可以修改提示、系统指令或上下文
- LLM采样:客户端向LLM发送经过审查的请求
- 结果审查:客户端审查LLM的响应,可以进行过滤或修改
- 返回结果:客户端将最终结果返回给服务器
消息格式详解
请求参数结构
采样请求使用标准化的消息格式,主要包含以下几个核心组件:
1. 消息数组(Messages)
interface Message {
role: "user" | "assistant";
content: TextContent | ImageContent;
}
interface TextContent {
type: "text";
text: string;
}
interface ImageContent {
type: "image";
data: string; // base64编码
mimeType: string; // 如 "image/png"
}
2. 模型偏好设置(Model Preferences)
interface ModelPreferences {
hints?: string[]; // 模型名称提示
costPriority?: number; // 成本优先级 (0-1)
speedPriority?: number; // 速度优先级 (0-1)
intelligencePriority?: number; // 智能程度优先级 (0-1)
}
3. 上下文包含设置(Context Inclusion)
type IncludeContext = "none" | "thisServer" | "allServers";
4. 采样参数(Sampling Parameters)
interface SamplingParams {
temperature?: number; // 随机性控制 (0.0-1.0)
maxTokens?: number; // 最大token数
stopSequences?: string[]; // 停止序列
metadata?: Record<string, any>; // 特定于提供商的参数
}
响应格式
interface SamplingResponse {
model: string;
stopReason?: "endTurn" | "stopSequence" | "maxTokens" | string;
role: "user" | "assistant";
content: {
type: "text" | "image";
text?: string;
data?: string;
mimeType?: string;
};
}
TypeScript SDK 实战演示
下面我们通过完整的TypeScript代码示例来演示如何实现MCP采样功能。
1. 基础类型定义
// types.ts
export interface MCPSamplingRequest {
method: "sampling/createMessage";
params: SamplingRequestParams;
}
export interface SamplingRequestParams {
messages: Message[];
systemPrompt?: string;
includeContext?: IncludeContext;
modelPreferences?: ModelPreferences;
temperature?: number;
maxTokens?: number;
stopSequences?: string[];
metadata?: Record<string, any>;
}
export interface Message {
role: "user" | "assistant";
content: MessageContent;
}
export interface MessageContent {
type: "text" | "image";
text?: string;
data?: string;
mimeType?: string;
}
export interface ModelPreferences {
hints?: string[];
costPriority?: number;
speedPriority?: number;
intelligencePriority?: number;
}
export type IncludeContext = "none" | "thisServer" | "allServers";
export interface SamplingResponse {
model: string;
stopReason?: "endTurn" | "stopSequence" | "maxTokens" | string;
role: "user" | "assistant";
content: MessageContent;
}
2. MCP采样客户端实现
// mcp-sampling-client.ts
import {
MCPSamplingRequest,
SamplingRequestParams,
SamplingResponse,
Message,
ModelPreferences
} from './types';
export class MCPSamplingClient {
private wsConnection: WebSocket | null = null;
private pendingRequests = new Map<string, (response: any) => void>();
constructor(private serverUrl: string) {}
async connect(): Promise<void> {
return new Promise((resolve, reject) => {
this.wsConnection = new WebSocket(this.serverUrl);
this.wsConnection.onopen = () => {
console.log('MCP连接已建立');
resolve();
};
this.wsConnection.onerror = (error) => {
console.error('MCP连接错误:', error);
reject(error);
};
this.wsConnection.onmessage = (event) => {
this.handleMessage(JSON.parse(event.data));
};
});
}
private handleMessage(message: any): void {
const { id, result, error } = message;
const resolver = this.pendingRequests.get(id);
if (resolver) {
this.pendingRequests.delete(id);
if (error) {
console.error('采样请求错误:', error);
} else {
resolver(result);
}
}
}
async requestSampling(params: SamplingRequestParams): Promise<SamplingResponse> {
if (!this.wsConnection) {
throw new Error('MCP连接未建立');
}
const requestId = this.generateRequestId();
const request: MCPSamplingRequest & { id: string } = {
id: requestId,
method: "sampling/createMessage",
params
};
return new Promise((resolve, reject) => {
this.pendingRequests.set(requestId, resolve);
// 设置超时
setTimeout(() => {
if (this.pendingRequests.has(requestId)) {
this.pendingRequests.delete(requestId);
reject(new Error('采样请求超时'));
}
}, 30000);
this.wsConnection!.send(JSON.stringify(request));
});
}
private generateRequestId(): string {
return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}
disconnect(): void {
if (this.wsConnection) {
this.wsConnection.close();
this.wsConnection = null;
}
}
}
3. 采样请求构建器
// sampling-request-builder.ts
import { SamplingRequestParams, Message, ModelPreferences } from './types';
export class SamplingRequestBuilder {
private params: Partial<SamplingRequestParams> = {};
addMessage(role: "user" | "assistant", text: string): this {
if (!this.params.messages) {
this.params.messages = [];
}
this.params.messages.push({
role,
content: { type: "text", text }
});
return this;
}
addImageMessage(role: "user" | "assistant", imageData: string, mimeType: string): this {
if (!this.params.messages) {
this.params.messages = [];
}
this.params.messages.push({
role,
content: { type: "image", data: imageData, mimeType }
});
return this;
}
setSystemPrompt(prompt: string): this {
this.params.systemPrompt = prompt;
return this;
}
setContext(context: "none" | "thisServer" | "allServers"): this {
this.params.includeContext = context;
return this;
}
setModelPreferences(preferences: ModelPreferences): this {
this.params.modelPreferences = preferences;
return this;
}
setSamplingParams(
temperature?: number,
maxTokens?: number,
stopSequences?: string[]
): this {
if (temperature !== undefined) this.params.temperature = temperature;
if (maxTokens !== undefined) this.params.maxTokens = maxTokens;
if (stopSequences !== undefined) this.params.stopSequences = stopSequences;
return this;
}
build(): SamplingRequestParams {
if (!this.params.messages || this.params.messages.length === 0) {
throw new Error('至少需要一条消息');
}
return this.params as SamplingRequestParams;
}
}
4. 高级采样管理器
// advanced-sampling-manager.ts
import { MCPSamplingClient } from './mcp-sampling-client';
import { SamplingRequestBuilder } from './sampling-request-builder';
import { SamplingResponse } from './types';
export class AdvancedSamplingManager {
private client: MCPSamplingClient;
private requestHistory: Array<{ request: any; response: SamplingResponse; timestamp: number }> = [];
constructor(serverUrl: string) {
this.client = new MCPSamplingClient(serverUrl);
}
async initialize(): Promise<void> {
await this.client.connect();
}
// 智能体对话功能
async agentConversation(
userInput: string,
systemContext: string = "你是一个有帮助的AI助手",
options: {
temperature?: number;
maxTokens?: number;
includeHistory?: boolean;
modelHints?: string[];
} = {}
): Promise<string> {
const builder = new SamplingRequestBuilder()
.setSystemPrompt(systemContext)
.setContext("thisServer")
.setSamplingParams(
options.temperature ?? 0.7,
options.maxTokens ?? 1000
);
// 包含历史对话
if (options.includeHistory && this.requestHistory.length > 0) {
this.requestHistory.slice(-5).forEach(({ request, response }) => {
if (request.params.messages) {
request.params.messages.forEach((msg: any) => {
builder.addMessage(msg.role, msg.content.text || '');
});
}
if (response.content.text) {
builder.addMessage("assistant", response.content.text);
}
});
}
builder.addMessage("user", userInput);
// 设置模型偏好
if (options.modelHints) {
builder.setModelPreferences({
hints: options.modelHints,
intelligencePriority: 0.8,
speedPriority: 0.6,
costPriority: 0.4
});
}
const request = builder.build();
const response = await this.client.requestSampling(request);
// 记录对话历史
this.requestHistory.push({
request: { params: request },
response,
timestamp: Date.now()
});
return response.content.text || '';
}
// 文档分析功能
async analyzeDocument(
documentContent: string,
analysisType: 'summary' | 'sentiment' | 'key_points' | 'custom',
customPrompt?: string
): Promise<string> {
let systemPrompt: string;
switch (analysisType) {
case 'summary':
systemPrompt = "请对提供的文档内容进行简洁而全面的总结。";
break;
case 'sentiment':
systemPrompt = "请分析文档的情感倾向,包括积极、消极或中性的情感。";
break;
case 'key_points':
systemPrompt = "请提取文档中的关键要点和重要信息。";
break;
case 'custom':
systemPrompt = customPrompt || "请分析以下文档内容。";
break;
}
const request = new SamplingRequestBuilder()
.setSystemPrompt(systemPrompt)
.addMessage("user", `请分析以下文档内容:\n\n${documentContent}`)
.setContext("thisServer")
.setSamplingParams(0.3, 2000)
.setModelPreferences({
hints: ["claude-3", "gpt-4"],
intelligencePriority: 0.9,
speedPriority: 0.5,
costPriority: 0.6
})
.build();
const response = await this.client.requestSampling(request);
return response.content.text || '';
}
// 代码生成和审查功能
async generateCode(
description: string,
language: string,
requirements?: string[]
): Promise<string> {
let systemPrompt = `你是一个专业的${language}开发专家。请根据用户描述生成高质量的代码。`;
if (requirements && requirements.length > 0) {
systemPrompt += `\n\n特殊要求:\n${requirements.map(req => `- ${req}`).join('\n')}`;
}
const userPrompt = `请用${language}编写代码实现以下功能:\n${description}`;
const request = new SamplingRequestBuilder()
.setSystemPrompt(systemPrompt)
.addMessage("user", userPrompt)
.setContext("thisServer")
.setSamplingParams(0.2, 3000, ['```\n\n'])
.setModelPreferences({
hints: ["claude-3-5-sonnet", "gpt-4"],
intelligencePriority: 0.95,
speedPriority: 0.4,
costPriority: 0.5
})
.build();
const response = await this.client.requestSampling(request);
return response.content.text || '';
}
// 多轮推理功能
async multiStepReasoning(
problem: string,
steps: string[],
context?: string
): Promise<{ stepResults: string[]; finalAnswer: string }> {
const stepResults: string[] = [];
let accumulatedContext = context || '';
for (let i = 0; i < steps.length; i++) {
const systemPrompt = `你正在进行多步推理解决问题。当前是第${i + 1}步,共${steps.length}步。
原问题:${problem}
当前步骤:${steps[i]}
${accumulatedContext ? `已有上下文:\n${accumulatedContext}` : ''}
请专注于当前步骤,提供详细的分析和结论。`;
const request = new SamplingRequestBuilder()
.setSystemPrompt(systemPrompt)
.addMessage("user", `请执行步骤:${steps[i]}`)
.setContext("thisServer")
.setSamplingParams(0.1, 1500)
.build();
const response = await this.client.requestSampling(request);
const stepResult = response.content.text || '';
stepResults.push(stepResult);
accumulatedContext += `\n\n步骤${i + 1}结果:${stepResult}`;
}
// 最终综合
const finalRequest = new SamplingRequestBuilder()
.setSystemPrompt(`请基于所有步骤的分析结果,给出问题"${problem}"的最终答案。`)
.addMessage("user", `所有分析步骤已完成:\n${accumulatedContext}\n\n请给出最终答案。`)
.setSamplingParams(0.0, 1000)
.build();
const finalResponse = await this.client.requestSampling(finalRequest);
return {
stepResults,
finalAnswer: finalResponse.content.text || ''
};
}
// 获取对话历史
getConversationHistory(): typeof this.requestHistory {
return [...this.requestHistory];
}
// 清理历史记录
clearHistory(): void {
this.requestHistory = [];
}
// 资源清理
async cleanup(): Promise<void> {
this.client.disconnect();
this.clearHistory();
}
}
5. 实际使用示例
// usage-examples.ts
import { AdvancedSamplingManager } from './advanced-sampling-manager';
async function demonstrateMCPSampling() {
// 初始化采样管理器
const samplingManager = new AdvancedSamplingManager('ws://localhost:8080/mcp');
try {
await samplingManager.initialize();
console.log('MCP采样客户端已初始化');
// 1. 智能体对话示例
console.log('\n=== 智能体对话示例 ===');
const conversation1 = await samplingManager.agentConversation(
"请解释一下什么是量子计算?",
"你是一个物理学专家,擅长用通俗易懂的语言解释复杂概念。",
{
temperature: 0.7,
maxTokens: 800,
modelHints: ["claude-3-5-sonnet"]
}
);
console.log('AI回答:', conversation1);
// 2. 文档分析示例
console.log('\n=== 文档分析示例 ===');
const documentContent = `
人工智能技术在过去十年中取得了突破性进展。深度学习、自然语言处理、
计算机视觉等领域的快速发展,推动了AI在各行各业的广泛应用。
然而,AI技术的快速发展也带来了一些挑战,包括数据隐私、算法偏见、
就业影响等社会问题。
`;
const analysis = await samplingManager.analyzeDocument(
documentContent,
'key_points'
);
console.log('关键要点分析:', analysis);
// 3. 代码生成示例
console.log('\n=== 代码生成示例 ===');
const generatedCode = await samplingManager.generateCode(
"创建一个TypeScript函数,用于计算数组中所有数字的平均值",
"TypeScript",
["添加类型检查", "处理空数组情况", "添加JSDoc注释"]
);
console.log('生成的代码:', generatedCode);
// 4. 多轮推理示例
console.log('\n=== 多轮推理示例 ===');
const reasoningResult = await samplingManager.multiStepReasoning(
"如何设计一个高效的缓存系统?",
[
"分析缓存系统的核心需求",
"评估不同的缓存策略",
"考虑性能和存储的权衡",
"设计具体的实现方案"
],
"这是为一个高并发的Web应用设计缓存系统"
);
console.log('推理步骤结果:');
reasoningResult.stepResults.forEach((result, index) => {
console.log(`步骤 ${index + 1}:`, result.substring(0, 200) + '...');
});
console.log('最终方案:', reasoningResult.finalAnswer);
// 5. 查看对话历史
console.log('\n=== 对话历史统计 ===');
const history = samplingManager.getConversationHistory();
console.log(`总共进行了 ${history.length} 次采样请求`);
} catch (error) {
console.error('采样演示出错:', error);
} finally {
// 清理资源
await samplingManager.cleanup();
console.log('资源已清理');
}
}
// 错误处理和重试机制示例
async function robustSamplingExample() {
const samplingManager = new AdvancedSamplingManager('ws://localhost:8080/mcp');
async function samplingWithRetry(
operation: () => Promise<string>,
maxRetries: number = 3,
delay: number = 1000
): Promise<string> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await operation();
} catch (error) {
console.log(`采样尝试 ${attempt} 失败:`, error);
if (attempt === maxRetries) {
throw new Error(`采样在 ${maxRetries} 次尝试后仍然失败`);
}
// 等待后重试
await new Promise(resolve => setTimeout(resolve, delay * attempt));
}
}
throw new Error('不应该到达这里');
}
try {
await samplingManager.initialize();
const result = await samplingWithRetry(async () => {
return await samplingManager.agentConversation(
"请简单介绍一下TypeScript的主要特性",
"你是一个前端开发专家",
{ temperature: 0.3, maxTokens: 500 }
);
});
console.log('稳健采样结果:', result);
} finally {
await samplingManager.cleanup();
}
}
// 运行示例
if (require.main === module) {
demonstrateMCPSampling().catch(console.error);
}
最佳实践与安全考虑
1. 采样请求设计最佳实践
- 清晰的提示结构:使用明确、结构化的提示,避免歧义
- 合理的token限制:根据任务复杂度设置适当的maxTokens
- 温度参数调优:创意任务使用较高temperature,事实性任务使用较低值
- 上下文管理:谨慎使用includeContext,只包含必要的上下文信息
2. 安全性最佳实践
- 输入验证:严格验证所有消息内容,防止注入攻击
- 敏感信息过滤:在客户端过滤或脱敏敏感数据
- 访问控制:实现适当的用户权限和访问控制
- 审计日志:记录所有采样请求用于安全审计
3. 性能优化策略
- 请求缓存:缓存常见查询的结果
- 批处理:将多个相关请求合并处理
- 异步处理:使用异步模式处理长时间运行的采样
- 资源监控:监控token使用量和API成本
4. 错误处理机制
- 超时处理:设置合理的请求超时时间
- 重试策略:实现指数退避的重试机制
- 优雅降级:提供备用方案应对采样失败
- 用户反馈:向用户提供清晰的错误信息
实际应用场景
1. 智能文档处理系统
利用MCP采样功能构建自动化文档分析和处理流水线,支持多种文档格式的智能解析、摘要生成和关键信息提取。
2. 代码助手集成
在IDE中集成MCP采样,提供上下文感知的代码生成、重构建议和bug修复方案,提升开发效率。
3. 客户服务自动化
构建智能客服系统,通过采样功能理解客户问题并生成个性化回复,同时保持人工监督能力。
4. 内容创作平台
为内容创作者提供AI辅助工具,支持文章写作、创意生成和内容优化,同时确保内容质量和原创性。
总结
MCP采样功能为AI应用开发提供了强大而安全的LLM集成方案。通过本文的深度解析和TypeScript实战代码,开发者可以:
- 理解采样机制:掌握MCP采样的核心概念和工作原理
- 实现完整功能:利用提供的代码框架快速构建采样应用
- 遵循最佳实践:确保应用的安全性、性能和可维护性
- 扩展应用场景:基于采样功能构建更复杂的AI应用
MCP采样不仅是一个技术工具,更是连接AI能力与实际应用需求的重要桥梁。通过合理使用这一功能,我们可以构建既强大又安全的下一代AI应用。
随着MCP生态的不断发展,采样功能将在更多场景中发挥重要作用。建议开发者持续关注MCP的最新发展,不断优化和完善自己的实现方案。