如何设计可取消、可恢复的异步大模型长任务系统?
先用自己的话答,再看参考说法
60 秒是练习上限,不是必须凑满。原理题讲清因果,设计题讲清约束,项目题只讲真实证据。
别照着背。参考说法只用于对照;直接回答问题,简单题说清楚就收尾。项目题只用自己的经历和数字。
参考内容当前已显示;开始口述后会暂时隐藏。
面试时怎么答
把长任务建模成资源,而不是延长 HTTP 超时:提交返回 job id,Worker 用租约消费,阶段结果写检查点,客户端查询或订阅状态。取消也应是状态转换,并由 Worker 在安全点响应。追问消息重复投递时,要说明副作用幂等;追问进程故障时,再讲心跳、租约过期和从一致检查点恢复。
可以这样答:
异步长任务应当建模为有状态的 Job:提交后立即返回 job id,Worker 通过租约领取任务,执行过程中写心跳、进度和阶段性检查点,客户端通过查询或事件订阅获取结果。取消请求只改变状态,Worker 在安全点停止。由于队列常是至少一次投递,外部副作用必须幂等;Worker 崩溃后由租约过期触发接管,并从一致检查点恢复。
核心回答
提交接口先完成鉴权、配额和参数校验,写入任务记录后立即返回 job ID;队列只传任务引用,worker 从持久状态读取固定的输入与发布版本。任务状态至少包含 queued、running、succeeded、failed、cancelling、cancelled,并带单调版本号。长步骤保存 checkpoint,worker 用 lease/心跳声明所有权;超时后任务可以重放,因此外部副作用必须使用幂等键或去重表,不能假设消息系统提供端到端 exactly-once。
用户通过轮询、流式事件或签名 webhook 获得进度。取消是协作式的:控制面写取消意图,worker 在安全点停止后续模型与工具调用,清理租约并保存可解释的最终状态。
展开说明
关键设计点包括:
- 提交幂等:客户端重试同一 idempotency key 应返回原 job,而不是重复计费和执行。
- 版本固定:模型、Prompt、工具 Schema 与输入对象版本在创建时冻结,恢复任务不能悄悄换到最新版本。
- 预算与截止时间:设置最大 token、步骤、墙钟时间和费用;每个子调用共享剩余预算,而不是各自完整重试。
- 结果存储:大结果进入对象存储,任务表只存位置、摘要、校验和与保留期;下载继续按原用户鉴权。
- 故障语义:区分可重试基础设施错误、确定性参数错误和需要人工处理的业务冲突,进入有界重试或死信队列。
进度百分比若无法可靠估计,应报告已完成阶段和最近心跳,避免伪精确。
工程实践
采用事务 outbox 或等价机制保证“任务记录已写入”和“待执行事件可见”不会只完成一半。故障注入覆盖 worker 被杀、重复投递、模型超时、取消与完成竞态、webhook 重放和对象过期。指标包括排队时长、运行时长、各阶段重试、恢复次数、取消生效延迟、每成功任务成本和死信数量。
常见追问
- 为什么队列消费成功不等于业务只执行一次? 至少一次投递下,确认丢失或租约超时会让同一消息再次消费;业务副作用需要幂等键和唯一约束。
- 任务取消与 worker 完成同时发生时,状态怎样收敛? 用带版本的条件更新定义终态优先级,只允许一次状态转换成功,并让迟到结果按规则丢弃或保存为非正式产物。
- 恢复长任务时为什么必须固定模型和 Prompt 版本? 中途换版本会使前后阶段语义不一致,破坏可复现和审计;若必须升级,应创建新的任务版本并显式迁移。
一句话复习
长任务用持久状态机、幂等副作用、租约与 checkpoint 抵抗重放,并让预算、取消和版本贯穿全程。
参考资料
评论与补充
评论会直接显示在这道题下面。可以写自己的答法、继续追问或指出错误,不需要 GitHub 账号,也不会跳转到 Issue;内容会公开,请勿填写个人隐私、公司机密或受保密约束的材料。
正在连接站内评论服务…
正在加载评论…
还没有评论,你可以先写下自己的理解或追问。