让 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 是法律。

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐