用 50 行 Python 让 AI 帮你审完整个代码仓库(附完整可运行代码)
用 50 行 Python 让 AI 帮你审完整个代码仓库(附完整可运行代码)
很多人用 AI 审代码的方式是:复制一个文件,粘贴进对话框,等回复,再复制下一个。
这种方式有两个问题:一是累,二是 AI 看不到文件之间的依赖关系,给出的建议往往是孤立的、没有上下文的。
真正有用的代码审查,应该是让模型同时看到整个 repo 的结构,然后给出跨文件的、有依赖意识的建议。
今天就来实现这个。
思路
核心逻辑很简单:
1. 递归遍历 repo,收集所有代码文件
2. 把文件路径 + 内容拼成一个大的 context
3. 一次性发给模型,让它做整体审查
难点在于:大型 repo 的 token 量会超限。解决方案是分批 + 摘要:先让模型对每个文件生成摘要,再把摘要汇总后做整体分析。
完整代码
import os
import sys
from pathlib import Path
from openai import OpenAI
# 改一行 base_url,国内直连,无需代理
client = OpenAI(
api_key="your_api_key_here",
base_url="https://api2everything.xyz/v1"
)
# 要审查的文件类型
CODE_EXTENSIONS = {'.py', '.js', '.ts', '.go', '.java', '.rs', '.cpp', '.c', '.h'}
# 单文件 token 上限(粗略按字符估算,4 char ≈ 1 token)
MAX_CHARS_PER_FILE = 8000
def collect_files(repo_path: str) -> list[dict]:
"""递归收集代码文件"""
files = []
repo = Path(repo_path)
# 跳过这些目录
skip_dirs = {'.git', 'node_modules', '__pycache__', '.venv', 'dist', 'build'}
for path in repo.rglob('*'):
if any(part in skip_dirs for part in path.parts):
continue
if path.is_file() and path.suffix in CODE_EXTENSIONS:
try:
content = path.read_text(encoding='utf-8', errors='ignore')
files.append({
'path': str(path.relative_to(repo)),
'content': content[:MAX_CHARS_PER_FILE],
'truncated': len(content) > MAX_CHARS_PER_FILE
})
except Exception:
pass
return files
def summarize_file(file: dict) -> str:
"""让模型对单个文件生成结构摘要"""
truncation_note = "(内容已截断)" if file['truncated'] else ""
prompt = f"""请对以下代码文件做简短分析(100字以内),包括:主要功能、潜在问题、值得关注的点。
文件路径:{file['path']} {truncation_note}
{file['content']}
response = client.chat.completions.create(
model="gpt-4o-mini", # 摘要阶段用便宜的小模型
messages=[{"role": "user", "content": prompt}],
max_tokens=200
)
return response.choices[0].message.content
def review_repo(repo_path: str, model: str = "gpt-4o"):
"""主流程:审查整个 repo"""
print(f"📂 扫描仓库:{repo_path}")
files = collect_files(repo_path)
if not files:
print("未找到代码文件")
return
print(f"📄 找到 {len(files)} 个文件,开始生成摘要...\n")
# 第一阶段:并行生成每个文件的摘要
summaries = []
for i, file in enumerate(files):
print(f" [{i+1}/{len(files)}] {file['path']}")
summary = summarize_file(file)
summaries.append(f"### {file['path']}\n{summary}")
# 第二阶段:汇总摘要,做整体审查
print("\n🔍 正在进行整体代码审查...\n")
all_summaries = "\n\n".join(summaries)
final_prompt = f"""你是一位资深工程师,正在对一个代码仓库做整体 Code Review。
以下是仓库中每个文件的摘要:
{all_summaries}
请从以下维度给出整体审查报告:
1. **架构问题**:模块划分、依赖关系是否合理
2. **安全风险**:有无明显的安全漏洞或不良实践
3. **性能隐患**:可能的性能瓶颈
4. **代码质量**:命名、注释、可维护性
5. **优先修复项**:列出最需要立即处理的 3 个问题
用中文回答,给出具体的文件路径和改进建议。"""
response = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": final_prompt}],
max_tokens=2000
)
print("=" * 60)
print("📋 Code Review 报告")
print("=" * 60)
print(response.choices[0].message.content)
if __name__ == "__main__":
repo_path = sys.argv[1] if len(sys.argv) > 1 else "."
review_repo(repo_path)
使用方式
pip install openai
# 审查当前目录
python review.py .
# 审查指定路径
python review.py /path/to/your/project
把 your_api_key_here 换成你的 key 就能跑。
几个值得注意的细节
为什么摘要阶段用 gpt-4o-mini?
摘要是重复性、低难度任务,用小模型足够,成本大概是 gpt-4o 的 1/15。整体审查才需要强模型的推理能力。这种分层调用是控制成本的常见手段。
为什么不直接把所有文件塞进一个 prompt?
对于超过 20 个文件的 repo,直接拼接很容易超过 128k context 限制,而且模型在超长 context 中间部分的注意力会显著下降(lost in the middle 问题)。分批摘要 + 汇总的方式更稳定。
想换成 Claude 怎么办?
把 model 参数改成 claude-sonnet-4-5 就行,接口格式完全兼容,base_url 不用动。
关于 API 费用
跑一次中型项目(50 个文件左右),大概消耗:
- 摘要阶段(gpt-4o-mini):约 $0.02
- 整体审查(gpt-4o):约 $0.05
如果直接用 OpenAI 官方,加上国内访问需要的代理成本,实际花费会更高。
我自己用的是 无量Api,国内直连,价格比官方便宜 60% 以上,OpenAI / Claude / Gemini / DeepSeek 300+ 模型都有,注册就送 ¥1 余额,改一行 base_url 就能用,上面代码里已经写好了。
扩展方向
- 加
--fix参数,让模型直接输出修复后的代码 - 接入 GitHub Actions,每次 PR 自动触发审查
- 把报告格式改成 SARIF,直接导入 VS Code 的 Problems 面板
有跑起来遇到问题的,评论区说一下,我看到都会回。觉得有用的话点个赞,后续还会写更多 AI + 工程效率的实战内容。