面经-agent

面经-agent

Agent 异步工具(长耗时后台任务)的设计与完成通知

1. 核心概念辨析:什么是 Agent 的“异步工具”?

很多人容易把“异步”混淆为代码层面的多任务并发,在 Agent 体系中必须严格区分两个层次:

  • 微观层面(工具并发执行):大模型在一轮对话中同时触发了多个 tool_calls(如同时读取 3 个文件),Agent 运行时利用 asyncio 并发执行这 3 个工具。此时会话仍处于同一轮等待中,属于单轮会话内部的局部耗时优化。
  • 宏观层面(会话级异步工具 / 后台长任务 Background Task):
    • 核心考点:工具本身耗时极长(几分钟甚至几小时,如批量爬虫、视频生成、模型微调训练);
    • 交互特征:工具调用后立刻脱钩返回任务凭据(job_id),当前会话轮次结束,用户完全不用干等,可以继续向 Agent 提问聊其他话题;后台任务完成后,系统自动通过消息机制将结果送回上下文,隐式唤醒大模型向用户总结汇报。

2. 同步工具 vs 异步工具的判定原则与选型

核心维度 同步工具 (Sync Tool) 异步工具 (Async Tool / Background Task)
执行耗时 极短(毫秒级 ~ 2 秒以内) 长且不可控(十几秒 ~ 几分钟 ~ 几小时)
依赖关系 强依赖:大模型下一句话必须立刻看到该数据 弱依赖/解耦:大模型无需原地等待,可先向用户反馈已在后台排队办理
典型代表 1. 数学计算器 (calculator)
2. 当前时间/天气查询 (get_weather)
3. 知识库 RAG 向量检索 (vector_search)(必须拿到文本片段才能回答)
1. 全网多源批量爬虫 (crawl_500_pages)
2. AI 文生视频 / ComfyUI 工作流 (generate_video)
3. 代码沙箱模型训练 (train_model)
4. 海量数据报表导出与异步人工审批

3. 异步工具架构全流程设计(结合 my-pi-agent 源码实战)

在生产级 Agent 运行时中,异步工具的执行与通知由以下四大环节构成闭环:

环节 1:触发与即时脱钩(返回 Task Ticket)

  • 当大模型决定调用异步工具时,工具函数绝不等待真实逻辑跑完;
  • 在 100ms 内启动后台异步协程或子进程,并立即返回一个任务凭据(如 {"status": "running", "job_id": "bg_000001"});
  • 大模型拿到 job_id 后,立即向用户输出安抚确认话术(如“已在后台为您启动任务 bg_000001,您无需等待,可以继续向我提问”),当前轮次正常闭环结束,释放用户交互界面。

环节 2:后台任务状态机与孤儿进程防御

  • 后台 Worker 维护持久化状态机:PENDING ➔ RUNNING ➔ COMPLETED / FAILED / CANCELLED;
  • 支持进度查询(Progress)与取消令牌(Cancellation Token);
  • 注册进程树清理机制(如 _kill_process_tree),防止任务被取消或进程退出时产生失控的孤儿进程。

环节 3:任务完成通知与事件入队

  • 后台任务执行完毕后,自动组装标准结构化通知(如 <task_notification id="bg_000001"> 包含退出码与输出日志);
  • 核心动作:将通知投递至系统的动态干预队列(MessageQueue 的 Follow-up 追问队列),静默等待主循环调度。

环节 4:ReAct 主循环收割与隐式二次唤醒(Silent Re-triggering)

  • 在 ReAct 微内核(loop.py)的外层循环中设置探测点:
    1
    2
    3
    4
    5
    6
    # loop.py 核心收割逻辑
    if get_follow_up_messages is not None:
    followups = get_follow_up_messages()
    if followups:
    pending_messages = _as_messages(followups)
    continue # 🚨 核心:不退出循环,携带完成通知开启新一轮 ReAct!
  • 绝不直接向前端倾倒冰冷的原始 JSON,而是将 <task_notification> 作为新上下文重新唤醒大模型,由大模型以自然语言组织总结并流式推给用户(如“顺便向您汇报,刚才在后台运行的任务已顺利完成,这是为您整理的数据分析…”)。

4. 进阶架构:基于 tmux 终端多路复用的长任务设计(Pi 官方设计哲学)

在 Coding Agent(如 Pi 原厂架构)中,传统通过普通子进程(subprocess)在后台运行命令存在三大死穴:

  1. 无伪终端 (No TTY):进度条 \r 刷屏,日志缓冲严重,读出来全是 ANSI 转义乱码;
  2. 无法交互输入:程序若中途弹出 [Y/n] 或等待密码输入,后台进程当场永久死锁卡死;
  3. 断线不可恢复:Agent 重启后无法找回之前的终端会话。

基于 tmux 的神仙解法(四大核心操作):

  1. 开辟独立静默会话:tmux new-session -d -s task_001 "command",赋予子任务一个带有完整虚拟终端(PTY)的独立后台沙盒;
  2. 无乱码终端截屏(核心杀手锏):调用 tmux capture-pane -pt task_001,tmux 内部的虚拟终端渲染引擎会把进度条和转义符消化掉,直接吐给大模型一张极其干净的终端纯文本屏幕快照;
  3. 模拟键盘输入:若发现程序卡在等待确认,通过 tmux send-keys -t task_001 "yes" Enter 模拟人工敲击键盘化解死锁;
  4. 状态检测与收割:监控任务完成标记或退出码,提取完整日志并调用 tmux kill-session 清理现场,最后将通知塞回 MessageQueue 驱动大模型向用户总结汇报。