首页
/ Langflow AGENTS-example.md 解析:一份面向 AI 编码代理的开发规范模板,从权衡优先级到交付前检查清单

Langflow AGENTS-example.md 解析:一份面向 AI 编码代理的开发规范模板,从权衡优先级到交付前检查清单

2026-09-06 17:55:54作者:晏闻田Solitary

AGENTS-example.md 是 Langflow 仓库根目录提供的一份语言无关、框架无关的开发标准示例模板,定义了从核心理念、设计原则、代码质量、架构分层,到测试、评审与交付前检查的完整工程规范。本文以该模板为骨架逐节拆解其规则体系,并结合 Langflow 仓库中的实际配置(ruff、pytest、pre-commit、codecov)与配套的 docs/agents/ 文档、后端代码评审 Skill,展示这份模板在真实项目中如何被适配、落地与强制执行,帮助读者掌握"为 AI 编码代理编写可执行开发规范"的方法。

模板的定位:为什么 Langflow 需要一个 AGENTS-example.md

Langflow 仓库中存在多份面向 AI 编码代理(coding agent)的指引文件,分工明确:

  • AGENTS.md:项目级代理指引,描述项目概览、前置条件(Python 3.10–3.14、uv、Node.js)与常用命令(make initmake unit_testsmake alembic-revision 等);
  • CLAUDE.md:说明本项目采用 AGENTS.md 作为向 AI 代理提供上下文的标准,通过 @AGENTS.md 导入指令让 Claude Code 自动加载;
  • AGENTS-example.md本文主角——一个标注为 "EXAMPLE" 的参考模板,作者明确提示"使用需谨慎(Use at your risk)",建议在采纳前先按项目需要适配;
  • docs/agents/PHILOSOPHY.mddocs/agents/ARCHITECTURE.mddocs/agents/TESTING.md 等:Langflow 团队将模板思想"适配"到本项目后的实际产出(如十项项目哲学、单向依赖边界、组件测试基类);
  • .agents/skills/backend-code-review/SKILL.md:一个直接消费该模板规则的评审 Skill,其中明确引用了 "per AGENTS-example.md" 的文件行数限制,并把模板中的测试反模式(Liar、Mirror、Giant、Mockery……)逐条写进了评审规则。

可以看出,Langflow 的用法是:模板提供通用规则骨架,项目文档注入领域细节,工具链(Skill/pre-commit)负责强制检查。这种"模板 + 适配 + 执行"的三层结构,是本文解读该模板的主线。

核心理念:权衡优先级与基本规则(第 1 节)

模板开宗明义地给出了冲突发生时的权衡优先级(Trade-off Priority):

  1. 正确性(Correctness) —— 代码做它该做的事;
  2. 简洁与可读性(Simplicity and readability) —— 代码易于理解;
  3. 可测试性(Testability) —— 代码易于测试;
  4. 性能(Performance) —— 代码足够快;
  5. 抽象与复用(Abstraction and reuse) —— DRY。

这个排序的潜台词是:性能排第 4、抽象排第 5,意味着"先写对,再写快,最后才谈优雅"。模板结尾也再次强调:"当拿不准时,选择简单;当权衡发生时,遵循第 1 节的优先级。先构建正确性,之后再做优化,永远保持可测试。"

与之配套的基本规则(Ground Rules)共有五条:

  • 修改前先阅读并理解现有代码;
  • 遵循项目既有的模式与约定;
  • 需求含糊时,先提问再写代码;
  • 优先增量交付:先核心逻辑,再边界情况,最后打磨;
  • 不过度工程化,为今天的需求而建,不为假想的未来而建。

Langflow 自身的项目哲学文档 docs/agents/PHILOSOPHY.md 正是这种"先问该不该做,再问怎么做"思路的产物,其中第 11 条信条要求"没有证据证明改动有效,就不算修复"(先复现失败、再证明修复消除了它),与模板中"需求含糊时先提问"一脉相承。

设计原则:SOLID、DRY、KISS、YAGNI(第 2 节)

SOLID:附"常见误区"的实现版解释

模板没有停留在 SOLID 的口号上,而是为每条原则配了"规则 + 常见错误"两列的表格:

原则 规则 常见误区
SRP 单一职责 每个类/函数/文件只有一个变化理由。需要用到"和/或"来描述它时,就该拆分 把 SRP 误解为"一个类一个函数"。SRP 指的是一个变化轴
OCP 开闭原则 通过写新代码而非改旧代码来增加行为;在预期变化的地方用多态或策略模式 过早抽象导致的过度工程。OCP 只适用于有证据表明需求会变化的地方
LSP 里氏替换 子类必须遵守父类契约;"is-a" 关系不严格时优先组合而非继承 重写父类方法却直接抛 NotImplementedError 或什么都不做
ISP 接口隔离 定义小而面向角色的接口;客户端只依赖它用到的方法 创建一个含 15+ 方法的"上帝 service"接口
DIP 依赖倒置 在模块边界依赖抽象而非具体实现;领域逻辑永远不 import 基础设施 把 DIP 等同于"用依赖注入就行"。DIP 是反转源码依赖的方向

值得注意的是 Langflow 的架构文档 docs/agents/ARCHITECTURE.md 将 DIP 落成了可检查的硬规则:依赖图只能单向流动(langflow → langflow-base → lfxlfx 禁止 import langflow.*),并给出反例——"在 src/lfx/from langflow.services.deps import session_scope" 是违规写法,正确做法是在 lfx 内定义接口、由应用层注入实现。这正是模板中"依赖倒置"从概念到边界的典型适配。

DRY:三条红线

  • 只有当完全相同的业务规则在 3 处以上重复时(Rule of Three)才抽取共享逻辑;
  • 配置、常量、schema 定义保持单一事实来源;
  • 宁可重复,也不要错误的抽象。两段看起来相似但服务于不同业务目的的代码不是重复——强行合并会制造意外的耦合。

"错误的抽象"被明确定义为:过早泛化、目的不清、把无关关注点耦合在一起。

KISS 与 YAGNI:反过度工程的量化口径

  • 选择满足当前需求的最简实现;标准库优先于自造轮子;
  • "一次普通的函数调用胜过元编程;只需要数据分组时,字典胜过类";
  • 不要"以防万一"地引入设计模式、抽象或框架;
  • 只有存在具体的当前需求时才实现功能;至少有两个具体用例之前,不要搭"通用/可扩展"框架;
  • 定期删除投机性代码和无用的 feature flag;
  • "三行相似代码优于一个过早的抽象。"

代码质量:命名、类型、不可变性与函数设计(第 3 节)

命名规则

  • 名字应揭示意图,回答"它为什么存在、它做什么";
  • 函数用动词:getcreateupdatedeletevalidateformatparse
  • 布尔量用前缀:ishascanshould
  • 除非业界通用(idurlapi),否则不用缩写;
  • 禁用泛化命名:dataresultobjthingtempmiscutils
  • 名字中不出现 "and"、"or"、"then"——出现即暗示承担了多个职责。

这套命名规则在 Langflow 的评审 Skill ​.agents/skills/backend-code-review/SKILL.md 中被逐条复刻为检查项("Functions should use verbs (get, create, validate). Booleans should use prefixes (is_, has_, can_, should_)"),说明它已超出"示例"范畴,成为实际评审依据。

强类型、不可变性与早返回

  • 强类型:处处使用强类型,避免 any/object/dynamic/Object;公共函数必须有带类型的参数与返回值;不许为了编译通过而强转 any
  • 不可变:默认不可变(constreadonlyfinalfrozentuplefrozenset);转换函数返回新对象而非原地修改;绝不向外暴露可变内部集合,只返回副本或只读视图;函数内部的可变局部变量没问题——危险的是可变共享状态
  • 早返回与守卫子句:在函数顶部校验前置条件并尽早 return/throw;通过取反条件、提前返回来降低嵌套;让"快乐路径"停留在最低缩进层级。
  • 无魔法值:重复出现的数字和字符串抽成命名常量,用描述性变量名替代内联字面量。
  • 注释:不注释显而易见的代码;注释只解释 WHY,绝不解释 WHAT;不留注释掉的代码(那是版本控制的工作);TODO 注释必须带 ticket 引用。
  • 函数:保持短小、单一抽象层级;一个函数做一件事,做两件事就拆分;不用切换行为的布尔参数,而是拆成两个具名函数;每次改动都清除死代码和未使用的 import。

从仓库的 lint 配置看,这些规则有工具兜底:pyproject.toml 中 ruff 配置 select = ["ALL"]line-length = 120pydocstyle.convention = "google",即几乎启用全部 lint 规则族,并用 Google 风格 docstring 约定约束注释。

架构:分层职责、依赖注入与 DDD 的适用边界(第 4 节)

关注点分离

  • 领域、应用、基础设施三层关注点必须分离;
  • 领域/业务逻辑对框架、数据库、HTTP 层的 import 数量必须为零;
  • 副作用(I/O、日志、指标)留在系统边缘,业务逻辑保持纯粹;
  • 层与层边界上使用 DTO 或值对象——永远不要把 ORM 模型或 HTTP 请求对象传进业务逻辑。

分层职责表

模板用一张 "CAN / CANNOT" 表格把五类层的边界钉死:

可以 不可以
Handler/Controller 接收输入、委派给 service、返回输出 包含业务逻辑、直接调数据库
Service/Orchestrator 协调操作、执行业务规则 感知 HTTP/传输细节、直接执行 SQL
Repository/Data Access 执行查询、映射数据 做业务决策、调用外部 API
Helper 转换数据、校验、格式化 产生副作用、做 I/O、维护状态
External Client 与外部服务通信 包含业务逻辑、访问数据库

Langflow 的 docs/agents/ARCHITECTURE.md 给出了这张表的"项目化"版本——Service vs Utility vs Component 三分类:Service(继承 services/base.Service、经 services/factory.py 注册、有生命周期与共享连接的单例)、Utility(无共享状态、无生命周期的纯/近纯函数,放 helpers/lfx/utils/)、Component(画布上用户可见的节点子类)。它甚至点破了模板隐含的陷阱:"MyHelperService 这种其实只是一堆函数的 service" 是坏味道——工具函数就该是函数,不该套 service 壳。

依赖注入的五条细则

  • 通过构造函数或方法参数注入依赖,让所有依赖显式化;
  • 注入的是 I/O 边界(数据库、HTTP 客户端、文件系统、时钟),使它们在测试中可替换;
  • 组合根(composition root)留在应用入口,与业务逻辑分离;
  • 一个类需要注入超过 ~4 个依赖时,说明它职责过载,应拆分;
  • 只注入有副作用或随环境变化的东西;纯工具函数不需要注入。

DDD:仅在值得时应用

模板对领域驱动设计持谨慎态度:仅当领域复杂度确凿地证明有必要时才引入 DDD;Entity、Value Object、Aggregate 只在真正创造价值时使用;错误与不变量也应建模为领域的一部分。这与 Langflow 哲学第 2 条"每个后端能力必须落到画布上(如果不能被非 Python 用户以组件形式接线,它属于 SDK 而非平台)"的克制气质一致——先问"值不值",再谈"怎么建"。

文件结构:行数上限、职责分文件与命名禁区(第 5 节)

单文件生产代码上限

指标 指南
代码行数(不含 import、类型定义、文档) ~500 行(到 ~530 可接受;600+ 是红旗)
承担不同职责的函数 最多 5 个
承担相同职责(同前缀)的函数 最多 10 个
文件内主类 1 个
小型相关类(异常、DTO、枚举) 5 个(且同类型)

Langflow 评审 Skill 对这一节做了显式背书:"生产文件超过 ~500 行……600+ 行应视为红旗……测试文件超过 ~1000 行应按逻辑分组拆分(per AGENTS-example.md)",并解释了 500 行阈值背后的理由:行数越大的文件缺陷率越高、评审越慢,且是多重职责(SRP 违规)的信号。

单职责文件与"一句话测试"

每个文件必须有一个存在理由一个变化理由。判据是一个测试:能否不用"和/或",用一句话描述这个文件的用途?

按职责前缀分文件

函数必须按职责类别分组,不同前缀的函数不允许共存于同一文件

职责 函数前缀 对应文件
Types/Models 类型定义、接口、无逻辑的类 {feature}_types
Constants MAX_*DEFAULT_*、枚举 {feature}_constants
Validation validate*check*is_valid* validation
Formatting format*build*serialize*to_* formatting
Parsing parse*extract*from_* parsing
External calls fetch*send*call*request* {service}_client
Data access save*load*find*delete*query* {feature}_repository
Orchestration 主入口、协调 {feature}_service
Handlers 端点、控制器、视图 {feature}_handler

反过度拆分与命名禁区

  • 不要把 1–2 个合计不到 20 行的琐碎函数拆成独立文件;
  • 私有辅助函数(_func)留在使用它的文件里;一行工具函数不单独成文件;
  • 拆分时机 = 出现清晰、可复用的职责;合并时机 = 拆分只增加复杂度而无收益;
  • 永远不用泛化文件名的独立文件:utilshelpersmisccommonshared。评审 Skill 给出的解释是:叫 utils.py 的文件会在几个月内变成 50+ 个函数的垃圾场——每个函数组应放进以职责命名的文件(formatting.pyvalidation.py)。

模板最后给出一张标准模块结构图:

feature/
├── {feature}_service          # Orchestration
├── {feature}_types            # Type definitions
├── {feature}_constants        # Constants and enums
├── helpers/
│   ├── validation             # ONLY validation functions
│   ├── formatting             # ONLY formatting functions
│   └── parsing                # ONLY parsing functions
├── services/
│   └── {external}_client      # ONLY external API communication
├── repositories/
│   └── {feature}_repository   # ONLY data persistence
└── handlers/
    └── {feature}_handler      # ONLY request handling

错误处理:错误是 API 契约的一部分(第 6 节)

模板给出七条错误处理铁律:

  • 显式处理预期错误,零静默失败;
  • 不用泛型异常(ExceptionErrorobject),使用领域相关错误类型;
  • 抛出/返回的错误必须带上下文(什么失败、什么输入导致的、如何修复);
  • 错误是 API 契约的一部分;
  • 在系统边界校验输入,非法数据快速失败;
  • 区分可恢复错误与致命异常;
  • 绝不静默地"修正"非法输入——用清晰消息拒绝它。

配套的正反例代码:

# BAD
try:
    result = do_something()
except:
    pass

# GOOD
try:
    result = do_something()
except ValidationError as e:
    logger.warning("Validation failed", extra={"error": str(e), "field": e.field})
    raise DomainError(f"Invalid input: {e.field}") from e

要点在于 GOOD 写法做了三件事:捕获具体异常类型、把失败记入结构化日志(带 field 上下文)、以 raise ... from e 保留异常链——而不是吞掉异常假装一切正常。

安全:默认拒绝与边界校验(第 7 节)

模板的安全清单可以归纳为四组:

输入与信任边界

  • 在边界处净化并校验所有用户/外部输入;
  • 永远不信任系统边界之外的数据;
  • 使用白名单(allowlist)而非黑名单——默认拒绝,只接受已知安全的模式;
  • 复杂结构用 schema 校验库(Pydantic、zod、JSON Schema),不手写校验;
  • 服务端校验永远不可省略——客户端校验只是 UX 便利,不是安全措施。

密钥管理

  • 密钥不进代码,使用环境变量或 secret manager;
  • 不允许硬编码 API key、token、密码。

数据访问与错误输出

  • SQL 一律参数化查询,禁止字符串拼接;
  • 面向最终用户的错误消息不暴露内部细节。

测试数据

  • 测试中使用伪造/匿名数据,绝不使用真实用户数据。

在 Langflow 仓库中,"密钥不进代码"这条规则由工具链闭环执行:.pre-commit-config.yaml 配置了 detect-secrets 钩子(以 .secrets.baseline 为基线扫描),评审 Skill 也把"硬编码密钥"列为 Critical 级发现项。

可观测性:结构化日志、级别与 PII 零容忍(第 8 节)

日志原则

  • 使用结构化日志(key-value / JSON),而非格式化字符串;
  • 在关键决策点与边界处打日志,而不是在紧循环内部;
  • 日志应包含:操作名、相关 ID、结果(成功/失败)、必要时耗时;
  • 全代码库保持字段名一致。

日志级别

级别 使用场景
ERROR 有东西坏了,需要人工介入
WARN 降级但可自恢复
INFO 重要的业务事件
DEBUG 诊断细节,生产环境关闭

PII 零容忍

  • 绝不记录:邮箱、用户名、手机号、住址、token、密码;
  • 允许的标识符auth_iduser_idinternal_id
  • print() / console.log() 不得携带用户数据——它们会流向生产日志。

Langflow 的评审 Skill 把这一节细化到了具体实现层面:统一使用 lfx.log.logger 的异步日志方法(adebugainfoawarningaerroraexception),禁用 print() 与标准库 logging;允许的 ID 进一步收敛为 user_idflow_idsession_id;异常输出统一用 {e!s} 表示法。

测试:测试代码就是生产代码(第 9 节)

模板在此节的立场很强硬:"Test code is production code. 它接受同样的打磨、评审与质量标准。"

核心原则

  • 为所有核心逻辑写单元测试;
  • 遵循 AAA(Arrange-Act-Assert)结构:一个测试一个 act、一个逻辑断言
  • 测试必须相互独立、确定性、不依赖执行顺序;
  • Mock 或 fake 掉所有外部依赖(DB、API、文件系统、时间、随机性);
  • 测试命名清晰:should_[expected]_when_[condition]

不仅要验证,还要"进攻"

这是本模板最有辨识度的部分。模板明确指出:快乐路径测试只是地基,单独的快乐路径测试是不够的。必须写主动"进攻"代码、寻找缺陷的对抗性测试:

  • 意外的输入类型:None""[]{}0-1
  • 边界值:最大 int、最大长度、恰好等于上限、超过上限一格;
  • 畸形数据:缺字段、多字段、错误类型、非法格式;
  • 错误状态:依赖失败时会发生什么?
  • 验证"不该发生的事":被禁止的状态被正确拒绝;
  • 错误消息与类型:不只验证"它失败了",还要验证它如何失败。

并给出两条纪律:

  1. 基于需求/规格写测试,而不是照抄源码当前的行为——这是捕捉"代码偏离预期"型 bug 的唯一手段;
  2. 测试失败时先问代码是不是错了,而不是默默改断言去迁就现状——不理解原因就改断言是被禁止的。

测试文件规则

指标 指南
每文件行数 ~1000 行指南——超过可考虑拆分,但覆盖单一模块时非强制
每文件测试数 无硬性上限——只在覆盖无关行为时才拆分
Setup(Arrange) 每测试 ~20 行上限(超出则抽取为 helper/factory)

原则是按逻辑边界拆分测试文件,而不是按任意行数:一个文件对应一个模块/服务,即使 800+ 行也完全没问题。

覆盖率:80% 目标,75% 底线

  • 目标 80%,最低可接受 75%,低于 75% 视为任务未完成;
  • 重点盯分支覆盖if/else 两侧、所有 catch 块),而非仅仅是行覆盖;
  • 没有断言的高覆盖率毫无价值——每个测试至少有一个有意义的断言;
  • 覆盖率必须实际运行并展示(后端和前端都要)。

模板给出的三类运行命令:

# Python
pytest tests/your_tests.py --cov=src/module_under_test --cov-report=term-missing --cov-branch -v

# JavaScript/TypeScript (Jest)
npx jest tests/your_tests.test.ts --coverage --collectCoverageFrom="src/module/**/*.{ts,tsx}"

# JavaScript/TypeScript (Vitest)
npx vitest run tests/your_tests.test.ts --coverage

所有创建的测试必须通过:零失败、零异常;禁止禁用/跳过/删除测试来掩盖失败;禁止留下"以后再修"的测试;覆盖率不足 75% 就继续补测试、重跑,直到达标。

不该测什么:简单 getter/setter/trivial mapper 不值得测;实现细节(方法调用顺序、内部状态)应该测行为来替代;不要用无意义断言堆覆盖率。

七大测试反模式(禁止)

反模式 问题
The Liar(骗子) 测试通过,但没有验证它声称要验证的行为
The Mirror(镜子) 测试读源码然后断言代码恰好做了什么——零 bug 产出
The Giant(巨无霸) 50+ 行 setup、多个 act、几十个断言——应拆成 5+ 个独立测试
The Mockery(陪练) mock 多到测试实际只测了 mock 的搭建过程
The Inspector(窥探者) 与实现细节耦合,任何重构都把它打碎
The Chain Gang(连环犯) 测试依赖执行顺序或共享可变状态
The Flaky(飘忽者) 不改代码时有时过有时挂

结合仓库实际可以看到这套规范的"适配版"取舍:docs/agents/TESTING.md 针对模板中"mock 掉所有外部依赖"一条做了项目级修正——Langflow 明确"避免 mock、优先打真实依赖"(因为"mock 通过、生产失败"曾让团队付出多个发布周期的代价),mock 只保留给 LLM(MockLanguageModel)与真正不稳定且与被测逻辑正交的依赖;需要凭据的测试打 @pytest.mark.api_key_required 交给 CI 门控。而 codecov.yml 揭示了另一个现实:仓库当前的整体覆盖率目标(backend 55%、lfx 60%、frontend 10%、patch 40%)是"渐进式改进"的定位,与模板"新代码 80%/75%"的绝对要求并存——前者管存量大盘,后者管每次新增的交付质量。模板命令在 Langflow 中的对应物是 AGENTS.md 中的 make unit_tests(并行)、make unit_tests async=false(串行)、uv run pytest path/to/test.py,pytest 的 marker(api_key_requiredsecurityreal_services 等)统一声明在 pyproject.toml[tool.pytest.ini_options] 中。

代码评审:Blocker 优先的评审顺序(第 10 节)

模板定义了评审的固定优先级(先处理阻断项):

  1. 安全与 PII —— 日志无 PII、无硬编码密钥、输入有校验;
  2. DRY —— 无重复的类型、类、函数或逻辑;
  3. 文件结构 —— 行数上限被遵守、职责已分离;
  4. 架构 —— 单一职责、分层正确;
  5. 代码质量 —— SOLID、强类型、错误处理;
  6. 测试 —— 快乐路径对抗性测试兼备、覆盖率达标;
  7. 可观测性 —— 结构化日志、无 PII。

针对测试的四个灵魂拷问:

  1. 是否同时有快乐路径测试与对抗性测试?
  2. 如果有人改坏了逻辑,这些测试能否抓住回归?
  3. 是否存在没被覆盖的边界情况或失败模式?
  4. 如果我删掉一行业务逻辑,是否至少有一个测试会失败?

对遗留代码的态度是"不传染":不延续坏模式(即使周围代码很烂,新代码也要写好的);不未经评审就从遗留代码复制粘贴;在可能的范围内把新代码与遗留隔离。Langflow 的 docs/agents/ARCHITECTURE.md 对这一点有精确表述:"langflow/base/ 是遗留目录,不要再往里面加东西"——新共享原语一律进 src/lfx/src/lfx/base/

文档:C4 分级与功能文档必备章节(第 11 节)

何时写文档

  • 功能实现完成之后再生成功能文档;
  • 文档与代码同仓存放(Markdown);
  • 使用通用语言(ubiquitous language)——文档、代码、沟通中使用同一套术语。

C4 文档分级

级别 读者 内容
Context (L1) 产品/干系人 系统在其环境中的位置
Container (L2) 两者 应用、数据库、队列
Component (L3) 工程团队 内部服务细节

功能文档的八个必备章节

  1. Overview —— 摘要、业务背景、限界上下文;
  2. 通用语言术语表 —— 领域术语并附代码引用;
  3. 领域模型 —— 聚合、实体、值对象、事件;
  4. 行为规格 —— Gherkin 场景(快乐路径、边界、错误);
  5. 架构决策记录(ADR) —— 上下文、决策、后果;
  6. 技术规格 —— 依赖、API 契约、错误码;
  7. 可观测性 —— 指标、日志、仪表盘;
  8. 部署与回滚 —— feature flag、迁移、回滚预案。

交付前检查清单:代码出门前的最后一道闸(第 12 节)

模板要求:交付任何代码前,逐项验证全部清单项。

Critical(阻断项)

  • [ ] 任何日志、打印、webhook 消息中无 PII
  • [ ] 代码中无密钥或凭据
  • [ ] 无重复的类型、类或逻辑(DRY)
  • [ ] 无生产文件超过 ~500 行 / 测试文件超过 ~1000 行
  • [ ] 同一文件内无混合职责前缀的函数
  • [ ] 所有用户输入在系统边界被校验

Important(必须修复)

  • [ ] 每个文件/函数单一职责
  • [ ] 恰当的错误处理(无静默失败、错误信息有意义)
  • [ ] 强类型(无 anyobjectdynamic
  • [ ] 类型放专属 types 文件、常量放专属 constants 文件
  • [ ] 领域逻辑独立于框架/基础设施

Testing(强制)

  • [ ] 所有核心逻辑有单元测试
  • [ ] 快乐路径与对抗性测试同时存在
  • [ ] 所有创建/修改的测试通过——零失败
  • [ ] 覆盖率报告已运行且输出已展示(后端与前端)
  • [ ] 覆盖率 ≥ 75%(目标 80%)
  • [ ] 无测试反模式(Liar、Mirror、Giant、Mockery、Inspector)

Quality(应该修复)

  • [ ] 关键决策点有结构化日志
  • [ ] 注释解释 WHY 而非 WHAT
  • [ ] 无过度工程(没有 1–2 个琐碎函数单独成文件的文件)
  • [ ] 未延续遗留坏模式

Pre-Commit

  • [ ] Linter 已对所有改动文件运行——零错误
  • [ ] Formatter 已对所有改动文件运行——零 diff
  • [ ] 类型检查器已运行(如适用)——零错误

这份"Pre-Commit"清单在 Langflow 仓库中有完整的工具链对应物,恰好构成对模板第 12 节最有力的注脚。.pre-commit-config.yaml 中挂着的钩子包括:ruff check --fixruff format(对应 Linter/Formatter 零错误零 diff)、detect-secrets(对应"无硬编码密钥")、biome check 与 staged 的 no-any 检查(对应前端强类型)、以及一批 Langflow 自研检查脚本——如 check_component_env_writes.py(组件禁止写 os.environ,呼应"可变共享状态是危险")、Alembic 迁移的 Expand-Contract 校验等。评审 Skill 中的"Pre-Commit Verification"一节则把它变成评审动作:make format_backend(先格式化再评审,避免格式噪音掩盖真实改动)、make lint(lint 期发现的类型错误比生产崩溃便宜一个数量级)、make unit_tests(失败测试意味着改动破坏了既有行为,调查是代码错还是测试错)。

如何把这份模板落到自己的项目:从 Langflow 的实践看

把全文 12 节串起来读,AGENTS-example.md 实际上给出了一条可复制的落地路径,而 Langflow 仓库本身就是它的示范工程:

  1. 模板先行,标注"示例"身份。仓库根目录放 AGENTS-example.md,显式声明"Use at your own risk,采纳前请适配",避免它被误当成项目强制规范;
  2. 适配层注入领域细节docs/agents/ 下的 PHILOSOPHY / ARCHITECTURE / TESTING 等文档保留了模板的骨架(权衡、分层、对抗性测试、检查清单),但把通用规则替换成了可判定的项目事实:单向依赖图、组件版本兼容契约(file_names_mapping)、"避免 mock"策略、make unit_tests 命令;
  3. 工具链兜底强制pyproject.toml(ruff select = ["ALL"]、120 行宽、pytest marker 与 90s 超时)、codecov.yml(分组件的覆盖率目标与阈值)、.pre-commit-config.yaml(ruff/biome/detect-secrets/迁移校验钩子)把"软规则"变成提交前自动执行的"硬门禁";
  4. 评审 Agent 消费同一套规则.agents/skills/backend-code-review/SKILL.md 将模板的规则(500 行上限、75%/80% 覆盖率、七大测试反模式、PII 零容忍)转写成带 Critical/Suggestion/Nit 分级输出格式的评审 Skill,让人工评审与 AI 评审共用同一把尺子。

需要强调的适用前提:该模板自称"语言无关、框架无关",其表格中的命令(pytest/Jest/Vitest)与类名(如 Component)是示意性的;具体阈值(500 行、75% 覆盖率、~4 个注入依赖上限)是经验性指南而非行业标准,采纳时应以团队现状校准——正如 Langflow 把整体覆盖率目标设为渐进式的 55%/60%/10%,而把 75% 底线只施加于新交付的代码。模板结尾的三句话可以作为收尾原则:"拿不准时选择简单;权衡时遵循优先级;先正确,后优化,永远可测。"

登录后查看全文
热门项目推荐
相关项目推荐