View a markdown version of this page

开始使用双向流式传输 WebSocket - Amazon Bedrock AgentCore

开始使用双向流式传输 WebSocket

Amazon Bedrock AgentCore Runtime 允许您部署支持 WebSocket 流媒体的代理,以实现实时双向通信。本指南将引导您使用 WebSocket创建、测试和部署您的第一个双向流媒体代理。

在本部分中,您将学习:

  • AgentCore 运行时如何支持 WebSocket 连接

  • 如何创建具有双向流媒体功能的代理应用程序

  • 如何在本地测试您的代理

  • 如何将代理部署到 AWS

  • 如何调用已部署的代理

  • 如何使用带 WebSocket 连接的会话

有关该 WebSocket 协议的更多信息,请参阅 WebSocket RFC 6455

AgentCore 运行时如何支持 WebSocket 连接

AgentCore Runtime 的 WebSocket 支持支持在客户端和代理之间实现持久的双向流媒体连接。 AgentCore Runtime 期望容器8080/ws路径的端口上实现 WebSocket 端点,这符合标准的 WebSocket 服务器实践。

AgentCore Runtime 的 WebSocket 支持提供了与之相同的无服务器、会话隔离、身份和可观察性功能。InvokeAgentRuntime此外,它还支持使用 Sigv4 或 OAuth 2.0 身份验证通过 WebSocket 连接实现低延迟、实时的消息双向传输,非常适合实时对话语音代理等应用程序。

支持的 WebSocket 库

WebSockets 在 AgentCore Runtime 上使用的双向流媒体支持使用任何 WebSocket 语言库的应用程序。唯一的要求是客户端必须通过 WebSocket 协议连接连接到服务端点:

wss://bedrock-agentcore.<region>.amazonaws.com/runtimes/<agentRuntimeArn>/ws

使用支持的身份验证方法之一(sigv4 标头、Sigv4 预签名 URL 或 OAuth 2.0),并且代理应用程序按照 HTTP 协议合同中的规定实现 WebSocket 服务合同。

这种灵活性允许您在不同的编程语言和框架中使用首选 WebSocket 实现,从而确保与现有代码库和开发工作流程的兼容性。

WebSocket 与 AgentCore 运行时一起使用

在本入门教程中,您将使用 b edrock-agentcore Python SDK 和用于部署的 CLI 创建、测试和部署支持双向流式传输的代理应用程序。AgentCore

先决条件

在开始之前,请确保你有:

第 1 步:设置项目并安装依赖关系

创建项目文件夹并安装所需的软件包:

mkdir agentcore-runtime-quickstart-websocket cd agentcore-runtime-quickstart-websocket python3 -m venv .venv source .venv/bin/activate

将 pip 升级到最新版本:

pip install --upgrade pip

安装以下必需的软件包:

  • bedrock-agentcor e-用于构建 AI 代理的 Amazon AgentCore Bedrock SDK,包括 python 库依赖关系 websockets

pip install bedrock-agentcore

第 2 步:创建您的双向直播代理

为您的双向流媒体代理代码创建一个名websocket_echo_agent.py为的源文件。添加以下代码:

from bedrock_agentcore import BedrockAgentCoreApp app = BedrockAgentCoreApp() @app.websocket async def websocket_handler(websocket, context): """Simple echo WebSocket handler.""" await websocket.accept() try: data = await websocket.receive_json() # Echo back await websocket.send_json({"echo": data}) except Exception as e: print(f"Error: {e}") finally: await websocket.close() if __name__ == "__main__": app.run(log_level="info")

创建requirements.txt并添加以下内容:

bedrock-agentcore

包含 python websockets 库依赖关系

了解代码

  • BedrockAgentCoreApp: 创建代理应用程序,用于扩展 Starlette 以部署 AI 代理,提供 WebSocket 支持、HTTP 路由、中间件和异常处理功能

  • WebSocket 装饰器@app.websocket装饰器会自动处理端口 8080 上/ws路径上的连接

  • Echo Logic:使用回传接收到的数据 {"echo": data}

  • 错误处理:使用 try/except /finally 结构来确保正确的错误记录和优雅的连接关闭。

第 3 步:在本地测试您的双向流媒体代理

启动您的双向流媒体代理

打开终端窗口,使用以下命令启动双向流媒体代理:

python websocket_echo_agent.py

您应该会看到显示服务器在 8080 端口上运行的输出。

测试 WebSocket 连接

创建名为websocket_agent_client.py:的本地 WebSocket 客户端

import asyncio import websockets import json async def local_websocket(): uri = "ws://localhost:8080/ws" try: async with websockets.connect(uri) as websocket: # Send a message await websocket.send(json.dumps({"inputText": "Hello WebSocket!"})) # Receive the echo response response = await websocket.recv() print(f"Received: {response}") except Exception as e: print(f"Connection failed: {e}") if __name__ == "__main__": asyncio.run(local_websocket())

打开另一个终端窗口并运行客户端,在本地测试您的双向流媒体代理:

python websocket_agent_client.py

成功:你应该会看到这样的回复Received: {"echo":{"inputText":"Hello WebSocket!"}}。在运行代理的终端窗口中,输入Ctrl+C以停止代理。

第 4 步:将双向流媒体代理部署到 AgentCore Runtime

安装部署工具

安装 C AgentCore LI:

npm install -g @aws/agentcore

验证安装:

agentcore --help

创建项目并部署到 AWS

为您的双向流媒体代理创建一个新项目:

agentcore create

部署您的代理:

agentcore deploy
注意

从代理文件所在的项目目录 (agentcore-runtime-quickstart-websocket) 中运行这些命令。

部署后,您将收到一个代理运行时 ARN,如下所示:

arn:aws:bedrock-agentcore:us-west-2:accountId:runtime/websocket_echo_agent-xyz123

保存此 ARN,因为您需要它来调用已部署的代理。

步骤 5:调用已部署的双向流媒体代理

设置环境变量

设置所需的环境变量:

  1. 导出您的代理 ARN:

    export AGENT_ARN="arn:aws:bedrock-agentcore:us-west-2:accountId:runtime/websocket_echo_agent-xyz123"
  2. 如果使用 OAuth,请导出您的不记名令牌:

    export BEARER_TOKEN="your_oauth_token_here"

身份验证方法

InvokeAgentRuntimeWithWebSocketStreamAPI 操作建立了一个 WebSocket 连接,该连接支持客户端和代理之间的双向流式传输。您可以使用以下方法对 WebSocket 连接进行身份验证:

  • AWS 签名版本 4 标头:使用您的 AWS 凭据对 WebSocket 握手请求标头进行签名

  • AWS 签名版本 4 Pre-signed 网址:使用作为查询参数提供的 Sigv4 签名创建预签名 WebSocket URL

  • OAuth 持有者令牌:在授权标题中传递 OAuth 令牌以进行外部身份提供商集成

提示

确保您拥有bedrock-agentcore:InvokeAgentRuntimeWithWebSocketStream权限。

使用 SigV4 签名的标头进行连接

以下示例说明如何使用 Sigv4 签名标头建立 WebSocket 连接并与代理运行时通信:

from bedrock_agentcore.runtime import AgentCoreRuntimeClient import websockets import asyncio import json import os async def main(): # Get runtime ARN from environment variable runtime_arn = os.getenv('AGENT_ARN') if not runtime_arn: raise ValueError("AGENT_ARN environment variable is required") # Initialize client client = AgentCoreRuntimeClient(region="us-west-2") # Generate WebSocket connection with authentication ws_url, headers = client.generate_ws_connection( runtime_arn=runtime_arn ) try: async with websockets.connect(ws_url, additional_headers=headers) as ws: # Send message await ws.send(json.dumps({"inputText": "Hello!"})) # Receive response response = await ws.recv() print(f"Received: {response}") except websockets.exceptions.InvalidStatus as e: print(f"WebSocket handshake failed with status code: {e.response.status_code}") print(f"Response headers: {e.response.headers}") print(f"Response body: {e.response.body.decode()}") except Exception as e: print(f"Connection failed: {e}") if __name__ == "__main__": asyncio.run(main())

运行客户端来测试已部署的代理:

python websocket_agent_client_sigv4_headers.py

成功:你应该会看到这样的回复:

Received: {"echo":{"inputText":"Hello!"}}

使用预签名 URL 连接(通过查询参数进行 sigv4)

以下示例说明如何使用 Sigv4 查询参数创建 WebSocket URL 并建立连接:

from bedrock_agentcore.runtime import AgentCoreRuntimeClient import websockets import asyncio import json import os async def main(): runtime_arn = os.getenv('AGENT_ARN') if not runtime_arn: raise ValueError("AGENT_ARN environment variable is required") client = AgentCoreRuntimeClient(region="us-west-2") # Generate WebSocket pre-signed URL (with SigV4 via query parameters) # wss://...amazonaws.com/runtimes/.../ws?X-Amz-Algorithm=AWS4-HMAC-SHA256 # &X-Amz-Credential=...&X-Amz-Date=...&X-Amz-Expires=300 # &X-Amz-SignedHeaders=...&X-Amz-Signature=... sigv4_url = client.generate_presigned_url( runtime_arn=runtime_arn, expires=300 # 5 minutes ) try: async with websockets.connect(sigv4_url) as ws: await ws.send(json.dumps({"inputText": "Hello!"})) response = await ws.recv() print(f"Received: {response}") except websockets.exceptions.InvalidStatus as e: print(f"WebSocket handshake failed with status code: {e.response.status_code}") print(f"Response headers: {e.response.headers}") print(f"Response body: {e.response.body.decode()}") except Exception as e: print(f"Connection failed: {e}") if __name__ == "__main__": asyncio.run(main())

运行客户端来测试已部署的代理:

python websocket_agent_client_sigv4_query_parameters.py

成功:你应该会看到这样的回复:

Received: {"echo":{"inputText":"Hello!"}}

使用 OAuth 进行连接

AgentCore 运行时支持对连接进行 OAuth 持有者令牌身份验证。 WebSocket 要使用 OAuth 身份验证,您需要为代理运行时配置 JWT 授权,如使用入站身份验证和出站身份验证进行身份验证和授权的 JWT 入站授权和 OAuth 出站访问示例部分中所述。

完成 OAuth 设置并按照 OAuth 指南中的第 4 步:使用不记名令牌调用代理获得持有者令牌后,即可使用该令牌建立连接。 WebSocket

带有 OAuth 的 Python 客户端

以下示例说明如何使用 OAuth 从 Python 建立 WebSocket 连接:

from bedrock_agentcore.runtime import AgentCoreRuntimeClient import websockets import asyncio import json import os async def main(): # Get runtime ARN from environment variable runtime_arn = os.getenv('AGENT_ARN') if not runtime_arn: raise ValueError("AGENT_ARN environment variable is required") # Get OAuth bearer token from environment variable bearer_token = os.getenv('BEARER_TOKEN') if not bearer_token: raise ValueError("BEARER_TOKEN environment variable required for OAuth") # Initialize client client = AgentCoreRuntimeClient(region="us-west-2") # Generate WebSocket connection with OAuth ws_url, headers = client.generate_ws_connection_oauth( runtime_arn=runtime_arn, bearer_token=bearer_token ) try: async with websockets.connect(ws_url, additional_headers=headers) as ws: # Send message await ws.send(json.dumps({"inputText": "Hello!"})) # Receive response response = await ws.recv() print(f"Received: {response}") except websockets.exceptions.InvalidStatus as e: print(f"WebSocket handshake failed with status code: {e.response.status_code}") print(f"Response headers: {e.response.headers}") print(f"Response body: {e.response.body.decode()}") except Exception as e: print(f"Connection failed: {e}") if __name__ == "__main__": asyncio.run(main())

运行客户端来测试已部署的代理:

python websocket_agent_client_oauth.py

成功:你应该会看到这样的回复:

Received: {"echo":{"inputText":"Hello!"}}
带有 OA JavaScript uth 的浏览器客户端

浏览器的本机 WebSocket API 不提供在握手期间设置自定义标头的方法。为了支持浏览器的 OAuth 身份验证, AgentCore Runtime 在握手期间接受Sec-WebSocket-Protocol标题中嵌入的不记名令牌。 WebSocket

令牌必须采用 base64url 编码,前缀为 sentinel 子协议base64UrlBearerAuthorization.base64UrlBearerAuthorization

以下示例说明如何 JavaScript 使用 OAuth 从浏览器建立 WebSocket 连接:

<!DOCTYPE html> <html> <body> <button onclick="connect()">Connect</button> <div id="output"></div> <script> function connect() { const bearerToken = "your_oauth_token_here"; const runtimeArn = "arn:aws:bedrock-agentcore:us-west-2:accountId:runtime/agent-xyz123"; // Base64url encode token const base64url = btoa(bearerToken) .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=/g, ''); const ws = new WebSocket( `wss://bedrock-agentcore.us-west-2.amazonaws.com/runtimes/${runtimeArn}/ws`, [`base64UrlBearerAuthorization.${base64url}`, "base64UrlBearerAuthorization"] ); ws.onopen = () => ws.send(JSON.stringify({ inputText: "Hello!" })); ws.onmessage = (e) => document.getElementById("output").innerText = e.data; } </script> </body> </html>
注意

此身份验证方法适用于无法设置自定义标头的基于浏览器的客户端。对于非浏览器客户端(Python、 Node.js 服务器等),请使用 Pyth on 客户端中显示的 OAuth 标头身份验证和 OAuth。

注意

尚不支持除base64UrlBearerAuthorization之外的子协议。

重要

这是一个参考示例。不建议在生产代码中对令牌进行硬编码。

会话管理

在 WebSocket 连接上提供 session_id (X-Amzn-Bedrock-AgentCore-Runtime-Session-Id)(作为 URL 查询参数或请求标头)会将连接路由到隔离的运行时会话。代理可以访问存储在该会话中的对话上下文,通过引用以前的交互来实现对话的连续性。不同的会话 ID 可以访问独立的上下文,从而确保用户或对话之间完全隔离。

如需全面的会话生命周期管理,包括跟踪、清理和错误处理,请参阅为代理使用隔离会话

使用带 WebSocket 连接的会话

要使用带 WebSocket 连接的会话,请为每个用户或对话生成一个唯一的会话 ID,并在建立连接时传递该会话 ID:

SigV4 Headers
  1. from bedrock_agentcore.runtime import AgentCoreRuntimeClient import websockets import asyncio import json import os async def websocket_with_session(): client = AgentCoreRuntimeClient(region="us-west-2") session_id = "user-123-conversation-456" runtime_arn = os.getenv('AGENT_ARN') ws_url, headers = client.generate_ws_connection( runtime_arn=runtime_arn, session_id=session_id ) try: async with websockets.connect(ws_url, additional_headers=headers) as ws: await ws.send(json.dumps({"inputText": "Hello!"})) response = await ws.recv() print(f"Response: {response}") except websockets.exceptions.InvalidStatus as e: print(f"WebSocket handshake failed with status code: {e.response.status_code}") print(f"Response headers: {e.response.headers}") print(f"Response body: {e.response.body.decode()}") except Exception as e: print(f"Connection failed: {e}") asyncio.run(websocket_with_session())
SigV4 Pre-signed URL
  1. from bedrock_agentcore.runtime import AgentCoreRuntimeClient import websockets import asyncio import json import os async def websocket_with_session(): client = AgentCoreRuntimeClient(region="us-west-2") session_id = "user-123-conversation-456" runtime_arn = os.getenv('AGENT_ARN') presigned_url = client.generate_presigned_url( runtime_arn=runtime_arn, session_id=session_id, expires=300 ) try: async with websockets.connect(presigned_url) as ws: await ws.send(json.dumps({"inputText": "Hello!"})) response = await ws.recv() print(f"Response: {response}") except websockets.exceptions.InvalidStatus as e: print(f"WebSocket handshake failed with status code: {e.response.status_code}") print(f"Response headers: {e.response.headers}") print(f"Response body: {e.response.body.decode()}") except Exception as e: print(f"Connection failed: {e}") asyncio.run(websocket_with_session())
OAuth
  1. from bedrock_agentcore.runtime import AgentCoreRuntimeClient import websockets import asyncio import json import os async def websocket_with_session(): client = AgentCoreRuntimeClient(region="us-west-2") session_id = "user-123-conversation-456" runtime_arn = os.getenv('AGENT_ARN') bearer_token = os.getenv('BEARER_TOKEN') ws_url, headers = client.generate_ws_connection_oauth( runtime_arn=runtime_arn, session_id=session_id, bearer_token=bearer_token ) try: async with websockets.connect(ws_url, additional_headers=headers) as ws: await ws.send(json.dumps({"inputText": "Hello!"})) response = await ws.recv() print(f"Response: {response}") except websockets.exceptions.InvalidStatus as e: print(f"WebSocket handshake failed with status code: {e.response.status_code}") print(f"Response headers: {e.response.headers}") print(f"Response body: {e.response.body.decode()}") except Exception as e: print(f"Connection failed: {e}") asyncio.run(websocket_with_session())
提示

为获得最佳效果,请使用会话 ID 的 UUID 或其他唯一标识符,以避免不同用户或对话之间发生冲突。

通过对相关 WebSocket 连接使用相同的会话 ID,可以确保在同一对话中保持上下文,从而使您的代理能够在之前的交互基础上提供连贯的响应。

包含 WebSocket 连接的会话生命周期

对于 WebSocket 连接,每次客户端和代理之间有消息活动时,会话的空闲超时都会被重置。这包括任何 WebSocket 消息交换,例如从客户端向代理发送数据、从代理到客户端接收响应或 WebSocket ping/pong 帧。这意味着,只要消息继续流动,活跃的 WebSocket 对话就会使会话保持活动状态,从而防止在正在进行的互动期间会话过早终止。

有关配置生命周期设置的更多信息,请参阅配置 Amazon Bedrock AgentCore 生命周期设置。要通过代理运行状况更直接地控制会话生命周期,请参阅运行时会话生命周期管理

停止运行时会话

要在配置之前停止正在运行的会话IdleRuntimeSessionTimeout(默认为 15 分钟),请参阅停止正在运行的会话

可观测性

Amazon Bedrock O AgentCore bservability 可帮助您跟踪、调试和监控您在亚马逊 Bedro AgentCore ck Runtime 中托管的代理。首先按照启用 Amazon Bedrock AgentCore 运行时可观察性中的说明启用 CloudWatch 交易搜索。要观察您的代理,请参阅查看您的 Amazon Bedrock AgentCore 代理的可观察性数据

对于 WebSocket 连接,跟踪表示完整的连接会话,而不是单个消息交换。

自定义标头

自定义标头允许您在初始 WebSocket 连接时将应用程序中的上下文信息直接传递给代理代码。有关自定义标题支持、配置和限制的完整信息,请参阅将自定义标题传递给 Amazon Bedrock AgentCore Runtime

此外,前缀为的标头X-Amzn-Bedrock-AgentCore-Runtime-Custom-可以在 WebSocket 连接中作为 URL 查询参数传递。

例如,您可以在 WebSocket URL 中将自定义标头作为查询参数传递:

wss://bedrock-agentcore.<region>.amazonaws.com/runtimes/<agentRuntimeArn>/ws?X-Amzn-Bedrock-AgentCore-Runtime-Custom-TestHeader=query-param-test-value

代理应用程序容器将把这些作为标题接收:

"headers": { "x-amzn-bedrock-agentcore-runtime-custom-testheader": "query-param-test-value" }

附录

安全注意事项

提示

有关所有 Runtime 安全建议的综合视图,请参阅 R AgentCore untime 安全最佳实践

身份验证

所有 WebSocket 连接都需要通过 Sigv4 或 OAuth 2.0 进行适当的 AWS 身份验证

会话隔离

每个会话都使用专用资源在隔离的执行环境中运行

传输安全

所有连接都使用 HTTPS 上的 WSS(WebSocket 安全)进行加密通信

访问控制

IAM 策略控制 WebSocket 连接权限和对特定代理的访问权限

问题排查

常见 WebSocket-specific 问题

以下是您可能遇到的常见问题:

连接失败

验证您的代理应用程序是否在处理连接请求 /ws

身份验证方法不匹配

确保您的客户端使用的身份验证方法(OAuth 或 Sigv4)与代理配置时使用的身份验证方法相同

由于超过限制,连接已关闭

如果超过限制(例如消息帧速率或消息帧大小限制),则连接将自动关闭。有关完整的限制信息,请参阅 Amazon Bedrock 的配额 AgentCore

已超出消息帧大小

配置消息帧分段或实现分块,使其保持在 32KB 帧大小限制以下。在发送之前将大消息拆分成较小的块

Health 检查失败

确保您的代理容器实现了 HTTP 协议合同中指定的/ping端点。此端点可验证您的代理是否处于运行状态并准备好处理请求,从而实现服务监控和自动恢复

错误处理

WebSocket 连接使用标准的关闭码进行错误通信。常见的关闭代码包括:

  • 1000-普通封口

  • 1001-走开

  • 1008-违反政策(超过限制)

  • 1009-邮件太大(超出消息帧大小限制)

  • 1011-服务器错误

WebSocket 与其他协议对比

何时使用 WebSocket

  • Real-time 带有即时音频流的语音对话,实现自然的对话流程

  • 双向 audio/text /binary 数据流(将数据块从客户端流式传输到代理,反之亦然)

  • 中断处理(用户可以在对话中打断代理)

何时使用 HTTP

  • HTTP 用于请求-响应模式,无需双向流式传输

其他入门示例

有关在 Runt AgentCore ime 中使用 WebSocket 双向流式传输的其他示例,请参阅WebSocket 双向流式传输 GitHub 示例:

  • Sonic 实现 (Python):原生 Amazon Nova Sonic WebSocket 实现,提供实时音频对话、语音选择和中断支持

  • Strands 实现 (Python):使用 Strands Framework-based BidiAgent 实现,通过自动会话管理和工具集成来简化实时音频对话

  • Echo 实现 (Python):用于测试 WebSocket 连接和身份验证的简单回声服务器