做 To B 的人都有同一条痛点:信息不是不公开,而是公开了没人盯。政策今天发、招标明天挂,等到你想用的时候,窗口已经关了。苏运AI 的做法是把它拆成两个独立引擎,各跑各的:政策引擎只管「抓原文、留快照」,招标引擎只管「捞机会、去重、入台账」,两者都不烧模型额度。今天把流水线的骨架和两条纪律讲透。
政策引擎的职责很窄:从官方源把标题、链接、发布时间抓下来,不做任何解读。解读交给 AI 单独一步做,两件事物理隔离。
为什么必须隔离?因为抓取是确定性的(同样的源、同样的时间窗,结果可复现),解读是不确定性的(模型每次输出措辞都不同)。如果把两者揉在一个脚本里,一旦模型输出跑偏,你无法判断到底是「源没抓到」还是「模型编了」。隔离之后,抓取层出错会立刻表现为「条目数异常」,一眼定位。
实现上有个容易被忽略的细节:快照与页面要分开存。当天真实抓到的条目写进当日快照(这才是「今天新增」),页面渲染时如果条目不够,用最近几天的快照滚动补位——补位内容只用于排版,绝不写回快照。这样避免了「补位内容被当成新政策,一天天滚雪球越滚越老」这个经典 bug。
招标引擎的输出形态是一条条机会:项目名、预算、截止时间、招标人、来源链接。但真正决定它有没有用的,不是抓得多,而是去重准不准。
去重的关键动作只有一个:写入前先问「台账里有没有同名项目」。看起来朴素,但它解决了情报系统最致命的一种失败——把昨天报过的当成今天的。一旦客户看到「连续三天推同一个标」,信任就没了。
还有一类更隐蔽的重复:同一标的不同批次。比如一个物业标第一次招标流标、重新招标,预算可能不变也可能调整,项目编号会变。这类条目既不能当「完全重复」丢掉(限价可能上调,是新机会),也不能当「全新项目」重复计数(同一个标)。正确做法是:入台账,但显式标注批次差异,让看的人自己判断。今天巡检里就有一条这样的——松陵街道六个政策性住宅小区物业,上一批 09-11 已入台账,本次是第二次招标、限价从 1872.88 万上调到 2310.90 万,如实标注重招而不是当新标报喜。
把文件推到服务器上、命令返回 rc=0,只能证明「文件写进去了」,不能证明「用户看到的是这一版」。中间可能隔着缓存、可能服务器做了转码、可能同名旧文件覆盖了新文件。
所以校验必须回到内容层:部署完成后独立发一次请求,把线上正文拉回来,检查两件事——① 字节数/MD5 是否与本地一致;② 关键标记是否在正文命中(今天日期、品牌标记等)。
为什么要有第②项?因为真实遇到过服务器侧转码导致字节数对不上的情况——文件其实是新版本,内容也是对的,只是字节不完全一致。此时若只看哈希就判定失败并反复重传,是纯粹浪费通道(还可能把好文件覆盖坏)。正确的降级顺序是:哈希不符 → 看内容标记是否命中 → 命中则判成功(附警告),未命中才判失败并进入重推流程。
部署失败不等于远端死了。必须分三种情况处理:
配套的硬约束:批量部署每批不超过 10 个文件。一次推 20 多个文件,一是超时概率陡增,二是失败时你分不清是哪个文件、还是通道整体挂了。小批次让每次失败都局部可归因。
把工作分层后,AI 的位置就很清楚了:抓取、去重、校验、回读——全是零成本的确定性代码;解读、写作、归因——才是 AI 的活。这个分层带来两个直接好处:
① 成本:日常 90% 的运行不调用任何模型,只有「今天有什么值得说」才用一次模型。
② 可信:AI 只在「输入已经确定」之后出场,它的错误只会出现在措辞和归因,不会出现在「事实本身」——因为事实是抓来的、逐条带来源和时间。
这套「双引擎 + 两条纪律」的骨架,就是苏运AI 对外做 AI 代运营 / 工作流 / 情报站 时的标准件:把你所在行业每天在公开渠道冒头的信息(政策、招标、行情、竞对),做成日更、可溯源、不重样的情报流水线,然后直接接到销售或交付环节。情报的保鲜期以天计,越早一天拿到,窗口就多一天——这正是我们把它做成自动化的全部理由。