如何用本地 LLM 翻译长文档:分块与检查
我们在 LM Studio 中用本地 LLM 以三种方式翻译了 3,179 个单词,每种方式都隐藏着一个无声的错误。分块大小、设置以及能发现这些错误的检查方法。

人们使用本地 LLM 翻译文档只有一个原因:文件不能离开他们的机器。本地模型可以完成这项工作,但它给你的是纯文本,而不是翻译后的文件,而且它最严重的错误往往是悄无声息的。在我们的测试中,一个针对 3,179 词摘录的单一请求返回了正确的段落数和一个干净的完成信号,然而其中一段丢失了超过三分之一的内容,并增加了源文中不存在的句子。
简短回答: 在段落边界处将文本分割成约 600 词的块,在系统指令中放入人名和重复术语的词汇表,关闭模型的思考模式,并在信任每个块之前将其与源文逐段比较。我们运行测试的三种方式都在某处失败了,而且没有一次失败产生错误消息。预计笔记本电脑上的中型模型处理整本书需要数小时,并计划自己重建格式。
以下所有内容均来自 2026 年 10 月 23 日的一次运行:在配备 64 GB 内存的 Apple M4 Max 上,使用 LM Studio 0.4.8 中的 Qwen 3.6 27B(Q4_K_M GGUF),将卡夫卡《变形记》的开头从德语翻译成英语。测试脚本、结果和原始失败示例可免费下载,以便您用自己的模型重复测试。
何时本地 LLM 是合适的工具
当文档的规定而非便利性决定选择时,在本地运行翻译:
- 客户合同、研究协议或雇主政策禁止将文件上传到外部服务;
- 文本是个人或机密信息,且您无法事先移除敏感部分;或者
- 您需要处理许多文件且没有按文档计费的成本,并且您已经拥有合适的硬件。
如果以上情况均不适用,本地模型通常是通往更差结果的更慢路径。您放弃了文档翻译服务提供的三样东西:原始格式的翻译文件、比您的机器能容纳的更大的模型,以及为整本书的一致性而构建的工作流程。在选择任一途径之前,请仔细阅读文档翻译隐私检查清单。它涵盖了处理文件的权限、最小工作副本以及服务对上传内容的处理方式。
“本地”也需要一个精确的含义。模型在您的计算机上运行,在我们的测试中,请求仅发送到 localhost。这并不能告诉您模型周围的应用程序记录、更新或报告了什么。如果您的规定要求证明没有任何内容离开设备,请检查运行时自身的设置和政策,或者在没有网络访问的机器上运行它。
我们测试了什么
我们翻译了《变形记》的前 19 段(3,179 个德语词),来自公共领域的古腾堡计划版本。文学德语是一个公平的压力测试:段落长,句子嵌套,相同的人物和职位反复出现。
所有三次运行都使用了相同的模型和设置:温度 0.2,最大输出 12,000 个 token,上下文窗口 16,384 个 token。指令要求每个德语段落对应一个英语段落,别无其他。
| 运行 | 我们发送的内容 | 输出段落数(源文:19) | 输出词数 | 时间 |
|---|---|---|---|---|
| A. 分块 | 6 个约 600 词的块,仅指令 | 19 | 3,319 | 10.4 分钟 |
| B. 分块 + 词汇表 + 上下文 | 相同的分块、一个包含 7 个术语的术语表,以及将上一段源文标记为“请勿翻译” | 20 | 3,446 | 10.5 分钟 |
| C. 单次请求 | 一次性处理全部 19 个段落 | 19 | 3,309 | 9.5 分钟 |
每次运行都以正常的停止信号结束,而每次运行都包含不同的静默错误。运行 C 丢失并编造了文本。运行 B 翻译了被告知要跳过的文本。运行 A 是最干净的一次,但在其最后一个分块中给一个角色分配了错误的身份。
失败 1:一次大请求丢失了部分段落
运行 C 正常完成,并准确返回了 19 个段落。段落计数检查本会通过。然而,第 6 段在源文为 260 词的情况下,返回时只有 214 词。
在源文中,格里高尔看着时钟,意识到自己错过了火车,然后考虑请病假:他的老板会带着健康保险医生一起来,这位医生认为每个人都健康但逃避工作,而格里高尔承认自己除了困倦和异常食欲外,实际上感觉良好。运行 C 翻译了第一部分,然后丢弃了整个病假段落,即该段 260 个德语词中的 98 个。取而代之的是,它写道格里高尔“会当场被解雇”,办公室助理“倾向于把向他报告的一切视为展示自己的机会”,以及这个想法“让他嘴角上扬”。这些内容在德语原文中均不存在。
分块运行完整翻译了同一段落,共 267 词。
一个样本并不能证明长请求总是失败。它确实说明了需要检查什么:一个长的单次请求可能在结构上看起来完整,却静默地压缩或编造文本。不懂德语的读者没有理由注意到这一点。
失败 2:模型翻译了被告知要跳过的“上下文”
一个常见的技巧是随每个分块发送上一段,以便模型保持连贯。在运行 B 中,我们将其添加到消息中,标签为“上下文(已翻译,请勿翻译)”。
在第 4 个分块中,模型还是翻译了它。该分块为三个源段落返回了四个段落,第一个是第 3 个分块最后一段的第二次翻译。如果拼接在一起,书中将包含该段落两次,每次措辞不同。
实用规则:如果发送上下文,请将其排除在要求模型翻译的文本之外,保持简短,并检查每个分块的段落数。如果无法检查,就不要发送。
失败 3:单独发送的分块给角色分配了错误的身份
运行 A 发送每个分块时没有术语表,也没有上下文。对于前五个分块,这效果很好:Prokurist 在其出现的全部 16 处都译为“chief clerk”。第六个分块是一个单独的段落,其中首席文书隔着门训斥格里高尔。单独来看,模型将 der Prokurist 翻译为“旅行推销员”,这是格里高尔自己的工作。段落数匹配,长度比为 1.00,因此两项结构检查都没有注意到。
在运行 B 中,系统指令中包含术语表,并以上一段作为上下文,同一段落正确使用了“chief clerk”。这个测试无法说明是两者中的哪一个修复了问题。由于上下文也导致了失败 2,术语表是跨分块携带名称和角色的更安全位置:它简短,位于指令中,并且可以机械地检查。
行之有效的工作流程
1. 首先从文件中提取纯文本
本地 LLM 翻译的是文本,而不是文件。在开始之前转换文档:
- DOCX 或 EPUB: 导出为纯文本或 Markdown,每个块一个段落,标题保留为单独的行。
- 带文本层的 PDF: 提取文本,然后修复断行和连字符。我们的指南修复 OCR 断行和连字符涵盖了相同的清理工作。像 Docling 这样的转换器可以从 PDF 和 Office 文件生成 Markdown。
- 扫描版 PDF: 先运行 OCR。如果您不确定 PDF 是否有可用的文本,请参阅PDF 文本提取与 OCR 对比。
保持段落结构不变。后续每一项检查都依赖于源文与译文段落之间的一一对应关系。
2. 关闭思考模式并确认已关闭
当前许多开源模型在回答前会先进行推理。对于翻译任务而言,这会浪费时间和输出 token。在我们的测试中,一个 200 token 的测试请求有 199 个 token 花在了推理上,最终返回了空答案。
我们尝试了三种常见的开关方式。在提示词中添加 /no_think 没有效果,使用 chat_template_kwargs 并设置 enable_thinking: false 也没有效果。在请求中发送 "reasoning_effort": "none" 成功关闭了推理:响应报告 0 个推理 token,并直接返回了译文。该参数并未列在 LM Studio 的聊天补全页面上,因此请将其视为我们在 0.4.8 版本中对此模型观察到的行为。请检查你自己响应中的 reasoning_tokens 计数,而不要轻信任何开关。
3. 在分块之前确定上下文窗口大小
上下文窗口必须能容纳指令、分块和完整译文。在我们的分块运行中,一个 500 到 670 词的德语分块根据术语表和上下文的不同,使用了约 800 到 1,500 个输入 token,以及 640 到 870 个输出 token,因此几千个 token 就足够了。而单次处理 3,179 词的请求需要 4,953 个输入 token 和 3,930 个输出 token。
根据 Ollama 的上下文长度文档(查阅于 2026 年 10 月 23 日),其默认上下文长度根据可用内存设定:显存低于 24 GiB 时为 4k token,24 到 48 GiB 时为 32k,48 GiB 及以上时为 256k。你可以通过 OLLAMA_CONTEXT_LENGTH 来提高该值。在 LM Studio 中,加载模型时设置上下文长度。如果分块加上其译文无法容纳,输出可能会被截断。
4. 按段落边界分块,约 600 词
绝不要在段落或句子内部进行分割。我们的分块目标为 700 词,并在最近的段落边界处结束,最终产生了六个 243 到 667 词的分块。较小的分块成本很低:运行 A 耗时 10.4 分钟,而单次请求为 9.5 分钟,并且失败的分块重新运行的成本很低。
保持指令简短,并对每个分块使用相同的指令。我们的指令是:翻译成英文,每个输入段落严格对应一个输出段落,段落之间用空行分隔,并且只输出译文。在同一指令中添加术语表:每行一个名称、头衔或反复出现的术语,格式为 Prokurist = chief clerk。我们的构建翻译术语表指南涵盖了应包含的内容。短分块会丢失周围的故事情节,而术语表正是承载这些信息的关键。
5. 在合并之前检查每个分块
对每个分块运行三项检查:
- 段落数。 输出的段落数必须与输入相同。这项检查发现了失败 2。
- 每段长度比。 比较每个译文段落与源文的词数。这项检查发现了段落数检查遗漏的失败 1。
- 每段术语表术语。 源文术语出现的地方,其要求的译文应出现相同的次数。这项检查发现了其他两项检查都遗漏的失败 3。屈折语言在此需要一些判断,因为德语或俄语术语会改变形式。
对于德译英散文,运行 A 的各段落词数比保持在 0.98 到 1.17 之间(输出词数/输入词数)。运行 C 中受损段落的比值为 0.82。通过检查你语言对中几个可信的段落来设定你自己的范围;我们脚本中的默认值只是起点,并非标准。
被标记的段落是首先应该阅读的地方,而不是错误的证据。然后阅读译文本身,尤其是名称、数字、否定词以及读者会据此采取行动的任何内容。书籍翻译 QA 清单涵盖了该审查流程。
6. 重建文档
模型返回的是文本。标题、脚注、表格、图片、页面布局和样式必须手动或通过转换工具放回。对于短报告,这是小事。对于带有脚注和表格的书籍,这可能比翻译本身花费更长时间。
整本书需要多长时间
我们的分块运行在 10.4 分钟内翻译了 3,179 词,在这台机器上约为每分钟 300 词。按此速度,一部 90,000 词的小说大约需要五小时的生成时间,还不包括检查和重新运行。这是基于一次运行的简单算术,并非基准测试。速度会随模型大小、量化、硬件、语言对以及机器上同时运行的其他任务而变化。
模型文件在磁盘上为 17.5 GB,上下文缓存和运行时缓冲区还需要在此基础上占用内存,因此机器需要的可用内存明显多于文件大小。较小的模型运行更快、占用内存更少,但通常会在质量上有所损失。在翻译整本书之前,请先在具有代表性的样本上进行测试。我们的最佳翻译 LLM指南解释了如何构建该样本并公平地比较模型。
本地 LLM 还是文档翻译服务
| 问题 | 本地 LLM | 文档翻译服务 |
|---|---|---|
| 文件能否离开你的机器? | 不需要 | 需要 |
| 返回内容 | 需要你重新拼装的纯文本 | 翻译后的文件 |
| 模型规模 | 受限于你的内存 | 受限于服务提供商 |
| 整本书的一致性 | 你的任务:术语表、分块、检查 | 部分服务已内置 |
| 每份文档的成本 | 你的硬件和时间 | 按文档或按词计价 |
如果你的规定允许上传文件,文档服务能省去上面的大部分工作。BookTranslator 可翻译完整的 PDF、EPUB 和 DOCX 文件并返回翻译后的文件,其常见问题解答称上传的文件和翻译输出不会用于训练 AI 模型。它是云服务,因此当文件必须留在你的机器上时,它就不是一个选项。如果你正在权衡自己运行模型还是付费使用服务,LLM 翻译的实际成本 展示了如何为 token 方面做预算。
获取测试文件
所有文件都在 /files/blog/translate-with-local-llm/ 文件夹中:
local_llm_translation_test.py:针对 LM Studio 本地 API 的完整测试,包含全部三次运行。将其指向另一个模型或源文本即可重复测试。check_translation.py:逐段比较源文本和译文,并打印段落数不匹配、长度比超出范围以及缺失的术语表术语(使用--term "Prokurist=chief clerk")。它适用于任何工具的输出。results.csv:每次请求及其段落数、词数、token 数和时间。failure-examples.txt:全部三次失败的德语源文和原始模型输出。
在依赖任何长文翻译之前,先用你的术语表运行 check_translation.py。它只需几秒钟,就标记出了本次测试中的全部三处失败。它无法判断一个流畅的句子是否正确,因此被标记的段落是你阅读的起点,而非终点。





