Gemini Live API 会话恢复为何遗漏最后一轮对话?
从日志看,较可能是恢复句柄没有包含最后一轮完整的模型回答。session_resumption_update 不会在每轮对话结束时都作为“保存完成”通知触发;它表示服务端在某个时点提供了可恢复状态。你的代码只在收到有效更新时写入文件,因此如果最后一轮之后没有新的有效更新,文件中保存的仍是此前收到的句柄。
为什么会少掉最后一轮
你的代码在接收流时处理句柄更新:
if response.session_resumption_update and response.session_resumption_update.resumable and response.session_resumption_update.new_handle:
save_handle(response.session_resumption_update.new_handle)
日志显示,Also remember numbers 6, 7, 8 之后确实打印了一个 handle,但它出现在模型回答这组数字之前。仅凭这个顺序,无法确认该句柄是否包含了这轮已经完成的全部对话;日志也没有显示模型回答结束后又收到更新。
Live API 文档说明,句柄由服务端通过 SessionResumptionUpdate 提供,应保留最新的可恢复句柄。会话在某些状态下无法恢复,例如模型正在生成内容时;此时更新可能会标记为不可恢复。文档没有承诺每个用户回合结束后都会发送新句柄。Session management WebSockets API reference
记录每次句柄更新
先记录所有更新,包括不可恢复的更新,以确认句柄是在最后一轮回答的哪个阶段到达的。不要只打印有效句柄:
update = response.session_resumption_update
if update is not None:
print(
"session resumption update:",
"resumable=", update.resumable,
"has_new_handle=", bool(update.new_handle),
)
if update.resumable and update.new_handle:
save_handle(update.new_handle)
print("Saved resumable handle")
还要记录每次保存的时间,以确认 last_session_handle.txt 最终对应哪次更新。重新连接时传入最近一次有效句柄。如果服务端没有发出更新,客户端就无法从这段代码中推导出更新后的句柄。
需要精确保留最后一轮时
如果业务要求恢复后一定能看到完整的问答内容,就应在应用侧保存对话记录,并在恢复时按需补发尚未包含在恢复状态中的内容。句柄更新是服务端提供的恢复点,不能保证每条消息都已持久化。补发时要避免重复发送已包含在恢复上下文中的消息。
你可能并没有漏掉代码中的某个句柄字段检查。更可能的情况是,服务端没有在最后一轮完成后发出新的可恢复句柄,或者最后收到的句柄对应的状态还没有包含完整回答。现有日志无法判断具体是哪一种;记录更新状态和时间可以进一步确认。
备注:内容仅供参考。
