# 频道

> 通过频道，你可以从 Telegram、微信、QQ、钉钉、企业微信或飞书等消息平台与 Qwen Code agent 进行交互，而无需使用终端。你可以从手机或桌面聊天应用发送消息，agent 的响应方式与在 CLI 中完全一致。

- 网址：https://funcoding.ai/agents/qwen-code/users/features/channels/overview/
- 来源：Qwen Code 官方文档原文（中文），Apache-2.0 许可，同步于 2026-10-11
- 官方原文：https://qwenlm.github.io/qwen-code-docs/zh/users/features/channels/overview

---
通过频道，你可以从 Telegram、微信、QQ、钉钉、企业微信或飞书等消息平台与 Qwen Code agent 进行交互，而无需使用终端。你可以从手机或桌面聊天应用发送消息，agent 的响应方式与在 CLI 中完全一致。

代码托管平台（目前支持 [GitHub](https://funcoding.ai/agents/qwen-code/users/features/channels/github/)）和经过认证的工作区账户（目前支持 [钉钉工作区](https://funcoding.ai/agents/qwen-code/users/features/channels/dws/)）也通过频道提供支持。

## 工作原理

运行 `qwen channel start` 时，Qwen Code 会：

1. 从 `settings.json` 读取频道配置
2. 使用 [Agent Client Protocol (ACP)](https://funcoding.ai/agents/qwen-code/developers/architecture/) 生成单个 agent 进程
3. 连接到各个消息平台并开始监听消息
4. 将接收到的消息路由给 agent，并将响应发送回对应的聊天

所有频道共享一个 agent 进程，但每个用户的会话是隔离的。每个频道可以拥有自己的工作目录、模型和指令。

## 快速开始

1. 设置机器人或经过认证的工作区账户（请参阅各频道专属指南：[Telegram](https://funcoding.ai/agents/qwen-code/users/features/channels/telegram/)、[微信](https://funcoding.ai/agents/qwen-code/users/features/channels/weixin/)、[QQ Bot](https://funcoding.ai/agents/qwen-code/users/features/channels/qqbot/)、[钉钉](https://funcoding.ai/agents/qwen-code/users/features/channels/dingtalk/)、[钉钉工作区](https://funcoding.ai/agents/qwen-code/users/features/channels/dws/)、[企业微信](https://funcoding.ai/agents/qwen-code/users/features/channels/wecom/)、[飞书](https://funcoding.ai/agents/qwen-code/users/features/channels/feishu/)、[GitHub](https://funcoding.ai/agents/qwen-code/users/features/channels/github/)）
2. 将频道配置添加到 `~/.qwen/settings.json`
3. 运行 `qwen channel start` 启动所有频道，或运行 `qwen channel start <name>` 启动单个频道

想接入未内置的平台？请参阅 [插件](https://funcoding.ai/agents/qwen-code/users/features/channels/plugins/)，将自定义适配器作为扩展添加。

## 配置

频道在 `settings.json` 的 `channels` 键下进行配置。每个频道都有一个名称和一组选项：

```json
{
  "channels": {
    "my-channel": {
      "type": "telegram",
      "token": "$MY_BOT_TOKEN",
      "senderPolicy": "allowlist",
      "allowedUsers": ["123456789"],
      "sessionScope": "user",
      "cwd": "/path/to/working/directory",
      "instructions": "Optional system instructions for the agent.",
      "groupPolicy": "disabled",
      "dmPolicy": "open",
      "groups": {
        "*": { "requireMention": true }
      }
    }
  }
}
```

### 选项

| 选项                     | 是否必需         | 描述                                                                                                                                                             |
| ------------------------ | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`                   | 是               | 频道类型：`telegram`、`weixin`、`qq`、`dingtalk`、`dws`、`wecom`、`feishu`、`github`、`gitlab` 或来自扩展的自定义类型（参见 [插件](https://funcoding.ai/agents/qwen-code/users/features/channels/plugins/)）                       |
| `token`                  | Telegram         | 机器人 Token。支持 `$ENV_VAR` 语法从环境变量读取。微信、钉钉、企业微信或飞书不需要此项                                                                             |
| `clientId`               | 钉钉, 飞书       | 钉钉 AppKey 或飞书 App ID。支持 `$ENV_VAR` 语法                                                                                                                  |
| `clientSecret`           | 钉钉, 飞书       | 钉钉 AppSecret 或飞书 App Secret。支持 `$ENV_VAR` 语法                                                                                                           |
| `botId`                  | 企业微信         | 企业微信智能机器人 Bot ID。支持 `$ENV_VAR` 语法。参见 [企业微信](https://funcoding.ai/agents/qwen-code/users/features/channels/wecom/)                                                                                          |
| `secret`                 | 企业微信         | 企业微信智能机器人 Secret。支持 `$ENV_VAR` 语法。参见 [企业微信](https://funcoding.ai/agents/qwen-code/users/features/channels/wecom/)                                                                                          |
| `model`                  | 否               | 此频道使用的模型（例如 `qwen3.5-plus`）。覆盖默认模型。适用于支持图像输入的多模态模型                                                                            |
| `senderPolicy`           | 否               | 允许与机器人交互的用户：`allowlist`（默认）、`open` 或 `pairing`                                                                                                 |
| `allowedUsers`           | 否               | 允许使用机器人的用户 ID 列表（由 `allowlist` 和 `pairing` 策略使用）                                                                                             |
| `sessionScope`           | 否               | 会话作用域：`user`（默认）、`chat_thread` 或 `single`。旧版 `thread` 在已配置时仍兼容，但不再为新的 Web Shell 配置提供                                                  |
| `multiSession`           | 否               | 在一个聊天中保留最多八个按所有者作用域的命名任务。需要守护进程管理模式、`sessionScope: "user"`，不使用 webhook 或群聊历史回填，且未启用频道循环                    |
| `messagePrefix`          | 否               | 仅分发以任何前导 `@提及` 之后以此精确大小写敏感前缀开头的用户消息；前缀及其后的空白会在分发前被移除                                                                                   |
| `cwd`                    | 否               | agent 的工作目录。默认为当前目录                                                                                                                                 |
| `approvalMode`           | 否               | 频道会话的工具审批模式。无人值守的 webhook 任务需要 `yolo`；该设置应用于频道上的每个会话                                                                          |
| `instructions`           | 否               | 自定义指令，会追加到每个会话的第一条消息之前                                                                                                                     |
| `webhooks`               | 否               | 守护进程管理频道的 webhook 来源和投递目标。参见 [Webhook 触发的任务](#webhook-triggered-tasks)                                                                  |
| `groupPolicy`            | 否               | 群聊访问权限：`disabled`（默认）、`allowlist`、`pairing` 或 `open`。参见 [群聊](#group-chats)                                                                     |
| `dmPolicy`               | 否               | 私聊/DM 访问权限：`open`（默认）或 `disabled`（静默丢弃所有私聊）。适用于仅限群聊的机器人                                                                         |
| `groupHistoryLimit`      | 否               | 可选的群聊历史回填。`0` 或省略则禁用。正整数表示在下次机器人被 @提及/回复时，持久化保存该数量的来自已授权发送者或已批准配对群组成员的未被提及群消息。              |
| `groups`                 | 否               | 每个群组的设置。键为群聊 ID 或 `"*"`（表示默认设置）。参见 [群聊](#group-chats)                                                                                  |
| `dispatchMode`           | 否               | 当机器人繁忙时发送消息的处理方式：`steer`（默认）、`collect` 或 `followup`。参见 [调度模式](#dispatch-modes)                                                       |

设置 `messagePrefix` 后，每条用户撰写的消息都必须以前缀和非空内容开头，例如 `/review inspect #123`。只有前缀和其前方的提及会被移除；用户在前缀之后输入的提及会原样到达 agent。共享命令和 agent 命令使用相同的规则（`/review /help`、`/review /clear` 等）。Telegram 注册的命令菜单操作仍然无需前缀即可使用——除非配置的前缀本身就是其中之一，此时前缀优先，该命令也必须带前缀发送（`/new /new`）。附件在平台支持时需要匹配的说明文字；无说明文字的 Telegram、飞书、微信、钉钉和企业微信媒体消息仍会继续运行，其占位文本不会作为群聊历史被引用回来。原生 todo、webhook 以及提供者生成的任务分配或评审请求事件也无需前缀即可运行，因为它们是系统事件而非聊天消息。

有两个行为是刻意设计的，在启用前缀之前值得了解。钉钉或企业微信自动填入转录文本的语音消息被视为用户口述的文本，因此它必须像其他消息一样携带前缀，否则会被丢弃——只有未转录的语音笔记才会作为无说明文字媒体运行。而且前缀在配对之前检查，因此来自未知发送者或未批准群组的首次联系也必须携带前缀；如果不按此顺序，繁忙群组中每条未带前缀的消息都会触发配对回复，而这正是前缀要消除的噪音。请通过其他渠道告知新用户前缀，或者保持配对频道不使用前缀。

### 发送者策略

控制谁可以与机器人交互：

- **`allowlist`**（默认）— 只有在 `allowedUsers` 中列出的用户才能发送消息。其他用户会被静默忽略。
- **`pairing`** — 未知发送者会收到一个配对码。机器人管理员通过 CLI 批准他们，并将其添加到持久化白名单中。`allowedUsers` 中的用户会完全跳过配对。参见下方的 [私聊配对](#dm-pairing)。
- **`open`** — 任何人都可以发送消息。请谨慎使用。

### 会话作用域

控制会话的管理方式：

- **`user`**（默认）— 每个用户一个会话。同一用户的所有消息共享一个对话。
- **`chat_thread`** — 每个聊天话题/线程一个会话，由该话题中的参与者共享。
- **`thread`** — 为保留现有配置而保留的旧版话题/线程路由。
- **`single`** — 所有用户共享一个会话。所有人共享同一个对话。

### 命名任务

守护进程管理的频道可以在同一个聊天中为同一用户保留多个命名对话：

```json
{
  "channels": {
    "my-channel": {
      "type": "telegram",
      "sessionScope": "user",
      "multiSession": true
    }
  }
}
```

目录严格私有于对应的频道、聊天和发送者。任务名使用 1–32 个 ASCII 字母、数字、下划线或连字符，不区分大小写且必须唯一。最多可同时打开八个任务；关闭任务会将其分离但不会删除其对话记录，因此后续选择该任务会重新打开完全相同的对话。会话 ID 不会被聊天命令接受，也不会在聊天命令中显示。

命名结果会标识其来源任务：私聊使用 `[task]`，而群聊使用 `[sender · task]`。命名文本权限提示还会显示确切的请求 ID 以及对应的 `/approve <id>`、`/approve-always <id>` 和 `/deny <id>` 命令。该标签仅用于展示，不会存储在模型对话记录中。

一个任务保持选中状态以接收下一条普通消息，但其他命名任务可能继续并发运行。`/session new <name>` 共享配置的工作区，而 `/session new <name> --worktree` 在守护进程工作区的 `.qwen/worktrees/` 目录下为该任务创建一个隔离的检出。守护进程在重启后重新打开任务之前会验证持久化的 worktree 所有者；缺失、变更或外来所有权的记录会 fail closed（失败即拒绝），而不是静默地将任务移入共享工作区。创建或选择另一个任务不会取消或重新定向早期的工作，延迟的结果保留其来源任务标签。繁忙的任务无法关闭，但其活跃提示可以通过现有的频道取消行为使用 `/session cancel [<name>]` 取消。独立排队的轮次不会被取消，但在 `collect` 调度模式下，缓冲在被取消提示之后的后续消息会被该现有行为丢弃。媒体准备不会被定向。裸权限命令仅适用于选中的任务，而明确的请求 ID 可以响应所属的非活动任务。`/clear`、`/new` 和 `/reset` 也适用于选中的 worktree 任务：任务获得新的对话，同时保留其 worktree 和文件。繁忙的 worktree 任务在提示完成前会拒绝重置，worktree 记录损坏的任务会报告失败而不会触碰文件。频道记忆仍然作用于聊天而非命名任务。

此模式在独立 `qwen channel start`、使用 webhook、频道或群组的 `groupHistoryLimit` 非零，或启用频道循环时不可用。如果该频道已存在启用的循环，守护进程 worker 将拒绝启动，直到循环被禁用。

### 频道记忆

频道记忆为某个聊天或话题存储持久上下文。每条记忆都有稳定的 ID，因此列表响应可用于确定性的后续操作。

- `记住：默认使用 staging 环境` 是确定性形式，为当前聊天或话题恰好保存一条标量记忆。
- 要在一个请求中保存多条独立的事实，请使用通过分类器路由的自然语言短语。例如：`请记住这三条约定：使用 staging；发布前测试；优先中文回复` 会创建可独立管理的记忆。完全重复的事实会被跳过并报告，不会创建重复条目。包含类似凭证文本的请求会被拒绝；请移除敏感信息后单独保存非敏感事实。
- `查看记忆` 列出记忆及其稳定 ID。使用 `查看第 2 页记忆` 查看后续页面，`查看记忆 <id>` 查看单条记忆，或使用自然过滤请求如 `只看中文偏好` 列出匹配的记忆。
- `查看刚才那条记忆`、`把关于 staging 的记忆改成默认使用 production` 和 `忘掉刚才那条` 在自然引用恰好解析为一条记忆时生效。自然更新和移除操作会先显示拟议的变更。在 60 秒内使用 `确认更新记忆` 或 `confirm memory update` 确认更新，或使用 `确认删除记忆` 或 `confirm memory removal` 确认移除。精确 ID 的更新和移除仍然是即时的，无需确认。
- `清空记忆` 启动全部清除确认流程；`确认清空记忆` 完成清除。

当自然的查看、更新或移除请求匹配多条记忆时，机器人会返回候选 ID 和预览，而不会修改记忆。模糊结果没有待定的选择：请使用一个精确 ID 重试请求，例如 `忘掉 m-a31f0d82c7e4`。精确 ID 操作仍然是确定性的快速路径。没有匹配的自然请求会报告未找到匹配的记忆。

待定的更新、移除和清除确认仅适用于创建它们的发送者以及对应的聊天或话题。较新的清除、自然更新或自然移除提议会替换同一发送者和目标的较旧待定操作。待定确认在频道进程重启时会被丢弃。

旧版斜杠命令别名 `/remember-channel`、`/channel-memory` 和 `/forget-channel` 已被移除。它们不再是频道记忆命令。

频道记忆遵循频道访问门控。任何被 `senderPolicy`、`dmPolicy`、`groupPolicy`、群组设置、配对和 @提及要求接受的消息都可以读取、写入、更新或清除该聊天或话题的记忆。同一群组的已接受成员共享该群组的目标存储。当群组记忆应限于受信任的发送者时，请使用 `allowlist` 或 `pairing` 策略。

旧版 `CHANNEL.md` 记忆会在首次变更时自动迁移到结构化的 `CHANNEL.json` 存储。结构化记忆在独立频道和守护进程管理频道的重启间持久化，并在新目标作用域会话启动时（包括 `/clear` 之后）注入。

在初始注入之后，每条被接受的消息还会召回最多三条与该消息相关的记忆。这使持久事实在长时间运行的会话中保持可用，而无需将每条存储的记忆添加到每个轮次。召回基于当前消息，不会修改存储的记忆。

记忆仍然以当前聊天或话题为键。它不会在 `sessionScope: single` 会话中注入或召回，因为该会话在整个频道间共享，而非作用于单个目标。

频道记忆不会自动从普通对话中学习事实，也不会接受 `第一个` 作为模糊自然引用的确认。当自然引用模糊时，请使用清晰的记忆请求和精确的记忆 ID。

### Token 安全

机器人 Token 不应直接存储在 `settings.json` 中。请使用环境变量引用：

```json
{
  "token": "$TELEGRAM_BOT_TOKEN"
}
```

在 shell 环境或 `.env` 文件中设置实际的 Token，并确保在运行频道前加载该文件。

## 私聊配对

当 `senderPolicy` 设置为 `"pairing"` 时，未知发送者会经过以下审批流程：

1. 未知用户向机器人发送消息
2. 机器人回复一个 8 位字符的配对码（例如 `VEQDDWXJ`）
3. 用户将配对码分享给你（机器人管理员）
4. 你通过 CLI 批准该用户：

```bash
qwen channel pairing approve my-channel VEQDDWXJ
```

批准后，用户的 ID 会保存到频道的按工作区作用域的白名单（`~/.qwen/channels/<workspace-scope>/<name>-allowlist.json`），后续所有消息均可正常通过。配对状态按工作区作用域管理，因此两个使用相同频道名称的工作区会维护各自独立的批准记录。

### 配对 CLI 命令

```bash
# 列出待处理的配对请求
qwen channel pairing list my-channel

# 通过配对码批准请求
qwen channel pairing approve my-channel <CODE>
```

从频道的工作区目录运行这些命令（或传递 `--cwd <dir>`）—— 配对状态按工作区存储。

### 配对规则

- 配对码为 8 个大写字符，使用无歧义的字母表（不包含 `0`/`O`/`1`/`I`）
- 配对码 1 小时后过期
- 每个频道同时最多 3 个待处理请求，每个发送者最多 1 个 — 额外的请求会被拒绝，直到有请求过期或被批准
- `settings.json` 中 `allowedUsers` 列出的用户会跳过用户配对；在 `groupPolicy: "pairing"` 下，群组本身仍需被批准
- 已批准的用户按工作区存储在 `~/.qwen/channels/<workspace-scope>/<name>-allowlist.json` 中 — 请将此文件视为敏感文件

## 群聊

默认情况下，机器人仅在私聊中工作。要启用群聊支持，请将 `groupPolicy` 设置为 `"allowlist"`、`"pairing"` 或 `"open"`。

### 群聊策略

控制机器人是否参与群聊：

- **`disabled`**（默认）— 机器人忽略所有群消息。最安全的选项。
- **`allowlist`** — 机器人仅在 `groups` 中通过群聊 ID 明确列出的群组中响应。`"*"` 键提供默认设置，但**不**作为通配符允许所有群组。
- **`pairing`** — 来自未知群组的有意 @提及或回复会为该群组创建一个配对请求。批准后，该群组中的每个成员都可以在该群组中使用机器人；`senderPolicy` 继续控制私聊。
- **`open`** — 机器人在其加入的所有群组中响应。请谨慎使用。

使用与用户配对相同的 CLI 命令批准群组。待处理请求会标识群组和发起它的成员：

```bash
qwen channel pairing approve my-channel <CODE>
```

群组批准按群组的聊天 ID 存储在频道的工作区作用域中。在 GitHub 和 GitLab 上，聊天 ID 是仓库/项目路径，因此重命名或转移会分离存储的批准 — 重命名后请重新批准群组。在同一路径下重新创建的仓库或项目会继承任何过期的批准 — 在任何重命名、转移或删除后撤销群组批准。
未被提及的消息永远不会创建群组配对请求，即使群组将 `requireMention` 设置为 `false`；批准后，配置的 @提及策略会正常应用。

群组配对请求与私聊配对请求共享同一个待处理队列：一个频道最多持有 3 个待处理请求，一个发送者在用户和群组请求中最多持有 1 个待处理请求（参见[配对规则](#pairing-rules)）。

### @提及触发

在群聊中，机器人默认需要被 `@提及` 或回复其某条消息才会响应。这可以防止机器人对群聊中的每条消息都进行回复。

使用 `groups` 设置按群组进行配置：

```json
{
  "groups": {
    "*": { "requireMention": true },
    "-100123456": { "requireMention": false }
  }
}
```

- **`"*"`** — 所有群组的默认设置。仅设置配置默认值，并非白名单条目。
- **群聊 ID** — 覆盖特定群组的设置。覆盖 `"*"` 的默认值。
- **`requireMention`**（默认：`true`）— 为 `true` 时，机器人仅响应 `@提及` 它或回复其消息的内容。为 `false` 时，机器人响应所有消息（适用于专属任务群）。

### 群聊历史回填

默认情况下，Qwen 会忽略未被提及的群消息，且不将其存储为会话轮次。要让下一次 `@提及` 包含最近的群聊上下文，请将 `groupHistoryLimit` 设置为正整数。

```json
{
  "channels": {
    "my-dingtalk": {
      "type": "dingtalk",
      "clientId": "$DINGTALK_CLIENT_ID",
      "clientSecret": "$DINGTALK_CLIENT_SECRET",
      "groupPolicy": "open",
      "groupHistoryLimit": 50,
      "groups": {
        "*": { "requireMention": true },
        "sensitive-group-id": {
          "requireMention": true,
          "groupHistoryLimit": 0
        }
      }
    }
  }
}
```

- 省略或设置为 `0` 将禁用回填。
- 群组级别的 `groupHistoryLimit` 会覆盖频道级别的值。
- 仅持久化来自已授权发送者或已批准配对群组成员的消息。
- 被 `groupPolicy` 或群组白名单拒绝的消息不会被持久化。
- 待处理的群聊历史以本地 JSONL 格式存储在 `~/.qwen/channels/<channel-name>-group-history.jsonl` 或 `$QWEN_HOME/channels/<channel-name>-group-history.jsonl` 中。
- 缓存的消息会在下次实际触发时作为不受信任的上下文注入，且不会作为独立的会话轮次写入。

### 群聊消息评估流程

```
1. groupPolicy — 此群组是 disabled、listed、paired 还是 open？ (否 → 忽略/配对流程)
2. dmPolicy — 是否允许此私聊？                      (disabled → 忽略)
3. requireMention — 机器人是否被 @提及/回复？         (否 → 忽略)
4. senderPolicy — 此发送者是否已获批准？             (已配对群组跳过；否则否 → 用户配对流程)
5. 路由到会话
```

### Telegram 群聊设置

1. 将机器人添加到群组
2. 在 BotFather 中**禁用隐私模式**（`/mybots` → Bot Settings → Group Privacy → Turn Off）— 否则机器人将无法看到非命令消息
3. 更改隐私模式后，**将机器人移出并重新添加**到群组（Telegram 会缓存此设置）

### 查找群聊 ID

要为 `groups` 白名单查找群聊 ID：

1. 如果机器人正在运行，请先停止它
2. 在群聊中发送一条提及该机器人的消息
3. 使用 Telegram Bot API 检查排队的更新：

```bash
curl -s "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/getUpdates" | python3 -m json.tool
```

在响应中查找 `message.chat.id` —— 群聊 ID 是负数（例如 `-5170296765`）。

## 媒体支持

频道支持向 agent 发送图片和文件，不仅限于文本。

### 图片

向机器人发送照片，agent 即可看到它 —— 这对于分享截图、错误信息或图表非常有用。图片会作为视觉输入直接发送给模型。

要使用图片支持，请为频道配置多模态模型：

```json
{
  "channels": {
    "my-channel": {
      "type": "telegram",
      "model": "qwen3.5-plus",
      ...
    }
  }
}
```

### 文件

向机器人发送文档（PDF、代码文件、文本文件等）。文件会被下载并保存到临时目录，同时会将文件路径告知 agent，以便其使用文件读取工具读取内容。

文件功能适用于任何模型 —— 无需多模态支持。

### 平台差异

| 功能  | Telegram                                     | 微信                           | 钉钉                                      | 飞书                                                      |
| -------- | -------------------------------------------- | -------------------------------- | --------------------------------------------- | ----------------------------------------------------------- |
| 图片   | 通过 Bot API 直接下载                  | 通过 CDN 下载并进行 AES 解密 | downloadCode API（两步）                   | Open API 资源端点（需鉴权的 GET 请求，50MB 限制） |
| 文件    | 通过 Bot API 直接下载（20MB 限制）     | 通过 CDN 下载并进行 AES 解密 | downloadCode API（两步）                   | Open API 资源端点（50MB 限制）                    |
| 说明文字 | 图片/文件的说明文字作为消息文本包含在内 | 不适用                   | 富文本：单条消息中混合文本和图片 | 富文本（`post`）：提取文本；忽略嵌入的图片 |

> QQ Bot 不处理传入的媒体 —— 图片和贴纸消息会被忽略，因此上表中没有其媒体处理的相关行。
>
> 企业微信支持文本、图片、文本混合图片、文件、视频和语音消息（转写后传入）。图片作为附件传递给 agent；文件和视频下载到临时本地路径。详见 [企业微信](https://funcoding.ai/agents/qwen-code/users/features/channels/wecom/#images-and-files)。

## 调度模式

控制在机器人仍在处理上一条消息时，发送新消息会发生什么。

- **`steer`**（默认） —— 机器人取消当前请求并开始处理你的新消息。最适合普通聊天，因为后续消息通常意味着你想纠正或重新引导机器人。
- **`collect`** —— 你的新消息会被缓冲。当前请求完成后，所有缓冲的消息会合并为一条后续提示。适合异步工作流，方便你排队输入想法。
- **`followup`** —— 每条消息按顺序排队，并作为独立的轮次进行处理。适用于批量工作流，其中每条消息都是独立的。

```json
{
  "channels": {
    "my-channel": {
      "type": "telegram",
      "dispatchMode": "steer",
      ...
    }
  }
}
```

你还可以为每个群组单独设置调度模式，从而覆盖频道的默认设置：

```json
{
  "groups": {
    "*": { "requireMention": true, "dispatchMode": "steer" },
    "-100123456": { "dispatchMode": "collect" }
  }
}
```

## 响应投递

频道使用正常的响应投递路径。共享的投递层发送已完成的响应，适配器可以提供原生的渐进式显示，例如就地更新交互卡片。平台消息长度限制仍可能会拆分长响应。

已退役的 `blockStreaming`、`blockStreamingChunk` 和 `blockStreamingCoalesce` 设置不再受支持，可以从频道配置中移除。它们不会影响投递。频道设置管理会拒绝为这些字段新添加或更改的值。未更改的存储值在编辑保留频道的 `type` 时会被保留或移除；更改频道的 `type` 需要先移除这些字段。

## 定时频道循环

频道内置持久化调度器，用于延迟执行提示并将结果推送回创建它的同一聊天。你可以用自然语言向 agent 提出请求，例如 `每 15 分钟检查一次部署情况并报告任何变化`，也可以直接使用本地命令：

```text
/loop add "*/15 * * * *" check the deployment and report any change
/loop list
/loop inspect <id>
/loop cancel <id>
```

当 agent 为你管理这些任务时，会使用 `channel_loop_create`、`channel_loop_list` 和 `channel_loop_cancel` 工具。调度使用标准的五字段 cron 表达式，基于机器的本地时间。任务在无人值守的情况下运行，最终响应会自动投递到创建它的聊天中。

频道循环与 [定时运行提示](https://funcoding.ai/agents/qwen-code/users/features/scheduled-tasks/) 中描述的会话作用域任务不同：

- 它们存储在 `$QWEN_HOME/channels/` 下 —— 独立频道直接使用 `cron.json`，而守护进程管理的频道使用 `daemon/` 下的按工作区文件。两者在频道重启后仍然保留。
- 它们作用于当前频道聊天或话题。每个目标最多可以有 10 个启用的循环，每条提示限制为 4,000 个字符。
- 它们需要支持主动投递的适配器和目标。Telegram、钉钉、飞书和企业微信已选择加入，但受各平台特定的目标限制约束。
- 在 `sessionScope: "single"` 下不可用，因为该作用域不绑定到单个聊天目标。
- 如果目标的授权在循环到期时已被撤销，则已保存的循环会被禁用。

## 后台子代理结果

当 agent 将工作委派给后台子代理或 fork 时，完成结果会投递回拥有该会话的频道聊天。投递可能在原始轮次结束后发生，因此在后台工作活跃期间请保持频道服务或守护进程运行。

## 斜杠命令

频道支持斜杠命令。这些命令在本地处理（无需 agent 往返）：

- `/help` —— 列出可用命令
- `/clear` —— 清除当前会话并重新开始（别名：`/reset`、`/new`）
- `/status` —— 显示会话信息和访问策略
- `/btw <question>` —— 提出一个侧面问题而不中断当前任务；纯文本问题，最多 4096 个字符，需要支持侧面问题的 agent 连接
- `/sessions [all]` —— 列出打开的命名任务，或包含已关闭的任务；仅在 `multiSession: true` 时可用
- `/session current` —— 显示选定的命名任务
- `/session new <name>` —— 创建并选择共享工作区任务
- `/session new <name> --worktree` —— 创建并选择位于其自身 Git worktree 中的任务；仅限守护进程管理的命名任务模式
- `/session use <name>` —— 选择打开的任务或重新打开已关闭的任务
- `/session cancel [<name>]` —— 取消选中任务的活跃提示，或指定另一个所属任务；独立排队的轮次不会被取消，但 `collect` 模式下缓冲在被取消提示之后的后续消息会被现有取消行为丢弃；媒体准备不会被定向
- `/session close <name>` —— 关闭任务但不删除其对话记录
- `/loop add "<cron>" <prompt>` —— 创建持久化的定时频道循环
- `/loop list` —— 列出当前聊天的循环
- `/loop inspect <id>` —— 显示循环状态和运行详情
- `/loop cancel <id>` —— 禁用循环

所有其他斜杠命令（例如 `/compress`、`/summary`）都会转发给 agent。命名任务命令仅在启用该模式时注册，因此 `/sessions` 对现有配置仍保持 agent 可见。

命名任务命令适用于所有频道类型（Telegram、微信、QQ、钉钉、企业微信、飞书、GitHub）。`/cancel` 目前仅由 Telegram 注册，循环创建需要当前适配器和目标支持主动投递。

## 运行

```bash
# 启动所有已配置的频道（共享 agent 进程）
qwen channel start

# 启动单个频道
qwen channel start my-channel

# 检查服务是否正在运行
qwen channel status

# 停止运行中的服务
qwen channel stop
```

机器人在前台运行。按 `Ctrl+C` 停止，或在另一个终端中使用 `qwen channel stop`。

### 实验性守护进程管理模式

你也可以在 `qwen serve` 下运行已配置的频道：

```bash
# 在守护进程生命周期下启动一个频道
qwen serve --channel my-channel

# 启动所有已配置的频道
qwen serve --channel all

# 或在受 token 保护的守护进程上稍后启用频道
QWEN_SERVER_TOKEN=secret qwen serve
qwen channel set my-channel --token secret

# 查询或停止守护进程管理的频道
qwen channel status --daemon-url http://127.0.0.1:4170 --token secret
qwen channel stop --daemon-url http://127.0.0.1:4170 --token secret
```

此模式启动由 `qwen serve` 管理的按工作区分组的 channel worker 进程。worker 通过 SDK 连接回守护进程，并使用相同的频道适配器。它们与守护进程进程分离，因此频道适配器崩溃不会导致守护进程崩溃。显式的 `--channel` 选择具有最高优先级，若无法就绪则会导致守护进程启动失败。无标志启动时，会恢复 trusted 主工作区的 `serve.channels` 设置。次级工作区不会独立恢复自身的 `serve.channels`。在两者均无来源的情况下，守护进程不会加载频道适配器，也不会预留租约，直到第一次执行 `qwen channel set`。

自动恢复会跳过无效的启动设置，以及 worker 启动前发生的验证或租约失败，同时保留不相关的设置。worker 启动失败后，守护进程仅在清理成功后才继续运行。全局运行时启动超时或未确认的 worker 停止仍遵循正常的启动失败路径；worker 终止未确认期间，服务租约继续保持。当频道未能恢复时，请检查守护进程日志中关于 `serve.channels` 的消息。

存储的启动名称必须非空、不含前后空白，且不含不安全的控制字符或不可见字符。无效条目会按数组索引逐条跳过并记录。启动过程不会重命名实例，也不会重写配置。频道启动开关反映已保存的设置；运行时状态显示频道是否正在运行。

`qwen serve --channel` 与 `qwen channel start` 不是同一个服务。独立的 `qwen channel start` 仍然使用 ACP 支持的频道服务，并且可以运行具有不同 `cwd` 值的频道配置。守护进程管理的频道要求每个所选频道的 `cwd` 都解析到守护进程注册的工作区。在多工作区模式下，选择替换会保留工作区有序频道列表未变化的 worker；`all` 仍然仅限于主工作区。

不带 `--daemon-url` 时，`qwen channel status` 和 `qwen channel stop` 保留独立的 pidfile 行为。它们的 `--daemon-url` 变体用于查询或停止守护进程管理器。运行时选择不会写入设置，也不会在守护进程重启后保留。如果就绪的 worker 意外退出，守护进程会继续运行，并在 `/daemon/status` 中报告频道 worker 警告。

## Webhook 触发的任务

守护进程管理的频道还可以接受经过鉴权的 webhook 事件。Qwen 接收事件作为上下文，进行摘要并决定哪些内容重要，然后将最终响应投递到配置的聊天目标。这不是原始通知中继。
Webhook 任务需要 `approvalMode: "yolo"`，因为它们在没有交互式审批的情况下运行。该设置应用于整个频道，而不仅仅是 webhook 轮次，因此请使用专用的 webhook 频道，或严格限制该频道的普通聊天发送者。

频道配置示例：

```json
{
  "channels": {
    "dingtalk-main": {
      "type": "dingtalk",
      "clientId": "$DINGTALK_CLIENT_ID",
      "clientSecret": "$DINGTALK_CLIENT_SECRET",
      "cwd": "/repo",
      "senderPolicy": "allowlist",
      "allowedUsers": ["12345"],
      "approvalMode": "yolo",
      "sessionScope": "user",
      "webhooks": {
        "sources": {
          "github-ci": {
            "secretEnv": "QWEN_CHANNEL_GITHUB_CI_SECRET",
            "targets": {
              "operator": {
                "chatId": "DINGTALK_USER_ID",
                "senderId": "webhook:github-ci",
                "isGroup": false
              },
              "team": {
                "chatId": "OPEN_CONVERSATION_ID",
                "senderId": "webhook:github-ci",
                "isGroup": true
              }
            }
          }
        }
      }
    }
  }
}
```

对于钉钉，请在每个目标上明确设置 `isGroup`。私聊目标使用钉钉用户 ID 作为 `chatId`，并设置 `isGroup: false`；群聊目标使用群组 `openConversationId`，并设置 `isGroup: true`。其他适配器可能需要各自的主动投递目标格式。

守护进程管理的钉钉、飞书、Telegram 和企业微信频道会从已授权的入站消息中动态观察联系人。列出在默认七天新鲜度窗口内主工作区中观察到的联系人：

```bash
curl -H "Authorization: Bearer $QWEN_SERVER_TOKEN" \
  http://127.0.0.1:4170/workspace/channel/observed-contacts
```

使用 `GET /workspaces/:workspace/channel/observed-contacts` 选择另一个已注册的受信任工作区。添加 `?freshWithinSeconds=N` 可选择从一秒到 365 天的窗口。守护进程通过 `workspace_channel_observed_contacts` 能力通告此 API。

响应返回完整的平台 ID 和标签。群组标签使用已接受的入站消息中已有的名称（如果可用）：钉钉提供 `conversationTitle`，Telegram 提供 `chat.title`。飞书和企业微信的群组标签目前回退到完整 ID；不查询平台目录或群组详情 API。话题标签也回退到完整 ID。每个 `lastObservedAt` 是规范的 ISO 8601 UTC 时间戳，精确到毫秒；客户端可以将其转换为用户的本地时区进行显示。顶层 `users` 包含在私聊中观察到的用户。`groups` 包含观察到的群聊，`groups[].users` 包含在每个群组中观察到的用户，`groups[].topics[].users` 包含在飞书或 Telegram 话题中观察到的用户：

```json
{
  "users": [
    {
      "channelName": "feishu-main",
      "label": "Example User",
      "id": "ou_complete_user_id",
      "lastObservedAt": "2026-07-17T08:00:00.000Z"
    }
  ],
  "groups": [
    {
      "channelName": "feishu-main",
      "label": "oc_complete_chat_id",
      "id": "oc_complete_chat_id",
      "lastObservedAt": "2026-07-17T08:05:00.000Z",
      "users": [
        {
          "label": "Example User",
          "id": "ou_complete_user_id",
          "lastObservedAt": "2026-07-17T08:05:00.000Z"
        }
      ],
      "topics": []
    }
  ]
}
```

这些嵌套用户是被观察到的参与者，而非权威的群组成员关系。只有通过了私聊/群组、@提及、发送者和配对门控的消息才会被记录。重复观察会刷新标签和时间戳；被动观察无法检测退出或删除，直到关系变得过时。消息内容永远不会被存储。有界的注册表存储在 `$QWEN_HOME/channels/daemon/<workspaceHash>/observed-contacts.json` 中，位于工作区检出之外，并按工作区隔离。其 500 条观察限制由该工作区中的所有频道和对话共享，超过 365 天的观察会在下次接受的写入时被移除。如果注册表损坏或使用了不受支持的版本，请删除该文件以重置；接受的流量会重新创建它。Webhook 配置和投递不受影响。

启动 `qwen serve` 并启用频道 worker：

```bash
QWEN_SERVER_TOKEN="$QWEN_SERVER_TOKEN" qwen serve --require-auth --channel dingtalk-main
```

请求示例：

```bash
curl -X POST "http://127.0.0.1:4170/channels/dingtalk-main/webhooks/github-ci" \
  -H "x-qwen-webhook-secret: $QWEN_CHANNEL_GITHUB_CI_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "eventType": "push",
    "targetRef": "operator",
    "title": "CI pipeline finished",
    "payload": {
      "targetRef": "refs/heads/main",
      "repository": "qwen-code",
      "status": "success"
    }
  }'
```

Webhook 路由通过 webhook secret 请求头进行鉴权，即使 `qwen serve` 已启用 bearer auth。不要将守护进程 bearer token 分享给 webhook 提供者。Webhook 配置和 `secretEnv` 值在守护进程启动时加载；更改 webhook 来源或轮换 secret 后请重启 `qwen serve`。`202 {"accepted": true}` 响应表示频道 worker 已接受该任务的所有权，而非最终响应已投递到聊天。排查投递失败时，请检查守护进程和频道 worker 日志以及 `/daemon/status`。

### 多频道模式

当你不带名称运行 `qwen channel start` 时，`settings.json` 中定义的所有频道会一起启动，并共享单个 agent 进程。每个频道维护自己的会话 —— Telegram 用户和微信用户会获得独立的对话，即使他们共享同一个 agent。

每个频道使用其配置中各自的 `cwd`，因此不同的频道可以同时处理不同的项目。

### 服务管理

频道服务使用 PID 文件（`~/.qwen/channels/service.pid`）来跟踪运行中的实例：

- **防止重复**：在服务已运行时执行 `qwen channel start` 会显示错误，而不会启动第二个实例
- **`qwen channel stop`**：从另一个终端优雅地停止运行中的服务
- **`qwen channel status`**：显示服务是否正在运行、运行时间以及每个频道的会话数

### 崩溃恢复

如果 agent 进程意外崩溃，频道服务会自动重启它并尝试恢复所有活动会话。用户可以继续他们的对话，而无需重新开始。

- 服务运行期间，会话会持久化到 `~/.qwen/channels/sessions.json`
- 崩溃时：agent 在 3 秒内重启并重新加载已保存的会话
- 连续 3 次崩溃后，服务会退出并报错
- 正常关闭（Ctrl+C 或 `qwen channel stop`）时：会话数据会被清除 —— 下次启动始终是全新的
