代码算事实、模型做解释:本地LLM处理瑞士行政信

瑞士行政信件本地 LLM 助手用代码算截止日期、模型只做解释,并诚实标注未测边界。
开发者构建了名为 Sportello chiaro 的本地小工具,用平实意大利语解释瑞士行政信件并标出法定期限。其核心设计原则是:语言模型绝不产出关键事实。截止日期由正则匹配送达通知日期、按文书类型选取天数再由 `timedelta` 计算,模型只负责生成四段可读解释。模型调用失败时自动回退到规则输出,用户仍能看到截止日期与回复模板。工具仅用 Python 标准库约 300 行,测试覆盖规则层面,模型默认配置未经测试,也未做输出 schema 校验,未处理周末与假日。作者强调把语言与事实拆开处理、并诚实标注未测试部分,是这类工具可信度的基础。
瑞士的公共机构来信往往附带着不容忽视的时间节点。一份 Zahlungsbefehl(支付令)通常只留给你十天时间去提出异议,Einsprache(异议申请)的法定期限则常见为三十天。错过日期,一项权利就没了。而这些信件使用的语言,对许多收件人来说并非母语。
开发者为此构建了一个名为 "Sportello chiaro" 的本地小工具,用平实的意大利语解释这类信件,并标出截止日期。这是一个 MVP(最小可行性产品),其核心设计思路很值得聊一聊:在涉及法律事实的场景里,语言模型该站在什么位置。

核心原则:模型绝不去产出关键事实
语言模型擅长解释,但在日期运算和准确引用天数这件事上并不可靠。因此,截止日期不交给模型来生成,而是由代码产出。
工具用一段正则匹配送达通知日期,提取类似德语的 zugestellt am 或法语的 notifié le 之后跟随的日期字符串:
SERVED_RE = re.compile(
r"(?:zugestellt am|zustellung am|zugestellt:|notifié le|notifiée le|reçu le)"
r"\s*(\d{1,2})[.\/](\d{1,2})[.\/](\d{4})", re.I)
拿到通知日期后,工具根据文书类型选取对应的天数——Zahlungsbefehl 或 Strafbefehl 取 10 天,Einsprache 取 30 天——再执行 end = served + timedelta(days=days) 完成计算。
模型随后才登场,拿到信件原文和一段系统提示词。提示词的核心约束很直白:只用信件中已有的信息,不得编造日期、金额或法条。它的任务只有一件,生成四个固定章节的可读解释。
Zahlungsbefehl 与 Strafbefehl 的法定异议期限
Zahlungsbefehl(支付令)是瑞士债务催收程序的开端,由州级 Betreibungsamt(催收机构)发出。收到后,债务人若认为债务不存在或金额有误,可在十日内向同一机构提交 Rechtsvorschlag(法律异议),逾期则债务被认定为无争议,可进入强制执行。Strafbefehl(刑事处罚令)是检察官在不经主审程序时直接作出的处罚决定,收件人若不服,同样需在十日内提出 Einsprache,否则判决生效。Einsprache 一词在两种程序中含义略异:在刑事处罚令中即指对处罚令本身提出异议,在行政决定中则泛指对官方处分的异议申请。工具按文书类型切换 10 天与 30 天,正是对应这些不同的法定框架。
优雅降级:模型掉了,事实还在
调用本地模型的部分用的是朴素的 urllib,取返回结果里的第一个 choice 文本。一旦模型调用失败,分析流程会自动回退到基于规则的那套输出,并记录下错误。
用户依然能看到截止日期和一份回复模板,只是少了那些解释性的文字。这种设计把"必须正确"和"读起来顺畅"这两件事解耦了——前者永远不会因为模型抖动而消失。
朴素 urllib 与本地模型服务
代码中直接使用 Python 标准库 urllib 向本地推理服务发起 HTTP 请求,取返回 JSON 中第一个 choice 的文本。这通常意味着模型以 OpenAI 兼容的 /v1/chat/completions 接口暴露,Ollama 与 llama-cpp-python 都提供此类端点。相比 requests 或官方 SDK,urllib 无需额外依赖,代价是错误处理更繁琐、超时与重试都要手写,且流式输出支持有限。对于约 300 行、只面向单机用户的 MVP 而言,这是刻意的最小依赖选择;但生产环境通常会换成更成熟的 HTTP 客户端,以处理连接池、超时策略和后端切换。
已经测过的部分
开发者对测试边界的交代很克制,值得细看:
- 技术栈:仅用 Python 3.10 标准库(
urllib、http.server、re、datetime、json),约 300 行。提供一个 CLI 和运行在127.0.0.1:8080的本地网页。 - 模型:测试中使用的是通过
llama-cpp-python跑起来的 Gemma 3 1B(Q4_K_M)。其设想的默认配置是通过 Ollama 调用更大的模型,但那个配置并未经过测试。 - 测试:六个 pytest 测试,全部停留在规则层面。其中一个验证 10 月 12 日送达加 10 天得到 2026 年 10 月 22 日;另一个验证回复模板的选择逻辑;第三个验证无关文本会被判定为低紧急度。
- 端到端:用一封虚构的信做了一次完整流程,用 1B 模型大约跑了 40 秒。
Gemma 3 1B 与 Q4_K_M 量化
Gemma 3 1B 是 Google 发布的小型开源模型,参数量约十亿,可在普通笔记本 CPU 上运行。Q4_K_M 是 GGUF 格式下的一种 4 比特量化方案,K 表示采用 k-quant 分块量化,M 为中等压缩等级,通常在模型大小与输出质量之间取得较好平衡。量化后模型体积从数 GB 降至不足 1 GB,推理速度更快,但生成文本的连贯性和事实一致性会有所下降。这解释了为何用 1B 模型跑一封虚构信需要约 40 秒,也解释了为何把日期计算与可读解释拆开:小模型即使解释得生硬,也不影响截止日期本身的正确性。
尚未完成的部分
同样需要被清楚说明的是缺口:
- 对模型输出没有做 schema 校验。工具不会去核实回答是否包含那四个章节,也不会核对行文里的截止日期与计算出的日期是否一致。这是开发者下一步打算补上的。
- 截止日期的计算没有处理周末和公共假日。
- 不支持 OCR,也不支持 PDF 输入,只能粘贴文本。
- 还没有用户,仓库也未公开。
- 它不是法律建议,开发者也不打算把它当作法律建议来呈现。
为什么要本地运行
这些信里写着姓名、地址和债务信息。把模型留在用户自己的机器上,意味着文本始终不离开本地。代价是小模型更慢、表达也更生硬——这正是把必须正确的部分交给规则来承担的原因。
可复用的思路
当一项任务同时涉及语言和事实,把它拆开。让代码产出必须精确的内容,让模型负责解释。然后,把自己测过和没测过的部分都讲清楚。
这个原则的适用范围远不止瑞士的行政信件。任何需要从文档中提取硬性事实并辅以自然语言说明的场景——保险理赔通知、税务函件、法院文书——都可以借鉴这种"代码管计数、模型管表达"的分工。而对未测试边界的诚实标注,本身就是这类工具可信度的一部分。
相关推荐

Product Hunt 推出可视化发布编辑器,告别繁琐填写
Product Hunt 推出可视化发布编辑器,支持点击原位编辑名称、标语、画廊和 maker 信息,自动保存草稿,并用检查清单引导创作者完成发布。本文解析其编辑逻辑与对发布体验的影响。

泽连斯基亲述:俄军2000万人压境,我们如何守住基辅
泽连斯基访谈回顾俄乌战争初期:俄军200,000兵力直扑基辅,乌军主力却在东部。他讲述动员如何将军队从200,000扩张到800,000,以及基辅州、切尔尼戈夫州如何被收复。

Ovren Live Preview:用自然语言实时预览产品改动
Ovren Live Preview 是一款用自然语言描述改动、在真实页面上实时预览的 AI 开发工具。了解其核心功能、工作流、市场定位与潜在挑战。