ECC 的 Python 模式规则:用 Protocol、Dataclass DTO 与资源管理塑造 Agent 可执行的 Python 编码规范
导读:本文将围绕 ECC(Everything Claude Code)仓库中面向 Kiro/ECC 环境的 Python 模式 steering 文件展开,说明它是如何在 AI Agent 编辑
*.py文件时被自动加载、并将若干 Python 惯用模式固化为可执行编码规则的。读完本文,你将理解结构化鸭子类型(Protocol)、Dataclass DTO、上下文管理器与生成器这几组 Python 核心模式在 Agent 协作开发中的落地方式,并能在自己的 Kiro/Claude Code/Codex 项目中复用这套"规则 + skill + hook"的分层设计。
一、先认清这份文件的角色:一份按需注入的 Python 模式规则
在 ECC 仓库根目录的 .kiro 组件集中,.kiro/steering/python-patterns.md 属于 steering file(方向性规则文件) 的一员。依据 .kiro/README.md 的说明,steering file 提供"始终在线的规则与上下文",用来塑造 Agent 处理代码的方式,其中按加载策略分为三种:
inclusion: auto:每次对话都自动加载(如coding-style、patterns);inclusion: fileMatch:仅在匹配到特定文件扩展名/路径时加载;inclusion: manual:通过#dev-mode、#review-mode等指令手动触发。
本文件即第二种的典型代表。它的 YAML frontmatter 明确写入了注入条件:
---
inclusion: fileMatch
fileMatchPattern: "*.py"
description: Python patterns extending common rules
---
也就是说,当 Agent(Kiro IDE/CLI 中的 AI 助手)正在编辑或审查 .py 文件时,这份 Python 专属模式规则才进入上下文;处理 TypeScript、Go 等其他语言时则由各自的 steering 文件接管(例如 .kiro/steering/typescript-patterns.md、.kiro/steering/golang-patterns.md)。这种"语言匹配才注入"的机制,目的就是避免通用规则与 Python 专属约束相互干扰,同时把不必要的上下文负担降到最低。
文件开头的一句话点明了它在规则体系中的定位:
This file extends the common patterns rule with Python specific content.
也就是说,它不是独立王国,而是对通用模式规则的 Python 方言扩展。与之对应的通用规则在仓库中有两份同源副本:Kiro 侧位于 .kiro/steering/patterns.md(inclusion: auto),ECC 主规则侧位于 rules/common/patterns.md;而 Kiro 版之外,ECC 主规则仓库内也保存了几乎同内容的 Python 规则版本 rules/python/patterns.md,并声明 paths: ["**/*.py", "**/*.pyi"]。对比这两份文件可以看出,.kiro/steering/python-patterns.md 只是把同一套模式内容适配成 Kiro 的 frontmatter 格式,正文与 rules/python/patterns.md 保持一致——这正体现了 ECC"同一套规则、多 harness 适配"的工程做法。
二、Protocol(鸭子类型):用结构子类型替代继承耦合
steering 文件给出的第一组 Python 模式是"Protocol(Duck Typing)":
from typing import Protocol
class Repository(Protocol):
def find_by_id(self, id: str) -> dict | None: ...
def save(self, entity: dict) -> dict: ...
这是一段**结构子类型(structural subtyping)**声明:只要一个类具备 find_by_id 与 save 两个同签名方法,即便它没有继承任何基类,也被视为满足 Repository 契约。对比传统的 ABC + abstractmethod(名义子类型,必须显式继承),Protocol 的优势在于:
- 类型安全但不引入继承树:调用方(如业务服务)只需声明依赖
Repository类型,静态检查器(mypy、pyright)即可校验传入对象是否满足接口; - 解耦存储实现:无论底层是数据库、HTTP API 还是内存字典,只要实现对应方法就能被注入;
- 测试友好:在测试中可用轻量伪对象直接替换真实实现,无需 Mock 复杂继承链。
这段示例同时呼应了通用规则 rules/common/patterns.md 中"Repository Pattern"的定义——标准操作(findAll、findById、create、update、delete)收敛到一致接口、业务逻辑依赖抽象接口而非存储机制。二者放在一起读,才能看出 ECC 的思路:通用层定义"仓库模式该长什么样",Python 层定义"用 typing.Protocol 把它表达出来"。
更完整的落地示例可以在配套 skill .kiro/skills/python-patterns/SKILL.md 中看到,它补充了"任何具有这些方法的类都满足协议"的实现类、泛型化 Repository(Generic[T]) 以及基于 Protocol 的构造器注入写法(UserService.__init__(self, repository: Repository, ...))。
三、Dataclasses as DTOs:用数据类承载传输对象
steering 文件的第二组模式把 dataclass 定位为 DTO(数据传输对象)与值对象的标准载体:
from dataclasses import dataclass
@dataclass
class CreateUserRequest:
name: str
email: str
age: int | None = None
要点解析:
@dataclass自动生成__init__、__repr__、__eq__,让"定义数据结构 + 字段类型"成为唯一需要手写的部分;- 字段类型注解即文档:
age: int | None = None表示年龄为可选的整型,缺省值为None; - DTO 定位意味着它只做数据搬运,不承载业务行为,避免在 API 边界上泄露领域模型。
在 ECC 仓库自身代码中,这一模式有非常直观的运用。位于 src/llm/core/types.py 的 LLM 抽象层类型定义大量使用 frozen dataclass(@dataclass(frozen=True)),例如 Message 与 ToolDefinition。frozen=True 让实例不可变,天然具备哈希与线程安全语义,这与 rules/python/coding-style.md 中"优先不可变数据结构"(推荐 frozen=True dataclass 与 NamedTuple)的规则完全一致,形成"规则书写 → 仓库代码印证"的闭环。
若需要可变集合默认值或复杂默认值,skill 层给出了更完整的进阶写法:
from dataclasses import dataclass, field
@dataclass
class CreateUserRequest:
name: str
email: str
age: int | None = None
tags: list[str] = field(default_factory=list)
@dataclass(frozen=True)
class User:
"""Immutable user entity"""
id: str
name: str
email: str
其中 field(default_factory=list) 规避了"可变默认参数"这一经典 Python 反模式,frozen=True 则把 DTO 升级为不可变值对象;若需要校验,可在 __post_init__ 中执行 email 格式与年龄范围检查(详见 skill 中"Dataclasses with Validation"一节)。
四、Context Managers 与 Generators:资源管理与惰性迭代的两条铁律
steering 文件用两条精炼规则收束了 Python 资源管理的核心哲学:
- 使用上下文管理器(
with语句)进行资源管理; - 使用生成器实现惰性求值与内存高效的迭代。
这两条看似简短,实则是 Python 中最能影响正确性与内存占用的一组决策。展开看:
上下文管理器让资源释放无法被遗漏。 最典型的对照是文件读取:
# 正确:无论是否抛异常,with 块退出都会关闭文件
with open(path, 'r') as f:
return f.read()
# 错误:异常路径下可能泄漏文件句柄
f = open(path, 'r')
try:
return f.read()
finally:
f.close()
对于更复杂的"要么全成功要么全回滚"语义,.kiro/skills/python-patterns/SKILL.md 提供了基于 @contextmanager 的事务式上下文管理器——yield 之后的代码块充当 finally,出错时回滚并重新抛出异常:
from contextlib import contextmanager
from typing import Generator
@contextmanager
def database_transaction(db) -> Generator[None, None, None]:
"""Context manager for database transactions"""
try:
yield
db.commit()
except Exception:
db.rollback()
raise
with database_transaction(db):
db.execute("INSERT INTO users ...")
生成器把"一次性读入全量"变为"按需逐条产出"。 处理大文件或大结果集时,这是内存差异巨大的两种写法:
# 惰性逐行读取,内存占用与文件大小无关
def read_large_file(path: str) -> Iterator[str]:
with open(path) as f:
for line in f:
yield line.strip()
# 生成器表达式实现惰性求值(对比 list comprehension 会构造上百万元素的中间列表)
total = sum(x * x for x in range(1_000_000))
生成器还能组合成数据管道——前一个生成器的产出作为后一个的输入,全程不产生中间大列表(见 skill 的 Pipeline pattern 示例)。这一组合与 ECC 面向长流水线、资源受限的 harness 执行场景高度契合。
五、Reference:一条规则如何"向上收敛、向下授权"
steering 文件结尾的 Reference 段落值得单独解读:
See skill:
python-patternsfor comprehensive patterns including decorators, concurrency, and package organization.
这是一次明显的职责划分:
- steering/rules 层只保留最高频、最需要"每时每刻都提醒 Agent"的少量模式(Protocol、dataclass DTO、上下文管理器与生成器),避免常驻上下文过载;
- 完整模式目录交给按需调用的 skill。
python-patternsskill 在仓库中有两个可用副本——Kiro 侧 .kiro/skills/python-patterns/SKILL.md 与 ECC 主技能集 skills/python-patterns/SKILL.md,声明按**/*.py、**/*.pyi匹配。skill 中覆盖了 steering 文件未展开的纵深主题:
| 主题类别 | skill 中提供的具体内容 |
|---|---|
| 类型系统 | TypeVar/Generic/ParamSpec 泛型、str | int | None 联合类型(Python 3.10+)、类型别名 JSON |
| 装饰器 | functools.wraps 保元数据、参数化装饰器 @repeat(times=3)、类装饰器与单例、类型安全日志装饰器 |
| 并发 | ThreadPoolExecutor(I/O 密集)、ProcessPoolExecutor(CPU 密集)、asyncio.gather 与异步上下文管理器 |
| 错误处理 | 自定义异常层级(DomainError → 子类)、raise ... from e 异常链、Python 3.11+ except* Exception Groups |
| 包组织 | src/ 布局、domain/services/infrastructure 分层、__init__.py 显式导出与 __all__ |
| 面向对象进阶 | @property 读写控制、构造器注入式依赖注入 |
| 性能与内存 | __slots__ 减少内存占用、循环内字符串拼接改用 "".join()、StringIO |
因此,一套完整的 Python 模式体系在 ECC 中是这样协同的:通用层(rules/common/patterns.md)定设计原则 → Python 规则层(本文主题文件与 rules/python/patterns.md)给最高频 Python 表达 → skill 层(skills/python-patterns/SKILL.md)提供按需查阅的全量模式库 → hook 层在编辑时提醒 Agent 落实。四个层次按上下文代价递增、触发频率递减排列。
六、规则之外:让 Agent 真正"照章办事"的配套机制
模式规则只有在被 Agent 实际执行时才产生价值。ECC 为 Python 规则配备了三条执行保障:
1. 编辑即检查的 Hook。 配置文件 .kiro/hooks/python-lint-on-edit.kiro.hook 定义了:当 *.py 文件被编辑保存时(when.type = fileEdited),触发 Agent 对改动文件做"类型错误、PEP 8 违规、常见反模式"的即时检查并标记问题。这与 steering 文件的 fileMatch: "*.py" 在触发面上完全对齐——一个负责"写之前给规则",一个负责"写之后给检查"。
2. 专职评审 Agent。 仓库提供 python-reviewer agent(描述见 .kiro/README.md):专门按 PEP 8、类型注解、错误处理与最佳实践评审 Python 代码。规则文件负责把"应然"注入上下文,评审 Agent 负责把"实然"与规则对照。
3. 可落地的工具链配置。 ECC 仓库自身的 pyproject.toml 是这些模式可被执行工具验证的实证:ruff 开启 E/F/I/N/W/UP 规则集、mypy 设定 python_version 与严格检查、pytest 配置 testpaths、asyncio_mode = "auto";同时 typing 相关依赖与 src/ 布局(见 [tool.hatch.build.targets.wheel] packages = ["src/llm"])正是 skill 中"标准项目布局 + 现代工具链"一节的现实投影。换到任何项目,都可以参照这套配置把"Protocol、dataclass、惰性迭代"等模式变成机器可判定的门槛。
七、把这份模式清单用进你自己的项目
若想让自己的 Kiro / Claude Code / Codex 项目获得同样的 Python 模式约束,可按 .kiro/README.md 的安装方式操作:
# 定位到 .kiro 组件目录(Kiro 版 ECC 组件集)
cd .kiro
# 安装到指定项目(非破坏性拷贝,不覆盖既有文件)
./install.sh /path/to/your/project
# 或安装到当前目录 / 全局(对所有 Kiro 项目生效)
./install.sh
./install.sh ~
安装后,steering、skills、hooks 三类组件即可协同工作:编辑 .py 时自动加载本规则文件;需要完整模式参考时在对话中输入 /python-patterns 唤起 skill;保存文件时由 python-lint-on-edit hook 触发即时自检。你也可以复制 rules/python/patterns.md 与 rules/python/coding-style.md 到自己的 ECC 规则目录,使规则随代码评审流程一起生效。
实践建议速查:新写 Python 模块前先问三个问题——接口依赖是否需要"鸭子但可静态校验"(用 Protocol);跨层传递的数据是否需要自描述(用 dataclass/frozen=True DTO);资源或大数据的生命周期是否已交给 with 与生成器。这三个问题覆盖了 .kiro/steering/python-patterns.md 的全部要点,也是 Python 代码保持"可读、显式、最少惊讶"的最低门槛——正如 python-patterns skill 收尾所强调的:when in doubt, prioritize clarity over cleverness。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00