本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
搭配 AgentCore 閘道使用抽樣
取樣是一種 MCP 功能,可讓 MCP 伺服器在工具呼叫期間向用戶端請求 LLM 完成。這可讓伺服器利用 AI 功能,而無需直接存取語言模型 — 用戶端會處理模型調用並傳回結果。AgentCore Gateway 會將 MCP 伺服器目標的取樣請求轉送到您的用戶端,id以閘道產生的識別符取代請求。
先決條件
若要搭配閘道使用抽樣:
-
工作階段已啟用 (2025-11-25 版及更早版本) — 取樣需要工作階段支援。請參閱搭配閘道使用 MCP 工作階段。對於版本 2026-07-28和更新版本,您不需要將 sessionConfiguration 新增至閘道,因為這些版本是無狀態的。
-
已啟用回應串流 (2025-11-25 版及更早版本) — 在開放連線期間,取樣請求會以 SSE 區塊的形式傳送。在閘道的 true中streamingConfiguration.enableResponseStreaming將 設定為 protocolConfiguration.mcp。對於版本 2026-07-28和更新版本,您不需要啟用回應串流。這些版本透過多往返請求 (MRTR) 模式提供取樣,而不是回應串流上的伺服器起始請求。如需詳細資訊,請參閱模型內容通訊協定文件中的多重往返請求。
-
MCP 伺服器目標類型 — 抽樣請求源自 MCP 伺服器目標。
-
Client 宣告取樣功能 — 用戶端必須宣告對取樣的支援,閘道才能轉送取樣請求。對於版本 2025-11-25和更早版本,用戶端會在initialize請求中宣告此支援。對於版本 2026-07-28和更新版本,用戶端會為 _meta 欄位 () 中的每個請求宣告它io.modelcontextprotocol/clientCapabilities。
抽樣的運作方式
當 MCP 伺服器目標在工具執行期間需要完成 LLM 時,它會傳送sampling/createMessage請求。閘道會將此請求轉送給用戶端做為 SSE 事件,取代請求 id。用戶端會叫用其語言模型,並將結果傳回至閘道,再將其轉送至目標。
此處所述的流程適用於版本 2025-11-25和更早版本,其中伺服器在開啟的 SSE 串流上sampling/createMessage以伺服器起始的請求傳送。對於 版本 2026-07-28 和更新版本,抽樣會改用多來回請求 (MRTR) 模式。伺服器會傳回將 resultType設為 的臨時結果input_required。然後,用戶端會在重試原始請求時提供完成。如需詳細資訊,請參閱模型內容通訊協定文件中的多重往返請求。
抽樣請求包括:
用戶端會以下列方式回應:
-
model — 使用的模型。
-
role — 一律為 assistant。
-
content — 產生的內容 (文字或影像)。
用戶端可完全控制要使用的模型,以及如何處理請求。伺服器modelPreferences是提示,而不是要求。用戶端也可以根據自己的政策修改或拒絕請求。
取樣流程
-
用戶端使用 Mcp-Session-Id標頭傳送tools/call請求。
-
Gateway 會將工具呼叫轉送至 MCP 伺服器目標。
-
目標會開啟 SSE 串流並傳送sampling/createMessage請求。
-
Gateway 會將取樣請求轉送給用戶端做為 SSE 事件,取代請求 id。
-
用戶端會使用提供的訊息叫用其語言模型。
-
用戶端會使用相同的 Mcp-Session-Id和id來自閘道請求的 ,傳送具有取樣結果的新請求。
-
Gateway 會將結果轉送至 MCP 伺服器目標。
-
目標會繼續處理並傳回最終工具結果。
-
Gateway 會將最終結果轉送至用戶端並關閉串流。
MCP 伺服器目標開發人員指南
傳送取樣請求的 MCP 伺服器目標應將取樣呼叫包裝在 try-catch 區塊中,並處理用戶端不支援取樣的情況。如果閘道的用戶端未宣告取樣功能,閘道不會將其宣告至目標。如果目標仍然傳送取樣請求,閘道會將 -32601(找不到方法) 錯誤傳回目標。
當無法使用取樣時,伺服器應實作備用路徑 (例如使用內建模型或略過 AI 輔助步驟)。
保護請求狀態 (2026-07-28 版及更新版本)
在 版本 2026-07-28 和更新版本上,抽樣使用多往返請求 (MRTR) 模式,在用戶端和 MCP 伺服器目標requestState之間具有不透明。保護該值是共同的責任:閘道在不儲存的情況下授權和轉送它,而您的 MCP 伺服器目標必須驗證它,並防止一個使用者重播另一個使用者的請求狀態。如需 MCP 伺服器必須遵循的完整共同責任模型和保護指引,請參閱 MCP 伺服器目標考量中的保護引出和取樣的請求狀態。
錯誤處理
| 案例 |
錯誤 |
說明 |
|
當沒有等待取樣請求時,用戶端會傳送取樣回應
|
JSON-RPC -32600(無效的請求)
|
找不到此工作階段的相符取樣請求。
|
|
用戶端使用id不符合待定請求的 傳送抽樣回應
|
JSON-RPC -32600(無效的請求)
|
id 必須與sampling/createMessage請求中閘道傳送的 相符。
|
|
MCP 伺服器會傳送抽樣請求,但閘道未宣告支援
|
JSON-RPC -32601(找不到方法)
|
已傳回 MCP 伺服器目標。請參閱故障診斷。
|
疑難排解
錯誤:「錯誤呼叫工具 'sample_tool':找不到方法: sampling/createMessage」
當 MCP 伺服器目標傳送取樣請求,但閘道的用戶端未宣告取樣功能時,就會發生此錯誤。對於版本 2025-11-25和更早版本,用戶端會在 期間宣告此功能initialize。對於版本 2026-07-28和更新版本,用戶端會針對 _meta 欄位中的每個請求宣告。閘道會將 -32601(找不到方法) 錯誤傳回目標。目標可能會將此作為工具執行錯誤傳回給用戶端。
若要解決問題:
-
如果您是 MCP 伺服器開發人員:新增取樣呼叫的錯誤處理。不支援取樣時實作備用路徑:
您必須在create_message通話related_request_id=ctx.request_context.request_id中包含 。這是閘道正確將抽樣請求與原始工具呼叫建立關聯的必要項目。如果沒有它,抽樣將無法運作。
try:
result = await ctx.session.create_message(
messages=[{"role": "user", "content": {"type": "text", "text": "Summarize this document"}}],
max_tokens=500,
related_request_id=ctx.request_context.request_id,
)
except Exception as e:
# Fallback when client doesn't support sampling
logger.warning(f"Sampling not supported: {e}")
result = fallback_summarization(document)
-
如果您是閘道用戶端開發人員:對於 2025-11-25和更早版本,請確保您的用戶端在 期間宣告取樣功能initialize。對於 版本 2026-07-28和更新版本,請在 _meta 欄位 (io.modelcontextprotocol/clientCapabilities) 中宣告每個請求。下列範例顯示initialize宣告:
{
"capabilities": {
"sampling": {}
}
}
程式碼範例
LangGraph MCP 用戶端 (langchain-mcp-adapters) 和 Strands MCP 用戶端目前不支援取樣。使用如下所示的 MCP 用戶端方法來處理來自閘道的取樣請求。
範例
- Python requests package (2025-11-25 and earlier)
-
在這些版本上,用戶端會在 期間宣告取樣功能initialize,而取樣請求會以sampling/createMessage請求的形式送達開啟的 SSE 串流。將 MCP-Protocol-Version標頭設定為閘道支援的版本。
import requests
import json
import sseclient
gateway_url = "https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp"
headers = {
"Content-Type": "application/json",
"Accept": "text/event-stream",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
# Step 1: Initialize with sampling capability
init_response = requests.post(gateway_url, headers=headers, json={
"jsonrpc": "2.0",
"id": "init-request",
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {"sampling": {}},
"clientInfo": {"name": "my-agent", "version": "1.0.0"}
}
})
session_id = init_response.headers["Mcp-Session-Id"]
headers["Mcp-Session-Id"] = session_id
headers["MCP-Protocol-Version"] = "2025-06-18"
# Step 2: Call tool (streaming response)
response = requests.post(gateway_url, headers=headers, json={
"jsonrpc": "2.0",
"id": "tool-call-1",
"method": "tools/call",
"params": {
"name": "summarizeDocument",
"arguments": {"documentId": "doc-789"}
}
}, stream=True)
# Step 3: Process SSE events
client = sseclient.SSEClient(response)
for event in client.events():
data = json.loads(event.data)
if data.get("method") == "sampling/createMessage":
sampling_id = data["id"]
print(f"Sampling request: {data['params']['messages']}")
# Step 4: Invoke your LLM and send result
llm_result = invoke_your_model(data["params"]) # Your LLM invocation
requests.post(gateway_url, headers=headers, json={
"jsonrpc": "2.0",
"id": sampling_id,
"result": {
"model": "claude-sonnet-4-20250514",
"role": "assistant",
"content": {"type": "text", "text": llm_result}
}
})
elif "result" in data:
print(f"Tool result: {data['result']}")
break
- Python requests package (2026-07-28)
-
在版本 上2026-07-28,取樣會使用多往返請求模式,而不是 SSE 串流上的伺服器起始請求。用戶端會_meta在每次請求時宣告 中的取樣功能。如果工具需要完成,回應是包含 中的sampling/createMessage請求inputRequests和不透明 input_required的結果requestState。用戶端會叫用其模型,並使用新的 id、 inputResponses和未修改的 重試原始請求requestState。工作階段和initialize交握不會使用。閘道的 supportedVersions 必須包含 2026-07-28。
import requests
gateway_url = "https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp"
META = {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": {"name": "my-agent", "version": "1.0.0"},
"io.modelcontextprotocol/clientCapabilities": {"sampling": {}}
}
headers = {
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"MCP-Protocol-Version": "2026-07-28",
"Mcp-Method": "tools/call",
"Mcp-Name": "summarizeDocument"
}
arguments = {"documentId": "doc-789"}
# Step 1: Call the tool, declaring the sampling capability in _meta
response = requests.post(gateway_url, headers=headers, json={
"jsonrpc": "2.0",
"id": "tool-call-1",
"method": "tools/call",
"params": {"name": "summarizeDocument", "arguments": arguments, "_meta": META}
}).json()
result = response["result"]
if result.get("resultType") == "input_required":
# Step 2: Fulfill each sampling request by invoking your model
input_responses = {}
for key, input_request in result.get("inputRequests", {}).items():
params = input_request["params"]
print(f"Sampling request: {params['messages']}")
llm_result = invoke_your_model(params) # Your LLM invocation
input_responses[key] = {
"model": "claude-sonnet-4-20250514",
"role": "assistant",
"content": {"type": "text", "text": llm_result}
}
# Step 3: Retry the tool call with a new id, the input responses,
# and the requestState echoed back unmodified
retry_params = {"name": "summarizeDocument", "arguments": arguments, "_meta": META,
"inputResponses": input_responses}
if "requestState" in result:
retry_params["requestState"] = result["requestState"]
response = requests.post(gateway_url, headers=headers, json={
"jsonrpc": "2.0",
"id": "tool-call-2",
"method": "tools/call",
"params": retry_params
}).json()
result = response["result"]
print(f"Tool result: {result}")
- MCP Client
-
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
import asyncio
async def sampling_handler(request):
"""Handle sampling requests from the server by invoking an LLM."""
messages = request.params.messages
llm_response = await invoke_your_model(messages, max_tokens=request.params.maxTokens)
return {
"model": "claude-sonnet-4-20250514",
"role": "assistant",
"content": {"type": "text", "text": llm_response}
}
async def use_sampling(url, token):
headers = {"Authorization": f"Bearer {token}"}
async with streamablehttp_client(url=url, headers=headers) as (
read_stream, write_stream, _
):
async with ClientSession(
read_stream, write_stream,
sampling_handler=sampling_handler
) as session:
await session.initialize()
result = await session.call_tool(
name="summarizeDocument",
arguments={"documentId": "doc-789"}
)
print(f"Tool result: {result}")
return result
asyncio.run(use_sampling(
url="https://mygateway-abcdefghij.gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp",
token="YOUR_ACCESS_TOKEN"
))