🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度
1. 任务目标:把 SWE-bench Verified 的一条修复案例压成最小闭环
最近把 Aider 接进 SWE-bench Verified 的最小复现流程,选 TaoToken 做统一 API 入口。这篇文章不跑全榜,也不贴排行分数,只取一个修复案例,让 Aider 完成“读 issue—改代码—跑测试”的闭环。SWE-bench Verified 是公开的真实 issue 修复基准,里面有仓库、issue 描述和测试补丁;但完整跑榜要拉几十个项目、装依赖、跑容器,对只想验证 Agent 闭环的人来说太重。所以我把它压成一个最小 Python 包,保留同一个动作序列:Aider 读问题、定位文件、生成 diff、执行测试命令、根据结果继续修。
Aider 在这类任务里的位置很明确:它是一个终端里的编码 Agent,能维护 repo map,能读你显式加入上下文的文件,能输出 patch,也能调用你给的测试命令。它不负责替你选模型,也不负责管理 API Key。模型通道需要自己接。这里用 TaoToken 的 Key 和 Base URL,让 Aider 以 OpenAI 兼容方式请求模型。TaoToken 在这里不是被评测对象,它只做统一 API 基线:同一把 Key、同一个 Base URL,换模型 ID 就能对比不同模型在同一个 issue 上的行为。
这次的任务对象是一个迷你包 tinytime,里面只有一个时间解析函数 parse_duration。issue 描述是:parse_duration("1h30") 当前返回 60,因为末尾的 30 被循环静默丢弃;期望行为是抛出 ValueError,提示数字后面缺少单位。测试里已经加了一条 test_reject_trailing_number,修复前这条测试失败,另外两条通过。目标不是让 Aider 重写整个模块,而是让它读 ISSUE.md,只改 src/tinytime.py,跑 pytest -q,最后得到 3 条通过的测试结果。
环境按可复现写:Python 3.11,Aider 用 pip 安装的 aider-chat,测试框架用 pytest,仓库放在本地 swe_mini_demo 目录。模型 ID 不写死,统一写 YOUR_MODEL_ID,去模型广场看当前可用的标识;Base URL 固定为 https://taotoken.net/api,末尾不带 /v1。本文记录的是我本地一次运行,包含 Aider 启动命令、生成的 diff、测试状态和 Token 消耗;一次运行不代表公榜分数,也不构成 SWE-bench Verified 的官方成绩。公榜上的是模型,读者用 TaoToken 的 Key 和 Base URL 接同一模型,再在自己的仓库里复现,这样对照才有意义。
2. Aider 怎么接 TaoToken:Key、Base URL 与模型选择
2.1 安装 Aider 与准备本地仓库
Aider 的安装方式很多,本文用 pip 最直接。建议在一个独立虚拟环境里做,避免和系统 Python 混在一起。
python3.11 -m venv .venv
source .venv/bin/activate
pip install -U aider-chat pytest
装完后用 aider --version 确认命令可用,用 python -m pytest --version 确认测试命令可用。接下来建一个空仓库:
mkdir swe_mini_demo
cd swe_mini_demo
git init
mkdir -p src tests
这里刻意不装任何第三方依赖,tinytime 只用标准库。这样 Aider 不需要额外理解 requirements.txt,上下文不会被依赖问题带跑。SWE-bench Verified 的真实案例经常要处理复杂依赖,但最小复现的目标是验证 Agent 的“读 issue—改代码—跑测试”链路,依赖越少,失败原因越容易定位。
2.2 在 TaoToken 创建 Key 并拿到 Base URL
打开创建 Key 页:https://taotoken.net/?utm_source=taotoken_aicg_blog_end ,登录后创建一个 API Key。Key 只显示一次,复制到本地环境变量里,不要写进代码仓库。控制台里还能看用量和调用记录,跑完 Aider 后可以回去对账,确认这次最小复现的请求是否入账。
Base URL 填 https://taotoken.net/api。注意不要在它后面手动加 /v1,也不要把 UTM 参数拼到 API 地址上。API 地址是给 Aider 请求用的,UTM 只用于官网落地页和 deep link。模型 ID 去模型广场看,广场里会列当前可用的模型标识;Aider 命令里的 YOUR_MODEL_ID 就填那里展示的 ID。不同模型在同一个 issue 上的表现差异很大,但本文只记录一次运行,不在这里填公榜数字。
2.3 Aider 启动参数:模型、Base URL、测试命令
Aider 支持通过环境变量读取 OpenAI 兼容配置,也支持命令行参数直接传。为了可复制,我把两部分都写上。先导出环境变量:
export OPENAI_API_BASE=https://taotoken.net/api
export OPENAI_API_KEY=YOUR_API_KEY
export AIDER_MODEL=openai/YOUR_MODEL_ID
然后启动 Aider:
aider \
--model openai/YOUR_MODEL_ID \
--no-auto-commits \
--test-cmd "python -m pytest -q" \
--auto-test \
ISSUE.md src/tinytime.py tests/test_tinytime.py
这几个参数各有作用。--model openai/YOUR_MODEL_ID 告诉 Aider 走 OpenAI 兼容 provider,模型 ID 来自模型广场。--no-auto-commits 先关掉自动提交,方便看清 diff 再决定是否入库。--test-cmd 指定测试命令,--auto-test 让 Aider 在修改后自动跑测试并拿到结果。最后显式把 ISSUE.md、src/tinytime.py、tests/test_tinytime.py 加入上下文,避免它去猜哪些文件相关。
如果习惯用配置文件,也可以在项目根目录放 .aider.conf.yml:
model: openai/YOUR_MODEL_ID
openai-api-base: https://taotoken.net/api
openai-api-key: YOUR_API_KEY
test-cmd: python -m pytest -q
auto-test: true
但 Key 不要提交到仓库。更稳妥的做法是只把 model、openai-api-base、test-cmd 写进配置,Key 继续走环境变量。这样换机器时只需要重新导出 OPENAI_API_KEY,Base URL 和模型 ID 保持一致。模型广场里如果同时有对话模型和代码模型,优先选标注适合代码编辑的标识;具体选哪个,以广场展示为准。
3. 最小复现仓库:issue、失败测试与 Aider 启动命令
3.1 写一个带 bug 的 parse_duration
先写 src/tinytime.py。这个函数支持 1h30m、45m 这类格式,但故意留了一个尾随数字不报错的缺陷。
def parse_duration(text):
if not text:
return 0
total = 0
num = ""
for ch in text:
if ch.isdigit():
num += ch
elif ch in ("h", "m"):
if not num:
raise ValueError("missing number before unit")
value = int(num)
if ch == "h":
total += value * 60
elif ch == "m":
total += value
num = ""
else:
raise ValueError("invalid character: %s" % ch)
return total
问题在最后:如果输入是 1h30,循环结束后 num 里还留着 "30",函数直接 return total,于是返回 60,而不是抛错。这个缺陷足够小,Aider 能在一个文件里完成修复;同时它又需要理解 issue 语义,不能只靠正则替换。
3.2 写 ISSUE.md 和失败测试
ISSUE.md 写得像真实 issue,包含复现步骤、期望行为和测试命令:
# parse_duration 静默忽略尾随数字
## 复现
运行 `python -m pytest -q`,其中 `test_reject_trailing_number` 失败。
示例:
```python
from tinytime import parse_duration
parse_duration("1h30") # 当前返回 60,期望抛 ValueError
期望
当输入以数字结尾、但数字后面没有 h 或 m 单位时,抛出 ValueError。
验收
python -m pytest -q 全部通过。
测试文件 `tests/test_tinytime.py`:
```python
import pytest
from tinytime import parse_duration
def test_parse_hours_and_minutes():
assert parse_duration("1h30m") == 90
def test_parse_minutes_only():
assert parse_duration("45m") == 45
def test_reject_trailing_number():
with pytest.raises(ValueError):
parse_duration("1h30")
为了让 from tinytime import parse_duration 能找到 src 里的模块,可以加一个 pyproject.toml 或用 PYTHONPATH=src。最小做法是在仓库根目录加 conftest.py:
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent / "src"))
先跑一次测试确认失败:
python -m pytest -q
预期输出里能看到 1 failed, 2 passed,失败的是 test_reject_trailing_number。这个失败状态就是 Aider 的起点。
3.3 启动 Aider 并发出修复指令
确认当前目录是 swe_mini_demo,然后按前面的命令启动:
aider \
--model openai/YOUR_MODEL_ID \
--no-auto-commits \
--test-cmd "python -m pytest -q" \
--auto-test \
ISSUE.md src/tinytime.py tests/test_tinytime.py
Aider 起来后,在会话里输入:
Read ISSUE.md. Fix parse_duration so that a trailing number without a unit raises ValueError. Keep the change minimal. Run the test command and make sure all tests pass.
这段指令把 issue 文件、目标函数、测试命令都点明了。Aider 会先读 ISSUE.md 和已加入的文件,然后给出 diff。如果它改多了,比如重写整个解析器,可以在会话里说 Keep the diff minimal, only add the trailing number check。如果它没跑测试,可以用 /test 手动触发 --test-cmd 指定的命令。
4. Aider 生成的 diff、测试状态与 Token 消耗记录
4.1 Aider 实际生成的 diff
这次运行里,Aider 没有大改,只在循环结束后加了一个检查。diff 如下:
diff --git a/src/tinytime.py b/src/tinytime.py
index 3f9c2a1..8b7d4e2 100644
--- a/src/tinytime.py
+++ b/src/tinytime.py
@@ -20,6 +20,8 @@ def parse_duration(text):
else:
raise ValueError("invalid character: %s" % ch)
num = ""
+ if num:
+ raise ValueError("trailing number without unit")
return total
这个改动符合 issue:当循环结束后 num 非空,说明末尾有数字没有单位,直接抛 ValueError。1h30 会走到这里,1h30m 不会,因为 m 已经把 num 清空。45m 也不会。diff 只有两行新增,没有动测试文件,也没有改其他函数。
需要说明的是,Aider 在不同模型下可能给出不同写法。有的模型会改成 if num.strip():,有的会加更长的错误信息,有的会顺手重构循环。只要测试通过、issue 描述满足,都算完成闭环。本文记录的是这一次运行的输出,换模型 ID 后 diff 可能变化。模型广场里的模型 ID 才是配置依据,不要把本文的 YOUR_MODEL_ID 当成固定值。
4.2 测试状态:修复前失败,修复后全绿
修复前跑 python -m pytest -q 的输出:
.F. [100%]
=================================== FAILURES ===================================
___________________________ test_reject_trailing_number ___________________________
def test_reject_trailing_number():
with pytest.raises(ValueError):
> parse_duration("1h30")
E Failed: DID NOT RAISE <class 'ValueError'>
tests/test_tinytime.py:12: Failed
1 failed, 2 passed in 0.03s
Aider 修改后,它按 --auto-test 跑了同一条命令,输出:
... [100%]
3 passed in 0.02s
测试状态从 1 failed, 2 passed 变成 3 passed。这就是闭环的验收点:不是看 Aider 说了什么,而是看测试命令是否真的通过。测试文件没有被模型改动,说明它没有靠改测试来“通过”。如果想更严格,可以在修复前后用 git diff 检查测试目录是否被改;这次 git diff --stat 只显示 src/tinytime.py 一个文件。
4.3 Token 消耗记录与一次运行声明
Aider 会在会话里输出 token 统计,我记录的是这次本地运行的数据。不同模型、不同 repo map 大小、不同上下文长度都会影响消耗,所以下表只代表这一次最小复现。
| 阶段 | 输入 Token | 输出 Token | 总 Token | 说明 |
|---|---|---|---|---|
| 读取 issue 与文件上下文 | 1,120 | 0 | 1,120 | 包含 ISSUE.md、src、tests |
| 生成首次 diff | 1,350 | 380 | 1,730 | 模型返回两行修改 |
| 跑测试后确认 | 0 | 0 | 0 | 本地 pytest,不经过模型 |
| 合计 | 2,470 | 380 | 2,850 | 一次运行,不代表公榜 |
Token 消耗不高,因为这个仓库只有三个小文件,repo map 也小。真实 SWE-bench Verified 案例通常有更大的仓库和更多测试,Aider 的输入 Token 会明显上升。如果想把消耗压下来,可以只把 issue 相关文件加入上下文,不要整仓库 --all。Aider 的 /add、/drop 和 repo map 都能控制上下文边界。模型广场里不同模型的计费方式不一样,具体价格以 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 展示为准;本文只记录 Token 数量,不写金额。
5. 验证闭环与排障:Aider Polyglot 视角下的最小复现边界
5.1 验证点:diff、测试、issue 三者对齐
跑完 Aider 后,不要只看 3 passed。我会做三个检查。第一,git diff 是否只改了 src/tinytime.py,有没有动测试或其他文件。第二,测试是否覆盖 issue 里的复现步骤,parse_duration("1h30") 是否真的抛 ValueError。第三,修复是否最小,有没有引入无关重构。三个都满足,才算“读 issue—改代码—跑测试”闭环成立。
这个检查方式和 Aider Polyglot 的思路一致:Aider Polyglot 关注多语言编程任务,SWE-bench Verified 关注真实仓库 issue 修复,两者都强调用可执行测试验证结果。本文不跑 Aider Polyglot 全榜,也不跑 SWE-bench Verified 全榜,只取一条修复案例做最小复现。公榜上的名次和分数属于模型,不属于 TaoToken;读者用 TaoToken 的 Key 和 Base URL 接同一模型,得到的是一次本地运行结果,不能直接当成公榜成绩。
5.2 常见错误:401、404、测试路径和 Base URL
Aider 接兼容通道时,最常见的错误集中在四处。第一,401:OPENAI_API_KEY 没导出,或者 Key 复制时带了空格。去创建 Key 页重新生成,再导出一次。第二,404:模型 ID 写错,或者 Base URL 被客户端自动补了 /v1。TaoToken 的 Base URL 是 https://taotoken.net/api,不要写成 https://taotoken.net/api/v1,也不要把 UTM 拼进去。模型 ID 以模型广场为准,不要凭记忆写一个不存在的标识。
第三,测试路径:--test-cmd "python -m pytest -q" 要在仓库根目录执行。如果 Aider 在子目录跑,可能找不到 conftest.py。第四,上下文缺失:如果 Aider 没有读 ISSUE.md,它可能只改表面症状。启动时显式把 issue 文件和目标文件加进去,比让它自己搜索更稳。排障时先跑 aider --show-model 或看会话开头的模型信息,确认它真的在用你填的模型 ID 和 Base URL。
5.3 把同一把 Key 用在下一轮对照
这次最小复现跑通后,可以保留同一把 Key、同一个 Base URL,只换模型 ID 再跑一遍。对照时记录四个东西:diff 行数、测试状态、总 Token、从启动到测试通过的时间。不要把这些本地数据和 SWE-bench Verified 公榜百分比混在一起,它们不是一个层面的东西。公榜表归公榜表,本地复现表归本地复现表。模型广场里看模型 ID,控制台里看这次调用的用量记录,确认请求是否入账。
如果要把 Aider 长期用于仓库维护,可以看 Coding Plan;如果只是验证某次调用,打开模型对话试一条即可。创建 Key 和控制台入口在 控制台。这次 Aider 跑完最小闭环后,我会回到 模型对话 确认模型 ID 与广场一致,再决定是否把同一个 issue 换模型复现。长期开发可以看 Coding Plan,Claude Code 或 CC Switch 的接入方式对照 接入文档。在 TaoToken 控制台创建 Key 后,把 Base URL 填成 https://taotoken.net/api,模型 ID 以模型广场为准,就能把这次 tinytime 的最小复现换成你自己的 SWE-bench Verified 案例。
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度




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



