第十八节 子任务与后台执行
[!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 = 默认)、删除(无二次确认、不留结束记录);「已结束」区列原因并可「知道了」。结束原因:已完成 / 已达次数上限 / 已到期 / 模型已取消 / 你点了停止 / 会话已删除 / 会话已归档 / 错过触发时间 / 触发时会话空闲,已跳过 / 投递失败 / 工作区今日送达次数已用完。