Skip to Content
开发者指南REST API 集成指南

REST API 集成指南

对于希望通过 HTTP 将 Qwen Code 嵌入自有产品的团队:以 qwen serve 作为后端,并从自己的前端驱动它。

本页是入口。完整路由参考见 qwen-serve-protocol.md;内部实现见 daemon 深度解析;可运行的 TypeScript 演练见 examples/daemon-client-quickstart.md

存在哪些路径

基于 daemon 构建有六种方式,区分标准只有一个——你拥有多少前端?

路径你拥有的部分状态
daemon + 内置 Web Shell无——直接使用 shipped 版本当前已发布(用户指南
daemon --no-web + 自有 UI整个前端当前已发布——本页
daemon + 品牌化 Web Shell品牌,非代码尚未构建(#11357 
daemon + 自托管 Web Shell 构建前端构建尚未构建(#11358 
daemon via SDK DaemonClient客户端代码,无需原始 HTTP当前已发布(TSJava)——Python SDK 仅支持进程传输,没有 daemon 客户端,因此 Python 集成通过原始 HTTP 走路径 2
daemon via MCP bridge无——由另一个 agent 驱动qwen-serve-mcp 形式随 @qwen-code/sdk 发布——参见 bridge READMEQWEN_BRIDGE_ALLOW_GLOBAL_SCOPE 可可选地允许全局作用域写操作

无头模式 qwen -p 和面向编辑器的 ACP over stdio 是独立的集成路径。Channel 和扩展也可以通过 daemon 运行;参见 channel 指南扩展参考

设计前须知

daemon 不在进程内执行推理。 它生成 qwen --acp 子进程并在它们与 HTTP 之间进行代理。它在同一 Node 二进制下运行 CLI 入口脚本,使用 QWEN_CLI_ENTRY 或回退到 process.argv[1]。嵌入 Node 后端必须将 QWEN_CLI_ENTRY 指向已安装的 Qwen CLI 入口脚本;PATH 上没有 qwen 查找。缺失入口点会表现为 MissingCliEntryError

稳态下每个活跃工作区运行时只有一个子进程,而不是每个会话一个。工作区中的每个会话都多路复用到该子进程并共享其进程、OAuth 状态、文件缓存和层级内存解析。因此故障域是工作区:如果子进程退出,多路复用到它的所有会话会一起被拆除。容器大小应按 daemon 加上每个已注册工作区一个子进程来规划,并为每次 channel 切换期间每个运行时预留一个额外子进程的余量。当会话必须独立失败时,运行独立的 daemon——--max-sessions 限制的是并发数,而非爆炸半径。

认证为单运营方模式。 运行时 bearer token 授予整个 bearer 受控 API 的访问权限,可信的 loopback 调用方拥有完整权限,包括以 daemon 用户身份执行代码。没有按终端用户的主体模型。如果你将其置于多用户产品之后,你的后端负责用户身份,且不得将 daemon token 交给浏览器。容器化和多租户部署被明确推迟——参见用户指南中的”v0.16-alpha 已知限制”。

已配置的 channel webhook 入口(POST /channels/:channelName/webhooks/:source)在 bearer 认证之前使用自己的 x-qwen-webhook-secret 认证;在配置 channel webhook 源之前它处于非活动状态。

启动 daemon

export QWEN_SERVER_TOKEN="$(openssl rand -hex 32)" qwen serve --no-web --require-auth \ --hostname 0.0.0.0 --port 4170 \ --workspace /srv/project

--no-web 保留下面列出的路由,但禁用 Web Shell 资源和依赖表面:在 macOS 上是 /live/* 路由和 /live/host socket,在所有平台上是 GET /mcp-app-sandbox。通过环境变量而非 --token 传递 token,因为后者可通过 /proc/<pid>/cmdline 被任何本地用户读取。

下面的 Bash 示例通过文件描述符使用 shell 的 printf 内建命令传递 Authorization header,使 token 不出现在 curl 的参数中。

集成实际使用的路由

daemon 注册的大部分路由用于驱动 Web Shell——git 操作、扩展安装、工作区信任、语音、定时任务——并随该 UI 变化。下面的子集规模小一个数量级。

这些是 REST 集成所需的路由。其余视为内部接口。

发现

路由用途
GET /health存活探针
GET /capabilities预检——在任何操作之前读取 workspaceCwdpolicy.permission

会话生命周期

路由用途
POST /session创建。发送 sessionScope: "thread" 以获得独立对话
DELETE /session/:id关闭。持久化的会话保留并可重新加载
POST /session/:id/load · /resume恢复持久化的会话
POST /session/:id/heartbeat推迟空闲回收器
PATCH /session/:id/metadata会话元数据
POST /session/:id/model在绑定的服务内切换模型
GET /session/:id/status运行时状态——尚无专门参考章节

提示与流式传输

路由用途
POST /session/:id/prompt提交。返回 202 表示准入,而非完成
POST /session/:id/cancel仅取消活动提示
GET /session/:id/eventsSSE 流。在提示之前订阅
GET /session/:id/transcript对话历史
GET /session/:id/context上下文窗口使用情况
GET /session/:id/export · GET /session/:id/pending-prompts尚无专门参考章节

权限

路由用途
POST /session/:id/permission/:requestId回答 permission_request。路由到拥有该会话的运行时,因此在任何工作区状态下都正确——尚无专门章节
POST /permission/:requestId进程全局形式,仅连接到工作区的 bridge:对于由其他已注册运行时拥有的会话返回 404,响应体与默认 first-responder 策略下的丢失投票相同——因此此处的 404 本身并不意味着请求已被回答

只读工作区上下文

路由用途
GET /file · /file/bytes读取文件或字节范围
GET /stat · GET /list · GET /glob路径元数据、目录列表、glob——尚无专门章节
GET /workspace/tools活动 ACP 子进程报告的工具;没有子进程时,响应包含 acpChannelLive: falsetools: []not_started 错误——尚无专门章节

参考覆盖率。 上述 25 个路由中有 17 个具有专门章节。 其余 8 个中,部分仅在行文中提及,三个完全缺失:GET /session/:id/pending-promptsPOST /session/:id/permission/:requestIdGET /workspace/tools。 弥合此差距的工作跟踪于 #11359 

最小流程

1. 预检。 读取 workspaceCwd(以便创建时可省略 cwd)和 policy.permission(以便了解谁可以回答权限请求)。

curl -sH @<(printf 'Authorization: Bearer %s\n' "$QWEN_SERVER_TOKEN") http://daemon:4170/capabilities

2. 创建会话。 使用 sessionScope: "thread",除非调用方需要共享一个对话——默认的 "single" 会使同一工作区的第二次创建_复用_已有会话,将不相关的调用方串行化到一个队列中。

curl -sX POST http://daemon:4170/session \ -H @<(printf 'Authorization: Bearer %s\n' "$QWEN_SERVER_TOKEN") -H 'Content-Type: application/json' \ -d '{"sessionScope":"thread"}' # → {"sessionId":"…","workspaceCwd":"/srv/project","attached":false}

3. 先订阅再提示。 Last-Event-ID: 0 从最早保留的事件开始重放,这是捕获创建与订阅之间触发的事件(特别是 model_switch_failed)的方式。在附加时(默认的 sessionScope: "single" 复用已有会话),该事件是唯一表明不良 modelServiceId 被拒绝的信号,因为该失败故意不作为 HTTP 错误传播。在携带 modelServiceId全新创建时(步骤 2 的请求体不携带),200 响应体还携带 modelApplied,当切换被拒绝时为 false,这是要操作的确定性信号,而非有界环上的事件。不携带 modelServiceId 的创建完全没有 modelApplied 键。

curl -N http://daemon:4170/session/$SID/events \ -H @<(printf 'Authorization: Bearer %s\n' "$QWEN_SERVER_TOKEN") \ -H 'Accept: text/event-stream' -H 'Last-Event-ID: 0'

每个 data: 行是一个完整的单行信封;信封的 typeevent: 行匹配。

重放受 --event-ring-size 和固定的每订阅 8 MiB 字节预算限制。如果流发出 state_resync_requiredreason: "replay_budget_exceeded",通过 POST /session/:id/load 恢复,而不是将重放视为完成。

4. 提示。 202 表示已准入,而非已完成。通过 promptId 关联流上的 turn_complete / turn_error。在 turn_complete 上读取 stopReason;在 turn_error 上读取 message 以及可选的 code / errorKind——参见 POST /session/:id/prompt

curl -sX POST http://daemon:4170/session/$SID/prompt \ -H @<(printf 'Authorization: Bearer %s\n' "$QWEN_SERVER_TOKEN") -H 'Content-Type: application/json' \ -d '{"prompt":[{"type":"text","text":"What does src/main.ts do?"}]}' # → 202 {"promptId":"…","lastEventId":42}

5. 回答权限请求。 当 agent 想要运行工具_且其审批模式要求确认_时,它会发出 permission_request,轮次阻塞直到有人回答或你取消——默认没有超时--permission-response-timeout-ms 默认为 0 = 无限等待),因此未回答的请求会持续占用会话提示队列中的槽位,直到你取消或关闭会话。如果流程需要截止时间,自行设置。

该模式是子进程自身的 Qwen 设置 tools.approvalMode,从 daemon 主机和 --workspace 目录的设置中解析;daemon 在生成时不固定任何值。其默认值为 auto,无需询问即可批准一类工具调用——这些调用根本不发布 permission_request——但仍会对其余调用询问。不受信任的工作区文件夹被强制降为 default(询问),这就是为什么一个部署会看到这些事件而另一个不会,且 GET /capabilities 报告的是投票调解策略而非审批模式,因此预检无法告知你当前处于哪种姿态。如果你的集成依赖审批门控,显式固定 tools.approvalMode 并提前决定如何回答:自动批准可能已经在没有任何人选择它的情况下生效。

在会话作用域路由上回答:它路由到拥有该会话的运行时,因此无论工作区配置如何都能工作。

curl -sX POST http://daemon:4170/session/$SID/permission/$REQUEST_ID \ -H @<(printf 'Authorization: Bearer %s\n' "$QWEN_SERVER_TOKEN") -H 'Content-Type: application/json' \ -d '{"outcome":{"outcome":"selected","optionId":"proceed_once"}}'

6. 关闭。 DELETE /session/$SID204。磁盘上的会话被保留。

运维

关注点位置
并发上限--max-sessions--max-total-sessions;超限创建返回 503 并带 Retry-After
速率限制--rate-limit 加上按类别的 --rate-limit-* 标志
空闲清理--session-idle-timeout-ms;通过 POST /session/:id/heartbeat 保持活跃
内存--child-heap-mode 仅为观察模式。--memory-budget-mb 控制 POST /session/:id/load 的自适应实时日志增长池,而非 SSE 重放;固定 --max-journal-bytes--max-journal-events 中的任一个会禁用增长。两个标志都不会调整子进程大小或拒绝生成,也不控制其实际堆上限(--max-old-space-size,从主机内存派生)。预算计算参见配置。SSE 重放由 --event-ring-size 和固定的每订阅 8 MiB 预算单独限制;缺失尾部会产生 state_resync_requiredreason: "replay_budget_exceeded"
提示截止时间--prompt-deadline-ms;超时发出 turn_error
错误错误分类
可观测性可观测性
完整标志列表配置
Last updated on