Files
agent-loop/research/async-agent-loop.md
2026-11-12 15:29:12 +08:00

36 lines
6.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 异步 Agent Loop 是怎么调度的
DeepSeek 的设计文章在第 4.1 节把长工具调用拆成启动和完成两次交互。启动先返回「已启动」通知,工具继续运行。Agent Loop 可以在当前推理步结束后处理新输入,执行器在工具结束后把结果送回原会话。本文核对了文章中文镜像、DeepSeek Harness `fcc0ad4` 和公开原型 `6337fc8` 的源码、文档与上游测试,时序数字为假设值。 [设计文章 §4.1](https://telegra.ph/Super-agent-%E8%AE%BE%E8%AE%A1%E6%8E%A2%E7%B4%A2%E8%BF%88%E5%90%91%E6%9B%B4%E8%87%AA%E4%B8%BB%E7%9A%84-Agent-%E7%B3%BB%E7%BB%9F-10-31-2#:~:text=4.1%20%E5%85%A8%E5%8F%8C%E5%B7%A5%E4%BA%A4%E4%BA%92)
## 一个会话里发生了什么
在 DeepSeek Harness 的术语里,一次模型请求和它调用的工具组成一个 step,一个 turn 可以包含多个 step。Loop 在 step 边界取出可处理的输入,组装下一次模型请求。同步执行长命令时,当前 step 要等命令的最终结果。命令实现即使用了 JavaScript 的 `async/await`,同一会话仍在等这个 step 结束。异步工具则把工作交给后台执行器,返回 `job_id`,让当前 step 可以结束。此后用户消息和后台完成通知都可以成为模型的输入,后台任务的进度独立推进。 [Turn 与 Step](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/docs/architecture.md#L81-L112)、[Bash 工具的两个分支](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/shell/tool-bash/src/index.ts#L498-L530)
公开原型的 Worker 会在前台 shell 命令等待超过 5 秒时把命令交给后台。Harness 也支持直接使用 `run_in_background`,任务获准后先返回 ID,启动失败可以随后以失败结果结算。完成通知会进入正在运行的 Agent 的下一步,或者在开启唤醒投递时让空闲 Agent 发起后续一轮。短输出可以随通知一起返回,长输出留给 `job_output` 读取。 [原型的 Worker 调度](https://github.com/deepseek-ai/dsh-superagent-prototype/blob/6337fc823ce20251c8de8085948165c81aaa701e/docs/003-execution.md#L23-L45)、[Bash 工具文档](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/shell/tool-bash/README.md#L60-L62)、[完成通知的投递](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/jobs/tool-jobs/src/index.ts#L355-L410)
如果后续工作确实依赖结果,Agent 可以调用 `job_output(wait: true)`。Harness 的这个等待可以被当前 step 的用户 steer 提前结束,返回仍在运行的状态,让新消息进入下一步,原命令继续运行。排给后续 turn 的消息会继续等待。上游测试分别覆盖这两条路径,此处核对了测试代码。 [等待与 steer 的实现](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/jobs/tool-jobs/src/index.ts#L461-L515)、[上游测试](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/jobs/tool-jobs/tests/steer-wait.spec.ts#L88-L150)
## 等一分钟的测试,谁省下了时间
假设修完过期判断后启动一组本地回归,耗时 60 秒。第 10 秒你问「把刚才的 diff 给我看一下」,这一步只读现有改动,假设模型处理和回答用 3 秒,异步版此时可以开始下一步。
| 从测试启动计时 | 同步调用 | 异步调度 |
| --- | --- | --- |
| 第 0 秒 | 当前 step 开始等待测试结果 | 后台任务开始,工具先返回 `job_id` |
| 第 10 秒 | 追问已发送,当前 step 仍在等测试 | Loop 开始处理追问 |
| 第 13 秒 | 测试仍在跑 | Agent 已回 diff,测试继续跑 |
| 第 60 秒 | 测试结束,Loop 可以处理追问 | 测试结束,完成通知交回原会话 |
| 第 63 秒 | Agent 回 diff | Agent 可以已经在汇报回归结果 |
在这个示意里,追问到回答从 53 秒变成 3 秒,测试本身两边都是 60 秒。若追问换成「测试通过了吗」,第 60 秒才有最终结果,前面只能回答当前状态。若等待期间还有独立工作,例如只读检查同一改动的边界条件,就可能把这段工作和回归重叠起来。若每一步都依赖前一步结果,或者工具本身很快,重叠空间就很小。结果自动投回会话还能让 Agent 在命令完成后自行继续,用户可以等汇报再回来。
并发带来的成本落在执行器和会话管理上。任务要有明确的归属、状态和取消方式,完成结果要对应启动它的任务。如果测试途中改了代码,已有结果应标明对应的版本,必要时重新验证。后台进程也会占用资源。Harness 的本地 job 服务提供并发限制,任务在所属 Agent 被释放或 Harness 关闭时结束。持久化与重启恢复需要额外机制。 [本地 Job 服务与生命周期](https://github.com/deepseek-ai/deepseek-harness/blob/fcc0ad462172522aaf5c93a7b2e01f6b9f0b0159/packages/jobs/jobs-local/README.md#L10-L23)
## 和 T3 Code 的关系
T3 的 Queue 表达「等后续一轮」,Steer 表达「交给当前一轮」。输入框接受了消息、Provider 收到了消息、模型把它纳入下一次请求,是三个不同时间点。Provider 决定当前工具会继续、等待还是被中断。T3 与文章直接对应的机制是后台完成事件,例如 Codex 适配器在符合条件的命令结束后提交通知,T3 服务把它送回原线程,当前轮忙时排在后面。开另一个会话可以并行做另一件事,而这个例子关注同一会话如何继续处理输入并接回测试结果。 [T3 的 Queue 与 Steer](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/docs/user/composer.md#L63-L80)、[Codex 后台结果](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.ts#L5179-L5238)、[T3 同线程续跑](https://github.com/pingdotgg/t3code/blob/a536ff7ac0c080190f098965d0a0d244caf5b211/apps/server/src/orchestration-v2/ProviderContinuationService.ts#L182-L205)
## 周五的演示边界
两遍都跑同一个本地测试,输入同一个只读追问,分别展示同步等待与后台执行。模型用固定桩,测试命令真实运行。记录测试启动、追问到达、Loop 将追问交给模型桩、测试退出、结果进入会话的时间。让观众看见异步版在测试还运行时已经回答,以及结束后会话确实收到退出码。Demo 验证交互顺序,现场时长用于说明等待发生在哪里。