公司动态

前台语音与后台任务为什么要做双循环:从委派到结果新鲜度

📅 2026/8/11 18:25:39
前台语音与后台任务为什么要做双循环:从委派到结果新鲜度
前台语音与后台任务为什么要做双循环从委派到结果新鲜度一个迟到结果如何变成事故用户对语音 Agent 说“帮我找上海周末适合孩子的活动。”系统把搜索交给后台前台没有卡住还能自然回应“好我查一下你可以继续补充要求。”两秒后用户补充“不要室外的最好周日下午。”又过几秒用户接到电话改口说“算了先帮我记一下晚点看。”十秒后第一轮搜索成功完成。结果本身没有任何事实错误它确实找到了上海周末亲子活动。但语音 Agent 突然打断电话把室内和室外活动混在一起念了一遍。从后台任务看这是一次成功从用户体验看这是三次失败结果对应旧条件交付时机错误用户已经撤回了立即播报的意图。这类问题不能靠“把请求放进线程池”“换成消息队列”或“用更强模型”解决。异步执行只是让前台不必等待真正困难的是后台完成以后谁有权决定这个结果是否仍属于当前会话、是否仍满足当前目标、是否应该现在出现以及已经发生的外部副作用怎样处理。OpenAI 对 GPT-Live 的公开描述确认了一条重要方向连续交互由前台语音模型维持搜索、深度推理和更复杂的 Agent 工作可以委派给后台模型后台运行时对话仍可以继续。[S1] 但官方没有公开内部任务字段、状态机或消息协议。本文讨论的是实现类似体验时需要显式解决的工程合同不是对 GPT-Live 私有架构的猜测。全文只沿一条判断链展开后台完成只是一个事件版本化任务信封必须重新证明结果仍属于当前目标前台才决定是否以及怎样交付。后面的双状态机、五道准入门、取消、重试、指标和失败注入都是这一个任务信封在不同阶段的读取与验收方式不是六套并列框架。一、异步只搬走等待没有解决结果归属传统串行语音链路通常是听完用户输入调用工具等待工具完成再生成和播放回答。它的问题很直接——后台任务耗时越长前台越像断线。最自然的改造是异步化前台提交一个任务立即恢复收音后台继续搜索、推理或执行工具完成后再发回结果。OpenAI Responses API 的 Background mode 就提供了这种公开能力任务可以异步运行调用方通过 Response 对象轮询状态也可以取消进行中的后台 Response。[S2]但“异步”通常只改变执行位置没有自动建立两个循环之间的语义关系。很多系统仍保留一个危险假设task completed - append result to current conversation - speak这个箭头同时偷掉了五个判断完成的是否还是当前任务任务目标是否已经被用户修改结果依赖的数据是否仍有效当前是否适合打断用户结果是否已经交付过或者是否带有不可重复的副作用。因此真正的双循环不是“前台一个线程、后台一个线程”而是两个拥有不同目标、时间尺度和完成条件的控制循环。循环首要目标典型时间尺度主要状态成功条件前台交互循环让当前交流可理解、可中断、可继续毫秒到秒当前话题、话权、用户最新意图、播放状态用户在当下获得合适反馈后台任务循环把搜索、推理或业务工作可靠完成秒到分钟甚至更久任务身份、输入快照、执行进度、工具副作用、结果工作按任务合同完成或明确失败二者必须解耦否则长任务会冻结前台二者又必须重新连接否则后台会带着旧目标自由返回前台只能被动接收。二、事故根因执行时钟与意图时钟持续分叉后台任务启动时拿到的是某个时刻的目标快照。前台会话却没有停在这个快照上用户可能继续补充条件、修正实体、取消操作、开启第二个任务甚至离开当前话题。所以系统里至少存在两个时钟。第一个是执行时钟。它描述任务已经排队、运行、调用了哪些工具、生成了哪些中间结果、是否完成。第二个是意图时钟。它描述用户当前想解决什么问题、哪些约束已经改变、旧任务是否仍有意义、结果应该怎样交付。如果只看执行时钟任何COMPLETED都会被当成成功。如果只看意图时钟后台可能因为每次用户插话都被盲目重启造成浪费、重复副作用和永远无法完成。可靠系统要做的是把二者显式比较而不是假设它们自动一致。最小判断可以写成deliverable completed task_identity_matches task_version_matches freshness_policy_passes side_effect_state_is_known delivery_policy_allows_now这里的task_id、task_version等名称是本文建议的工程字段不是 OpenAI 内部 Schema。它们的价值在于让“为什么不播报”成为可解释决策而不是让一个迟到回调直接支配当前会话。三、全文主模型版本化任务信封很多实现只给后台队列传一个conversation_id完成后再读取这段会话的最新消息。这个设计看似灵活实际上把任务目标变成了一个不断移动的指针后台无法证明自己究竟为哪一版需求工作前台也无法判断结果对应哪一版输入。更稳妥的做法是为每次可独立完成的工作建立稳定任务身份并保存启动时的目标快照。一个最小任务信封可以是task_id:task_8f21task_version:3conversation_id:conv_42parent_event_id:evt_user_190goal:type:family_activity_searchsummary:上海周日下午室内亲子活动snapshot_hash:sha256:...execution:status:runningcreated_at:2026-08-09T10:00:0008:00deadline_at:2026-08-09T10:00:3008:00cancel_requested_at:nullside_effect_class:read_onlyfreshness_policy:require_current_task_version:truemax_result_age_seconds:60dependency_versions:location:shanghaidate_window:2026-08-09/2026-08-10delivery_policy:mode:wait_for_floorinterrupt_priority:lowallow_notification:true这些字段分成四类职责。1. 身份字段回答“这是谁的结果”task_id在任务整个生命周期中稳定task_version在用户修改目标时递增parent_event_id把任务和发起它的用户事件连接起来。后台返回时必须携带这些身份不能只说“搜索完成”。2. 目标快照回答“它做的到底是哪件事”摘要方便人读结构化条件和 hash 用于机器比较。这里不要求把完整对话复制到每个任务而是固定与任务正确性有关的条件。如果用户把“周末”改成“今天”系统应能指出旧任务哪一项依赖已经失效。3. 执行字段回答“取消和副作用进行到哪里”读操作和写操作不能共用同一取消语义。搜索任务取消后最多浪费计算付款、发邮件或创建工单可能已经产生外部效果。side_effect_class至少要区分只读、可幂等写入、可补偿写入和不可逆写入。4. 新鲜度与交付字段回答“现在还能不能说”TTL 只是其中一个条件。一个两秒前完成的结果如果对应旧城市也已经过期一个十分钟前完成的航班延误查询如果数据版本仍有效可能仍可展示。新鲜度必须由业务依赖和当前目标共同决定。四、任务信封怎样吸收用户的新输入后台任务运行时前台收到的新输入至少要分成五类。分类错误比后台模型答错更常见。用户输入例子对后台任务的默认动作是否递增任务版本状态查询“查到哪了”保持任务读取进度或给出诚实等待说明否目标修订“不要室外的”修改目标能增量更新则派生新版本否则取消旧版并重启是明确取消“不用查了”发出取消请求前台立即停止承诺交付通常是并行新任务“顺便查一下停车”新建独立任务并建立依赖或并行关系新任务独立计数话题切换“先聊别的”任务可继续、暂停或取消由交付策略决定不一定关键是“先分类再动作”不能把所有用户补充都追加到同一个 Prompt。例如“不要室外的”不是新的闲聊消息而是旧任务的约束修订。如果后台支持增量搜索可以创建task_version2并复用仍有效的中间结果如果不支持就应让版本 1 进入SUPERSEDED启动版本 2。无论采用哪条路线版本 1 的完成事件都不能直接进入前台。“先聊别的”也不自动等于取消。用户可能仍希望稍后收到结果只是不想让搜索阻塞当前话题。这时任务继续运行但交付方式从speak_when_ready改为notify_or_save比盲目取消更符合意图。五、完成事件为什么必须进入交付状态机最容易出错的状态机只有四个状态PENDING - RUNNING - SUCCESS/FAILED。它适合描述执行器不足以描述对话系统。双循环至少需要两组状态。执行状态PROPOSED - ACCEPTED - RUNNING - COMPLETED | | | - FAILED - CANCEL_REQUESTED - CANCELLED | - CANCEL_UNCONFIRMED交付状态RESULT_RECEIVED - ELIGIBILITY_CHECK |- READY |- STALE |- SUPERSEDED |- DUPLICATE |- REQUIRES_CONFIRMATION READY - DELIVERED | DEFERRED | SAVED | DISCARDED这两个状态机拆开后一个任务可以执行成功但交付为STALE也可以执行失败但前台给出有价值的恢复建议还可以取消请求未及时传播但前台已经停止承诺结果并在后台继续追踪未知副作用。“完成不等于交付”是整篇文章最重要的边界。完成事件只能触发准入检查不能直接触发 TTS。六、怎样读取任务信封五道准入检查第一关身份是否匹配结果必须绑定稳定task_id事件必须绑定唯一event_id或等价身份。OpenAI Webhooks 官方文档明确说明失败会触发指数退避重试少数情况下可能重复投递同一事件可以使用webhook-id去重。[S3]因此Webhook、消息队列或轮询观察到同一完成状态时消费端必须幂等。去重键应该防止重复改变业务状态而不是只防止日志重复打印。第二关目标版本是否仍是当前版本如果用户已经把上海改成杭州旧搜索即使完成也不能播报。这里不能用“最后完成者获胜”因为耗时更长的旧任务往往最后返回。应以目标版本或单调序号决定谁有资格推动前台。第三关依赖和时间是否仍新鲜新鲜度不是一个统一的expires_at。天气、库存、价格、路线、权限、用户位置和会话目标都有不同失效规则。任务应该记录它依赖哪些版本返回时只重查会改变结论的依赖而不是无条件相信缓存或无条件全部重算。第四关副作用状态是否已知如果后台只是搜索过期结果可以丢弃。如果后台已经发送邮件、提交订单或控制设备丢弃回答并不能撤销事实。结果准入前必须知道外部动作是未开始、已提交、已确认、未知还是已补偿。第五关现在是否适合交付内容正确不代表此刻应该打断。用户可能正在说话、接电话、执行高风险确认或已离开会话。前台要根据优先级和当前话权选择立即打断、等待自然停顿、先给一句摘要、发送通知、存入任务中心或者静默丢弃。这五关共同决定结果“可交付”其中任何一关失败都不应让后台完成事件直接进入播放器。七、副作用边界之一取消是一条传播链OpenAI Background mode 提供对进行中 Response 的取消并说明重复取消是幂等的。[S2] 这对模型执行层很有价值但应用系统不能把它解释成“所有工作都已经撤销”。一个后台任务可能已经经过前台意图 - 任务调度 - 模型推理 - 工具调用 - 外部系统 - 回调 - 结果交付用户说“取消”时至少要分别记录前台是否已经接受取消意图调度器是否停止派发新步骤模型或 Workflow 是否收到取消正在运行的工具是否支持协作停止已产生的副作用是否需要补偿迟到结果是否被隔离用户是否得到诚实确认。Temporal 的官方文档提供了一个清晰参照Workflow 取消是可处理、可清理的协作式请求Activity 只有发送 heartbeat 并设置 heartbeat timeout才有机会收到取消。Terminate 则是立即停止、不给 Workflow 清理机会的另一种语义。[S5]这说明“发出 cancel”与“执行已停止”必须分开。对用户的表达也要分级已收到取消请求可以说“我正在停止”后台已确认停止且无副作用可以说“已经取消”外部动作状态未知必须说“任务已停止继续处理但刚才的提交状态还在确认”副作用已发生不能说取消成功只能进入撤销或补偿流程。对不可逆动作最可靠的设计往往不是更强取消而是在提交前增加确认门槛把后台任务限制在“准备方案”由前台在用户确认后才执行。八、副作用边界之二重试必须服从业务幂等连接断开、Webhook 超时或工具返回 5xx 时系统很容易选择自动重试。但“没收到成功响应”不等于“对方没有执行”。RFC 9110 的边界很明确客户端不应自动重试非幂等请求除非它知道请求语义本身是幂等的或者能够确认原请求没有被应用。[S6]这对 Agent 工具尤其重要。以下三种调用不能混在同一重试策略中操作示例建议只读搜索、查询天气可在限次与截止时间内重试幂等写入以稳定业务键更新草稿携带幂等键服务端返回同一操作结果非幂等或不可逆转账、发消息、控制设备未确认原操作状态前不得盲目重试一个常见事故是前台因超时重新提交任务后台两个版本都成功发送邮件系统只保留第二个结果于是界面看起来正常收件人却收到两封。正确做法不是只在队列层去重而是把稳定operation_id传到真正产生副作用的服务端并记录外部系统返回的业务标识。九、准入通过后前台仍要选择交付方式语音 Agent 最容易滥用的动作是后台一完成就抢到话权读结果。实际上交付至少有六种方式。立即打断只适合高优先级、强时效、用户明确等待的结果例如安全告警。等待自然停顿适合普通搜索和推荐不破坏当前发言。先给摘要结果很长时先说结论再询问是否展开。请求确认结果会触发高风险动作或目标可能变化时先确认再执行或播报。通知或任务中心用户已切换话题、离开语音会话或不适合打断时保存并提醒。静默丢弃任务已取消、被新版本替代、结果重复且没有审计价值时不进入用户界面。交付策略应在任务启动或用户修改意图时确定并允许前台更新。它不能由后台模型根据“我已经做完了”自行决定。十、怎样观察这条判断链是否真的有效后台任务成功率很高仍可能对应糟糕体验。至少需要四组指标。1. 目标一致性过期结果注入率已被修改、取消或替代的结果仍进入前台的比例版本命中率交付结果与当前task_version一致的比例依赖失效发现率价格、位置、权限等变化是否在交付前被识别。2. 取消可靠性取消请求接受延迟调度停止延迟工具停止确认延迟CANCEL_UNCONFIRMED占比取消后副作用发生率。3. 幂等与重复重复完成事件率去重命中率重复副作用率同一任务多版本并发完成率。4. 交互质量后台完成后到合适交付时机的延迟不必要打断率用户主动追问进度率长结果二次展开率用户切换话题后仍被旧结果打断的比例。这些指标必须能按conversation_id - task_id - task_version - event_id - operation_id - delivery_id串起来。否则事故复盘只能看到“任务成功”和“用户不满意”两个互不相连的事实。十一、再用八个失败注入验证状态边界场景注入方式通过条件用户修订目标任务运行中修改地点或时间旧版本结果不得播报新版本可解释地接管用户取消完成前与完成瞬间分别取消取消与完成竞态有确定决策不按到达顺序碰运气重复回调同一完成事件投递两次业务状态与副作用只推进一次回调乱序版本 2 先完成版本 1 后完成版本 1 进入 superseded不覆盖当前结果工具超时但已执行模拟写操作响应丢失不自动重复副作用先查询 operation 状态前台断线后台运行时关闭语音连接任务按策略继续或取消恢复后不会重复交付结果过期修改依赖版本或推进时钟准入门拒绝旧结果必要时重算或请求确认用户正在说话完成事件在长发言中到达普通结果等待话权高优先级结果按策略处理如果系统只测“后台能否完成”它验证的是执行器只有覆盖目标变化、取消竞态、重复投递、乱序和副作用才是在验证双循环。十二、按风险分四步上线而不是一次造完所有组件完整 Workflow、事件溯源和补偿事务并不适合所有团队。可以按风险逐层落地。第一阶段稳定身份与交付隔离为每个后台任务分配task_id和版本后台结果只能进入准入检查不能直接触发 TTS。先把旧版本结果污染率降到零。第二阶段取消确认与幂等消费区分取消请求和取消完成Webhook、消息队列和轮询统一以事件身份去重。所有重试先按只读、幂等写入和非幂等副作用分类。第三阶段依赖感知的新鲜度记录目标依赖和截止时间。高变化数据在交付前轻量复核避免只用统一 TTL。第四阶段交付策略与多任务再加入立即打断、等待话权、摘要、通知和任务中心。只有单任务版本化稳定后才开放多个后台任务并发否则复杂度会成倍放大。十三、什么时候应当退回简单串行链路双循环会增加任务存储、状态机、去重、取消、补偿、观测和交互策略成本。以下场景更适合简单串行链路任务通常在一两秒内完成等待不会破坏体验用户必须逐步确认字段不能在后台自由推进操作高风险且不可逆任何并行都会增加误执行概率业务不需要在会话外保存或恢复任务团队尚不能可靠处理幂等键、任务版本和副作用审计。对于这些场景清晰地说“我需要几秒钟请稍等”可能比伪装成自然连续交互更可靠。双循环的价值不是让架构更先进而是在实时交流和长任务确实同时存在时避免两者互相阻塞或互相污染。结论完成属于后台交付属于当前前台GPT-Live 的后台委派方向让语音 Agent 可以同时追求自然交流和复杂任务能力。但一旦前台会话继续向前后台结果就不再天然属于“当前”。真正可靠的系统不会把COMPLETED直接翻译成“现在说出来”。它会先问这是哪个任务、哪一版目标、依赖是否仍有效、取消是否收敛、副作用是否明确、现在怎样交付最合适。前台循环负责维护当下的交流与意图后台循环负责可靠完成工作。二者通过版本化任务身份、协作式取消、结果新鲜度、幂等事件和交付策略连接。只有做到这一步“后台执行时仍可继续对话”才不是演示层的并发而是生产级的连续交互。参考资料[S1] OpenAI, Introducing GPT-Live: https://openai.com/index/introducing-gpt-live/[S2] OpenAI API, Background mode: https://developers.openai.com/api/docs/guides/background[S3] OpenAI API, Webhooks: https://developers.openai.com/api/docs/guides/webhooks[S5] Temporal Java SDK, Workflow cancellation: https://docs.temporal.io/develop/java/workflows/cancellation[S6] RFC 9110, HTTP Semantics, Section 9.2.2: https://www.rfc-editor.org/rfc/rfc9110.html#section-9.2.2事实边界已确认GPT-Live 官方发布页确认连续交互与后台委派方向OpenAI 公共 API 文档确认 Background mode、取消、轮询/恢复流、Webhook 重试和去重边界Temporal 与 RFC 提供协作式取消和重试语义的公开参照。作者工程设计任务信封、目标版本、双状态机、五道准入门、交付策略、指标和失败注入均为实现类似系统的建议不代表 OpenAI 私有协议。未知项GPT-Live 内部任务消息格式、调度器、取消传播、存储、模型拓扑、结果新鲜度字段和前后台模型间通信机制未公开。