在 AI 辅助编程领域,GitHub Copilot 虽然方便,但往往只能针对当前文件进行补全,缺乏对'整个项目结构'的宏观理解。随着 Claude 3.5 Sonnet 在 Coding Benchmarks(编程基准测试)中表现优异,以及 Gemini 1.5 Pro 开放百万级上下文窗口,我们完全有能力自己动手,构建一个比 Copilot 更懂业务逻辑的私人编程助手。本文将从 AST(抽象语法树)解析开始,深入讲解如何利用 Python 构建一个 RAG(检索增强生成)架构,并通过 API 聚合网关接入大模型,实现对遗留代码(Legacy Code)的自动化重构与审计。
一、痛点:为什么我们需要'第二代'AI 编程助手?
作为一名每天要写几百行代码的开发者,你是否遇到过以下场景:
- 接手'屎山'代码:前人留下的代码逻辑错综复杂,没有任何文档,Copilot 只能补全语法,却无法告诉你'这个类是干嘛的'。
- 全局重构困难:当你修改了一个底层函数的参数,很难评估这对上层几十个调用方会产生什么影响。
- 模型幻觉:使用普通的 GPT-3.5 或 4.0 写代码,经常出现调用的库不存在,或者语法过时的问题。
Claude 3.5 Sonnet 的出现改变了游戏规则。 它在 HumanEval 和 MBPP 等代码测试集中,展现出了惊人的'一次通过率'。更重要的是,它的逻辑推理能力极其适合处理复杂的系统架构问题。而配合 Gemini 1.5 Pro 的超大上下文,我们甚至可以把整个 Linux 内核的一部分扔给它去分析。
今天,我们就用 Python 来实现一个 CLI(命令行)工具,我给它取名为 Code-Auditor。
二、架构设计:基于 LLM 的代码分析流水线
要实现一个能读懂项目的 Agent,不能简单地把代码粘贴给 AI。我们需要设计一个 Pipeline:
- 文件扫描器(File Scanner):遍历项目目录,通过
.gitignore 规则过滤掉无关文件(如 node_modules, __pycache__)。
- 上下文压缩(Context Compressor):对于超大项目,直接发送会消耗巨额 Token。我们需要对代码进行预处理(如去除注释、压缩空行)。
- 大模型网关(LLM Gateway):通过 API 调用 Claude 3.5 Sonnet 或 Gemini 1.5 Pro。
- 流式响应处理(Stream Handler):实时输出分析结果,提升交互体验。
2.1 为什么选择 API 聚合模式?
在实战中,直接对接 Anthropic(Claude 的母公司)或 Google 的 API 存在两个工程难题:
- 网络连通性:国内服务器无法直连。
- 多模型切换:你可能希望用 Claude 写代码,用 Gemini 分析文档。维护多套 SDK 成本太高。
因此,本项目采用 OpenAI 兼容协议 的聚合网关方案。这意味着我们可以用标准的 openai Python 库,去调用 Claude 和 Gemini,实现'一套代码,模型随意切'。
三、环境准备与工具链
在开始 Coding 之前,请确保你的环境满足以下要求。
3.1 核心依赖库
我们需要安装以下 Python 库:
openai: 虽然我们要调用的不是 GPT,但通过兼容协议,这是最通用的客户端。
pathspec: 用于解析 .gitignore 文件,避免把垃圾文件发给 AI。
rich: 用于在终端输出漂亮的彩色文本和进度条。
pip install openai pathspec rich python-dotenv
3.2 获取 API Access
为了演示,我们将使用支持 Claude 3.5 Sonnet 和 Gemini 1.5 Pro 的算力平台,且接口格式与 OpenAI 完全一致。
API Key 获取地址:请前往相关服务商官网申请开发者通道。
四、核心代码实战:编写 Code-Auditor
我们将代码分为三个模块:scanner.py(文件处理)、client.py(模型交互)、main.py(主程序)。
4.1 模块一:智能文件扫描器 (scanner.py)
这个模块的难点在于:如何像 Git 一样聪明地忽略文件?
import os
import pathspec
class ProjectScanner:
def __init__(self, root_dir):
self.root_dir = root_dir
self.gitignore = self._load_gitignore()
def _load_gitignore(self):
"""加载.gitignore 规则"""
gitignore_path = os.path.join(self.root_dir, ".gitignore")
if os.path.exists(gitignore_path):
with open(gitignore_path, "r", encoding="utf-8") as f:
return pathspec.PathSpec.from_lines("gitwildmatch", f)
return pathspec.PathSpec.from_lines("gitwildmatch", [])
def scan(self):
"""遍历项目,返回所有代码文件的内容"""
file_count = 0
code_context = ""
default_ignore = {".git", "__pycache__", "node_modules", "venv", ".idea", ".vscode"}
for root, dirs, files in os.walk(self.root_dir):
dirs[:] = [d for d in dirs if d not in default_ignore]
for file in files:
file_path = os.path.join(root, file)
rel_path = os.path.relpath(file_path, .root_dir)
.gitignore.match_file(rel_path):
file.endswith((, , , , , )):
:
(file_path, , encoding=) f:
content = f.read()
code_context +=
file_count +=
Exception:
code_context, file_count
4.2 模块二:Claude 模型客户端 (client.py)
这里是魔法发生的地方。注意 base_url 的配置,这是我们能够在一个 SDK 里调用不同模型的关键。
from openai import OpenAI
import os
class AIClient:
def __init__(self, api_key):
self.client = OpenAI(
api_key=api_key,
base_url=os.getenv("API_BASE_URL", "https://api.example.com/v1")
)
def analyze_code(self, code_context, prompt):
system_prompt = "你是一名拥有 20 年经验的资深架构师,精通 Clean Code 原则。你的任务是分析用户提供的项目代码,找出潜在的 Bug、性能瓶颈,并给出重构建议。请直接输出 Markdown 格式的报告,不要废话。"
try:
stream = self.client.chat.completions.create(
model="claude-3-5-sonnet",
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": f"项目代码如下:\n{code_context}\n\n用户需求:{prompt}"}
],
stream=True,
temperature=0.2
)
return stream
except Exception as e:
print(f"API 调用错误:{e}")
return None
4.3 模块三:主程序入口 (main.py)
结合 rich 库,打造极客风的终端界面。
import os
from scanner import ProjectScanner
from client import AIClient
from rich.console import Console
from rich.markdown import Markdown
console = Console()
def main():
api_key = os.getenv("VECTOR_API_KEY")
if not api_key:
console.print("[red] 错误:请设置环境变量 VECTOR_API_KEY[/red]")
return
target_dir = input("请输入要分析的项目路径 (默认当前目录): ").strip() or "."
with console.status("[bold green] 正在扫描项目文件...[/bold green]"):
scanner = ProjectScanner(target_dir)
context, count = scanner.scan()
console.print(f"[blue] 扫描完成!共发现 {count} 个代码文件,字符数:{len(context)}[/blue]")
if len(context) > 200000:
console.print("[yellow] 警告:项目过大,建议切换至 gemini-1.5-pro 模型以支持超长上下文[/yellow]")
while True:
user_query = input("\n请输入你的指令 (例如:'找出代码中的安全漏洞' 或 'q'退出): ")
if user_query.lower() == 'q':
break
ai = AIClient(api_key)
stream = ai.analyze_code(context, user_query)
if stream:
console.print("\n[bold cyan]--- Claude 3.5 Sonnet 分析报告 ---[/bold cyan]\n")
full_response = ""
chunk stream:
chunk.choices[].delta.content:
content = chunk.choices[].delta.content
(content, end=, flush=)
full_response += content
()
__name__ == :
main()
五、深度解析:为什么 Claude 3.5 更适合写代码?
在运行上述代码时,你会发现 Claude 3.5 Sonnet 与 GPT-4o 的一个显著区别:它更懂'人话'。
- Artifacts 思维:Claude 倾向于一次性生成完整的、可运行的代码块,而不是像挤牙膏一样一段段崩。
- 指令遵循(Instruction Following):在复杂的 Prompt 下(比如要求它同时遵循 PEP8 规范、添加类型注解、并编写单元测试),Claude 3.5 的遗漏率远低于其他模型。
- 视觉多模态辅助:虽然本文主要演示文本代码,但 Claude 3.5 的视觉能力极强。你可以截图 IDE 的报错弹窗发给它,它能精准定位 UI 层面的 Bug。
进阶技巧:利用 Gemini 1.5 Pro 处理超大项目
如果你的项目是一个几十万行的老旧 Java 工程,Token 数量轻松突破 10 万。这时候 Claude 的 200k 上下文可能捉襟见肘。
在 client.py 中,你只需要将 model 参数修改为 gemini-1.5-pro。平台会自动将请求路由到 Google 的服务器。Gemini 1.5 Pro 支持高达 100 万甚至 200 万 Token 的上下文。这意味着你可以把整个框架的源码一次性喂给它,问它:'请画出这个项目的 UML 类图'。这种能力在以前是无法想象的。
六、避坑指南与性能优化
在开发这个 Agent 的过程中,有几个技术细节需要注意:
6.1 Token 截断与成本控制
虽然是按量付费,但把整个 node_modules 发过去绝对是灾难。
- 优化方案:务必完善
ProjectScanner 中的过滤逻辑。对于 Python 项目,排除 venv;对于前端,排除 dist 和 build。
- 估算:1 个中文字符约等于 0.7 个 Token,1 行代码约等于 5-10 个 Token。
6.2 提示词工程(Prompt Engineering)
针对代码重构,推荐使用 CO-STAR 框架编写 Prompt:
- C (Context): "你是一个资深 Python 后端工程师..."
- O (Objective): "重构这段代码,使其符合解耦原则..."
- S (Style): "使用 Google 代码风格,强制类型提示..."
- T (Tone): "专业、严谨..."
- A (Audience): "面向初级开发者,代码要有详细注释..."
- R (Response): "输出 Markdown 格式..."
6.3 API 超时处理
分析大项目时,模型思考时间可能长达 30 秒。确保你的 HTTP Client 设置了足够的 timeout 时间,或者使用流式(Stream)接收,这样可以避免连接被中间网关切断。
七、结语
AI 不会取代程序员,但'会用 AI 的程序员'一定会取代'不会用 AI 的程序员'。
从 Copilot 的自动补全,到我们今天构建的全局代码审计 Agent,AI 介入开发的深度正在不断加深。掌握 API 聚合技术,灵活调用 Claude、Gemini 等不同特性的模型,将成为未来全栈开发者的必备技能。