最近在整理《恶魔君 1989》第28集的字幕时,我用 DeepSeek 把英文字幕完整转成了中文。走完这一轮最大的感受是:DeepSeek 的翻译质量确实比通用在线翻译更适合字幕场景,但整个流程要做顺,必须把字幕清洗、上下文分段、格式还原和失败重试单独处理。这个经验不局限于这一集,老动画、纪录片、课程视频的字幕英转中基本都能复用。如果你正准备用大模型批量翻译字幕,这篇文章按实操顺序给你拆一遍。
先说结论:字幕翻译这个任务,真正花时间的不是调用模型,而是处理输入和输出。DeepSeek 擅长理解上下文、统一术语、保持角色语气,但前提是字幕文本要整理得足够规整。如果你直接把 srt 文件整个丢给模型,大概率会遇到翻译行数变少、时间码错乱、ass 样式标签丢失、同一角色名前后不一致这些问题。
下面按实际落地顺序拆解。
1. 字幕翻译这件事,难点不在“翻译”,在流程
1.1 为什么不能直接丢给翻译工具
字幕文件不是纯文本,它至少包含三层信息:序号、时间码、显示文本。如果是 ass 格式,还会包含样式控制代码。普通在线翻译工具只能处理第四层的文本,但返回结果时,前三层信息经常被夹带、错乱或者丢失。
还有一个更隐蔽的问题:字幕是按“显示时间”拆行的。同一个完整句子经常被拆成两行甚至三行。直接按行翻译,模型只看到半句话,代词、转折、因果关系都会判断错。尤其老动画里角色说话节奏快,一行字幕经常只有一个短语,单看根本不知道是谁在说话、对谁说话、语气是什么。
DeepSeek 这类大模型虽然有很强的上下文理解能力,但它只能处理你喂给它的文本结构。你把一段拆碎的字幕按行喂进去,它再聪明也只能跟着碎片走。所以第一步不是调 prompt,而是把字幕文件解析成“结构化的翻译单元”。
1.2 一条字幕任务的标准工序
我一般把字幕英转中拆成六步:
- 获取字幕文件并检查格式。
- 解析字幕文件,提取时间码、序号、样式标签和文本。
- 清洗文本,移除网页标签、乱码、多余空格。
- 按台词块合并上下文,调用 DeepSeek 翻译。
- 把翻译结果写回原字幕文件,保留原有时间码和标签。
- 校验输出,人工抽查术语、漏行和时间轴。
看起来简单,但每一步都可能出问题。比如合并上下文时,合并太多会导致 prompt 超过上下文窗口;合并太少又会丢失语境。又比如写回字幕时,如果翻译文本里有英文引号或逗号,可能会破坏 ass 标签结构。
这个流程一旦跑通,换任何一集字幕都能复用。所以我建议不要一上来就研究复杂参数,先把最小流程搭出来。
1.3 判断你是否需要 AI 字幕工作流
如果你只处理一两集字幕,用现成的字幕翻译软件就够了,不需要搭脚本。但如果你的需求是批量翻译、术语统一、多集连续剧,那 AI 字幕工作流值得投入。
还有一种情况也适合自己处理:源字幕质量差,里面有不少错误英文。这时候通用翻译软件会照字面翻,错误会一路放大。用 DeepSeek 配合术语表和 prompt,可以在一定程度上纠正明显的拼写、断句和歧义。
反过来,如果你的需求只是“能看懂大概意思”,那在线翻译完手动复制出来,可能更快。没必要为了 20 行的字幕搭一条完整流水线。
2. 准备阶段:先确认字幕类型、格式和接入方式
2.1 先区分文本字幕和硬字幕
处理字幕前,先确认源材料是哪种情况:
- 视频里有字幕,但没有字幕文件:这是硬字幕,需要先做 OCR 识别,再把识别结果整理成字幕文本。
- 有单独的 .srt 或 .ass 文件:这是软字幕,可以直接处理。
- 字幕文件存在,但时间轴和音频不完全匹配:需要先做偏移校正,再开始翻译。
我这次处理的是已经提取好的英文字幕文件,所以第一步是查看文件前 50 行,确认时间轴是否连续、文本是否存在乱码、有没有夹杂 HTML 标签或广告注释。
如果字幕是从网页或数据库抓取的,很容易混入多余字符。这些字符不清理,后面调用模型时会出现两类问题:一类是模型不理解无意义符号,输出会变得奇怪;另一类是输出文件写回后,播放器可能解析失败。
2.2 srt 与 ass 的差异
常见的字幕格式有 srt 和 ass,它们的结构差异很大。
| 格式 | 结构特点 | 处理重点 |
|---|---|---|
| srt | 序号、时间码、文本,结构简单 | 保持时间码格式,避免序号丢失 |
| ass | 包含样式定义、特效标签、对话事件 | 保留标签,如 {\pos}、{\an8}、{\c&HFFFFFF&} 等,不要翻译标签内容 |
srt 处理起来更安全。它的每一块是独立结构,模型不容易破坏。ass 则必须有标签保护机制,否则模型可能把 {\an8} 当成普通文本处理,结果就是字幕位置乱跳、字体颜色错乱。
如果你要处理的是 ass 字幕,建议先做一个预处理:把行内的 ass 标签用占位符替换,比如用 [TAG1]、[TAG2] 代替,翻译完再恢复。这样模型只翻译可见文本,不会动样式代码。
2.3 模型接入的几种方式
DeepSeek 的接入方式我见过三类,各有利弊。
第一类是官方 API。这种方式适合批量处理,脚本稳定,有账号体系、计费和接口文档。你需要申请密钥,按请求量使用。适合有一定开发能力、要处理几十集字幕的情况。
第二类是本地部署。把模型跑在自己的机器上,数据不需要出本地网络,适合隐私要求高的场景。但对硬件有要求,显存和内存不够的话,跑大上下文会很吃力。如果你的机器配置不高,不要硬开最大上下文窗口。
第三类是桌面封装工具。一些项目会把 DeepSeek 封装成带界面的工具,通常叫 harness 或桌面版。好处是操作简单,适合不熟悉代码的人。坏处是封装工具之间的功能差别很大,有的只支持单条文本翻译,有的才支持字幕文件导入。使用前一定要确认它是否支持 srt/ass 解析,是否保留时间轴,否则你翻译完还是得手动粘贴回去。
我不太建议在前期同时研究三条路线。先选一种最适合自己的,把流程跑通,再考虑切换。
2.4 建一张术语表
字幕翻译的术语一致性问题,靠模型记忆是解决不了的。同一个角色名,模型可能上一行译成“恶魔男爵”,下一行译成“邪恶魔王”。同一个咒语名,不同行也可能出现不同译法。
所以在准备阶段,我会先建一个术语表。对《恶魔君 1989》这种老动画来说,术语表至少包含几类:
- 角色名:主角、配角、反派的名字。
- 专有名词:恶魔名、妖怪名、招式名、地点名。
- 特殊表达:角色口头禅、咒语、语气词。
- 是否保留原文:某些专有名词可能保留英文更好,要在表里标注。
术语表最终会拼进 prompt。它的作用是约束模型,不让它自由发挥。实际经验是,术语表不需要很长,10 到 30 条通常就够。太长的术语表反而会占用上下文窗口,影响核心翻译。
3. 先跑通单条字幕:清洗、分段和上下文策略
3.1 按台词块读入,不要按文件行读入
字幕文件的行结构是这样的:
123 00:09:55,123 --> 00:09:58,456 Demon Lord, you cannot defeat me!这里的文本是“Demon Lord, you cannot defeat me!”,但它可能只是完整对话的一部分。解析时应该按“块”读取,每一块包含序号、时间码、文本。而不是按物理行逐行读,因为那样会把序号、时间码和文本混在一起。
我常用的思路是:
# 伪代码:说明字幕解析思路 for block in parse_srt(file): block_id = block["id"] timecode = block["timecode"] text = block["text"] translated = translate_text(text) write_to_output(block_id, timecode, translated)这只是一个示例流程。实际用哪个库解析,取决于你的开发环境。重点是:在解析层面就把序号、时间码和文本彻底分开,翻译只针对文本,其他字段原样保留。
3.2 保留上下文和角色信息
字幕里经常看不到说话人,但翻译时需要知道是谁在说。尤其是两三个角色对谈的场景,如果上下文不够,模型会把主语搞混。
我的做法是:在翻译当前块时,把前面几条相邻的原文也一起传进去作为上下文。例如:
上一段字幕:I will summon the demon tonight. 上一段字幕:You are crazy. He will destroy us all. 当前段字幕:Let him come. I am ready.模型看到前三行,就能明白当前这句话是主角在回应别人的劝阻,语气要坚定,而不是单纯翻译“让他来,我准备好了”。
上下文窗口不宜太长。传 3 到 5 条原文通常足够。太长会稀释模型对当前行的注意力,增加时间成本。
3.3 用一条样例验证 prompt
不要一次性提交整个字幕文件。我一般先取前 20 到 30 行做样例,跑一遍确认三件事:
- 模型是否正确只输出了文本,没有额外解释。
- 原文里 30 行,输出是否也是 30 行。
- 角色名和术语是否按术语表翻译。
样例跑通了,再继续跑完整文件。这个习惯能省很多时间。因为如果你 prompt 设计有问题,批量跑完才发现,等于全部重来。
3.4 单条样例的成功标准
很多初学者把“模型没报错”当成成功。实际上,对于字幕任务,成功标准要更具体:
- 输出行数与输入行数完全一致。
- 序号和时间码没有被修改。
- 所有可见文本都被翻译成中文,没有遗留英文。
- 角色名、专有名词符合术语表。
- 译文长度适合显示,不会一屏塞满长句。
如果某一条不满足,就先调整输入结构或 prompt,不要直接调模型参数。大多数问题出在输入侧,不是模型侧。
4. 翻译提示词、参数和《恶魔君》类老动画的注意点
4.1 提示词里要写清什么
给 DeepSeek 的翻译 prompt 至少要包含五类信息:
- 角色设定:你是一名资深字幕翻译。
- 输入格式说明:下面是一个字幕块,包含序号、时间码和英文文本。
- 输出格式要求:只输出中文译文,不要输出序号、时间码或解释。
- 术语表:角色名按指定译法翻译。
- 风格要求:口语自然,适合字幕展示,尽量简洁。
一个示例 prompt 大概是:
你是一名资深字幕翻译。下面是一个字幕块: ID: 123 Time: 00:09:55,123 --> 00:09:58,456 Text: Demon Lord, you cannot defeat me! 请把 Text 翻译成中文。要求: 1. 只输出译文本身。 2. 中文要自然,符合角色语气。 3. 不超过 24 个汉字。 4. 角色名词表:Demon Lord=魔君,Alice=爱丽丝。这个提示词结构简单,但很有效。它把约束说清楚了,模型不需要猜测。
4.2 与字幕场景相关的参数
字幕翻译对随机性很敏感。同一个输入,如果每次输出差异过大,说明随机性太高,不适合字幕场景。
常见可调参数包括:
| 参数 | 对字幕翻译的影响 | 建议 |
|---|---|---|
| temperature | 越高越随机,越低越稳定 | 字幕翻译尽量低,建议先从小数值试起 |
| max_tokens | 控制单次输出的最大长度 | 根据字幕文本长度预留足够余量 |
| top_p | 控制候选词范围 | 如果接口支持,可以配合温度一起调 |
| 上下文窗口 | 单次请求能处理多长内容 | 不要填满,给输出留空间 |
不同版本的模型接口,参数范围可能不一样。落地时以你实际接入的接口文档为准。我的建议是:先保持默认参数跑一遍,看到输出不稳定或重复,再调低 temperature。不要一开始就追求“完美参数”。
4.3 老动画字幕的翻译注意点
《恶魔君 1989》是早期动画,字幕和现代美剧有明显差异。老动画对话中常有大量专有名词、感叹词、叫喊和短句,翻译时要注意几点:
第一,专有名词要稳定。恶魔名、妖怪名、招式名尽量对照术语表。同一个名字在不同集里出现时,译名要一致。尤其连续剧集,第28集的译名最好和前面集数保持一致,否则观众会误解。
第二,语气词要有保留。台词里的“Hah!”, “Grrr…”, “No way!” 这类表达,不能全部翻译成“哈!”“呃……”。要根据场景选更自然的中文情绪词,比如“哼!”“休想!”“可恶!”。
第三,注意台词长度。英文短句翻译成中文后可能变长,也可能变短。如果译文太长,播放时会出现一屏塞满字的情况。所以 prompt 里我会加一个“尽量简洁”的约束,必要时人工压缩。
第四,老动画里有些台词是交代设定的,翻译时要把因果关系理顺。这类台词如果只看一行碎片,很容易译反。
5. 时间轴、样式标签和字幕校验
5.1 时间轴不要交给模型生成
这是我在字幕翻译里踩过最明显的坑。最开始我让模型直接输出完整字幕块,包括时间码和序号。结果模型偶尔会把时间码格式写错,比如把00:09:55,123写成00:09:55.123,或者把结束时间提前。
正确的做法是:时间轴在程序里原样保留,翻译只处理文本。
具体流程是:
- 解析字幕文件,把时间码和文本拆开。
- 把文本发给 DeepSeek 翻译。
- 拿到中文译文后,把原时间码、原序号和中文文本重新拼装成新的字幕文件。
这样即使模型输出只包含文本,最终字幕文件也不会缺时间轴。
5.2 ass 样式标签保护
ass 格式里,一行字幕可能长这样:
{\an8}Demon Lord, you cannot defeat me!{\an8}表示字幕显示在屏幕上方中间。如果你直接把这个字符串发给模型,它可能会把这段标签改成别的样子,或者干脆删掉。播放时字幕位置就变了。
我通常的做法是:在清洗阶段把标签替换成占位符,比如把 {\an8} 换成 [T1],把 {\c&HFFFFFF&} 换成 [T2]。翻译时模型只会看到 [T1],不会去翻译它。翻译完成后再把占位符还原成原标签。
这个保护机制对批量任务很重要。ass 字幕里标签一旦丢失,人工恢复会非常痛苦。
5.3 校验清单
翻译完成不代表结束,一定要校验输出文件。
我的校验顺序是:
- 新字幕文件能否被播放器正常加载。
- 字幕块数量是否和原文件一致。
- 时间码格式是否正确,有没有逗号和小数点混用。
- 有没有空文本行、重复序号。
- 抽查 5% 到 10% 的字幕,对照原文看术语、语气和断句。
抽查时我会把原文和译文并排显示。重点看三处:角色名是否一致、咒语类特殊名词是否保留、明显语气是否丢失。
如果发现某一行有明显错误,直接手动修改,不需要重新批量跑一遍。
6. 坑点与排查:从第28集到批量任务
6.1 翻译请求失败的排查链路
请求 DeepSeek 失败时,不要急着怀疑模型能力。按这个顺序查:
- 先看返回的错误信息,是超时、鉴权失败还是请求格式错误。
- 确认接口地址、密钥、模型名称是否填对。
- 确认请求体里的字段名和接口文档一致,尤其是 messages、model、max_tokens 这类字段。
- 确认输入文本里没有非法字符,比如未闭合的引号、异常控制符。
- 确认单次请求没有超过上下文窗口限制。
如果是批量任务中途失败,要看是否有重试机制。我一般会为单条请求加 2 到 3 次重试,并记录失败日志。字幕文件里某一两条失败,不应该让整个任务中断。
6.2 翻译结果“怪”时先调哪里
当翻译结果读起来很奇怪时,大多数人会想调 temperature。但我的习惯是先改输入,再改 prompt,最后才动参数。
排查顺序是:
- 先看原文是否被正确清理。原文如果带 HTML 标签、乱码、重复空格,模型输出必然乱。
- 再看上下文。如果模型不知道谁在说话,译文就会缺少语气。
- 接着看 prompt。如果没写清楚“只输出译文”,模型可能会给你一段解释。
- 最后再看参数,把 temperature 调低一档,重新试一次。
不要连续重试同一条请求,输入不变、参数不变,结果大概率只是随机变化。
6.3 字幕不同步和漏行
输出字幕不同步,最常见的原因不是翻译,而是写回逻辑有误。
比如解析时丢失了时间码,或者拼接时把序号弄错位。排查时先在输出文件里随机抽几条,对比原文序号和时间码。如果时间码和原文件一模一样,但播放时还是不同步,那是视频文件本身的时间轴问题,和翻译无关。
漏行则多半是分段或批量调用时丢消息。解决方法是:翻译完成后,按序号把输出映射回原字幕块。如果发现有缺失行,单独补充翻译,而不是重新提交整段。
6.4 多集批量处理的稳定性设计
如果你要处理的不止第28集,而是整部动画几十集,一定要做批量任务的稳定性设计。
关键点有三个:
- 并发控制。不要一次性把所有集数提交到队列里。先跑 1 到 2 集,确认流程稳定,再扩大范围。
- 失败重试和断点续跑。每集输出一个独立结果文件,记录处理状态。已经成功的集数不要重复调用。
- 输出命名规范。比如
ep28.zh.srt、ep28.zh.ass,和源文件放在不同目录,避免覆盖原英文字幕。
批量任务除了关注“能不能跑”,还要关注“跑完后能不能直接用”。我见过不少批量任务最后生成一堆半成品,就是因为没有为每集输出单独校验。
字幕英转中这个任务,真正稳下来靠的不是某一个参数,而是把输入文本、上下文、术语表、输出格式和重试机制都做好。DeepSeek 能减少翻译上的死板感,但字幕文件本身的格式和批量任务的管理,还是要靠自己。
你如果正准备处理老动画或剧集字幕,建议先拿一集把流程跑通,再决定要不要批量。最值得盯住的三件事:行号别丢、标签别坏、术语统一。