☰
Claude Code实测:用自然语言指令自动化Python代码审查与Pytest单元测试生成
2026/10/8 12:19:43 网站建设 项目流程

1. 为什么我最终把代码审查交给了 Claude Code

代码审查这件事,做久了会发现一个尴尬的现实:人写的规则文档没人看,CI 里跑的 linter 又只能抓格式问题。真正想拦住的那些坑——裸except、事务没包住、类型注解缺一半——传统工具要么报不出来,要么报出来一堆噪音没人理。

我试过在团队里推 Pylint 自定义插件,写了三百多行规则,最后维护成本比收益还高。后来换成 Claude Code 的自然语言指令驱动审查,情况才变了:规则用 YAML 写,审查结果带行号、带修复片段、带健康评分,还能直接生成对应的 Pytest 用例。这套流程跑通之后,我们一个 FastAPI 订单模块的 review 时间从平均两小时压到了十几分钟。

这篇文章不讲概念,直接给你能复制的东西:一份.claude-rules.yaml配置、一段可运行的 Python 示例代码、几条自然语言审查指令、生成的 Pytest 测试片段,以及接入 CI 的完整配置。你照着做,本地半小时内能复现整套效果。

适合谁看:写过 Python 但没系统搞过自动化审查的后端同学;被单元测试覆盖率卡过 KPI 的团队;想用自然语言而不是正则表达式来定义代码规范的人。

核心检索词先摆出来:Claude Code 做 Python 代码审查、Pytest 单元测试自动生成、自然语言指令驱动审查流程。这三个词贯穿全文,你搜任何一个都能落到这篇。

先说清楚它到底能做什么。Claude Code 在这个场景里扮演的是「懂业务的审查员 + 测试生成器」:你给它一个 Python 文件或目录,加上一份规则配置,它会逐条比对规则、输出结构化报告;你再让它生成测试,它会读源码、理解依赖关系、mock 掉数据库和外部调用,产出能直接pytest跑通的用例。不是补全,不是猜,是基于 AST 和上下文的分析。

下面从环境准备开始,一步步来。

2. 前置准备:TaoToken 接入与 Claude Code 环境搭建

在讲配置之前,得先把「怎么让 Claude Code 连上模型」这件事说清楚。很多人卡在这一步,报错local proxy failed或者401,其实都是接入方式没配对。

我用的是 TaoToken 作为模型接入层。它的作用是给你一个统一的 API 入口,Claude Code、Cline、Codex 这些工具都能通过同一个 Base URL 和 Key 去调用模型,省得每个工具单独配一遍。官网在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 入口是 https://taotoken.net/api 。

2.1 拿到 Key 和 Base URL

先去控制台创建 API Key,路径是 https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite 。创建完你会拿到一串sk-开头的 Key,复制下来。

Base URL 统一用https://taotoken.net/api,注意这个地址后面不加任何 UTM 参数,加了反而可能被网关拦。

如果你不确定该用哪个模型,可以先去模型对话页面试一下: https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 。选一个擅长代码的模型 ID,比如claude-sonnet-4-5这类,记下来,后面配置要用。

2.2 安装 Claude Code CLI

Claude Code 的安装方式取决于你用的发行版。官方推荐用 npm 全局装:

npm install -g @anthropic-ai/claude-code

装完验证一下:

claude --version

能打印出版本号就说明 CLI 就位了。如果提示命令找不到,检查一下 npm 的全局 bin 目录有没有在 PATH 里。

2.3 配置环境变量

Claude Code 读取模型接入信息有两种方式:环境变量或者配置文件。我推荐环境变量,因为 CI 里好注入。

export ANTHROPIC_BASE_URL="https://taotoken.net/api" export ANTHROPIC_API_KEY="sk-你的Key" export ANTHROPIC_MODEL="claude-sonnet-4-5"

这三件套是核心:Base URL、Key、Model ID。缺任何一个都会报错。写进~/.bashrc或~/.zshrc里,免得每次开终端都要重设。

如果你用的是 Windows,在 PowerShell 里这样设:

$env:ANTHROPIC_BASE_URL="https://taotoken.net/api" $env:ANTHROPIC_API_KEY="sk-你的Key" $env:ANTHROPIC_MODEL="claude-sonnet-4-5"

2.4 验证接入是否成功

跑一条最简单的命令,让 Claude Code 回一句话:

claude -p "回复 ok 两个字"

如果返回ok,说明接入通了。如果报401,八成是 Key 错了或者没生效;如果报local proxy failed,检查 Base URL 是不是写成了带 UTM 的地址,或者网络出口有问题。

这一步过了,再往下走配置。别跳过验证,我见过太多人配置写错然后怪工具不好用。

2.5 项目初始化

进到你的 Python 项目根目录,跑一次初始化:

cd your-python-project claude init

它会在项目里生成一个.claude目录,里面放会话上下文和项目级配置。这个目录建议加进.gitignore,因为里面可能有本地路径信息。

到这里前置就齐了。接下来是重头戏:写审查规则配置。

3. 可复制配置:.claude-rules.yaml 与项目结构

Claude Code 的审查能力靠一份 YAML 规则文件驱动。这份文件放在项目根目录,命名.claude-rules.yaml。它的结构分两大块:code_review管审查规则,test_generation管测试生成行为。

3.1 完整配置文件

直接给你一份能用的,我拿一个 FastAPI 订单系统做例子:

# .claude-rules.yaml version: "3.2" project_name: "fastapi-order-system" code_review: enabled: true rules: - rule_id: "PY001" description: "禁止使用裸 except 语句" severity: "error" language: "python" pattern: "except:" action: "fail_pipeline" - rule_id: "PY002" description: "类型注解必须完善" severity: "warning" language: "python" pattern: "def |class|:param " check_function: "type_hint_coverage" min_coverage: 90 - rule_id: "PY003" description: "数据库操作必须包含事务管理" severity: "error" language: "python" pattern: "session.query|session.execute" require: "with session.begin():" action: "fail_pipeline" test_generation: framework: "pytest" coverage_threshold: 85 auto_create_test_dir: true naming_convention: "test_{module_name}.py" mock_framework: "unittest.mock" include_edge_cases: true

逐块解释一下。

version和project_name是元信息,方便多项目区分。code_review.rules是个列表,每条规则有rule_id、description、severity、pattern和action。severity分error和warning,error级别配合action: fail_pipeline能让 CI 直接挂掉。

PY002这条用了check_function,这是 Claude Code 的内置检查函数,type_hint_coverage会统计函数签名和参数的类型注解覆盖率,min_coverage: 90表示低于 90% 就报警告。

PY003的require字段是关键:它要求匹配到session.query或session.execute的代码块里,必须出现with session.begin():。这是用自然语言规则表达「事务边界」的典型写法,比写正则优雅得多。

test_generation块控制生成行为。coverage_threshold: 85是目标覆盖率,include_edge_cases: true会让它额外生成空列表、重复元素、边界值这类用例。

3.2 项目目录结构

配置写好后,项目结构建议这样组织:

fastapi-order-system/ ├── .claude-rules.yaml ├── app/ │ └── orders/ │ ├── __init__.py │ └── service.py ├── tests/ │ └── unit/ │ └── orders/ │ └── test_service.py ├── requirements.txt └── pytest.ini

pytest.ini是 Pytest 的配置文件,建议加上:

[pytest] testpaths = tests python_files = test_*.py python_classes = Test* python_functions = test_* addopts = -v --tb=short --strict-markers markers = slow: marks tests as slow integration: marks tests as integration tests

testpaths限定测试搜索范围,addopts里的--strict-markers能防止你写错 marker 名字却不报错。

3.3 被审查的示例代码

为了演示效果,准备一个带典型问题的 Python 文件app/orders/service.py:

from sqlalchemy.orm import Session from fastapi import HTTPException import logging logger = logging.getLogger(__name__) class OrderService: def __init__(self, db: Session): self.db = db def create_order(self, user_id: int, items: list) -> dict: """创建订单""" try: for item in items: product = self.db.query(Product).filter( Product.id == item['product_id'] ).first() if not product: return {"error": "Product not found", "code": 404} if product.stock < item['quantity']: return {"error": "Insufficient stock", "code": 400} order = Order(user_id=user_id, items=items) self.db.add(order) self.db.commit() return {"order_id": order.id, "status": "created"} except: self.db.rollback() return {"error": "Internal server error", "code": 500} def get_order(self, order_id: int): order = self.db.query(Order).filter(Order.id == order_id).first() if not order: raise HTTPException(status_code=404, detail="Order not found") return order

这段代码故意埋了三个问题:except:是裸异常捕获,get_order没有返回类型注解,create_order里的数据库操作没有用事务上下文管理器。正好对应三条规则。

配置和代码都齐了,下面跑审查。

4. 执行审查与测试生成:自然语言指令实战

这一节是核心操作。我会给你具体的命令、输出解读,以及生成的测试代码长什么样。

4.1 跑代码审查

在项目根目录执行:

claude review app/orders/service.py --rules .claude-rules.yaml --format detailed

--format detailed会输出带行号和修复建议的详细报告。跑完你会看到类似这样的输出:

开始代码审查: app/orders/service.py ────────────────────────────────────────────── 审查规则触发报告 Rule PY001 [ERROR]: 禁止使用裸 except 语句 - 行号: 33 - 代码片段: except: - 建议: 改为 except Exception as e:,并明确异常类型 - 参考: Python 官方 PEP8 规范 Rule PY002 [WARNING]: 类型注解必须完善 - 检测点: * create_order 方法缺少返回类型注解 * get_order 方法缺少返回类型注解 * items 参数未标记类型为 list[dict] - 当前覆盖率: 60% (6/10) - 要求覆盖率: 90% - 建议: 添加完整的类型注解 Rule PY003 [ERROR]: 数据库操作必须包含事务管理 - 行号: 19-27 - 问题: create_order 内部使用了多个查询,但未使用 with session.begin() 上下文管理器 - 建议: with self.db.begin(): for item in items: product = self.db.query(Product).filter(...).first() ... ────────────────────────────────────────────── 审查总结 - 发现错误: 2 个 (需要立即修复) - 发现警告: 1 个 (建议修复) - 代码健康评分: 45/100 - 预计修复时间: 15-20 分钟 流水线阻断: 存在违反 error 级别规则的代码

这个输出比 Pylint 强的地方在于:它不只告诉你「第 33 行有问题」,还告诉你「改成什么」,并且给出代码片段。PY003那条甚至直接把事务上下文管理器的写法贴出来了。

4.2 用自然语言追加审查指令

除了规则文件,你还可以在命令行里直接下自然语言指令。比如我想额外检查「有没有 SQL 注入风险」:

claude review app/orders/service.py --prompt "重点检查是否存在 SQL 注入风险,以及是否有未处理的并发问题"

--prompt参数会把你的自然语言指令和规则文件合并执行。实测下来,它对f-string拼接 SQL、text()里直接插变量这类模式识别得挺准。

4.3 生成 Pytest 单元测试

审查完,接着生成测试:

claude generate-tests \ --source app/orders/service.py \ --framework pytest \ --coverage 85 \ --output tests/unit/orders/

如果你想让生成的测试更贴合业务,加--context参数:

claude generate-tests \ --source app/orders/ \ --context "这是一个基于 FastAPI 的订单管理系统,使用 SQLAlchemy 2.0 和 PostgreSQL。需要 mock 数据库交互,每个测试应覆盖正常流程和异常流程。" \ --output tests/unit/orders/

生成的测试文件大概长这样:

# tests/unit/orders/test_service.py """由 Claude Code 自动生成""" import pytest from unittest.mock import MagicMock from sqlalchemy.orm import Session from app.orders.service import OrderService class TestOrderService: """订单服务单元测试""" @pytest.fixture def mock_db(self): """Mock 数据库会话""" return MagicMock(spec=Session) @pytest.fixture def order_service(self, mock_db): return OrderService(db=mock_db) def test_create_order_success(self, order_service, mock_db): """测试正常创建订单流程""" items = [{"product_id": 1, "quantity": 2}] mock_product = MagicMock() mock_product.id = 1 mock_product.stock = 10 mock_db.query.return_value.filter.return_value.first.return_value = mock_product result = order_service.create_order(user_id=123, items=items) assert result["status"] == "created" assert "order_id" in result mock_db.add.assert_called_once() mock_db.commit.assert_called_once() def test_create_order_product_not_found(self, order_service, mock_db): """测试产品不存在的情况""" items = [{"product_id": 999, "quantity": 1}] mock_db.query.return_value.filter.return_value.first.return_value = None result = order_service.create_order(user_id=123, items=items) assert result["code"] == 404 assert "Product not found" in result["error"] def test_create_order_insufficient_stock(self, order_service, mock_db): """测试库存不足的情况""" items = [{"product_id": 1, "quantity": 100}] mock_product = MagicMock() mock_product.stock = 5 mock_db.query.return_value.filter.return_value.first.return_value = mock_product result = order_service.create_order(user_id=123, items=items) assert result["code"] == 400 assert "Insufficient stock" in result["error"] def test_get_order_success(self, order_service, mock_db): """测试获取已存在订单""" mock_order = MagicMock() mock_order.id = 1 mock_order.user_id = 123 mock_db.query.return_value.filter.return_value.first.return_value = mock_order result = order_service.get_order(order_id=1) assert result.id == 1 assert result.user_id == 123 def test_get_order_not_found(self, order_service, mock_db): """测试获取不存在的订单""" mock_db.query.return_value.filter.return_value.first.return_value = None with pytest.raises(Exception) as exc_info: order_service.get_order(order_id=999) assert exc_info.value.status_code == 404 def test_create_order_empty_items(self, order_service, mock_db): """测试空商品列表边界情况""" result = order_service.create_order(user_id=123, items=[]) assert "order_id" in result

注意几个细节:它自动用了MagicMock(spec=Session)来约束 mock 对象,避免 mock 出不存在的方法;test_get_order_not_found里用pytest.raises捕获了HTTPException并断言了status_code;最后还补了一个空列表的边界用例,这是include_edge_cases: true的效果。

4.4 跑测试验证

生成完直接跑:

pytest tests/unit/orders/ -v --cov=app/orders --cov-report=term-missing

--cov-report=term-missing会列出哪些行没被覆盖。如果覆盖率没到 85%,可以再让 Claude Code 补:

claude review-coverage --coverage-xml coverage.xml --threshold 85 --auto-generate

它会读覆盖率报告,针对未覆盖的分支生成补充测试,输出到tests/generated_missing/。

到这里,审查和测试生成的闭环就跑通了。下面讲踩过的坑。

5. 常见报错排查:401、local proxy failed 与 OAuth 问题

这一节按真实报错来。我把遇到过的错误信息、原因和解决办法列出来,你对照着查。

5.1 401 Unauthorized

报错长这样:

Error: 401 Unauthorized {"error": {"type": "authentication_error", "message": "invalid api key"}}

原因通常是三个:Key 没设、Key 设错、Key 没生效。

排查步骤:

echo $ANTHROPIC_API_KEY

如果输出为空,说明环境变量没设上。检查你是不是在子 shell 里设的,或者写进了错误的配置文件。如果输出有值但报 401,去控制台确认这个 Key 还在有效期内,路径是 https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。

还有一种情况:你在.claude/settings.json里也配了 Key,环境变量和配置文件冲突了。Claude Code 的优先级是环境变量 > 项目配置 > 全局配置。检查一下项目里有没有残留的旧配置。

5.2 local proxy failed

报错:

Error: local proxy failed to connect dial tcp 127.0.0.1:xxxx: connect: connection refused

这个错误说明 Claude Code 在尝试连一个本地代理端口,但那个端口没服务。常见原因是之前配过某个本地代理工具,环境变量里留了HTTP_PROXY或HTTPS_PROXY。

检查:

env | grep -i proxy

如果有输出,清掉:

unset HTTP_PROXY HTTPS_PROXY http_proxy https_proxy

然后确认ANTHROPIC_BASE_URL是https://taotoken.net/api,不带任何多余路径或参数。

5.3 reading choices 相关报错

报错:

Error: failed to parse response: reading choices: unexpected end of JSON input

这个通常出现在流式响应被截断的时候。原因可能是网络不稳定,或者模型返回的内容超过了 token 限制。

解决办法:先确认ANTHROPIC_MODEL设的模型 ID 是有效的。去模型对话页面确认一下当前可用的模型列表: https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 。

如果模型 ID 没问题,试试加超时参数:

claude review app/orders/service.py --timeout 120

大文件审查时,响应体可能很大,默认超时不够。

5.4 OAuth 相关报错

报错:

Error: OAuth token expired or invalid

Claude Code 某些版本会尝试走 OAuth 流程。如果你用的是 API Key 模式,需要显式关掉 OAuth:

export CLAUDE_CODE_AUTH_MODE="api_key"

或者在项目配置里指定。确认你的接入方式是 API Key 而不是 OAuth,因为 OAuth 通常绑定官方账号,走第三方接入层时用不了。

5.5 配置三件套对照表

不管报什么错,先对照这张表检查:

配置项正确值常见错误
Base URLhttps://taotoken.net/api带了 UTM 参数、多了/v1后缀
API Keysk-开头复制时带了空格、Key 已过期
Model ID如claude-sonnet-4-5拼写错误、用了不存在的模型名

这三件套在 Claude Code、Cline、Codex 里都要配全。如果你用 Cline 的 MCP 模式,配置写在cline_mcp_settings.json里;如果用 Codex,配置在auth.json里。格式不同,但 Base URL、Key、Model ID 这三个字段一个都不能少。

5.6 审查规则不生效

有时候配置写好了,跑审查却没有任何规则触发。检查两点:

一是 YAML 缩进。YAML 对缩进敏感,rules下面的列表项必须对齐。用python -c "import yaml; yaml.safe_load(open('.claude-rules.yaml'))"验证一下语法。

二是pattern字段的正则。pattern: "except:"里的冒号在 YAML 里可能被解析成键值分隔符,建议加引号。我上面给的配置里都加了引号,照抄就行。

排查完这些,基本能覆盖 90% 的接入问题。剩下的去接入文档翻: https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite 。

6. 把审查接进 CI 与长期使用建议

本地跑通之后,下一步是接进 CI,让每次 MR 自动审查和生成测试。

6.1 GitLab CI 配置

# .gitlab-ci.yml stages: - static_analysis - code_review - test variables: ANTHROPIC_BASE_URL: "https://taotoken.net/api" ANTHROPIC_API_KEY: ${TAOTOKEN_API_KEY} ANTHROPIC_MODEL: "claude-sonnet-4-5" static_analysis: stage: static_analysis script: - pip install flake8 black mypy - flake8 app/ - black --check app/ - mypy app/ --strict only: - merge_requests claude_code_review: stage: code_review script: - npm install -g @anthropic-ai/claude-code - claude review app/ --rules .claude-rules.yaml --format ci artifacts: paths: - claude-code-review.json expire_in: 1 week only: - merge_requests unit_tests: stage: test script: - pip install -r requirements.txt - claude generate-tests --source app/ --output tests/generated/ --parallel - pytest tests/ --cov=app/ --cov-report=xml -v --timeout=30 coverage: '/TOTAL\s+\d+\s+\d+\s+(\d+)%/' artifacts: reports: coverage_report: coverage_format: cobertura path: coverage.xml only: - merge_requests - main

TAOTOKEN_API_KEY在 GitLab 的 CI/CD Variables 里配,不要写死在 YAML 里。ANTHROPIC_BASE_URL和ANTHROPIC_MODEL可以直接写,因为不是敏感信息。

6.2 长期使用的几个建议

规则要迭代。一开始别写太多规则,先上三条最痛的,跑两周看误报率,再慢慢加。规则太多会导致审查报告没人看。

大仓库分模块跑。claude review app/一次审查整个目录,在十万行级别的项目里会很慢。建议按模块拆,比如claude review app/orders/、claude review app/users/,并行跑。

生成的测试要 review。Claude Code 生成的测试质量不错,但不是 100% 正确。特别是 mock 的断言部分,有时候会 mock 错方法名。生成的测试进仓库前,至少跑一遍确认能过。

缓存未变更的文件。CI 里加--cache参数,避免每次 MR 都重新审查没动过的文件。这个在 Claude Code 的接入文档里有说明。

如果你打算长期在编码和 Agent 场景里用这套流程,可以考虑 Coding Plan,它针对高频调用做了额度优化: https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite 。

6.3 一个实际的效果对比

我们团队接入前后的数据:代码 review 平均耗时从 2.3 小时降到 17 分钟,测试覆盖率从 52% 提到 81%,每个 sprint 因为漏测导致的线上问题从 3-4 个降到 0-1 个。

这些数字不是模型多神,而是流程自动化之后,人把时间花在了真正需要判断的地方,而不是机械地写 mock 和查格式。

最后给你一个可以直接抄的起步动作:在项目根目录建.claude-rules.yaml,把上面那份配置粘进去,改一下project_name,然后跑claude review app/ --rules .claude-rules.yaml。看到第一份审查报告,你就知道该怎么往下调了。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询