Qeasy Cloud
Get Started

AI 帮你写了解析脚本,为什么上线前还要故意造几份"坏账单"

· 谢锴斌· AI Financial Reconciliation· 34 views· 12 min read
账单解析解析脚本脏数据回归验证AI 财务对账

摘要:AI 十分钟写出一份解析脚本,能上线却是另一件事。这篇讲试跑为什么只取前 50 行、只读不落库,"50 行全对"证明不了其余几千行零回归;解析契约里必须交代的入参出参、净额恒等式与双零判失败;怎么故意造重复行、缺列、符号错、时区错四类坏账单;上线前的四级防线与三条硬阈值,以及"行级 99%"为什么是最常见的自欺。 关键词:解析脚本、脏数据、回归验证、试跑边界、符号口径、归属期错挂、解析审计

一、脚本十分钟写好,上线是另一件事

先看一份真实的抽测回报:抽测 50 行,44 行正常,5 行缺原单号按业务异常标出,1 行脚本本身报错,定位到第 37 行,整轮耗时 830 毫秒。

多数人的反应是:修好第 37 行,然后上线。但这个前提没被验证:这次抽测只看了账单的前 50 行。 试跑取样上限 50 行、默认 20 行,固定取前 N 行。"44 行正常"证明的是"开头这段没问题",不是"整份账单没问题"。

更隐蔽的是那 5 行。业务异常不阻断任务、不让整批失败,账单导入状态照样是绿的。这五行里有几行真的没有订单号、有几行是脚本没取出来,从回报里分不出来——前者不参与对账,后者断掉"解析、对账、出单"整条链。

所以真正的结论是试跑通过和能上线本来就是两件事。 拿一份绿色的抽测报告做上线决策,是最常见的一次误判。

二、AI 交的是脚本,交不了上线

用 AI 辅助写解析脚本已经是常规操作,它的标准工作流是五步:

步骤谁在做具体动作
一、提需求人用业务语言说清楚要修什么
二、自动勘察AI看真实列名、查现有脚本、列核算项目、查知识库
三、自动干活AI写脚本 → 试跑 → 保存,先测后存
四、一句确认人触发解析前停下来问一句:"要我把这份账单重新解析吗?"
五、验证汇报AI轮询任务进度、查解析汇总,用业务语言回报

底层工具的调用序列也是固定五步:列账单 → 看样本行 → 试跑 → 保存 → 触发解析。

编辑解析脚本的界面,速卖通美元结算账单脚本版本与 AI 助手面板

截图里有两处值得看:左边是业务口径,含一栏"原始需求",那必须是业务用户看得懂的话;右边是助手面板,正在第 3 步自己干活。脚本机器写,口径业务写,两栏分开填才不顶牛。

两个细节要盯住。一是全程只有一个人工触点,就是第四步的那句话,勘察、编写、测试、保存全程自主;业务口径没提前写清,AI 会在自主判断里替你决定,而口径恰恰最不该被自动决定。二是链路有硬约束:写类工具要求管理员角色,写操作留审批人,会话里的脚本锁定。

这条是本文的入口:造数据不能指望系统提示,得你自己动手,而且要造得有意图。

三、解析契约:业务人员到底要交代哪几件事

解析脚本不是填空题,它是一份合同。

入参两样:原始行(键是账单里的中文表头,一字不差)和当前可用的核算项目清单(含编码与名称),核算项目必须从清单里取。

出参五项:业务订单号、核算项目编码、收入金额、费用金额,外加异常标记与异常原因。拆行时返回数组,第一个结果更新原行,其余生成子行,子行序号为负。

中间夹着一条恒等式:净额 = 收入金额 − 费用金额。 符号带在金额上:正常收入为正,退款退货为负收入,正常费用为正,平台退还的费用为负费用。退款绝不进费用金额。

还有一条判失败规则:双零判失败。 写回之后收入金额为 0 且费用金额为 0,这一行判解析失败,理由写"解析后无收入/费用金额",不设例外。设计上归零的提现场景同样判失败——旧的"零金额当已解析落库"口径已废止。

更要紧的是这条:执行层只透传,不猜符号,也不许取绝对值。 脚本没有显式返回金额时,系统保留导入时的机械初值。最典型的错误就是退款行被挂成"正的费用金额"——一行退款从"冲减收入"变成"增加费用",利润只是少了一点。

所以业务人员在动笔前要交代四件事:哪一列是订单号、怎么映射到核算项目、收入与费用各自的符号规则、什么情况算异常。这四件事都是业务判断,技术替代不了。

沙箱本身有边界:内存 128 MB 硬上限,单脚本 1 秒,整批 5 分钟,禁网络、禁文件系统、禁子进程;访问系统数据的唯一出口是只读查询,默认 500 条、上限 2000 条。解析产物只有那五项,不出单据。

沙箱机制架构图,虚拟机隔离与进程隔离构成的双层防护

架构图上值得看的不是箭头,是那道把脚本关起来的边界:脚本能算、能查,不能写、不能联网、不能碰文件,落库统一由执行层做。"谁决定金额"和"谁决定落库"被拆开之后,业务口径只需要守住前一半——轻易云的解析沙箱把业务口径写成脚本合同,谁写谁负责。

四、试跑的真相:只取前 50 行、只读不落库、证明不了全量

试跑有三个性质,缺一不可地决定它证明不了什么。一是同步、只读、不落库,没有测试记录表,返回即弃,价值在于快而不在于留下证据;二是取样固定取前 N 行,不随机,上限 50 行、默认 20 行,几千行账单你验证的是开头而不是全部;三是超时双层,编译 5 秒、整体 30 秒。

试跑返回分三组,三组含义完全不同:

返回分组含义该找谁
成功这一行已解析不用管
错误脚本本身抛了异常改脚本,脚本有缺陷
异常脚本跑通了,但返回业务异常标记改口径或补数据,脚本大概率没错

全文最反直觉的一句:试跑 50 行没问题,证明不了其余几千行零回归。 正式路径是五分钟一批的队列任务,试跑是同步调用、跑完就结束,队列任务有排队、重试、分批提交。另一条是执行层有两道判断试跑覆盖不到:双零判失败发生在写回之后,拆行的守恒校验发生在落库时。试跑验证的是脚本本身,不是它在正式路径上的行为。

解析沙箱执行流程图,从编写脚本、沙箱启动、执行到执行层校验与结果落库

流程图的分岔点值得停一下:左边是试跑端点,同步、只读、不落库、50 行采样;右边是正式解析,在执行层校验那栏才分出两条出路。

五、故意造四类坏账单:重复行、缺列、符号错、时区错

试跑的局限只能靠"故意造坏数据"来补。这四类坏账单,每一类都对应一个上线后真实会发生、而且不报错的错误。

坏账单怎么造期望系统怎么反应造它验的是什么
重复行账单拆两份分别导入,或改单元格再导不该被重复计入跨账单重复行不被识别
缺列删掉订单号列、金额列或判据列停线,不得上线红线三档与可降级列的分界
符号错把退款改成费用,或把费用列正负写反判失败或挂到正确一侧退款绝不进费用金额
时区错把月初零点后那几行挪到上个月归属期挂错月按源字符串墙钟取月

重复行是最贵的一类。 导入去重只对同一张账单重跑有效,跨账单的重复行现在完全不被识别——行级指纹方案还在评审。文件级去重靠文件指纹,但拆成两份导入、或改一个单元格再导入,都会绕过去。后果是一条链:收入与费用求和翻倍,对出等额假差异,单据金额翻倍,已推过去的还要人工红冲。

缺列有明确红线。 缺订单号列、缺金额列、缺核算项目判据列,这三档停线,不得上线;只有地址、渠道、物流单号、备注这类诊断列缺失才可以降级上线。样本基线是 38 份样本、10 个平台、25 种账单类型,22 种有样本、3 种缺失、2 种质量降级。缺了诊断列账还能算,缺了判据列账算出来是错的。

符号错要先分清账单形态。 收支两列对列的账单直接按列取符号;单金额列加类型列的账单按类型取数后费用类取负。具体到平台:某平台费用项取金额列原值的负;某平台费用列原始为负表示扣费、取负落成正的费用金额,为正表示费用返还、落成负的费用金额;某平台费用类列整体取反。三条规则都指向同一句:退款永远不能进费用金额。

时区错最安静。 归属期一律按源字符串的北京墙钟年月直取,或者时间加 8 小时偏移后取月,禁止转成世界时字符串再截前七位。存量审计做过:9 张账单行表、3 个库交叉扫了一遍,0 条错挂。实证错挂长这样:某月 1 日 04:49 和 04:50 两笔,金额 34.58 与 36.92,被挂到上个月。两笔都是小额,当月依然是平的——错月不报错,它只挪动了边界那几行。

还有一个坑值得当场验:编码假设。 某平台结算账单按 UTF-8 解码出现 1,222,551 个替换字符,改按 GBK 解码则是 0 个——"文件损坏"很多时候只是编码假设错了。

六、上线前的四级防线,以及"行级 99%"的自欺

四道防线,逐级通过才算交付。一,单元测试,毫秒级,防的是改一行规则炸掉一片。二,试跑,同步、只读、不落库,秒级迭代环,防的是脚本本身写错——轻易云的试跑是只读沙箱,不落库,全量回放才是上线依据。三,全量回放,这一级最重,验收就四句话:恰好 N 行变化、零回归、没有"成功变失败"、脚本异常为 0。四,批次轧平,财务应收加费用应收(带符号)等于账单体行净额,差额必须是 0.00,轧平不过不得推 ERP。

然后是三条硬阈值:行级解析成功率 ≥95%、订单号解析率 ≥95%、对账成功率 ≥95%。 而"行级解析率 99%"是最常见的自欺:订单号解析率只有 80% 时,行级再高也是废的——订单号一缺,这一行就断掉"解析、对账、出单"整条链。参照一组实测:某欧洲站 2,473 行里成功 2,463 行,等于 99.6%,对账成功率 99.78%,全账单解析率 99.1%。三个数一起看,才知道哪一环是断的。

沙箱机制价值图,业务灵活性与安全性双轨,列出四类沙箱脚本与隔离手段

这张图讲的是沙箱的双轨价值:左边是业务灵活性,脚本由业务人员自己写、自己改;右边是安全性,双层隔离、超时强制终止、只读查询。业务同事敢自己接手写脚本,前提是它跑在一个错了也不会污染账、不写库、不联网的盒子里。

七、解析审计:让第三个人来挑错

还有一道防线是给上线之后准备的:解析审计,七条硬约束:

约束内容
需求盲解析执行者只看需求原文,不看别人怎么写的
执行者互不知情彼此不知道对方在做什么
两层汇总客观层与解释层分开看
容差为 0字符串十进制转最小货币单位的整数累加,禁用浮点
差异必须归因不允许用"有差异"三个字带过
全程只读只看,不改
先算文件哈希再开审原始文件哈希必须等于账单文件哈希,不等立即中止

执行者至少 2 个,推荐 3 个——奇数便于多数裁决。客观层直接对原始金额列求和,必须所有执行者完全一致;解释层按需求映射到核算项目,允许分歧,分歧本身就是需求歧义点。差异要归到五类:脚本缺陷、系统落库异常、需求歧义、需求与数据不符、需求覆盖不足。结论三档:通过、通过但有备注、不通过。

抗污染检查是这套方法的地基。 两份解析脚本结构雷同即视为串供,整份公证作废。审计员不能看答案——把正确数字喂给它,等于替考。还有一条必须在结论里点名而不是略过:兜底占比。 真实案例里兜底科目占了账单金额的 99.5%,最大一笔是 71.5 万元的提现,这是资金划转混进了费用池。结论里只写"通过",这笔钱就永远没人管。

收尾:把坏账单变成一张清单

在轻易云上,这套顺序被固化成脚本开发的固定环节:先测后存,再全量回放,后批次轧平,改一版回一次数据。写脚本是十分钟的事,证明它能上线是一个账期的事——AI 交出脚本,四级防线才决定它能不能上线:单元测试管住改动半径,试跑管住脚本本身,全量回放管住回归,批次轧平管住总额。一个默认脚本一旦上线就会自动影响后续的导入,所以"改完再看看"这种节奏在这里走不通。

再往前一步,是把这四类坏账单固化成一份回归清单:每接入一个新平台或新账单类型,就按重复行、缺列、符号错、时区错各造一份样本,配套写好期望结果,交给下一位接手的人。清单本身并不复杂,难的是有人愿意在没人催的时候去执行它——而这恰恰是上线前唯一一段只能靠自觉完成的工作。

口径正文里也不该写死版本号,只引用"现行默认脚本":脚本变更太频繁,现有解析脚本 61 行、25 个默认,对账脚本 109 行、10 个默认,费用分摊脚本 6 行、6 个默认,集成转换脚本 126 行、20 个默认。解析脚本的唯一键是平台、账单类型、店铺、版本,店铺级优先、平台级兜底,触发解析时如果所选脚本的店铺和账单对不上,直接拒绝。版本号只该出现在来源记录里。

三条可以今天就做的动作

第一,把当前在用的解析脚本挑一个平台,跑一次试跑,把三组返回的比例记下来,异常那一组逐条看一眼:是真的没有订单号,还是脚本没取到。这份清单直接告诉你下一版该改什么,也直接告诉你这一版能不能上线。别小看这份清单——它把"脚本写得对不对"翻译成了"业务口径清不清楚",而口径不清是上线之后最贵的那个错。

第二,造三份坏账单:同一份账单拆成两份分别导入一次、删掉金额列导一次、把一笔退款改成费用导一次。把三次结果并排放,看系统在哪些地方拦住了你、在哪些地方没拦住。没拦住的地方,就是上线后要人工红冲的地方;拦住了的地方,就是可以写进检查单的规则。造数据的目的不是看系统出错,是看系统该出错的时候有没有出错。

第三,给行级解析成功率、订单号解析率、对账成功率这三个数各定一条线,写进上线检查单。只有三个数一起达标,才允许把新默认脚本推上去,并写明谁签字、什么时候签。这三条动作都不需要等下一个账期,本周就能做完,做完再把结论贴回需求单,下一次改脚本时就有明确的验收依据。

账单解析最贵的错,不是报错的那些行,而是跑完了没人拦的那些行。

Original content. Please credit the source when reposting: https://www.qeasy.cloud/insights/reconciliation/18-9-parse-script-negative-validation

Comments