1. 登录功能被 AI 写成 300 行,问题出在哪
你让 AI 实现一个用户登录功能,需求一句话:输入用户名密码,验证通过,返回 token。结果它给你端出来一套认证抽象层——AuthStrategy接口、OAuth2Strategy、JWTStrategy、SessionStrategy三个实现类、一个StrategyFactory工厂、再加一个AuthPluginManager插件管理器。三百行代码,结构图能画满一屏,看起来相当专业。
但你把调用链捋一遍会发现,真正跑通的路径只有一条:login(username, password)查库比对,签发 token。剩下三分之二的代码,是为「以后可能要加 OAuth2」「以后可能要支持 Session」准备的。问题是,这些「以后」在你的项目里大概率不会来。
这不是 AI 写错了,而是它在按「最佳实践」的默认模板输出。策略模式、工厂模式、插件化,单拎出来都是好设计,但好设计的前提是你真的需要那个扩展点。AI 不知道你的项目要不要 OAuth2,它只知道「可扩展是好代码」,于是全给你做上。这就是典型的过度设计陷阱:为不存在的未来需求买单。
这篇就围绕这个场景,讲清楚三件事:怎么用 TDD 把 300 行砍回 30 行、怎么用 TaoToken 统一管理 AI 编码时的 Key 配置、以及怎么在 settings.json / config.toml 里把模型接入固定下来,让 AI 后续生成代码时不再默认堆架构。适合正在用 AI 写业务代码、被生成结果复杂度困扰的开发者。
2. 先解决 Key 管理,再谈代码纠偏
在动手砍代码之前,有个前置问题得先处理:你用什么模型来帮你做这次重构。如果每次让 AI 改代码都要重新配一遍 Key、换一个供应商、改一次 base_url,那纠偏过程本身就会变成新的混乱源。
TaoToken 在这里的角色是统一入口。它把模型调用收敛到一个 API 地址和一把 Key 上,你切换模型、切换编码场景时,改的是配置而不是散落在各处的环境变量。官网地址是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api ,注意 API 地址不带 UTM 参数,配置时直接用这个。
对登录功能重构这个场景来说,你需要的是一个稳定的模型对话能力:把 300 行代码贴进去,让它逐段说明哪些是当前需求必需的、哪些是预判未来的。这个动作适合走模型对话入口,地址是 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite 。如果你是要长期做编码和 Agent 类任务,比如让 AI 持续参与重构、跑测试、改配置,那更适合用 Coding Plan,地址是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。
Key 的创建在控制台的 API Keys 页面:https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 。生成后先复制保存,后面配置里要用。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,遇到参数不确定时对照着看。
提示:Key 只显示一次,生成后立刻存到本地密钥管理里,不要直接写进会提交到仓库的配置文件。
3. 可复制的配置骨架:settings.json 与 config.toml
配置这件事,我建议分两层:一层是编辑器/客户端的 settings.json,管的是「AI 助手怎么连模型」;一层是项目里的 config.toml,管的是「这个项目的编码规范约束」。两层配合,才能让 AI 后续生成代码时不再默认堆抽象。
3.1 settings.json 骨架
以常见的编辑器 AI 插件配置为例,核心是把 base_url 和 api_key 指向 TaoToken:
{ "ai.provider": "openai-compatible", "ai.baseUrl": "https://taotoken.net/api", "ai.apiKey": "${env:TAOTOKEN_API_KEY}", "ai.model": "claude-sonnet-4-20250514", "ai.temperature": 0.2, "ai.maxTokens": 4096, "ai.systemPromptFile": ".ai/system-prompt.md" }几个参数说明一下。baseUrl固定用https://taotoken.net/api,不要加尾部斜杠。apiKey用环境变量引用,别硬编码,这样换机器时只改环境变量。temperature设 0.2 是因为重构类任务要的是稳定输出,不是发散创意。systemPromptFile指向项目内的提示词文件,把「禁止过度设计」这类约束写进去,比每次对话里重复交代更省事。
环境变量这样设:
export TAOTOKEN_API_KEY="sk-你的key"Windows PowerShell 用:
$env:TAOTOKEN_API_KEY="sk-你的key"3.2 config.toml 骨架
项目根目录放一个 config.toml,把编码约束固化下来:
[project] name = "auth-demo" language = "python" test_framework = "pytest" [ai.constraints] yagni = true max_function_lines = 30 forbid_patterns = ["StrategyFactory", "PluginManager", "AbstractAuthLayer"] require_test_first = true [ai.review] check_over_design = true check_unused_abstraction = true report_style = "concise"forbid_patterns这一项很关键。它明确告诉 AI:这个项目里不要出现工厂类、插件管理器、抽象认证层。require_test_first = true对应 TDD 纪律,让 AI 先写测试再写实现。max_function_lines = 30是个软约束,超过就提示拆分或说明理由。
3.3 system-prompt.md 里写什么
.ai/system-prompt.md放一段简短约束:
你是本项目的编码助手。遵守以下规则: 1. 只实现当前明确需求,不预判未来扩展。 2. 新增抽象前必须说明:当前有几个调用方需要它。 3. 优先写测试,再写最小实现,最后才考虑重构。 4. 单个函数不超过 30 行,超过需给出理由。 5. 禁止引入策略模式、工厂模式、插件架构,除非需求明确要求。这段提示词配合 config.toml,能把 AI 的默认输出从「架构展示」拉回「需求实现」。
4. 用 TDD 把 300 行砍回 30 行
配置就位后,开始实际重构。核心方法是 TDD 三步:RED、GREEN、REFACTOR。每一步都只为当前需求服务。
4.1 RED:先写失败测试锁住意图
不要先让 AI 改代码,先让它写测试。测试描述的是业务意图,不是实现结构:
# test_login.py import pytest from auth.login import login def test_login_with_valid_credentials_returns_token(): token = login("alice", "correct-password") assert token is not None assert len(token) > 20 def test_login_with_wrong_password_raises(): with pytest.raises(ValueError): login("alice", "wrong-password")此时auth/login.py还不存在,跑测试必然失败。这个「红」的状态很重要,它证明测试确实在检验东西,而不是走过场。
pytest test_login.py -v # 预期:ModuleNotFoundError 或 ImportError,测试红4.2 GREEN:写最小实现让测试变绿
现在让 AI 写实现,但明确要求:不要接口、不要工厂、不要插件,就一个函数。
# auth/login.py import hashlib import hmac import time import jwt SECRET = "your-secret-key" def login(username: str, password: str) -> str: user = _find_user(username) if user is None or not _verify_password(password, user["password_hash"]): raise ValueError("invalid credentials") return _issue_token(username) def _find_user(username: str): # 实际项目替换为数据库查询 fake_db = {"alice": {"password_hash": _hash("correct-password")}} return fake_db.get(username) def _verify_password(password: str, stored_hash: str) -> bool: return hmac.compare_digest(_hash(password), stored_hash) def _hash(password: str) -> str: return hashlib.sha256(password.encode()).hexdigest() def _issue_token(username: str) -> str: payload = {"sub": username, "exp": int(time.time()) + 3600} return jwt.encode(payload, SECRET, algorithm="HS256")跑测试:
pytest test_login.py -v # 预期:2 passed,测试绿到这里,功能已经跑通了。整个实现加上辅助函数不到 30 行,没有一行是为「未来」写的。
4.3 REFACTOR:真需要时才抽象
只有当项目确实要加第二种登录方式时,才允许重构。比如产品明确要求加 OAuth2,这时候再提取抽象:
# auth/strategies.py —— 仅在确实需要第二种登录方式时创建 from typing import Protocol class LoginStrategy(Protocol): def authenticate(self, credential: dict) -> str: ... class PasswordStrategy: def authenticate(self, credential: dict) -> str: return login(credential["username"], credential["password"])注意顺序:先有需求,再有抽象。不是先搭好框架等需求来填。
4.4 让 AI 帮你识别过度设计
把原来那 300 行贴给模型对话,用这个提示词:
以下是一段 AI 生成的登录代码。请逐段标注: 1. 哪些代码在当前需求(用户名密码登录返回 token)下会被执行; 2. 哪些是为未来需求准备的、当前无调用方的; 3. 给出删除建议,保留最小可运行实现。 输出格式:文件路径 | 行号范围 | 分类 | 理由实测下来,模型能比较准确地标出工厂类和插件管理器属于「无调用方」类别。这一步用模型对话入口做最顺手,地址在 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite 。
5. 验证请求与成功结果
配置和重构都做完后,要验证两件事:模型接入是否通、重构后的代码是否真的能跑。
5.1 验证模型接入
用 curl 发一个最小请求,确认 Key 和 base_url 配置正确:
curl -X POST https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "claude-sonnet-4-20250514", "messages": [{"role": "user", "content": "回复 OK 两个字母"}], "max_tokens": 16 }'预期返回里能看到"content": "OK"之类的响应。如果返回 401,检查 Key 是否复制完整;返回 404,检查 base_url 是不是写成了带路径的地址。
5.2 验证重构结果
跑完整测试套件,并统计代码行数:
pytest test_login.py -v wc -l auth/login.py预期输出类似:
test_login.py::test_login_with_valid_credentials_returns_token PASSED test_login.py::test_login_with_wrong_password_raises PASSED 2 passed in 0.12s 28 auth/login.py28 行,两个测试通过。对比原来的 300 行,删掉的是没有调用方的抽象层,保留的是真正跑通的逻辑。
5.3 验证 AI 后续输出是否收敛
再让 AI 加一个小功能,比如「登录失败三次锁定账户」,观察它是否还会默认堆架构:
在现有 login 函数基础上,增加登录失败三次锁定账户的逻辑。 要求:不新增类,不引入新抽象,只修改现有函数和测试。如果配置生效,AI 应该只在login函数里加计数逻辑,而不是新建一个LockStrategy或AttemptManager。这一步能验证你的 settings.json 和 config.toml 是否真的起了约束作用。
6. 本篇常见错排查
6.1 配置了但 AI 还是堆架构
最常见的原因是 system-prompt.md 没被加载。检查 settings.json 里ai.systemPromptFile的路径是否正确,以及文件是否真的存在于项目根目录。另一个原因是 config.toml 的forbid_patterns写得太泛,AI 可能换个名字绕过去,比如把StrategyFactory改成AuthResolver。这时候要把约束写成语义描述,而不是只列类名。
6.2 测试跑不起来
ModuleNotFoundError: No module named 'auth'通常是没在项目根目录跑 pytest,或者缺少__init__.py。在auth/目录下加一个空的__init__.py即可。jwt模块报错则是没装依赖:
pip install pyjwt pytest6.3 curl 返回 401 或 403
先确认环境变量是否真的导出成功:
echo $TAOTOKEN_API_KEY如果输出为空,说明 export 没生效,重新执行一遍。如果 Key 里有特殊字符,注意 shell 转义。403 一般是 Key 权限问题,去控制台确认这个 Key 是否绑定了对应模型。
6.4 base_url 写错导致 404
TaoToken 的 API 地址是https://taotoken.net/api,不要写成https://taotoken.net/api/v1再让客户端自己拼/v1,也不要加尾部斜杠。不同客户端对 base_url 的处理方式不一样,有的会自动补/v1/chat/completions,有的不会。对照接入文档确认你用的客户端该怎么填。
6.5 重构后测试绿了但线上报错
大概率是_find_user里的假数据没换成真实数据库查询。测试用的是内存假数据,线上要接真实存储。这一步别让 AI 猜你的表结构,把 schema 贴给它再改。
7. 把纠偏能力固定下来
过度设计这件事,单次纠偏不难,难的是让 AI 在后续每次生成里都保持克制。我的做法是把这套约束沉淀成项目模板:settings.json 管接入,config.toml 管规则,system-prompt.md 管语气,测试文件管边界。四样东西进版本库,换项目时直接复制。
模型接入这块,用 TaoToken 统一 Key 的好处是配置只写一次,后面换模型、换场景都不用动 base_url。长期做编码和 Agent 任务的话,Coding Plan 比按次调用更省心,地址在 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite 。接入细节和参数对照看文档 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,Key 在 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite 生成。
最后留一个我常用的检查动作:每次 AI 生成完代码,先别急着合并,跑一遍wc -l和测试,再问自己一句——这段代码里,有多少行是当前需求真的会执行的。如果比例低于一半,就该回去砍了。