F4: document task backend operation and publish API contracts

This commit is contained in:
Xin Wang
2026-10-23 23:48:08 +08:00
parent fff76fe889
commit 7db737d161
9 changed files with 746 additions and 180 deletions
+70 -66
View File
@@ -1,21 +1,21 @@
---
title: 提示词助手的对话模型与任务后端
description: 将任务后端从普通工具资源中迁出的适配草案。
description: Speaker 与内置 Reasoner、外部 OpenCode 任务后端的配置和运行边界。
---
# 提示词助手的对话模型与任务后端
状态:设计草案。当前已实现版本仍通过 task 工具资源连接 OpenCode;本文描述下一版迁移目标,不表示新配置或内置 Reasoner 已可使用。
状态:第一版已实现。任务后端使用独立资源配置;内置 Reasoner 和外部 OpenCode 都有运行路径。真实模型和远端 OpenCode 仍需使用有效连接配置进行部署联调,模拟协议测试不代表完成过真实编码任务。操作步骤见[后台任务使用说明](/prompt-background-tasks)。
## 范围与职责
仅提示词 Pipeline。一个助手配置一个 Speaker,可选一个任务后端:内置 Reasoner 或外部 OpenCode。外部 Coding Agent 首版只接 OpenCode。
仅提示词 Pipeline。一个助手配置一个 Speaker,可选一个任务后端:内置 Reasoner 或外部 OpenCode。Workflow、Realtime 和启动 Action 不支持任务委派。切换为 Realtime 时,界面会先确认解除当前助手的任务后端绑定,后端资源仍保留。
Speaker 使用现有 ASR → 对话 LLM → TTS 链路,负责交流、澄清、委派与播报。任务后端有独立上下文和执行策略。简单对话由 Speaker 完成,需要较强推理或执行能力时委派任务;任务执行期间 Speaker 继续响应用户。
Speaker 使用现有 ASR → 对话 LLM → TTS 链路,负责交流、澄清、委派与播报。任务后端使用独立上下文处理目标,执行期间 Speaker 继续响应用户。
```text
用户 ⇄ ASR / Speaker / TTS
│ 委派、查询、补充输入、取消
│ 委派、查询、回答问题、取消
▼
TaskService + 应用级 Coordinator
│ Pipecat 原生 Jobs
@@ -33,100 +33,104 @@ Speaker 使用现有 ASR → 对话 LLM → TTS 链路,负责交流、澄清
数据库存储 / 网页 / Speaker
```
产品配置使用「任务后端」资源。模型仍可通过内建 function calling 发起委派,这是模型与平台的通信方式;管理员不再创建 OpenCode Tool、不填写委派函数名,也不把它放入普通工具绑定列表。
管理员在「组件库 → 任务后端」创建资源,再在提示词助手中选择。普通工具资源只包含 HTTP、MCP、Client。Speaker 通过平台自动注册的 `delegate_task` 发起委派,无需填写函数名或绑定一项 OpenCode 工具。
## 资源与配置
新增 `TaskBackendResource`,与模型资源、工具资源并列。首版资源类型为 `reasoner | opencode`,用明确的配置分支,无需通用插件系统。
`TaskBackendResource` 与模型、工具资源并列,类型为 `reasoner | opencode`。资源负责连接、模型、执行策略和技能;助手的 `taskBackend` 只包含 `backendId`、`instructions` 和 `instructionSource`。
| 配置位置 | 内置 Reasoner | OpenCode |
| 配置 | 内置 Reasoner | OpenCode |
| --- | --- | --- |
| 后端资源 | 名称、说明、启用状态 | 名称、说明、启用状态 |
| 连接与模型 | 引用现有 LLM ModelResource;独立模型凭据由资源解析 | 服务地址、服务鉴权、工作目录、远端 agent;可验证支持时选择远端模型/variant |
| 推理配置 | 该模型支持的推理强度或预算 | 采用远端模型/agent 的配置及能力 |
| 执行策略 | 平台允许的服务端工具、任务时限、取消规则 | 任务时限、取消规则;权限及沙箱以远端实际环境为准 |
| 技能 | 平台管理并向该 Reasoner 加载的任务说明 | 远端已安装的原生技能及 agent 配置 |
| 基本信息 | 名称、说明、启用状态 | 名称、说明、启用状态 |
| 连接与模型 | 引用已启用的 LLM 模型资源,凭据在服务端解析 | 服务地址、用户名、服务密码、远端工作目录 |
| 推理配置 | 模型默认,或经能力声明的 low / medium / high | 可选远端 Agent;可成对指定 Provider ID / Model ID |
| 执行策略 | HTTP/MCP 工具白名单、任务时限;并发固定 1 | 任务时限;权限和沙箱由远端管理;并发固定 1 |
| 技能 | 内联技能名称与说明,加载到任务上下文 | 记录远端已部署技能的说明,平台不上传或安装技能 |
| 任务指令 | 可复用的后端指令,加上该助手的任务指令 | 相同 |
助手新增 `taskBackend` 配置,包含 `backendId`、该助手的任务指令、执行策略和技能选择;连接信息留在可复用的后端资源内。第一版不增加第三个模型角色或多后端路由。
默认任务时限为 600 秒,可设置 30–7200 秒。资源配置保存时和助手绑定时都会校验模型、工具及变量引用。修改资源不会改变已创建任务的冻结配置。
Speaker 继续引用现有 LLM 模型绑定。Reasoner 引用独立的 LLM 资源,即使选中同一个模型资源,也必须创建独立的模型服务实例、上下文和运行配置,避免推理强度、工具或对话历史互相影响。
### 内置 Reasoner
推理强度根据模型实际能力显示:例如模型可能支持 low/medium/high,也可能仅支持 thinking budget。配置由 provider 适配到真实参数,不静默忽略不支持的选项。当前模型工厂主要支持 OpenAI-compatible 接口;未支持的 provider 应明确拒绝,不能仅增加下拉选项。
Reasoner 引用 `openai-llm` 或 `dashscope-llm` 的 LLM 模型资源。即使与 Speaker 选择同一资源,每个任务也会创建独立的模型服务、上下文和运行设置。
推理强度使用实际的 `reasoning_effort` 参数。选择 low / medium / high 前,管理员须确认模型支持该参数,并在模型资源中声明 `values.supportsReasoningEffort = true`。未声明时只能使用「模型默认」;服务端会拒绝非默认值。当前没有通用 thinking budget 配置,也不自动推测模型能力。
Reasoner 只能调用该后端显式绑定的 HTTP/MCP 服务端工具,继续复用现有 `ToolExecutor`。Client 工具依赖浏览器连接,不能作为后台工具。技能是工作方法,不能扩大工具许可。平台没有为 Reasoner 增加通用 Shell/文件环境;需要远端编码执行时选择 OpenCode。
### 外部 OpenCode
平台连接已有的 OpenCode 服务,不安装软件、不启动远端进程。地址必须由平台后端可访问;工作目录使用远端机器上的绝对路径。服务鉴权凭据、远端模型 API 凭据与执行权限分别管理。
- 服务地址、用户名与密码负责 HTTP Basic 鉴权。
- `agent` 留空使用远端默认 Agent。
- `modelProviderId` / `modelId` 同时填写或同时留空;留空使用远端默认模型。模型凭据在 OpenCode 端配置。
- 文件、Shell、沙箱、技能权限由远端 Agent、运行账号和部署环境执行。工作目录不等于沙箱。
- `skillsNote` 仅记录远端技能及配置来源;平台不保证自动同步远端 `SKILL.md`。
界面没有提供无法实际生效的权限或沙箱开关,也不会自动授予远端执行权限。需要确认权限时由用户在任务卡片处理。
## Pipecat 复用与任务生命周期
当前安装的 Pipecat 1.13.0 包含 `BackendLLMWorker`,管理后台 LLM 上下文、多步工具调用和输出;`LLMContextWorker` 封装上下文聚合器。内置 Reasoner 应优先使用这些组件,工具执行桥接现有 ToolExecutor,不另写推理循环。
应用级 `WorkerRunner`、常驻 Coordinator 和串行任务 Worker 持有执行 Jobs;媒体 Pipeline 只订阅任务事件。断线或用户插话不会取消任务,明确取消时才进入停止流程。
`LLMWithBackend` / `BackendConnector` 已提供前台委派和后台消息传送语义,可复用其公开能力;`LLMWithBackend` 当前为 alpha,且默认会把 attach 会话绑定到媒体 Pipeline 生命周期。直接替换当前 LLM 槽会改变断线行为,必须保留应用级拥有者。
内置 Reasoner 使用 Pipecat `BackendLLMWorker` 管理独立的上下文和模型/工具调用循环;业务适配器注册 `complete_task` 与 `ask_user`。必须明确完成或提出问题,普通文本、模型空闲或 attach 回执都不是任务成功证明。平台没有自行实现第二套推理循环,也未修改 Pipecat。
应用级 Coordinator 拥有后端 attach/执行 Jobs,媒体 Pipeline 只订阅或解除订阅。内置 Reasoner 按任务创建独立 worker/context,任务后端资源只复用配置,不共享所有助手的任务历史。取消一个任务只能影响该任务。
任务结束后通过公开接口清空上下文、工具与处理器引用。当前 Pipecat 运行器仍保留结束 Worker 的注册对象直到应用关闭;本版适用于 MVP,长期高任务量运行还需要验证该框架行为。
Pipecat 继续负责 Worker/Job 派发、串行执行、超时和取消。TaskService 负责业务任务 ID、访问归属、后端选择、配置快照、记录与事件投影。OpenCode 适配器继续负责 HTTP/SSE、结果关联、远端 abort 和重新观察。
`LLMWithBackend` / `BackendConnector` 可供后续评估,但本版没有直接替换 Speaker 的 LLM 槽;保留应用级所有者才能维持语音断线后的执行。
统一后端边界可保持很小:执行并发出事件、查询状态、回复待处理输入、请求取消。恢复和运行中补充消息按后端实际能力处理,不要求两种后端假装支持相同能力。
Pipecat 负责 Job 派发、FIFO 串行、超时和取消。`TaskService` 负责业务任务 ID、后端选择、冻结配置、记录和事件投影。数据库记录不代替原生调度器。
- 原生 attach/idle、普通模型输出及远端接收回执都不是业务任务成功证明。内置 Reasoner 需通过明确的完成/待输入/失败语义返回结果;平台可注册任务内的完成和提问控制函数,复用原生工具回调,不自行实现推理循环。
- 任务提交携带目标及必要上下文。新任务冻结后端配置和策略,模型只能提交任务要求,不能更改地址、凭据、工作目录或授权。
- 进度保存在任务记录与网页;Speaker 接收适合用户的结果、问题及必要状态通知,不默认播报推理过程或原始工具日志。
- 语音插话保留后台任务。用户明确取消时,取消原生 Job 并核查执行后端;未确认远端停止时仍显示停止待确认。
- OpenCode 重启恢复仍使用已保存的 session/message 句柄重新观察,不重发未知提交。内置 Reasoner 首版在应用重启后标记中断并保留已存结果,不自动重放可能有副作用的工具调用;不声称原生 Job 自动持久恢复。
- 运行中任意修改目标需要后端能力支持。首版共同提供查询、取消、回答待处理问题;OpenCode 不自动重发目标来模拟实时 steer。
- **并发与部署**:仅单应用进程、一个 Uvicorn worker;所有任务全局并发固定为 1。已有未结束的 OpenCode 句柄会阻止新任务提交到后端,需先核查或停止旧任务。该约束无法控制平台之外的 OpenCode 客户端。
- **截止时间**:新任务在创建时保存截止时间,覆盖排队和执行;OpenCode 重连观察或应用重启后使用剩余时间,不重新延长截止时间。迁移前没有截止时间的历史任务保留原有观察时限语义。
- **成功判定**:OpenCode 的 204 只表示接收。需要取得关联到本次 message ID 的完成消息;Reasoner 需调用明确完成控制函数。
- **取消**:先取消原生执行 Job,再核查对应后端。OpenCode 需 abort 后确认状态,未确认时保留「停止待确认」。Reasoner 可停止本地执行;已发出的 HTTP/MCP 请求可能已有副作用,应核查业务系统结果。
- **恢复**:OpenCode 使用已存 session/message 句柄重新观察,不重发未知提交。Reasoner 在应用重启后标为中断失败,保留记录,不自动重放可能有副作用的工具。
- **输入与目标变更**:共同支持查询、取消、回答当前待处理问题。首版不支持任意运行中 steer;修改目标时先停止,再创建新任务。
- **通知**:网页保存和展示进度、问题及结果;Speaker 接收必要状态和结果,不默认播报内部推理或原始工具日志。离线结果保留在任务卡片,新语音连接不自动重播旧结果。
首版仍固定任务并发为 1,使用原生串行 Job,不开放尚未实现的任意并发配置。已有远端任务状态未确认时,保留当前阻止新编码提交的业务规则;其后可按后端/工作区拆分原生 worker。
自动测试/Responses 的模拟工具执行路径不会提交或控制真实后台任务,不能用该路径证明真实任务后端已连通。
新任务建议持久化任务截止时间:超时覆盖排队和执行,重启后向原生 Job 传入剩余时间。现有历史任务继续保留原有观察时限语义,不追溯修改历史含义。
## 数据迁移与升级
## 工具、技能与权限
迁移 `20261023_0027` 把旧 task 工具迁为 OpenCode 后端资源,迁移助手绑定,并保留固定值、变量或模板形式的 `instructionSource`。旧工具记录和普通工具绑定会移除。历史任务保留任务 ID、结果、冻结连接和远端句柄,并补充后端来源。
Speaker 的工具用于当前对话中的即时操作,例如显示消息和拍照按钮。Reasoner 使用单独配置的服务端 HTTP/MCP 工具白名单;客户端工具依赖浏览器连接,不能直接成为断线后继续执行的后台能力。现有 ToolExecutor 没有通用 Shell/文件执行环境,首版编码工作由 OpenCode 执行。
迁移不可安全 downgrade。升级前备份数据库;回退需要恢复迁移前备份与匹配的旧代码,不要只回退应用版本。若旧数据包含多个 task 绑定或非提示词 Pipeline 绑定,迁移会明确失败,需先修正这些配置。
技能是工作方法,不能增加执行权限。内置 Reasoner 可先加载平台保存的选中技能文本;实际工具仍按策略校验。OpenCode 优先使用其原生 SKILL.md 发现、加载及权限机制,首版远端技能由管理员部署,平台不承诺自动上传或同步技能文件。
本机运行时更新依赖后执行:
服务鉴权凭据、模型 API 凭据和执行权限是三个独立概念:OpenCode 服务密码用于访问服务,模型凭据由远端管理,文件/Shell 能力取决于远端 agent 权限和运行账号。
```bash
cd backend
.venv/bin/python -m alembic upgrade head
.venv/bin/python -m db.sync_interface_definitions
```
工作目录不等于沙箱。内置 Reasoner 的工具许可由平台执行桥校验;OpenCode 的文件/Shell/技能限制必须由远端 agent/session 或部署环境实际执行。无法经适配器应用或核查的策略应显示「由远端管理」,不能提供看似生效的授权、沙箱开关。首版不建设容器编排系统,也不为了任务执行而自动授予全部权限。
也可在仓库根目录运行 `make db-init`,它会迁移并同步模型接口定义。不要用演示数据 seed 代替正常升级。
## 前端适配
迁移后的原 instruction 预设显示在助手「任务要求来源」中;未修改时保存仍保留该来源。默认「Speaker 生成任务要求」适用于新的对话委派。
提示词编辑页保留当前设计系统,增加以下配置区:
## 代码位置
1. 模型与语音:现有 LLM 字段明确为「对话模型 Speaker」,保留 ASR/TTS。
2. 任务后端:关闭 / 内置 Reasoner / 外部 OpenCode;选择后端资源,按类型展示连接和模型配置。
3. 执行策略:展示能实际执行的策略与后端环境说明;首版并发固定 1。
4. 技能:Reasoner 选择平台技能;OpenCode 展示远端技能配置来源与已配置说明。
资源库新增「任务后端」,工具页移除创建 task 工具的入口。「外部工具」继续管理普通工具,任务配置不再要求管理员填写函数名或 instruction 参数绑定。现有后台任务卡片保留,统一显示两种后端的结果、待输入和取消状态。
## 当前代码的迁移位置
| 当前模块 | 调整目标 |
| 模块 | 职责 |
| --- | --- |
| schemas.py / models.py / db.models | TaskBackendResource、助手 taskBackend 配置、任务 backend_id/type/快照 |
| config_resolver.py | 分别解析 Speaker、任务后端、Reasoner 工具及技能;敏感连接参数只在服务端组装 |
| background_tasks/service.py | submit 接收解析后的任务后端配置,按类型选择执行后端,移除 RuntimeTool 依赖 |
| brains/prompt_tasks.py | 按助手 taskBackend 配置注册平台任务控制入口,使用统一任务状态与通知 |
| brains/prompt_brain.py | 根据 taskBackend 启用委派指导,普通工具循环仅处理普通工具 |
| background_tasks/native.py | 保留应用级原生 Job 宿主,内置 Reasoner 接入 BackendLLMWorker |
| background_tasks/opencode.py | 保留现有协议逻辑,增加经验证可用的 agent/model 选择 |
| routes/background_tasks.py | 从绑定后端解析配置,提交不再要求 toolId;保留查询/取消/输入接口 |
| 前端工具页 / 提示词编辑器 / api.ts | 新任务后端资源入口、独立配置区、移除 task ToolBinding |
| `task_backend_schemas.py` / `db.models` | 后端资源、助手绑定和任务来源 |
| `routes/task_backends.py` / `services/task_backend_resources.py` | 管理、校验、服务端凭据解析 |
| `services/background_tasks/service.py` / `native.py` | 业务任务投影与应用级原生 Jobs |
| `services/background_tasks/reasoner.py` | `BackendLLMWorker`、完成/提问控制与工具桥 |
| `services/background_tasks/opencode.py` | HTTP/SSE、结果关联、abort、重新观察 |
| `services/brains/prompt_tasks.py` | Speaker 委派入口、查询/输入/取消与通知 |
| `routes/background_tasks.py` | 从助手已绑定的后端解析提交配置,任务 API 不接收 toolId |
| 前端任务后端资源页 / 提示词编辑器 | 独立资源、Speaker 标注、指令预设和任务卡片 |
迁移已有 task 工具时,复制连接与凭据到后端资源,把助手绑定转为 taskBackend 引用。原 instruction 的固定值/变量绑定需明确迁为任务指令预设,不能静默丢弃;无法直接迁移的配置应给出具体提示。历史任务保留原 task_id、结果和冻结连接信息,补后端来源,正在执行的任务继续按原句柄观察。
## 验证边界
建议按三个可验收阶段落地:
验收应检查上下文隔离、不支持的推理配置明确拒绝、工具白名单和技能不能扩大权限、状态未知不重复执行、断线继续执行、取消可核查,以及旧凭据和指令预设不会丢失。仓库自动测试中使用的模型和 OpenCode 协议模拟会明确标注;真实 Provider、远端编码执行与部署网络仍需单独联调。具体执行记录以 `implement-stage/task-backends/BUILD_NOTE.md` 为准。
1. 迁出 task 工具资源和助手绑定,保持 OpenCode 执行与历史恢复可用。
2. 实现内置 Reasoner 的真实执行路径,复用原生 BackendLLMWorker 和现有服务端工具;前端只展示已实现的能力。
3. 补齐策略生效校验、技能加载、迁移回归和两种后端的共同验收。
## 参考
验收重点为 Speaker 无需等待任务结束才能继续交流;任务上下文隔离;不支持的推理配置明确拒绝;任务状态未知不重复执行;语音断线不取消任务;明确取消可核查;后台不能执行依赖已断开浏览器的客户端工具;技能不能扩大权限;历史连接与指令配置不丢失。
## 核查依据
- 本地已安装 Pipecat 1.13.0 源码:workers/llm/backend_llm_worker.py、llm_context_worker.py、pipeline/llm_with_backend.py。
- [Pipecat BackendLLMWorker](https://reference-server.pipecat.ai/en/latest/api/pipecat.workers.llm.backend_llm_worker.html)
- [Pipecat LLMWithBackend](https://reference-server.pipecat.ai/en/latest/api/pipecat.pipeline.llm_with_backend.html)
- [OpenCode Server](https://opencode.ai/docs/server/)
- [OpenCode 权限](https://opencode.ai/docs/permissions/)
- [OpenCode 技能](https://opencode.ai/docs/skills/)
- [OpenCode 模型配置](https://opencode.ai/docs/models/)