我不想再从整座历史里捞一句话
这次事情的起点很普通:我在熟悉几个软件和工作流程时,想把过去创建它们的关键提问找出来。那些提问并不只在一个助手里,也不只存在于一台设备上。它们散落在不同的对话记录和数据存储中,有的讨论页面,有的讨论代码,有的讨论文件结构,还有的讨论怎样把计划交接给下一个窗口。
我真正想找的,不是一条孤立的答案,而是过去形成判断的过程:当时为什么要建立代码图,为什么不能只看页面,为什么要把任务拆成方法论层、历史对话层和真实软件样板层。这些内容如果每次都重新翻,会很快变成一件比原问题更大的事。
历史对话一旦超过人的即时记忆范围,就不再只是聊天记录,而是一座需要被建模的知识库。
这句话听起来有点重,但它对应的是一个非常具体的场景:我问“以前我们是怎样分析一个软件的”,如果系统只能重新遍历所有记录,答案的速度就取决于历史有多大,而不是问题有多明确。
表面上是搜索,实际上是知识组织
一开始很容易把问题理解成关键词搜索。输入“页面分析”“代码图”或某个软件名,然后等待命中结果。这样的方式对找一段原话有用,却不适合找方法。因为同一个判断可能换过很多种说法,也可能出现在计划、执行报告和收尾讨论的不同位置。
更麻烦的是,命中的几条记录并不等于完整答案。关键词搜到的是字面相似,不是问题所需要的上下文。只看命中结果,容易把一个局部建议误当成最终原则,也可能漏掉后面修正过的判断。
如果不处理这个差别,后面会出现两个相反的问题:要么每次都全盘分析,速度和用量都不可接受;要么为了快,只读少量命中内容,得到一个看似流畅、实际上缺少关键边界的答案。找得快和找得全不是同一个指标,必须把它们拆开验证。
这件事让我重新意识到,历史知识库的第一层工作不是“把所有内容塞进去”,而是给内容建立可以更新的身份。一次对话至少要知道它属于哪个主题、哪个项目、哪个时间段,讨论的是事实、决策还是方法。只有这样,后面才有可能从主题缩到项目,再从项目缩到具体轮次。
先做分层索引,再谈秒级召回
我更愿意把索引分成几层,而不是一开始就追求一个万能搜索框。
第一层是主题索引。它回答“这批内容大概在讲什么”,例如软件熟悉、对话历史、计划交接或数据层收敛。第二层是项目索引。它回答“这个主题和哪些具体工作有关”,把同一项目中分散在不同助手里的对话聚拢起来。第三层才是轮次和证据索引,记录某个判断究竟来自哪几轮提问,是否后来被修改,能不能作为公开文章的事实依据。
这三层分别服务不同速度的查找。主题索引负责快速缩小范围,项目索引负责保持上下文,证据索引负责最后核对。用户提出问题时,不需要先把全部原文交给模型,而是先用摘要和标签筛出候选,再按需要回读原始片段。
这里最容易误判的是,摘要越长越可靠。实际上,过长的摘要会把候选范围重新变成一篇大文档,失去索引的意义。我会让摘要只保留能改变下一步判断的内容:这段对话解决了什么问题,采用了什么取舍,还留下了什么未知。
我选择分层索引,是因为它同时照顾了速度和可追溯性。只有主题标签,找得快但容易空泛;只有原文切片,证据足却不够快;把两者分开,才可以先快后准。
把增量更新当成基本能力
历史库不是一次性导入完就结束。新的对话每天都会产生,旧的计划也可能被修订。如果每次刷新都重新处理全部内容,系统很快会把大量时间花在重复劳动上;如果完全不刷新,索引又会逐渐落后,最后找不到刚刚形成的判断。
因此,更新应该围绕“变化了什么”展开。新增对话只进入新增队列,已有内容只在发生修改时重建摘要和关联关系,主题与项目的总索引则在局部变化后重新计算。为了避免同一段内容被重复计入,还需要给记录保留稳定标识,并区分原文、摘要和人工修订。
这不是为了追求复杂的工程形式,而是为了保留一个很朴素的事实:知识库的价值来自积累,积累必须比重做便宜。一个真正可用的历史系统,不是第一次导入得多漂亮,而是第 100 次更新仍然不需要从头开始。
增量更新还会带来一个边界问题:旧判断和新判断冲突时,不能简单覆盖。更稳妥的方式是保留时间关系和修订关系,让召回结果知道哪些是早期方案,哪些是后来确认的规则。否则,系统虽然返回了“正确”文字,却无法解释为什么曾经出现过另一种选择。
用三张图补足“熟悉软件”的上下文
这次讨论里还有一个重要转折:熟悉软件不能只看页面。页面图能告诉我用户看见了什么,代码图能告诉我功能怎样组织,文件结构图则能告诉我数据和资产放在哪里、由谁承载。
三张图并不是把资料画得更漂亮,而是把不同类型的问题分开。我要判断一个按钮能做什么,先看页面状态和入口;我要判断它为什么这样变化,再看代码调用和状态流转;我要判断能不能绕过页面完成操作,还要看文件结构、草稿格式和已有资产。少了其中一张图,就容易把“看见了”误认为“理解了”。
这套分层方法也适用于历史对话。可以把主题索引看成总览图,把项目索引看成关系图,把具体轮次看成证据图。它们的共同目标不是替人记住所有细节,而是让人能够在需要时沿着正确路径抵达细节。
当时我还把验收拆成3层:先验收方法论是否完整,再验收历史对话层是否能召回,最后用一个有真实源码和可操作界面的软件做样板。这样做是因为抽象方法很容易在纸面上成立,到了真实对象上却可能缺少状态、文件或操作证据。样板不是装饰,它用来暴露方法还没有覆盖的地方。
不用“看起来找到了”替代验证
索引建好以后,不能只问“能不能返回结果”。真正要问的是,结果是否覆盖了应该覆盖的内容,是否把无关内容排在前面,是否会漏掉只在后续轮次出现的修正。
我会准备一小组只能由目标记录回答的问题。比如,哪一轮提出了把历史记录当成新软件来分析?为什么要同时建立代码图、页面图和文件结构图?计划为什么要分成方法论层、历史对话层和真实软件样板层?每个问题都预先标出应该命中的记录,再测试系统返回的候选。
这类小样本问答不是为了制造一个漂亮分数,而是为了发现漏召回。精确率看返回内容有多少真正相关,召回率看应该找到的内容有多少被找到,漏召回抽样则专门检查“系统没有返回什么”。如果只测精确率,系统可以通过少返回来显得干净;如果只测召回率,结果又可能塞满无关材料。
最容易犯的错误捷径,是把关键词命中数当成质量证明。另一个错误捷径,是先做一个很大的自动摘要系统,再等真实问题来证明它有用。我判断应该先用少量真实问题做验收,是因为这些问题最接近未来使用场景,也最容易暴露索引层级、时间关系和边界处理上的缺陷。
下次我会怎么做
下次遇到同类需求,我会先问清楚要找的是原话、事实、决策,还是可复用方法。不同目标需要不同证据,不能用同一个搜索入口解决所有问题。随后我会先建立主题、项目和证据3层索引,给每条记录留下时间、来源范围和修订关系,再把新增内容纳入增量更新。
如果问题涉及熟悉软件,我会同时检查代码图、页面图和文件结构图,明确每张图解决什么未知。涉及计划交接时,我会把方法论、历史对话和真实样板分开验收,避免抽象结论直接冒充已验证能力。
最后,我会维护一组小而稳定的真实问题,定期检查精确率、召回率和漏召回样本。出现错误时,先判断是索引没覆盖、摘要丢信息、范围筛选过窄,还是原始证据本来就不足,再修对应层。
一个流程成熟的标志,不是它能在今天把答案找出来,而是下次面对更多记录时,仍然知道先缩小哪里、回读什么、怎样证明没有漏掉关键内容。我真正想留下的不是一套更快的搜索,而是一种让过去的判断可以持续被找到、被核对、被复用的工作习惯。