状态:已弃用(Deprecated) — 本文档记录该系统的完整设计与实现细节,作为技术归档保留。弃用原因见第七节。
一、项目概述
translating-articles 是一套基于 Claude Agent SDK 的长文分片翻译系统,用于将 Clippings/totranslate/ 中的外文文章翻译为中文,输出至 Clippings/translated/。
系统解决的核心问题是:LLM 上下文窗口有限,无法在保证翻译质量的前提下一次性处理超长文本(如播客文字稿、长篇访谈)。方案是将原文按章节切分为多个片段,逐片翻译,通过术语表接力和重叠段落保持跨片一致性。
技术栈
- Python 3.10+,async/await
claude_agent_sdk(query+ClaudeAgentOptions)- PyYAML、pathlib、hashlib
- 运行环境:
henri_envconda 环境
文件结构
.claude/skills/translating-articles/
├── SKILL.md # Skill 定义(Agent 直接翻译模式的指令)
└── scripts/
├── translate.py # 分片翻译主脚本
└── add_speakers.py # 说话人标注后处理脚本
tools/translate-chunks/{slug}/ # 运行时工作目录
├── meta.json # 元数据 + chunk manifest
├── glossary.json # 累积术语表
├── chunk-01-translated.json # 各片 checkpoint
├── chunk-02-translated.json
└── ...
二、架构设计
2.1 双模式架构
| 模式 | 适用场景 | 驱动方式 | 上下文 |
|---|---|---|---|
| Agent 直接翻译 | 短文(<30KB) | SKILL.md 指令,Agent 在会话中直接翻译 | 共享 Agent 上下文 |
| 脚本分片翻译 | 长文(>30KB),播客/访谈文字稿 | translate.py 独立进程 | 每片独立 LLM 调用 |
Agent 模式由 SKILL.md 描述翻译原则、格式规范和处理流程,Agent 读取原文后直接在会话中完成翻译。该模式简单直接,但受限于 Agent 的上下文窗口。
脚本模式是本系统的核心,下文重点描述。
2.2 分片翻译的核心理念
片间隔离:每片翻译是一次独立的 claude_agent_sdk.query() 调用,拥有完整的系统提示和独立上下文,不存在上下文溢出的风险。
一致性保证:片间通过两个机制维持翻译一致性:
- 术语表接力:每片翻译的输出中包含
GLOSSARY:段,脚本解析后注入下一片的 prompt。术语表滚雪球式积累,确保同一术语在全文中译法统一。 - 重叠段落:取前一片译文的末尾 3 段作为"衔接上下文"注入下一片 prompt,供模型参考语气和行文风格,但明确标注"不要重复翻译这部分"。
断点续传:每片翻译完成后立即写入 checkpoint 文件(含原文 hash),中断后可从断点继续,无需重新翻译已完成的片段。
三、处理流水线
3.1 预处理阶段
原文 .md → 解析 frontmatter → 提取元数据 → 自动检测 → 确定翻译策略
Frontmatter 解析:提取 title、author、source_url、date、tags 等字段。日期字段支持多种来源(published > date > created)和格式(datetime、isoformat、字符串)。
视频脚本自动检测(detect_video_transcript):扫描正文,统计以下模式的出现次数:
- 粗体时间戳:
**0:00** - 裸时间戳独占一行:
0:00 - 方括号时间戳:
[00:01:23] - 括号章节目录:
(00:00)
出现 ≥3 次即判定为视频脚本。此外,source_url 匹配 youtu.be 也直接视为视频脚本。
章节标题密度分析(detect_heading_density):统计 ## 和 ### 标题的频率,返回三档:
| 密度 | 判定条件 | 翻译策略 |
|---|---|---|
rich | 平均每 80 行 ≥ 1 个标题 | 翻译已有标题,适当优化 |
sparse | 有标题但密度不足 | 翻译已有 + 在话题切换处补充标题 |
none | 无标题 | 按话题切换自动插入 ### 标题 |
3.2 切分策略
主切分(split_into_chunks):以 ## 标题为边界切分。相邻短 section 合并,直到累积字符数接近 max_chars 上限。
超长 section 的逐级回退(_split_oversized):当单个 section 超过上限时,按以下顺序尝试拆分:
\n\n(段落) → \n(行) → 句末标点(.!?。!?) → 强制按字符数截断(在空格处断开)
每一级都检查拆分后的最大片段是否 ≤ max_chars,满足则停止回退。
Chunk Manifest:切分结果被序列化为 manifest(包含每片的 text、headings、text_hash、char_count),保存在 meta.json 中。续传时直接从 manifest 恢复,而非重新切分原文。
3.3 翻译执行
每片的 prompt 由以下模块拼合(按顺序):
┌─────────────────────────────────────────┐
│ 系统指令:翻译原则(信达雅、直译优先等) │ ~300 tokens
├─────────────────────────────────────────┤
│ 视频脚本指令(如适用) │ ~150 tokens
├─────────────────────────────────────────┤
│ 章节标题策略(rich/sparse/none 三选一) │ ~50 tokens
├─────────────────────────────────────────┤
│ 已确定的术语表(累积) │ ~50-300 tokens
├─────────────────────────────────────────┤
│ 前文衔接段落(前一片末尾 3 段) │ ~200-400 tokens
├─────────────────────────────────────────┤
│ 待翻译原文 │ 主体内容
├─────────────────────────────────────────┤
│ 输出格式指令(GLOSSARY 段要求) │ ~50 tokens
└─────────────────────────────────────────┘
翻译原则要点:
- 原文→中文直译优先,不经英文中介转写
- 避免过度补全(不补出原文没有的主语、因果、转折)
- 专业术语首次出现时:
中文翻译(原文术语) - 人名仅国际知名人物使用中文译名,其余保留原文
- 不要将翻译写成摘要或释义
视频脚本特殊处理:
- 移除所有时间戳
- 合并相邻短句为自然段落(3-5 句为一段)
- 口语转书面语
- 跳过广告/赞助商推广段落
- 说话人识别:根据上下文推断并标注
**说话人名字:**
重试与降级机制:
第 1 次 → 正常翻译
第 2 次 → 等待 10s 后重试
第 3 次 → 如片段 >5000 字符,拆为 5K 子片段分别翻译后拼合
术语表解析:翻译结果中如包含 GLOSSARY: 段,脚本按 原文 → 中文 格式逐行解析,merge 入全局术语表,传递给后续片段。
3.4 后处理
Markdown 排版修复(fix_markdown_formatting):
##正文章节降为###(避免与文档标题冲突)####统一为###- 标题前后确保空行
- 压缩连续空行(最多保留一个)
AI 生成导读(generate_intro):取译文前 3000 字作为上下文,调用 LLM 生成约 200 字的导读摘要,放在标题与正文之间。
输出文件生成:
| |
原文自动归档:翻译完成后,原文件从 totranslate/ 移至 _archived/translated/。
四、断点续传机制
断点续传是本系统应对长文翻译中断(网络超时、进程终止、token 限额)的核心能力。
4.1 Checkpoint 结构
每片翻译完成后,立即写入 chunk-{i:02d}-translated.json:
| |
4.2 续传流程
启动 → 读取 meta.json → 校验原文 hash
├─ hash 不匹配 → 警告并重新切分(旧 checkpoint 不再适用)
└─ hash 匹配 → 从 manifest 恢复切分
├─ 全部片段有 checkpoint → 直接合并输出
├─ 部分完成 + chunk-size 未变 → 跳过已完成,继续翻译
└─ 部分完成 + chunk-size 变化 → 保留已完成片段,
剩余文本按新 chunk-size 重切,清理旧的未完成 checkpoint
4.3 自动续传
系统无需 --resume 标志。每次运行自动检测工作目录中的已有 checkpoint:
- 已完成的片段:校验
source_hash一致后直接跳过 - 未完成的片段:正常翻译
- chunk-size 变更:仅对未翻译的剩余文本按新尺寸重切
五、辅助工具
5.1 说话人标注(add_speakers.py)
为访谈/播客的已翻译文本后置添加说话人标注。读取 translate-chunks/{slug}/ 中的已翻译 chunks,逐片调用 LLM 推断说话人身份,在每次说话人切换时插入 **说话人名字:** 标记。
规则约束:不修改任何翻译内容,仅插入标注。使用前一片末尾 3 段作为上下文判断当前说话人。
5.2 多模型支持
通过 --provider 参数切换模型。配置文件位于 ~/.configanthropic/keys/{provider},格式为环境变量导出(export KEY=VALUE)。
| Provider | 模型 | 用途 |
|---|---|---|
default | Claude Sonnet 4.6 | 主力翻译模型 |
glm | 智谱 GLM | 备选 |
minimax | MiniMax | 备选 |
六、翻译理念与 Prompt 设计
6.1 非中介翻译
明确要求"不要先改写成英文或借助其他中介语言理解后再翻译为中文"。这是针对 LLM 常见行为的约束——模型倾向于先将非英语原文理解为英文,再从英文翻译为中文,导致原文的语序、省略和修辞特征丢失。
6.2 直译优先的层次
直译(保留原文语序、语气、修辞、信息重心)
> 顺译(调整语序使中文通顺)
> 意译(为可读性牺牲部分原文结构)
明确禁止的行为:
- 过度补全(补出原文没有的主语、因果、转折)
- 把翻译写成摘要或释义
- 重新组织原文结构
6.3 术语处理策略
- 首次出现:
中文翻译(原文术语) - 后续出现:直接使用中文译法
- 术语表全文统一,通过 GLOSSARY 机制跨片传递
- 人名:仅国际知名人物用公认译名(如 Euler → 欧拉),其余保留原文
6.4 视频脚本处理哲学
视频脚本(播客、访谈、演讲)是本系统处理最多的文体。其特殊性在于:
- 时间戳噪声:原文中密布的时间戳需要完全移除
- 碎片化句子:口语转录按时间切割,单句往往不完整,需合并为自然段落
- 口语冗余:“you know”、“like”、“I mean” 等填充词需在转书面语时自然消除
- 广告插入:YouTube 视频常含赞助商推广,需直接跳过
- 多人对话:需根据上下文推断说话人身份并标注
七、成本分析与弃用原因
7.1 Token 消耗分析
每片翻译的固定开销约 700-1200 tokens(系统指令 + 术语表 + 衔接段落),与原文内容无关。
以一篇 70K 字符的播客文字稿为例:
| 切分方式 | 片数 | 固定开销合计 | 相对增量 |
|---|---|---|---|
| 10K/片 | 7 | ~5,600 tokens | 基准 |
| 5K/片 | 14 | ~11,200 tokens | +100% |
| 3K/片 | 24 | ~19,200 tokens | +243% |
术语表随翻译进行不断膨胀,后期片段的固定开销更高。此外,每片的输出端也因独立的格式指令而产生额外 token。
7.2 弃用原因
- Token 消耗大:分片架构的固有开销——每片都要重复系统指令、术语表、衔接段落,总 token 消耗显著高于一次性翻译
- 速度慢:串行逐片翻译,无并发。一篇 13 片的文章需要 13 次独立 API 调用,加上重试和导读生成,耗时可达数十分钟
- 性价比不足:与直接在 AI Studio 等交互式工具中翻译相比,翻译质量没有明显优势,但开发维护成本和运行成本都高得多
- 复杂度高:断点续传、chunk manifest、动态重切等机制增加了系统复杂度,调试和维护负担重
7.3 适用场景反思
分片翻译架构适合的场景:原文极长(>100K)且需要高度一致的术语体系。对于大多数文章(<50K),现代 LLM 的上下文窗口(128K-1M tokens)已足以一次性处理,分片的必要性大为降低。
八、命令行接口
| |
--resume 参数已废弃,系统现在自动检测断点续传。
附录:可复用的翻译提示词
以下提示词从本系统的 Prompt 设计中提炼而来,适用于 AI Studio 等支持长上下文的工具,整篇一次性翻译,无需分片。
请将以下文本翻译为中文。
## 翻译原则
- 直译优先:保留原文语序、语气、修辞和信息重心;实在不通顺再调整语序
- 不要中介转写:直接从原文翻译为中文,不要先理解为英文再转中文
- 不要过度补全:不补出原文没有的主语、因果、转折或解释
- 不要写成摘要或释义,不要重新组织原文结构
- 专业术语首次出现时:中文翻译(原文术语),后续直接用中文
- 人名:仅国际知名人物用公认译名(如 Euler → 欧拉),其余保留原文
- 保持 Markdown 格式,代码/命令不翻译
## 如果是视频脚本/播客/访谈
- 移除所有时间戳
- 合并相邻短句为自然段落(3-5 句一段),口语转书面语但保持流畅
- 跳过广告和赞助商推广段落
- 说话人识别:根据上下文在每次说话人切换时标注 **说话人名字:**,同一人连续发言不重复标注
- 在话题切换处插入 ### 三级标题,简洁概括该段核心话题
## 输出格式
1. 译文正文
2. 文末附术语表:
| 原文 | 中文 |
|------|------|
| term | 译法 |
---
## 待翻译内容
(粘贴原文)