能否举一个实际场景,说明如何使用 DAG(有向无环图)来编排多个 Skill 的执行?
面试官:“能举一个实际的业务场景,说明你是怎么用 DAG 来编排多个 Skill 的吗?”
候选人:
“最经典的场景就是‘商务出行全流程安排’。用户说一句‘下周二去深圳见客户,帮我安排一下’,背后涉及七八个 Skill 的协作。我以这个为例,完整走一遍 DAG 的构建和执行过程。
场景:商务出行全流程安排
涉及 Skill 清单:
构建 DAG
编排引擎拿到“安排出差”这个复合意图后,规划器生成如下 DAG:
┌──────────────┐
│ A. 查日历 │
└──────┬───────┘
│
┌────────────┼────────────┐
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ B. 查天气 │ │ E. 查政策 │ │ C. 订机票 │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
│ │ ┌──────┴──────┐
│ │ ▼ ▼
│ │ ┌─────────┐ ┌─────────┐
│ │ │ D. 订酒店│ │F. 约打车│
│ │ └────┬────┘ └────┬────┘
│ │ │ │
└──────┬──────┘ └─────┬──────┘
▼ ▼
┌─────────────────────────────────┐
│ G. 发送行程 │
└───────────────┬─────────────────┘
▼
┌──────────────┐
│ H. 写日报草稿│
└──────────────┘
DAG 设计的关键决策点
- 并行与串行判断
A(查日历)是所有任务的先行条件——如果周二有全天会议,直接终止后续流程并提醒用户。A 完成后,B(查天气)、E(查政策)、C(订机票)三个完全互不依赖,编排引擎会同时发起三个异步调用,大幅缩短总耗时。
- 条件分支:A 的检查逻辑
A 执行完后,编排引擎检查输出 has_conflict。如果为 true,整个 DAG 在 A 节点就中断,引擎生成一个澄清问题:“您周二已有全天会议,是否仍然需要安排?”用户确认后再继续。这种条件分支不需要硬编码在 Skill 里,而是作为 DAG 边的路由规则配置在编排层。
- 多级依赖链
C(订机票)成功后,D(订酒店)和 F(约打车)才能执行——D 需要知道航班到达时间来确定入住时间,F 需要落地时间。这两者之间无依赖,所以订机票完成后,订酒店和约打车又并行发起。
- 非关键路径降级
B(查天气)和 E(查政策)不是必须成功的路径。如果天气 API 挂了,G(发送行程)用默认提示“请关注当地天气”代替具体温度;如果政策 API 超时,挂一个标记让用户自行确认。在 DAG 配置中,这两条边标记为 weak_dependency,失败不阻塞后续。
- 最终汇聚与收尾
G(发送行程)需要等待 B、E、D、F 全部完成(或部分降级),汇总所有信息生成行程邮件。H(写日报草稿)只依赖 G,因为需要确认行程已发送,日报里要附上邮件链接。
执行过程中的断点恢复
假设在 D(订酒店)执行后,酒店涨价超出用户预算,D 返回 WAITING_USER_INPUT 状态,询问用户是否接受溢价。编排引擎暂停整个 DAG,把当前执行快照(已完成:A、B、C、E,等待确认:D)序列化存 Redis。用户回复“接受”后,引擎从 Redis 加载快照,从 D 的断点继续,随后并行触发 F,最后汇聚到 G 和 H。