Claude Code + Python 自动生成设计文档:让 AI 替你还“意图债“(附完整代码)
TL;DRAddy Osmani 提出了第三种技术债意图债Intent Debt——代码能跑但没人知道当初为什么这么写。AI 写代码的速度越快意图债累积的速度也越快。本文用 Claude Code 一个 80 行的 Python 脚本搭建一套自动生成架构决策记录ADR和设计文档的流水线——每次提交代码自动附带一份为什么这么做的说明从源头消除意图债。1. 什么是意图债Addy Osmani 在 2026 年 6 月 5 日的博文《The Intent Debt》中定义了三种技术债代码债Technical Debt代码写得烂难以维护。认知债Cognitive Debt代码逻辑绕新人看不懂。意图债Intent Debt代码能跑但当初的设计意图、约束条件、被否决的替代方案全部丢失了。三种债里意图债是最隐蔽的。代码债能靠 lint、测试、重构来还认知债能靠重命名、加注释来缓解。但意图债——那些为什么选了 Redis 而不是 PostgreSQL 做缓存、“为什么这个 API 设计成异步的”、“当初为什么不直接用 ORM”——这些信息一旦丢失后来的人只能靠猜。AI 写代码让这个问题雪上加霜。当 Claude Code 或 Copilot 替你生成了 200 行代码你 review 通过就合入了但生成这段代码时做的架构取舍、隐含假设全部没有记录下来。三个月后连你自己都不知道这段代码为什么长这样。解决方案不是让 AI 写得更慢而是让 AI 同时写一份设计文档。2. 核心思路每次 commit 自动产出 ADRADRArchitecture Decision Record架构决策记录是一种轻量级的设计文档格式只有四个字段# 标题做了什么事 ## 背景当时的情况是什么 ## 决策选了什么方案为什么 ## 后果这个决策会带来什么影响我们的方案用 Git pre-commit hook 触发 Claude Code自动分析即将提交的 diff生成对应的 ADR 草稿你 review 后一起合入仓库。3. 环境准备# 确保安装了 Claude Codenpminstall-ganthropic-ai/claude-code# 创建项目mkdirintent-debt-freecdintent-debt-freegitinitmkdir-pdocs/adr scripts4. 核心脚本创建scripts/generate-adr.py#!/usr/bin/env python3 自动生成架构决策记录ADR 用法: python scripts/generate-adr.py 在 git pre-commit hook 中调用自动分析 diff 并生成 ADR 草稿 importsubprocessimportjsonimportosimportsysfromdatetimeimportdatetimefrompathlibimportPath REPO_ROOTPath(__file__).resolve().parent.parent ADR_DIRREPO_ROOT/docs/adrdefget_git_diff():获取暂存区中代码文件的 difftry:resultsubprocess.run([git,diff,--cached,--diff-filterAM,--,*.py,*.ts,*.tsx,*.js,*.go,*.rs,*.java,*.rb,*.yaml,*.yml,*.json,*.sql],capture_outputTrue,textTrue,cwdREPO_ROOT)returnresult.stdout.strip()exceptExceptionase:print(f获取 diff 失败:{e},filesys.stderr)returndefget_commit_context():获取当前分支名和最近的 commit 信息作为上下文try:branchsubprocess.run([git,rev-parse,--abbrev-ref,HEAD],capture_outputTrue,textTrue,cwdREPO_ROOT).stdout.strip()recent_commitssubprocess.run([git,log,--oneline,-5],capture_outputTrue,textTrue,cwdREPO_ROOT).stdout.strip()returnf分支:{branch}\n最近提交:\n{recent_commits}exceptException:return无上下文信息defgenerate_adr_with_claude(diff_text,context):调用 Claude Code 分析 diff 并生成 ADRifnotdiff_text:print(没有代码变更跳过 ADR 生成)returnNonepromptf你是一个技术文档工程师。分析下面的代码变更生成一份架构决策记录ADR。 格式要求中文简洁每个字段不超过5行标题[一句话概括这次变更做了什么]背景[变更前的状态是什么触发了这次变更的需求或问题是什么]决策[选了什么方案为什么选这个而不是别的简要说明被否决的替代方案]后果[积极影响解决了什么问题][需要注意引入了什么新的约束或风险]上下文信息 {context} 代码变更git diff {diff_text} 只输出 ADR 内容不要加额外的解释。 try: result subprocess.run( [claude, --print, --output-format, text, prompt], capture_outputTrue, textTrue, cwdREPO_ROOT, timeout120 # 2 分钟超时 ) return result.stdout.strip() except subprocess.TimeoutExpired: print(Claude Code 超时diff 可能太大尝试缩小提交范围, filesys.stderr) return None except Exception as e: print(fClaude Code 调用失败: {e}, filesys.stderr) return None def save_adr(adr_content): 保存 ADR 到文件 ADR_DIR.mkdir(parentsTrue, exist_okTrue) date_str datetime.now().strftime(%Y-%m-%d) # 从标题提取文件名 first_line adr_content.strip().split(\n)[0] slug first_line.replace(# 标题, ).replace(# , ).strip() slug .join(c if c.isalnum() or c in _- else for c in slug) slug slug.lower().replace( , -)[:60] filename f{date_str}-{slug}.md filepath ADR_DIR / filename with open(filepath, w, encodingutf-8) as f: f.write(f# {first_line.replace(# , ).replace(#, ).strip()}\n\n) f.write(f日期: {date_str}\n) f.write(f状态: 提议中\n\n) f.write(adr_content) print(fADR 已生成: {filepath}) return str(filepath) if __name__ __main__: diff get_git_diff() context get_commit_context() adr generate_adr_with_claude(diff, context) if adr: path save_adr(adr) print(f\n请 review 后决定是否合入{path}) print(提示如果 ADR 内容不准确可以直接编辑该文件。) else: print(未生成 ADR无变更或调用失败)5. 接入 Git Hook创建.git/hooks/pre-commit或使用 husky 等工具管理#!/bin/bash# 每次 commit 前自动生成 ADRecho分析变更并生成架构决策记录...python3 scripts/generate-adr.py# 如果 ADR 文件被创建自动加入暂存区ADR_FILE$(ls-tdocs/adr/*.md2/dev/null|head-1)if[-n$ADR_FILE];thengitadd$ADR_FILEechoADR 已暂存:$ADR_FILEfi# 不阻塞提交——ADR 是辅助性的不通过就阻止提交会破坏工作流exit0chmodx .git/hooks/pre-commit6. 更进一步用 CLAUDE.md 做项目级意图基线除了每次提交自动生成 ADR还有一个更治本的做法维护一份项目级的CLAUDE.md或AGENTS.md作为所有 AI 工具共享的意图基线。创建CLAUDE.md# 项目意图基线 ## 架构决策 - 选择 FastAPI 而非 Django团队对异步有强需求Django 的 async 支持当时还不成熟 - Redis 做缓存层访问频率远高于数据变更频率用 Redis 比数据库物化视图更灵活 - 放弃微服务团队 3 人微服务的运维成本远超收益 ## 技术约束 - Python 版本≥ 3.11因为用了 match-case 语法 - 部署环境AWS ECS Fargate不能用需要持久化本地存储的方案 - 第三方 API 限速OpenAI API 每分钟 500 次所有批量操作必须有 rate limiter ## 已否决的方案 - 不用 Celery太重用 Redis Queue (RQ) 足够 - 不用 Kubernetes团队没有 K8s 运维经验ECS 够用这份CLAUDE.md有两个作用一是每次 Claude Code 启动时自动加载确保它生成代码时尊重已有的架构决策二是它本身就是一份意图文档新成员入职第一件事就是读它。7. 踩坑与最佳实践坑 1diff 太大导致 ADR 质量下降一次提交改了 20 个文件、500 行Claude Code 很难生成精准的 ADR。解决方案养成小步提交的习惯。如果你在用 Claude Code 写代码可以要求它每完成一个独立功能就提示我 commit。坑 2ADR 文件越来越多管理混乱建议建一个docs/adr/INDEX.md按时间倒序列出所有 ADR并给每份 ADR 加状态标签提议中 / 已采纳 / 已废弃。可以用一个简单脚本自动更新索引。坑 3不要用 ADR 替代真正的设计讨论ADR 是记录工具不是决策工具。如果一个架构决策涉及多个团队或需要权衡先在文档或会议上讨论清楚再用 ADR 记录结论不要反着来。坑 4CI 成本每次 commit 都调用 Claude Code 会增加 API 开销。如果你的提交频率很高一天几十次建议改成只在 push 时生成用 pre-push hook或者在 CI 中只在合并到 main 分支时触发。8. 效果检验搭好这套系统一个月后你应该能看到这些变化每个 PR 都附带一份 ADRreviewer 能快速理解为什么这么改新人入职时读docs/adr/目录就能了解项目的关键架构决策当你半年后回来看一段代码不需要在 Slack 历史里翻当时的讨论——ADR 文件就在代码旁边意图债不会因为你注意了就消失。它需要系统化的机制来对抗。这套脚本的价值不是 AI 写得有多好而是它让你每次提交都被提醒“这段代码的意图我记下来了吗”参考资料Addy Osmani - The Intent Debt (2026-06-05)Claude Code 官方文档ADR GitHub 组织 - 架构决策记录最佳实践