AI 生成注释的策略
什么时候需要注释?
一个常见的误区是"注释越多越好"。实际上,好的代码应该是自解释的,注释应该解释为什么(Why),而不是是什么(What)。
需要注释的情况
- 复杂的业务逻辑(解释业务规则来源)
- 非直觉的算法(解释为什么选择这个方法)
- 临时的 workaround(说明原因和何时可以删除)
- 公共 API 函数(所有参数和返回值)
不需要注释的情况
- 自解释的代码(
i++不需要// i 加一) - 可以用更好的命名替代的注释
- 重复代码语义的注释
- 过时的注释(比没有注释更危险)
函数文档注释自动生成
# 给 AI 的提示:为以下 Python 函数生成 Google Style docstring
async def send_notification(
user_ids: list[int],
message: str,
channel: str = "email",
priority: int = 5
) -> dict[str, int]:
# AI 生成的 Google Style docstring
"""向指定用户发送通知。
通过配置的通知渠道(邮件/短信/Push)向用户列表发送通知消息。
会自动过滤无效的用户 ID 和退订用户。
Args:
user_ids: 接收通知的用户 ID 列表。重复的 ID 只发送一次。
message: 通知内容,支持 Markdown 格式(仅在 email 渠道有效)。
长度限制:email 不超过 10000 字符,sms 不超过 160 字符。
channel: 通知渠道,支持 'email'、'sms'、'push'。
默认为 'email'。
priority: 发送优先级,1(最高)到 10(最低),默认 5。
高优先级(1-3)会绕过频率限制直接发送。
Returns:
发送结果统计字典:
{
'sent': 成功发送数量,
'failed': 发送失败数量,
'filtered': 被过滤数量(无效ID/退订)
}
Raises:
ValueError: 当 channel 不是支持的渠道类型时。
ValueError: 当 priority 不在 1-10 范围内时。
RateLimitError: 当发送频率超过限制时(仅低优先级触发)。
Example:
>>> result = await send_notification(
... user_ids=[1, 2, 3],
... message="您的订单已发货",
... channel="sms"
... )
>>> print(result)
{'sent': 3, 'failed': 0, 'filtered': 0}
"""
TypeScript/JavaScript JSDoc 生成
// AI 生成的 JSDoc
/**
* 计算购物车的总价,包含税费和折扣。
*
* @param items - 购物车商品列表
* @param coupon - 优惠券对象,可选
* @param taxRate - 税率(0-1 之间的小数),默认 0.1(10%)
* @returns 价格计算结果对象
*
* @example
* ```typescript
* const items = [
* { id: 1, price: 29.99, quantity: 2 },
* { id: 2, price: 9.99, quantity: 1 }
* ];
* const result = calculateCartTotal(items, null, 0.08);
* console.log(result.total); // 75.87
* ```
*
* @throws {Error} 当 taxRate 不在 0-1 范围内时
*/
function calculateCartTotal(
items: CartItem[],
coupon: Coupon | null,
taxRate: number = 0.1
): PriceResult { ... }
Rust Doc Comments 生成
/// 解析 TOML 配置文件并返回强类型配置结构。
///
/// 会按照以下优先级合并配置(高优先级覆盖低优先级):
/// 1. 环境变量(前缀 `APP_`)
/// 2. 用户配置文件(`~/.config/app/config.toml`)
/// 3. 默认配置
///
/// # Arguments
///
/// * `path` - 配置文件路径,如果文件不存在则使用默认配置
///
/// # Returns
///
/// 返回 [`AppConfig`] 结构,所有字段均已填充(有默认值保底)
///
/// # Errors
///
/// - [`ConfigError::ParseError`] - TOML 语法错误
/// - [`ConfigError::ValidationError`] - 配置值不合法(如端口超出范围)
///
/// # Examples
///
/// ```rust
/// use myapp::config::load_config;
///
/// let config = load_config("config.toml")?;
/// assert_eq!(config.server.port, 8080);
/// ```
pub fn load_config(path: &Path) -> Result<AppConfig, ConfigError> {
todo!()
}
README 自动生成
README 生成 Prompt 模板
请根据以下项目信息生成一个专业的 README.md。
项目基本信息:
- 项目名称:{project_name}
- 一句话描述:{description}
- 技术栈:{tech_stack}
请生成包含以下部分的 README:
1. **项目标题和徽章**(build status, coverage, license, version)
2. **简介**(2-3 段,说明项目解决什么问题,主要特性)
3. **快速开始**(5分钟内能跑起来的最短步骤)
4. **安装**(详细的安装步骤,包括依赖)
5. **配置**(重要的配置项说明,.env 示例)
6. **使用方法**(基本使用示例,配代码块)
7. **API 文档**(如果是库/服务,列出主要接口)
8. **开发指南**(如何在本地开发、运行测试)
9. **部署**(如何部署到生产环境)
10. **贡献指南**(简单说明 PR 流程)
11. **License**
格式要求:
- 使用清晰的标题层次
- 代码示例使用代码块并标注语言
- 关键命令用代码格式
- 中文文档(除了技术术语)
项目目录结构:
{directory_tree}
package.json / pyproject.toml 内容:
{config_file}
自动化 README 更新脚本
#!/usr/bin/env python3
# scripts/update_readme.py
# 在 CI/CD 中运行,自动更新 README 中的 API 文档部分
import subprocess
import anthropic
import re
def get_api_changes() -> str:
"""获取最近的 API 相关变更"""
result = subprocess.run(
["git", "diff", "HEAD~1", "HEAD", "--", "src/api/"],
capture_output=True, text=True
)
return result.stdout
def update_readme_api_section(changes: str) -> None:
client = anthropic.Anthropic()
with open("README.md", "r") as f:
readme = f.read()
response = client.messages.create(
model="claude-3-5-haiku-20241022",
max_tokens=2048,
messages=[{
"role": "user",
"content": f"""
根据以下 API 代码变更,更新 README.md 中的 API 文档部分。
只更新 ## API 文档 和 ## 快速开始 部分。
代码变更:
{changes}
当前 README:
{readme}
请输出完整的更新后的 README.md 内容。
"""
}]
)
with open("README.md", "w") as f:
f.write(response.content[0].text)
if __name__ == "__main__":
changes = get_api_changes()
if changes:
update_readme_api_section(changes)
Changelog 自动生成
从 Git Log 生成 Changelog
# 获取上一个版本以来的 commit 历史
git log v1.2.0..HEAD --pretty=format:"%h %s (%an)" --no-merges
# 输出示例:
# a3f8b21 feat: add user avatar upload endpoint (Alice)
# 8d2c1b3 fix: prevent duplicate email registration (Bob)
# 1e9a4f5 refactor: extract payment service (Alice)
# 7c3b2d0 docs: update API documentation (Carol)
# 给 AI 的 Changelog 生成 Prompt
请根据以下 git commit 历史生成用户友好的 Changelog。
版本号:{new_version}
发布日期:{release_date}
上一版本:{previous_version}
Commit 历史:
{git_log}
生成规则:
1. 按类型分组:Breaking Changes、New Features、Bug Fixes、Performance、Refactoring、Documentation
2. Breaking Changes 必须放在最前面并用警告标记
3. 使用用户视角的语言("现在可以上传头像"而非"添加了 avatar upload endpoint")
4. 过滤掉纯内部重构(用户不关心的变更)
5. 遵循 Keep a Changelog 格式(https://keepachangelog.com)
输出格式:Markdown
OpenAPI Spec 文档生成与同步
从代码自动生成 OpenAPI
# FastAPI 自动生成 OpenAPI Spec
# FastAPI 本身支持自动生成,但我们可以用 AI 增强注释质量
from fastapi import FastAPI
from pydantic import BaseModel, Field
app = FastAPI(
title="My API",
description="""
## 概述
这是 MyApp 的后端 API 文档。
## 认证
所有端点(除了 `/auth/login`)都需要在 Header 中提供 Bearer Token:
```
Authorization: Bearer {your_token}
```
## 错误码
| 状态码 | 含义 |
|--------|------|
| 400 | 请求参数错误 |
| 401 | 未认证或 Token 过期 |
| 403 | 权限不足 |
| 404 | 资源不存在 |
| 429 | 请求频率超限 |
""",
version="1.0.0"
)
class UserCreateRequest(BaseModel):
email: str = Field(
...,
description="用户邮箱,注册后不可修改",
example="user@example.com",
pattern=r"^[^@]+@[^@]+\.[^@]+$"
)
name: str = Field(
...,
min_length=1,
max_length=50,
description="显示名称,长度 1-50 字符",
example="张三"
)
文档与代码同步的最佳实践
最糟糕的文档是过时的文档——它比没有文档更危险,因为它会误导用户。建议在 CI/CD 流程中添加文档同步检查:每次 PR 合并时,自动更新 API 文档,并用 AI 检查 README 中的示例代码是否仍然有效。
文档自动化的深层原则
文档腐化(Documentation Rot)的根本原因
文档变得过时,几乎是每个项目的必然问题。理解根本原因才能设计正确的防腐策略:
文档和代码的"双写"成本
修改函数时,开发者需要同时更新文档字符串、README 示例、API 文档——额外的工作很容易被"先跑通功能"的优先级压后。AI 能将文档生成自动化,但更重要的是将"代码改了→文档自动提醒更新"纳入工作流(如 CI 检查 docstring 与函数签名的一致性)。
隐式知识未文档化
开发者知道"这个函数不能并发调用"、"传入的 ID 必须先被 validate_id() 检查过",但这些隐式约束往往不写在文档里,因为"自己知道"。AI 生成文档时,应明确要求 AI 检查"是否有任何调用前置条件或副作用应该记录",将隐式知识显式化。
文档粒度不当
为每行代码写注释(过细)和只有一个顶层 README(过粗)都是文档问题。正确粒度:每个公共函数有 docstring(谁调用谁需要知道),每个模块有模块级注释(描述这个模块的职责),项目有 README(快速上手),架构有 ADR(Architecture Decision Record,记录重要决策的背景和理由)。
ADR(架构决策记录)与 AI 的结合
架构决策记录(ADR)是文档化"为什么做了这个技术决策"的最佳实践。AI 可以帮助起草 ADR:
# ADR-003:选择 PostgreSQL 而非 MongoDB
## 状态
已接受
## 背景
系统需要存储用户订单数据。订单数据结构相对固定(有明确的关系),但未来可能增加灵活的扩展字段。
## 决策
使用 PostgreSQL + JSONB 字段。主要结构使用关系表,扩展属性存入 JSONB 列。
## 原因
- 订单数据有严格的 ACID 事务需求(不能部分写入)
- 现有团队的 SQL 经验更丰富
- PostgreSQL 的 JSONB 提供了足够的灵活性
- 避免引入新的基础设施(当前已有 PostgreSQL 实例)
## 后果
- 正面:事务安全、运维成本低、学习成本低
- 负面:扩展属性的查询性能不如 MongoDB;如果数据结构变化频繁需要数据库迁移
- 中性:需要注意 JSONB 列不能建立标准索引(需要 GIN 索引)
让 AI 帮助生成 ADR 的正确方式
向 AI 提供:你们讨论的技术选型背景、考虑过的备选方案、最终选择的理由(口语描述即可)。AI 帮你整理成标准 ADR 格式。关键:ADR 中的"原因"和"后果"必须是你真实思考的结果,不能让 AI 编造——否则 ADR 就失去了"记录真实决策依据"的价值。
文档自动化工具链
pdoc3 / Sphinx(Python)
从代码中的 docstring 自动生成 HTML 文档。pdoc3 更简单(零配置),Sphinx 更强大(支持交叉引用、自定义主题)。配合 AI 生成的 docstring,几乎可以实现"代码即文档"。
TypeDoc(TypeScript)
从 TypeScript 源码的 JSDoc 注释生成文档。TypeScript 的类型信息会自动反映在文档中(参数类型、返回类型无需重复说明)。
Storybook(UI 组件文档)
React/Vue/Svelte 组件的交互式文档系统。AI 可以帮助生成 Story 文件(组件的各种使用场景展示),让 UI 文档和组件代码保持同步。
swagger-autogen / FastAPI 自动文档
FastAPI 基于 Python 类型注解自动生成 OpenAPI 文档,是"代码即文档"的最佳实践。AI 生成的 Pydantic Model 和路由函数,只要类型注解完整,API 文档就自动完整。
第8章小结
- 注释应该解释"为什么"而不是"是什么":自解释的代码不需要注释;业务规则、反直觉的算法选择、临时 workaround 必须注释
- 先写函数签名+文档字符串,再让 AI 生成 docstring 的详细内容——这比让 AI 从零开始写更准确
- FastAPI + Pydantic 是"代码即文档"的最佳实践:类型注解完整 → API 文档自动完整;AI 生成代码时应指定补充所有
description和example字段 - ADR(架构决策记录)是最被忽视但价值最高的文档形式:记录"为什么"比记录"是什么"价值高 10 倍;AI 帮整理格式,人类提供真实决策依据
- 文档腐化的核心原因是"双写成本";解决方案是将文档检查纳入 CI/CD,代码改变时自动提醒更新文档
- 隐式约束显式化:让 AI 生成文档时主动询问"是否有调用前置条件、并发限制、副作用需要记录"