
最近折腾了一个 LLM(大型语言模型)驱动的代码重构工具 Morph,踩了几个坑,这篇把问题说清楚。
平时用 LLM 做代码重构,输出的是一个 diff,reviewer 只能一行行读、盲信模型。你根本没法知道模型是不是漏了某个引用、搞坏了 import,或者悄悄改了什么逻辑——除非一行行把代码看完。
Morph 换了个思路。它不要求 LLM 生成代码,而是让 LLM 用结构化的类型化操作计划来描述要改什么——比如 RenameSymbol、MoveFunction、ExtractModule 之类的。reviewer 几秒钟扫完十个结构化操作,就知道要改什么、为什么改、按什么顺序改。转换引擎会对真实代码库的依赖图验证计划,用 tree-sitter 做 AST(抽象语法树)操作原子化应用每个操作,运行测试套件确认正确性,然后把干净的变更提交 review。任何失败的转换都会自动回滚。
LLM 的活儿是声明意图,不是写代码。剩下的交给 Morph 的引擎。
当重构被表达为类型化计划时,每个操作在运行前都是可验证的。计划验证器检查文件存在性、符号存在性、依赖冲突和操作冲突——这些都是针对真实依赖图做的。转换器按依赖顺序应用操作。验证器每次应用后都跑 pytest——任何失败都会触发自动回滚。
源码生成没有任何这些保证。类型化计划有。
自然语言目标输入 LLM Planner,输出经过验证的 TransformationPlan。计划验证器基于 NetworkX 依赖图检查文件存在性、符号存在性、依赖冲突和操作冲突。转换器用 tree-sitter AST 操作按依赖顺序应用操作,同时先备份文件。验证器跑 pytest——任何失败触发自动回滚。干净的变更通过 GitPython 交给暂存管理器,并在报告中总结。
每个操作都是一个类型化的 Pydantic 模型。LLM 填充字段——Morph 验证并执行。
在验证任何计划之前,Morph 会用 tree-sitter 解析整个代码库,构建一个 NetworkX 依赖图。这个图用来:
这就是 Morph 敢在真实代码库上跑的原因——计划是在真实依赖结构上验证过的,动手之前就已经确保安全了。
每次非 dry-run 的应用调用都会在修改任何文件之前快照所有受影响的文件。如果 pytest 报告转换后失败,Morph 会自动从快照恢复。工作区始终保持在干净的已知良好状态。
用 OpenRouter 在 anthropic/claude-haiku-4-5 上跑了真实 dry-run——LLM 解析了自然语言重命名目标,在 5 秒内生成了经过验证的 RenameSymbol 计划。完整输出和复现步骤在 RESULTS.md 里。
pip install -e .
本地推理的话,装好 Ollama 然后拉取模型:
ollama pull gemma4:e4b
云端后端的话,配置对应的环境变量:
OPENROUTER_API_KEY - OpenRouter(推荐)
OPENAI_API_KEY - OpenAI
ANTHROPIC_API_KEY - Anthropic
用自然语言描述你想做什么,Morph 会自己推断出操作:
morph refactor --goal "rename calculate_total to compute_total" ./src
预览计划但不修改任何文件:
morph refactor --goal "extract validation logic into validate_input()" ./src --dry-run
生成并保存计划,方便执行前检查:
morph plan --goal "add type annotations to all functions in utils.py" ./src --output plan.json
应用已保存的计划:
morph refactor --plan plan.json ./src
验证代码库通过自己的测试套件:
morph verify ./src
生成上次运行的 Markdown 报告:
morph report ./src --format markdown --output REFACTOR_REPORT.md
Morph 可以对接任何 provider。OpenRouter 是推荐的起点——一个 API key 可以路由到下方所有模型,不需要单独注册账号。
Planner 使用 temperature=0.1——低随机性让结构化输出的结果更稳定。未知模型字符串会自动通过 OpenRouter 路由,不需要加 --backend 标志。
morph refactor --goal "..." PATH - 从目标生成计划并应用
morph refactor --plan FILE PATH - 应用之前保存的计划
morph refactor ... --dry-run - 显示计划但不修改文件
morph plan --goal "..." PATH - 仅生成并显示计划
morph verify PATH - 运行测试套件并报告通过/失败
morph report PATH - 生成上次运行的 Markdown/JSON 报告
常用标志:--model、--backend、--dry-run、--no-rollback、--output
克隆项目并以可编辑模式安装(包含开发依赖):
git clone https://github.com/dakshjain-1616/morph
cd morph
pip install -e ".[dev]"
运行完整测试套件:
pytest tests/ -v
代码检查和类型检查:
ruff check morph/ && mypy morph/
这个项目是用 NEO 搭的。(NEO 是一个完全自主的 AI 工程代理,能写代码、做 AI/ML 任务,包括模型评测、提示词优化和端到端 AI 流水线开发。)
需求是做一个重构 CLI,核心是让 LLM 用结构化类型化计划描述意图,而不是生成原始代码;需要 AST 级别的执行、依赖图验证、测试失败自动回滚、支持多 LLM 后端。NEO 完整实现了:LLM Planner 生成类型化 TransformationPlan 输出(temperature=0.1)、7 个类型化 Pydantic 操作模型、Plan Validator 基于 NetworkX 图检查文件存在性/符号存在性/依赖冲突、Transformer 用 tree-sitter AST 操作按依赖顺序应用(带文件备份)、Verifier 跑 pytest 失败自动快照回滚、Staging Manager(GitPython)、报告生成器,以及包含全部 6 条命令和关键标志的完整 CLI。
用它安全地重构生产代码库。
不要让 LLM 重写文件,用自然语言描述重构目标。Morph 会基于真实依赖图验证计划,原子化应用,测试失败自动回滚。dry-run 模式让你在动手之前精确看到会发生什么。
用保存的计划工作流做团队 review。
跑 morph plan --goal "..." --output plan.json 生成结构化计划但不应用。把 JSON 发给团队,执行前 review。reviewer 看到的是十个类型化操作,不是一堆原始 diff——review 更快、更好判断。
在 CI/CD 流水线里用它做重构步骤。
morph verify PATH 跑测试套件并返回通过/失败的退出码,可以作为 CI 步骤组合使用。配合 morph refactor 和 --dry-run,可以搭出一个流水线:提议、review、应用重构,每个阶段都有自动化测试验证。
扩展它,加入更多操作类型。
每个操作都是 operations 层里的类型化 Pydantic 模型。新操作遵循相同模式:定义 Pydantic 模型、实现转换器逻辑、注册。LLM Planner、Plan Validator 和 CLI 会自动识别它。
Morph 把重构从"代码生成"变成了"意图声明"。LLM 用结构化、可验证的计划描述要改什么。引擎做机械性的工作。测试确认正确性。结果是:运行前可审计、运行后可验证、如果搞砸了自动可逆的重构。
代码在这里:https://github.com/dakshjain-1616/Morph