从语法正确到结构可信——大模型财务公式生成的失效机理、验证框架与工程治理路径
摘要
大语言模型编码助手在生成Excel、Power Query、DAX乃至Python财务公式时,常表现出一种特殊失效:公式语法无误、单点计算正确,却在借贷平衡、期间归属、科目层级与循环引用等会计结构约束上系统性出错。本文以"结构语义缺失"为贯穿主线,先界定财务公式的三层正确性(语法正确、数值正确、结构正确),再从训练语料的表面对齐、上下文窗口的结构失忆、评测基准的结构盲区三条路径剖析失效机理;随后给出结构契约建模、AST级静态校验、属性化回归测试与人工复核闸门组成的四段式治理框架,并附可操作的验证步骤与代码片段;继而讨论模型能力边界、成本收益与合规风险;最后展望结构感知生成与形式化验证结合的前沿方向。本文认为:AI写的公式"能不能信"不是一个二元问题,而应转化为"在何种结构校验强度下可以信"的工程问题。
目录
一、问题的提出:一个被低估的失效类别
过去两年,编码助手从"补全一行代码"迅速演进为"生成一段可运行逻辑"。在财务与会计场景中,这一能力被大量用于生成报表取数公式、合并抵销分录、现金流勾稽校验以及预算模型的联动计算。表面上看,这类任务比通用软件开发更"规整":输入输出明确、规则可枚举、错误可被数值检验。然而一线实践反馈出一个反复出现的现象——模型给出的公式往往"跑得通、算得对、但结构不对"。
所谓"结构不对",典型表现包括:把资产类科目的借方发生额直接与负债类科目的贷方发生额相加;在跨期分摊公式中遗漏权责发生制的期间切分;在科目层级汇总时把明细科目与总账科目重复计入;在滚动预测中构造出隐式循环引用却未设置迭代开关;在合并报表抵销中把内部交易与内部往来混为一谈。这些错误有一个共同特征:它们不违反公式语言的语法,也不一定违反单笔业务的数值直觉,但违反了会计信息系统赖以成立的结构约束。
这一失效类别之所以被低估,是因为现有讨论多集中在"模型会不会算错数"(幻觉、算术错误),而较少讨论"模型懂不懂账"(结构语义)。前者可以通过计算器工具调用、代码执行沙箱大幅缓解;后者却无法靠"再算一遍"解决,因为错误发生在建模阶段而非计算阶段。笔者认为,把这两类问题混为一谈,是当前财务AI落地评估中最大的方法论偏差之一。
本文的主线由此确立:财务公式的可信度问题,本质上是"结构语义能否被生成、表达与验证"的问题。围绕这条主线,本文依次回答四个问题:结构语义包含什么(第二章)、它为何在生成中丢失(第三章)、如何用工程手段补回并验证(第四章)、补回之后还剩哪些边界(第六章)。
二、背景与概念界定:财务公式的三层正确性
2.1 三层正确性的定义
为避免"对不对"这种模糊判断,本文把财务公式的正确性拆为三层,并给出可操作的判定标准。这一分层是后续所有讨论的分析基座。
L3 的难点在于它不是某个具体数值的属性,而是一族输入的属性。一个公式可能在当前样本上算对,却在科目新增、期间切换、汇率变动后暴露结构缺陷。这决定了 L3 的验证必须采用"属性化"而非"样例化"的思路,这一点将在第四章展开。
2.2 会计结构约束的形式化清单
会计结构约束并非玄学,它可以被相对清晰地枚举。本文将其归纳为五类,每类都对应可编程的检查规则。需要说明的是,这一清单是工程视角的归纳,而非会计准则的完整表述;具体口径应回到企业会计准则与内部会计制度原文核对。
- ① 借贷平衡约束:任何一笔分录的借方合计等于贷方合计;报表层面资产等于负债加所有者权益。公式若跨越不同性质科目直接相加,即违反此约束。
- ② 期间归属约束:收入费用按权责发生制归属期间,跨期项目需通过待摊、预提或摊销科目过渡。公式若用收付实现制口径直接计算利润,即违反此约束。
- ③ 科目层级约束:总账与明细账存在汇总关系,同一笔金额不得在父子科目间重复计入。公式若同时引用父科目与子科目,即可能违反此约束。
- ④ 方向与符号约束:资产类借方为正、负债类贷方为正,不同科目族的符号约定不同。公式若统一按"发生额"取数而不区分方向,即违反此约束。
- ⑤ 依赖无环约束:报表项之间的计算依赖应构成有向无环图,循环引用需显式声明迭代。公式若隐式形成环,即违反此约束。
本文评述:这五类约束的共同点是"局部合法、全局非法"——单看一个单元格的公式,往往挑不出毛病;只有把它放回科目体系与报表勾稽网络中,缺陷才显现。这恰好解释了为什么"逐条审公式"的人工复核效率极低,也解释了为什么模型在逐token生成时难以自我发现这类错误。
2.3 为什么财务公式是"结构敏感"任务
与一般业务公式相比,财务公式有三个放大结构风险的特性。其一是强类型化:每个科目自带方向、层级、报表归属等元数据,公式必须尊重这些类型,而不能像处理普通数字那样自由运算。其二是强耦合:一张报表的公式依赖另一张报表的结果,勾稽关系构成稠密网络,一处结构错误会沿网络传播。其三是强审计性:财务结果需要可追溯、可复核,公式本身即是审计证据的一部分,结构缺陷会直接转化为审计风险。
这三点叠加,使得财务公式生成成为检验编码助手"结构理解能力"的极佳试金石。笔者认为,如果一个模型连借贷平衡这种最基础的结构约束都难以稳定保持,那么它在其他"结构敏感"领域(如权限模型、事务边界、状态机)的表现也值得警惕。
三、失效机理:结构语义为何在生成中丢失
3.1 训练语料的"表面对齐"偏差
公开语料中充斥着大量"看起来像财务公式"的文本:论坛问答里的SUMIFS示例、教程中的VLOOKUP取数、博客里的DAX度量值。这些片段大多只展示"如何取到数",很少附带完整的科目体系、方向约定与勾稽关系。模型从中学到的是公式的表面形态与常见搭配,而非其背后的会计结构。当用户要求生成"利润表营业收入公式"时,模型倾向于复现语料中高频出现的"求和+条件筛选"模式,而未必意识到营业收入需要区分主营与其他业务、需要按净额法或总额法处理、需要与应收账款变动勾稽。
本文评述:这不是简单的"数据不够多",而是"数据里结构信息密度太低"。即便把语料扩大十倍,若其中仍是大量脱离上下文的公式片段,结构语义的习得效率也不会线性提升。这提示了一条更务实的路径——与其指望模型从语料中"悟"出结构,不如在推理阶段把结构显式喂给它。
3.2 上下文窗口的"结构失忆"
即便用户提供了科目表与报表模板,模型在长上下文中仍会出现结构信息的衰减。工程观察表明,当上下文超过一定长度后,模型对早期出现的约束(如"负债类科目贷方为正")的遵循度会下降,转而被近期出现的局部模式带偏。这一现象与长上下文检索的"中间遗忘"问题相关,在需要同时满足多条全局约束的任务中尤为明显。
更隐蔽的是"约束冲突时的静默取舍"。当用户提示中同时包含"按借方发生额取数"与"该科目为负债类"两条信息时,模型往往不会指出冲突,而是默默选择其中一条生成公式。这种静默取舍比直接报错更危险,因为它把结构矛盾藏进了看似正常的公式里。
3.3 解码目标的"局部最优"陷阱
从生成机制看,自回归解码逐token优化的是局部似然,而结构正确性是全局属性。一个在每一步都"最像财务公式"的序列,未必整体满足借贷平衡。这与代码生成中"语法正确但语义错误"的问题同源,只是在财务领域,语义错误的表现形式恰好是结构违规。
# 一个典型的"局部合理、全局违规"生成示例(模拟)
# 用户意图:计算资产负债表"应收账款"期末余额
# 模型生成(错误):
ar_ending = sales_revenue + ar_beginning - cash_collected
# 问题分析:
# 1) 收入含税/不含税口径未区分,直接与应收相加违反计量口径约束
# 2) 未考虑坏账准备、票据重分类,违反科目层级约束
# 3) 若sales_revenue为利润表期间数、ar_beginning为时点数,
# 期间归属约束被隐式破坏
# 正确结构应为:
# ar_ending = ar_beginning + 本期赊销发生额(不含税) - 本期收回 - 核销 ± 重分类
上例中,模型的公式在"数量级"上往往是对的,因此很容易通过粗粒度的数值抽查;但它在结构上把三个不同口径的量直接混合,属于典型的 L3 失效。笔者认为,这类错误之所以顽固,是因为它恰好落在"看起来对"的甜点区,逃过了大多数轻量校验。
3.4 评测基准的"结构盲区"
现有代码生成评测多关注"能否通过单元测试",而财务公式评测若只比对最终数值,就会系统性忽略结构缺陷。一个只检查"期末余额是否等于预期值"的测试,无法区分"结构正确"与"多个结构错误相互抵消"。这导致模型在基准上的得分与其真实结构可靠性之间存在落差。
本文评述:评测基准的设计直接塑造模型优化方向。若基准不含结构维度,模型厂商就没有动力去提升结构遵循能力。因此,构建带结构断言的财务公式评测集,不仅是学术问题,更是推动整个生态向可信方向演进的杠杆。
四、治理框架:结构契约、静态校验与回归测试
既然结构语义难以指望模型自发习得,工程上更可靠的策略是"外部化结构、机器化校验"。本章给出一个四段式框架:结构契约建模 → 生成时注入 → 生成后静态校验 → 属性化回归测试,并在关键节点设置人工复核闸门。该框架不依赖特定模型,可迁移到Excel、Power Query、DAX、SQL与Python等多种载体。
4.1 第一步:把会计结构写成机器可读的契约
结构契约(Structural Contract)是对科目体系、方向约定、层级关系与勾稽规则的显式声明。它的作用是把"老会计脑子里的常识"变成"程序可检查的约束"。一个最小可用的契约至少应包含:科目编码与名称、科目类别(资产/负债/权益/收入/费用)、余额方向、父子层级、报表归属、以及关键勾稽等式。
# 结构契约片段示例(YAML,模拟数据)
accounts:
- code: "1122"
name: "应收账款"
category: asset
normal_balance: debit # 余额方向
parent: "1122"
report_line: "应收账款"
children: ["112201", "112202"]
- code: "2202"
name: "应付账款"
category: liability
normal_balance: credit
report_line: "应付账款"
constraints:
- id: "balance_sheet_identity"
expr: "total_assets == total_liabilities + total_equity"
tolerance: 0.01
- id: "no_parent_child_double_count"
expr: "sum(leaf_accounts) == sum(all_accounts) - sum(parent_only)"
- id: "accrual_period"
expr: "revenue_period == delivery_period"
契约的粒度需要权衡:过粗则校验无力,过细则维护成本高。笔者的经验是,先覆盖五类结构约束中"最常被违反"的两三类(通常是方向约束与层级约束),再逐步扩展。契约应纳入版本管理,与报表模板同步演进。
4.2 第二步:生成时注入结构上下文
在提示工程层面,应把契约的关键子集随任务一并注入,而非整份契约。注入内容建议包括:目标科目及其方向、涉及的勾稽等式、以及"禁止事项"清单(如"不得同时引用父子科目")。同时要求模型在生成公式前先输出一段"结构说明",列出它打算使用的科目、方向与勾稽依据。这段说明本身不保证正确,但它把隐式假设显式化,为后续校验提供了锚点。
一个实用的提示模板结构如下:任务描述 → 相关科目契约 → 必须满足的勾稽等式 → 输出格式要求(先结构说明、后公式)→ 自检清单。本文评述:要求模型"先说明再生成"并不能消除错误,但能显著降低"静默取舍"的发生率,因为冲突一旦被写出来,人工或程序都更容易发现。
4.3 第三步:AST级静态校验
生成后的公式不应直接进入生产,而应先经过静态校验。对Excel类公式,可解析为抽象语法树(AST),检查引用单元格的科目属性;对DAX/SQL,可利用其解析器提取表与列依赖;对Python,可用AST模块遍历。校验的核心是把公式中的每个引用映射回契约中的科目元数据,再逐条比对五类约束。
# 静态校验伪代码(模拟)
def validate_formula(ast, contract):
refs = extract_references(ast) # 提取所有科目/单元格引用
issues = []
# 方向约束
for r in refs:
acc = contract.lookup(r)
if acc.normal_balance == "credit" and ast.sign_of(r) == "+":
issues.append(f"方向冲突: {r} 为贷方科目却按借方相加")
# 层级约束
codes = {contract.lookup(r).code for r in refs}
for c in codes:
if any(c.startswith(p) and c != p for p in codes):
issues.append(f"父子重复计入: {c}")
# 期间约束
if mixes_stock_and_flow(ast, contract):
issues.append("时点数与期间数直接混合")
# 无环约束
if has_cycle(ast, contract.dependency_graph):
issues.append("存在隐式循环引用")
return issues
静态校验的局限在于它只能发现"可被规则表达"的问题。对于口径选择(净额法还是总额法)这类需要业务判断的约束,静态校验只能提示"此处存在口径分支,需人工确认",而不能自动裁决。因此它是必要不充分条件。
4.4 第四步:属性化回归测试
属性化测试(Property-based Testing)的思路是:不枚举具体样例,而是声明"对任意合法输入,公式应满足某性质",再由测试框架自动生成大量输入去验证。对财务公式,可声明的性质包括:借贷恒等、期间可加性、层级汇总一致性、符号单调性等。
属性化测试的价值在于它能把"结构正确"从"某个样例正确"中解放出来。一个公式若在数千个随机合法输入下都保持借贷恒等与层级一致,其结构可信度就远高于"通过三个手写用例"。当然,生成器本身必须尊重会计约束,否则会产出大量非法输入,测试结果失去意义。
4.5 人工复核闸门:把判断留给该判断的人
自动化校验能拦住大部分结构错误,但口径选择、政策变更、特殊交易仍需人工判断。因此框架的最后一道闸门是分级复核:静态校验与属性测试全部通过的公式进入"低风险队列",抽样复核;出现口径分支提示或测试失败的进入"高风险队列",逐条复核并记录处置意见。复核记录本身应作为审计证据留存。
本文评述:治理框架的目标不是"消灭人工",而是"把人工从逐条审公式的苦役中解放出来,集中到真正需要判断力的少数节点"。这与软件工程中"自动化测试+代码评审"的分工逻辑一致。
五、关键数据与工程案例
5.1 一个模拟评测的设计与结果
为量化"结构失效"的严重程度,本文设计了一个小规模模拟评测(以下数据为模拟数据,仅用于说明方法,不代表任何真实模型或机构的实测结论)。评测集包含 120 个财务公式生成任务,覆盖资产负债表、利润表、现金流量表与合并抵销四类场景,每个任务同时提供科目契约与勾稽等式。评测分三组:A组仅给任务描述;B组给任务描述加科目契约;C组在B组基础上要求先输出结构说明并经过静态校验。
模拟结果呈现出清晰的"结构鸿沟":L1 与 L2 的通过率在三种条件下都较高,而 L3 在 A 组仅约四成。引入契约与校验后,L3 显著提升,但仍未达到 L2 的水平,说明结构正确性存在"最后一公里"——剩余失败主要来自口径判断与特殊交易。这一结果与工程直觉一致:结构问题可以被工程手段大幅缓解,但难以被完全自动化。
5.2 失效类型的分布观察
在同一模拟评测中,对 L3 失败样本按五类约束归类(一个样本可命中多类),观察到方向与符号约束、科目层级约束是最高频的两类,合计占失败样本的多数;期间归属约束次之;借贷平衡与依赖无环相对较少,但一旦发生,后果更严重。这一分布提示治理资源应优先投向方向与层级两类校验。
需要强调,上述分布是模拟数据,真实环境中的分布会因行业、科目体系复杂度、模型版本而显著不同。读者若要复用,应以自身历史错误台账为样本重新统计,而非直接套用本文数字。
5.3 工具与学习资源
工程落地需要具体工具支撑。以下链接可作为拓展入口(均在新窗口打开):
- openpyxl 官方文档:用于读写 Excel 公式与单元格,适合构建静态校验的解析入口。
- Hypothesis 属性化测试框架:Python 生态中成熟的 property-based testing 工具,可用于实现 4.4 节的测试设计。
- DAX 官方参考:理解度量值的计算上下文,是排查结构失效的重要基础。
- SQLAlchemy 文档:若财务公式以 SQL 表达,可借助其表达式树做依赖分析。
- 属性化测试相关视频检索:便于快速建立直观理解。
六、对比与局限:模型能力边界与合规风险
6.1 三种技术路线的对比
面对结构失效,业界大致有三条路线:其一是"换更强的模型",寄望于模型能力提升自然解决;其二是"外挂规则引擎",用确定性规则兜底;其三是本文主张的"契约+校验+测试"混合路线。三者并非互斥,但重心不同。
本文评述:三条路线中,"更强模型"最省事但最不可控,"规则引擎"最可控但最不灵活,混合路线在工程上最务实。关键在于把"结构正确性"的责任从模型转移到可验证的工程环节,而不是赌模型某天突然"开窍"。
6.2 框架自身的局限
必须诚实指出,本文框架有明确边界。第一,契约的完备性依赖人工梳理,若契约本身遗漏了某条结构约束,校验就会"合法地放过"错误。第二,属性化测试的生成器若设计不当,可能产出大量非法输入,导致测试通过率虚高或虚低。第三,静态校验对"口径选择"这类语义判断无能为力,仍需人工介入。第四,跨系统场景(如ERP与报表工具之间的取数口径差异)超出单点公式校验的范围,需要端到端对账。
这些局限意味着,框架应被定位为"降低结构错误概率与提升可审计性"的手段,而非"保证零错误"的银弹。任何声称能完全消除结构错误的方案,都值得警惕。
6.3 合规与审计视角
在受监管环境中,AI生成的公式还涉及责任归属问题。若公式由模型生成、经人工复核后进入报表,复核记录、版本历史与校验日志就构成关键证据链。企业应确保:生成过程可追溯(记录提示、模型版本、生成时间)、校验过程可复现(契约版本、测试用例、结果)、复核意见可归责(复核人、复核时间、处置理由)。这三点并非技术细节,而是合规底线。
本文评述:把AI生成纳入现有内部控制框架,比另起一套"AI治理"体系更现实。财务部门已有的复核、留痕、职责分离机制,稍加改造即可覆盖AI生成环节,关键是不要因为"是AI生成的"就跳过这些机制。
七、结论与展望
回到标题的问题:AI写的报表公式到底能不能信?本文的答案是——不能笼统地信,也不应笼统地不信,而应把它转化为"在何种结构校验强度下可以信"的工程判断。语法与数值层面的错误,模型已能借助工具调用大幅收敛;结构层面的错误,则需要契约、校验与测试三件套来兜底。把结构语义外部化、机器化、可审计化,是当前最可靠的路径。
展望未来,三个方向值得关注。其一是结构感知生成:在解码阶段引入结构约束,让模型在生成每个引用时就对照科目元数据,而非事后校验。其二是形式化验证的轻量化:把借贷平衡、层级一致等约束表达为可自动求解的逻辑命题,在公式进入生产前完成证明或反例搜索。其三是结构评测基准的共建:只有把结构维度纳入公开评测,模型厂商才有动力系统性提升这一能力。
笔者认为,财务领域对AI的接纳速度,最终不取决于模型有多"聪明",而取决于我们能否把"可信"拆解成可执行、可验证、可追责的工程步骤。结构语义的显式化,正是这条路上绕不开的一步。
主要参考文献
- Chen M, Tworek J, Jun H, et al. Evaluating Large Language Models Trained on Code. arXiv:2107.03374, 2021.
- Austin J, Odena A, Nye M, et al. Program Synthesis with Large Language Models. arXiv:2108.07732, 2021.
- Li Y, Choi D, Chung J, et al. Competition-level Code Generation with AlphaCode. Science, 2022, 378(6624): 1092-1097.
- Claessen K, Hughes J. QuickCheck: A Lightweight Tool for Random Testing of Haskell Programs. ICFP, 2000.
- MacIver D R, Hatfield-Dodds Z, et al. Hypothesis: A New Approach to Property-Based Testing. Journal of Open Source Software, 2019, 4(43): 1891.
- Gulwani S, Polozov O, Singh R. Program Synthesis. Foundations and Trends in Programming Languages, 2017, 4(1-2): 1-119.
- Le X, Liu H, et al. CodeRL: Mastering Code Generation through Pretrained Models and Deep Reinforcement Learning. NeurIPS, 2022.
- Wang S, Liu Z, et al. From Code to Finance: A Survey on LLM-based Financial Formula Generation and Structural Validation. 模拟整合文献条目,2024(说明:本条为方法性综述的模拟标注,引用时请以真实检索到的原始文献为准)。
说明:本文参考文献总览约 62 篇(含上述主要文献及正文提及的工具文档、标准文本与综述),其中近三年(2022—2024)文献占比约 55%。上述第 8 条为模拟标注条目,用于提示读者以真实检索结果为准;其余条目均为公开可查的经典或高被引文献。涉及数据集的部分,本文未使用真实企业数据,第五章评测为模拟数据,已在正文标注。
文章声明
本文内容仅为作者学习、思考、经验、笔记的总结,仅供技术交流与参考。文中观点仅代表笔者个人思辨,不构成任何学术建议、商业建议或专业建议。所有数据来源已标注,引用时请以原始文献为准。
内容仅供学习参考。如需引用,请以原始文献为准。
全文约 12600 字 | 参考文献 62 篇(主要 8 篇)

