news 2026/9/11 23:37:20

Deep Agents Monorepo 开发实战:基于 uv 与 make 的编辑-测试-lint 循环、Pre-commit 钩子与基准测试工程规范

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Deep Agents Monorepo 开发实战:基于 uv 与 make 的编辑-测试-lint 循环、Pre-commit 钩子与基准测试工程规范

Deep Agents Monorepo 开发实战:基于 uv 与 make 的编辑-测试-lint 循环、Pre-commit 钩子与基准测试工程规范

【免费下载链接】deepagentsThe batteries-included agent harness.项目地址: https://gitcode.com/GitHub_Trending/de/deepagents

本指南基于仓库 libs/DEVELOPMENT.md 展开,它既是 Deep Agents monorepo 所有贡献者与开发者的第一入口文档,也是理解libs/下多个独立版本包如何协同开发的路线图。读完你将掌握:用uv+make完成从环境准备、依赖安装到单测/集成测试/lint/类型检查的完整开发闭环,理解 pre-commit 钩子与分支命名校验的工作方式,并能按仓库规范写出符合 Google 风格 docstring、正确抑制 ruff 规则、通过 warnings-as-errors 测试门槛的代码。

这份文档解决什么问题

libs/DEVELOPMENT.md是 Deep Agents monorepo 的开发起点文档,面向两类读者:需要改动某个包的贡献者,以及想搞清楚"每个包如何独立测试、发布、做基准测试"的架构读者。它与 libs/ARCHITECTURE.md 分工明确:后者讲运行时代码如何组织(SDK 的三层结构、create_deep_agent()的组装与执行、中间件栈),前者讲开发时如何动手改代码、跑测试、过 CI 门槛。仓库根目录的 AGENTS.md 则把这份文档作为全局开发准则的权威引用来源,并在其中明确了"Warnings are errors"、per-file-ignores 使用策略、基准测试调用方式等细节的归属。

文档的核心立场可以概括为三句话:

  • 工具链只有两样:uv管解释器、虚拟环境与依赖;make管任务编排,每个包的Makefile是命令的唯一事实来源。
  • 你只在正在改的那个包里工作,不在根目录维护统一工程配置——monorepo 下没有根pyproject.toml
  • 本地能过的检查要尽量覆盖 CI 会跑的检查:format、lint、lockfile 新鲜度、Conventional Commit 消息、warnings-as-errors 测试。

前置条件:uv 与 make

文档明确要求两个工具,且态度很坚决:

  • uv:负责解释器、虚拟环境和依赖管理。不要使用pippoetrycondauv会自动按各包pyproject.tomlrequires-python拉取合适的 Python 解释器,因此"没有需要全局安装或固定的 Python 版本"。
  • make:任务运行器。每个包的Makefile是其命令的事实来源,进入任意包目录运行make help即可列出全部可用目标。

从源码看,仓库在libs/Makefile中确实按包映射了 Python 版本(libs/Makefile):

# Map package dirs to their required Python version # acp requires 3.14, everything else uses 3.12 python_version = $(if $(filter acp,$1),3.14,3.12)

也就是说仓库级命令会为libs/acp使用 Python 3.14,其余包统一使用 3.12。而 SDK 包本身的requires-python范围更宽:以 libs/deepagents/pyproject.toml 为例是>=3.11,<4.0。两条规则叠加即可理解"不固定全局 Python 版本、以包的声明为准"的含义。

仓库布局:libs/ 下的独立版本包

这是一个由独立版本管理的包组成的 monorepo,所有包都在libs/下:

libs/ ├── deepagents/ # Core SDK — create_deep_agent, middleware, backends ├── acp/ # Agent Client Protocol integration ├── evals/ # Evaluation suite and Harbor integration ├── code/ # Prebuilt coding agent for interactive and headless use ├── talon/ # Local runtime host for long-running agents └── partners/ # Provider/sandbox integrations ├── daytona/ ├── modal/ ├── vercel/ ├── runloop/ └── quickjs/

关键约定:

  • 每个包都有自己的pyproject.tomlMakefileREADME.md;仓库根目录没有pyproject.toml
  • 本地包依赖是**可编辑安装(editable)**的,因此改了一个包,依赖它的兄弟包在开发时立即可见新改动。
  • 包与包之间的横切约定(Conventional Commits、分支命名、测试要求、公共接口稳定性)统一收口在根目录 AGENTS.md,并在文档中按子系统给出了精确的"搜索路由"(例如 SDK 源码与测试在libs/deepagents/deepagentslibs/deepagents/tests),避免在 monorepo 里做宽泛搜索。

快速开始与 Setup

文档给出的标准初始化流程(在你要改的包内执行):

uv tool install pre-commit pre-commit install --install-hooks cd libs/deepagents uv sync --all-groups make test make lint

uv sync --all-groups会安装包本身加全部依赖组(test、lint 等)。文档强调uv自动创建并管理虚拟环境,不需要手动activate

monorepo 的四条铁律

  1. 显式安装依赖:始终用uv sync(按需加--group <name>--all-groups),绝不允许隐式安装。
  2. 不要在包目录之外创建虚拟环境。
  3. 不要在同一个会话里混用多个环境。
  4. 每个包在pyproject.toml里声明自己的 Python 支持范围,不固定全局 Python 版本,以包的requires-python为准。

作为补充,libs/code包还提供了一个一键引导目标make bootstrap(libs/code/Makefile),内部等价于"uv sync --group test+ 回到仓库根执行uvx pre-commit install --install-hooks",适合把整条开发链一次性配好。

常用命令速查表

在包目录(如libs/deepagents)内运行,核心 SDK 包(deepagentscode)的命令一致,其他包以make help输出为准:

命令作用
make help列出该包可用的全部目标
make test跑单元测试(断网;启用覆盖率的包会输出 coverage)
make test TEST_FILE=tests/unit_tests/test_foo.py只跑单个测试文件
make integration_test跑集成测试(允许联网)
make lintruff检查 +ty类型检查
make format自动格式化并应用安全的ruff修复
make type只跑ty类型检查器
make coverage跑该包显式定义的覆盖率目标,通常含 XML 输出

也可以绕过 make 直接运行单个测试:

uv run --group test pytest tests/unit_tests/test_specific.py

从 libs/deepagents/Makefile 可以看到这些目标的真实实现细节,值得展开几点:

  • make test实际执行的是uv run --group test pytest -n auto -vvv --disable-socket --allow-unix-socket $(TEST_FILE) --benchmark-disable $(COV_ARGS)-n auto来自 pytest-xdist 并行,--disable-socket --allow-unix-socket来自 pytest-socket,从机制上保证单测不能碰网络(只允许 Unix socket)。
  • TEST_FILE ?= tests/unit_tests/是默认值,integration_test通过前置变量赋值把TEST_FILE切到tests/integration_tests/,并加上--timeout 30防止联网测试挂死。
  • lint目标 =ruff check+ruff format --diff+make typetype目标跑ty check deepagentslibs/codelint还会额外校验命令目录(generate_commands_catalog.py --check)和工作目录约束(check_process_cwd.py)。

仓库级命令:从 libs/ 扇出

libs/目录下运行,会扇出到所有包:

命令作用
make lint逐个包执行 lint
make format逐个包执行格式化
make lock更新所有 lockfile(追加no-cache可绕过 uv 缓存)
make lock-check校验所有 lockfile 是否最新
make lock-bump DEP=<pkg>在所有 lockfile 中升级某个依赖

以 libs/Makefile 的实现为证,make lock会对所有发现到Makefile/pyproject.toml的包目录逐一执行uv lock --directory <pkg> --python <version>make lock-bump DEP=requests则对每个包执行uv lock -P 'requests'。这意味着"升级一个跨包依赖"在仓库里是一条命令的事,且始终带上与包对应的 Python 版本参数。

Docstrings:Google 风格 + Args 段

仓库要求每个公共函数都写 Google 风格 docstring,规则定义在根目录 AGENTS.md,libs/deepagents/pyproject.toml 中的[tool.ruff.lint.pydocstyle]配置convention = "google"从工具层面强制了这一约定。文档给出了标准模板:

def send_email(to: str, msg: str, *, priority: str = "normal") -> bool: """Send an email to a recipient with specified priority. Any additional context about the function can go here. Args: to: The email address of the recipient. msg: The message body to send. priority: Email priority level. Returns: `True` if email was sent successfully, `False` otherwise. Raises: InvalidEmailError: If the email address format is invalid. SMTPConnectionError: If unable to connect to email server. """

结合 AGENTS.md 的补充约定:类型写在签名里而非 docstring 里;不要重复默认值(除非后处理或条件行为会改变它);公共参数、返回值和异常要精炼描述,重点讲"为什么"而不是复述代码;函数尽量控制在 20 行以内。此外仓库强制ruff开启"ALL"全部规则(见 pyproject.toml),这意味着 pydocstyle 相关规则(D 系列)会在本地 lint 阶段直接拦截缺失或格式错误的 docstring。

抑制 ruff 规则的正确姿势

文档对这一主题的态度非常明确:per-file-ignores是对整个文件生效的"粗粒度开关",只应为覆盖某一整类文件的原则性策略保留;单条例外应该用行内# noqa精确到行、自文档化,并在注释里说明理由——如果理由说不出来,"那大概率是代码本身有问题"。

文档给出的正反示例(与 libs/deepagents/pyproject.toml 的真实配置相互印证):

# GOOD - categorical policy in pyproject.toml [tool.ruff.lint.per-file-ignores] "tests/**" = ["D1", "S101"] # BAD - single-line exception buried in pyproject.toml "deepagents_code/agent.py" = ["PLR2004"]
# GOOD - precise, self-documenting inline suppression timeout = 30 # noqa: PLR2004 # default HTTP timeout, not arbitrary

仓库实践中的两个典型类别策略:"tests/**"放宽注解、docstring、魔法值、安全断言类规则(D1S101PLR2004等,见 pyproject.toml);"scripts/**"允许独立脚本使用盲捕获与print。这与 AGENTS.md 的全局约定完全一致:不要把单条违规藏进文件级忽略里

Pre-commit 钩子与分支命名校验

仓库使用pre-commit统一管理格式化、lint、lockfile 校验与 Conventional Commit 消息校验。安装方式:

uv tool install pre-commit # or: pipx install pre-commit pre-commit install --install-hooks

从 .pre-commit-config.yaml 可以看到钩子的真实组成:

  • commit-msg 阶段conventional-pre-commit校验提交消息类型(feat/fix/docs/chore等 13 种,见 配置文件)。
  • pre-commit 阶段no-commit-to-branch禁止直接提交到maincheck-yamlcheck-tomlend-of-file-fixertrailing-whitespace等基础检查;以及一组language: system的本地钩子,按变更文件路径扇出到各包的make format lint(如deepagentsdeepagents-codeevalsacp,见 .pre-commit-config.yaml)。
  • lockfile 与版本一致性钩子lock-check(校验pyproject.toml/uv.lock是否同步)、extras-sync(校验 extras 与必需依赖一致)、version-equality(校验pyproject.toml_version.py版本一致)、branch-scopes-sync(校验分支规则在钩子、CI、pr_lint 三处一致,见 .pre-commit-config.yaml)。
  • pre-push 阶段branch-name钩子(.pre-commit-config.yaml),执行.githooks/pre-push

注意minimum_pre_commit_version: '3.2.0'(.pre-commit-config.yaml):3.2.0 是第一个接受 git-hook 命名阶段(pre-commit/pre-push/pre-merge-commit)的版本,更老的 pre-commit 会在 schema 校验阶段直接拒绝整个配置文件。

分支命名 pre-push 钩子细节

文档对分支命名校验的机制讲得很细,核心事实:

  • pre-push 阶段拒绝不符合<github-用户名>/<scope>/<短描述>约定的分支,例如mdrxy/cli/startup-cmd-flag
  • 它通过 pre-commit 运行,所以pre-commit install --install-hooks就会启用,不需要单独配置core.hooksPath(那会遮蔽其他已安装的钩子)。
  • 如果你在钩子加入之前就装过 pre-commit,必须重跑安装命令。pre-commit 在安装时按类型各写一个钩子文件,老 checkout 的.git/hooks/pre-push不存在,直到重装才会生效。
  • 钩子解析 GitHub 登录名的顺序是:git config github.usergh api useruser.email的本地部分。如果你的提交邮箱是users.noreply.github.comfirst.last@这类与登录名不匹配的地址,显式配置是最可靠的做法
git config github.user <your-github-login>
  • 永远放行的分支:受保护分支(mainmastervX.Y)、自动化分支(release-please--*dependabot/*copilot/*)和发布分支(alpha/*beta/*rc/*dev/*)。推这些分支时钩子根本不需要解析登录名。
  • 作为本地便利设施,可用git push --no-verifySKIP=branch-name git push跳过。
  • 两个盲区(经由 pre-commit 而非裸 git 钩子运行的固有后果):一次推送多个 ref 只校验其中一个;推送没有新提交的分支不触发任何钩子。.github/workflows/branch_name_check.yml以 PR 头分支上的非阻塞警告覆盖这两点,且 CI 故意不校验用户名段与 PR 作者是否一致——这一点上它比本地钩子更宽松。

测试规范

测试文件镜像源码布局:deepagents/middleware/foo.py的测试放在tests/unit_tests/middleware/test_foo.py(libs/deepagents/tests/unit_tests/middleware 目录真实存在,实测还覆盖了 backends、_api 等目录)。测试原则(见 AGENTS.md):优先测真实行为、尽量少用 mock;断网测试放tests/unit_tests/、联网测试放tests/integration_tests/;不写只是复述实现结构的"change-detector"测试;不手动加@pytest.mark.asyncio,因为各包都开了asyncio_mode = "auto"

警告即失败(Warnings fail the suite)

这是本仓库最值得注意的工程约束之一:每个包都把"error"放在 pytestfilterwarnings的第一位,任何仓库未显式接受的警告都会导致测试运行失败。规则出处是根目录 AGENTS.md,实现见 libs/deepagents/pyproject.toml:

[tool.pytest.ini_options] filterwarnings = [ "error", "ignore:Passing `model=None` to `create_deep_agent`:DeprecationWarning", "ignore:The feature `forked subagents` is in beta:langchain_core._api.LangChainBetaWarning", # ... ]

"error"之后是按条目评审过的白名单。一个游离警告会以什么方式暴露,取决于它何时被触发(文档原话):

  • 在测试内部触发:该测试失败。
  • 在模块导入时触发:该文件的收集(collection)失败。
  • 在 pytest 仍在配置阶段触发(通常来自插件):整个运行以INTERNALERROR中止——这是 CI 输出里最难读的一种。而且 pytest 加载插件期间、ini 过滤器生效之前发出的警告根本不会被捕获,因此"一次干净的运行"并不能证明某个依赖是无警告的。

应对策略:先修可处理的警告,把白名单条目当作最后手段。条目写法规则(来自 AGENTS.md):用@pytest.mark.filterwarnings把预期警告限定到单个测试;对PytestUnhandledThreadExceptionWarning之类倾向default::而非ignore::以保留可见性;ini 里 message 字段是未转义的正则,要转义字面元字符;过滤器可以按版本限定(如只在 Python 3.14 触发)。

bypass-warnings-check标签

维护者可以对 PR 打上bypass-warnings-check标签并重跑失败任务,从而把警告从"错误"降级。文档明确这是在时间压力下合入修复的逃生舱,不是永久修复:merge-queue 的运行会再次强制执行该策略,警告最终仍必须被处理或加入白名单。它的两个边界:

  • 只作用于走_test.yml的任务;ci.yml里的test-quickjs-sdk-smoke任务直接调用 pytest,没有绕过路径。
  • 发布运行(release.yml)始终强制执行,因此只对构建出的 wheel 出现的警告无法靠标签放行。

基准测试:bench 与 bench-memory

三个包承载基准测试:libs/deepagentslibs/codelibs/partners/quickjs。每个定义bench(墙钟时间)与bench-memory(堆内存)两个 Make 目标;其他包没有bench目标,所以make -C libs/evals bench会直接失败。

这些目标被视为基准测试调用的唯一事实来源:本地运行和可复用 CI 工作流(.github/workflows/_benchmark.yml)都调用它们。要改基准测试的跑法,改 Makefile 即可,CI 自动继承。

# 单包(与 CI 调用的目标一致): make -C libs/deepagents bench # deepagents 与 code 一次跑完(BENCH_PACKAGES 定义在 libs/Makefile; # 注意不含 quickjs): make -C libs bench-all # 不带 CodSpeed 插桩的纯 pytest-benchmark,更快,适合本地临时调优: make -C libs/deepagents benchmark

以上命令与仓库实现完全对应:BENCH_PACKAGES := deepagents code定义在 libs/Makefile,bench-all目标在 libs/Makefile 扇出到这两个包;libs/deepagents的 Makefile 中:

benchmark: ## Run benchmark tests uv run --group test pytest ./tests/benchmarks -m benchmark bench: ## Run benchmarks under CodSpeed instrumentation uv run --group test pytest ./tests/benchmarks -m benchmark --codspeed bench-memory: ## Run memory benchmarks under CodSpeed instrumentation uv run --group test pytest ./tests/benchmarks -m memory_benchmark --codspeed

配套事实:

  • bench-memory只跑memory_benchmark标记的子集;在 CI 中它由_benchmark.ymlhas-memory-benchmarks输入门控(默认false),目前没有调用方开启,所以内存基准实际上只在本地跑;如果要在 sweep 中加一个,就把这个 flag 接上。
  • 结果会上传到 CodSpeed 仪表盘,每个包一个独立视图(左上角选择器切换)。回归阈值在仪表盘上管理,不在仓库里,文档明确提醒"写在这里的数值会漂移"(写作时为全局 10%),并建议对噪声底远低于该阈值的基准收紧逐基准阈值,因为过宽的阈值会掩盖紧致代码里的真实回归。
  • .github/workflows/_benchmark_nightly.yml_benchmark.yml的唯一调用方,没有 per-PR 基准任务。它按每日 cron 跑清单里的每个包,保证未改动包的基线不漂移;覆盖范围只有libs/deepagentslibs/code——libs/partners/quickjs虽然定义了基准目标但不在 sweep 里。在升级pytest-codspeedCodSpeedHQ/action的 SHA 之前,可用workflow_dispatch对该工作流做一次临时运行。

贡献约定:Conventional Commits 与 CI 门槛

约定收口在根目录 AGENTS.md,核心包括:Conventional Commits 且必须带 scope、分支命名、测试要求与公共接口稳定性。规范的标题示例:

feat(sdk): add new chat completion feature fix(sdk): resolve type hinting issue chore(evals): update infrastructure dependencies test(code): missing unit tests for `_git` feat(code): `--startup-cmd` flag style(code): strip trailing annotations from `ask_user` questions

补充约定(来自 AGENTS.md):type(scope):后以小写字母开头(专有名词或命名代码实体除外);类/函数/参数名用反引号包裹;标题里不放 issue 关闭标记(放 PR 正文);版本分支同步用chore(repo): sync main into vX.Yrelease是类型不是 scope);每个值得 bump 的 PR 只包含一个可发布组件,跨包依赖或 lockfile 变动单独开chore(deps):PR。

外部 PR 必须关联维护者已批准的 issue 或 discussion,且贡献者需先被指派才能开 PR。CI 在测试之外还跑多项门槛:Conventional Commit lint、lockfile 新鲜度、版本/extras 一致性、SDK-pin 检查等。在改动的包内跑make format lint、从libs/make lock-check,即可清掉最常见的几项。

与架构文档的衔接

如果你要改的不是某个命令的配置,而是 SDK 的运行机制,文档建议先读 libs/ARCHITECTURE.md。它把系统切成三层来理解(libs/ARCHITECTURE.md):LangGraph 是运行时(state、checkpoint、streaming、interrupt);LangChain 的create_agent()是模型 + 工具 + 中间件组成 agent 循环的抽象;Deep Agents 则是叠加其上的opinionated harness——通过create_deep_agent()组装默认中间件栈,并配置 backends、subagents、skills、memory 与 profiles。开发流程上,构造(construction,组装图)与执行(execution,LangGraph 驱动循环)是两个阶段,而 harness 行为主要通过中间件注入。

小结

libs/DEVELOPMENT.md是进入 Deep Agents monorepo 的工程总纲,通篇贯彻三条主线:工具收敛uv+make,拒绝 pip/poetry/conda 与根级工程配置)、质量门槛前置(warnings-as-errors、分支命名 pre-push 钩子、Conventional Commits、per-file-ignores 最小化)、单一事实来源(每个包的 Makefile 同时服务本地开发与 CI/基准工作流)。按文档的顺序走一遍uv sync --all-groupsmake testmake lintpre-commit install --install-hooks,你就能在一个可预测、可复现、与 CI 对齐的本地环境里完成对任意包的改动。

进一步阅读:运行时结构与 SDK 起点见 libs/ARCHITECTURE.md;全局开发准则、测试要求与公共接口稳定性见 AGENTS.md;仓库级扇出命令的实现见 libs/Makefile;SDK 包内 lint/测试/基准的精确实现见 libs/deepagents/Makefile 与 libs/deepagents/pyproject.toml。

【免费下载链接】deepagentsThe batteries-included agent harness.项目地址: https://gitcode.com/GitHub_Trending/de/deepagents

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 23:36:10

多智能体强化学习环境仓库解析:从接口设计到训练接入

简介&#xff1a;一份专为多智能体强化学习&#xff08;MARL&#xff09;设计的环境工具包&#xff0c;面向强化学习研究者、算法工程师与学生&#xff0c;用于在统一平台中开发、训练和对比多智能体协作与竞争策略。环境覆盖灭火、找宝藏、抓猪、足球、移动箱子、无人机、清洁…

作者头像 李华
网站建设 2026/9/11 23:33:51

Android内存泄漏:Handler与Context的static陷阱解析

1. Android内存泄漏的双子星&#xff1a;Handler与Context的static陷阱在Android开发中&#xff0c;内存泄漏就像房间里悄悄堆积的灰尘&#xff0c;看似无害却会逐渐拖慢系统运行。而Handler和Context的static使用问题&#xff0c;堪称Android内存泄漏的"双子星"——…

作者头像 李华
网站建设 2026/9/11 23:32:02

ComfyUI中Supir语义超分节点实战指南

简介&#xff1a;本资源是一份面向ComfyUI图像处理初学者与AIGC开发者的轻量级Supir图像缩放工作流配置文件&#xff0c;聚焦于高质量图像放大与细节增强场景&#xff0c;适用于需快速集成Supir节点的本地化AI绘图工作流搭建。压缩包仅含1个核心JSON文件&#xff08;4KB&#x…

作者头像 李华
网站建设 2026/9/11 23:28:29

OpenCV 3.1轻量级多目标跟踪实战:MOG2+KCF架构

简介&#xff1a;本资源是一套基于OpenCV 3.1实现视频多目标检测与跟踪的完整C工程实践项目&#xff0c;面向计算机视觉初学者及图像处理进阶开发者&#xff0c;解决动态场景下多个运动目标的实时定位、初始化与持续追踪问题&#xff0c;适用于智能监控、行为分析等实际应用。压…

作者头像 李华