给 Codex 的 1.9GB 日志做本地搜索:不建索引,12 秒出结果
一位 Reddit 用户给 Codex 的 1.9GB 原始日志写了本地只读搜索工具 Oglyanutsya。它靠 ripgrep、字节偏移和哈希校验找原话,刻意不做持久索引。性能从 119 秒压到 12 秒,代价是每次都要重新扫文件。
Reddit 的 r/PromptEngineering 版块上,有位叫 Dream-SRA 的用户,给 Codex 做了一个本地搜索工具,名字叫 Oglyanutsya,俄语里大概是“回头看”的意思。
起因很具体:他和 Codex 有一个很长的工作对话,日志约 1.9GB。上下文压缩后,模型还能记住工作方向,但没法逐字看到早先的完整对话。于是他和 Codex 一起写了这个只读搜索工具,专门搜 Codex 自己的原始日志。
工具会递归扫描 .codex/sessions 和 .codex/archived_sessions,按 thread_id 把同一段对话的物理副本归组。默认只搜根级用户对话,子代理日志要通过参数显式打开,避免把技术活动和主对话混在一起。
搜索范围有明确边界:只接受 JSONL 日志里真实的用户和助手消息。系统与开发者指令、推理过程、工具调用及结果、技术事件、压缩摘要、environment_context 等合成块都不算。历史文本被当作数据,不当作指令。旧消息里写“忽略之前的指令”,工具不会执行。
搜索流程也值得看。Codex 先给出记忆中的一句话、一个稀有词、大概日期范围,或者已知的对话和说话人。比如:
记忆中的词组合:
memory + capabilities + handshake
稀有锚点:
handshake
时间:
2026 年 10 月
然后 Oglyanutsya 先找精确短语。精确匹配不够,就把组合里的词拆开分别搜,在内存里对 JSONL 记录号取交集,只保留同一条消息里包含完整词组合的记录。它不会把不同消息里的词拼成一个结果。命中后用字节偏移打开对应记录,解析 JSON,确认是真实用户或助手消息,再按消息自身时间戳过滤。文件日期不参与,因为一段对话可能九月开始、十一月还在继续。最后重新检查解码后的全文,并取出前后两条有实质内容的消息,跳过中间的技术记录。
普通 .jsonl 文件走 ripgrep 快速路径,拿到行号和绝对字节偏移。工具再定位 JSONL 记录的起止位置,按 UTF-8 解码,解析 JSON。压缩的 .jsonl.zst 不落盘解压,用流式读取处理。
返回结果包括精确引文、前后消息、说话人角色、助手回复阶段、时间戳、thread_id、item_id、JSONL 记录号、原始记录字节范围、引文在消息内的 UTF-8 坐标,以及完整消息和引文的 SHA-256。这样结果不仅能展示,还能回到原始来源独立校验。
性能变化也很有意思。第一版把整个日志当流处理,1.9GB 花了约 119 秒。后来引入 ripgrep 快速路径,精确短语约 1.8 秒找到,但程序随后打开了 953 次 хендшейка 的匹配,总时间仍要约 35 秒。改算法后,每个词独立搜索,在内存里对记录号取交集,再打开原始记录。同一个日志上,查询 memory + capabilities + handshake,原始用户消息找到于 2026 年 10 月 29 日,打开记录数从 953 降到 200,总时间约 12 秒。原消息里这些词被逗号和额外文本隔开,能命中是因为它们出现在同一条消息里,不是靠精确字符串。
这个工具刻意不建持久索引。没有 SQLite,没有 embeddings,没有向量库,没有搜索词典,没有语义图,没有对话副本,没有引文缓存,也没有保存的词组合列表。唯一的持久记忆是 Codex 原始日志。匹配行列表和搜索词交集只存在于单次查询的内存里,进程退出就消失。代价很直接:每次搜索都要重新扫描原文件,所以是 12 秒,不是 12 毫秒。好处也直接:没有派生数据库悄悄取代原始历史,成为新的真相来源。
测试也围绕这些边界展开:精确引文能找到;三个词不相邻也能找到;三个词分别出现在三条消息里不会合并成一个结果;日期过滤用消息时间戳;子代理默认排除,显式请求才包含;environment_context 不会被当成用户的话;搜索后原始文件大小和 SHA-256 不变;工具不会留下隐藏状态文件。作者说全部测试通过。
工具被包装成一个本地 skill。当用户提到当前上下文里已经找不到的旧对话、旧决定、旧引文或旧区分时,它会激活。skill 说明里明确禁止把它当成普通文件搜索或网页搜索的替代。分工是:Codex 的原生工具负责理解含义、形成联想词组合、搜工作文件、查文档和网页、决定下一次查询;Oglyanutsya 负责在 Codex 原始对话历史里找逐字证据。拿到证据后,Codex 继续用自己的推理。它不拦截也不禁用任何东西,只是多给模型一个很窄的操作:看自己的原始日志。
作者还向 OpenAI 提了一个产品层面的想法。Codex App Server 已经能读对话和其中单条 item,但他没找到让模型自己全局搜索整段对话历史内容的内置方式。他认为需要两个只读操作:
history.search_original(...)
history.read_context(...)
不要“永久记忆”,不要自动生成用户历史的向量数据库,也不要把几 GB 日志塞进上下文窗口。只要模型能组织一个特征词组合,在自己的原始日志里定位它,再重读周围几条消息。
帖子下面有几个问题也挺实际。bytezvex 喜欢不建持久索引这点,觉得字节偏移加哈希校验比“信我,我找到了”可靠。the_busy_walrus 问,如果只记得大概内容、不记得准确词,稀有词锚点还管用吗。RileyReplay 问,搜索是否覆盖工具输出,因为有时想找的是文件路径或报错字符串,这些东西只出现在命令输出里,用户没打过。原文工具目前只收用户和助手消息,所以这类需求正好落在它的边界外。
反常识的地方在取舍:多数“记忆”方案想快、想自动、想不占上下文,于是加索引、加向量库、加缓存。这个工具反过来,愿意每次多等十几秒,换来源可验证、历史不被派生数据替代。它不一定适合所有人,但对那些需要回到原话的人来说,慢一点有慢一点的道理。
发布时间: 2026-11-13 17:01