notebooklm-py 研究任务等待完全指南用轮询、取消与两层状态机搞定 Deep Research【免费下载链接】notebooklm-pyUnofficial Python API and agentic skill for Google Gemini Notebook. Full programmatic access to Gemini Notebooks features—including capabilities the web UI doesnt expose—via Python, CLI, and AI agents like Claude Code, Codex, and OpenClaw.项目地址: https://gitcode.com/GitHub_Trending/no/notebooklm-py一个 Deep Research 任务已经跑了十几分钟你的脚本停在等待循环里只能问一句它到底还在不在跑notebooklm-py 是一个非官方的 NotebookLM Python API 与 CLI它的研究任务解析器负责把 POLL_RESEARCH 原始报文解码成结构化任务再用一套两层状态机驱动长时 Deep Research 的轮询、取消与结果取用——把等多久、怎么停、失败了怎么办这几个问题一次说清。先讲目标一次可靠的等待要兜住什么等待长时任务的本质不是睡一会儿而是随时分清自己处在三种结果中的哪一种并给每一种配一个不同的动作。在 NotebookLM 里Research 是让后端替你去搜 web 或翻 Google Drive 文档再把发现导入笔记本。fast 模式秒级出结果deep 模式Deep Research则是货真价实的长时任务——异步管线在后台执行可能跑上几分钟期间客户端手里只有两个动作轮询、取消。所以一次可靠的等待要兜住三态进行中任务在后台跑客户端保持轮询、不去打扰终态成功结果落地调用方去取来源列表或报告正文终态的失败 / 取消 / 无结果最容易翻车的地方。若失败只是一个笼统的 failed调用方分不清是查询词太窄该换词、该重试、还是被人取消了——后两者对应完全不同的下一步。研究任务解析器正是为这第三种情况设计的。状态码速查表一张解码词典状态码表是整个状态机的解码词典它的每个词条都来自真实抓包而非推测。后端把真实状态藏在报文的 task_info[4] 槽位里notebooklm-py 逐个确认了各码含义完整观测记录见 docs/rpc-reference.md。状态码含义termination_reason观测来源与处理1任务进行中in_progress任务落定前每次轮询都会遇到2完成且带结果completedfast web、fast Drive 与 deep 运行中均见过3无匹配结果零来源no_results仅在 Drive 运行中观测到按查询问题对待不当系统错误4经 CANCEL_RESEARCH 取消cancelled来自中途取消的 deep 运行6推测的完成码completed从未真实观测到仅做兼容保留表里藏着两个工程决策**码 3 不是错误。**它伴随一个空的来源包出现说的是Drive 里没搜到文件——问题出在查询而不是系统故障**不认识的码不猜。**这套 Google 内部协议没有文档、随时可能变陌生码一律落成 unknown。因为猜错的代价远比承认不知道要高。两层状态为什么要拆开把一个事实拆成两层——粗层只管兼容、细层只管行动且两层必须从同一张码表派生——是这个设计的关键。两层状态机定义在 src/notebooklm/_types/research.py第一层 ResearchStatus粗粒度in_progress / completed / failed / no_research / not_found。它存在的意义是向后兼容老代码里检查 status failed 的分支继续成立第二层 ResearchTerminationReason细粒度in_progress / completed / no_results / cancelled / unknown把粗化过程中丢掉的信息找回来。两层共享同一事实源termination_reason_from_code 先把原始码翻译成终止原因status_from_termination_reason 再把原因粗化成生命周期状态。于是status 说成功、reason 却说未知这种自相矛盾的组合在类型层面就构造不出来。再往前一步ResearchTask 还会从这两层派生面向用户的解释与修复建议reason_message 与 hint无结果 搜的是 Drive → 建议改用精确文件名、文档 URL 或文档 ID无结果 搜的是 Web → 建议换一组更宽泛的查询词被取消 → 提示若还需要这些来源请重新启动研究。也就是说一个 deep 任务失败或被取消之后你拿到的不是冷冰冰的failed两个字而是一句告诉你下一步该做什么的话。怎么等、怎么停wait_for_completion 的默认参数全是为长时 Deep 任务做的取舍而取消是个完全没有回执的操作可靠的做法是把复核写进契约。wait_for_completion 的三个默认取舍轮询间隔默认 5 秒initial_interval 可调不给配额制造无谓压力总超时默认 1800 秒30 分钟足以覆盖绝大多数 deep 运行的真实时长到期抛 ResearchTimeoutError 结束等待任务锁定pinning首次轮询拿到具体 task_id 后之后的每次轮询都带上这个 id 当判别器。就算同一个笔记本里又起了一个并行研究任务它的结果也混不进当前等待循环。还有一个容易被忽略的细节已锁定的任务某次轮询返回 NOT_FOUND 时循环不会就此退出而是把它当作复制延迟下的瞬态状态、继续等——长时任务的状态本身就可能慢半拍才出现。停的这边取消是个fire-and-forget操作请求发出去服务端不回任何回执——空响应无条件返回连 run_id 都不校验。怎么确认取消真的生效了唯一的办法是取消之后再 poll 一次几秒内任务状态会翻成 failed终止原因 cancelled码 4。就像拔了插头还得回头确认设备真的停了才能走。对已处于终态的任务取消是静默空操作重复调用安全幂等。deep 任务另有一个专属坑start() 返回的 task_id 其实是个 sessionId拿它去取消会静默失败任务照跑不误真正能停掉 deep 运行的是 start 返回的 report_id或 poll 暴露出的 task.task_id——两种模式下服务端都接受后者。解析器如何扛住脏报文解析器的原则很朴素分清哪些槽位保证存在、哪些允许降级再用类型层防御把脏报文挡在状态机外面。解析逻辑在 parse_research_task_models配套行适配器在 src/notebooklm/_web/rows/research.py保证槽位按错误处理task id 或 info 块缺失说明报文真的漂移了明确抛错不硬撑可选槽位按 None 降级URL、摘要、时间戳缺了只填 None返回的任务对象依然可用类型防御数值槽位显式拒绝 bool——bool 是 int 的子类不设防的话报文里的 true 会被悄悄吞成状态码 1保留原始码ResearchTask.status_code 把 wire 码原样留着调用方仍能看出它到底是哪一类 failedCLI 的 JSON 输出形状也不受扰动保持字节级稳定。收尾三条可以带走的设计原则把这套实现翻一遍有三条值得抄进自己的长时任务代码**粗层只管兼容细层只管决策。**两层必须出自同一张码表——同源才不会出现自相矛盾的状态。**没观测到就别装懂。**面对未文档化的协议诚实的 unknown 永远比自信的猜测安全。**没有回执的操作复核一步才算做完。**像取消这种 fire-and-forget把取消后再轮询一次写进 API 契约里才是最后一道防线。有了这层解析器Python 脚本、CLI 与 AI Agent 都能放心地启动、等待、取消一个可能跑上几分钟的 Deep Research 任务而不用自己去啃原始 RPC 报文。【免费下载链接】notebooklm-pyUnofficial Python API and agentic skill for Google Gemini Notebook. Full programmatic access to Gemini Notebooks features—including capabilities the web UI doesnt expose—via Python, CLI, and AI agents like Claude Code, Codex, and OpenClaw.项目地址: https://gitcode.com/GitHub_Trending/no/notebooklm-py创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?