第十八节 子任务与后台执行

[!ref] 详解见用户手册「子任务与后台执行」节。

18.1 派发参数

参数 类型 默认 说明
prompt string — 子任务提示词;必填
agent_id string 当前助手 指派子助手人设
model string 当前模型 子任务模型
run_in_background bool false true 走后台
timeout_ms int 600_000 前台超时;后台不适用

18.2 BackgroundRegistry

字段 默认 说明
同时在跑上限 64 超出立即拒绝并提示稍后重试
终态保留 30 分钟 超过窗口被回收
优先级 killed > done 外部 stop 与自然结束撞拍时 killed 胜

18.3 子任务工具

工具 参数 说明
Agent prompt, agent_id, run_in_background? 派发单个子任务
AgentParallel legs[](2–16), timeout_seconds? 一次拆多路并行 fan-out(见 §18.3.1)
TaskOutput task_id, limit? 拉取后台任务状态 / 输出片段
TaskStop task_id 强制终止后台任务
StopAgentToolRun child_session_id 单独停止某个正在跑的子代理(后台 / 并行腿 / 同步内联均支持);幂等。可选保留已产生的子任务记录
TaskWait task_ids, mode=all|any, timeout_seconds(默认 300,最长 1800) 阻塞等待后台任务 / 子代理;超时返回「还在跑」让模型决定继续。结果附带 other_tasks(同会话未被本次等待覆盖的后台任务);运行中任务带 elapsed_ms
EnterPlanMode / ExitPlanMode 无 进入 / 退出筹划
TodoWrite todos 写入或更新待办列表

18.3.1 AgentParallel 参数

参数 类型 默认 说明
legs array — 必填,2–16 条;每条独立 fresh-context 子 Agent,全部完成后聚合返回
legs[].subagent_type string — 必填,目标子代理类型
legs[].prompt string — 必填,自包含子任务提示词(腿看不到主对话历史)
legs[].description string — 可选,3–5 词,仅用于日志 / UI
legs[].model string 继承 可选,单腿模型覆盖
timeout_seconds int 600 整体等待超时,上限 1800;到时未完成的腿返回 pending 并在后台继续

少于 2 条会报错(改用 Agent),多于 16 条静默截断到前 16。每条腿作为真实后台任务派发、内部统一 Wait(all) 聚合;单腿输出超 8000 runes 截断(提示用 TaskOutput 取全文)。腿为叶子层、不可再嵌套 Agent / AgentParallel。v1 仅 all 模式。返回 ParallelResult(completed / num_ok / num_failed / num_pending / legs[] 等,永不抛错)。

渲染:调用卡片执行期即显示并随实时 store 反映各腿运行状态(停止后不再转圈);极简密度下结果块不被工具组误折叠。

18.3.2 子代理终态

状态 含义
运行中 running 在跑
已暂停 paused 用户暂停,可继续
完成 completed 正常跑完
已结束 ended 盘上无明确终态(导入会话 / 重载回灌)。此前此类记录谎报为「完成」
失败 failed / 已终止 killed / 被拒绝 denied 按盘上 sidecar 终态回灌
  • 被 TaskStop 终止的任务不显示成功标记;MarkKilled 当场结算 DurationMS,不记为 0。
  • 子代理只在用户显式 Stop 时终止:respawn、新消息等内部动作不再级联 kill。

18.3.3 子代理抽屉动作

动作 说明
停止 / 暂停 / 继续 「继续」可带「补充指令」;从已保存的运行历史续跑
重试 截断到最后一条用户消息后重新运行
再跑一次 用相同 type + prompt 重新发起(prompt 缺失时禁用)
编辑消息 / 删除消息 运行中拒绝编辑;编辑走侧挂编辑器 + 增量更新
删除工具调用 连带删除配对的工具结果;无 id 的导入旧记录不可单独删除
从此处重试 此消息起重新生成(用户消息保留提问重答;助手 / 工具消息重做该步)
从此处继续 保留到此消息为止,其后丢弃,回到该时间点续跑;「补充指令」一并带入
复制 / 复制选中的部分 —
复制 JSONL 路径 / 复制 TaskWait 参数 后者给出 task_ids + timeout 的 JSON;TaskOutput / TaskStop 用同一 id

消息柄菜单头部显示该消息的绝对 + 相对时间;删除 / 重试 / 继续均有行内二次确认。

18.3.4 TaskWait 调用行呈现

项 行为
预期等待时间 调用行显示 ≤ timeout_seconds 的预算
总体倒计时 在途且确有后台任务在跑时才启动;倒数到 0 回落为灰色静态预算,不停驻 0ms
完成态图标 条头图标换为打钩时钟
紧凑模式 配合子任务状态马赛克(一格一任务、按状态着色)
最终回复 终态下展示「给主代理的最终回复」

18.4 长程任务崩溃恢复

后台任务(run_in_background=true)的进度落盘到本机全局目录(每任务一份 JSON 快照);走到终态(done / error / killed)即删除快照。

项 默认 说明
落盘范围 仅后台任务 前台同步任务不落盘
启动扫描 异步、不阻塞 先做脏条目清理(父会话已删的条目自动剔除),再列出残留任务
自动恢复开关 关(auto_resume_tasks) 设置 → 智能体 → 自省;开启后启动自动续跑(夜间无人值守)
启动自动恢复上限 5 防「续跑消息风暴」;其余转手动横幅
恢复方式 注入父会话续跑 不直接重启子进程,而是向原父会话注入「继续 / 重新委派」消息(对用户可见)
手动入口 顶部恢复横幅 每条可「恢复 / 忽略」,另有「全部忽略」

18.5 自修复循环参考

错误按来源(request / gateway / upstream)与类别分流后映射到 4 类修复策略,各有按会话计的尝试上限:

修复策略 适用错误 上限
transient_compact(压缩重试) 上下文超限 2
transient_fallback(切换服务提供方,需确认) 无可用通道 / 上游过载 / 上游认证失败 3
backoff(退避重试) 限流 / 超时 / 网络 3
terminal(交还用户) 余额不足 / 需重登 / 模型不存在 —

特例:upstream 来源的 auth_error 重判为 transient_fallback(某通道 key 失效而非用户凭据);仍可重试的 terminal 救回为 backoff;5xx / 408 默认可重试,其它 4xx 终止。

  • 网络抖动自愈:瞬断 / 临时离线时探测「离线 → 在线」再续跑,这段等待不计入重试预算;连接重置 / DNS 暂时解析失败 / 握手中断等连接级瞬断细分为网络问题(而非笼统 llm_error)。
  • 产出型自愈(MaxOutcomeHeal = 3,连续计数、干净收尾清零):回复被长度截断自动续写(truncated_continue)、推理绕圈打断(reasoning_loop)、内容过滤换述(content_filter)、回复停在半句(cut_mid_sentence)、说了下一步却没动手(announced_no_action)。后两者只在 finish=stop 的轮次终点判,核对回合与自报暂停的回合不判;先判半句、再判宣告(看最后一句);以提问、交还用户、客套语、列表 / 表格 / 标题收尾均判为正常。续跑消息 source=auto_self_heal 不可见;撞顶 toast「自动修复已放弃:{kind} 连续几轮没能纠正 —— 需要人工介入」。
  • 门禁升级:同一处检查 / 测试失败或待办无进展达上限(测试门禁 3 次、无进展待办 2 次)时升级提示换思路。
  • 服务提供方备选经 App.RespondProviderFallback 回写确认,前端 SelfRepairFallbackBanner;后端事件 self_repair:fallback_confirm / _applied / _declined / self_repair:outcome。

18.6 经验学习闭环参考

组成 说明
自愈历史学习(P1) 每类自愈成败落盘 ~/.config/avlcode/self-heal-stats.json;平滑率 (succ+1)/(total+2)。样本 < 5 用默认上限 3;率 < 0.2 → 1、0.2–0.5 → 2、≥ 0.5 → 3;每类至少 1,仅下调不上调
自动反省(P2/P3) auto_reflect(默认关,设置 → 智能体 → 自省)开启后,多步任务收尾异步跑一次 GRAI+KISS 复盘;读轨迹摘要(最多 5 个错误步)+ 自愈统计,产出 ≤ 8 条 Keep/Improve/Stop/Start 教训
教训去向 沉淀到记忆宫殿 _pending 草稿盒(房间 scratch、类型 decision、不衰减),需人工审批后才入正式库;按标题去重;事件 reflection:done

18.7 会话内例行程序参考

与 设置 → 例行程序(工作区例行程序,§6.13)是两套独立数据:会话内例行程序由模型在会话中创建,到点送进创建它的会话。存于 ~/.config/avlcode/workspaces/<工作区 ID>/session-routines.yaml(不在项目目录的 .avlcode/ 下),调度器每 5 秒扫一次已打开的工作区。

工具 参数 说明
RoutineCreate name(≤ 40 字)、prompt(≤ 4000 字,须自包含)、schedule(必填 type + minutes / at / time / days)、when_idle(run / skip)、delivery(step_end 默认 / interrupt)、max_runs、expires_in_hours 新建;停止之后才到达的调用被拒收
RoutineList 无 本会话未结束(含暂停)的例行程序 + 最近结束记录(每会话保留 10 条)
RoutineCancel routine_id(rt_ 开头)、reason(一行,展示给用户) 取消;已结束的返回 cancelled=false
schedule.type 含义 约束 默认有效期 / 上限 默认次数 / 上限
after N 分钟后一次 minutes 1–1440;when_idle 必填 — 1 / 1
every 每 N 分钟 minutes 1–720;when_idle 必填 max(8, ⌈3×分钟/60⌉) 小时,封顶 24 / 24 小时 30 / 200
at 指定时间一次 YYYY-MM-DD HH:MM,须在将来、最远 30 天 — 1 / 1
hourly 每小时 time 只取分钟(HH:MM / :MM / MM) 72 / 720 小时 72 / 720
daily / weekdays 每天 / 工作日 time 为 HH:MM 168 / 720 小时 不限 / 显式给时 ≤ 1000
weekly 每周 time + days(0=周日 … 6=周六,至少一天) 168 / 720 小时 不限 / 显式给时 ≤ 1000
项 取值
可用范围 仅主会话;auto / execute 三个工具全有,plan / prepare / assess 仅 List / Cancel;子代理与 TUI 不可用;无全局开关,不受工具延迟加载影响(常驻)
工具分组 routine.* = 全部三个;agent.* / agent.read.* 仅含 List / Cancel
数量上限 每会话未结束 ≤ 5;每工作区未结束 ≤ 50;每会话 24 小时内新建 ≤ 10;每工作区每自然日送达 ≤ 300 次(超出:一次性的结束、重复类跳过)
到点时会话在跑 按 delivery 插入当前循环;插不进去时每 15 秒重试、最多 10 分钟,超时一次性的结束(delivery_failed)、重复类跳过
到点时会话空闲 when_idle=run 起一轮(用会话最近的工作模式与该会话的模型);skip 则一次性的结束(idle_skipped)、重复类跳过。会话忙(等审批 / 换代 / 发送在途 / 测试门禁在跑)或刚停下不到 10 秒时 5 秒后再看
连续失败 3 次自动暂停(例行程序起的一轮以错误收场也算);一次性的 60 秒后重试;正常收尾或「恢复」清零
错过 不补发:重新进入调度范围时超过 1 分钟即算错过(一次性的结束 missed,重复类从当前重算);暂停后恢复也不补发
停止 停止按钮与 IM /stop 取消本会话全部(user_stopped);删除会话连同记录清除;归档会话以 session_archived 结束
消息流 source=auto_routine,显示为折叠行「⏰ 例行 · 名称 · 3/30」;送达尾注(不是用户新消息、不代表新授权、完成后应 RoutineCancel)只给模型看;不进会话目录
IM 例行程序起的一轮,回复转发给绑定该会话的 IM 对端(抬头「⏰ 例行「名称」」);IM 侧无管理命令

「例行」strip 动作:暂停 / 恢复、编辑(名称、提示、计划类型、分钟 / 时间 / 星期、会话空闲时、会话在跑时、次数上限、有效期;0 = 默认)、删除(无二次确认、不留结束记录);「已结束」区列原因并可「知道了」。结束原因:已完成 / 已达次数上限 / 已到期 / 模型已取消 / 你点了停止 / 会话已删除 / 会话已归档 / 错过触发时间 / 触发时会话空闲,已跳过 / 投递失败 / 工作区今日送达次数已用完。