【AI】如何让 Codex 严格遵循你的代码规范与架构风格
摘要:本文探讨如何让AI代码生成工具Codex遵循团队开发规范。Codex因训练数据多样性和上下文限制,生成的代码风格不一致。解决方案分四个层级:1)单次Prompt中明确规范要求和示例代码;2)项目级规范文件(如.cursorrules)和架构决策记录;3)团队级文档和代码库;4)工具链强制检查(如pre-commit)。通过分层约束,可使Codex输出符合团队规范的代码,提升协作效率。关键技巧
·
让 Codex 成为"团队资深开发":规范与架构的强制遵循指南
核心挑战:Codex 像一位能力很强的外包工程师——写得快,但风格不一定符合你的团队规范。如何让它"入乡随俗"?
一、问题根源:为什么 Codex 会"乱来"?
1. 训练数据的多样性
Codex 读过的代码风格:
├── Google 风格(Python)
├── PEP8 官方风格
├── 各种开源项目(风格混杂)
├── 个人博客(质量参差)
└── 你的团队风格?→ 占比极小
结果:生成代码风格随机,像"代码盲盒"
2. 上下文的局限性
| 场景 | 问题 |
|---|---|
| 空项目启动 | 无参考,按"常见模式"生成 |
| 已有代码库 | 只能看到当前文件,看不到团队规范文档 |
| 跨文件修改 | 无法感知项目级架构约束 |
二、解决方案全景图
┌─────────────────────────────────────────┐
│ Level 1: 即时约束(单次Prompt) │
│ ├── 风格描述(自然语言) │
│ └── 示例代码(少样本学习) │
├─────────────────────────────────────────┤
│ Level 2: 上下文注入(项目级) │
│ ├── .cursorrules / .ai-rules 文件 │
│ ├── 架构决策记录(ADR) │
│ └── 核心模块作为上下文 │
├─────────────────────────────────────────┤
│ Level 3: 系统级规范(团队级) │
│ ├── 代码规范文档(Markdown/PDF) │
│ ├── 架构蓝图(C4模型/UML) │
│ └── 历史代码库(RAG检索增强) │
├─────────────────────────────────────────┤
│ Level 4: 工具链强制(工程化) │
│ ├── Pre-commit Hook(自动格式化) │
│ ├── CI/CD 检查(Lint/SAST) │
│ └── 代码审查(人工最终把关) │
└─────────────────────────────────────────┘
三、Level 1:单次 Prompt 的精确约束
模板:风格强制描述
"""
【团队代码规范 - 必须严格遵守】
命名规范(违者重构):
- 类名:大驼峰,领域前缀(UserService, OrderRepository)
- 函数:动词开头,小驼峰,禁止缩写(getUserById ✅, getUsrById ❌)
- 私有:下划线前缀(_internalMethod)
- 常量:全大写下划线(MAX_RETRY_COUNT = 3)
代码结构(强制检查):
- 函数长度:≤30行,超限必须拆分
- 参数数量:≤4个,超限用DTO
- 嵌套深度:≤3层,用早期返回
- 导入顺序:标准库→第三方→本地模块,字母序
类型系统(Python严格模式):
- 全部函数必须类型提示,禁用Any
- 复杂返回用NamedTuple或TypedDict
- mypy --strict 零警告
错误处理(统一模式):
- 自定义异常继承BaseException→DomainException→具体异常
- 禁止裸except,必须捕获特定异常
- 日志记录:ERROR级别以上自动附加trace_id
文档规范(Google风格):
"""
技巧:少样本学习(Few-Shot)
在 Prompt 中插入团队现有代码作为"范例"
"""
【参考范例 - 严格模仿此风格】
范例1:领域服务(UserService)
```python
class UserService:
"""
用户领域服务,处理用户核心业务逻辑。
Attributes:
_user_repo: 用户仓储接口
_event_bus: 领域事件总线
"""
def __init__(
self,
user_repo: IUserRepository,
event_bus: IEventBus
) -> None:
self._user_repo = user_repo
self._event_bus = event_bus
async def activate_user(
self,
user_id: UUID,
activated_by: UUID
) -> UserActivationResult:
"""
激活用户账户。
Args:
user_id: 待激活用户ID
activated_by: 操作人ID(审计用)
Returns:
UserActivationResult: 包含激活后用户状态和领域事件
Raises:
UserNotFoundError: 用户不存在
UserAlreadyActiveError: 用户已是激活状态
"""
user = await self._user_repo.get_by_id(user_id)
if user is None:
raise UserNotFoundError(f"User {user_id} not found")
if user.is_active:
raise UserAlreadyActiveError(f"User {user_id} already active")
user.activate(activated_by)
await self._user_repo.save(user)
self._event_bus.publish(UserActivatedEvent(
user_id=user_id,
activated_at=datetime.utcnow(),
activated_by=activated_by
))
return UserActivationResult(
user=user,
events=[UserActivatedEvent]
)
【你的任务】
按照上述范例的风格,实现 OrderService 的 create_order 方法。
必须包含:相同的文档格式、类型提示、错误处理模式、事件发布机制。
“”"
---
## 四、Level 2:项目级规范注入
### 方案 1:.cursorrules 文件(Cursor 专属)
在项目根目录创建 `.cursorrules`:
```markdown
# 团队代码规范 - Cursor AI 遵循指南
## 全局约束
- 所有 Python 代码必须符合 PEP8 + 团队扩展规范
- 类型提示覆盖率 100%,禁用 Any
- 异步代码优先使用 asyncio,禁止混用线程
## 架构规则
- 严格遵循 Clean Architecture,禁止跨层调用
- Domain 层:纯业务逻辑,零外部依赖
- Application 层:编排用例,定义接口
- Infrastructure 层:实现接口,处理技术细节
- Interface 层:HTTP/WebSocket 入口
## 命名约定
| 层级 | 类名 | 方法名 | 文件命名 |
|------|------|--------|---------|
| Domain | UserEntity, OrderValueObject | 业务动词 | user_entity.py |
| Application | UserService, OrderUseCase | execute, handle | user_service.py |
| Infrastructure | UserRepositoryImpl, RedisCache | 技术动词 | user_repository_impl.py |
| Interface | UserController, OrderHandler | HTTP动词 | user_controller.py |
## 禁止清单
- [ ] 禁止在 Domain 层使用 datetime.now()(用时钟接口)
- [ ] 禁止 Repository 直接返回 ORM 对象(必须转 Domain 对象)
- [ ] 禁止在循环内查询数据库(必须用 IN 或 JOIN)
- [ ] 禁止明文存储密码(必须用 bcrypt)
- [ ] 禁止 API 返回 SQL 错误详情(必须转业务错误码)
## 测试要求
- 单元测试:pytest,覆盖率 >90%
- 测试命名:test_被测方法名_场景_预期
- Mock 策略:外部依赖全部 Mock,Domain 层不 Mock
## 文档模板
函数文档必须包含:
1. 一句话功能描述
2. Args: 参数名、类型、说明
3. Returns: 返回值类型、结构
4. Raises: 异常类型、触发条件
5. Example: 调用示例(复杂函数)
方案 2:架构决策记录(ADR)作为上下文
"""
【上下文注入】以下 ADR 文档描述本项目的架构约束,所有代码必须遵循:
ADR-001: 使用 CQRS 分离读写模型
- 命令(写):通过 ApplicationService → Domain → Repository
- 查询(读):直接通过 QueryService → 读优化数据库/缓存
- 禁止:在命令路径直接返回查询结果
ADR-002: 事件溯源(Event Sourcing)用于订单聚合
- Order 状态变更必须通过领域事件(OrderCreated, OrderPaid)
- 状态重建:从 Event Store 重放事件
- 快照策略:每50个事件生成快照
ADR-003: 外部 API 调用使用防腐层(Anti-Corruption Layer)
- 所有第三方调用必须经过 Adapter → Client → DTO 转换
- 禁止:业务代码直接依赖外部 SDK
- 熔断:Hystrix,超时 3s,失败率 50% 触发
【当前任务】
实现订单支付流程,必须遵循 ADR-001 的命令路径、ADR-002 的事件发布、ADR-003 的支付网关调用。
"""
方案 3:核心文件强制引用
在 Cursor/Copilot 中,将以下文件固定到上下文:
必引文件(Always Include):
├── architecture/ddd_concepts.py # 领域基类、值对象定义
├── architecture/base_repository.py # 仓储接口规范
├── architecture/unit_of_work.py # 事务管理
├── shared/exceptions.py # 异常体系
├── shared/events.py # 事件基类
└── pyproject.toml # 依赖约束(禁止随意添加)
示例文件(参考风格):
├── modules/user/user_service.py # 服务层范例
├── modules/user/user_repository.py # 仓储层范例
└── tests/user/test_user_service.py # 测试范例
五、Level 3:系统级规范与 RAG
方案:构建团队知识库
团队知识库结构(用于 RAG 检索):
├── 01-架构规范/
│ ├── 分层架构详解.md
│ ├── 领域驱动设计实践.md
│ └── 接口设计规范.md
├── 02-代码规范/
│ ├── Python编码规范.md
│ ├── 命名约定.md
│ └── 错误处理模式.md
├── 03-最佳实践/
│ ├── 性能优化指南.md
│ ├── 安全编码清单.md
│ └── 测试策略.md
├── 04-领域知识/
│ ├── 电商领域术语表.md
│ ├── 订单状态机.md
│ └── 支付流程.md
└── 05-历史决策/
├── ADR-001-使用CQRS.md
├── ADR-002-事件溯源.md
└── ADR-003-微服务拆分.md
RAG 流程:
# 伪代码:Codex 查询知识库
def generate_code_with_rag(requirement: str) -> str:
# 1. 检索相关规范
relevant_docs = vector_db.search(
query=requirement,
filters={"category": ["架构规范", "代码规范", "领域知识"]},
top_k=5
)
# 2. 组装增强 Prompt
enhanced_prompt = f"""
【团队规范检索结果】
{format_docs(relevant_docs)}
【需求】
{requirement}
【约束】
严格遵循上述检索到的规范,如有冲突以架构规范优先。
"""
# 3. 调用 Codex
return codex.generate(enhanced_prompt)
六、Level 4:工具链强制(最后一道防线)
Pre-commit Hook 自动修正
# .pre-commit-config.yaml
repos:
- repo: https://github.com/psf/black
rev: 24.1.0
hooks:
- id: black
args: [--line-length=88, --target-version=py311]
- repo: https://github.com/PyCQA/isort
rev: 5.13.0
hooks:
- id: isort
args: [--profile=black, --line-length=88]
- repo: https://github.com/PyCQA/flake8
rev: 7.0.0
hooks:
- id: flake8
args: [--max-line-length=88, --extend-ignore=E203]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: v1.8.0
hooks:
- id: mypy
args: [--strict, --ignore-missing-imports]
- repo: local
hooks:
- id: architecture-check
name: Architecture Compliance Check
entry: python scripts/check_architecture.py
language: system
files: \.py$
自定义架构检查脚本
# scripts/check_architecture.py
import ast
import sys
from pathlib import Path
class ArchitectureChecker(ast.NodeVisitor):
"""检查代码是否符合分层架构"""
VIOLATIONS = []
def __init__(self, file_path: str):
self.file_path = file_path
self.layer = self._detect_layer(file_path)
def _detect_layer(self, path: str) -> str:
if "/domain/" in path:
return "domain"
elif "/application/" in path:
return "application"
elif "/infrastructure/" in path:
return "infrastructure"
elif "/interface/" in path:
return "interface"
return "unknown"
def visit_Import(self, node):
# Domain 层禁止导入外部依赖
if self.layer == "domain":
for alias in node.names:
if alias.name in ["requests", "sqlalchemy", "redis"]:
self.VIOLATIONS.append(
f"{self.file_path}:{node.lineno}: "
f"Domain层禁止导入外部依赖 {alias.name}"
)
self.generic_visit(node)
def visit_Call(self, node):
# 检查是否直接实例化 Repository(应该用依赖注入)
if isinstance(node.func, ast.Name) and "Repository" in node.func.id:
if not self._is_injected(node):
self.VIOLATIONS.append(
f"{self.file_path}:{node.lineno}: "
f"禁止直接实例化 {node.func.id},应使用依赖注入"
)
self.generic_visit(node)
def _is_injected(self, node):
# 简化检查:是否在 __init__ 中被赋值
# 实际实现需要更复杂的 AST 分析
return False
def main():
violations = []
for py_file in Path("src").rglob("*.py"):
with open(py_file) as f:
tree = ast.parse(f.read())
checker = ArchitectureChecker(str(py_file))
checker.visit(tree)
violations.extend(checker.VIOLATIONS)
if violations:
print("架构规范检查失败:")
for v in violations:
print(f" ❌ {v}")
sys.exit(1)
else:
print("✅ 架构规范检查通过")
sys.exit(0)
if __name__ == "__main__":
main()
CI/CD 强制检查
# .github/workflows/code-quality.yml
name: Code Quality Gate
on: [push, pull_request]
jobs:
quality-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install black isort flake8 mypy pytest
pip install -r requirements.txt
- name: Format check
run: |
black --check --diff src/
isort --check-only --diff src/
- name: Lint
run: flake8 src/
- name: Type check
run: mypy --strict src/
- name: Architecture check
run: python scripts/check_architecture.py
- name: Test coverage
run: |
pytest --cov=src --cov-report=xml --cov-fail-under=90
- name: Security scan
run: |
pip install bandit safety
bandit -r src/
safety check
七、实战:完整工作流示例
场景:新功能"订单取消"
Step 1:准备规范上下文
# .cursorrules(已存在)
# ADR-004-订单状态机.md(已存在)
# src/modules/order/order_service.py(参考范例,已固定上下文)
Step 2:编写约束性 Prompt
"""
【功能需求】实现订单取消功能
【必须遵循的规范】(来自 .cursorrules)
1. 通过 OrderService 应用服务入口
2. 领域逻辑在 Order 聚合根内实现 cancel() 方法
3. 状态校验:已发货订单不可取消(根据 ADR-004 状态机)
4. 发布 OrderCancelledEvent 领域事件
5. 调用 InventoryService 释放库存(通过防腐层)
6. 记录操作日志(审计用)
【参考实现风格】
见 src/modules/order/order_service.py 中的 create_order 方法
【禁止】
- 在 Service 中直接操作数据库(必须用 Repository)
- 在 Domain 中调用外部服务(必须用事件或接口)
- 返回原始 ORM 对象(必须转 DTO)
【输出要求】
1. 先输出 Order 聚合根的 cancel 方法(Domain层)
2. 再输出 OrderService.cancel_order 方法(Application层)
3. 输出对应的单元测试(pytest)
4. 每个方法附带架构合规性说明(如何满足规范)
"""
Step 3:Codex 生成 → 人工审查
# Codex 生成代码
class Order:
def cancel(self, cancelled_by: UUID, reason: str) -> List[DomainEvent]:
"""
取消订单(Domain层)。
架构合规:
- ✅ 纯业务逻辑,无外部依赖
- ✅ 状态校验在聚合根内完成
- ✅ 返回领域事件,不直接调用外部服务
"""
if self.status == OrderStatus.SHIPPED:
raise DomainException("已发货订单不可取消")
if self.status == OrderStatus.CANCELLED:
raise DomainException("订单已是取消状态")
self.status = OrderStatus.CANCELLED
self.cancelled_at = datetime.utcnow()
self.cancel_reason = reason
return [OrderCancelledEvent(
order_id=self.id,
cancelled_by=cancelled_by,
items=[item.sku for item in self.items],
reason=reason
)]
# 人工审查点:
# ✅ 符合状态机约束(ADR-004)
# ✅ 无外部依赖(通过架构检查脚本)
# ⚠️ 需确认:cancelled_by 是否已在上下文中验证权限?
Step 4:自动化检查
$ git add .
$ pre-commit run --all-files
black....................................................................Passed
isort....................................................................Passed
flake8...................................................................Passed
mypy.....................................................................Passed
Architecture Compliance Check............................................Passed
$ git push
# CI/CD 流水线自动运行,全部通过后合并
八、常见陷阱与解决
| 陷阱 | 现象 | 解决方案 |
|---|---|---|
| 规范描述太长 | Codex 忽略后半部分约束 | 拆分为必做(硬性)和推荐(软性),硬性放前面 |
| 示例代码过时 | Codex 模仿旧风格 | 定期更新参考范例,确保与当前规范一致 |
| 跨文件不一致 | 同项目不同文件风格迥异 | 强制引用共享基类和工具函数 |
| 规范冲突 | 多条规范矛盾(如简洁 vs 安全) | 明确优先级(安全 > 性能 > 简洁) |
| 新规范难推广 | 历史代码不符合新规范 | 分阶段:新代码强制,旧代码逐步重构 |
九、一句话总结
让 Codex 遵循规范 = 把规范变成它上下文的一部分 + 用工具链强制执行。
Prompt 是建议,Hook 是法律。
更多推荐



所有评论(0)