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

# 多轮对话

要在同一会话里发多条用户消息，使用 `QoderSDKClient`——它维护长连接，可以根据模型回复决定下一句。一次性、无状态查询用 `query()`，见 [快速开始](/zh/cli/sdk/python/quick-start)。

***

<div id="多消息会话" />

## 多消息会话

每次调用 `client.query(...)` 追加一轮输入，再用 `client.receive_response()` 消费到本轮回复结束：

```python theme={null}
import anyio

from qoder_agent_sdk import (
    AssistantMessage,
    QoderAgentOptions,
    QoderSDKClient,
    ResultMessage,
    TextBlock,
    access_token_from_env,
)


async def main():
    options = QoderAgentOptions(auth=access_token_from_env())

    async with QoderSDKClient(options=options) as client:
        await client.query("What is the capital of France?")
        async for msg in client.receive_response():
            if isinstance(msg, AssistantMessage):
                for block in msg.content:
                    if isinstance(block, TextBlock):
                        print(f"Assistant: {block.text}")

        # Choose the next message based on the previous response.
        await client.query("What is the population of this city?")
        async for msg in client.receive_response():
            if isinstance(msg, ResultMessage):
                print(f"Done: {msg.subtype}")


anyio.run(main)
```

***

<div id="运行中插话" />

## 运行中插话

在消费当前回复时再次调用 `client.query(...)`，即可把新消息发送到同一个长连接会话：

```python theme={null}
await client.query(
    "Stop the current direction and analyze only the failing tests.",
    priority="now",
)
```

`priority` 决定消息何时交给会话：

| 值         | 行为              |
| --------- | --------------- |
| `"now"`   | 停止当前回复，立即处理这条消息 |
| `"next"`  | 默认值；在下一个合适的时机处理 |
| `"later"` | 等当前回复结束后处理      |

相同优先级的消息按发送顺序处理。`priority="now"` 适合立即改变当前方向；如果只想停止当前回复、不发送新消息，应使用 [`client.interrupt()`](#中断当前轮次)。

<div id="写入上下文但不启动新-turn" />

### 添加上下文但不触发回复

`should_query=False` 会把消息加入对话，但不会仅凭这条消息触发回复。消息的处理时机仍由 `priority` 决定。

```python theme={null}
await client.query(
    "All subsequent suggestions must be compatible with Python 3.10.",
    should_query=False,
)
```

***

<div id="中断当前轮次" />

## 中断当前回复

只有 `QoderSDKClient` 提供运行时中断能力，一次性 `query()` 迭代器不提供。调用 `await client.interrupt()` 可以停止当前回复，但不会断开 client，之后仍可继续对话。

```python theme={null}
import asyncio

from qoder_agent_sdk import QoderAgentOptions, QoderSDKClient, qodercli_auth


async def receive_turn(client):
    return [msg async for msg in client.receive_response()]


async def main():
    options = QoderAgentOptions(auth=qodercli_auth())
    async with QoderSDKClient(options=options) as client:
        await client.query("Inspect all files in the repository.")
        response_task = asyncio.create_task(receive_turn(client))

        await asyncio.sleep(5)
        await client.interrupt()
        await response_task


asyncio.run(main())
```

`interrupt()` 不会清空后续消息队列或断开 client，之后仍可发送下一轮输入。

<div id="取消排队消息" />

### 取消排队消息

给需要跟踪的消息设置会话内唯一的 `message_uuid`，再使用 `client.cancel_async_message(message_uuid)` 取消尚未开始执行的消息：

```python theme={null}
await client.query(
    "Create a migration checklist after the current task is complete.",
    priority="later",
    message_uuid="optional-follow-up",
)

cancelled = await client.cancel_async_message("optional-follow-up")
```

取消成功返回 `True`；消息不存在或已无法取消时返回 `False`。未设置 UUID 的消息无法通过该方法取消。不要在同一会话内复用 UUID。

***

<div id="管理会话生命周期" />

## 管理会话生命周期

`QoderSDKClient` 的连接生命周期由调用方掌握。两种管理方式：

<div id="自动管理推荐" />

### 自动管理（推荐）

适合会话生命周期跟某个函数 / 代码块绑定的场景：

```python theme={null}
async with QoderSDKClient(options=options) as client:
    await client.query("Hello")
    async for msg in client.receive_response():
        ...
# The connection closes automatically when the async with block exits.
```

<div id="手动管理" />

### 手动管理

适合 client 被长生命周期对象持有、或需要从外部条件（超时、用户取消等）触发关闭的场景：

```python theme={null}
client = QoderSDKClient(options=options)
await client.connect()

try:
    await client.query("Hello")
    async for msg in client.receive_response():
        ...
finally:
    await client.disconnect()
```
