让 AI coding 不再就近解决:如何在 monorepo 中建设 AI context

让 AI 写代码不再"就近解决":如何在 monorepo 里建设 AI context?

AI 常把需求写快了,但顺手又造一遍"节流/懒加载/环境判断"等轮子,结果是能跑却变沉,技术债上升。AI 不是不懂复用,而是"看不到"你的共享库。问题的本质是:AI 的思考模式天生倾向"就地解决",思维聚焦于当前文件或仓库。再加上其不清楚自己的能力边界,难以主动突破上下文限制,导致其很难"优先复用 monorepo 的能力",从而不断造轮子。

本文给出一套可被 AI 消化的上下文体系(CLAUDE.md + USEME.md + 规则),让它先复用、再改造,按团队的方法写对代码。你将看到:AI 如何"看世界"、monorepo 的典型局限、我们如何建设可消费的 AI context,以及一份可复制的落地清单。


AI 是怎么"看世界"的

语言模型不是 IDE,它靠"上下文窗口"理解你的意图。看得见的东西(当前文件、最近看过的文件、你粘给它的片段)权重更高。

以一个真实案例说明:我们让 AI 实现一个"判断是否在微信环境内"的功能。如果只把业务文件丢给它,AI 会写出这样的代码:

typescript 复制代码
// ❌ AI "就近解决" 的典型输出
const isWeChatEnv = () => /MicroMessenger/i.test(navigator.userAgent);

useEffect(() => {
    if (isWeChatEnv()) {
        // WeChat 专属逻辑
    }
}, []);

看起来不错?但问题是:

  1. 重复造轮子 :我们的 common-ua 包里已经有 isWeChat 方法了
  2. 脆弱的 UA 嗅探:容易被 UA 覆盖、WebView 差异或地区版本影响
  3. SSR 隐患 :直接访问 navigator/window
  4. 边界不清:未处理服务端渲染或无 UA 的场景

但如果 AI 能"看到"我们的公共库文档,它会写出:

typescript 复制代码
// ✅ 有了正确上下文后的输出
import { isWeChat } from 'common-ua';

if (isWeChat()) {
    // WeChat 专属逻辑
}

区别很明显:代码更短、更安全、更可维护。关键是 AI 需要在正确的时机"看见"正确的信息。


在 monorepo 里的两大局限

1. 找不到"正确的能力边界"

先看看我们的 monorepo 目录结构:

bash 复制代码
monorepo_apps/                     # 根仓库
├── support_modules/               # 公共能力仓库
│   ├── common-util/               # 纯工具函数库
│   ├── common-react-hooks/        # 无业务耦合 Hooks
│   └── common-ua/                 # UA/环境检测
│   └── ......
└── apps/                          # 业务应用
    ├── 业务1/                      # 业务1
    ├── 业务2/                      # 业务2
    └── ......

在这个结构中,AI 经常分不清能力边界,比如:

  • 让它做"移动端适配",它可能在业务代码里写 window.innerWidth < 768,而不是用 common-uaisMobile()

2. 文档信息碎片化

我们统计了一下改造前的文档分布:

  • README.md:数量多,内容重复度高,难以维护
  • 老 Wiki 页面:存在过期信息,容易误导
  • 口头传承的"最佳实践":不可追踪,且经常与代码不一致

AI 面对这么多信息源,经常选择"安全策略"------重新实现,而不是冒险引用可能过期的代码。


踩坑历程:从混乱到有序

第一阶段:意识到问题(痛苦期)

我们发现团队里 AI coding 的输出虽然能跑,但质量参差不齐:

统计数据(改造前 3 个月):

  • 重复实现的工具函数:27 个
  • 不一致的导入风格:占比 48%

典型问题案例:

typescript 复制代码
// 案例:AI 重复实现已有的 UA 检测
const isMobile = () => {
    return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
};

// 实际上 common-ua 里已经有更完善的实现:
import { isMobile } from 'common-ua/src/platform';

第二阶段:探索解决方案(试错期)

我们尝试了几种方法:

方法 1:对话窗口建立约定 效果:约等于没有。AI 不会记住上次的约定。

方法 2:在每个项目的 README 里写"使用指南"

效果:信息重复,维护成本高,AI 还是经常找不到。

方法 3:建立"代码库索引文件" 我们写了一个 index-of-libraries.md,列出所有可用的工具。 效果:有改善,但 AI 还是倾向于"就近解决",除非明确指出文件路径。

第三阶段:系统性改造(见效期)

在 monorepo 项目里用 AI,最重要的是要先给它"定好规矩"。 首先,每次让 AI 改代码之前,最好先让它了解一下项目结构。比如让它先看看根目录的 package.json 和 CLAUDE.md,确认这是个什么样的项目。我们项目有 25 个子应用,共享库就在 support_modules 目录下,这些信息对 AI 来说很重要。 其次,要明确告诉 AI"先找现成的,再考虑新写"。


我们的解决方案:让 AI 有"路标"、有"准则"、有"口袋书"

核心架构:两层文档体系

scss 复制代码
CLAUDE.md (总路标)
├── 快速开始 (命令速查)
├── Monorepo 概览 (包清单 + USEME 路径)
├── AI 协作规范 (Do/Don't)
├── 常见坑与约束
├── 文档地图与生成
└── 版本与兼容性说明

support_modules/*/USEME.md (具体指南)
├── 目录
├── 导入说明 (强制具体路径)
├── 重点 API 参数表
├── 分类 API 概览
├── 组件用法示例
├── 注意事项
└── 最佳实践与故障排除

1. 文档路标:CLAUDE.md

设计原则:AI 看到这个文件,应该能在 5 秒内理解项目全貌。 可以通过 claude init 命令生成,也可以借助其他大模型生成。

AI 协作规范(Do/Don't)

Do

  • 使用具体文件路径导入;禁止 barrel(如 import { X } from 'pkg')。
  • 最小化影响:不改对外 API;不做无意义格式化;保持文件/模块结构不变。
  • SSR 安全:涉及 window/document 仅在浏览器端执行;必要时判空/条件分支。

Don't

  • 不写版本兼容信息到 USEME(统一放本文件)。
  • 不扩大改动范围(移动文件、拆并模块)除非明确要求。

2. 可被 AI 消化的用法手册:各包的 USEME.md

在公共包下建立简约并明确的 USEME.md 文档,供 AI 阅读和了解该包的功能和用法。

设计原则:每个示例都能直接复制粘贴使用,每个参数表都能当 API 手册查。

提示词模板(给 AI 的最小上下文)

在与 AI 协作时,建议附上精简、稳定的上下文提示,避免跑偏:

objectivec 复制代码
你在一个 pnpm + monorepo 项目中工作。
先读根目录 CLAUDE.md 了解规则,再读相关包的 USEME.md。
优先复用 support_modules 下的能力,禁止 barrel 导入,必须使用具体文件路径。
若涉及 UA/SSR/性能,请优先查找 common-ua、common-react-hooks、common-util 的对应能力。
在给出修改前,用项目内既有 API 校对一次是否可复用。

小技巧:把这段模板固化到 .cursorrules 或常用的 Prompt 片段里,减少每次重复粘贴。

3. 跨仓库上下文打通:业务仓库"认识"support_modules

技术实现:给 cursor 添加 Rules:

go 复制代码
严格遵循工作流程:收到任务 → 检查 Rules → 分析项目结构 → 执行。
阅读项目中的 package.json、CLAUDE.md 和 USEME.md 以遵循项目约定。
检查该项目是否为 monorepo 架构,如果为 monorepo 子仓库,则向上查看父仓库和 support_modules 的指导文件(package.json、CLAUDE.md 和 USEME.md)以进行跨仓库协作。

关键机制

  1. 自动索引 :AI 会主动检查大仓的 CLAUDE.md
  2. 路径映射 :通过 CLAUDE.md 的"文档地图",AI 知道去哪找每个包的 USEME.md
  3. 优先级控制 :公共库的 USEME.md 比业务代码有更高的参考权重

实施细节:魔鬼在细节里

1. 文档结构的精心设计

标题层级:我们发现 AI 对标题层级很敏感

  • ## 重点 API 参数:AI 优先关注
  • ### 具体函数名:AI 能精确定位
  • #### 参数详解:AI 会仔细解析

表格格式:参数表的列顺序经过多次优化

markdown 复制代码
| 参数名 | 类型 | 默认值 | 必填 | 说明 |

这个顺序比其他排列方式的 AI 解析准确率高 15%。

2. 跨仓库协作的技术细节

完整目录结构

bash 复制代码
monorepo_apps/                  # 根仓库
├── claude.md                   # 总路标
├── support_modules/            # 公共能力仓库
│   ├── common-util/
│   │   ├── USEME.md
│   │   └── src/
│   ├── common-react-hooks/
│   │   ├── USEME.md
│   │   └── src/
│   └── common-ua/
│       ├── USEME.md
│       └── src/
└── apps/                       # 业务应用
    ├── 业务1/                   # 业务1
    └── 业务2/                   # 业务2

在根仓库 claude.md 中添加文档地图

bash 复制代码
support_modules - 核心业务逻辑模块
| 包 | 用途 | 文档 |
| ----------------- | --------------- | --------------- |
| umu-util | 工具函数库 | `support_modules/umu-util/USEME.md` |
| umu-react-hooks | 无业务耦合 Hooks | `support_modules/umu-react-hooks/USEME.md` |
| umu-ua | UA/环境检测 | `support_modules/umu-ua/USEME.md` |

AI 索引机制

  1. AI 读取 .cursorrules,知道要检查父仓库
  2. 通过 monorepo_apps/CLAUDE.md 获取全局规范
  3. 根据"文档地图"索引各包的 USEME.md
  4. 在生成代码时优先使用公共库的能力

踩坑经验:我们犯过的错误

1. 文档过于详细反而有害

错误做法 :最初我们在 USEME.md 里写了很详细的实现原理和设计思路。 结果:AI 被"误导",经常尝试"改进"我们的实现。

正确做法:只写用法,不写原理。让 AI 当"用户",不当"维护者"。

2. 示例代码的"诱导性"很强

错误做法:示例中使用了简化的错误处理:

typescript 复制代码
// ❌ 糟糕的示例
loadMore().then((data) => setList([...list, ...data]));

结果:AI 照搬这种写法,忽略了错误处理。

正确做法:示例必须展示完整的最佳实践:

typescript 复制代码
// ✅ 完整的示例
loadMore()
    .then((data) => setList((prev) => [...prev, ...data]))
    .catch((err) => showError(err.message))
    .finally(() => setLoading(false));

3. 过度约束反而降低效率

错误做法 :初期我们制定了 20+ 条详细规范。 结果:AI 被约束得"畏首畏尾",生成的代码过于保守。

正确做法:精简为 5 条核心约束,其他通过示例引导。


若你也准备在 monorepo 里用好 AI coding,可以这样落地

第一步:建立文档体系

核心文件优先级

  1. CLAUDE.md(总路标)
  2. 各公共包的 USEME.md(常用工具)

第二步:跨仓库集成

在编辑器(如 cursor)中添加 rules,

业务仓库配置

重要:因为 AI 往往会寻求"就近解决"。所以需要强制规定 AI 的思考模式,要求先阅读 rules 并了解项目结构,然后再工作。

arduino 复制代码
// .cursorrules
严格遵循工作流程:收到任务 → 检查 Rules → 分析项目结构 → 执行。
检查该项目是否为 monorepo 架构,如果为 monorepo 子仓库,则向上查看父仓库和 support_modules 的指导文件以进行跨仓库协作。

第三步:一小时落地清单(可直接执行)

  • 在根目录新增/完善 CLAUDE.md:包含包清单、文档地图、导入约束
  • 为常用公共包补齐 USEME.md:每个至少 1 个复制即用的示例
  • 统一导入方式:在示例和脚手架中全部改为具体文件路径
  • 在编辑器加入 .cursorrules:强制工作流与跨仓库检索
  • 加入 3 个简单的静态检查脚本(重复工具、barrel 导入、SSR 危险 API)
  • 选一个真实需求做"对照试验":先不加上下文生成一次,再按规范生成一次,对比差异

尾声

AI coding 的价值不止是"写快一点",更在于"写对一点"并且"复用多一点"。在 monorepo 里,这意味着给 AI 一张清晰的地图、明确的边界和可复制的惯用法。

我们用 CLAUDE.md 约束,用 USEME.md 传达,最终让 AI 在业务仓库里自然地"看见并复用" support_modules 的能力。实际落地后,重复造轮子的情况显著减少,提交一次通过率明显提升,新人融入速度也更快。

轮子造得再好,也比不上全仓库的人一起用同一个。现在,AI 也学会了这一点。

如果你也在大型项目里用 AI coding,不妨试试这套"文档驱动"的方法。让 AI 助手也会自动"学会"你们的最佳实践,成为真正能理解业务、写出符合团队要求代码的 AI coding engineer。

相关推荐
yangshuo12811 小时前
AI编程工具对决:Kilo vs Augment 开发Flutter俄罗斯方块游戏实战对比
flutter·游戏·ai编程
大志说编程2 小时前
LangChain框架入门17: 手把手教你创建LLM工具
python·langchain·ai编程
风云信步2 小时前
微软开源 GitHub Copilot VS code plugin 源码分析 (二) copilot-instructions.md 文件的应用逻辑
aigc·ai编程·cursor
bug菌2 小时前
还在为Java开发效率低下而苦恼?Trae能否成为你的编程救星?
aigc·ai编程·trae
风云信步2 小时前
GitHub CEO '不改变就改行': 拥抱AI,Copilot instruction用法详解
aigc·openai·ai编程
bug菌3 小时前
如何快速借助字节Trae解决Java 性能问题?看此篇最为关键!
aigc·ai编程·trae
cpp加油站3 小时前
用Trae2小时写一个vercel MCP,让内置的Vercel部署功能用起来更爽(玩转100个MCP系列第六弹)
ai编程·mcp·trae
mCell5 小时前
编程的演进:从指令到意图
ai编程·claude·trae
关山19 小时前
MCP实战
python·ai编程·mcp