> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentscope.io/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> For AgentScope Python, use https://docs.agentscope.io/stable/en/index for new projects. For existing projects, check the installed agentscope version and use matching versioned documentation.
> The /latest/ alias points to the newest documentation and may move ahead of /stable/ when a development version exists. Do not mix AgentScope 1.x and 2.x APIs.
> State the AgentScope version when providing installation commands or code examples. ReMe uses its own continuously updated /reme/latest/ documentation.

# 人机交互

> 暂停以等待用户确认或外部执行，再通过结果事件恢复

当智能体遇到以下两种情况时，会暂停执行并发出特殊事件：需要**用户确认**的工具调用（权限系统返回 ASK），或标记为**外部执行**的工具（结果必须来自智能体外部）。两种情况下，都通过向 `reply` / `reply_stream` 传回结果事件来恢复智能体。

暂停期间，`reply` 会返回一条 `finished_reason` 为 `None` 的等待提示消息：回复处于停靠状态而非结束，在外部结果到达之前，剩余的工具调用不会执行。

## 用户确认

当权限系统判断某个工具调用需要用户批准时，智能体会发出 `RequireUserConfirmEvent` 并暂停。

**1. 接收 RequireUserConfirmEvent**

使用 `reply_stream` 检测暂停。事件结构如下：

**reply\_id** `str` *required*

当前回复的 ID，用于恢复智能体。

**tool\_calls** `list[ToolCallBlock]` *required*

等待用户确认的工具调用列表。每个 `ToolCallBlock` 包含：

**id** `str`

此工具调用的唯一标识符。

**name** `str`

工具名称（如 `"Bash"`、`"Write"`）。

**input** `str`

JSON 编码的输入参数。

**suggested\_rules** `list[PermissionRule]`

自动生成的权限规则，用户可接受以允许类似的未来调用。

```python theme={null}
from agentscope.event import RequireUserConfirmEvent

async for event in agent.reply_stream(msg):
    if isinstance(event, RequireUserConfirmEvent):
        for tc in event.tool_calls:
            print(f"工具: {tc.name}, 输入: {tc.input}")
            print(f"建议规则: {tc.suggested_rules}")
```

**2. 构建确认结果**

为每个待处理的工具调用创建 `ConfirmResult`，指明是否允许执行。也可以修改工具调用输入或接受建议的权限规则：

```python theme={null}
from agentscope.event import ConfirmResult, UserConfirmResultEvent

confirm_results = []
for tc in event.tool_calls:
    confirm_results.append(ConfirmResult(
        confirmed=True,           # 或 False 表示拒绝
        tool_call=tc,             # 传回（可选择修改）
        rules=tc.suggested_rules, # 接受规则以便未来自动允许
    ))
```

**3. 恢复智能体**

将 `UserConfirmResultEvent` 传回 `reply` 或 `reply_stream`：

```python theme={null}
confirm_event = UserConfirmResultEvent(
    reply_id=event.reply_id,
    confirm_results=confirm_results,
)
result = await agent.reply(confirm_event)
```

* **已确认**的工具调用立即执行，智能体继续推理
* **已拒绝**的工具调用会产生大语言模型可见的错误结果，模型可能会换一种方式重试
* **已接受的规则**会持久化到权限引擎中，匹配的未来调用将自动允许，无需再次提示

## 外部工具执行

当智能体调用 `is_external_tool = True` 的工具时，会发出 `RequireExternalExecutionEvent` 并暂停。工具的逻辑在智能体外部运行，通常由人工操作或外部系统执行。

**1. 接收 RequireExternalExecutionEvent**

事件结构如下：

**reply\_id** `str` *required*

当前回复的 ID，用于恢复智能体。

**tool\_calls** `list[ToolCallBlock]` *required*

需要外部执行的工具调用列表。每个 `ToolCallBlock` 包含：

**id** `str`

此工具调用的唯一标识符。

**name** `str`

外部工具名称。

**input** `str`

JSON 编码的输入参数。

```python theme={null}
from agentscope.event import RequireExternalExecutionEvent

async for event in agent.reply_stream(msg):
    if isinstance(event, RequireExternalExecutionEvent):
        for tc in event.tool_calls:
            print(f"外部执行: {tc.name}({tc.input})")
```

**2. 外部执行并构建结果**

在智能体外部执行操作，并将结果封装为 `ToolResultBlock` 对象：

```python theme={null}
from agentscope.message import ToolResultBlock, TextBlock, ToolResultState
from agentscope.event import ExternalExecutionResultEvent

execution_results = []
for tc in event.tool_calls:
    # 执行实际操作（API 调用、人工操作等）
    output = await run_external_operation(tc.name, tc.input)

    execution_results.append(ToolResultBlock(
        id=tc.id,
        name=tc.name,
        output=[TextBlock(text=output)],
        state=ToolResultState.SUCCESS,
    ))
```

**3. 恢复智能体**

传回 `ExternalExecutionResultEvent` 以恢复智能体：

```python theme={null}
external_event = ExternalExecutionResultEvent(
    reply_id=event.reply_id,
    execution_results=execution_results,
)
result = await agent.reply(external_event)
```

结果会被注入智能体上下文，推理从中断处继续。

### 内置的 AskUser

`AskUser` 是框架内置的外部执行工具，让智能体在需要用户拿主意时把问题摆出来。它一次最多提 4 个问题，每个问题 2 到 4 个选项，用法参见[询问用户](https://docs.agentscope.io/zh/versions/2.0.12dev/building-blocks/tool/python-tool.md#询问用户)。

`RequireExternalExecutionEvent` 中 `tc.input` 的结构如下，界面据此渲染：

| 字段 | 含义 |
| - | - |
| `questions[].question` | 问题正文 |
| `questions[].header` | 不超过 12 个字符的短标签，通常渲染成一个 chip |
| `questions[].context` | 回答时需要对照看的内容（草稿、报错、待比较的两份设计），展示在选项上方 |
| `questions[].multi_select` | 是否允许多选 |
| `questions[].options[].label` / `description` | 选项文字，以及它意味着什么 |
| `questions[].options[].preview` | 单选题可选的并排预览内容，例如代码片段或界面草图 |

界面除了这些选项，还需要提供一个「其他」自由输入项，因为工具已经向用户承诺了这一点。

回传时，`output` 写给模型读，同时要在 `metadata` 里按 `AskUserMetadata` 的结构放同一份答案，供程序按选择分支：

```python 回传 AskUser 的答案 theme={null}
from agentscope.message import ToolResultBlock, TextBlock, ToolResultState
from agentscope.tool import AskUserAnswer, AskUserMetadata

result = ToolResultBlock(
    id=tc.id,
    name=tc.name,
    output=[TextBlock(text="鉴权方式：OAuth 2.0（推荐）")],
    metadata=AskUserMetadata(
        answers=[
            AskUserAnswer(
                question="接入哪种鉴权方式？",
                selected=["OAuth 2.0（推荐）"],  # 用户勾选的选项 label
                other=None,                      # 用户自由输入时填在这里
            ),
        ],
    ).model_dump(),
    state=ToolResultState.SUCCESS,
)
```

> [!NOTE]
>
> 如果多个工具调用都需要外部交互，而只传回了部分确认或执行结果，智能体不会为尚未确认或执行的工具调用重新发出请求事件。

> [!TIP]
>
> 同一批并发的工具调用之间会对确认请求去重：若某次调用已被同批次中更早一次确认所建议的规则覆盖，就不会再次向用户发出确认请求。安全类确认请求不参与这种去重。

> [!TIP]
>
> 构建交互式界面时使用 `reply_stream`：它可以实时检测暂停事件并立即提示用户。以编程方式处理事件的自动化流程则使用 `reply`。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.