


























在前两章,我们学会了用“文档”为AI设定全局法律,用“负空间设计”雕刻具体任务的边界。我们已经拥有了强大的“软约束”能力。然而,当项目规模膨胀,代码库变成一个拥有数百个文件、数万行代码的庞然大物时,你会发现,即使有再完美的文档,AI在面对这个“巨兽”时,依然会开始表现出“困惑”、“健忘”甚至“精神错乱”的迹象。
它可能会在一个看似简单的修改中,引用一个八竿子打不着的模块;或者在重构一个函数时,忘记了它在五个文件之外的某个隐秘角落里被调用过。问题的根源,不在于我们的指令不够清晰,而在于我们向AI的大脑里,一次性塞入了远超其“认知带宽”的信息。
本章,我们将学习如何运用软件工程中最经典、最强大的思想——模块化与解耦——来解决这个问题。但这并非老调重弹,我们将从一个全新的视角,即“AI友好型架构”的视角,来重新审视和应用这些原则。
我们的目标是:通过精心的物理代码结构设计,将一个庞大的、令人生畏的代码库,拆解成一系列AI可以轻松理解和处理的、独立的“小问题”。我们不仅要解耦“代码”,更要解耦“AI的注意力”。
要理解如何治愈AI的“疯病”,我们必须先诊断它的病因。AI在面对庞大代码库时表现出的种种“智障”行为,并非因为它真的“笨”,而是源于其底层工作原理与人类心智模型的根本性差异。
人类工程师在阅读一个庞大项目时,大脑里会自动构建一个层次化的、带权重的心智模型。
而AI没有这种能力。对它来说,你提供给它的所有代码上下文,都是一个扁平化的、无差别的Token序列。config.js里的一个配置项,和UserService.js里的核心业务逻辑,在它的“眼中”,重要性是相同的。它缺乏对代码“宏观结构”和“语义重要性”的理解。
这种“扁平化诅咒”导致:
【实战噩梦】
你让AI修改一个CSS样式文件中的颜色变量。因为上下文中包含了整个项目的文件,AI在分析时,注意到了后端数据库配置文件db.config.js中,也有一个名为'primary-color'的字符串(可能是某个注释或测试数据)。结果,它不仅修改了CSS文件,还“贴心”地帮你把数据库配置文件里的字符串也改了,导致整个后端服务无法连接数据库。这就是典型的“错误关联”。
一个设计不良的大型项目,往往充满了各种“隐性依赖”。
人类开发者或许能通过“项目经验”和“口耳相授”记住这些“雷区”。但AI对此一无所知。这些隐性依赖,对于AI来说,就是“认知黑洞”。它在代码的字面上,完全看不到这两个模块之间有任何联系。
当AI修改了其中一个模块时,它无法预测这个改动会像一颗投入水中的石子,通过看不见的涟漪,影响到远方的另一个模块,最终导致系统在某个意想不到的地方崩溃。
【实战噩梦】
你的前端项目里,有一个authStore.js负责用户认证,它会在用户登录后,往window对象上挂载一个全局的currentUser对象。项目里有十几个组件,都隐式地依赖于window.currentUser的存在。现在,你让AI重构authStore.js,使用更现代的Context API。AI出色地完成了任务,但它不知道window.currentUser这个“黑魔法”的存在,自然也就删除了这行代码。结果,项目里那十几个组件,在用户登录后,全部因为读取不到currentUser而崩溃。
这是最直接、最物理的限制。所有大模型都有一个上下文窗口的Token上限。即使是像Claude 3这样拥有200K甚至1M超长上下文的模型,这个上限依然存在。
当你的项目代码总量超过这个上限时,你就不可能一次性把所有信息都喂给AI。你将不得不手动挑选“相关”的文件。但这个“挑选”的过程,本身就是一个巨大的心智负担,而且极易出错。你很可能会遗漏某个关键的依赖文件,从而误导AI做出错误的决策。
更重要的是,即便没有达到Token上限,上下文越长,AI的“推理成本”和“出错概率”也会呈指数级上升。在一个塞满了20万Token的超长对话里,AI的“注意力”会严重衰退,它很可能会忘记你在对话开始时定下的某个重要约束。这被称为“大海捞针”问题。
结论: 对抗AI“发疯”的根本方法,不是去训练一个更聪明的AI,也不是寄希望于无限长的上下文窗口。而是从我们的代码架构本身入手,将那个巨大的、扁平的、充满隐性依赖的“认知泥潭”,改造成一个由许多小型的、独立的、接口清晰的“认知积木”所组成的有序世界。
这就是模块化解耦在AI时代的全新使命。
在进行模块化解耦时,最常见的错误是按照“技术类型”或“功能页面”进行划分。比如,把所有的API请求放一个文件夹,所有的UI组件放另一个文件夹。这种划分方式有一定作用,但它并没有触及问题的核心。
一种更深刻、更符合AI心智模型的解耦模式,我称之为“能力驱动解耦”,或者叫“主流程-能力”模式。
这种模式的核心思想是:将一个复杂的业务功能,拆分为一个极其简洁、稳定的“主流程”,以及一系列可插拔的、独立的“辅助能力”。
【一个生动的比喻】
想象一下你在指挥一场电影拍摄。
作为导演,你只需要调用这三个团队即可。如果觉得爆炸效果不好,你不需要修改剧本,你只需要把特效团队叫过来,对他们说:“重做这个爆炸,我想要更震撼的效果。” 特效团队的工作,完全不会影响到演员或道具团队。
AI编程也应如此。我们作为“导演”(决策者),应该让AI分别去和各个“专业团队”(能力模块)打交道,而不是让它面对一整个乱糟糟的片场。
重构前:一个臃肿的“巨无霸”函数(AI的噩梦)
// A monolithic, AI-unfriendly function
async function handleUserRegistration(formData) {
// 1. Validation
if (!formData.email || !formData.password) {
// Directly manipulating UI state
showError("Email and password are required.");
return;
}
if (formData.password !== formData.confirmPassword) {
showError("Passwords do not match.");
return;
}
// 2. API Call (tightly coupled)
try {
const response = await fetch('/api/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: formData.email, password: formData.password })
});
if (!response.ok) {
const errorData = await response.json();
showError(errorData.message);
return;
}
const userData = await response.json();
// 3. Local Storage (tightly coupled)
localStorage.setItem('authToken', userData.token);
localStorage.setItem('user', JSON.stringify(userData.user));
// 4. Analytics (tightly coupled)
analytics.track('User Registered', { userId: userData.user.id });
// 5. Navigation (tightly coupled)
router.push('/dashboard');
} catch (error) {
showError("An unexpected error occurred.");
// 6. Logging (tightly coupled)
logErrorToServer(error);
}
}
这个函数就是典型的“认知泥潭”。它把校验、API、本地存储、分析、导航、日志等至少6个不同的“能力”,紧紧地耦合在了一起。如果你让AI修改其中任何一部分(比如“把localStorage换成sessionStorage”),AI的“扁平化”视野,需要同时理解所有这6个部分,极易出错。
重构后:“主流程-能力”模式(AI的天堂)
第一步:抽离“能力”模块
我们创建一系列独立的、职责单一的能力模块。
// capabilities/validator.js
export function validateRegistrationForm(formData) {
if (!formData.email || !formData.gpassword) return { isValid: false, message: "..." };
// ...
return { isValid: true };
}
// capabilities/authApi.js
export async function registerUser(email, password) {
const response = await fetch('/api/register', { ... });
// ...
return await response.json();
}
// capabilities/session.js
export function saveSession(token, user) {
localStorage.setItem('authToken', token);
localStorage.setItem('user', JSON.stringify(user));
}
// capabilities/analytics.js
export function trackRegistration(userId) {
analytics.track('User Registered', { userId });
}
// capabilities/navigation.js
export function redirectToDashboard() {
router.push('/dashboard');
}
// ...等等
注意,每一个能力模块都是纯粹的、独立的、易于测试的。让AI修改session.js,你只需要把这一个文件和它的测试文件给AI,完全不需要提供任何其他业务逻辑的上下文。
第二步:重写“主流程”
现在,我们用“导演”的视角,重写handleUserRegistration函数。
// main-flows/userRegistration.js
import { validateRegistrationForm } from '../capabilities/validator';
import { registerUser } from '../capabilities/authApi';
import { saveSession } from '../capabilities/session';
import { trackRegistration } from '../capabilities/analytics';
import { redirectToDashboard } from '../capabilities/navigation';
import { notifyError } from '../capabilities/notifier';
import { logError } from '../capabilities/logger';
// A clean, AI-friendly main flow
export async function handleUserRegistration(formData) {
const validation = validateRegistrationForm(formData);
if (!validation.isValid) {
return notifyError(validation.message);
}
try {
const { token, user } = await registerUser(formData.email, formData.password);
saveSession(token, user);
trackRegistration(user.id);
redirectToDashboard();
} catch (error) {
notifyError("Registration failed. Please try again.");
logError(error);
}
}
看到这个“主流程”的美妙之处了吗?
authApi.js;如果我们要改路由跳转的目的地,我们去改navigation.js。主流程文件本身,是对修改封闭的。AI如何在这种架构下工作?
现在,当你想让AI修改功能时,你的指令会变得无比精确和安全。
localStorage换成sessionStorage。”(AI需要在那个200行的巨无霸函数里,小心翼翼地找到那两行代码,同时祈祷不要影响到其他逻辑。)capabilities/session.js文件。请把其中的localStorage全部替换为sessionStorage。”(AI面对的是一个只有几行代码的小文件,任务清晰,不可能犯错。)通过“主流程-能力”模式的拆分,我们为AI创造了一个“最小认知单元”。我们每次只让它处理一个“能力”模块,这使得我们可以将提供给它的上下文代码量,降到最低,从而从根本上规避了AI在庞大代码库里“发疯”的所有病因。
“主流程-能力”模式是一种逻辑上的解耦思想。为了让它在物理上真正落地,我们需要设计一个与之匹配的、AI友好的项目目录结构。
一个“AI友好”的目录结构,其核心目标是:让“关注点”在物理上高度集中,让“依赖关系”在物理上清晰可见。 换句话说,就是经典的设计原则:高内聚,低耦合。
原则一:按“业务领域”而非“技术类型”组织
传统的项目结构喜欢这样组织:
/
├── components/ (所有UI组件)
├── services/ (所有API服务)
├── stores/ (所有状态管理)
└── utils/ (所有工具函数)
这种结构的最大问题是“低内聚”。当你需要开发一个“用户管理”功能时,你需要在components、services、stores这三个文件夹之间反复横跳。如果要让AI帮你开发,你就必须把这三个文件夹里的相关文件,一股脑地全扔给它,造成巨大的上下文负担。
AI友好的结构,应该按“业务领域”或“功能特性”来组织:
/
├── features/
│ ├── UserManagement/
│ │ ├── components/ # 只属于用户管理的UI组件
│ │ ├── hooks/ # 只属于用户管理的业务逻辑
│ │ ├── userApi.js # 只属于用户管理的API客户端
│ │ ├── userStore.js # 只属于用户管理的状态
│ │ └── index.js # 导出该功能的公共接口
│ ├── OrderManagement/
│ │ ├── ...
│ └── ...
└── shared/
├── components/ # 可被所有feature共享的通用组件 (Button, Input...)
├── hooks/ # 可被所有feature共享的通用hooks (useAuth, useApi...)
└── ...
在这种结构下,当你让AI开发“用户管理”功能时,它的“认知边界”被物理地限制在了features/UserManagement/这个文件夹内。你只需要把这个文件夹的上下文给它,它就能获得完成任务所需的全部信息,而不会被OrderManagement里的任何代码所干扰。这就是高内聚。
同时,UserManagement和OrderManagement之间没有任何直接的依赖关系。它们之间的通信,只能通过shared里共享的模块进行。这就是低耦合。
原则二:显式声明“公共接口”
每个业务领域模块(如UserManagement),都应该有一个index.js文件,作为其唯一的“出口”。这个文件显式地导出了该模块希望被外部(其他模块或应用主入口)使用的部分。
// features/UserManagement/index.js
// 只导出高阶组件和hooks,不暴露内部实现细节
export { UserListPage } from './pages/UserListPage';
export { useUserStore } from './userStore';
模块内部的其他文件,如components/UserTable.js,则不应该被外部直接引用。
这种做法的好处是:
index.js里的导出不变,模块内部的实现就可以自由地进行重构,而不用担心破坏外部依赖。UserManagement的功能时,你不需要给它看这个模块的全部源代码。你只需要告诉它:“你可以从features/UserManagement导入UserListPage和useUserStore。” 这就好像是给了AI一份简单易懂的“API文档”,而不是一本厚厚的“源码全集”。原则三:根除“魔术依赖”和“副作用”
AI最害怕的就是那些看不见的、隐式的依赖。一个AI友好的项目,必须致力于将所有依赖都显性化。
import。这使得依赖关系一目了然,并且极易于在测试中进行模拟。一个AI友好的项目结构,不仅仅是为了让人类看得更清晰,它更是一种主动的、为AI的“认知缺陷”量身定制的“脚手架”。 它通过物理隔离,强制性地降低了AI在任意时刻所需要处理的信息复杂度,从而将AI的强大算力,引导到我们需要的、安全的、创造价值的地方。
理论听起来很棒,但面对一个已经存在的、混乱的项目,从何下手呢?别怕,重构并不需要推倒重来。遵循以下步骤,你可以在半小时内,显著提升你现有项目的“AI友好度”。
前提: 你的项目已经使用了某种模块化系统(如ES Modules, CommonJS)。
这个阶段,我们只做“考古”和“规划”,不动一行代码。
src目录的完整文件结构,打印到一个文本文件中。UserList.jsx, api/user.js, stores/user.js...)用黄色标记。OrderTable.jsx, pages/OrderDetail.jsx, services/order.js...)用蓝色标记。components/Button.jsx, utils/formatDate.js...)用绿色标记。// New Structure Plan
/src
/features
/User/ (all yellow files go here)
/Order/ (all blue files go here)
/shared (all green files go here)
/lib (external library configs, e.g., axios instance)
/pages (if you use a file-based router like Next.js)
/styles (global styles)
App.jsx
main.jsx
现在,我们开始“搬家”。这个过程很机械,但非常重要。
features/User, features/Order, shared等新文件夹。components/UserList.jsx → features/User/components/UserList.jsxservices/order.js → features/Order/orderApi.js (可以顺便重命名)components/Button.jsx → shared/components/Button.jsxA移动到了B。请检查并修复其所有的import语句的相对路径。” AI会非常高效地完成这个任务。最后一步,为我们新的feature模块,建立清晰的“城墙”。
index.js文件:在每一个features目录(如features/User/)下,创建一个index.js文件。App.jsx或其他feature)使用的?通常是页面级组件、状态管理的store或高阶hooks。在index.js里将它们导出。// features/User/index.js
export { UserPage } from './components/UserPage';
export { useUser } from './hooks/useUser';
User模块功能的地方(比如你的主路由文件),将原来深层、混乱的导入,修改为从index.js导入。import { UserPage } from './features/User/components/UserPage';
import { useUser } from './features/User/hooks/useUser';
import { UserPage, useUser } from './features/User';
恭喜! 经过这30分钟,你的项目可能在功能上没有任何变化,但在“AI友好度”上,已经发生了质的飞跃。你现在拥有了一个:
features/User目录,而不用担心它会搞乱订单逻辑。index.js接口进行,大大减少了AI产生“认知黑洞”的可能。这半小时的投入,将在你未来与AI协作的数百个小时里,为你节省下难以估量的时间和心力。你为你的“超级实习生”,创造了一个它能理解、能高效工作的、整洁有序的工位。现在,你们可以一起,真正开始创造价值了。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。