📢 转载信息
原文链接:https://www.kdnuggets.com/ai-writes-python-code-but-maintaining-it-is-still-your-job
原文作者:Bala Priya C
作者提供
# 引言
AI 编码工具在编写可运行的 Python 代码方面变得异常出色。它们可以在几分钟内构建完整的应用程序和实现复杂的算法。然而,AI 生成的代码往往难以维护。
如果您正在使用 Claude Code、GitHub Copilot 或 Cursor 的智能体模式等工具,您很可能已经遇到过这种情况。AI 帮助您快速交付可运行的代码,但代价会在稍后显现。您可能在几周后重构一个臃肿的函数,仅仅是为了理解它的工作原理。
问题不在于 AI 编写了糟糕的代码——尽管有时确实如此——而在于 AI 优化的是“立即运行”并完成您提示中的要求,而您需要的是长期可读且可维护的代码。本文将重点介绍 Python 特有的策略,教您如何弥合这一差距。
# 避免“空白画布”陷阱
开发人员犯的最大错误是让 AI 从头开始。AI 智能体在有约束和指导方针的情况下工作效果最佳。
在编写第一个提示之前,请自己设置好项目的基本结构。这意味着要选择项目结构——安装核心库并实现一些可运行的示例——以定下基调。这可能看起来适得其反,但它有助于让 AI 编写的代码更好地符合您应用程序的实际需求。
首先手动构建几个功能。如果您正在构建一个 API,请自己实现一个完整的端点,包含您想要的所有模式:依赖注入、适当的错误处理、数据库访问和验证。这将成为参考实现。
假设您手动编写了第一个端点:
from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session router = APIRouter() # 假设 get_db 和 User 模型在别处定义 async def get_user(user_id: int, db: Session = Depends(get_db)): user = db.query(User).filter(User.id == user_id).first() if not user: raise HTTPException(status_code=404, detail="User not found") return user
当 AI 看到这种模式时,它就能理解我们如何处理依赖、如何查询数据库以及如何处理缺失的记录。
这同样适用于您的项目结构。创建目录、设置导入、配置测试框架。AI 不应该做这些架构决策。
# 让 Python 的类型系统承担繁重工作
Python 的动态类型很灵活,但这种灵活性在 AI 编写代码时会成为一种负担。请将类型提示(Type Hints)视为应用程序代码中必不可少的护栏,而不是可有可无的选项。
严格的类型检查可以在 AI 错误到达生产环境之前将其捕获。当您要求每个函数签名都包含类型提示,并在严格模式下运行 mypy 时,AI 就无法走捷径。它不能返回模糊的类型,也不能接受可能是字符串也可能是列表的参数。
更重要的是,严格的类型会促使设计更加完善。例如,一个尝试编写接受 data: dict 的函数的 AI 智能体可以对该字典的内容做出许多假设。但是,一个接受 data: UserCreateRequest 的函数的 AI 智能体,其中 UserCreateRequest 是一个 Pydantic 模型时,只有一个明确的解释。
# 这会约束 AI 编写正确的代码 from pydantic import BaseModel, EmailStr class UserCreateRequest(BaseModel): name: str email: EmailStr age: int class UserResponse(BaseModel): id: int name: str email: EmailStr def process_user(data: UserCreateRequest) -> UserResponse: pass # 而不是这个 def process_user(data: dict) -> dict: pass
使用强制执行契约的库:2.0 版本的 SQLAlchemy(带有类型检查模型)和使用响应模型的 FastAPI 是绝佳的选择。这些不仅仅是良好实践;它们是让 AI 走上正轨的约束。
将 mypy 设置为严格模式,并使通过类型检查成为不可协商的要求。当 AI 生成的代码无法通过类型检查时,它会迭代,直到通过为止。这种自动反馈循环产生的代码比任何提示工程都能产生更好的代码。
# 创建文档以指导 AI
大多数项目都有开发人员会忽略的文档。对于 AI 智能体,您需要它们实际使用的文档——比如一份包含指导方针的 README.md 文件。这需要一个包含清晰、具体规则的单个文件。
在项目根目录创建一个 CLAUDE.md 或 AGENTS.md 文件。不要让它太长。重点关注项目独有的内容,而不是通用的 Python 最佳实践。
您的 AI 指导方针应明确说明:
- 项目结构以及不同类型的代码应放在何处
- 在常见任务中使用哪些库
- 应遵循的具体模式(指向示例文件)
- 明确禁止的模式
- 测试要求
这是一个 AGENTS.md 文件的示例:
# 项目指导方针 ## 结构 /src/api - FastAPI 路由 /src/services - 业务逻辑 /src/models - SQLAlchemy 模型 /src/schemas - Pydantic 模型 ## 模式 - 所有服务都继承自 BaseService (参见 src/services/base.py) - 所有数据库访问都通过仓库模式 (参见 src/repositories/) - 对所有外部依赖使用依赖注入 ## 标准 - 所有函数都有类型提示 - 使用 Google 风格的文档字符串 - 函数行数少于 50 行 - 提交前运行 `mypy --strict` 和 `ruff check` ## 绝不 - 避免裸露的 except 子句 - 避免 type: ignore 注释 - 避免可变默认参数 - 避免全局状态
关键在于具体。不要只说“遵循最佳实践”。要指出确切的演示该模式的文件。不要只说“正确处理错误”;要展示您想要的错误处理模式。
# 编写指向示例的提示
通用提示会产生通用代码。引用您现有代码库的特定提示会产生更具可维护性的代码。
不要只问 AI “添加身份验证”,而是通过引用您的模式来引导其完成实现。这是一个指向示例的提示示例:
在 src/services/auth_service.py 中实现 JWT 身份验证。遵循 src/services/user_service.py 中 UserService 的相同结构。使用 bcrypt 进行密码哈希(已在 requirements.txt 中)。
在 src/api/dependencies.py 中添加身份验证依赖项,遵循 get_db 的模式。
在 src/schemas/auth.py 中创建 Pydantic 模式,类似于 user.py。
在 tests/test_auth_service.py 中添加 pytest 测试,使用 conftest.py 中的 fixture。
请注意,每条指令都指向一个现有的文件或模式。您不是在要求 AI 构建架构;您是在要求它将您的需求应用于新功能。
当 AI 生成代码时,根据您的模式对其进行审查。它是否使用了相同的依赖注入方法?它是否遵循相同的错误处理方式?它是否以相同的方式组织导入?如果不是,请指出差异并要求它与现有模式保持一致。
# 在实现前规划
AI 智能体移动速度很快,这有时可能会降低它们的实用性,如果速度是以牺牲结构为代价的话。在编写任何代码之前,请使用规划模式或要求提供实现计划。
规划步骤会迫使 AI 思考依赖关系和结构。它还为您提供了一个在实现之前发现架构问题的机会——例如循环依赖或冗余服务。
要求一个明确说明以下内容的计划:
- 将创建或修改哪些文件
- 组件之间存在哪些依赖关系
- 将遵循哪些现有模式
- 需要哪些测试
像审查设计文档一样审查此计划。确认 AI 理解您的项目结构。验证它是否使用了正确的库,并确认它没有重复已存在的功能。
如果计划看起来不错,就让 AI 执行。如果不是,请在编写任何代码之前修正计划。修复一个糟糕的计划比修复糟糕的代码要容易得多。
# 编写真正进行测试的测试
AI 在编写测试方面非常出色且速度极快。但是,除非您明确定义了“有用”的含义,否则 AI 在编写有用的测试方面效率不高。
AI 测试的默认行为是只测试“成功路径”(happy path),而别无其他。您会得到测试来验证一切顺利时代码是否有效,而这恰恰是您最不需要测试的时候。
明确指定您的测试要求。对于每个功能,要求进行以下测试:
- 成功路径测试
- 验证错误测试,检查无效输入时会发生什么
- 边缘情况测试,针对空值、None、边界条件等
- 错误处理测试,针对数据库故障、外部服务故障等
向 AI 指出您现有的测试文件作为示例。如果您已经有了良好的测试模式,AI 也会编写有用的测试。如果您还没有好的测试,请先自己编写一些。
# 系统地验证输出
AI 生成代码后,不要只检查它是否能运行。要通过清单对其进行检查。
您的验证清单应包括如下问题:
- 它是否通过了 mypy 严格模式检查
- 它是否遵循了现有代码的模式
- 所有函数是否都少于 50 行
- 测试是否涵盖了边缘情况和错误
- 所有函数是否都有类型提示
- 它是否正确使用了指定的库
尽可能自动化。设置 pre-commit 钩子来运行 mypy、Ruff 和 pytest。如果 AI 生成的代码未能通过这些检查,就不要提交。
对于无法自动化的部分,在审查了足够多的 AI 代码后,您会发现常见的反模式——例如,承担过多任务的函数、吞噬了异常的错误处理,或者与业务逻辑混在一起的验证逻辑。
# 实施实用的工作流程
现在让我们把到目前为止讨论的所有内容整合起来。
您开始一个新项目。您花时间设置结构、选择和安装库,并编写了几个示例功能。您创建了 CLAUDE.md 文件并写入了指导方针,还编写了具体的 Pydantic 模型。
现在您要求 AI 实现一个新功能。您写了一个详细的提示,指向您的示例。AI 生成一个计划。您审查并批准它。AI 编写代码。您运行类型检查和测试。一切都通过了。您根据您的模式审查了代码。它匹配。您提交。
对于一个手动需要一小时的功能,从提示到提交的总时间可能只需要大约 15 分钟。但更重要的是,您获得的“代码”更容易维护——它遵循您建立的模式。
下一个功能会更快,因为 AI 有更多的示例可以学习。代码会随着时间的推移变得更加一致,因为每个新功能都会强化现有的模式。
# 总结
随着 AI 编码工具被证明非常有用,您作为开发人员或数据专业人员的工作正在发生变化。您现在花费在编写代码上的时间更少了,而花费在以下方面的时间更多了:
- 设计系统和选择架构
- 创建模式的参考实现
- 编写约束和指导方针
- 审查 AI 输出并维护质量标准
最重要的技能不是写代码的速度。而是设计能够约束 AI 编写可维护代码的系统。是了解哪些实践可以扩展,哪些会产生技术债务。我希望这篇文章对您有所帮助,即使您选择的编程语言不是 Python。让我们知道您认为我们还能做些什么来保持 AI 生成的 Python 代码的可维护性。继续探索吧!
Bala Priya C 是来自印度的一名开发人员和技术作家。她喜欢在数学、编程、数据科学和内容创作的交叉点工作。她的兴趣和专业领域包括 DevOps、数据科学和自然语言处理。她喜欢阅读、写作、编码和咖啡!目前,她正致力于通过撰写教程、操作指南、观点文章等内容来学习并与开发者社区分享她的知识。Bala 还创作引人入胜的资源概览和编码教程。
🚀 想要体验更好更全面的AI调用?
欢迎使用青云聚合API,约为官网价格的十分之一,支持300+全球最新模型,以及全球各种生图生视频模型,无需翻墙高速稳定,文档丰富,小白也可以简单操作。
评论区