乐于分享
好东西不私藏

AI-Native 软件工程(11):Knowledge Layer——为什么知识层半年就馊了

AI-Native 软件工程(11):Knowledge Layer——为什么知识层半年就馊了

上篇拆了反馈层——什么信号值得回流,什么必须丢掉。被四维筛子留下来的那一小撮信号,最后流到了知识层。这一篇聊的就是:这些信号到了知识层之后,会发生什么。

剧透一下结论:大多数情况下,它们会以远比你预期更快的速度腐烂。

去年这个时候,我们团队搭过一套”经验库”。立项书上写得很正经:把过去半年所有 Agent 跑过的成功路径抽象成可复用的知识条目,未来同类任务直接命中检索,省 token、省时间、省踩坑。立项时大家很兴奋,觉得这是把”组织记忆”变成”Agent 记忆”的关键基础设施。

第一个月条目还不多,两百条左右。Agent 命中率挺高,团队里几个工程师都跑来夸——”这条建议给力,省了我半天”。

第三个月,条目膨胀到一千七百多条。Agent 还在用,但开始出现一些怪现象:它会信誓旦旦地按一条三个月前的”经验”去操作一个早已重构过的系统,结果在前两步就撞墙。撞完之后它居然还会引用同一条经验解释为什么撞墙:”根据 lesson #834,这个模块需要先获取 X 权限。”——可那个权限模型上个月被换掉了。

第六个月,没人再敢直接信这套经验库。它没坏,每天还在被检索,但所有人在引用它之前都得手动验证一遍。原本”省时间”的工具,变成了”多一步验证”的负担。后来我们把它砍了,回到无知识库的状态,反而轻松了。

复盘的时候我意识到:我们不是输在”做不出来知识库”,我们是输在默认了知识是不会过期的东西。在传统软件工程里,文档放一年没人改也还可以参考——因为文档描述的系统也一年没动。但 AI-Native 系统里,代码、依赖、API、提示词、Agent 行为本身都在以周为单位演化。半年前的”最佳实践”,今天可能是反模式。知识没坏,是世界变了。

知识层的核心命题,因此不是”知识怎么组织”,而是另外一个完全不同的问题:知识是有半衰期的。你怎么知道一条经验是不是已经馊了?怎么在它馊之前用,馊之后丢?

知识 ≠ 文档,更不等于经验池

我先把三个经常被混在一起的概念拆开,否则后面没法谈。

文档是显性的、人写给人看的、长生命周期的、版本管理的。一份 API 文档是文档。一份 ADR(架构决策记录)是文档。它的主要消费者是同事,主要质量保证手段是 review 和审稿。

经验池是 Agent 跑过任务之后留下的痕迹的集合。一条经验池条目可能长这样:”上次给 user-service 加字段时,先在 staging 跑了三遍迁移才发现 rollback 脚本忘了写。”它是半结构化的、原始的、未经裁剪的。

知识是从经验池里被抽象、归纳、提纯之后的可复用判断。从上面那条经验池条目里,可以蒸馏出一条知识:”对 user-service 这类核心服务做 schema 迁移,必须先在 staging 验证 forward + rollback 双向脚本。”

很多团队的”知识库”其实是经验池披了一层壳。原始 trace 直接打上 tag 就丢进去,号称”AI 时代的知识管理”。这套东西在 Agent 看来是个垃圾堆——它检索回来一大堆 stdout 片段,需要自己再做一次归纳。结果就是每次决策都在重复同样的归纳工作,token 成本和延迟都吃不消。

知识层真正要存的,是已经被蒸馏过、可以直接作为判断依据的那一层。这一层比经验池小一到两个数量级,比文档活得短一到两个数量级。它的产出有成本——你得有人或者另一个 Agent 来做蒸馏——这是工程取舍,不是技术细节。

半衰期:知识层最容易被忽略的轴

我现在判断一条知识值不值得入库,第一道关不是”它写得对不对”,而是”它的半衰期有多长”。

什么是知识的半衰期?我的定义是:从这条知识被记录开始,过多久之后,它有 50% 的概率已经不再准确。

这个数字差别巨大。我把日常碰到的知识大致分了五档。

半衰期档位 典型内容 入库策略
周级 某个 PR 的临时 workaround、调试中开的临时端口、当前 sprint 的优先级 不入库,留在任务级缓存
月级 当前项目的 API 命名约定、临时引入的第三方依赖版本 进项目级 memory,自动衰减
季度级 团队当前用的部署流程、当前架构下的故障域 进项目级,需季度复审
年级 公司技术栈选型、核心服务的边界契约、领域模型 进全局,但要绑定版本
多年级 工程原则、架构判断方法、对某类问题的思考框架 全局,长期

我以前犯过的最大错误,是把不同档位的知识混在一个池子里,用同一种检索策略。结果就是 Agent 检索一个稳定的”领域模型”问题,被一条周级的临时 workaround 干扰,给出了一个三个月前才有意义的建议。

这个错误的本质,是没有区分”事实”和”约定”。事实可以长期稳定——勾股定理一万年也是对的。约定的稳定性取决于环境,环境一变,约定就废了。AI-Native 系统里的”知识”大部分是约定不是事实,这就是为什么它腐烂得这么快。

知识衰减的三种模式

一条知识从准到不准,不是某个时间点突然失效,而是渐进式衰减。理解衰减模式,才能设计对应的应对策略。

第一种是底层变化触发的衰减。底层代码、API、依赖、数据模型变了,所有依赖于它的知识都失效。这种衰减是”硬失效”——一旦发生,旧知识不只是不准,是会主动误导。我之前那个经验库踩的就是这个坑。应对手段是版本绑定:每条知识入库时绑定它依赖的”底层指纹”——可以是 commit hash、API 版本号、schema 版本。底层一变,所有绑定的知识自动标记为”待复审”。

第二种是累积漂移导致的衰减。没有一个明确的”变化事件”,但环境在慢慢变。比如团队规模从 5 个人变成 50 个人,原来”开会决定”的流程不再成立;比如服务规模从 QPS 100 变到 QPS 10 万,原来”直连数据库”的做法不再 OK。这种衰减没有明确的失效时间点,只能用渐进降权:知识入库时记录上下文(团队规模、QPS 量级、数据规模),检索时如果当前上下文跟入库时差距太大,自动降权或要求人工确认。

第三种是反例累积触发的衰减。一条知识本来 80% 准,用着用着发现某些边界条件下不对,反例越积越多,可信度逐步下降。这种衰减是最隐蔽的,因为单看任何一次反例都”看起来不严重”。应对手段是反例计数器:每条知识在使用过程中如果被反例覆盖,记一次。反例数超过阈值,知识自动降级——从”建议”降到”参考”,再降到”归档”。

三种衰减叠加,意味着知识层不是一个”写入即永久”的系统,而是一个持续自我修剪的系统。它的健康度不取决于”存了多少条”,而取决于”过期条目占比有多低”。

检索 vs 灌注:两种使用模式的取舍

知识入库的姿势讲完了,下一步是 Agent 怎么用它。这里有一条经常被忽略的分界线。

第一种用法是检索:Agent 在决策点主动发起查询,”我需要关于 X 的过往经验”,知识层返回最相关的若干条,Agent 自己判断是否采纳。RAG 是这个模式的代表。

第二种用法是灌注:相关知识在 Agent 看到任务之前就被注入到 system prompt 或 context 前缀里。这种方式下 Agent 不需要主动检索——它在”已经知道”的状态下开始决策。

两种用法的取舍非常具体:

检索是按需付费的。Agent 用不到,就不查,零成本。代价是 Agent 必须有”我应该查这个”的元认知——它要先意识到自己有知识盲区。这件事对一些复杂任务可以做到,对简单任务往往做不到,因为 Agent 不知道自己不知道。

灌注是预付费的。所有相关知识默认在场,Agent 不需要自觉。代价是固定的 context 占用,而且无关知识会干扰决策。我之前提过反馈层的”context 预算”——灌注模式下,每条灌注的知识都在挤压决策空间。

我自己的取舍:稳定的、跨任务必用的少量知识走灌注(比如”我们用 pytest 不是 unittest”),数量控制在 10 条以内、总长度不超过 1000 字;其他都走检索,由 Agent 在需要时主动发起查询。

有些团队会问到第三种方案——fine-tune。把知识 fine-tune 进模型权重。这个方案在工程上几乎不该被首先考虑。原因有三:第一,fine-tune 后知识无法精确删除,一旦知识过期你没法干净撤销;第二,fine-tune 的成本和周期跟 AI-Native SE 里”知识半衰期以月计”的现实不匹配;第三,fine-tune 后的知识不再可观测——Agent 用了什么判断、为什么用,看不出来。fine-tune 在”长期稳定 + 大量样本 + 风格而非事实”的场景下有价值,但这跟我们这里讨论的工程知识不是同一回事。

隐性知识:最值钱也最难落

显性知识相对好处理——它已经被人想清楚、写下来了,剩下的是组织、索引、检索。

真正难的是隐性知识。架构决策背后的”为什么这样选”、风格偏好里”为什么这种命名我们不接受”、踩过的坑里”为什么当时没看出来”——这些东西通常没人写下来,因为写下来需要的精力比直接做事多得多。

隐性知识在 AI-Native SE 里的价值,比显性知识高一个量级。因为显性知识 Agent 自己查文档也能查到,但隐性知识只能从你的团队里来。一个 Agent 接手新项目,知道”用 pytest 不是 unittest”是基础;知道”这个项目里测试覆盖率追求 90% 是因为去年一次生产事故源于一段未覆盖的 fallback 分支”,才是真正能影响决策的判断。

把隐性知识落到 Agent 能用的形态,工程上有几条具体路径。

一是决策点采集:在反馈层的”决策点记录”机制里,强制要求 Agent 解释”为什么选 A 不选 B”。理由本身就是隐性知识的种子。

二是人工注入接口:让团队成员能在工作流里随手补一句”对了,这种情况我们一般这么处理”,自动归档成知识候选。注意是”随手”而不是”专门”——专门的知识管理动作大家都不愿意做,能在做事的同时顺便做的才有持续性。

三是事故复盘强制蒸馏:每次出事故的复盘报告,结尾必须有一条”如果 Agent 下次遇到类似情境,它应该知道什么”的强制字段。这条字段的产出物直接进知识库。

四是风格知识由示例承载:架构师的判断很多没法用规则描述清楚,但可以用”好的例子”和”坏的例子”成对承载。这种成对示例的检索效果,往往比规则陈述更准。

这四条路径都有一个共同特点:它们不是另起炉灶建一个”知识工程”流程,而是把知识蒸馏嵌入到现有工作流里。在 AI-Native SE 里,单独的”知识管理工具”几乎都会失败——只有跟工作流深度耦合的知识沉淀机制才能持续。

知识层与 Planner / Verify 的接口

知识不是”被读”,是”被引用进推理路径”。这句话听起来有点抽象,我用具体例子说清楚。

Planner 在做任务分解时,需要知识层告诉它”这类任务通常分几步、风险在哪、哪些步骤可以并行”。如果知识层只是返回一堆文本片段,Planner 还得自己做归纳——这就退化成了 Agent 在写代码前先读了一遍文档,价值有限。

更好的设计是:知识层提供结构化输出。同样一条”用户认证迁移”的知识,可以同时暴露三种视图——给 Planner 的视图是步骤模板、给 Verify 的视图是验证清单、给 Agent 自己的视图是叙事说明。同一条知识,按消费者的需要分发不同切面。

Verify 层调用知识层的方式更隐蔽。Verify 不是”读知识”,是”知道有哪些 invariant 必须验”。比如”用户认证迁移”这条知识里,应该附带一组验证断言——”迁移后老 token 是否还能登陆?”、”迁移后审计日志的用户 ID 是否对得上?”。这些断言是知识的一部分,但 Verify 在调用时只关心断言列表,不关心叙事内容。

这种”按消费者切面”的设计,要求知识入库时不是写一段散文,而是按预定义的结构填字段。听起来很重,但好处是 Agent 真的能”引用”知识进推理,而不是把知识当成另一段需要再次解读的文本。

我现在的实现:每条入库知识至少有四个字段——叙事(人读的)、Planner 模板(步骤分解)、Verify 断言列表(可执行验证)、版本指纹(底层依赖)。前三个字段是消费侧,第四个字段是衰减管理用的。蒸馏这件事不便宜,但它把”被动文档”变成了”主动可用的判断”,差别值得这个投入。

共享边界:什么知识全局,什么必须隔离

多 Agent 系统里有一个非常容易被忽略的设计问题:知识层的共享边界。

最幼稚的设计是”所有 Agent 共用一个知识库”。听起来很合理——共享知识不是更高效吗?但你试一下:Agent A 在客户 X 的项目里学到的”这个客户的 prod 库密码存在 vault 路径 Y”,被 Agent B 在客户 Z 的项目里检索到了——你的知识层刚刚帮你做了一次数据泄露。

知识共享有边界,边界由两个维度决定:租户边界抽象级别

租户边界决定了”哪些 Agent 之间可以共享”。客户 A 的项目知识不应该泄漏到客户 B。同一公司内部不同业务线的知识可不可以共享,看具体合规要求。这一层是硬边界,违反就是事故。

抽象级别决定了”什么样的知识有资格跨边界共享”。具体到某个数据库、某个 API 密钥、某个文件路径的知识,永远不能跨租户。抽象到”这一类问题应该这么思考”的知识,可以跨。中间这一大片,需要逐条判断。

我用的简单规则是:只有不带任何具体标识符的、纯方法论级别的知识,才允许进入全局池。 任何含有客户名、项目名、密钥、地址、IP、路径的条目,强制隔离在该租户的知识空间内。蒸馏阶段就要做这次过滤——蒸馏时如果发现一条候选知识无法剥离具体标识符,它就该被降级到租户级,而不是上升到全局级。

这个边界比想象中难维护。一个工程师在写”如何调优 PostgreSQL 慢查询”这样看起来纯方法论的知识时,可能不经意带上一个”我们生产库的连接池上限是 200″的细节——这条细节就把它从全局降级到了租户级。需要工具层面的强制检查,不能靠自觉。

我现在的设计选择

把上面这些拆完,我自己实际在用的知识层架构是这样的——同样不是推荐给所有人,是我现在场景下的取舍。

知识入库走显式蒸馏路径。原始经验池里的 trace 不会直接进知识库。每条候选知识要经过一次蒸馏步骤,产出四字段结构:叙事 + Planner 模板 + Verify 断言 + 版本指纹。蒸馏可以由人做,也可以由专用的”reviewer Agent”做,但必须留蒸馏痕迹。

知识带半衰期标签。入库时强制选择档位(周/月/季度/年/多年),不同档位走不同的过期策略——周级到期直接删,年级到期触发复审。

衰减监测自动化。底层指纹绑定 git commit / API version / schema version,底层变化时自动标记相关知识”待复审”。反例计数器记录每次使用后的反馈,超阈值自动降级。

检索默认按需,灌注严格白名单。Agent 主动检索为主,只有不超过 10 条的”必备知识”走灌注,且这 10 条要定期复审。

共享边界用蒸馏阶段卡死。蒸馏时强制检查具体标识符,发现则降级到租户级。全局知识池入门门槛远高于租户池。

健康度指标,跟”条目数”无关。我盯的是三个数字:过期占比(应该低于 5%)、命中后被采纳率(应该高于 60%)、平均被反例覆盖次数(应该低于 1)。这三个数字一旦恶化,砍知识库比扩张更紧迫。

这套设计也不是终态。它解决了”知识库越积越馊”的问题,但带来新的代价——蒸馏成本不便宜,每条知识入库前的工程开销显著高于”直接存 trace”。我现在认为这个代价值得,但在小团队或者快速验证的场景下,可能直接用经验池不蒸馏反而更经济。

系列下一站

知识层处理的是”信号活下来之后怎么沉淀、怎么用”。下一篇是这个系列的最后一篇——Collaboration Layer:当 Agent 不止一个,当人和 Agent 同时在改一个系统,决策权、知识、上下文怎么协调?为什么大多数”多 Agent 协作”系统其实是几个 Agent 各自为政?

写在结尾

知识层的设计错误,跟反馈层的设计错误是同构的——都源于”以为更多就是更好”。反馈层错在以为收集越多越聪明,知识层错在以为入库越多越值钱。

最干净的知识层是空的——零过期,零误导,零维护成本,但也零价值。最丰富的知识层是把所有 trace 都存下来——理论上信息完整,实际上 Agent 每次决策都被噪声埋掉。

中间这一大片地带怎么走,没有标准答案。但有一个判断标准,可能比所有具体设计都重要:你的知识层在第 N 天,是在帮 Agent 做出更好的判断,还是在帮 Agent 复制旧的错误?

如果你的知识库已经存到几千条但说不清最近一周谁用过哪条,它大概率在腐烂。如果你的 Agent 引用知识时给出的理由总是”根据 lesson #X”,但没人能说清 lesson #X 是不是还成立——它已经在退化。

知识层不是软件工程的存档室,它是 Agent 的工作记忆。工作记忆里塞满过期的、不准的、自相矛盾的东西,比空白的工作记忆更糟。

去看一下你的知识库,里面有多少条是过去三个月没被任何 Agent 主动用过的?把那些先清理掉,再谈扩张。