手上有一张几万行的银行流水表:日期一列混着"2026/3/5"和"20260305",金额一列是带千分位的文本。要把日期统一成标准格式,把五万以上的交易筛出来按金额排序,再按对手方汇总进出总额。
这一份,你咬咬牙手工也能做完。
真正的问题在后面:电脑里还有几百份同样格式的表,每一份都要做一模一样的加工。手工做,是按周计的体力活。让大模型做,听起来顺理成章——把要求说一遍,让它把几百份全做掉。但这类数据碰不得公网,很多机构的红线是:流水表一个字节都不能出内网。
于是需求变成了:离线、本地,在一张 RTX 4090(24G 显存)这样的消费级显卡上,让一个塞得进显存的小模型,替你把几百份表格加工掉。
我们为此做了一个本地 Excel 加工 Agent,顺手把 Agent 圈的一个默认答案拉出来正面实测了一轮,有些结果把我们自己都说服了。
两条技术路线
"让模型写代码",是这两年 Agent 圈处理数据任务的默认答案。要处理表格?让模型写 Pandas。好处实实在在:最灵活,也最轻量——不需要预先设计任何加工能力,一个代码解释器就是全部基建,再长尾的需求都能表达。在能访问云端大模型的场景里,这确实是最优解。
但我们的场景是离线的。内网里没有云端旗舰,只有本地小模型——27B 这个量级,4bit 量化后 24G 显存刚好装得下。问题就来了:小模型写代码,行不行?
所以我们准备了第二条路线:让模型"点菜"。预先设计一份固定菜单——11 个列算子(日期标准化、金额清洗、值映射、拆列合列这些)加 6 个行过滤谓词(等值、区间、包含这些)。模型不写代码,只从菜单里挑合适的项、填好参数,组合成一份加工配方;真正动数据的是本地的确定性引擎,每个算子都是提前写好、测好的代码。
区别的本质:进后厨,模型的输出空间是"任意代码";点菜,输出空间是"合法配方"。前者出错的方式有无穷多种,后者屈指可数。
孰优孰劣,不靠感觉,测了才知道。
工具面是怎么设计的
菜单之外,还有三条规矩。
第一条:全量数据永远不进模型。模型"看表"时只拿到表头和每列不超过 10 个采样值——几万行数据,它一行完整的都看不到。采样值足够判断"这列是日期、格式混乱",但泄露不了任何一条完整记录;顺带上下文极小,小模型的窗口也装得下。
第二条:执行前必须预览,确认后不许变卦。模型提交配方后,引擎返回前 20 行的前后对照和一个预览凭据;用户确认后,模型只能凭这个凭据执行刚刚预览过的那份配方——不能重新预览,不能偷偷改参数。就像装修:报价单签了字,施工必须按签字那份来。
第三条:逐列失败不废整行。某个单元格转换失败,保留原值、计入统计,不废整行,更不允许静默丢行——加工完行数对不上就是缺陷,没有商量余地。
配方这个设计,还藏着开头那个"几百份文件"问题的答案:配方是确认一次、可以反复用的资产。在第一份表上看过预览、点了确认,配方就定型了;剩下几百份同构的表,是同一份配方的逐份确定性重放,第 300 份和第 1 份的执行逻辑一字不差。写代码当然也能复用,但代码里若埋着一个不报错的 bug,它同样会一字不差地复制几百遍。
怎么测的,结果怎么样
测评用一张 2998 行、38 列的模拟银行流水,出了八道题:日期原位标准化、高额交易筛选排序、按类型筛选、去重、分组聚合、方向映射、缺失清理、筛选后汇总——都是真实数据加工里最常见的形状。
判分只认 Agent 实际生成的那个下载文件:逐列、逐行、逐单元格和冻结的标准答案比对;行数、列序、排序、源文件是否被改动、结果里有没有活公式,任何一条硬门失败,整题判负。判产物,不判话术——模型聊天时"我已经为您完成了转换"说得再自信,都不加一分。
四个模型上场:云端的 DeepSeek-V4-Flash 和 Qwen3.6-35B-A3B,本地的 Qwen3.6-27B 和 Gemma4-31B(都是 4bit 量化跑在单张 RTX 4090 上)。前三个两条路线各跑一遍,Gemma 只跑了工具路线,温度统一为 1。
云端旗舰 DeepSeek 两条路线都是 8/8——模型足够强时,写代码确实又灵活又轻量,怎么走都能到终点。
反转在往下的每一档。Qwen3.6-35B-A3B(每次推理只激活 3B 参数),工具路线 7/8,写代码路线掉到 3/8——同一个模型换条路线,成绩腰斩不止。而本地单卡上的 Qwen3.6-27B,工具路线 8/8、均分 98.1,和 284B 旗舰的 99.4 几乎打平。写代码路线的成绩随模型变小塌方得非常快,工具路线却把一个 27B 的本地模型,直接抬到了旗舰档位。
结果解读:写代码输在哪
先看写代码路线的三种死法。
一是只说不做:35B-A3B 有四道题,看完表结构就开始解释"我打算写这样一段代码",代码块贴在聊天里,却始终没有提交执行——如果判分听话术,这四道题它都"完成"了。
二是修不好:有一道题它确实执行了,报了 KeyError,改一版再报,连改七次也没跑通。
三是静默失真,最吓人。本地 27B 只挂了一道题:筛选、行数、列、排序全对,但生成的代码顺手把金额列从文本转成了数值——"191000.00"变成"191000",20 个单元格丢了小数位,四条同额记录的排序还发生了漂移。文件正常生成、打开毫无异样。错误不报错,这是数据加工里最危险的一类失败。再想想开头的场景:这段代码要套在几百份文件上,就是几万个不会报错的错误数字,没有人会逐份打开核对。
对照工具路线的失败:35B-A3B 有三道题第一次参数填错——漏了必填的上限、多塞了不存在的字段——引擎返回结构化报错,直接指出缺什么,三道题全部在下一轮修复,最终文件全对。唯一真正的失败,是一道聚合题陷入长循环被超时掐掉——败得明明白白,用户看到的是"任务失败",不是一张看起来没问题的错表。
为什么会这样?就三条。输出空间小:让小模型稳定写出几百行全对的代码很难,从 17 个选项里挑几个、填对参数,难度不在一个量级。报错可自救:配方不合法,引擎的报错是类型化、指名道姓的,模型拿到就知道怎么改;代码报错是一段 traceback,小模型经常越修越乱。安全面小:要安全地执行模型写的任意代码,需要沙箱、断网、文件系统隔离、资源看门狗一整套工程,省一层就是把主机交给模型;工具路线天然没有"任意代码执行"这个攻击面,引擎只做菜单上那 17 件事。对离线交付到客户环境的软件来说,这一条的分量不比准确率轻。
小结:场景决定路线
这不是"代码模式无用论",两条路线是场景分工。能访问云端大模型时,让它写代码依然最灵活、最轻量——DeepSeek 双 8/8 就是证据,代码也是固定菜单覆盖不了的长尾需求的逃生舱。所以产品上我们默认走工具路线,写代码作为显式开启的高级能力保留。
测评也有边界:八道题、单次全量运行,是能力测评不是稳定性统计;测的是单份文件的正确性,批量靠的是配方重放机制本身的确定性。Gemma4-31B 工具路线只有 6/8——工具设计是杠杆,不是魔法,抬得动 27B 不代表抬得动所有模型。速度上,本地 27B 单题平均两分钟,云端旗舰只要 25 秒,本地化省的是合规成本,不是时间。
但对必须离线、电脑里压着几百份同构表格的场景,方向是清楚的:与其等一个塞得进显卡的"更强模型",不如把工具面设计好——模型只负责在第一份表上把配方点对,剩下几百份交给确定性引擎重放。一个 27B 的本地小模型就够用,顺带把"模型乱写代码"的安全风险关在门外。
如果你也面临类似问题:数据不能出内网、几百份表格等着做同样的加工,或者想交流 AI Agent 在离线场景的落地问题,欢迎添加我:
#技术分享与交流