ADK-Python 文件组织规范实战指南:目录布局、文件头约定与测试镜像规则
【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-python
ADK(Agent Development Kit)Python 代码库在src/google/adk/下维护着数百个模块,为了让新增代码在"私人可见性、统一文件头、可预测的测试落点"三方面保持一致性,仓库通过.agents/skills/adk-style/这一风格技能沉淀了一套文件组织规范。本文以 file-organization.md 为骨架,结合workflow/、tools/environment/的真实目录、scripts/compliance_checks.py的合规检查实现与.pre-commit-config.yaml的钩子配置,讲清楚在 ADK-Python 中新增一个.py文件时应遵循的布局规则、文件头要求,以及测试文件"镜像源码路径"的命名方法论,帮助你在提交代码前一次性通过全部机器检查。
一、两条核心布局原则
原文档将文件组织概括为两条铁律,任何新增代码都必须遵守:
workflow/目录下"一文件一类"(One class per file):src/google/adk/workflow/中的每个模块文件只承载一个核心类,文件与类一一对应。src/google/adk/下新增模块默认私有(private by default):新文件必须以_下划线前缀命名,是否对外暴露由包的__init__.py与可见性规则决定。
从仓库实际目录看,这两条原则被严格执行。以src/google/adk/workflow/为例,目录下几乎全是_前缀文件,且每个文件对应一个独立类:
src/google/adk/workflow/ ├── __init__.py # 公开 API 的出口 ├── _base_node.py # BaseNode / START ├── _graph.py # Graph / Edge / DEFAULT_ROUTE ├── _node.py # Node / node 装饰器 ├── _join_node.py # JoinNode ├── _function_node.py # FunctionNode ├── _retry_config.py # RetryConfig ├── _errors.py # NodeTimeoutError ├── _workflow.py # Workflow └── _node_runner.py # 内部运行器(不出现在公开 API)而src/google/adk/workflow/__init__.py正是可见性规则的落点:它定义了__all__,只导出BaseNode、DEFAULT_ROUTE、Edge、FunctionNode、JoinNode、Node、NodeTimeoutError、RetryConfig、START、Workflow、node这些公开符号,并通过_LAZY_MEMBERS字典将符号映射到各自的_私有模块做惰性导入,外部使用者从包顶层导入,永远不需要也不应该触及内部_模块。这与 visibility.md 中"文件私有、符号经__init__.py显式导出"的约定完全呼应——原文档在 file-organization 中只是点了一句"see the visibility reference",想要完整理解命名规则与公开符号暴露机制,应配合该参考文档阅读。
二、文件头三部曲:每个src/google/adk/模块的标准开头
规范要求src/google/adk/下的每个模块文件都从以下三部分开始,顺序固定:
- Apache 2.0 许可证头:由
addlicense钩子自动补齐; from __future__ import annotations:延迟注解求值,配合类型检查与 Pydantic 模型定义使用;- 导入语句:按"标准库 → 第三方 → 相对导入"三段排列。
from __future__ import annotations这一条并非口头约定,而是被scripts/compliance_checks.py的check_future_annotations()函数机器化强制:任何不在豁免名单内的源码文件缺失该行,compliance-checks检查就会失败并阻断提交。豁免范围与文档描述完全一致——__init__.py、version.py、tests/目录以及contributing/samples/目录下的文件无需该语句。
以src/google/adk/workflow/__init__.py的真实文件头为例,可以看到标准三段的实际形态:
# Copyright 2026 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # ...(Apache 2.0 许可证头全文) from __future__ import annotations from typing import TYPE_CHECKING from ..utils import _lazy其中from __future__ import annotations位于许可证头之后、所有导入之前;标准库导入(typing)与相对导入(..utils)分属不同段落,符合"standard library → third party → relative"的顺序约定。想要了解这三段之间更多细节(如cli/包的导入方向限制、TYPE_CHECKING的循环导入规避),可继续阅读 imports.md 与 typing.md。
三、机器强制:这些约定由哪些钩子守护
原文档指出许可证头由addlicense钩子添加、from __future__ import annotations由scripts/compliance_checks.py检查。仓库根目录的.pre-commit-config.yaml完整揭示了这三道防线:
- id: addlicense # 自动为文件添加 "Google LLC" + Apache 2.0 许可证头 name: addlicense entry: bash -c '... addlicense -c "Google LLC" -l apache "$@" ...' - id: check-new-py-prefix # 强制新增 .py 文件必须以下划线前缀命名(私有默认) - id: compliance-checks # 调用 scripts/compliance_checks.py 做多项合规检查 entry: scripts/compliance_checks.py其中compliance-checks的实际逻辑位于 scripts/compliance_checks.py,与文件组织规范直接相关的检查点包括:
check_future_annotations(content, filename):校验from __future__ import annotations是否存在,豁免条件精确实现为filename.endswith('__init__.py')、filename.endswith('version.py')、路径含'tests/'、路径含'contributing/samples/'四类;- 同一脚本还顺带检查 logger 命名(必须是
google_adk.前缀)、禁止cli/包外反向导入、mTLS 端点、内部短链与 FastAPI 路由装饰器顺序等,任一失败都会sys.exit(1)阻断流程。
因此,在 ADK-Python 中"文件放哪里、叫什么名字、文件头长什么样"不再是评审意见,而是 PR 之前就必须通过的机器门槛。相关钩子的完整清单与各自检查内容,可以对照 SKILL.md 末尾的 "A check failed — where to look" 速查表逐项定位。
四、测试文件放哪里:镜像源码路径
规范对测试落点的要求只有一句话:在tests/unittests/下镜像源码的目录结构。文档给出的第一组示例在仓库中真实存在:
src/google/adk/tools/environment/_edit_file_tool.py tests/unittests/tools/environment/test_edit_file_tool.py对应到仓库:源码位于 src/google/adk/tools/environment/_edit_file_tool.py,测试位于 tests/unittests/tools/environment/test_edit_file_tool.py。同一目录下还有配套的_read_file_tool.py→test_read_file_tool.py、_write_file_tool.py、_execute_tool.py等,镜像关系一一对应、目录层级完全一致。
这条规则的工程价值在于可推导性:看到任意一个src/google/adk/下的源码文件,任何人都能零成本推算出它的测试文件路径;反过来,测试失败时也能沿镜像路径立即定位到被测实现。注意镜像时只保留源码文件名的"去下划线、去扩展名"部分——_edit_file_tool.py对应test_edit_file_tool.py,前缀统一为test_,而不是test__edit_file_tool。
五、一对多测试:以源码文件名作为共享前缀
当一个源文件需要拆分成多个测试文件时,规范给出的命名技巧是:使用源码文件名(去掉前导下划线与扩展名)作为共享前缀,后缀表达测试关注的不同维度。文档示例在workflow/目录下同样真实存在:
src/google/adk/workflow/_workflow.py tests/unittests/workflow/test_workflow.py tests/unittests/workflow/test_workflow_hitl.py tests/unittests/workflow/test_workflow_nested.py对照仓库 tests/unittests/workflow/ 目录,这套命名体系被大规模执行:围绕_workflow.py一个源文件,测试族扩展到了test_workflow.py(基础行为)、test_workflow_hitl.py(人工介入场景)、test_workflow_nested.py(嵌套工作流)、test_workflow_concurrency.py(并发)、test_workflow_dynamic_nodes.py(动态节点)、test_workflow_failures.py(失败路径)、test_workflow_parallel_worker.py(并行执行)、test_workflow_routes.py(路由)等十余个文件;而_base_node.py、_graph.py、_join_node.py等同样各自拥有test_base_node.py、test_graph.py、test_join_node.py一一对应的测试。
这种"前缀 + 维度后缀"模式的好处是:用test_workflow_*一个 glob 就能搜出某个类的全部测试场景,源码变更时按前缀即可定位所有需要同步更新的测试文件,也方便 CI 按模块粒度并行分发测试任务。
六、实操自查清单
在 ADK-Python 中新增或移动一个.py文件前,对照以下清单逐项确认:
| 检查项 | 要求 | 强制方式 |
|---|---|---|
| 文件位置 | 功能模块放入src/google/adk/<子包>/对应目录 | 人工 + 评审 |
| 文件命名 | 新文件默认私有,必须以_前缀开头(如_workflow.py) | check-new-py-prefix钩子 |
workflow/内聚性 | 一个文件只放一个核心类 | 人工 + 评审 |
| 许可证头 | 文件头包含 Apache 2.0 许可证("Google LLC") | addlicense钩子自动补齐 |
| 延迟注解 | 非豁免文件必须含from __future__ import annotations | compliance-checks(compliance_checks.py) |
| 导入顺序 | 标准库 → 第三方 → 相对导入 | isort/ruff钩子 |
| 公开符号暴露 | 仅在包__init__.py中导入并写入__all__,配合 visibility.md | 人工 + 评审 |
| 测试镜像 | 测试置于tests/unittests/<同构路径>/test_<源码名>.py | 人工 + 评审 |
| 一对多测试 | 多测试文件共享test_<源码名>_前缀,后缀表达场景维度 | 人工 + 评审 |
需要说明的是:__init__.py、version.py、tests/与contributing/samples/四类文件享有豁免——它们无需from __future__ import annotations,但其余规则(如测试镜像)依然适用。若新增文件需要对外提供公开 API,请务必先阅读可见性参考文档,理解"文件私有、符号公开"的完整暴露链路,再动手提交。
【免费下载链接】adk-pythonAn open-source, code-first Python toolkit for building, evaluating, and deploying sophisticated AI agents with flexibility and control.项目地址: https://gitcode.com/GitHub_Trending/ad/adk-python
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考