技术教程 · 阅读约 10 分钟

Codex 循环两小时不动手?用 Claude 写个「自动代码审查机器人」替代它

Codex 循环两小时不动手?用 Claude 写个「自动代码审查机器人」替代它

你有没有遇到过这种情况:

把一个任务丢给 AI Coding 工具,它开始「分析代码」「读取文件」「理解上下文」……然后一直转,一直转,两个小时过去了,一行代码没写。

V2EX 今天就有人吐槽 Codex 的 spark 模型:循环了两个钟头的看源码+compact 就是不动手。

这不是个例。很多 AI Coding 工具在面对「审查整个 repo」这类任务时,会陷入无限的「思考」循环——因为它们试图一次性理解所有东西,反而什么都做不了。

解法其实很简单:自己写一个轻量的代码审查脚本,把任务拆小,让模型每次只看一个文件。


思路:分而治之,而不是一口吞

核心逻辑:

1. 遍历 repo 里所有 .py / .ts / .js 文件

2. 每个文件单独发给模型,让它只做一件事:找问题

3. 把所有结果汇总成一份 Markdown 报告

这样每次调用上下文可控,模型不会「迷失」,也不会循环。


完整代码(Python,可直接运行)


#!/usr/bin/env python3

"""

repo_review.py — 自动代码审查脚本

用法: python repo_review.py ./your-project

"""



import os

import sys

from pathlib import Path

from openai import OpenAI



# 改一行 base_url,直连国内,比官方省 60%

client = OpenAI(

    api_key=os.environ.get("OPENAI_API_KEY", "your-api-key-here"),

    base_url="https://api2everything.xyz/v1",

)



# 支持审查的文件类型

SUPPORTED_EXTENSIONS = {".py", ".ts", ".js", ".go", ".java", ".rs"}



# 单文件最大字符数(避免超出上下文)

MAX_FILE_CHARS = 8000



REVIEW_PROMPT = """你是一个资深代码审查工程师。请审查以下代码,重点关注:

1. 潜在的 Bug 或逻辑错误

2. 安全漏洞(SQL 注入、未校验输入等)

3. 性能问题

4. 代码可读性和命名规范



文件名: {filename}



{code}




请用简洁的 Markdown 列表输出问题,每条问题注明行号(如果能判断)。

如果代码没有明显问题,直接回复「✅ 无明显问题」。

不要重复代码内容,只输出审查结论。"""





def get_files_to_review(repo_path: str) -> list[Path]:

    """递归获取所有需要审查的文件"""

    root = Path(repo_path)

    files = []

    

    # 跳过这些目录

    skip_dirs = {".git", "node_modules", "__pycache__", ".venv", "dist", "build"}

    

    for path in root.rglob("*"):

        if any(skip in path.parts for skip in skip_dirs):

            continue

        if path.is_file() and path.suffix in SUPPORTED_EXTENSIONS:

            files.append(path)

    

    return sorted(files)





def review_file(file_path: Path) -> dict:

    """审查单个文件,返回结果"""

    try:

        content = file_path.read_text(encoding="utf-8", errors="ignore")

    except Exception as e:

        return {"file": str(file_path), "result": f"❌ 读取失败: {e}"}

    

    # 文件太大就截断,避免超出上下文

    if len(content) > MAX_FILE_CHARS:

        content = content[:MAX_FILE_CHARS] + "\n\n... [文件过长,已截断]"

    

    if not content.strip():

        return {"file": str(file_path), "result": "⏭️ 空文件,跳过"}

    

    try:

        response = client.chat.completions.create(

            model="claude-3-5-sonnet-20241022",  # 也可以换成 gpt-4o / deepseek-chat

            messages=[

                {

                    "role": "user",

                    "content": REVIEW_PROMPT.format(

                        filename=file_path.name,

                        code=content

                    )

                }

            ],

            max_tokens=1024,

            temperature=0.2,  # 审查任务用低温度,输出更稳定

        )

        result = response.choices[0].message.content

    except Exception as e:

        result = f"❌ API 调用失败: {e}"

    

    return {"file": str(file_path), "result": result}





def generate_report(reviews: list[dict], repo_path: str) -> str:

    """生成 Markdown 格式的审查报告"""

    lines = [

        f"# 代码审查报告",

        f"\n**项目路径**: `{repo_path}`",

        f"**审查文件数**: {len(reviews)}",

        "\n---\n",

    ]

    

    issues_found = 0

    for review in reviews:

        lines.append(f"## 📄 `{review['file']}`\n")

        lines.append(review["result"])

        lines.append("\n---\n")

        if "✅" not in review["result"] and "⏭️" not in review["result"]:

            issues_found += 1

    

    lines.insert(3, f"**发现问题的文件数**: {issues_found}\n")

    return "\n".join(lines)





def main():

    if len(sys.argv) < 2:

        print("用法: python repo_review.py <repo路径>")

        sys.exit(1)

    

    repo_path = sys.argv[1]

    if not os.path.isdir(repo_path):

        print(f"错误: {repo_path} 不是有效目录")

        sys.exit(1)

    

    files = get_files_to_review(repo_path)

    print(f"找到 {len(files)} 个文件,开始审查...\n")

    

    reviews = []

    for i, file_path in enumerate(files, 1):

        print(f"[{i}/{len(files)}] 审查: {file_path}")

        review = review_file(file_path)

        reviews.append(review)

    

    report = generate_report(reviews, repo_path)

    

    output_file = "review_report.md"

    Path(output_file).write_text(report, encoding="utf-8")

    print(f"\n✅ 审查完成!报告已保存到: {output_file}")





if __name__ == "__main__":

    main()


运行方式


# 安装依赖

pip install openai



# 设置 API Key(用无量Api的 key)

export OPENAI_API_KEY="sk-your-key-here"



# 审查你的项目

python repo_review.py ./your-project

几分钟后,当前目录会生成一份 review_report.md,每个文件的问题一目了然。


几个值得注意的细节

为什么不用流式输出? 审查任务需要完整结果再汇总,流式在这里反而增加复杂度。

模型选哪个? 代码审查推荐 claude-3-5-sonnet 或 gpt-4o,理解能力强。如果只是快速扫描,deepseek-chat 性价比极高,速度也快。

文件截断会不会漏掉问题? 会。超过 8000 字符的文件建议手动拆分,或者把 MAX_FILE_CHARS 调大(注意对应模型的上下文限制)。

temperature 为什么设 0.2? 审查是分析任务,不需要创意,低温度让输出更稳定、更少幻觉。


关于 API 费用

这个脚本每审查一个中等大小的文件大概消耗 1000-2000 tokens。一个 50 个文件的项目,用 Claude Sonnet 大概花 ¥0.5 左右。

如果你直接用官方 API,同样的调用要贵将近 3 倍。我现在用的是 无量Api,国内直连,支持 OpenAI / Claude / Gemini / DeepSeek 等 300+ 模型,比官方便宜 65%,注册还送 ¥1 余额。接入方式就是改一行 base_url,其他代码完全不用动——脚本里已经写好了。


遇到问题欢迎评论区留言,比如「某类文件审查结果不准」「想加入自动 PR comment 功能」这些我都可以继续写。

觉得有用的话点个赞,下次继续写 AI 工具实战。