去年园区项目上线第三周,招商总在群里甩了一句,「B座现在空着多少间」。系统三秒回了「17间」。他回了个问号,接着问,「这17间怎么算出来的」。
那一刻我有点慌。我们花了一个月把 NL2SQL 跑通,答得快,答得像模像样,可真要解释「数从哪来」,我俩都卡住了。
后来我摸清了门道。问数平台能不能上生产,门槛不在「会不会把人话翻成 SQL」,在「它给的答案,业务方能不能自己核对」。一个数如果没有来路,哪怕再自信,也只是个没凭据的猜测。
先交代一句背景,免得它显得没来路。园区日常跑着一套数字化管理平台,招商、合同、账单、巡检、物联全在里面,房源、租客、合同、账单四类主数据老老实实躺在库里。问数平台没有另起一套业务系统,它只是接在旁边的一个只读问答层,负责把人的问题翻成查询、再翻回人话。这篇不聊它怎么建模、怎么接网关,单说一件事,怎么让它的答案经得起复核。
黑盒答案的代价
早先我们偷懒,模型吐什么数业务就用什么数。出过一回真事。
财务月底对收缴率,系统给的是 92%。她没多想,报上去了。隔天运营拿着台账一对,说不对,实际应该 81%。差的那 11 个点,是因为模型把「往期欠费」也塞进了分母。SQL 没报错,数也算出来了,可口径从根上就偏了。
问题不在模型笨。在于它只给了你一个孤零零的结果,没给任何能让你判断对错的线索。你拿着 92% 去找谁吵,吵不出名堂。
换成可核对的写法,系统除了回数字,还会把分母定义、时间窗、数据日期一起亮出来。财务扫一眼分母,马上说「你这应收含了往期,重算」。吵得出来,才是好事。
我们把答案拆成几段给人看
现在每次问答,返回的不是一个数字,是一整段带证据的东西。大致长这样。
{ "question": "本月各楼栋收缴率", "sql": "SELECT bld.name, sum(b.paid)/NULLIF(sum(b.due),0) ...", "rows": [ {"楼栋":"A","收缴率":0.81}, {"楼栋":"B","收缴率":0.88} ], "caliber": "应收=当期应收,不含往期欠款;时间窗=自然月", "data_date": "2026-10-24" }你可以把它拆成五块。
提问原文,系统先复述一遍你问的是什么,避免它理解错了你还不知道。
生成的 SQL,原样摊开。这步最要紧,业务看不懂 SQL 没关系,但技术或者财务能拿去库里跑一遍。
中间结果,也就是那张 rows 表,让人看到聚合前长什么样。
统计口径,用大白话写清「怎么算的」,比 SQL 更接地气。
数据日期,标明这个数截止到哪天,免得拿上周的数当本周的用。
五块凑齐,一个答案才算是「可核对」的。缺一块,信任就塌一块。
按规则计算,别让模型即兴发挥
可核对有个前提,计算本身得是可复现的。收缴率、逾期金额、空置率这类指标,不该由模型现场发挥,得有写死的规则。
我们在语义层之外又叠了一层计算规则,大致长这样。
metrics: collection_rate: formula: paid_amount / NULLIF(due_amount, 0) due_amount: "当期应收,不含往期欠款" window: "自然月" overdue_amount: formula: sum(balance) filter: "账单到期日 < 今天 AND 余额 > 0"这块和语义层分工不同。语义层解决「查哪个字段」,规则层解决「字段怎么算」。两层分开,改口径只要动配置,不用去碰提示词,模型感知不到变化,也不会因为一次微调把别的数带歪。
有个细节值得记一下。规则写进配置,比写进 prompt 稳得多。prompt 里写「收缴率不含往期」,模型理解不稳定,换个问法可能就忘了。配置是硬约束,跑出来就是那个值。
样例库其实是回归测试
光有规则和口径还不够,我们还攒了一库 FewShot 样例。每条是四元组,问题、意图、SQL、口径。
{ "question": "下个月有哪些租约到期", "intent": "contract.expiring", "sql": "SELECT * FROM park.lease_contract WHERE end_date BETWEEN current_date AND current_date + 30", "caliber": "到期日落在未来30天内,不含已续签" }库里现在六十来条。新问法只要沾边就命中,比反复调提示词省事。
但我后来发现它更大的用处不在「教模型」,在「守系统」。每次我们动语义层或者改了规则,就把这六十条重新跑一遍。如果「下月到期合同」生成的 SQL 跟之前不一样了,说明改动把别的地方带崩了。这些样例慢慢变成了我们的回归测试集,也是答案可核对的基准线。
经验能复用,系统也变得可防回退。这两件事其实是同一件事。
上线之后发生的反转
系统能摊开 SQL 之后,财务反倒开始挑刺了。不是挑我们的刺,是挑数据的刺。
有回她核对出来,台账里 12 间房状态标错了,以前靠人肉兜底,谁也没觉得有问题。现在系统直接算,错得明明白白,运营跑来追着我改数。我一边改一边觉得,这其实是好事,数据烂就让它早点烂在台面上。
招商那边也变了。以前问数得发群等运营查,现在自己问自己看。有回他问完没追着问「怎么算的」,自己点开下面的 SQL 扫了一眼,说「哦,含了往期」,接着就去改台账了。那一下我挺踏实,说明他信这个数了。
几条踩过的坑
答案里必须带统计口径和数据日期。少了这两样,别人拿什么核你。
计算规则写成配置,别塞进 prompt。配置是硬约束,prompt 是软建议。
答不出就明说,别硬编。编出来的数比「不知道」危险十倍,因为它看着对。
把样例库当测试资产养着。每次动语义层,先跑一遍,心里才有底。
收个尾
问数平台这东西,炫技的部分其实最不值钱。真正值钱的是,它敢不敢把取数逻辑摊开,让一个不懂 SQL 的人也能说一句,「这数我信」。
我们那个项目,从「答得快」走到「答得让人信」,花的时间比搭管道长得多。但走完这一步,招商总和财务才真的把它当成自己的工具,而不是一个偶尔灵光的玩具。