

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 交互式外壳（终端）
<a name="runtime-get-started-command-shell"></a>

该`InvokeAgentRuntimeCommandShell`操作将在正在运行的 AgentCore 运行时会话中打开一个持续的交互式终端会话 WebSocket。与一次性命令执行不同，shell 会话维护状态——环境变量、工作目录和命令历史记录会传递输入。这样可以在应用程序中进行调试、环境检查和构建终端体验。

要拨打电话`InvokeAgentRuntimeCommandShell`，你需要`bedrock-agentcore:InvokeAgentRuntimeCommandShell`权限。

## 工作原理
<a name="runtime-command-shell-how-it-works"></a>

 `InvokeAgentRuntimeCommandShell` WebSocket 与在代理会话中运行的交互式 shell 进程建立连接。该连接使用二进制帧来双向传输终端输入和输出。

 **同一个代理，同一个会话 ** 

 `InvokeAgentRuntimeCommandShell`与`InvokeAgentRuntime`和在相同的代理运行时上运行`InvokeAgentRuntimeCommand`。你不能创建单独的资源。您部署的代理`CreateAgentRuntime`接受任何活动会话上的 shell 连接。

**注意**  
您可以传递一个`session_id`来定位特定的运行时会话。如果省略，则为每个连接创建一个新会话。要使用重新连接，必须同时存储和并重复使用`session_id`。`shellId`

该连接支持：


| 功能 | 说明 | 
| --- | --- | 
| 永久状态 | 环境变量、工作目录和命令历史记录在同一个会话中传递输入。 | 
| 重新连接 | 提供相同的，`session_id`并在断开连接后重新`shellId`连接到同一 shell。该服务可重放多达 256 KB 的缓冲输出。 | 
| 多个并发外壳 | 每个运行时最多 10 个活跃的 shell 会话（终端）。新连接在满负荷时会被拒绝。 | 

## 先决条件
<a name="runtime-command-shell-prerequisites"></a>
+  `bedrock-agentcore:InvokeAgentRuntimeCommandShell` IAM 权限
+  AgentCore 运行时处于 READY 状态的有效运行时端点 ARN

**注意**  
2026 年 6 月 5 日之后创建的代理自动支持交互式外壳（终端）。如果您在此日期之前部署了代理，则必须重新部署它以更新代理运行时间。

## 使用 AgentCore CLI
<a name="runtime-command-shell-cli"></a>

有关安装和设置说明，请参阅 AgentCore CLI [ 入门](runtime-get-started-cli.md)。

CLI 提供了内置的终端体验`agentcore exec`。

```
agentcore exec --it
```

要连接到特定的运行时，请执行以下操作：

```
agentcore exec --it --runtime <runtime-arn> --region us-west-2
```

按下`Ctrl+]`即可在不关闭外壳的情况下将其从外壳上拆下。CLI 打印一个重新连接命令：

```
agentcore exec --it \
  --runtime <arn> \
  --region <region> \
  --session-id <uuid> \
  --shell-id <id>
```

对于单发命令，请省略`--it`：

```
agentcore exec "ls -la /tmp"
```

对于机器可读的输出，请使用 JSON 模式：

```
agentcore exec --json "echo hello"
# Output: {"success":true,"exitCode":0,"stdout":"hello\n","stderr":""}
```

有关其他 CLI 示例，请参阅[上的示](https://github.com/awslabs/agentcore-samples)AgentCore 例 GitHub。

## 使用 AgentCore SDK
<a name="runtime-command-shell-sdk"></a>

安装 Python SDK：

```
pip install bedrock-agentcore
```

**Example**  

1. 以下示例显示如何使用默认 Amazon 凭据打开 shell 会话。

   ```
   import asyncio
   from bedrock_agentcore.runtime import AgentCoreRuntimeClient, ShellChannel
   
   async def main():
       runtime_arn = "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/my-agent"
       client = AgentCoreRuntimeClient(region="us-west-2")
   
       async with client.open_shell(runtime_arn) as shell:
           print(f"Connected. Shell ID: {shell.shell_id}")
   
           # Send a command
           await shell.send("echo Hello from AgentCore Shell\n")
   
           # Read output frames
           async for frame in shell:
               if frame.channel == ShellChannel.STDOUT:
                   print(frame.text, end="")
                   if "Hello from AgentCore Shell" in frame.text:
                       break
   
   asyncio.run(main())
   ```

1. 以下示例显示如何使用预签名 URL 打开 shell 会话。

   ```
   import asyncio
   from bedrock_agentcore.runtime import AgentCoreRuntimeClient, PresignedAuth, ShellChannel
   
   async def main():
       runtime_arn = "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/my-agent"
       client = AgentCoreRuntimeClient(region="us-west-2")
   
       async with client.open_shell(runtime_arn, auth=PresignedAuth(expires=120)) as shell:
           await shell.send("whoami\n")
   
           async for frame in shell:
               if frame.channel == ShellChannel.STDOUT:
                   print(frame.text, end="")
                   break
   
   asyncio.run(main())
   ```

1. 以下示例显示如何使用 OAuth 持有者令牌打开 shell 会话。

   ```
   import asyncio
   from bedrock_agentcore.runtime import AgentCoreRuntimeClient, OAuthAuth, ShellChannel
   
   async def main():
       runtime_arn = "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/my-agent"
       bearer_token = "your_oauth_token_here"
       client = AgentCoreRuntimeClient(region="us-west-2")
   
       async with client.open_shell(runtime_arn, auth=OAuthAuth(bearer_token=bearer_token)) as shell:
           await shell.send("echo oauth-connected\n")
   
           async for frame in shell:
               if frame.channel == ShellChannel.STDOUT:
                   print(frame.text, end="")
                   if "oauth-connected" in frame.text:
                       break
   
   asyncio.run(main())
   ```

 **重新连接 ** 

一种常见的模式是在断开连接后重新连接到 shell，保留所有会话状态。`shellId`

```
import asyncio

from bedrock_agentcore.runtime import AgentCoreRuntimeClient

async def main():
    client = AgentCoreRuntimeClient(region="us-west-2")
    runtime_arn = "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/my-agent"
    session_id = "my-session-0000000000000000000000"
    shell_id = "my-shell"

    shell = await client.open_shell(
        runtime_arn,
        session_id=session_id,
        shell_id=shell_id,
    ).__aenter__()
    print(f"connected (reconnected={shell.reconnected})")
    await shell.send("export GREETING='hello'\n")
    await asyncio.sleep(1)

    async with client.open_shell(
        runtime_arn,
        session_id=session_id,
        shell_id=shell_id,
    ) as shell2:
        print(f"reconnected (reconnected={shell2.reconnected})")
        assert shell2.reconnected


if __name__ == "__main__":
    asyncio.run(main())
```

 **Auto-reconnect** 

当连接断开时，SDK 也可以自动重新 WebSocket 连接。使用`ReconnectConfig`来启用此功能：

```
import asyncio
from bedrock_agentcore.runtime import AgentCoreRuntimeClient, ReconnectConfig, ShellChannel

async def on_reconnect(reconnected: bool):
    print(f"Reconnected: {reconnected}")

async def main():
    runtime_arn = "arn:aws:bedrock-agentcore:us-west-2:123456789012:runtime/my-agent"
    shell_id = "my-persistent-shell"
    config = ReconnectConfig(max_retries=5, base_delay=0.5, on_reconnect=on_reconnect)

    client = AgentCoreRuntimeClient(region="us-west-2")
    async with client.open_shell(runtime_arn, shell_id=shell_id, reconnect_config=config) as shell:
        # If the connection drops, the SDK retries automatically
        await shell.send("long-running-command\n")
        async for frame in shell:
            if frame.channel == ShellChannel.STDOUT:
                print(frame.text, end="")

asyncio.run(main())
```

有关其他 SDK 示例，请参阅[上的示](https://github.com/awslabs/agentcore-samples)AgentCore 例 GitHub。

## 常见使用案例
<a name="runtime-command-shell-use-cases"></a>

交互式调试  
打开 shell 来检查代理的运行时环境 — 检查已安装的软件包、读取日志文件、检查文件系统或测试命令，然后再将它们添加到代理代码中。  

```
python --version && pip list | head -20
```

环境检查  
验证环境变量、网络连接、可用工具和文件系统状态。在诊断代理故障或验证部署配置时很有用。  

```
env | grep AWS && curl -s http://169.254.169.254/latest/meta-data/
```

编码代理终端访问权限  
AI 编码代理使用交互式 shell（终端）作为其执行环境。当编码代理需要运行代码、安装软件包或运行测试时，它会打开 R AgentCore untime 的 shell 会话并直接执行命令，就像开发人员使用终端一样。例如，Claude Code、Amazon Kiro 和 OpenAI Codex 都连接到外壳会话，他们可以在其中迭代编写代码、运行代码、观察输出并循环修复错误。持久状态意味着代理可以在不丢失步骤之间上下文的情况下运行一系列命令。  

```
# A coding agent opens a shell and iterates on code
async with client.open_shell(runtime_arn, shell_id="agent-workspace") as shell:
    await shell.send("cd /workspace && git clone https://github.com/user/repo.git\n")
    await shell.send("cd repo && pip install -r requirements.txt\n")
    await shell.send("python -m pytest tests/ -v\n")
    # Agent reads test output, fixes failures, re-runs — all in the same shell
```

Long-running 进程  
启动寿命超过单个 HTTP 请求的进程。使用重新连接来检查进度或在一段时间内提供其他输入。  

```
nohup python train.py > /tmp/train.log 2>&1 &
```

## 关键设计选择
<a name="runtime-command-shell-design"></a>

持续的互动会话  
每个连接都映射到一个长期存在的 shell 进程。您可以发送多个命令而无需重新建立连接，并且先前命令（导出的变量、`cd`更改）累积的状态可供后续命令使用。

二进制框架结束 WebSocket  
终端 I/O 以二进制 WebSocket 帧的形式流式传输。这支持原始终端控制序列、颜色、光标移动和全屏应用程序，无需编码开销。

使用输出重播重新连接  
当您使用该服务重新连接时`shellId`，该服务最多可重放 256 KB 的最近输出。这使您可以在不丢失上下文的情况下从网络中断中恢复。在断开连接期间，shell 进程继续运行。

会话限制  
当运行时已经打开了 10 个 shell 会话（终端）时，新的连接会被拒绝并出现错误。在打开新会话之前，必须关闭现有会话。

## 安全注意事项
<a name="runtime-command-shell-security"></a>

**提示**  
有关所有运行时安全建议的综合视图，请参阅 AgentCore 运行时[安全最佳实践](runtime-security-best-practices.md)。

**重要**  
在责任 Amazon 共担模式下，您对在运行 AgentCore 时会话中运行的命令负责。 Amazon 在 microVM 级别提供安全的基础设施和隔离。您对执行的命令、处理的数据和配置的访问控制负责。

外壳会话（终端）的安全边界是 microVM。每个 AgentCore 运行时会话都在具有自己的内核、内存和文件系统的独立微虚拟机中运行。Shell 会话无法访问其他客户的工作负载或逃离虚拟机边界。但是，在您的虚拟机中，shell 命令可以完全访问容器文件系统以及您配置的任何凭据或机密。

 **使用 CloudWatch 日志进行审计 ** 

AgentCore Runtime 将请求 ID 和连接元数据发送到您的代理的 Amazon Logs CloudWatch 日志组。您可以使用这些日志来监控 shell 连接活动并维护审计记录。终端 I/O 内容 (stdin/stdout) 将流式传输到您的客户端，不由该服务记录。

 **审计 CloudTrail ** 

 Amazon CloudTrail 在您的账户中记录 `InvokeAgentRuntimeCommandShell` API 调用。每条记录都包含呼叫者身份、时间戳、源 IP 地址和响应状态等元数据。 CloudTrail 不记录请求或响应负载。 CloudTrail 用于审核谁打开了 shell 会话以及何时打开，然后使用请求 ID 与 CloudWatch 日志关联以获取连接详细信息。

对于敏感工作负载，可以考虑实施其他控制措施，例如：
+ 使用 IAM 策略限制哪些委托人可以致电 `InvokeAgentRuntimeCommandShell` 
+ 配置 VPC 终端节点以保持网络内的流量
+ 设置 CloudWatch 日志指标筛选器和警报以检测意外的连接模式
+ 定期查看 CloudTrail 日志中是否有未经授权的访问尝试

## 错误处理
<a name="runtime-command-shell-error-handling"></a>

建立 shell 会话连接时，在 WebSocket 升级期间可能会遇到以下错误：

 **ValidationException**   
当请求参数无效时发生。如果会话 ID 少于 33 个字符、目标区域未启用该功能或代理未处于 READY 状态，则会发生这种情况。

 **AccessDeniedException**   
当你没有必要的权限时发生。确保您的 IAM 政策包含`bedrock-agentcore:InvokeAgentRuntimeCommandShell`权限。

 **ResourceNotFoundException**   
当找不到指定的代理运行时发生。验证运行时 ARN 是否正确。

 **RuntimeClientError (424) **   
发生在以下几种场景中：(1) 已达到最大并发 shell 会话（终端）（10 次打开）— 关闭现有会话并重试。(2) Shell ID 格式无效-必须为 1-128 个字母数字字符、下划线或连字符。(3) 无法访问运行时间 — 退避后重试。解析响应正文 JSON `error` 字段以区分原因。

 **ThrottlingException**   
当您超过 API 速率限制时发生。实现指数退避和重试逻辑。

 **ConflictException**   
另一个连接`shellId`同时声明了相同的内容。1 秒后重试。这是一种狭义的竞争条件（不是持续状态），重试后会立即解决。

 **RetryableConflictException (409) **   
当您在服务预置或关闭目标会话时打开 shell 会话连接时发生。消息是`Session operation in progress, please retry`。这种情况是暂时的，可以重试。窗口很短，已经运行的会话不受影响。使用短暂的指数退避重试。因为`InvokeAgentRuntimeCommandShell`是一 WebSocket 个 API，所以 Amazon 软件开发工具包不会自动重试。自己重试。

连接后，以下关闭代码表示连接终止的原因：


| 代码 | 含义 | 客户操作 | 
| --- | --- | --- | 
|  `1000`  | 正常关闭 — 外壳干净退出或正常断开连接 | 显示 “已断开连接”。正常终止。 | 
|  `1001`  | 即将消失 — 服务器部署或关闭 | Auto-reconnect 已存储`shellId`。 | 
|  `1003`  | 不支持的数据 — 在连续 5 个文本框之后发送（仅限二进制协议） | 不要自动重新连接。切换到二进制帧。 | 
|  `1006`  | 异常关闭 — 未收到关闭帧时在本地合成（网络死机、TCP RST） | Auto-reconnect 已存储`shellId`。 | 
|  `1008`  | 策略违规 — 连接 TTL 已过期（1 小时）、超过帧速率限制（250 frames/sec）或写入缓冲区溢出 | Auto-reconnect 用于 TTL 到期（重新连接时为新 TTL）。对于速率限制：退缩，然后重新连接。 | 
|  `1009`  | 消息太大 — 帧负载超过 64 KB | 减小帧大小（区块到 <64 KB），然后重新连接。会话仍然有效。 | 
|  `1011`  | 服务器错误-意外内部故障 | 使用退避功能重试。 | 
|  `4000`  | 已替换 — 另一台与之连接的客户端 `shellId`  | 不要自动重新连接。显示 “从另一台客户端连接的会话”。 | 

## 最佳实践
<a name="runtime-command-shell-best-practices"></a>

使用时请遵循以下最佳实践`InvokeAgentRuntimeCommandShell`：
+ 为每个逻辑会话使用唯一的`shellId`（例如 UUID）以启用重新连接。将存储`shellId`在客户端。
+ `ReconnectConfig`在 SDK 中使用可自动处理瞬态网络中断，无需手动重新连接逻辑。
+ 立即读取输出帧。如果客户端落后，服务器的写入缓冲区将填满，连接将以代码关闭`1008`。
+ 对于大型输入（例如粘贴文件），将内容拆分为每帧小于 64 KB 的块，以避免关闭代码。`1009`
+ 设置适当的连接超时。最长连接时长为 1 小时 — 重新连接`shellId`以后继续连接。
+ 完成后明确关闭会话。分离的会话计入 10 个会话的限制。

## 限额和限制
<a name="runtime-command-shell-limits"></a>


| 限制 | 值 | 说明 | 
| --- | --- | --- | 
| 最大帧有效载荷大小 | 64 KB | 超过此限制的帧数会导致关闭代码`1009`。 | 
| 帧率 | 250 frames/sec | 超过此值会触发关闭代码`1008`。 | 
| 最大连接持续时间 | 1 小时 | 连接使用代码关闭`1008`。使用相同的方法重新连接`shellId`以继续。 | 
| 每个运行时的并发 shell 会话（终端） | 10 | 如果 10 个会话已经打开，则新连接将被拒绝。关闭现有会话并重试。 | 
| 重新连接缓冲区 | 256 KB | 重新连接外壳时重放的最大输出。 | 

有关完整的服务限制，请参阅亚马逊 Bedrock AgentCore [ 的](bedrock-agentcore-limits.md)配额。