AI CLI工具项目复盘:从Python脚本到跨平台分发包的产品化之路
一、从"给我写个脚本"到"可以公开发布"
一切从一句"帮我写个脚本"开始:每天需要把本地Markdown文件中的Mermaid图表自动渲染为PNG并嵌入文档。Python脚本15分钟写完,能用。但很快需求扩展——需要支持批量处理、自定义主题、导出PDF。脚本从50行膨胀到400行,开始在同事之间传阅。某天有人问:"这玩意能不能brew install?"
这句话开启了从脚本到产品的产品化过程。技术本质没变——调用mermaid-cli渲染图表。但用户体验的期望从"我能跑"变成了"我能install"、"我能配置"、"我能CI集成"。
二、从Python脚本到独立二进制
第一步:PyPI发布 —— 让Python用户能装
将脚本改造成标准的Python包结构:
mmd-render/
setup.py
mmd_render/
__init__.py
cli.py
renderer.py
themes/
README.md
# setup.py
from setuptools import setup, find_packages
setup(
name="mmd-render",
version="0.1.0",
packages=find_packages(),
install_requires=["click", "playwright"],
entry_points={
"console_scripts": [
"mmd-render=mmd_render.cli:main",
],
},
python_requires=">=3.9",
)
发布到PyPI后,用户只需pip install mmd-render即可使用。但问题随之而来:有些用户没有Python环境,或Python版本不对(系统自带Python 3.7,需要3.9+)。"这工具很好,但我装不上"——这是用户的原话。
第二步:PyInstaller打包 —— 消除Python依赖
PyInstaller能将Python脚本打包为独立可执行文件(包含Python解释器和所有依赖):
pip install pyinstaller
pyinstaller –onefile –name mmd-render cli.py
生成的单个二进制文件约25MB(主要是Playwright的浏览器内核),但不需要任何Python环境。在GitHub Release中为三个平台提供下载:
- mmd-render-darwin-amd64
- mmd-render-darwin-arm64
- mmd-render-linux-amd64
第三步:包管理器分发 —— 消除"下载zip"的摩擦
"curl下载→chmod→移动到PATH"的三步安装在开发者社区是不容忽视的摩擦。接入包管理器:
# Homebrew Formula
class MmdRender < Formula
desc "Render Mermaid diagrams from Markdown files"
homepage "https://github.com/user/mmd-render"
url "https://github.com/user/mmd-render/releases/download/v0.2.0/mmd-render-darwin-arm64"
sha256 "abc123…"
version "0.2.0"
def install
bin.install "mmd-render-darwin-arm64" => "mmd-render"
end
test do
system "#{bin}/mmd-render", "–version"
end
end
brew install mmd-render——一行命令搞定安装。安装量从PyPI的约200次/月增长到brew+PyPI合计约1200次/月。
三、CLI的用户体验设计
命令设计的渐进式暴露:
# 简单路径:零配置即可用
mmd-render docs/
# 中级路径:常用参数
mmd-render docs/ –theme dark –output-dir rendered/ –watch
# 高级路径:配置文件
mmd-render docs/ –config mmd-render.yml
配置文件支持(.mmd-render.yml或mmd-render.yml):
theme: dark
output_format: png
scale: 2
watch: true
# CI模式——非交互,失败即退出
ci: false
# 排除模式
exclude:
– "**/node_modules/**"
– "**/.git/**"
错误信息的友好化:
# 用户犯错时,不报Python Traceback,而是给出清晰的诊断
def validate_input(path: str):
if not os.path.exists(path):
click.echo(f"错误: 路径 '{path}' 不存在", err=True)
click.echo("提示: 检查路径是否正确,或使用 –help 查看用法")
sys.exit(1)
mermaid_files = glob.glob(os.path.join(path, "**/*.md"), recursive=True)
if not mermaid_files:
click.echo(f"警告: 在 '{path}' 中未找到Markdown文件", err=True)
sys.exit(0)
四、产品化过程中的坑
坑1:Playwright依赖的大小问题。 mermaid-cli依赖Playwright的Chromium内核(约150MB)。PyInstaller打包后二进制从3MB膨胀到25MB,GitHub Release的单文件限制(2GB)虽然没触及,但用户下载体验明显变差。方案:将Chromium作为外部依赖——如果系统已安装Chromium则复用,否则提示安装。
坑2:Homebrew Formula的审核流程。 提交Homebrew Formula需要满足严格的审核标准:必须有test do块、依赖声明完整、无网络请求、无sudo。第一次提交因为缺少test do被拒。
坑3:版本管理的语义化。 早期版本号随意(0.1.2→0.1.3a→0.1.3b),导致用户和CI脚本难以追踪。引入SemVer + 自动发布:Git Tag → GitHub Actions → 构建→ PyPI + GitHub Release。
五、总结
从脚本到产品的产品化过程,核心经验:
- 包管理器分发(brew/pip/npm)是CLI工具分发的最佳方式——"一行命令安装"是准入门槛
- 独立二进制消除了Python版本依赖——打包后的25MB对用户的便利性是值得的
- CLI设计遵循"渐进式暴露"——零配置可用,高级功能可配,CI模式可脚本化
- 错误信息不要暴露Traceback——用户要的是诊断,不是调试信息
- SemVer + 自动发布是可持续维护的基础
最大的教训:从脚本到产品最大的工作量不在代码(400行Python扩展到了约800行),而在分发。PyPI搭建、Homebrew Formula编写、GitHub Actions CI配置、多平台测试——这些"非代码工作"约占总工期的60%。如果知道最终要公开发布,应该从一开始就按标准Python包组织代码,避免后续重构。

