UI.Vision RPA 这个名字,我第一次看到的时候以为是又一个套壳的浏览器小插件,点开装上之后才发现,它其实是一套把“网页操作、图像识别、键鼠模拟”装进同一个扩展里的自动化工具箱。它原来的名字叫 Kantu,核心玩法是用一张三列的表格来写脚本——命令、目标、值,一行就是一步,能点按钮、填表单、翻页抓数据、按图找位置、模拟桌面上的鼠标键盘,还能被外部程序用命令行唤起来跑。它解决的问题很实在:那些每天重复几十遍、逻辑简单但量大、又懒得每次都找人写的网页操作,全都归它管。适合谁?做运营的要天天批量填后台,做测试的要跑冒烟流程,做数据整理的要定时扒页面上的数字,甚至普通办公场景里那种“每月固定去某个系统导一份表”的活,都能落在它身上。零编程基础也能在半小时内出第一个能用的脚本,懂点 JavaScript 的话上限还能再拔高一截。
1. 先想清楚:这类工具真正补的是哪块缺口
1.1 从“能不能自动”到“值不值得自动”
我见过太多人一上来就问“这个能不能自动登录后台批量提交”,答案是能,但真正该先问的是另一句:这条流程一个月跑几次,一次多少分钟,改一次要多久。如果一个月只跑一次、一次五分钟,你花两小时去调脚本,这笔账是亏的;但如果是每天跑、一次四十分钟,哪怕调试花一整天也值。自动化工具的价值从来不在“酷”,而在“把人的注意力从低价值动作里赎回来”。
所以选型的第一步不是看功能列表,是先给手上的活分个类。我把重复劳动大致分三层:第一层是纯网页内的动作,比如登录、点菜单、填字段、翻页、导出——这类用浏览器自动化最省事;第二层是网页加本地文件的组合,比如从页面抓数存成表格、或者读一份名单批量提交——这就需要有文件读写能力;第三层是必须碰桌面软件或者必须“看见屏幕”才能干的活,比如某个只提供客户端的系统、比如一个弹窗必须靠图像确认位置——这一层才是真正拉开工具差距的地方。搞清楚自己的活落在第几层,再决定要不要深入这个工具,比盲目上手强得多。
1.2 几条主流路线的取舍
市面上能自动点网页的路子不算少,我把常见的几条摆在一起对比,这是我的实际判断,不是纸面参数:
| 路线 | 上手成本 | 网页内操作 | 桌面/图像能力 | 维护成本 | 适合谁 |
|---|---|---|---|---|---|
| 纯录制回放类工具 | 极低 | 够用但脆 | 基本没有 | 页面一改就崩 | 一次性任务 |
| 代码型自动化框架 | 高 | 强且稳 | 需要额外桥接 | 中,但可版本管理 | 有开发能力的人 |
| 本工具(表格脚本+视觉) | 低到中 | 强 | 自带图像识别与键鼠模拟 | 中,靠选择器和图片 | 非专职开发但要干实事的人 |
代码型框架的优势是工程化程度高、断言和日志体系成熟,劣势是门槛在那儿摆着,一个不写代码的运营同学要独立维护一套脚本,成本太高。纯录制工具的优势是快,问题是它记的是坐标和脆弱的路径,页面结构一动就得重来。而 UI.Vision RPA 这类工具的位置很微妙:它把脚本写成表格,把“找元素”和“认图片”两套能力揉在一起,门槛压到很低,同时保留了变量、条件、循环、JavaScript 执行这些能撑起复杂逻辑的东西。
我个人的判断标准很直白:如果这个流程只有我一个人跑、跑完就作废,我用录制;如果这个流程要交给别人维护、要跑半年以上,我会认真写选择器和错误处理;如果这个流程必须跨越浏览器边界去碰桌面软件,那基本就只剩这类带视觉能力的工具可选了。
1.3 架构拆解:它其实是三层拼起来的
把工具拆开看,结构比我最初想的清晰。最上面一层是浏览器扩展本体,负责在页面里执行点击、输入、读取文本、执行页面内的 JavaScript,这一层的能力边界就是浏览器的权限边界——它能做浏览器允许脚本做的一切,也做不了浏览器不允许的事。中间一层是视觉与识别,把屏幕上的一块区域截图、和预先存好的小图做匹配,或者把区域里的文字转成可读字符串,这一层解决的是“页面上没有可靠的标识、只能靠眼睛”的场景。最下面一层是本地桥接模块(通常叫 XModules 之类),负责突破浏览器沙箱去读写本地文件、真实地移动鼠标点击桌面、调用更强的文字识别。
这个分层很重要,因为它决定了很多问题的归属:脚本报“找不到元素”,问题在第一层;脚本报“图片置信度不足”,问题在第二层;脚本报“无法写入文件”,问题在第三层。新手最容易犯的错是把三类错误混在一起排查,越查越乱。我后面写排查章节的时候会严格按这个分层来,先定位是哪一层的锅,再谈怎么修。
还有一点要提前说明:这个工具的核心脚本格式兼容 Selenium IDE 那套命令体系,意味着一份脚本理论上可以在两边迁移。这个设计的好处是你不会被锁死,坏处是有些命令的语义为了兼容做了妥协,用起来会觉得“怎么这么绕”。我的处理方式是:核心流程用通用命令写,只有需要视觉和桌面的部分才用它的扩展命令,这样将来真要迁到代码框架,改造成本可控。
2. 上手前的准备与核心概念对齐
2.1 环境准备与权限边界先说清楚
安装本身没什么可说的,从浏览器的扩展商店装上,工具栏出现一个图标就算完事。真正要提前想清楚的是权限。这类工具要正常工作,基本会向你要三项东西:读取和修改你访问的网页内容、访问你下载和上传的文件、以及在本地开一个服务端口给外部程序调用。前两项是它干活的必需品,第三项是它能被命令行唤起的原理。装的时候别一路无脑点同意,看清楚它要什么,心里有个数。
我的习惯是给自动化单独开一个浏览器用户配置(Profile),不和日常浏览混用。原因很实际:脚本跑起来会连续打开关闭标签页、会疯狂点击,混在日常窗口里你自己都没法干活;另外有些脚本需要保持登录态,单独配置里登录一次能管很久,还不会污染你日常的账号环境。这个动作花五分钟,能省掉后面无数次“脚本把我正在写的文档页面给关了”的糟心事。
还有一条:如果你只用网页内的功能,扩展本体就够了;一旦涉及读写本地 CSV、模拟桌面点击、更强的文字识别,就需要装本地桥接模块。这部分能力有一部分是要授权的,免费额度够跑通大多数个人场景,但要拿它做长时间无人值守的批量任务,得先算清楚授权成本和省下的人力哪个更划算。我的建议是先用免费能力把手上的流程跑通,确认真能省时间,再考虑升级,不要一上来就买。
2.2 命令三要素:Command、Target、Value
这个工具的脚本本质就是一张表,三列:命令(做什么)、目标(对谁做)、值(做成什么样)。比如要在一个输入框里打字,命令是输入类命令,目标是这个输入框的定位表达式,值是要打的文字。要读页面上某个数字,命令是取文本,目标是那个元素,值填一个变量名,读到的内容就存进这个变量。
这套设计的精妙之处在于它极容易理解,看一眼就知道这行在干嘛,不像代码那样需要脑内模拟执行。但它的坑也在这儿:三列都是字符串,没有类型,你写1和写"1"在它眼里可能不一样。数值比较和字符串比较的结果差异,是这个工具里最容易翻车的地方之一。我踩过一次,循环条件里拿读出来的文本直接和数字比大小,结果字符串按字典序比,"10" 比 "9" 小,循环提前退出了,查了半小时才反应过来。从那以后我养成习惯:凡是参与计算的值,先用 JavaScript 执行那类命令转一遍数字,再拿去比。
变量在表格里用${变量名}的形式引用,这个语法和很多模板引擎一致,不难记。内置变量是一堆以感叹号开头的名字,比如控制等待超时的、控制出错是否中断的、记录上一条命令是否成功的、当前循环行号的。这些内置变量是写出健壮脚本的关键,比命令本身更值得花时间记,我在第 5 章会集中讲几个最常用的。
2.3 存储结构:宏、子宏、测试套件
工具里管脚本叫“宏”,一个宏就是一张命令表。多个宏可以放进一个文件夹,文件夹可以整体按顺序执行,相当于一个测试套件。宏之间可以互相调用,也就是一个宏执行到某一步时跳去跑另一个宏,跑完再回来——这就是“子宏”的用法。
这个结构看着简单,但用好了能把项目组织得很干净。我的组织方式是:一个原子动作一个宏,比如“登录”“打开目标页面”“导出报表”“退出登录”,每个宏只干一件事,只关心自己那一段;然后写一个主宏,按顺序调这些子宏,主宏里只放流程调度和错误处理,不放具体操作细节。这样做的直接好处是改需求时改动面极小——登录逻辑变了只动登录宏,其他宏一行不用碰;间接好处是调试方便,哪个环节出问题单独跑那个宏就行,不用每次从头跑一遍完整流程。
这里有个容易忽略的细节:子宏调用时的变量作用域。我的经验是全局变量在各宏之间是通的,但子宏里定义的局部变量回到主宏可能读不到,所以凡是需要跨宏传递的数据,我会显式地存到全局变量里,命名加个前缀区分,避免撞名。这个习惯在宏数量超过五六个之后会救你的命,否则你会在某一天发现两个宏用了同一个变量名,互相把对方的值覆盖了,而你完全不知道为什么数据是错的。
3. 十五分钟跑通第一个能用的宏
3.1 录制起手,手写收尾
新手最快的上手路径是先录一遍。点录制,手动把流程走一遍,停止,你会得到一张完整的命令表。这一步的意义不是直接拿去用,而是让你看清楚每个动作被翻译成了什么命令、目标长什么样。录出来的脚本九成情况下是不能直接投入生产的,因为它记的元素定位往往很脆弱,而且塞满了多余的等待和无关点击。
我的做法叫“录制起手,手写收尾”:录一遍拿到骨架,然后逐行清理——删掉所有无意义的点击和停顿,把脆弱的定位表达式换成稳定的,给关键步骤补上等待,把硬编码的值抽成变量。这个过程大概能把二十行的录制脚本压到八行左右,而且稳定性提升一个档次。
清理时我有个判断标准:凡是“页面加载完成后自动就会到位”的等待,删掉;凡是“点了按钮要等接口返回才出现”的等待,保留并且改成条件等待。前者是无脑等,纯浪费时间;后者是真的需要等,删了必崩。区分方法很简单,把那条等待注释掉跑三次,一次不崩就删,崩了就改条件等待。
3.2 元素定位:三套方案怎么选
定位是这个工具里最需要动脑子的部分,它支持三种方式,我按优先级排序:
第一优先是元素自带的唯一标识(比如 id 或 name)。这类定位最快最稳,页面改版通常也不会动它。可惜现实是很多内部系统根本不给你这个,能用的就珍惜。
第二优先是结构路径(xpath 或 CSS 选择器)。这类定位灵活,能表达“第三个表格里的第二行第五列”这种复杂关系。写的时候我有个铁律:尽量用语义定位,不用序号定位。//button[text()='提交']比//div[3]/button[2]稳得多,后者页面加一个广告位就全乱。写 xpath 我一般先在浏览器开发者工具里试,能唯一定位到一个元素才算过关,返回一堆的说明写得太宽。
第三是图像定位,也就是把按钮截个小图存下来,让脚本在页面上找这块图。这是兜底方案,用在两种场景:页面元素完全无法用选择器描述(比如整块是画布渲染的),或者定位表达式写出来极其复杂且易碎。图像定位的代价是换分辨率、换主题、换浏览器缩放就失效,所以它只适合环境高度可控的场景。
提示:图像定位一定要在“最终运行环境”里截图。你在自己电脑上截的图,拿到别人机器上跑,字体渲染和缩放比例差一点点就匹配失败,这个坑我踩过不止一次。
定位表达式写完,一定要做的一件事是加断言:先确认元素存在、可见,再做操作。多写这一行,你得到的报错会从“点击失败”变成“第 N 步找不到提交按钮”,排查时间差十倍。
3.3 完整例子:读名单、批量填表、回写结果
说一个我认为最有代表性的场景:手上有一份名单表格,需要逐个到某个系统里查询并记录结果。这个流程麻雀虽小五脏俱全,涵盖了读文件、循环、操作、写回、错误处理五件事。
第一步是读入。用文件读命令把名单读进来,工具会把它当成一张二维表,同时提供一个内置变量告诉你总共有多少行、当前在第几行。这里要注意的是表格的编码问题,我建议统一存成 UTF-8,否则中文姓名字段读进来就是乱码,而这问题在报错信息里完全看不出来,只会表现为“查询不到这个用户”。
第二步是循环。用条件循环命令,从第二行开始(第一行一般是表头),条件是当前行号不超过总行数。循环体内部通过行号去取每一列的值,取到的值赋给变量备用。这里有个很实用的技巧:把行号本身也存进一个变量并且写进日志,这样跑到一半崩了,你能准确知道断在第几行,下次从那里续跑,不用从头再来。
第三步是操作。打开目标页、定位输入框、清空、填入刚才取到的值、点查询、等结果出现、把结果文本读出来存到变量。这一串里最容易出问题的是“等结果出现”,因为查询是异步的,你点了按钮页面不会立刻变。这里的正确做法是用等待可见类命令,指定目标元素和超时时间,而不是拍脑袋写个固定睡眠。固定睡眠的问题在于慢的机器上不够、快的机器上浪费,而且它会掩盖真实的加载问题。
第四步是写回。把刚才读到的结果追加到输出表格的对应列,或者在内存里维护一张结果表,循环结束后一次性落盘。我倾向后者,原因是一行一存盘在数据量大时会有明显的 IO 开销,而且中途崩了文件处于半写状态很麻烦。
第五步是错误处理。在循环体内每一步操作之后,检查上一条命令是否成功的内置变量,失败了就把这一行标记为“失败”、记下原因、继续下一行,而不是整个流程中断。这个设计非常关键——批量任务里个别行失败是常态,你要的是一份带失败标记的结果表,而不是一个跑到第 37 行就停住的脚本。
这套骨架写顺了之后,你会发现公司里八成的重复网页操作都能往里套,只是换一下定位和字段。
4. 视觉识别与桌面自动化:真正的分水岭
4.1 图像匹配的置信度参数怎么定
图像匹配的原理不复杂:拿你存的小图,在屏幕或页面的指定区域里逐块滑动比对,算一个相似度分数,超过阈值就算找到。这个阈值通常叫置信度,取值在 0 到 1 之间。参数看着简单,但它是整个视觉能力里最需要经验的地方。
调高阈值,匹配更严格,误点少,但容易找不到;调低阈值,容易找到,但可能匹配到相似的其他元素上。我的一般取值是 0.7 到 0.8 这个区间起步,先跑通确认能稳定找到,再看有没有误匹配的风险往上调。如果同一个页面上存在长得几乎一样的多个按钮(比如列表里每行都有一个“编辑”),那必须把阈值调高、同时把截图范围收窄,只截那个按钮独有的特征部分,否则脚本会一直在第一行上打转。
截图本身也有讲究。我的三条经验:第一,只截必要区域,图越小匹配越快、越不容易被页面布局变化影响;第二,避开动态内容,千万别把按钮上的数字、时间戳、未读红点截进去,那些东西每秒都在变;第三,留一点边距,把按钮周围的空白也截进去一点,匹配时能利用上下文提高准确率。这三条听着琐碎,但每一条背后都是被误匹配折磨过的经历。
还有一个很少被提到的点:分辨率和缩放。图像匹配本质上是像素比对,如果运行环境的屏幕缩放不是 100%,或者浏览器缩放不是默认值,截图和实际渲染就对不上。我现在的做法是在脚本开头用命令把浏览器缩放强制归位,并且把这条写进注释里,免得以后接手的人一脸茫然。
4.2 文字识别:什么时候靠谱,什么时候别碰
工具带的文字识别能力,用对了是神器,用错了是灾难。它能做的是把屏幕上一块区域里的文字转成字符串,适合的场景很明确:某个数字或状态只以图像形式呈现,页面上抓不到。比如图表里的数值标签、截图里的水印文字、客户端软件里的余额显示。
不适合的场景同样明确:能用选择器直接读到文本的地方,绝不要用识别。原因很实在,识别是有误差的,会把 0 认成 O、把 1 认成 l、把小数点吃掉,而这些误差是随机的、不可预测的,一旦进入下游计算就会变成灾难性的错误数据。我的判断标准是:如果这个值最终要参与计算或者要写进正式报表,选择器能拿到就必须用选择器;只有选择器完全拿不到,才退到识别,而且识别出来的结果必须经过格式校验。
校验怎么做?我一般加两步:先用正则匹配确认格式对不对(比如金额必须是数字加两位小数),格式不对就重试一次,两次都不对就标记失败。这个小逻辑写起来不到十行,但能挡掉九成以上的脏数据。
识别的准确率还跟区域大小强相关。区域越大,识别引擎要做的工作越多,出错概率越高。所以截图要尽量贴着文字边缘,别把大片空白和无关元素框进去。另外如果文字是白字彩底或者字号很小,识别率会明显下降,这种场景我会考虑先放大页面再截。
4.3 桌面自动化绕不开的焦点与坐标
一旦流程跨出浏览器去操作桌面软件,会立刻遇到两个新问题:焦点和坐标。
焦点问题的表现是:脚本模拟的按键跑到了别的窗口里。原因是模拟键盘输入是把事件发给“当前活动窗口”,如果脚本执行过程中有什么东西抢了焦点(一个弹窗、一个系统通知、你自己手贱点了一下),按键就打偏了。我的处理原则是:每次模拟输入前,先显式地把目标窗口激活一次,不要假设它还是前台。这个动作多花半秒,能避免大量“偶尔失败一次”的诡异问题。
坐标问题更麻烦。图像匹配能找到位置,但如果你用的是硬编码坐标,那换个分辨率就全废。所以桌面点击我一律用“找图再点”的方式,绝不用固定坐标。即使必须用相对偏移(比如“点在找到的图标右边 50 像素处”),我也会把这个偏移写成变量并注释清楚,方便环境变化时统一调整。
还有一个容易被忽略的点:执行速度和界面响应速度不匹配。脚本的点击间隔是毫秒级,而桌面软件打开一个窗口可能要一秒。如果你不主动等待,脚本会在窗口还没出来的时候就开始找图,然后报“找不到”。所以桌面流程里,我几乎每个动作之间都插了一个“等待某个标志出现”的等待,而不是固定睡眠——固定睡眠在快机器上是浪费,在慢机器上是不够。
5. 工程化:让脚本能被别的程序调用
5.1 命令行入口与参数传递
脚本调通了,下一步就是让它脱离“手动点运行”的状态。这个工具提供了一个本地接口:扩展在本地开一个服务端口,外部程序往这个端口发一段结构化的请求,说明要跑哪个宏、传什么参数,扩展执行完再把结果返回。具体端口号在设置里能查到,不同安装可能不同,这一点要自己确认。
这个能力打开了很多门。最典型的是定时任务——用系统自带的任务计划,每天早上八点发一个请求过去,跑完自动关掉。其次是和其他程序串起来:先用别的脚本准备好数据文件,再唤起宏去处理,处理完宏写一个结果文件,下游程序读走。整个过程不需要人在中间点任何东西。
通过请求传参数这件事需要设计一下。我不建议在请求里塞大量数据,因为请求体大小有限制,而且调试起来不直观。更稳的做法是:请求里只传一个文件路径或者任务编号,宏自己去读对应的文件。这样数据量不受限,而且出了问题你能直接打开文件看,比在日志里翻一大段 JSON 舒服得多。
5.2 错误捕获、重试与断点续跑
无人值守的任务,健壮性比功能重要十倍。我总结出三个必须做的动作。
第一个是全局的错误开关。工具默认遇到错误就中断整个宏,这在调试时是好事,在生产时是灾难——因为一次网络抖动就让整批任务停了。我会在宏开头把“出错继续”的内置变量打开,然后在每个关键步骤之后单独判断是否成功,自己决定这一步失败了该怎么办。这样控制权在我手里,而不是在工具的默认行为里。
第二个是重试。网页自动化失败的原因里,相当一部分是瞬时的:网络慢了一拍、元素渲染晚了一点、接口偶发超时。这类失败重试一次大概率就好了。我的做法是把高风险步骤包进一个“最多试三次”的小循环,每次失败后等一到两秒再试,三次都失败才标记为真失败。实测下来这一招能把失败率压下去一大截,而且实现成本极低。
第三个是断点续跑。批量任务最怕的是跑到第 800 条崩了,重新跑又得从第一条开始。解决办法是让脚本记住进度:每处理完一条,就把已完成的标识写进一个进度文件;脚本启动时先读这个文件,跳过已完成的。这个机制写起来不复杂,但需要保证“写进度”这个动作在处理成功之后立刻执行,不能放在循环末尾统一写,否则崩溃时进度就丢了。
5.3 日志与结果落盘
不带日志的自动化脚本等于黑盒。出了问题你只能看到“失败”两个字,然后开始瞎猜。我要求自己的每一个脚本都能回答三个问题:跑到第几步了、这一步的输入是什么、输出是什么。
实现方式很朴素:在关键节点往日志文件里追加一行,格式是“时间戳 + 步骤名 + 关键变量值”。日志不要写得太细,每一步都写会淹没重点;也不要太粗,只写开始和结束等于没写。我的粒度是:每个业务步骤写一行,每次重试写一行,每次异常写一行带原因。这个粒度下,出问题时看日志基本能一眼定位到哪一条数据、哪一步出的岔子。
结果落盘我坚持用表格文件,不用文本。原因是表格能直接被人打开看、能排序筛选、能二次加工,而纯文本日志给人看的体验差太多。落盘时机前面提过,我倾向在内存里攒着、循环结束或者攒够一批再写,减少 IO;但进度标记必须实时写,这两者不冲突,分开存两个文件就行。
6. 踩坑实录与排查速查
6.1 常见现象对照表
下面这张表是我和身边人真实遇到过的问题汇总,按“现象—可能原因—处理方式”组织,遇到问题时可以先扫一眼。
| 现象 | 大概率原因 | 处理方式 |
|---|---|---|
| 报找不到元素,但人眼看着就在 | 元素在 iframe 里 / 元素还没渲染完 | 先切换框架再定位;把固定等待改成等元素可见 |
| 偶尔成功偶尔失败,毫无规律 | 存在竞态,某一步没等加载完就往下走 | 逐个步骤加条件等待,找出真正的瓶颈步 |
| 图片匹配一直失败 | 缩放比例、分辨率、主题与截图时不一致 | 在运行环境重新截图,统一缩放比例 |
| 循环只跑了一轮就退出 | 条件里拿字符串比大小 | 强制转成数字再比较 |
| 中文全是乱码 | 文件编码不是 UTF-8 | 统一存成 UTF-8,读取时确认编码 |
| 桌面按键打到了别的窗口 | 焦点被抢 | 每次输入前显式激活目标窗口 |
| 批量跑到一半停住 | 默认遇错即停 | 打开容错开关,逐条判断并记录失败 |
| 定时任务没跑起来 | 浏览器没开 / 端口不对 / 用户会话未登录 | 确认浏览器常驻、端口正确、登录态有效 |
这张表覆盖不了所有情况,但能挡掉最常见的一批。真正排查时我的顺序是固定的:先看日志定位到具体哪一步,再判断错误属于哪一层(页面内、视觉、本地桥接),然后只在这一层里找原因。跳层排查是最浪费时间的做法。
6.2 几条交过学费换来的经验
第一条,能在页面内解决的,绝不上升到视觉。视觉定位是最后手段,因为它的稳定性天然比选择器差一个数量级。我见过有人图省事,整个脚本全用找图点击,结果换了台电脑全部报废,重截了三十多张图。选择器写起来麻烦,但那是“一次麻烦换长期稳定”,账要算长远。
第二条,不要在脚本里硬编码任何会变的东西。账号、网址、文件路径、阈值、超时时间,全部抽成变量放在宏的开头,改的时候只改那几行。这个习惯的价值在你需要把脚本交给同事、或者需要在测试环境和生产环境之间切换时会成倍体现。
第三条,先让脚本能跑,再让它跑得稳,最后才让它跑得快。新手常犯的错是一上来就追求效率,删掉所有等待、优化所有循环,结果脚本跑得飞快但每天崩两次,维护成本远高于省下的那点时间。我的顺序反过来:先加足够的等待保证不出错,稳定运行一周之后,再逐个把固定等待换成条件等待,一点点压缩时间。这个过程急不得。
第四条,每个脚本都要写“这个脚本干什么、谁改过、改了什么”。工具本身没有强制的版本管理,但可以在宏的第一行放个注释写明用途和最后修改时间。这个动作十秒钟,能省掉半年后你自己看着一堆脚本发呆的半小时。
最后分享一个我在实际使用中的体会:这类工具最大的价值不是替你点几下鼠标,而是逼着你把手上的流程第一次完整地、无歧义地描述出来。很多人以为自己熟悉某个流程,真到要写成脚本时才发现中间有三处“看情况”、两处“凭经验判断”,这些模糊地带平时靠人的临场反应糊过去了,一旦要交给机器就全暴露了。把这些模糊地带补清楚,哪怕最后没用工具,你对这个流程的理解也已经上了一个台阶。