网鱼AI电商助手  ·  面向闲鱼卖家的 AI 铺货与发布自动化 工作日 09:00–18:00  ·  试用与部署 免费

发布台账,两条通道一个口径

台账最容易做坏的地方不是字段少,而是两条通道各记一本:手机 APP 通道一份、电脑网页版一份,字段名和取值口径还不一样,合起来统计时先要花半天对齐。这页讲清一本台账的字段该怎么定、item_id 为什么要回读、时间戳取哪一端、历史记录为什么不能被覆盖,以及从这本账里到底能算出哪些数、哪些数现在还算不出来。

单一口径item_id 回读时间戳历史不可覆盖对账复盘报表
小型库房的货架与包裹
One ledger · 通道不同,口径只有一套

01  /  一本账

两条通道,只能有一个口径

发布数据的第一次分裂,几乎总是从两条通道各记一本开始的。手机 APP 通道跑完记一份表,电脑网页版通道跑完记另一份表,两份表都是人设计的,字段名、时间取值、成功判定各自不同。单看每一份都合理,合起来统计时问题才出来:同一天的总量要对两次,两条通道的成功率算法不一样,价格一列一个有货币符号一个没有,时间戳一个取本地时间一个取请求时间。

这些差异不会自己暴露。它们会在某次复盘时集中出现:按两份表算出来的日总量差了三条,查了一下午,发现是其中一份把失败也记成了成功;或者同样的两条记录,一份记的是提交时间、一份记的是回执时间,跨零点的那几条就被分到了两天。

分裂点两份表常见的差异合并时的后果
字段名一个叫标题一个叫商品名,一个叫价格一个叫售价合并要人工映射,映射一次错一次
时间取值一份取提交时间,一份取回执时间跨零点的记录分到两天,日总量对不上
成功判定一份以回执为准,一份以流程跑完为准成功率不可比,趋势没有意义
去重键一份用标题,一份用序号同一条商品可能被记两次或漏掉

做法是两条通道写同一本台账,由同一个写入模块负责落盘。这个模块只做一件事:接收一条已经规范化的记录,追加到同一个文件里。通道自己不做格式化,也不做成功判定,只把原始结果交上来,由这个模块统一判定与写入。好处很直接——口径只有一处定义,改口径只改一处;两条通道的记录天然可比,因为它们的字段含义是同一套。

单一口径还有一个不显眼但很实用的作用:它让两条通道可以互相校验。同一份发布计划在两条通道上执行,记录的字段结构一致,就能逐条比对哪一条在哪个环节慢、哪一条更容易失败。如果口径分裂,这种比对做不了,因为差异可能来自口径,也可能来自执行,分不开。

要注意的是,单一口径不等于所有通道行为一致。手机通道有设备、有界面等待,网页通道有请求重试,两者的失败模式本来就不同。台账要做的是把不同的失败模式映射到同一套状态上(成功、失败、跳过、取消),而不是把执行过程抹平。状态是四个,过程各有各的日志,两者不要混在一起。

判断自己的账本是不是已经分裂了,有个很简单的检查:拿同一天的数据,分别从两条通道的记录里算一次总量,再算一次合并后的总量。三个数应当完全相等。不相等,就先修口径,不要急着看趋势——口径没修之前,所有趋势都是口径的产物,不是经营的结果。

02  /  字段口径

字段与取值:每一列只允许一种含义

台账的字段不在多,在于每一列的含义唯一。一列里混了两种含义,这一列就没法用来算任何东西。下面是这本账的核心字段,以及每一列的口径要定死的地方。

字段含义口径要点
item_id平台侧这条商品的唯一标识以回读到的值为准,不以本地生成的编号为准
标题实际提交上去的标题存提交时的文本,不存计划文本
描述实际提交上去的描述保留原样,包括换行,不要压缩成一行
价格实际提交的价格只存数值,单位与格式统一,不要带符号
时间戳这条发布生效的时刻取一个定义,全站统一,并记录时区
通道这条由哪条通道执行两条通道用同一套枚举值
状态成功、失败、跳过、取消四态之外不新增,其他情况归入其中一种并写原因

时间戳这一列最需要定死。一条发布涉及至少三个时刻:计划时刻、提交时刻、拿到回执的时刻。三个都真实存在,但如果台账里混着用,同一批数据就没法按天切分。做法是选一个作为主时间戳(通常取拿到成功回执的时刻,因为它最接近这条商品真正对外可见的时刻),其余两个存在旁边作为辅助列。这样按天切分只用一个基准,排查时还能看到另外两个。

价格只存数值,是有具体原因的。带了货币符号、带了千分位、带了区间(比如 800 到 900),这一列就没法求和、没法比较、也没法和计划值做一致性判断。写法统一之后,批量核对是一行代码的事;写法不统一,每次核对都要写一次清洗规则,而清洗规则本身也会出错。

状态只有四个,这一点要坚持。新增状态看起来更精确,实际会让统计变形:每加一个状态,所有按状态聚合的报表都要改,而且四个状态之外的情况往往只有一两条,为它单独开一个状态,代价远大于收益。遇到四态覆盖不了的情况——比如提交成功但回读不到 item_id——正确做法是归入失败并写清原因,而不是新开一个疑似成功。

还有一列容易被漏掉:原因。失败、跳过、取消三种状态都必须带原因,原因是枚举值而不是自由文本,这样能统计。自由文本看起来更灵活,实际三个月之后就没人能统计了,因为同一个原因有十几种写法。枚举值不够用时扩充枚举,不要退化成写句子。

字段定完之后要写进文档,并且规定:新增字段只能加在末尾,不能改已有字段的含义。改含义是最危险的一种变更,它不会报错,只会让历史数据和新数据不可比——而这种不可比往往几个月后才被发现,那时候已经没法重建了。字段变更的记录方式见版本更新。

03  /  回读校验

item_id 要回读,不能靠推断

发布成功这件事有三个不同层次的定义,混在一起是所有台账不准的根源。第一层是流程跑完了:点完了提交按钮,页面跳走了。第二层是拿到了成功回执:界面或接口明确返回了成功。第三层是这条商品在平台上真的存在,能按标识找到。前两层都在本地可判,第三层必须回读。

为什么流程跑完不算成功

提交按钮点下去,界面可能跳到结果页,也可能停在原地弹了个提示。流程判断的是动作执行完了,不是平台接受了。把这一层当成功,台账里会混进大量实际上没发出去的记录。

为什么回执也不算最终

回执说明平台收到了这次请求,但不代表后续处理完成。有些情况是回执成功、商品随后进入审核或未通过。所以回执是必要条件,不是充分条件。

回读解决什么

回读是按 item_id 去平台上找这条商品,找到了才算真的存在。item_id 从回执里取,不是本地生成的编号。本地编号只能内部对账,对外没有意义。

回读不到怎么办

归入失败,原因写清是回执缺失还是回读未命中。不要重试发布——重试可能造出重复商品,正确处理是等一轮之后再回读一次,仍然不到就人工确认。

回读的频率要有节制。每条发布后立刻回读一次,是必要的;隔几分钟再回读一次,用来确认状态稳定,也是合理的。但不要写成循环轮询,那会让请求量随商品数量线性增长,而且大部分轮询是无效的。做法是每条固定两次:提交后一次、几分钟后一次,两次都命中就定成功,否则定失败。

item_id 的另一个用途是对账。台账里存了 item_id,就能把"计划里的这一条"和"平台上的那一条"对上。没有它,对账只能靠标题加价格去猜,而标题可能被改过、价格可能被调过,猜错的概率不低。

两条通道的 item_id 获取方式不同:手机通道从结果页或商品列表里读,网页通道从接口返回里取,两者的差别写在电脑网页版通道和手机 APP 自动化通道里。两者都要落到同一个字段上,格式统一(去掉前后空格、去掉非数字字符),否则同一个值会被当成两个。这一点在初建台账时最容易忽略——先跑通了,数据看着对,等到做去重和跨通道比对时才发现格式不一。

回读还有一个隐性收益:它顺手验证了标题和价格是不是真的按计划发出去了。回读到的商品信息可以和提交时的记录比对,不一致就说明中间有人改过。这类不一致不常见,但一旦出现,往往意味着流程里有未经记录的干预,比数据本身更值得关注。

04  /  历史与防护

历史记录只能追加,不能覆盖

台账的价值随时间增长,前提是历史记录不被改写。一条记录被覆盖,损失的不只是那一条,而是所有以它为基准的比较——上周和这周比,比的可能是两套不同的记录方式。

所以写入规则只有一条:追加。修改不靠改原行,靠追加一条新的状态记录,原行保留。这样任何一条商品的历史都能完整回放:什么时候发、什么时候失败、什么时候重发成功。需要当前状态时,取最后一条状态记录;需要过程时,全部读出来。

覆盖式写入的危险在一次真实事故里体现得很清楚:自检流程污染了生产发布记录。根因是路径解析早于环境变量生效——程序在环境变量还没被设置的时候就把数据目录解析成了默认的生产路径,于是本该写到测试目录的自检数据,写进了生产台账。表现出来不是报错,而是生产记录里凭空多出一批商品,而且它们看起来完全正常。

防护一:路径要显式

数据目录用绝对路径写在配置里,不要依赖启动之后才生效的环境变量。这条是那次事故的直接修复。

防护二:写前留备份

任何会改动正式台账的操作,动手之前先落一份备份文件。出问题时能退回到操作前,而不是只能往下修。

防护三:进程带标记

自检进程带标记,带标记的进程一旦尝试写生产数据直接抛错。把判断做在写入模块里,而不是靠调用方自觉。

防护四:整轮哈希比对

自检前后对生产文件做一次哈希比对,不一致就报警。这一条能抓住所有没想到的写入路径,是最后一道网。

这四条防护的顺序有意义:前两条防的是写错地方,第三条防的是写错之后还继续,第四条防的是前三条都没拦住的情况。只做其中一条都不够——路径写对了,也可能有人在别处直接打开了生产文件;进程标记做了,也可能有第三个进程没带标记。

备份这件事要说得更具体一点:备份不是把文件复制一份叫备份,而是在改动之前生成一份带时间标记的副本,并且验证过能读回来。很多所谓的备份从来没被恢复过,等到要用的时候才发现文件是空的或者格式不对。验证的方式很简单:备份完立刻读一次,行数与原文件一致。

追加式写入在实现上还有一个细节:并发。两条通道同时写同一本台账时,必须有一把锁,或者用追加模式加一次性写入整行,避免两行交错。这个问题在多设备并行时会放大,多台设备同时回写结果,写入冲突的概率随设备数上升。并发写入的处理与设备侧的做法见多设备并行管理。

05  /  报表口径

从台账能算出什么,什么暂时算不出来

台账有了,下一步是报表。这里要克制:能算的算,不能算的不要硬凑。一张报表里混进一个口径不明指标,整张表的可信度就没了。

现在能算的

  • 每日、每周的发布条数,按通道、按类目、按服务线分
  • 成功率:成功条数除以当日槽位数,四态齐全才算得出
  • 失败与跳过的原因分布,按枚举值统计
  • 计划时间与实际时间的偏差分布
  • 同一批商品的标题与价格分布,用于看相似度
  • 每条商品的完整时间线,含失败与重发

现在算不出来的

  • 曝光与浏览量:台账不记录平台侧的展示数据
  • 成交与转化:成交发生在平台侧,未纳入本账
  • 问询数量与质量:需要读消息,不在本账范围
  • 单条商品的收益:缺少成本侧数据
  • 账号健康度评分:没有可核对的构成项

把这两组分开,是为了避免一种常见的错:用发布量去解释成交。发布量涨了、成交也涨了,看起来相关,实际上中间隔了好几层——曝光、点击、问询、议价。台账只覆盖第一层,用它去解释后面几层,结论一定是错的。真要分析成交,得把平台侧的数据接进来,那是另一件事。

成功率这个指标要算对,关键是分母。分母是当日槽位数,不是当日发布条数。用发布条数当分母,跳过和取消的条目就被排除在外了,成功率会虚高。四态齐全的账本才能算这个指标,这也是为什么状态只允许四个、不允许新增。

偏差分布比平均值有用。计划时间与实际时间的平均偏差接近零,可能是一半提前一半延后互相抵消;而看分布就能发现某一类商品总是延后,原因可能是图片多、上传慢,或者总是排在窗口末端。平均值掩盖的东西,分布会显出来。

报表的更新频率要跟决策频率匹配。日更的报表如果没人每天看,就会变成噪声;周更的报表如果用来做当天决策,就太慢。比较合理的配置是:日报只看四个数(当日槽位数、成功数、失败数、跳过数),周报看分布与趋势,月报看结构与口径是否需要调整。三层各看各的,不要在日报里塞趋势图。

还有一条原则:报表里的每个指标都要能追到账本里的具体字段。追不到的指标不要放进报表,哪怕它看起来很重要。一个追不到的指标,出了一次异常之后就无法解释,而无法解释的指标在决策里等于不存在。

06  /  计划对账

计划与实际,按槽位对账而不是按条目

台账和排期表是同一份数据的不同视图,对账就是让两个视图对上。对账的锚点选错,整件事就白做。按条目对账会把同一条的多次尝试算成一次,按槽位对账才能看出每一天的执行质量。

每个槽位只有四种终态:成功、失败、跳过、取消。四个数加起来应当等于当日槽位数。这个等式是所有对账的基础,它不成立,说明有槽位丢了状态——通常是程序在中途退出,没来得及写。发现不成立时先补状态,不要先分析原因。

三种差异的原因归属要分清。跳过属于闸门或健康闸,看当日闸门记录就知道是哪一条规则挡的;失败属于执行层,看设备日志和界面快照;取消属于人工干预,要记录是谁取消的、为什么。如果三类混在一起统计成未按计划发布,每周会看到十几个数字,但一个都修不了。

对账项算法异常时的含义
槽位守恒成功加失败加跳过加取消等于槽位数有槽位丢了状态,先补记录
时间偏差实际时间戳减计划时间执行环节变慢,或槽位本身靠后
内容一致台账里的标题价格与计划值比对发布前有人改过内容
同款计数按指纹分组后统计每组条数超出三条,说明结构规则没生效

时间偏差这一项要分开看两种情况。一种是槽位本身靠后,计划时间就是窗口末端,实际执行也接近末端,偏差很小;另一种是执行环节慢,计划时间在前面,实际拖到了后面。前者不是问题,后者才是。区分方法是对比同一天的多个槽位:如果所有槽位都往后拖固定的量,是执行慢;如果只有末端几个槽位拖,是排期太满。

内容一致这一项容易被忽略,但它能抓到一类隐蔽问题:发布前有人改了文案或价格,台账记的是实际值,计划里是原值,两边不一致。不一致本身不一定是错——临时改价是正常操作——但如果没有记录,这件事就变成了一个无法解释的差异。做法是允许改,但改要留记录,谁改的、什么时候改的、为什么改。

同款计数要从台账里算,不要靠人记。按商品指纹分组,看每组的条数分布:如果出现某组超过三条,说明结构规则在某个环节被绕过了——可能是手工插入、可能是流程里没走闸门。这类问题靠肉眼翻台账几乎不可能发现,靠分组统计一眼就能看到。

对账的频率跟排期一致,一周一次。每天看会看到大量瞬时差异,分不清是真问题还是进度。一周一次,看三项:槽位守恒是否成立、三类差异的比例、顺延队列的深度。任意一项连续两周恶化,才值得动参数。

07  /  模块接口

台账和合规、风控、排期的接口

台账不是一份孤立的记录,它是几个模块共同的落点。每个模块往里写什么、从里读什么,定清楚了,几个模块才能互相校验;定不清楚,台账就会变成一堆字段的堆积。

从排期读:这一条该在什么时候发

排期给出计划时间与槽位编号,台账记录实际时间与槽位编号。两者用同一个槽位编号,对账才能按槽位做。槽位归属由同一个函数算出,不靠人工标注,所以两边的编号天然一致。

从合规读:这一条为什么被放行或被拦

合规闸门的结论要留下来,包括命中的规则与规则版本。台账里成功发布的记录应当能追到一次通过的复检;跳过状态的记录应当能追到命中的规则。没有这个连接,跳过就只是一个数字。

向风控供:相似度与分布的原始数据

风控要算的相似度、类目分布、时间分布,全部从台账的字段算出来,不需要另存一份。这也是单一口径的另一个好处:同一份数据既是记录,也是风控的输入。

向复盘供:可用于结论的最小集合

item_id、标题、描述、价格、时间戳,这五项能支撑绝大多数复盘问题。少一项,某个问题就答不了;多一项,维护成本上升但没有对应的问题。

接口定清楚的一个直接好处是排除了双份数据。很多系统里,排期有自己的一份表、合规有自己的一份日志、台账又是第三份,三份数据描述同一件事,任何一处不一致都要花时间判断谁是对的。正确的做法是:只有台账是权威来源,其他模块要么往里写,要么从里读,不各自维护副本。

要做到这一点,写入必须集中。两条通道自己不做格式化、不做成功判定,只把原始结果交给写入模块,由它统一判定与落盘。这个模块很小,但它是一处收口——所有数据从这里进,所有口径在这里定义。它跑在什么路径、写哪个文件,都要显式配置,不能靠推断。

读的一侧同样要有约定。报表、风控、排期都从台账读,读的时候用同一套字段名与状态枚举。任何模块想加一个自己的字段,加在台账里并写进文档,不要在自己的模块里另存一份衍生字段——衍生字段一旦另存,就和源头脱钩了,源头改了它不会跟着改。

这套接口在多设备并行时会受到压力:多台设备同时回写结果,写入模块要能处理并发。并发处理不当的表现是丢记录或交错写入,两者都不会报错,只会在对账时表现为槽位守恒不成立。设备侧怎么分工、并发怎么控制,见多设备并行管理;发布监控告警怎么接在这套数据上,见闲鱼发布监控告警。

08  /  复盘

复盘的方法,和几种看着像复盘的错

台账有了、报表有了,复盘做错的方式仍然很多。最常见的几种,共同点是用数据讲了一个自己已经相信的故事。

错法一:只看总量不看结构

这个月发了一百条,上个月八十条,看起来在增长。但如果这一百条里有一半集中在同一类目、标题高度相似,结构上是变差了。复盘要先看结构,再看总量。

错法二:用发布量解释成交

发布量涨、成交涨,中间隔着曝光、点击、问询、议价。台账只覆盖第一层,用它解释后面几层,结论一定错。要看成交,得把平台侧数据接进来。

错法三:拿一次波动当趋势

某一周成功率低了两条,就改参数。改完这一周,下一周的基线没了,从此每周都在重新开始。看趋势至少需要连续三周的同口径数据。

错法四:改了参数不记

参数改过但没留记录,后来看到数字变了也说不清是怎么变的。参数变更要与当期数据一起记,否则复盘没有依据。

正确的复盘顺序是:先确认口径没变,再看结构,再看趋势,最后才归因。口径变了的情况下,任何跨期比较都不成立,这时候第一步是先修口径,不是分析。判断口径有没有变,看三件事:字段有没有增删、状态枚举有没有变、时间戳取的时刻有没有换。三项都没变,才可以比较。

看结构的意思是:把这一期的数据按类目、按通道、按时段、按相似度分组,看分布是不是比上期更集中。集中度上升但总量也上升,说明是在同一个方向上堆量,这种增长不可持续;集中度下降而总量持平,往往是更好的状态,因为可扩展的空间变大了。

看趋势要拉长。周维度的数据有噪声,一条商品的失败就能让成功率掉几个百分点。三周以上的同口径数据才能看出方向。如果每周都在改参数,就永远得不到连续三周的基线——这是为什么参数变更要克制,改一次至少观察三周。

归因要落到可动的项上。成功率下降,归因到"平台变严"没有意义,因为它不可动;归因到"某一类模板的标题在这批商品上被拦得多",就可以改模板。归因的价值在于它指向一个具体动作,不指向动作的归因只是解释,不是复盘。

最后留一份复盘记录:这一期的口径、结构、趋势、改了哪一项参数、下一期要看什么。这份记录是下一期复盘的起点,没有它,每一期都是第一次。相关的判断方法在闲鱼发布监控告警里有更细的告警口径,四个模块的整体关系见产品功能总览。

两条通道各记一本表,合并时注意什么?
先修口径再合并。要统一四件事:字段名、时间戳取哪个时刻、成功判定以什么为准、去重键用什么。这四项不统一,合并出来的数字会互相矛盾,而且矛盾的原因很难定位。最省事的做法是让两条通道写同一本台账,由同一个写入模块负责判定与落盘,口径只在一处定义。
提交成功了,但没有 item_id,算不算发布成功?
不算。item_id 要从回执里取,取不到就说明这条商品在平台上无法被定位。正确做法是先归入失败并写清原因,等一轮之后再回读一次,仍然不到就人工确认。不要直接重试发布,重试可能造出一条重复商品,比缺一条更麻烦。
台账为什么不能直接覆盖修改?
覆盖会破坏所有跨期比较。改一条记录,损失的不只是那一条,而是以它为基准的趋势判断。正确做法是追加一条新的状态记录,原行保留。需要当前状态时取最后一条,需要过程时全部读出来。
自检数据写进生产台账这类事故怎么防?
四道防护一起做:数据目录用绝对路径写在配置里,不依赖环境变量;任何改动正式台账的操作先落一份备份并读回验证;自检进程带标记,带标记的进程写生产数据直接抛错;整轮自检前后对生产文件做哈希比对。前两道防写错地方,第三道防写错之后继续,第四道是最后的网。
成功率怎么算才对?
分母是当日槽位数,不是当日发布条数。用发布条数当分母,跳过和取消的条目会被排除,成功率会虚高。四态齐全的账本才具备算这个指标的条件,这也是为什么状态只允许成功、失败、跳过、取消四个,不随意新增。
从台账能看出成交情况吗?
不能。曝光、浏览、问询、成交都发生在平台侧,不在本账范围内。台账覆盖的是发布这一层:发了什么、什么时候发、成没成功、有没有被拦。用它去解释成交,中间隔着好几层转化,结论一定不可靠。
计划时间与实际时间差得多,说明什么?
要分开看。如果同一天所有槽位都往后拖差不多的量,是执行环节变慢;如果只有窗口末端的几个槽位拖,是排期太满。两种情况的处理不同,前者查设备和上传耗时,后者调当日条数。用平均值看不出来,要看偏差分布。
复盘多久做一次比较合适?
跟排期同步,一周一次。日看四个数(槽位、成功、失败、跳过),周看分布与趋势,月看结构是否需要调整。判断趋势至少需要连续三周的同口径数据,所以参数不要每周都改,改一次至少观察三周。

先跑通一条真实发布,再谈铺量

把账号、设备、商品素材交给我们的部署流程,先跑通一条真实发布并留下可核对的日志,确认没问题再谈规模化。