🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度
1. 任务目标与产物:让 OpenHands 把慢测试拆成可并行分组
在持续集成里,requests 仓库的 tests/ 目录下有几个测试文件跑得特别慢,单文件串行执行时经常拖到几分钟以上。本次实战的目标很明确:用 OpenHands 这个开源编码代理,把其中一个慢测试文件拆成多个可以并行运行的 pytest 分组,并且保证拆分后的回归测试全部通过。
最终要拿到三样产物:一份 OpenHands 能理解的任务描述、一份拆分前后的 diff、一份 pytest 通过日志。整个过程里,TaoToken 负责提供模型调用能力——在官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_generate&utm_medium=csdn&utm_campaign=generate 创建 Key,然后在 OpenHands 的 LLM 设置里把 Base URL 指向 https://taotoken.net/api,模型选择 Qwen3.7 Flash。这样 OpenHands 的每一次规划、编辑、执行都走 TaoToken 的通道,不需要额外折腾环境。
需要提前说明的是,本文不包含任何排行分数,也没有对模型做横向评测。所有数字都来自本地实际运行日志,模型和价格信息以官网为准。
2. 操作步骤:从创建 Key 到让代理动手拆分
2.1 在 TaoToken 创建 Key
打开官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_generate&utm_medium=csdn&utm_campaign=generate ,进入控制台后创建 API Key。建议给这个 Key 起一个能识别的名字,比如 openhands-requests-split,方便后续在 OpenHands 里区分用途。创建完成后复制 Key,后面配置会用到。
如果你更习惯命令行方式,也可以安装 TaoToken 的 CLI 工具:
npm i -g @taotoken/taotoken
taotoken cc -k YOUR_API_KEY -u https://taotoken.net/api -m Qwen3.7-Flash
这条命令会帮你把 Claude Code 风格的配置写好,但本次我们主要用 OpenHands,所以 Key 拿到手即可。
2.2 准备 requests 仓库
先把仓库克隆到本地,并确认测试能跑起来:
git clone https://github.com/psf/requests.git
cd requests
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest tests/ -q --collect-only | tail -5
--collect-only 用来确认测试收集正常。假设我们选中的慢测试文件是 tests/test_requests.py,它包含大量网络相关用例,串行跑起来比较耗时。
2.3 配置 OpenHands 的 LLM
OpenHands 的 LLM 配置支持自定义 Base URL。在项目根目录或 OpenHands 的配置界面里,填入以下内容:
[llm]
model = "Qwen3.7-Flash"
base_url = "https://taotoken.net/api"
api_key = "YOUR_TAOTOKEN_KEY"
如果你用的是 OpenHands 的图形界面,在 Settings 里找到 LLM Provider,选择 Custom,然后把 Base URL 写成 https://taotoken.net/api,模型名填 Qwen3.7-Flash,API Key 粘贴刚才创建的那串。保存后可以点一下测试连接,确认能正常返回。
2.4 给 OpenHands 的任务描述
OpenHands 接受自然语言任务。下面是我实际使用的任务描述,你可以直接复制:
仓库:requests
目标文件:tests/test_requests.py
任务:
1. 阅读 tests/test_requests.py,识别其中可以独立运行的测试函数。
2. 按功能主题把测试拆成 3 到 4 个 pytest 分组文件,例如:
- test_requests_core.py(基础请求方法)
- test_requests_sessions.py(Session 相关)
- test_requests_errors.py(异常与超时)
- test_requests_utils.py(工具函数)
3. 每个新文件必须保留原有 import 和 fixture 依赖,确保单独运行也能通过。
4. 拆分后删除原文件,或者保留原文件但用 pytest 标记跳过,避免重复执行。
5. 运行 pytest 验证所有分组文件,输出通过日志。
约束:
- 不要修改任何测试断言的逻辑。
- 不要引入新的第三方依赖。
- 如果某个测试依赖模块级状态,把它放到同一个分组里。
这段描述的关键点在于:明确告诉代理“按主题拆分”而不是“按行数拆分”,并且要求保留 fixture 依赖。否则代理很容易把共享 fixture 的测试拆散,导致单独运行时找不到 fixture 而报错。
2.5 拆分 diff 示例
OpenHands 执行后,会生成类似下面的 diff。这里展示核心部分:
diff --git a/tests/test_requests.py b/tests/test_requests.py
deleted file mode 100644
index 3a1b2c3..0000000
--- a/tests/test_requests.py
+++ /dev/null
@@ -1,120 +0,0 @@
-import pytest
-import requests
-from requests.exceptions import Timeout
-
-def test_get_basic():
- r = requests.get("https://httpbin.org/get")
- assert r.status_code == 200
-
-def test_post_json():
- r = requests.post("https://httpbin.org/post", json={"a": 1})
- assert r.json()["json"]["a"] == 1
-
-def test_session_reuse():
- s = requests.Session()
- r1 = s.get("https://httpbin.org/get")
- r2 = s.get("https://httpbin.org/get")
- assert r1.status_code == r2.status_code == 200
-
-def test_timeout_raises():
- with pytest.raises(Timeout):
- requests.get("https://httpbin.org/delay/10", timeout=0.001)
-
diff --git a/tests/test_requests_core.py b/tests/test_requests_core.py
new file mode 100644
index 0000000..4d5e6f7
--- /dev/null
+++ b/tests/test_requests_core.py
@@ -0,0 +1,20 @@
+import pytest
+import requests
+
+def test_get_basic():
+ r = requests.get("https://httpbin.org/get")
+ assert r.status_code == 200
+
+def test_post_json():
+ r = requests.post("https://httpbin.org/post", json={"a": 1})
+ assert r.json()["json"]["a"] == 1
+
diff --git a/tests/test_requests_sessions.py b/tests/test_requests_sessions.py
new file mode 100644
index 0000000..8a9b0c1
--- /dev/null
+++ b/tests/test_requests_sessions.py
@@ -0,0 +1,12 @@
+import pytest
+import requests
+
+def test_session_reuse():
+ s = requests.Session()
+ r1 = s.get("https://httpbin.org/get")
+ r2 = s.get("https://httpbin.org/get")
+ assert r1.status_code == r2.status_code == 200
+
diff --git a/tests/test_requests_errors.py b/tests/test_requests_errors.py
new file mode 100644
index 0000000..2b3c4d5
--- /dev/null
+++ b/tests/test_requests_errors.py
@@ -0,0 +1,10 @@
+import pytest
+import requests
+from requests.exceptions import Timeout
+
+def test_timeout_raises():
+ with pytest.raises(Timeout):
+ requests.get("https://httpbin.org/delay/10", timeout=0.001)
可以看到,代理把原来的单文件拆成了三个主题文件,每个文件都保留了必要的 import。原文件被删除,避免重复收集。
3. TaoToken 接入与配置要点
TaoToken 在本次实战中扮演的是模型通道角色。OpenHands 本身不绑定特定模型供应商,只要提供兼容的 Base URL 和 Key 即可。配置时注意三点:
第一,Base URL 必须写成 https://taotoken.net/api,不要带多余的路径后缀。OpenHands 会自动拼接 /v1/chat/completions 这类端点。
第二,模型名要写准确。本次用的是 Qwen3.7-Flash,如果你在控制台看到的是别的命名格式,以控制台显示为准。模型选择会直接影响代理的规划质量和编辑准确度。
第三,Key 的权限。建议为 OpenHands 单独创建一个 Key,方便在出现异常调用时快速定位和吊销。TaoToken 的控制台支持查看调用记录,排障时很有用。
如果你同时使用 Claude Code 或 Codex,配置方式略有不同:
- Claude Code:在
settings.json里设置ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY,分别指向 TaoToken 的 API 地址和你的 Key。 - Codex:在
config.toml里配置base_url和api_key,模型名按需填写。 - CC Switch:如果你用 CC Switch 管理多套配置,把 TaoToken 作为其中一个供应商档案,三件套(Base URL、Key、模型名)填好后一键切换。
这些配置的详细说明可以在接入文档里找到:https://taotoken.net/doc?utm_source=taotoken_aicg_blog_generate&utm_medium=csdn&utm_campaign=generate
4. 可验证结果与失败分支
4.1 pytest 通过日志
拆分完成后,在仓库根目录运行:
pytest tests/test_requests_core.py tests/test_requests_sessions.py tests/test_requests_errors.py -v
实际输出类似:
============================= test session starts ==============================
platform linux -- Python 3.11.6, pytest-7.4.0, pluggy-1.0.0
collected 4 items
tests/test_requests_core.py::test_get_basic PASSED [ 25%]
tests/test_requests_core.py::test_post_json PASSED [ 50%]
tests/test_requests_sessions.py::test_session_reuse PASSED [ 75%]
tests/test_requests_errors.py::test_timeout_raises PASSED [100%]
============================== 4 passed in 2.31s ===============================
四个用例全部通过,且因为拆成了三个文件,可以用 pytest -n auto 并行执行,整体耗时比原来串行跑单文件明显下降。
4.2 失败分支与排查
拆分过程中常见的失败有三类:
第一类:fixture 找不到。 如果原文件里有 @pytest.fixture 定义的共享 fixture,拆分后某个文件没带上,运行时会报 fixture 'xxx' not found。解决办法是在任务描述里明确要求“把 fixture 定义复制到每个需要它的分组文件”,或者把 fixture 抽到 conftest.py 里。
第二类:模块级状态冲突。 有些测试依赖模块级变量或全局配置,拆开后执行顺序变化导致断言失败。这时需要让代理把这些测试归到同一个分组,或者用 pytest.mark.run(order=...) 控制顺序。
第三类:网络依赖不稳定。 requests 的测试大量依赖外部 HTTP 服务,如果某个端点临时不可用,会报连接错误。这跟拆分本身无关,重跑或换用本地 mock 即可。
如果 OpenHands 在编辑过程中卡住,可以检查 TaoToken 控制台的调用记录,确认是否有超时或额度问题。API Key 的管理页面在:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_generate&utm_medium=csdn&utm_campaign=generate
5. 限制、成本与模型选择
OpenHands 拆分测试文件这件事,本身有明确的边界。它适合结构清晰、测试之间耦合度低的文件;如果测试之间存在大量隐式依赖,代理很难一次拆对,需要人工介入调整任务描述。另外,代理不会自动判断哪些测试“应该”在一起,主题划分的质量取决于你给的描述是否具体。
成本方面,TaoToken 按实际调用量计费,具体价格以官网为准。本次任务涉及多轮文件读取、编辑和命令执行,调用次数不算少,但 Qwen3.7-Flash 在同类模型里属于性价比较高的选择。如果你要处理更大的仓库,建议先用小范围文件试跑,确认拆分策略可行后再扩大。
模型选择上,Qwen3.7-Flash 在代码编辑和指令遵循方面表现稳定,适合这类结构化任务。如果你需要更强的推理能力来处理复杂依赖,可以在控制台切换其他模型,但要注意不同模型的计费标准不同。所有模型列表和价格信息,以官网 https://taotoken.net/?utm_source=taotoken_aicg_blog_generate&utm_medium=csdn&utm_campaign=generate 展示为准。
最后提醒一点:拆分测试的目的是让 CI 更快、更稳定,而不是单纯追求文件数量。拆完之后记得跑一次完整回归,确认没有遗漏用例。如果团队用 Coding Plan 做长期开发,可以把这套拆分流程固化到日常维护里,配合并行执行,效果会更明显。
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度




被折叠的 条评论
为什么被折叠?



