3.2 命令行工具(CLI)使用


CLI 是给人和脚本之间的契约接口

在实践的第二步,我们把「建索引」这种重复动作固化成命令行。好的 CLI 不该只是懒人福音,而是让流程可被脚本编排、可被复现。

下面用 argparse 搭一个最小可用的 LEANN CLI 骨架,覆盖 buildquery 两个子命令。注意我们强制要求 --dim 与嵌入一致,否则索引会静默错乱。

import argparse, json def build(args): # 读文档、切 chunk、嵌入、建索引,落盘到 args.out print(f'从 {args.src} 建索引 -> {args.out} dim={args.dim}') def query(args): print(f'在 {args.index} 上查: {args.text} 取前 {args.topk}') parser = argparse.ArgumentParser(prog='leann') sub = parser.add_subparsers(dest='cmd') pb = sub.add_parser('build'); pb.add_argument('--src'); pb.add_argument('--out'); pb.add_argument('--dim', type=int, required=True) pq = sub.add_parser('query'); pq.add_argument('--index'); pq.add_argument('--text'); pq.add_argument('--topk', type=int, default=5) # 演示:解析一条命令 ns = parser.parse_args('build --src docs/ --out idx/ --dim 64'.split()) getattr(__import__('__main__'), 'build')(ns)

CLI 的价值在于可编排。下面给出一个 shell 风格的执行序列(用 Python 描述),把「建索引→自检→查询」串成一条流水线,失败即停。

STEPS = [ 'leann build --src docs/ --out idx/ --dim 64', 'leann check --index idx/', 'leann query --index idx/ --text "退货政策" --topk 5', ] def run_pipeline(steps): for s in steps: print('执行:', s) # 真实环境用 subprocess.run,这里只演示编排与短路 if s.startswith('leann check') and False: return '自检失败,流水线终止' return '流水线完成' print(run_pipeline(STEPS))

案例:手动建索引漏了 dim 参数

  • 背景:同事凭记忆手敲命令,忘了 --dim 64,索引用默认 128 建成。
  • 操作:查询时向量维度不匹配直接报错;若没报错(旧版容忍),召回会全错。
  • 结果:把建索引写进 CLI 并 required=True,从机制上杜绝漏参。
  • 解读:CLI 把「容易忘的参数」变成必填,把人的疏忽转成机器的报错。
  • 变式:进一步把常用参数固化进配置文件,CLI 只留覆盖项。

CLI 不是一次写完就不动的。随场景变多,你会想加子命令。下面给出可扩展的子命令注册模式,新命令只需挂进一个字典,不必改主解析逻辑。

COMMANDS = {} def cmd(name): def deco(fn): COMMANDS[name] = fn return fn return deco @cmd('stats') def stats(args): print('索引统计:', args.index) @cmd('export') def export(args): print('导出:', args.index, '->', args.out) def dispatch(name, args): if name not in COMMANDS: raise SystemExit(f'未知命令: {name}') return COMMANDS[name](args) print('已注册:', list(COMMANDS))

这种注册式写法让 CLI 像插件一样生长。我们建议每条命令都返回明确退出码,脚本编排时才能据此判断是否短路,和 3.1 的自检、5.2 的监控串成一条「失败可见」的链路。

CLI 还有一个隐性价值:它把「操作步骤」变成了「可审计的记录」。手动操作靠人记,错了无从复盘;CLI 命令写进脚本,哪天出问题,翻脚本就能还原当时做了什么。在受监管的行业里,这种可复现性本身就是合规要求,不止是工程便利。

我们也提醒一个误区:CLI 不是越多命令越好。命令膨胀会带来隐藏的维护成本和学习成本。我们主张每个命令对应一个明确的高频动作,低频或一次性的操作留给 Python API 或脚本,不让 CLI 变成瑞士军刀式的大杂烩。判断标准很简单:这个动作会不会被脚本反复调用?会,就进 CLI;不会,就别加。

该进 CLI 留给 API/脚本
建索引、查索引 一次性迁移
健康检查 调试探针

CLI 的设计还影响团队协作的隐性成本。当所有环境操作都收敛到几条命令,新人不用读源码就能完成日常任务,资深的人也不用被反复打断去教同样的事。我们把这种「把知识固化进工具」的做法,视为团队规模化的前提。很多项目死在三人以上就乱,根因就是操作依赖口口相传,而 CLI 是把口口相传变成可执行文件的最直接手段。

当然,CLI 也要写帮助文本。每条命令的 help 就是它的最小文档,省略 help 等于把使用门槛又悄悄加回去。我们主张 help 里写清「做什么、要什么参数、产出什么」,而不是只列参数名。命令名也要克制,别用缩写让人猜,build 就是 build,可读性在每天被打字的地方最值钱。

把日常操作收敛成命令,本质上是在给团队买「不被打断」的自由,这笔账长期看远比省下的几行脚本值钱。

本节可考核点:能解释 CLI 相对手动操作的工程价值,并说明「必填参数」如何防止维度不匹配这类静默错误。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U