[控场AI]
· 4 分钟阅读· 2,398 字

别再让LLM做数学:印度村庄账本对账的沙箱协调器实践

别再让LLM做数学:印度村庄账本对账的沙箱协调器实践

LLM只做信息提取,数学与流程控制交给沙箱化协调器中的确定性代码。

文章分享了在印度村庄账本对账项目中遇到的工程困境:LLM 处理金额计算和账目核对时错误频出,而财务场景要求零误差。团队由此确立分工原则——LLM 仅负责理解手写、多语言、格式混乱的账本内容并提取金额与类别,所有加减运算、规则判断和流程控制交由外部 Python 工具函数完成。为安全执行这些工具,团队构建了沙箱化代理协调器,以状态机方式调度 LLM 生成的结构化指令,每个工具调用在独立容器中运行并做严格校验,避免进程内执行带来的无限循环、内存泄漏和文件操作风险。该架构在真实对账场景中显著提升准确率,并使规则变更只需修改工具函数而非重新提示模型,代价是增加了协调器与沙箱的工程复杂度。

为什么我们不再让LLM做数学了

在构建一个用于印度村庄账本对账的AI代理系统时,我们遇到了一个根本性问题:LLM不擅长数学,更不适合直接运行业务逻辑。最初,我们让LLM处理金额计算和账目核对,结果错误频出。印度村庄的账本往往手写、格式混乱、语言多样,对账过程涉及大量加减运算和规则判断。LLM的“近似正确”在这里完全行不通——一分钱的误差都可能导致对账失败。

于是我们决定:LLM只负责理解和提取信息,所有数学计算和流程控制都交给外部工具。这听起来简单,但实现起来需要一套沙箱化的代理协调器。

reddit source: why we stopped letting llms do math or run in-process: building a sandboxed agent coordinator for me

LLM 之所以在算术上不可靠,根源在于其自回归生成机制:它逐个 token 地"预测"下一个最可能的字符,而非像计算器那样执行确定性的符号运算。模型内部没有可寻址的寄存器或进位链,多位数加减、跨行汇总这类需要精确中间状态的操作,只能依赖训练数据中习得的模式近似,一旦位数增多或出现进位借位,误差概率迅速上升。温度采样、上下文窗口截断、提示词措辞变化还会引入额外的不确定性,使同一道题在不同调用间给出不同答案。这与传统程序"输入相同则输出相同"的可复现性形成根本冲突。在财务场景中,这种"近似正确"无法通过任何测试用例,因为对账的判定标准是零误差而非高概率正确。因此业界逐渐形成共识:把 LLM 定位为语义解析器与意图路由器,将确定性计算下沉到代码层,是当前工程条件下更稳妥的分工方式。

沙箱代理协调器的设计思路

核心思路是将LLM的能力限制在“理解”层面,而把“执行”交给确定性的代码。我们构建了一个协调器,它负责解析LLM的输出,并调度沙箱环境中的工具函数。这些工具函数用Python编写,专注于数学运算、数据校验和账本比对。LLM的每次调用都返回结构化的指令,协调器验证指令后,在沙箱中执行对应的工具。

这样做的好处是安全:即使LLM产生幻觉或恶意指令,沙箱也能阻止其访问系统资源或执行危险操作。同时,数学计算变得完全可复现和可审计——每一笔计算都有代码记录,而不是LLM的黑箱输出。

为什么不用进程内执行?

我们最初尝试让LLM在同一个进程内调用工具,但很快发现这带来严重风险。LLM可能生成无限循环、内存泄漏或意外的文件操作。沙箱化通过隔离进程和限制资源使用,避免了这些问题。每个工具调用都在独立的容器中运行,只能访问必要的输入数据,输出经过严格校验。

进程内执行指的是在同一 Python 解释器或同一操作系统进程里,直接调用 LLM 生成的代码或工具函数。这种模式下,LLM 的输出与宿主程序共享内存空间、文件描述符和环境变量,一旦模型产生幻觉代码——例如误写递归条件导致栈溢出、构造超大列表耗尽内存、或拼接出删除目录的路径——故障会直接波及协调器本身乃至整个服务进程。沙箱化则通过命名空间隔离、cgroup 资源限额、只读文件系统和网络禁用等手段,把每次工具调用关进一个一次性容器:即使代码崩溃或行为异常,影响范围也被限制在该容器内,超时后强制回收即可。这不仅是安全考量,也是可用性考量——进程级故障会导致整个对账任务中断,而容器级故障只需重试单次调用。对于需要审计的财务流程,沙箱还能完整记录每次调用的输入输出,形成可追溯的执行日志。

协调器如何工作

协调器本质上是一个状态机。它接收用户输入,调用LLM解析意图,生成工具调用序列,然后按顺序在沙箱中执行。执行结果返回给LLM进行下一步决策,直到任务完成。整个过程中,LLM只负责“下一步做什么”,而不直接操作数据。

这种架构在印度村庄账本对账场景中表现出色。账本中的手写数字、多语言混合(英语、印地语、地方文字)和模糊条目,LLM可以较好地提取和分类。但一旦提取出金额和类别,后续的汇总、核对和差异计算全部由沙箱中的代码完成,准确率大幅提升。

状态机是一种将系统行为建模为有限个状态及状态间转移的工程范式:每个时刻系统处于某个确定状态,接收到输入事件后按预定义规则迁移到下一状态,并可能产生副作用。在这里,协调器把对账任务拆解为"解析意图—生成工具调用—等待执行结果—评估下一步"的循环,LLM 的输出被约束为符合 schema 的结构化指令(如工具名加参数),而非自由文本。协调器在调用工具前会校验参数类型、取值范围和前置条件,校验失败则回退并重新询问 LLM。这种设计把不确定性收敛在"选择哪个工具"这一离散决策上,而每个工具的语义是确定的、可单元测试的。相比让 LLM 一次性生成整段业务流程代码,状态机加工具集的组合更易调试:出错时可以精确定位是意图识别错误、参数抽取错误还是工具实现错误,而非面对一段无法解释的黑箱输出。

实际效果与反思

通过这种分离,我们不仅提高了准确性,还增强了系统的可维护性。当对账规则变化时,只需修改沙箱中的工具函数,而不需要重新训练或提示LLM。LLM的提示词也可以更简洁,专注于信息提取任务。

当然,这种架构增加了工程复杂度。需要设计稳健的协调器、沙箱环境和工具接口。但对于高风险的财务对账场景,这是值得的。我们的经验是:不要相信LLM做数学,也不要让它直接运行业务逻辑。让LLM做它擅长的事——理解混乱的输入,然后由确定的代码完成精确的工作。

这篇来自Reddit的分享,虽然简短,但切中了LLM应用中的一个关键痛点。在多源分析中,这一观点也得到了其他开发者的呼应:LLM更适合作为“翻译器”而非“计算器”。

#LLM#沙箱#代理协调器#账本对账#印度村庄#数学运算#进程内执行
分享:

相关推荐