ADK Python 代码风格指南:adk-python 仓库的可见性、类型、Pydantic 与测试约定全解
【免费下载链接】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-python(Agent Development Kit)源码仓库中的编码规范与代码库约定,覆盖src/google/adk/与tests/unittests/两大区域:文件与符号的私有化可见性规则、导入方向、类型注解与 mypy 严格模式、Pydantic v2 模型模式、格式化与 pre-commit 钩子、日志、异步 I/O、文件组织与单元测试结构。读完本文,你将能够按照 ADK 的 house style 编写或修改源码与测试,定位各类格式化/静态检查失败(pyink、isort、ruff、mypy、addlicense、compliance-checks)的对应参考文档,并理解这些约定背后的设计理由。
本指南的权威出处是仓库中的 .agents/skills/adk-style/SKILL.md 及其references/目录下的 10 份分主题参考文档;文中的实现证据来自 src/google/adk、tests/unittests、pyproject.toml 与 scripts/compliance_checks.py。
一、约定总览:谁在强制这些规则
ADK 的大多数代码风格约定并非停留在"建议"层面,而是由pre-commit 钩子或CI 任务强制执行——违反规则会直接阻塞 PR,而不是等到代码评审阶段才被发现。因此,"读懂约定"与"知道去哪里查约定"同样重要。
1.1 按任务查参考文档
SKILL.md 给出了一张"任务 → 参考文档"速查表,写作或修改代码时应只阅读与当前任务相关的唯一参考文档:
| 任务 | 参考文档 |
|---|---|
新增.py文件;判断公共 vs 私有;__init__.py与__all__ | visibility.md |
编写import行;相对 vs 绝对;循环导入;TYPE_CHECKING | imports.md |
参数与返回值注解;Optionalvs\| None;keyword-only 参数;isinstance;assert;mypy | typing.md |
| 定义 Pydantic 模型、validator、私有属性或线上传输载荷 | pydantic.md |
| 缩进、行宽、引号;运行格式化器;各钩子检查什么 | formatting.md |
| 编写 docstring 或解释性注释 | documentation.md |
| 输出日志记录;模块 logger 命名;选择日志级别 | logging.md |
| 涉及 I/O 的一切——网络、磁盘、数据库 | async.md |
| 新文件放哪里;license 头;测试放哪里、叫什么 | file-organization.md |
| 编写或重构单元测试 | testing.md |
1.2 按失败的检查项查参考文档
当某个钩子报错时,对照下表定位问题来源:
| 失败的检查 | 参考文档 |
|---|---|
check-new-py-prefix | visibility.md |
compliance-checks | logging.md(logger 名)、typing.md(from __future__ import annotations)、imports.md(cli/导入方向) |
pyink、isort、ruff、addlicense、codespell | formatting.md |
| Mypy Check CI 任务 | typing.md |
二、可见性:private-by-default 的文件与符号体系
Python 没有访问修饰符,因此 ADK 用命名约定与模块结构来定义可见性边界,详见 visibility.md。
2.1 模块私有 / 内部文件
- 默认私有:
src/google/adk/下所有新增.py模块文件默认都必须带_前缀,由 pre-commit 钩子check-new-py-prefix强制。 - 即使文件内含有面向公共 API 的符号,文件本身也必须带下划线,符号再通过包的
__init__.py暴露出去。 - 仅供包内部使用的文件同样带前缀,例如
_task_models.py。 - 这类文件绝不允许被 ADK 框架之外的代码直接导入。
2.2 类与函数的可见性
- 公共:无下划线前缀,供模块/包的消费者使用。
- 内部/私有:带下划线前缀(如
_private_method()),仅供定义它的类或模块内部使用。
2.3 包私有(子系统可见性)
由于 Python 没有真正的 package-private 机制,ADK 通过以下方式模拟:
- 不导出:包级
__init__.py不导出该符号; - 下划线模块:内部实现细节放在
_前缀模块中; - 同一包内的代码可以导入这些
_模块,包外代码不可以; - 直接导入:框架内部必须从具体模块导入,绝不能从包的
__init__.py导入(原因见导入章节——避免循环导入与整包急切加载)。
2.4 公共 API 导出
- 包公共 API 必须在
__init__.py中显式导出; - 必须定义
__all__明确列出公共 API 符号; - 只有面向包外使用的公共名称才能被导入进
__init__.py并列入__all__; - 用户应能直接从包级别导入公共符号,而不是钻入内部模块。
2.5 示例:暴露公共接口 vs 隐藏实现细节
# 文件 src/google/adk/agents/llm/task/_task_agent.py(文件默认私有) class TaskAgent: # 公共符号 ... # 文件 src/google/adk/agents/llm/task/__init__.py from ._task_agent import TaskAgent __all__ = [ 'TaskAgent', ]# 文件 src/google/adk/agents/llm/task/_task_models.py(内部文件) class TaskRequest(BaseModel): # 模块内公共,但模块本身私有 ... # 文件 src/google/adk/agents/llm/task/__init__.py # 若 TaskRequest 仅供 task 包内部使用,则此处不导出它。三、导入规范:方向、分组与 TYPE_CHECKING
imports.md 定义了导入的三条核心规则。
3.1 相对导入 vs 绝对导入
- 源码(
src/):使用相对导入。from ..agents.llm_agent import LlmAgent - 测试(
tests/):使用绝对导入。from google.adk.agents.llm_agent import LlmAgent - 从模块导入,而非从包导入:写
from ..agents.llm_agent import LlmAgent,绝不写from ..agents import LlmAgent。在框架内部经由__init__.py导入会制造循环导入,并迫使包急切加载无关模块。 cli/包的特殊规则:- 把它当作外部包对待;
cli/内部文件之间用相对导入;cli/外部文件用绝对导入;- 依赖方向:
cli/可以导入代码库其余部分,但代码库其余部分不得导入cli/。scripts/compliance_checks.py 会在任何包外from ...cli... import ...时让提交失败。
3.2 一行一个名字
isort使用googleprofile(见 pyproject.toml 中profile = "google"配置),每个被导入的名字独占一行,因此from typing import Any, Optional会被拆成两行。排序不区分大小写,且不按类型分组——这正是PrivateAttr排在model_validator之后的原因:
from typing import Any from typing import Optional from pydantic import BaseModel from pydantic import Field from pydantic import model_validator from pydantic import PrivateAttr导入分为三个组,以空行分隔:标准库、第三方、相对导入。在测试中,google.adk归入第三方组(pyproject.toml的known_third_party),与google.genai、pytest并列。
3.3 不要折行长导入
80 字符限制不适用于 import 行:isort配置了line_length = 200(已确认位于 pyproject.toml),pyink 也会保持 import 行完整。长的from ... import ...保持单行——代码库中不存在带括号的 from-import。手动加括号或换行会在下一次格式化时被还原。
3.4 TYPE_CHECKING 导入
仅类型提示需要、但运行时可能造成循环导入的导入,应放在TYPE_CHECKING块中:
from __future__ import annotations from typing import TYPE_CHECKING if TYPE_CHECKING: from ..agents.invocation_context import InvocationContext其原理是:from __future__ import annotations让所有注解变成字符串(延迟求值),因此该导入在运行时永远不会真正执行。
四、类型注解与强类型:mypy strict 时代的写法
typing.md 是类型层面的核心参考。
4.1 通用规则
- 全量注解:所有函数参数与返回值都要写类型提示;
- 最小化
Any:优先使用具体类型或TypeVar,因为Any会禁用流经它的所有值的检查; from __future__ import annotations位于每个模块顶部:紧跟 license 头之后、其他任何 import 之前。scripts/compliance_checks.py 会在缺失时使提交失败。豁免对象:__init__.py、version.py、tests/、contributing/samples/;- 禁止带引号的类型提示:延迟注解已让前向引用无需引号,写
list[str]而非"list[str]"; - 内置泛型:新代码使用
list[str]、dict[str, int]、tuple[str, ...]。typing.List/typing.Dict只残留在旧模块中,不要新增、也不要无谓改写旧的。
4.2 Mypy 严格模式
Mypy 以strict 模式针对src/运行,并启用 Pydantic 插件,目标 Python 3.11——这些配置已确认在 pyproject.toml 的[tool.mypy]段(strict = true、plugins = ["pydantic.mypy"])。tests/与contributing/samples/被排除。
mypy .CI 任务会把你分支的错误与基线分支对比,只对新增错误失败——你触碰的文件里既有的错误不是你的问题,但你新增行上的错误是。
4.3Optional[X]vsX | None
两种写法在代码库中并存,约定是:
- 新代码(尤其是
workflow/):优先X | None; - 已有文件:跟随文件内既有风格;
- 没有理由就不要把一种重构为另一种。
4.4 参数用抽象类型、返回用具体类型
参数用collections.abc的抽象类型,让调用方可以传入任何兼容容器;返回用具体类型,让调用方确切知道拿到什么:
from collections.abc import Mapping from collections.abc import Sequence def merge_labels( labels: Mapping[str, str], extra: Sequence[str] ) -> dict[str, str]: ...4.5 Keyword-Only 参数
在参数顺序容易写错的构造器或函数中,在参数前加*——两个同类型参数就足以造成静默 bug:
class NodeRunner: def __init__( self, *, node: BaseNode, parent_ctx: Context, run_id: str | None = None, ): ...适用场景:含 2 个及以上非self参数的构造器、交换两个参数仍能通过类型检查的任何函数、接受多个str或int参数的方法。
4.6 可变默认参数
可变默认值在定义时只求值一次并被所有调用共享,一个调用方的修改会泄漏给下一个调用方。用None作为哨兵:
# Bad——每个调用方共享同一个 list def add(item: str, items: list[str] = []) -> list[str]: ... # Good def add(item: str, items: list[str] | None = None) -> list[str]: items = list(items) if items else [] ...这适用于list、dict、set及任何其他可变类型。
4.7 运行时类型判别:isinstance()
isinstance()是代码库处理多态输入的标配。写穷尽的if/elif链,并且总是以else收尾:
if isinstance(node, FunctionNode): ... elif isinstance(node, (JoinNode, ToolNode)): ... else: raise TypeError(f'Unsupported node type: {type(node)}')- 必须包含抛出
TypeError或处理未知情况的else,让新子类大声失败而不是静默无操作; - 优先
isinstance(x, SomeType)而非type(x) is SomeType——前者兼容子类; - 用元组一次检查多个类型:
isinstance(x, (TypeA, TypeB))。
4.8 生产代码禁用 assert
assert在 Python 以-O运行时会被剥离,因此断言不是运行时保证,且其失败信息对调用方毫无帮助。应改抛ValueError、TypeError或RuntimeError。测试中的 assert 没有问题。
五、Pydantic v2 模式:ADK 模型的标准写法
ADK 的模型全部基于Pydantic v2,pydantic.md 给出了统一模式。
5.1 基本模型结构
- 用
Field()表达校验、默认值与描述; - 用
PrivateAttr()表达不需要序列化的内部状态; - 用
model_post_init()做构造后置逻辑,而不是覆盖__init__——覆盖 Pydantic 模型的__init__会绕过校验顺序; - 使用
model_dump()/model_dump_json(),而不是 v1 的dict()/json()。
5.2 机制选择速查表
| 需求 | 模式 |
|---|---|
| 简单的数值/字符串边界 | Field(ge=0, le=100) |
| 单字段业务逻辑 | @field_validator('field') |
| 跨字段一致性 | @model_validator(mode='after') |
| 字段弃用/迁移 | @model_validator(mode='before') |
| 内部可变状态 | PrivateAttr(default_factory=...) |
| 构造后置设置 | model_post_init() |
5.3Field()约束
把边界声明在字段上,而不是为它们写 validator——规则紧贴数据,并会出现在生成的 JSON Schema 中:
compaction_interval: Optional[int] = Field(default=None, gt=0) injected_latency_seconds: float = Field(default=0.0, le=120.0)5.4 字段文档
house style 是在字段正下方写属性 docstring,Sphinx 可直接拾取:
model: Union[str, BaseLlm] = '' """The model to use for the agent. When not set, the agent inherits the model from its ancestor. """这些 docstring 仅作文档用途。若要让它们同时成为 JSON Schema 中的字段描述,在模型的ConfigDict中设置use_attribute_docstrings=True;SerializedBaseModel已默认启用:
class MyModel(BaseModel): model_config = ConfigDict(use_attribute_docstrings=True) field_name: str """Description of the field."""5.5 线上传输模型(On-Wire Models)
跨越网络或存储边界的模型——API 载荷、WebSocket 消息、持久化事件——应继承google.adk.utils._serialized_base_model中的SerializedBaseModel而非BaseModel。它设置alias_generator=to_camel加populate_by_name=True,并让model_dump_json()默认by_alias=True。于是 Python 侧保持 snake_case,线上格式保持 camelCase,调用方无需每次都记得传by_alias。
5.6field_validator:单字段校验
当约束需要Field()无法表达的逻辑时使用:
@field_validator('max_llm_calls') @classmethod def validate_max_llm_calls(cls, value: int) -> int: if value <= 0: raise ValueError('max_llm_calls must be positive.') return value规则:
- 在装饰器下显式加
@classmethod。Pydantic v2 会隐式应用,但 ADK 代码库中每个 validator 都显式写出; - 返回(可能被转换后的)值;
- 抛出命名了字段与边界的
ValueError; - 默认模式是
'after'(强转后运行),几乎总是你想要的,省略该参数。只有需要拦截原始输入时才传mode='before'。
5.7model_validator:跨字段与迁移校验
mode='before'——弃用与字段迁移:接收原始输入(通常是 dict),在任何字段被解析之前运行,用于重命名或回填字段:
@model_validator(mode='before') @classmethod def check_for_deprecated_save_live_audio(cls, data: Any) -> Any: """If save_live_audio is passed, use it to set save_live_blob.""" if isinstance(data, dict) and 'save_live_audio' in data: warnings.warn( 'The `save_live_audio` config is deprecated, use `save_live_blob`.', DeprecationWarning, stacklevel=2, ) if data['save_live_audio']: data['save_live_blob'] = True return data务必用isinstance(data, dict)防护:输入也可能是已经构造好的模型实例,直接索引会抛异常。
mode='after'——跨字段一致性:接收构造好的实例并必须返回它:
@model_validator(mode='after') def _validate_parallel_worker_config(self) -> Node: if self.max_parallel_workers is not None and not self.parallel_worker: raise ValueError( 'max_parallel_workers can only be set when parallel_worker is True.' ) return self六、格式化与 pre-commit 钩子:每条规则由谁执行
设置以 pyproject.toml 与.pre-commit-config.yaml为唯一权威来源,formatting.md 是对两者的汇总。
6.1 核心格式参数
- 2 空格缩进,绝不用 tab(
pyink-indentation = 2); - 80 字符行宽(pyink
line-length = 80),import 行例外; pyink(Google 的 Black 分支)负责 Python 格式化;- 引号跟随文件内已有的主流风格(
pyink-use-majority-quotes),pyink 不会把'x'重写成"x"——跟随被编辑文件的风格,而不是来回折腾引号; isort以profile = "google"排序导入(已确认位于 pyproject.toml)。
6.2 每个钩子检查什么
| 钩子 | 作用 |
|---|---|
ruff | 仅删除未使用的导入(lint.select = ["F401"]),自动修复,仅src/。__init__.py豁免,因为它的导入是再导出 |
isort | 导入顺序与分组 |
pyink | 其余所有格式化 |
addlicense | 为.py/.sh添加 Apache 2.0 头。Go 二进制未安装时跳过并告警;CI 仍会捕获 |
check-new-py-prefix | src/google/adk/下新文件需_前缀——见可见性章节 |
compliance-checks | logger 名、from __future__ import annotations、cli/导入方向、mTLS 端点 |
codespell | 代码与散文中的拼写。确属误报的加入 pyproject.toml 的ignore-words-list |
pyproject-fmt | 规范化pyproject.toml自身 |
mdformat | 仅README.md、CONTRIBUTING.md与contributing/**.md |
check-yaml、end-of-file-fixer、trailing-whitespace | 空白与 YAML 语法卫生 |
update-constraints | pyproject.toml变化时重新生成constraints-3.*.txt,需要网络 |
src/google/adk/cli/browser/、src/google/adk/v1/与v1_tests/从所有钩子中排除。
6.3 运行格式化器
安装一次 git 钩子,提交时自动格式化:
pre-commit install检查尚未提交的改动:
# 仅已暂存文件(这正是提交钩子运行的内容) pre-commit run # 指定文件 pre-commit run --files {path/to/file.py} # 全部文件 pre-commit run --all-filesCI 运行的是同一套配置,因此一次干净的pre-commit run --all-files意味着 lint 任务会通过。类型错误是独立的 CI 任务——见类型章节。
七、文档与注释:写 Why,不写 What
documentation.md 的要点:
- 类:解释预期用法;签名看不出用法时给出简洁示例;记录每个公共属性。Pydantic 模型用字段下方的属性 docstring 记录字段——见 Pydantic 章节;
- 方法与函数:记录每个参数、返回值与抛出的每个异常;
- 内部实现注释:解释为什么,而不是做了什么。代码本身已经说明了它做什么;注释的价值在于说明为什么这样做——代码中看不到的约束、bug 或顺序要求;
- 不链接 RFC、设计文档、issue 或 PR:它们腐化得比代码快,打不开链接的读者什么都得不到。把推理写进注释本身,链接放进 PR。
八、日志:统一 logger 树与级别语义
logging.md 是日志规范。
8.1 模块 logger
每个需要记日志的模块都以google_adk.前缀声明 logger:
logger = logging.getLogger('google_adk.' + __name__)scripts/compliance_checks.py 会在出现裸logging.getLogger(__name__)时使提交失败。前缀把所有 ADK 记录归入同一棵 logger 树,因此嵌入 ADK 的应用只需一次logging.getLogger('google_adk')调用就能提升或静默框架的日志,而不影响自己的日志。这一约定在源码中处处可见,例如 src/google/adk/agents/base_agent.py、src/google/adk/agents/_managed_agent.py 等模块均按此模式声明。
8.2 通用规则
- 惰性格式化:把值作为参数传入,字符串只在级别启用时才构建。
- 好:
logger.info('Processing item %s', item_id) - 坏:
logger.info(f'Processing item {item_id}')
- 好:
- 绝不记录机密:API key、凭据、token 或 PII;
- 上下文日志:可用时包含 trace ID,使记录在调用链上可关联。
8.3 日志级别
- DEBUG:诊断细节,内部实现中放心使用;
- INFO:预期里程碑(工作流开始、节点完成);
- WARNING:意外但不阻止操作继续(一次重试、一个弃用字段);
- ERROR:阻止操作完成的失败。
九、异步与并发:I/O 必须进 async def
async.md 是异步代码的核心约束:
- I/O 属于
async def:网络调用、文件系统访问、数据库查询、子进程等待都要放进 async 函数。ADK 在单个事件循环上运行一切,async 代码里的一次同步调用会拖住所有并发 agent,而不只是调用者; - 不要阻塞事件循环:async 代码内禁止同步 HTTP 客户端、
time.sleep或阻塞式文件读取; - 用
asyncio.to_thread包装同步 I/O:当某个库没有 async API(open()、pathlib、多数云 SDK 客户端)时:
async def save_data(path: Path, data: bytes) -> None: # 包装阻塞写入,让事件循环保持空闲。 await asyncio.to_thread(path.write_bytes, data)没有钩子检查这条规则——阻塞调用能通过 CI,之后以并发下的莫名延迟形式暴露,因此值得在评审阶段抓住。
十、文件组织:新文件放哪里、测试叫什么
file-organization.md 定义了物理布局。
10.1 文件头
src/google/adk/下每个模块以如下顺序开头:
- Apache 2.0 license 头(由
addlicense钩子添加); from __future__ import annotations;- 导入:标准库、第三方、相对导入。
from __future__ import annotations由 scripts/compliance_checks.py 检查,豁免__init__.py、version.py、tests/与contributing/samples/。另有约定:workflow/目录下一个类一个文件。
10.2 测试放在哪里
在tests/unittests/下镜像源码路径:
src/google/adk/tools/environment/_edit_file_tool.py tests/unittests/tools/environment/test_edit_file_tool.py一个源文件需要多个测试文件时,使用去掉下划线与扩展名的源文件名作为共享前缀:
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十一、单元测试:测行为,不测实现
testing.md 是测试编写的完整规范,仓库中 tests/unittests 的数千个测试均遵循此结构。
11.1 核心原则
- 通过公共接口测试——调用用户调用的,断言用户看到的;
- 测行为而非实现——验证结果(输出、副作用、错误),不验证内部机制;
- 重构免疫——若内部重构保持了相同行为,所有测试仍应通过。
pytest以asyncio_mode = "auto"运行,裸async def test_...无需@pytest.mark.asyncio。许多旧测试仍带着该标记,无害,也不值得清理。
11.2 测试命名描述行为
# 好——描述调用方观察到什么 def test_empty_queue_returns_none(): def test_retry_stops_after_max_attempts(): def test_missing_key_raises_key_error(): # 坏——描述实现细节 def test_deque_popleft_called(): def test_retry_counter_incremented(): def test_dict_getitem_raises():11.3 docstring:一行概述,复杂测试再补 Setup/Act/Assert
# 好——简单测试,一行足够 """Getting from an empty cache returns the default value.""" # 好——复杂测试带结构化分解 """Partial FR re-runs nested Workflow, resolved child completes while unresolved stays interrupted. Setup: outer_wf → inner_wf → (child_a, child_b) → join. Both children interrupt on first run. Act: - Run 2: resolve only child_a's FR. - Run 3: resolve child_b's FR. Assert: - Run 2: child_a produces output, invocation still interrupted. - Run 3: child_b produces output, join completes, no interrupts. """11.4 一个测试只覆盖一个行为
如果一个测试检查多个无关行为,拆开它。无法用一句话描述测试,说明它测得太多了。
11.5 不测内部状态
# 坏——伸手进私有属性 assert pool._workers[0].is_alive assert parser._state == 'HEADER' assert isinstance(router._handler, _FastHandler) # 好——通过公共接口测试 assert pool.active_count == 1 assert parser.parse('data') == expected assert router.route('/api') == handler11.6 用真实组件,只在边界处 mock
- Mock 外部依赖:LLM API、云服务、会话存储;
- 使用真实 ADK 组件:
BaseNode子类、Event、Context; - 测试
NodeRunner时 mockInvocationContext(它是边界)。
11.7 fixture 保持最小
定义能触发行为的最简单设置,避免"厨房水槽"式 fixture。
11.8 把 arrange 逻辑放在测试附近
只被一个测试使用的辅助类或 fixture 应内联定义在测试函数内;3 个以上测试共享时才提到模块级。
11.9 断言要"讲故事"
# 好——读起来像规格说明 assert queue.size == 0 assert config.get('timeout') == 30 assert response.status_code == 404 # 坏——过度防御,测的是框架行为 assert isinstance(queue, Queue) assert hasattr(config, 'get') assert len(response.headers) > 011.10 结构化为 arrange、act、assert
每个测试有三个清晰步骤:Arrange(设置场景特有外部状态,通用设置放 fixture)、Act(调用被测系统,通常一次调用)、Assert(验证返回值或可见状态变化,此处不再调用被测系统)。步骤间以空行分隔;复杂测试可用 "Given …"/"When …"/"Then …" 描述性注释,避免无信息量的裸标签。
11.11 按被测单元组织测试文件,而不是按改动
新测试加入被测模块/功能已有的测试文件中,绝不创建以 CL、bug 或一次改动命名的测试文件——那会把模块的覆盖碎片化,且因为下一个改该模块的人会在模块文件里找测试而不是在一次性文件里找而腐烂。新增文件前先找现有归属(test_<module>*.py);若兄弟测试已断言同一行为,扩展那条断言而非在新文件中复制。只有对真正的新模块/功能区才新建文件,命名为test_<module>_<feature>.py:
# 坏——以改动命名,把 llm_agent/runner/llm_request 的覆盖 # 碎片化进一个无人维护的大杂烩 tests/unittests/agents/test_improved_error_messages.py # 好——每个测试落在其单元所属的现有文件里 tests/unittests/agents/test_llm_agent_error_messages.py # LlmAgent 消息 tests/unittests/models/test_llm_request.py # LlmRequest 消息 tests/unittests/test_runners.py # Runner 消息11.12 测试文件结构模板
"""Tests for <ComponentName>. Verifies that <component> correctly <high-level behavior>. """ # --- Fixtures (minimal, one purpose each) --- def _make_service(): ... # --- Tests (one behavior per test) --- def test_<behavior_description>(): """<One sentence: what the system does from the outside.>""" # Given a service with default config service = _make_service() input_data = 'hello' # When the operation is performed result = service.do_something(input_data) # Then the result matches expectations assert result == expected十二、快速上手指南
为 adk-python 仓库贡献代码时,按以下顺序核对风格:
- 新增
.py文件:src/google/adk/下文件名带_前缀;测试文件镜像到tests/unittests/下,命名为test_<模块>[_<特性>].py,参考 visibility.md 与 file-organization.md; - 编写源码:文件头三件套(license +
from __future__ import annotations+ 分组导入);全量类型注解;I/O 进async def;日志用logging.getLogger('google_adk.' + __name__),参考 imports.md、typing.md、async.md、logging.md; - Pydantic 模型:
Field()表达约束、validator 处理逻辑、model_post_init()做置后设置,线上载荷继承SerializedBaseModel,参考 pydantic.md; - 提交前:
pre-commit run --all-files本地跑通全部钩子,再mypy .确认无新增类型错误;若某个钩子失败,按第二节的对照表定位参考文档,参考 formatting.md。
风格约定最终以 pyproject.toml 与.pre-commit-config.yaml为唯一权威来源,本文档是对它们的系统性汇总与解读。任何"这段代码是否符合 ADK 风格"的问题,都可以在 .agents/skills/adk-style 的 10 份参考文档中找到明确答案。
【免费下载链接】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),仅供参考