Sanjaya 是什么
Sanjaya 是一个开源 Python 库(uv add sanjaya),受 Recursive Language Model(RLM)agent 启发,构建用于多模态理解:视频、文档和图像。核心思路不同于传统方式:不是给模型 prompt 让它回答问题,而是让模型写一个 Python 程序来回答问题。
这个程序在沙箱 Read-Eval-Print Loop(REPL)里搜索 transcript、提取视频片段、采样帧、查询视觉模型、迭代——所有操作都不需要你手动管理。
RLM 的背景
2026 年 4 月初,Alex Zhang 等人发表了 RLM 论文,核心思想:
不要把长上下文塞进 prompt,而是给模型一个 Python REPL,让它写代码去查找。
论文命名了三个让 RLM 工作的属性:
- 文本留在 REPL 里:五本小说(约 220 万 token)不在 prompt 里,而是被索引,模型只通过代码读取它实际需要的那些段落作为引文,最终答案里只出现它引用过的内容
- 变量在轮次之间持久化:REPL 是一个长会话,模型构建
candidates列表、往evidence字典里添加内容、更新早期条目——当新的引用出现时,对应的条目被追加或更新 - 模型可以调用自己:
llm_query()对较小的模型运行一次 prompt,rlm_query()为子问题生成一个完整的子 RLM(自己的 REPL、自己的工具、自己的循环)
Sanjaya 的实现
Sanjaya 实现了全部三个属性:
- 符号化工具(symbolic handles):
search_documents()、search_transcript等 - 持久化状态:MontyRepl 会话,变量在迭代间保留
- 递归:
llm_query和rlm_query
关于 Context Rot
当今前沿模型(Opus、Codex 等)最大的约束之一是 context rot。Chroma 的技术报告发现:模型性能随输入长度变化显著退化,即使在简单任务上也是如此。实际表现:会话越长,模型表现越差,新会话通常能修复这个问题。
传统解法是 RAG。但 RAG 的问题在于:它要求你在开始之前就承诺一个检索策略。"找出比赛中的得分时刻"和"总结演讲者的论点"需要不同的 chunking、不同的 ranking、不同的 top-k。单一 pipeline 迫使问题适应一个不适合任何问题的通用形状。
对于视频,还有额外的差距:embedding 实际上触不到视觉内容。Captioning-then-indexing 能抓到文字图像里的文本,但"相机对准的位置"这个信号不是 caption 模型优化的目标。
测试结果
PhotoBench(图像)
PhotoBench 用自然语言对个人相册提问,如"哪些照片是在海滩拍的?""在厨房做晚餐""贵阳的夜间行人街道"等。在三个相册上跑了 60 个查询(每相册 20 个):
- MRR(平均倒数排名)在所有三个相册保持在 75% 以上(92.1%、75.1%、88.9%)
- 相册 1 达到 98.9% 召回率 @ 80% 精确率
- 召回率在所有相册保持在 86-99%
失败案例:精确率降到 53-61%,当查询需要的元数据工具没有暴露时——如"巴黎的照片"需要 GPS、"和 Sarah 的合照"需要人脸识别、"去年圣诞节的照片"需要日历数据。模型试图从像素推断,过度包含。
Video
没有 ground truth,没有自动化评分,只有 demo prompt 和 LongVideoBench clips。
成功案例:K-pop 表演视频(无可用 transcript),Sanjaya 通过帧采样确认了舞者数量和概貌。LongVideoBench 选择题,Sanjaya 给出了正确的场景序列(只是回答格式用了描述性箭头而非选项字符串,被评分器判定错误)。
失败案例:找出 Steph Curry 比赛里的每一个三分球。五次运行返回了 9、9、19、21、26 个三分,而实际数字约 114 个(不计重播)。每次都严重低估,因为模型采样的 transcript 和部分帧无法完成穷举。
成本对比(估算)
对 50 分钟视频问一个问题:
- Gemini 2.5 Flash:最便宜 $0.30,但每次问题都要重新读取整个视频
- Twelve Labs:如果你要对同一个视频库问数百个问题最便宜,索引成本可摊薄
- Sanjaya:简单 transcript 问题最便宜,穷举视觉工作最贵,无前期索引成本
四个工程决策
1. 保持工具表面小
暴露的每个工具都是替模型做的策略决定。没暴露的工具强制模型自己在 Python 里写策略。最初有 10 个视频工具,剪到 7 个。去掉的是:regex over transcript 结果、时间戳算术、列表聚合——模型用 Python 都能做,而且能做得比预设形状更好。保留的是 ffmpeg 剪辑提取、vision API 调用、字幕解析——这些是沙箱本身无法提供的 I/O。
规则:包装沙箱无法提供的东西(I/O、外部 API、二进制程序)。其他一切(循环、条件、聚合、格式化)模型自己写。
2. 在 prompt 里放什么
prompt 里有五本小说约 220 万 token。模型通过代码读取,不在 prompt 里。模型只看到它在最终答案里引用的那些段落。
3. 持久化 REPL vs 每次调用重启
MontyRepl 是一次长会话。变量在迭代间保留。模型构建 candidates 列表,追加到 evidence 字典,用新发现更新早期条目。
4. llm_query vs rlm_query
llm_query() 对较小模型运行一次 prompt。rlm_query() 为子问题生成整个子 RLM(自己的 REPL、自己的工具、自己的循环)。对于四个候选,模型可以并行 fan out:一个子 RLM 处理一个名字,各自深入研究那个角色的预言,然后最后一步汇总。
限制
- 简单问题 RLM 循环增加开销,模型在写代码,而一个 prompt 就能搞定
- 计数问题(每一个三分球、每一个广告间休)搞不定,因为采样不能穷尽
- Prompt 回归真实存在,版本更新可能让原来 pass 的 case fail
- 成本随问题难度而非输入长度变化——这是 RLM 和 RAG 相比最大的结构性差异
适合场景
需要 RLM 而非 RAG 的场景:长视频、超大相册(needle-in-haystack + 复杂推理问题)、大型文档集。
不适合:简单问题、同一个问题要问很多次的场景(Twelve Labs 更便宜)。