0%

从知识到任务上下文

上一篇文章把软件开发中的知识拆成了六个层次:代码、业务逻辑、架构设计、历史决策、需求、基础知识

拆完之后,一个很自然的问题就摆在了面前:六层知识浩瀚如海,但一次具体的开发任务——比如「在退款流程里加一个超 30 天拒退的校验」——只需要其中的极少一部分。剩下的全是噪音,不仅没用,还会干扰判断

怎么从知识的海洋中,捞出刚好需要的那一滴?

这就是 Context 要解决的问题。在整个 AI Native 软件开发的链路中:

1
Knowledge → Context → Decision → Specification → Execution

Context 是第二环,承接 Knowledge,支撑 Decision。但我越来越觉得,它可能是整个链路中最难的一环

不是因为其他环节简单,而是因为这一环要解决的问题,本质上没有一个完美解


一个看似简单的问题

先别急着讨论理论。回到上一篇那个退款场景:

任务:在退款流程中增加一个校验——超过 30 天的订单不支持退款。

这个需求只有一句话。但为了正确地实现它,你需要知道:

  • 退款的主流程在哪里?(代码)
  • 退款之后有哪些异步链路——MQ?Event?定时任务?(架构)
  • 有没有现成的校验逻辑可以参考?(代码中的模式)
  • 有没有幂等要求?(历史决策 + 基础知识)
  • 这个改动会不会影响积分、优惠券、通知?(架构 + 业务逻辑)
  • 有没有类似的历史改动可以参考?(历史决策)
  • 测试需要覆盖哪些边界场景?(需求 + 历史事故)

这些信息确实都存在于系统中——在代码里、在文档里、在某个人的脑子里。但它们不会自动跑到你面前。你必须主动去找

而且这里有一个很微妙的困境:在开始找之前,你并不知道上面这个清单。你只知道「我要改退款流程」。至于退款流程涉及什么、需要小心什么——这些是你边找边发现的

你需要上下文来发现你需要什么上下文


两种上下文

在讨论具体机制之前,先做一个区分。上下文不是一次性出现的——它有一个从少到多的构建过程:

1
2
3
4
5
6
7
初始上下文(Seed Context):在探索系统之前,你手里已经有的信息
- 任务描述(那一句话的需求)
- 持久化项目知识(CLAUDE.md、ADR、架构图、团队 Wiki)
- 你自己的基础认知(基础知识层——不用查也知道的东西)

构建后的上下文(Built Context):经过多轮探索后,最终形成的完整上下文
- Seed Context + 探索过程中获取的项目特定知识

这个区分的重要之处在于:Seed Context 的质量,直接决定了整个构建过程的效率

举个例子:如果你的 Seed Context 里已经有了一条信息——「退款流程涉及 MQ 消费者和定时任务补偿」——你第一轮就会主动去读那些代码。如果没有这条信息,你只能打开 RefundService.java,顺着调用链往下追,追到一半才发现原来还有 MQ,然后再去查 MQ 消费者

前者是主动检索,后者是被动发现。Seed Context 的作用不是直接给你答案,而是让你知道应该问什么问题

这直接解释了为什么 CLAUDE.md、ADR、架构文档在 AI 时代变得如此重要。它们不是在替代推理,而是在降低探索的盲目性


Context 的五重约束

Context 构建之所以没有一个完美解,是因为它同时面对五重互相冲突的约束:

1. 完备性——不能漏

任何一个相关的知识点漏掉了,对应的决策就会出错。漏掉了「MQ 消费者也会处理退款事件」→ 你改了主流程但没改消费者 → 上线后积分扣回逻辑行为不一致

2. 最小性——不能多

不相关的信息进入上下文,不只是浪费空间——它会主动稀释注意力。人类的工作记忆只有 4±1 个组块,AI 的上下文窗口虽然有 token 上限但更大一些,但注意力稀释的规律是相似的:噪音越多,信号越难被抓住

3. 容量限制——不能全要

无论是人还是 AI,上下文窗口有上限。你不可能把整个代码仓库、全部文档、所有历史 Issue 都装进去。你必须做取舍

4. 可获取性——有些知识就是不在那

基础知识在模型里,不需要获取。代码在仓库里,读就行了。但历史决策——三年前的那次事故复盘、那个设计决策的讨论——可能散落在工作聊天记录、已离职员工的脑子里、一个没人维护的 Wiki 页面。你知道它存在,但你拿不到

5. 不可预知性——你不知道你不知道什么

这是最根本的限制。你只能去查你意识到需要查的东西。如果某个定时任务完全不在你的认知范围内——你根本不知道它的存在——你就不会去搜索它。它可能是整个改动中最关键的影响点,但你对它一无所知


五重约束放在一起,两两互斥:

  • 完备性 ↔ 最小性:多找怕噪音,少找怕遗漏
  • 完备性 ↔ 容量限制:窗口放不下
  • 完备性 ↔ 不可预知性:有些东西你根本不知道应该去找
  • 最小性 ↔ 不可预知性:你怎么判断一个你不知道的东西是不相关的?

Context 构建不是一个技术问题——它是一个在理论上有上限的优化问题。你只能逼近最优解,无法达到


迭代构建:Context 的循环

既然一次性构建完美 Context 不可能,那就只能迭代。这个过程可以描述为三步循环:

1
当前上下文 → 分析知识缺口 → 获取知识 → 新知识揭示新缺口 → 再获取 → ... → 收敛

第一步:知识需求分析

从当前已有的信息出发,问自己一个问题:

基于我现在知道的,我还需要知道什么?

这不是检索,这是判断。输入是当前上下文,输出是一组「知识需求」。以上面的退款任务为例:

1
2
3
4
5
6
7
8
当前上下文:任务描述 + CLAUDE.md(提到退款模块在 order-svc)

分析 → 知识需求:
1. 退款主流程的代码在哪里?入口是什么?
2. 退款流程后面有没有异步链路?
3. 有没有现成的校验逻辑可以参考?
4. 有没有幂等约束?
5. 有没有类似的历史改动?

注意:这个清单在第一轮是不完整的。因为你还不知道 MQ 的存在,所以你不会列出「MQ 消费者的代码在哪」这个需求。这个需求会在第二轮——读到了 MQ 生产者代码之后——才会出现

知识需求分析的质量,取决于你已经知道多少。 而这又回到了 Seed Context 的重要性。

第二步:知识获取

针对每一个知识需求,从六层知识空间中获取。但不同层的知识,获取方式完全不同:

知识层 获取方式 难点
代码 读文件、追踪调用链、搜索关键字 量大,搜索精度低——搜索「退款」可能返回 200 个文件,其中 150 个不相关
业务逻辑 从多个代码片段中逆向还原 无法直接获取,需要合成——读了五个文件,每个有一段相关逻辑,但没有一个文件告诉你完整规则
架构设计 依赖图、调用图、目录结构 代码里的显式依赖能工具化获取,但隐式的架构意图需要推理
历史决策 检索 ADR、Wiki、Issue、PR 离散、稀疏,找到的文档可能已经过时
需求 查找原始 Issue/PRD 大概率找不到——需求迭代多次后,代码是唯一可信的记录
基础知识 不需要获取(已在模型内) 但需要激活——在正确的代码位置想起对应的知识

关键洞察:Context 构建不是一种统一操作,而是针对不同知识层的不同策略组合

代码层的获取是高频、动态的——每次任务都要读,但读什么取决于任务。架构层可以预计算——依赖图、调用关系,一次构建、多次复用。历史决策层是检索加验证——找到了还要判断这份 ADR 在三年前的决策现在是否仍然有效

第三步:缺口判断

每一轮获取之后,问自己另一个问题:

有没有什么东西,我不知道,但我感觉我应该知道?

这一步和第一步不同。第一步是正向推导——「我需要 X」。这一步是反向审视——「我是不是漏了什么」。

几个典型的缺口信号:

  • 因果链断裂:「我看到了幂等检查,但不知道为什么存在」→ 缺历史决策
  • 调用链未闭合:「我看到了 MQ 生产者,但没看到消费者」→ 缺架构知识
  • 模式不匹配:「这个写法和项目里其他类似模块不一样」→ 缺历史原因
  • 边界不清晰:「我不知道这个修改会影响几个系统」→ 缺依赖关系

有缺口 → 回到第一步,把缺口转化为新的知识需求
没有明显缺口 → Context 收敛,进入 Decision


这个循环的困难不在于循环本身

循环的逻辑不复杂。复杂的是循环中每一个步骤的执行质量

知识需求分析的质量取决于 Seed Context。Seed Context 差 → 第一轮需求清单就不全 → 获取方向就偏 → 需要在更晚的轮次才发现缺失。而每一轮额外的循环都在消耗时间和注意力

知识获取的质量取决于检索精度和合成能力。搜索「退款」出来 200 个文件——你看得过来吗?看了之后能不能从五个文件的片段里拼出完整业务规则?AI 帮你读,但 AI 的信息合成同样可能漏掉关键连接

缺口判断的质量取决于经验。新人根本不知道「MQ 消费者」应该存在,自然不会觉得没看到它是一个缺口。缺口判断能发现的是「已知的未知」,无法发现「未知的未知」。这让 Context 的完备性在根本上是一个不可判定问题


几个逼近策略

既然完美解不存在,那就有策略好过没策略。以下几个方向值得讨论:

1. 把 Seed Context 当作投资品

Seed Context 是一次构建、多次复用的资产。CLAUDE.md、架构图、ADR 索引——这些不是为了某一个任务准备的,而是为了降低每一次任务的探索成本。它们在首次创建时有成本,但边际收益随使用次数递增

一个实用的问题是:一份 Seed Context 好不好,不看它写了多少,看它让后续任务少走了多少弯路。 如果一个架构文档没有帮你减少探索轮次,它就不是一个好 Seed Context。

2. 不同知识层,不同生命周期

代码层的上下文随任务动态构建,不缓存。架构层的依赖关系可以预计算、随代码变更自动更新。ADR 可以按领域索引,每次相关任务时检索。基础知识不需要管理——管理的是「在什么位置激活哪条基础知识」的绑定关系。

把不同生命周期的知识混在一起管理,结果一定是过时和噪音同时存在。

3. 接受不完美,但标记盲区

既然无法保证完备性,一个次优策略是:把「这一轮我没覆盖但可能需要关注」的领域显式标记出来。不假装自己什么都知道——而是诚实地标注:「以下领域本轮未深入探索:定时任务补偿逻辑、跨系统的 Event 消费端」

这不会让 Context 更完备,但会让 Decision 更有自知之明。知道自己的决策建立在什么盲区之上,本身就是一种有价值的信息

4. 上下文窗口是一个预算问题

如果上下文窗口容量是固定的,Context 构建可以理解为:按照相关性从高到低填充窗口,直到窗口满。相关性排序决定了哪些知识进去,哪些留在外面。

排序的质量取决于 Seed Context 和每一轮的知识需求分析。你排得越准,窗口里装的东西越有价值。排得不准——窗口满了,但里面有一半是噪音,而你真正需要的东西没装进去


写在最后

这篇文章讨论了 Context 构建为什么是软件开发中最难的一步——不是因为技术复杂,而是因为它在理论上就没有完美解。五重约束互相冲突,你只能在完备和最小之间做逼近。

但反过来说:正因为难,Context 的能力才是一个工程师(或 AI Agent)核心竞争力的分水岭

你我都有这样的经验:两个工程师面对同一个任务,一个人花半天搞清楚状况然后半小时写完代码,另一个人上来就写然后花三天改 bug。他们的差别不在写代码的速度——而在 Context 构建的效率

在 AI 时代,这个差别可能被进一步放大。因为写代码的速度 AI 已经拉平了,但从知识到上下文的这一跳——知道该读什么、什么时候读够了、什么可以忽略——仍然高度依赖判断力

下一个问题自然就是:Context 构建完成了,接下来怎么用这些信息做出正确的工程决策?

这就是 Decision 要解决的问题。下一篇继续


*这是 AI Native 软件开发系列的第三篇。第一篇讨论了「软件开发管理的对象是知识而不是代码」,第二篇定义了「知识是什么」,这一篇分析了从知识到上下文的筛选过程。如果你有不同的理解或者实践经验,欢迎一起讨论