核心论点:Rules 是三层漏斗中投入产出比最高的一层——写一次,永久生效。但写 Rules 本身有门槛:太泛了没约束力,太细了维护不了。关键是找到"刚好够用"的粒度。
Rules 是什么
CodeBuddy 的 Rules 系统本质上是一个上下文注入器。你在.codebuddy/rules/下写的 markdown 文件,AI 在编辑匹配的文件时会自动读入。
# 规则文件的头部元数据---description:Python 代码规范globs:"**/*.py"# 匹配 Python 文件时自动加载alwaysApply:false# false = 按 glob 匹配加载,true = 每次对话都加载---关键字段:
| 字段 | 作用 | 适用场景 |
|---|---|---|
globs: "**/*.py" | 编辑 .py 文件时加载 | 语言级规范(日志、异常处理) |
globs: "**/*.tsx,**/*.vue" | 编辑前端文件时加载 | 前端规范(组件结构、状态管理) |
alwaysApply: true | 每次对话都加载 | 项目级通用规范(禁止硬编码、统一配置入口) |
一个反面教材:规则太泛,等于没有规则
Shop-Agent 项目最初只有一份通用规则——“遵循对应语言/框架的代码风格规范”、“配置文件外部化,环境变量管理敏感信息”、“避免硬编码”。效果:AI 确实不硬编码了,但该重造轮子还是重造轮子。因为"避免硬编码"太泛了——"用 os.getenv(‘REDIS_HOST’)"也是没硬编码,但它绕过了你项目里的Settings类。
规则要精确到"用项目中哪个具体组件做这件事",而不是"要遵循什么原则"。
正确写法:三种规则类型
经过 Shop-Agent 项目的反复迭代,我们沉淀了三种有效规则:
类型 1:禁止清单(Forbidden List)
告诉 AI绝对不能做什么。这种规则最容易写,也最立竿见影。
# 禁止重复实现 ## 禁止事项 - 禁止新建 cache 类 → 用 `src/modules/chat/core/redis_cache_service.py` - 禁止直接调 openai.ChatCompletion.create → 用 `src/modules/chat/core/llm_service.py` - 禁止在 router 里写内联业务逻辑 → 必须在 `core/` 下用 service 层 - 禁止硬编码配置(API Key、URL、阈值)→ 全部通过 `src/core/config.py` 的 Settings 读取 - 禁止 print() 打日志 → 用 structlog / logger - 禁止自创 JSON Schema 生成 → 用 Pydantic `model_json_schema()` - 禁止新增 pip install 依赖 → 先检查 requirements.txt 是否已有为什么有效:AI 的"默认行为"是写通用代码,禁止清单直接拦截了最常见的几种"默认行为→不兼容"路径。比如 AI 本能的"写个 cache 类"被第一条拦截后,它就会去搜索或询问现有的缓存方案。
类型 2:组件清单(Component Catalog)
告诉 AI项目里有什么可以用的。相比禁止清单的"不能做 X",组件清单是"用 Y 来做"。
# 已注册可复用组件 ## 核心基础设施 | 组件 | 路径 | 用途 | API | |------|------|------|-----| | 配置管理 | `src/core/config.py` | 所有配置统一入口 | `Settings()` | | 限流器 | `src/core/rate_limiter.py` | 并发控制 | `await rate_limiter.acquire()` | | Redis 缓存 | `src/modules/chat/core/redis_cache_service.py` | 对话缓存+向量缓存 | `get/set/delete` | | LLM 服务 | `src/modules/chat/core/llm_service.py` | 统一 LLM 调用 | `await llm.chat()` | | 工具注册 | `src/modules/chat/core/tool_registry.py` | 工具发现/调度 | `ToolService.dispatch()` | | 参数抽取 | `src/modules/chat/core/param_extractor.py` | 意图参数提取 | `extract()` | | 意图识别 | `src/modules/chat/core/intent_recognizer.py` | 意图分类 | `recognize()` | | 安全审查 | `src/modules/chat/core/content_filter.py` | 输入/输出过滤 | `filter()` | | 重排序 | `src/modules/chat/core/reranker_service.py` | 检索结果精排 | `rerank()` |关键设计:最后一列写了 API 入口。AI 看到model/embed就知道调用方式,不需要再去翻源码理解接口。
类型 3:编码约定(Coding Convention)
编程风格的硬性规定。这类规则最容易被写成泛泛的"遵循 PEP 8",但真正有用的是项目中实际踩过的坑。
# Python 编码约定 ## 异步 - 所有 I/O 操作必须用 async/await - 禁止用 time.sleep() → 用 asyncio.sleep() - 禁止用 requests 库 → 用 httpx.AsyncClient ## 日志 - 禁止 print(),统一用 structlog / logger ## 异常处理 - 禁止吞异常(bare except) - 业务异常抛 `BusinessException(code, message)`,不要抛裸 Exception - HTTP 异常统一由中间件捕获,service 层不要 try/except HTTPException ## 类型 - 所有函数必须有类型注解(含返回值类型) - disallow_untyped_defs=True(mypy 配置)规则粒度:什么时候拆成独立文件
从 Shop-Agent 的经验,一个很实用的原则:
| 规则类型 | 独立文件? | 理由 |
|---|---|---|
| 禁止清单 | 独立 | 会被频繁增删条目,隔离修改 |
| 组件清单 | 独立 | 内容多(表格),且需要自动化同步 |
| 编码约定 | 不独立 | 和语言绑定,自然放在python-code/RULE.mdc里 |
| 项目通用规范 | 独立 | alwaysApply: true,跨语言 |
所以我们项目的 Rules 目录最终是这样的:
.codebuddy/rules/ python-code/RULE.mdc ← 编码约定 + 通用 Python 规范 forbidden-list.mdc ← 禁止重复实现(独立维护) component-catalog.mdc ← 组件清单(自动化同步) project-rules/RULE.mdc ← 跨语言项目规范,alwaysApply为什么要拆:禁止清单和组件清单变更频繁(加新组件、发现新的常见错误),和编码约定放在一起会导致每次改一行就要 touch 整个文件——Git diff 噪音大,AI 上下文也膨胀。拆开后各司其职,维护成本最低。
规则维护:自动化而非手动
这是很容易被忽略的一点。手写的组件清单两周后就过时了——新加了a2a_task_service、改了一个类的签名,清单没跟上。
方案:脚本扫描 + Automation 定时同步
创建scripts/generate_component_catalog.py,通过静态分析扫描src/下所有公共类/函数,自动输出组件清单 markdown。然后用 CodeBuddy Automation 每周一自动跑:
名称: 同步组件清单 调度: FREQ=WEEKLY;BYDAY=MO;BYHOUR=9;BYMINUTE=0 任务: 运行 scripts/generate_component_catalog.py, 输出到 .codebuddy/rules/component-catalog.mdc这样组件清单永远和代码同步,不需要人工维护。
三条规则的生效场景对比
| 场景 | 禁止清单起作用 | 组件清单起作用 | 编码约定起作用 |
|---|---|---|---|
| AI 要加缓存逻辑 | 拦截"新建 cache 类" | 提供 redis_cache_service | - |
| AI 要调大模型 | 拦截"裸调 openai" | 提供 llm_service.chat() | - |
AI 写了time.sleep(5) | - | - | 要求 asyncio.sleep() |
AI 写了except: pass | - | - | 禁止吞异常 |
| AI 要在 router 里写 50 行业务 | 拦截"router 内联" | - | - |
三条规则各管一片,互不重叠。禁止清单和编码约定有少量交集(比如都涉及"不要做什么"),但禁止清单面向组件级复用,编码约定面向语言级规范。
立即可用的实操清单
如果你只做一件事,按这个顺序来:
- 先写禁止清单(10 分钟):列出你项目里最常见的前 5 个"AI 重造轮子"场景
- 在编码规则里加 3 条硬约定(5 分钟):日志方式、异常类型、类型注解要求
- 观察一周:看看 AI 又出现了哪些想重复实现的倾向,加到禁止清单
- 第二周开始做组件清单:有了前一周的积累,你知道哪些组件最常被 AI 忽略
别一开始就追求"完整组件清单"——那是第二周的事。第一周先把最痛的重造轮子场景堵住。
核心要点
- 规则要精确到"用哪个组件",不是"遵循什么原则"。
- 禁止清单 > 组件清单 > 编码约定,按这个优先级投入——禁止清单立竿见影,编码约定是锦上添花。
- 拆成独立文件——禁止清单和组件清单变更频繁,不要和编码约定混在一起。
- 组件清单用 Automation 自动同步——手写的清单两周就过时了。
- 从最痛的前 5 条开始,别追求大而全。AI 在你项目里最常重造的 5 个轮子,写进禁止清单即可见效。