将AI助手接入财务数据时遇到的三类问题及修复路径:①用MCP替代记忆实现实时查税;②并行工具调用兜底;③结构化输出校验签名防注入。
我一直在把 AI 助手接入那些必须保证正确性的系统,而金融数据是出问题最快的领域。"差不多对"对于聊天机器人来说没问题,但对于别人用来报税的数字来说就不行了。
这里是我实际遇到的三个问题,按顺序排列,以及每个问题的解决方案。没有哪个方案是特别 exotic 的——但顺序很重要,因为每个问题都会引出下一个。
第一个版本直接去问模型。"$4,180 的 GST 是多少?"它立刻给出了答案,看起来没问题。但它在门槛上微妙地错了,而且更糟糕的是——它完全不知道自己是错的。
这是直接使用原始 LLM 处理事实类问题的根本缺陷:它从有截止日期的训练数据中给出答案,而且它无法告诉你这个数据有多新。对于任何受监管的事项,光这一点就足以让它不合格。
解决方案:别让模型去记忆,让它去查。这就是 MCP(Model Context Protocol)的用武之地——这是一个开放标准,让助手可以在提问时调用工具。我让它指向一个公开的税务服务器,而不是依赖记忆:
{ "mcpServers": { "tax": { "url": "https://taxmcp.ai2fin.com" } } }
现在助手从定义的来源获取数字,而不是凭空编造。每次运行的数字不再漂移——这是它变成真实数据的第一个信号。
接地(Grounding)解决了准确性,但带来了一个更微妙的问题:无论答案是来自工具还是模型填补空白,看起来都一样。如果某个调用悄无声息地失败了,模型临时编造了一个答案,我完全没有办法发现。
解决方案:要求每个字段都有来源证明,没有来源的答案一律拒绝。我使用的服务器在每个响应中都会返回来源机构和验证日期:
> income_tax_estimate { country: "AU", income: 95000 }
< { incomeTax: ..., takeHome: ...,
source: "ATO — ato.gov.au", dataVerifiedOn: "2026-06-01" }
所以我的规则变成了:如果一个数字到达时没有 source 和 dataVerifiedOn,就不会展示给用户。这一项检查把"模型这么说的"变成了"澳大利亚税务局这么说的,日期是这天,这是链接"——这就是演示和真正能面向客户的工具之间的差距。
到这时,我的助手已经从工具获取答案了,而网页上展示的是同样的计算器。可以预见,它们产生了分歧。有人更新了其中一个税率表但没更新另一个,于是聊天机器人和网站对同一工资报出了不同的税后数字。这是史上最古老的 bug,在金融领域尤为残酷,因为两个答案看起来都有权威性。
解决方案:一个引擎,多个界面——税率表绝不保留两份。有效的设置是让 MCP 服务器和网页计算器都读取同一个底层引擎,这样就没有任何东西需要人工去同步了。当我在聊天和网页上看到相同的 income_tax_estimate 值时,我就知道两边背后只有一个真相来源。
如果你曾经维护过任何每年都会变动的东西的两份副本,你就会明白为什么这才是真正让你睡得着觉的解决方案。
三条规则,而且它们可以很好地泛化到税务之外:
不要让模型记忆事实——给它一个获取事实的工具。
要求每个获取到的值都有来源证明(来源 + 日期),拒绝没有来源的数据。
让一个引擎支撑所有界面,这样你的答案之间不可能产生分歧。
税务领域只是让 stakes 变得清晰可见——一个错误的 GST 数字是明显且令人尴尬的。但如果助手接触了它根本不该记忆的数据,同样的三个问题就会出现:定价、库存、用药剂量,任何会变动的东西都是如此。
文中用到的服务器是免费的,不需要注册账号,如果你想要一个真实的东西来测试这个模式:taxmcp.ai2fin.com。把你的客户端指向它,试着让它给你一个没有来源的数字。你做不到的——而这个约束就是整个方案的重点。