Babel Studio:一套本地优先、可追踪的 AI 翻译与漫画嵌字系统
2026/7/24 17:50:33 网站建设 项目流程

Babel Studio:一套本地优先的长文本翻译与漫画自动嵌字系统

项目名称:Babel Studio(巴别塔智能本地化工作室)

项目类别:生成式 AI / 智能体 / 多模态内容生产

开源仓库:GitHub - rust234a2/babel-studio

1. 背景:翻译完成不等于作品完成

小说和漫画的本地化,麻烦远不止把一句日文换成一句中文。长篇小说要一直维护人名、地名、称谓和世界观设定。章节一多,同一个角色很容易换个上下文就换了译名。漫画还多出竖排 OCR、阅读顺序、气泡检测、原文擦除、背景修复和重新排版。现有工具大多只管其中一截:译文留在聊天窗口,术语表放在另一个文件,嵌字时又得回到图像软件。

所以我想把这些环节收进同一个工作台。用户导入 TXT、Markdown、DOCX、EPUB 或漫画页面后,系统为作品建立档案,接着完成翻译、审校、消字、嵌字和质量复检,中间事件与产物也一并保存。未公开文本尽量不离开本机;公开或已获授权的漫画可以按需调用 Stepfun 视觉服务。

Babel Studio 从一开始就按“模型会失败”来设计。OCR 服务没启动,任务就走本地回退;文字放不进气泡,排版器宁可标记失败,也不能悄悄画出边界;微调 loss 再好看,也得经过固定测试才能谈效果。系统要留下足够的证据,让人能顺着记录找到出错的那一层。

2. 问题分析:为什么这条流水线难做

2.1 长篇文本的问题是记忆和约束

单个段落翻译得自然,不代表整本书都能保持一致。每次都把完整术语表和全部前文塞进 Prompt,上下文成本很快就会上涨,模型还未必听话;每章各管一份词表,人物改名时又得逐章修改。我最后采用的是作品级记忆、按需召回和译后检查,没有继续堆上下文长度。

2.2 漫画的问题横跨文字与图像

OCR 只能回答“图片里可能写了什么”。文字属于哪个气泡、先读哪一列、擦掉原文后怎样补背景、译文放进去会不会挡住人物,都不是 OCR 能单独解决的。日文竖排、多列对白、细长气泡和不规则边框还会继续放大误差,因此区域检测、OCR、图像修复、排版和视觉复检缺一不可。

2.3 本地部署的问题是资源调度

DGX Spark 有 128GB 统一内存,但 Qwen、Step-3.7-Flash、Sakura、Nemotron、向量模型和图像工具还是不适合全按峰值配置常驻。长上下文建库与高并发翻译的负载也不一样。模型装得下,只能说明方案有机会运行;现场能不能稳定,还得看量化方式、常驻服务和运行档位怎么安排。

2.4 团队协作的问题是模型太大

前端队友的普通开发机跑不了几十到上百 GB 的模型。假如 UI 开发必须连着真实推理服务,两个人只能轮流占用同一台模型机。为了解开这个结,项目提供了稳定的接口契约、可回放样例和 Mock/API 双模式,日常前端开发不必等 GPU 空闲。

3. 设计目标、作品特点与核心亮点

Babel Studio 用一套作品档案承接小说和漫画,让文本翻译与漫画嵌字共享术语资产。翻译时只注入当前段落命中的术语,完成后再检查定译、占位符和疑似漏译,既控制上下文长度,也避免同一个人物在不同媒介中出现两套名字。正文、模型权重、训练语料和 checkpoint 默认留在 NVIDIA DGX Spark;漫画视觉理解则保留 Stepfun API 和本地 OCR 两条路线,由用户按素材的敏感程度选择,云端不可用时也能降级运行。翻译、审校、文化适配和视觉处理各用合适的模型,系统只接管重复劳动,不承诺无人值守出版;不规则艺术字、跨格 SFX、严重受损背景和无法安全排版的气泡都会标记为needs_human,生成文件与通过质检也会分别显示。任务执行期间,每个阶段都会写入带递增序号的事件,章节、术语、检测图、消字图、成品页和质量报告则保存为可定位的产物。这样既能把质量问题追到具体章节、页面和气泡,也能在浏览器刷新或网络波动后从最后一条事件继续,不必重新支付一遍模型推理成本。

4. 系统设计:架构思路与模块关系

4.1 这套系统里,各项技术分别做什么

前端使用 React、TypeScript 和 Vite。FastAPI 本身不负责翻译,它把文件上传、任务创建和结果查询封装成 API,再编排后面的智能体。浏览器通过 HTTP 发起任务,通过 SSE 持续接收进度。对于这种服务器不断汇报、浏览器主要负责接收的长任务,单向事件流已经够用。

这里说的智能体并非某种新模型,而是职责、输入输出和工具权限都写清楚的程序。翻译智能体生成初稿,审校智能体负责回译与语义检查,文化适配智能体处理俚语和必要的缩句,编排器安排执行顺序、重试和降级。文字生成交给大语言模型,语义比较交给向量模型,图片与文字的联合理解则交给多模态模型。

漫画侧还会用到 OCR、目标检测和图像修复。OCR 识别字符,检测器寻找文字区域并生成待清除像素的 mask,LaMa 根据四周图像补回被擦除的背景,排版器再计算字体、行宽、方向和标点禁则。这几项工具各管一件事,无法由视觉模型的一次整页回答包办。

本地推理使用启用GGML_CUDA的 llama.cpp,把计算交给 NVIDIA GPU。权重采用 GGUF 格式,Q4、Q6、Q8 等量化方式用少量质量损失换取更低内存占用。KV Cache 保存已经算过的上下文状态,长度和精度都会影响内存与速度。LoRA 只训练少量附加参数,相关实验由 PyTorch CUDA 与 Triton 完成。

4.2 整体架构与设计思路

系统被拆成浏览器、编排器、领域流水线、模型服务和持久化五层:

React / TypeScript / Vite │ HTTP + SSE ▼ FastAPI Orchestrator │ ├── 文档解析 ── 术语召回 ── 翻译 ── 回译审校 │ └── 漫画检测 ── OCR ── 消字 ── 嵌字 ── 视觉复检 │ ├── Qwen / Sakura / Nemotron / bge-m3 ├── Step-3.7-Flash / Stepfun Vision └── comic-text-detector / RapidOCR / LaMa │ ▼ SQLite + JSONL ledger + 图片与报告 Artifact

这套架构有两条基本原则。能精确计算的内容交给代码,例如文档解析、气泡坐标、字符预算和事件序号;翻译、文化改写与视觉语境判断才交给模型。另一个原则是用稳定契约隔离变化:模型服务统一提供 OpenAI 兼容接口,流水线事件遵循固定 Schema,产物通过统一标识关联。以后替换模型时,前端和任务记录不用跟着推倒重来。

单个模型很难同时顾好翻译流畅度、术语一致性、文化适配和质量判断。拆开以后,每一步可以选更合适的模型,也可以单独重试或降级。前端始终只面对一套任务协议,不必关心后台刚刚切换了哪条模型路线。

5. 技术实现、技术栈与优化方案

5.1 文档解析与作品记忆

小说链路支持 TXT、Markdown、DOCX 和 EPUB。日文纯文本兼容 CP932、EUC-JP 与 ISO-2022-JP;DOCX 按段落提取,EPUB 按 OPF spine 顺序读取并忽略 ruby 注音。作品术语存入 SQLite,用project_id隔离,不同语言使用各自的候选规则。翻译时只召回当前段落命中的术语,再附上少量前后文帮助模型判断指代和口吻。模型仍被要求只输出当前段落,以免上下文越滚越长。

翻译完成后,代码先检查定译、占位符和疑似漏译。随后由 Nemotron 回译,bge-m3 比较原文与回译文本的语义相似度。低于阈值的片段会进入重译或人工复核。术语也不再是一段用完即丢的 Prompt,而是可以编辑、追踪和重新检查的数据。

5.2 技术栈说明:NVIDIA、Stepfun 与模型路由

模型没有简单按参数量排座次,我按任务分工:

类别实际采用的技术在项目中的作用
NVIDIA 硬件与 SDKDGX Spark、GB10 Grace Blackwell、NVIDIA CUDA Toolkit 13.0提供 128GB 统一内存与本地 GPU 推理能力
NVIDIA 大模型NVIDIA Nemotron Nano 9B v2回译审校、文化适配和缩句
Stepfun 阶跃星辰模型step-1o-turbo-vision、Step-3.7-Flash + mmproj云端漫画理解、本地长上下文与视觉复检
翻译与检索模型Qwen3.6-35B-A3B、Sakura-14B-Qwen3-v1.5、bge-m3通用翻译、日译中和语义相似度计算
漫画视觉工具comic-text-detector、OpenCV、ONNX Runtime、manga-ocr、RapidOCR、LaMa检测、OCR、消字和背景修复
应用与数据层React、TypeScript、Vite、FastAPI、SQLite、JSONLUI、任务编排、术语资产和事件记录

本地模型都提供 OpenAI 兼容接口。上层智能体只依赖服务地址和统一请求格式,所以 Sakura 没启动时可以退回 Qwen,Nemotron 更换部署方式也不用重写编排逻辑:

qwen=LLMClient("http://localhost:8081","qwen-batch")nemotron=LLMClient("http://localhost:8001","nemotron-local")sakura=LLMClient("http://localhost:8083","sakura")bge=LLMClient("http://localhost:8002","bge-m3")

我也评估过用 TensorRT-LLM 的trtllm-serve部署 Nemotron。不过在当前 aarch64 环境中,交付版本最后统一用了 CUDA 版 llama.cpp。应用层可以由 Docker Compose 启动,GPU 模型仍跑在宿主机,目前不依赖 NVIDIA Container Toolkit。这里列的是实际落地方案,而不是所有尝试过的技术名词。

5.3 漫画处理链与嵌字效果

漫画页先经过检测器,得到文字区域和像素级 mask,再由 manga-ocr、RapidOCR 或 Stepfunstep-1o-turbo-vision识别内容。纯色气泡直接填充,复杂背景交给 LaMa 修复。OCR、翻译和排版数据都用bubble_id串联,视觉模型返回的阅读顺序、说话人线索和情绪才能准确落回本地检测框。

嵌字时,排版器从可读字号开始尝试换行和缩放。只有确认溢出且字符预算允许,系统才会调用文化适配智能体缩句;还是放不下,就保留完整译文并转交人工处理。最终页面还可送入 Stepfun Vision 或本地 Step-3.7-Flash + mmproj,检查overflowocclusionmisplaced。mmproj 是把视觉编码结果映射给语言模型的投影权重。

下面两张图来自同一页测试素材。系统保留了拟声字和线稿,只清除气泡里的原文,再按气泡宽高选择字号与换行。

下面两张图来自同一页测试素材。系统保留了拟声字和线稿,只清除气泡里的原文,再按气泡宽高选择字号与换行。

消字后的中间图日译中并重新嵌字后的成品

5.4 长任务事件与前端协作

FastAPI 把事件追加到 JSONL ledger,每条都带递增的seq。前端记住最后收到的序号,重连时从after_seqLast-Event-ID接着收;状态层会丢弃重复事件。订阅端只需要建立一条 EventSource:

constsource=newEventSource(`${baseUrl}/jobs/${jobId}/events?after_seq=${afterSeq}`,);

前端支持 Mock 和 API 两种模式。队友平时用小型 fixture 开发书架、任务状态和错误界面,不需要下载模型权重。分支提交后,我再拉到模型机上跑契约校验,连接真实的 FastAPI、SSE 和模型服务。这样,UI 开发不会卡在 GPU 排期上。

5.5 部署说明:利用本地算力部署智能体

项目部署在 NVIDIA DGX Spark 上,硬件是 GB10 Grace Blackwell Superchip 和 128GB 统一内存,CUDA Toolkit 版本为 13.0。Qwen、Sakura、Nemotron、bge-m3 和 Step-3.7-Flash 分别由独立的 llama-server 进程加载;翻译、审校、文化适配等 Python 智能体运行在 FastAPI 编排器中,通过固定端口调用模型。模型进程可以按任务阶段启停,某项服务不可用时也方便切到回退路线。

模型权重、语料和 checkpoint 不进入 Git,由.envMODEL_DIR指向模型机目录。先在 DGX Spark 上编译启用 CUDA 的 llama.cpp server:

cmake-Bbuild-DGGML_CUDA=ON-DLLAMA_BUILD_SERVER=ON cmake--buildbuild -j$(nproc)

端口约定如下:Qwen8081、Sakura8083、Nemotron8001、bge-m38002、Step-3.7-Flash + mmproj8080。常用服务由仓库脚本启动:

MODEL_DIR=/path/to/models ./models/serve-B-qwen.shMODEL_DIR=/path/to/models ./models/serve-nemotron.shMODEL_DIR=/path/to/models ./models/serve-bge.shMODEL_DIR=/path/to/models ./models/serve-sakura.sh

模型服务健康后,再启动 FastAPI 编排器和 React 前端:

python3-mvenv .venv .venv/bin/pipinstall-rorchestrator/requirements.txt .venv/bin/uvicorn orchestrator.app:app--host0.0.0.0--port8051npmcicp.env.example .envnpmrun dev

Stepfun 云端视觉路线通过本机环境变量启用,密钥不会提交到 Git:

VITE_DATA_MODE=api VITE_API_BASE_URL=/api/v1 VITE_API_TIMEOUT_MS=15000 STEPFUN_API_KEY=<本地填写> STEPFUN_VLM_MODEL=step-1o-turbo-vision

浏览器入口是http://localhost:5173/。在服务器内部,可以用http://localhost:8051/health检查 FastAPI;浏览器端不直接访问这个地址,而是请求同源/api,再由 Vite 转发到后端。用户创建任务后,编排器按源语言和任务阶段选择本地智能体。只有打开视觉增强且素材允许时,漫画页面才会调用 Stepfun API。应用层也能通过 Docker Compose 启动,不过 GPU 模型服务仍留在宿主机,以免 CUDA 环境和大体积权重拖累日常前端联调。

5.6 大模型优化方案

资源方面,Qwen 使用UD-Q4_K_M,Sakura 使用 Q6_K,Step-3.7-Flash 使用 IQ4_XS 和 Q8 KV Cache,bge-m3 使用 Q8_0。这样能为 OCR、审校和图像处理留出内存。吞吐方面,我实测了 8、16 和 32 路并发,最后把 Qwen 定在 16 路,批量聚合吞吐约 235 token/s。继续提高并发,收益没有同比增长,延迟和内存波动反而更大。

调度上,环境分成建库/复核档与翻译量产档:大模型按阶段切换,小模型按需常驻,训练和整本夜跑通过SPARK-LOCK.md预约独占时段。质量优化则依靠固定测试集与位置打乱的第三方盲评。众包参考译文把 LoRA 训坏以后,我没有继续调参,而是换成通过教师门测试的 Qwen 35B 生成蒸馏目标。量化、KV Cache 和并发只是优化的一部分,数据与评估方法同样会决定最后的质量。

5.7 蒸馏模型

通用翻译老师 Qwen3.6-35B-A3B 是 MoE 模型,约有 35B 总参数,每个 token 激活约 3B。它以较低的单 token 活跃计算量换取更大的知识容量,适合在 DGX Spark 上当教师并批量生成数据。但部署时仍要保存和加载完整专家权重,运行时也依赖专家路由及相应算子。

学生 Qwen3-8B 是 Dense 模型,每个 token 都经过同一组 8B 参数。它并不天然比 MoE 质量更高,单 token 的活跃参数也未必更少。选择它主要是出于部署考虑:总权重小、计算路径固定、容易量化,LoRA 合并后还能直接导出成单个 GGUF。边缘设备、个人工作站和要求批延迟稳定的服务,更需要这种可移植性。

对比维度35B-A3B MoE 老师8B Dense 学生
主要价值容量大,适合生成高质量蒸馏数据权重小,适合长期部署和分发
每 token 路径动态选择部分专家固定经过同一组 Dense 层
内存特点激活参数少,但完整专家权重仍需驻留总权重只有 8B,Q4_K_M 成品为 4.68 GiB(5.03 GB)
微调与导出专家路由和适配模块更复杂LoRA、merge、GGUF 量化流程成熟直接
本项目定位教师与高吞吐量产档可部署的中译英专用学生

这次蒸馏要解决的是交付体积,而不是证明 Dense 全面胜过 MoE。教师门测试使用 200 条中译英网文样本,并用位置打乱的 DeepSeek A/B 判读。本地 35B 相对基础 8B 为 124 胜、60 负、16 平,净偏好+32pt,在这批数据上足以担任教师。随后由它生成 5 万条目标,清理 200 条残留 CJK 的输出,留下 49,800 条训练数据。8B 学生用 LoRA 训练 3,113 步,合并后量化为 4.68 GiB(5.03 GB)的 Q4_K_M GGUF。单句冒烟测试约 41 token/s,可独立运行在8084端口:

llama-server\-m/path/to/qwen3-8b-distill-50k-q4km.gguf\--aliasguofeng-zh-en-distill50\-c4096-nglall--jinja--port8084

这里要把训练评测和部署评测分开看。后文 200 条 A/B、BLEU 与 chrF++ 的对象是 BF16 基座挂载 LoRA;量化后的 GGUF 最初只做了加载和单句冒烟,后来又用同一个 Q4_K_M 成品跑完 6 章、407 段的长文全链路。它证明了量化模型能在 llama.cpp 下持续完成翻译、术语处理、回译、SSE 和产物生成,也帮我找出了质量门禁的问题。不过,两次评测的输入不同,也没有对 BF16 与 Q4 做逐条配对,不能据此认定二者质量完全相同。

6. 遇到的问题与解决方案

6.1 128GB 内存不等于模型可以全部常驻

最初我想把 Step-3.7-Flash、Qwen、Nemotron 和向量服务全部启动,随时响应不同智能体。实际一跑,长上下文和高并发负载开始争抢内存,现场演示反而更不稳定。最后只能把环境拆成“建库/复核档”和“翻译量产档”,GPU 使用登记在SPARK-LOCK.md。训练、整本夜跑和演示各占明确时段,“一键全开”也不再是目标。

6.2 整页视觉模型无法稳定对应气泡

日文竖排页会漏假名,也会把多列文字拼错顺序。可如果直接把整页交给多模态模型,返回文字又很难与本地气泡逐一对应。我最后保留了两步:先做确定性的区域检测,再把整页图、bubble_id和坐标交给 Stepfun,要求它按 ID 返回内容、阅读顺序和说话人线索。API 不可用时,日文回退到 manga-ocr,并按从上到下、同行从右到左重新排序。

6.3 翻译后存在12 个空泡

46 页漫画第一次跑完后有 12 个空泡。我以为译文太长,于是打开缩句救援重跑。空泡仍是 12 个,缩句成功次数为 0。核对预算后才发现,10 个气泡的译文字数压根没有超限;另外 2 个预算过小,系统为了不把拟声词压坏,拒绝了自动缩句。模型服务没坏,触发条件从一开始就没有成立。

问题出在 CJK 换行器。旧逻辑为了避免省略号和破折号落在行首,会把标点硬塞回上一行;紧接着,宽度校验又把这条超宽行判为不可排。排版器选择安全失败,没有把文字画出气泡,于是出现了“剧本有译文、成品没落字”的空泡。

修复后的规则是:上一行放不下禁则标点,就把末字和标点一起挪到下一行;如果窄到连一个字加标点都放不下,允许标点单独占行。......也只在显示层统一成中文……。简化后的核心判断如下:

carry=cur[-1]+chifchinNO_LINE_STARTandlen(cur)>1andfits(carry,max_w):lines.append(cur[:-1])cur=carryelse:lines.append(cur)cur=ch

随后,我把这 12 个真实气泡固化成回归样本。复用原译文和消字图重新排版,空泡从 12 个降到 0。以后再遇到类似故障,我会先查规则和数据,最后才考虑模型救援。

6.4 训练 loss 下降,译文却变差了

第一阶段,我用众包参考译文训练 Qwen3-8B LoRA。训练 loss 一直下降,可在同一套第三方 A/B 流程里,三个版本仍比基础模型低约 27 至 30 个百分点。过滤低分样本、清理异常符号也没能扭转结果。抽样复核后,问题变得很直接:参考译文本身经常还不如基础模型。loss 只能说明学生正在拟合目标,无法说明这个目标值得学。

后来我先给教师模型做门测试,再让本地 Qwen 35B 生成蒸馏目标。1 万条版本相对基础 8B 为 86 胜、72 负、42 平,净偏好+7pt;5 万条版本为 93 胜、68 负、39 平,净偏好+12.5pt。50k 与 10k 直接比较时是 75 胜、54 负、71 平,净偏好+10.5pt。结果终于从持续负向转为正向,CJK 泄漏也从基础模型的 9/200 降到 0/200。

这个实验没能把所有因果因素拆开。蒸馏方案同时更换了目标来源、清洗方式和数据分布;从 10k 扩到 50k 时,样本量增加五倍,一个 epoch 的优化步数也从 623 增到 3,113。目前只能说,在这套中译英网文数据和训练配方下,“35B 教师目标 + 清洗 + LoRA”比众包参考训练给出了更可靠的正向信号,50k 也强于 10k。至于提升分别有多少来自数据量、更新步数或某条清洗规则,现有实验还回答不了。

6.5 单句评测通过后,407 段 E2E 仍测出了什么

离线 A/B 能判断输出偏好,却看不到生产链是否安全。所以我用最终的 Q4_K_M 模型,把上传、章节解析、术语抽取、翻译、文化适配、回译审校、SSE、产物 API 和真实前端完整跑了一遍。输入由一本留出作品的 398 个连续正文段落,以及 9 个带跨章专名和占位符的原创段落组成,解析后共 6 章、407 段。

首次运行没有崩溃,407/407 段也都有输出,但这些输出离“可交付”还有一段距离:

E2E 发现为什么原有检查没拦住解决办法同数据最终复测
“10级学徒?”原样回显中文,却以相似度 1.0 进入final回译能复述中文原文,“语义相似”不等于“已经翻译”在回译前增加目标文字系统与原文照抄检查;整段重试仍失败时,只翻译残留片段并按字符边界回填,同时保护{player}和 HTML 标签CJK 残留段落1 → 0,3 次文字系统违例均自动修复
4 个短段被相邻上下文覆盖,1 个输出泄漏【Next Reference】短标题和对白信息少,参考段落反而占据生成注意力<reference_context translate="false">隔离参考;检测内部标记和相邻原文复述,命中后无上下文重试已知串段4 → 0,上下文标记泄漏1 → 0
黎明 => Dawn等误识别候选被当成强制术语,制造生硬译文和失败重试自动候选与人工确认没有权限边界只有confirmed术语进入 glossary 和确定性失败门槛,candidate只进入审核队列候选术语强制违例1 → 0
术语命中率 0.9975 仍掩盖Xilan/Ceylan等跨章变体后续章节发现的术语没有回填前文,指标只统计已有 mention项目术语汇总后对全书倒排扫描并补写 mentionmentions178 → 202;但别名归并仍待人工确认
23 段处于reviewing,项目却显示completed“流水线处理结束”和“允许发布”共用一个状态只要仍有待审段落,任务终态改为warning,书架和工作台显示“待校对”最终为395 final / 12 reviewing,项目终态为warning
前端加载 254/407 的快照后,被旧 SSE 事件回退到 32%历史事件无条件覆盖了更新的服务端快照进度百分比和已处理计数按单调递增方式合并最终 82 条 SSE 序号严格递增,单调合并回归测试通过
文化适配把fat merchant改成wealthy merchant,改变人物外貌自动“礼貌化”被错误当作文化适配默认切换为 advisory,只把建议和理由写入 ledger;显式开启auto才覆盖正文14 条建议均未自动改写正文

最终复测仍得到 407/407 段完整译文,平均回译相似度从 0.8949 升到 0.9012。在 398 个有参考的段落上,BLEU 从 19.94 升到 20.37,chrF++ 从 43.23 升到 43.76。占位符{player}<color=gold></color>全部保留。自动分数只涨了一点,但已知的 CJK 残留、提示标记和明显串段不再悄悄混进最终产物,这个变化更实用。

安全恢复不是免费的。自动恢复调用从 4 次增加到 21 次,吞吐从 28.9 降到 26.31 段/分钟,下降 8.96%。这一轮我接受了约 9% 的吞吐损失,因为错误被看见、还能自动恢复,比表面上的速度更重要。

复测后还有 12 个reviewing,都来自低于 0.75 的回译相似度。其中包括“晦气!”嘭嘭嘭!这类合理短译,说明固定阈值会误报短句。16 个新术语也都停留在 candidate,虽然没有污染正文,但Metatlin/Metatrin等专名在人工确认和别名归并前不会自动统一。因此,目前的准确定位是“带人工校对的内部 Beta”。

6.6 前后端都在运行,为什么页面还是空白或一直“正在读取”

录制投稿视频前,我在远程服务器上启动了 FastAPI 和 Vite。两个终端都没报错,浏览器标签页也显示着 Babel Studio,正文区域却始终一片空白。试过localhost、服务器局域网地址和 Tailscale 地址,情况都没变。第一反应很容易是 React 挂了,但标题能显示,说明index.html已经到达浏览器。接下来该确认的是前端模块有没有加载,以及浏览器连到的究竟是不是刚启动的服务。

我按下面的顺序排查:

  1. 先看服务是否真的监听端口。我检查了 Vite 和 FastAPI 进程,并在服务器内部请求前端地址、/health/projects、章节、术语和工件接口。API 都能返回数据,生产构建也能通过,问题不在翻译任务或后端存储。
  2. 然后核对浏览器端口。Docker 旧页面占着5173,新启动的 Vite 自动换到5174。我一直访问5173,看到的其实是旧容器。服务器的 HTTP 代理还会让普通curl localhost超时,所以本机探测改用curl --noproxy '*',免得把代理问题错认成服务没启动。
  3. 再检查地址和网络边界。用户电脑里的127.0.0.1指向用户电脑自己;服务器的192.168.*地址只在服务器所在局域网有效。当时 Tailscale 也没有让两端加入同一个网络。这些地址都代替不了 VS Code Remote 的端口隧道,外部转发域名还可能被 Vite 的allowedHosts拒绝。反复换网址没有用。
  4. 最后打开 VS Code 的“端口”面板。5174当时显示为“自动转发”,这条记录却没有把当前浏览器会话稳定接到远程 Vite。我删掉记录,点击“添加端口”,手动输入5174,状态随即变成“用户转发”。从面板点开localhost:5174后,VS Code 通过新隧道在本地浏览器打开页面,React 正常挂载,空白页消失。

页面总算出来了,书架却又一直停在“正在读取”。这次不是 React,也不是 FastAPI:前端客户端把 API 地址写死成了http://localhost:8051。网页虽然运行在远程服务器上,实际打开它的却是本地浏览器,因此这里的localhost指向我的电脑,而不是 DGX Spark。Vite 当时又没有配置/api代理,请求自然到不了服务器里的 FastAPI,界面还会一直等下去。

最后的改法很小。vite.config.ts把同源/api转发到服务器内部的http://127.0.0.1:8051src/api/client.ts.env.example的默认地址都改成/api/v1。这样浏览器只访问当前网页的来源,跨到8051的那一步由远程 Vite 完成,不再让本地浏览器猜“localhost 到底是谁”。我还给 API 请求加了 15 秒超时;后端或代理没启动时,页面会直接报连接超时,不会永远停在“正在读取”。

排查期间,Vite 还因为云端机器的 inotify watcher 达到上限而报过ENOSPC,不过它和空白页是两件事。生产构建正常,说明源码仍能编译。录制环境后来改用无 HMR 的生产构建和 preview,避免 watcher 再来添乱。稳定录制时由5175提供生产页面,同源/api转发到服务器内部的8051,VS Code 只需建立一个明确的用户转发端口。

以后再碰到这种问题,我会先看监听和服务器内直连,再检查 HTML、前端模块与 API,接着核对实际端口、请求地址和代理,最后重建远程端口转发。如果服务器内访问正常、浏览器侧异常,就先查浏览器到远程主机的交付路径,尤其留意浏览器眼里的localhost,别急着改业务代码。

7. 实验结果:翻译、长文本、文化适配与嵌字

7.1 总体结果

Babel Studio 目前已经跑通小说和漫画两条主链路。漫画侧用 46 页 OpenMantra 日漫做了整本验证;小说侧覆盖 TXT、Markdown、DOCX 和 EPUB,作品级术语、翻译、回译审校与质量回流也都进入了实际链路。下面这些结果可以复现:

验证项调整前调整后或当前结果
漫画空白气泡12 个0 个
CJK 排版回归缺少真实空泡样本12 个问题气泡进入回归,相关后端测试 115 项通过
Qwen 并发推理测试 8、16、32 路选择 16 路,聚合吞吐约 235 token/s
众包参考 LoRA相比基础模型低约 27–30pt停止沿低质量目标继续调参,改为先验证教师与数据
distill-10k 8B 学生旧 LoRA 持续负向86 胜、72 负、42 平,净偏好 +7pt
distill-50k 8B 学生10k 版净偏好 +7pt对基础 8B 为 93 胜、68 负、39 平,净偏好 +12.5pt;对 10k 为 75 胜、54 负、71 平
学生模型可部署性8B BF16 与 LoRA 分离合并并量化为 4.68 GiB(5.03 GB)Q4_K_M,冒烟约 41 token/s
Q4_K_M 长文 E2E单句冒烟,缺少流水线证据6 章 407 段全部完成;CJK 残留、上下文标记和已知串段均为 0
人工发布闸门23 个待审段仍显示 completed最终 395 final / 12 reviewing,任务以 warning / 待校对结束

7.2 多个模型的日译中对比

日译中测试包含 31 个真实漫画气泡。下面几组例子来自同一份 OCR 输入。“通用 Qwen 35B”当时还沿用一套不适合日译中的旧 Prompt,所以这组结果只能说明路由需要细分,不能证明通用模型永远更差。

日文原文通用 Qwen 35BQwen3-8B 零样本Sakura-14B 专用档观察
大体なんで使い捨てカメラなんだよ!因为是大体,所以是 disposable camera 啊!大概你是在用一次性相机啊!再说为什么是用抛弃式相机啊!Sakura 正确识别“大体”是转折语气,也没有英文残留
女か?女か?是女生吗?是女人吗?旧通用路由整泡漏译,后两者都可接受
お前もしかして你该不会你该不会是——Sakura 保留漫画对白的悬停语气
マフィア舐めんのも大概にしやがれ别他妈把黑手党当软柿子捏。别太小看黑手党了。通用模型语气更痞,Sakura 更忠实但偏平,需要文化适配按作品分级裁决

逐泡人工判读时,旧通用 Qwen 路线出现 1 处整泡漏译,以及 1 处误解并残留英文;Sakura 没有这两类硬伤。独立 DeepSeek A/B 盲评的方向一致:31 个漫画气泡中,Sakura 16 胜、6 负、9 平,净偏好+32.2pt。样本不大,但足以支持“日译中优先走专用模型”这项路由决定。它还不足以代表所有漫画题材,而且在某些强烈语气下,通用模型的表达反而更生动,风格取舍不能只看总分。

7.3 Dense 蒸馏前后的中译英对比

蒸馏评测使用 200 条固定样本,来自 15 本以整本书为单位、与微调训练集隔离的留出作品。基础模型和学生使用相同 Prompt,关闭 thinking,采用 greedy 解码。A/B 展示位置按固定种子打乱,DeepSeek-chat 只看到中文原文和两份匿名英文译文,再按忠实度与英文自然度判断胜、负或平。这样能控制微调阶段的书籍泄漏和位置偏差,但无法排除基础模型、教师或裁判在预训练阶段见过相关文本。

指标基础 Qwen3-8Bdistill-10kdistill-50k如何解读
对基础模型 A/B86 胜 / 72 负 / 42 平93 胜 / 68 负 / 39 平两个蒸馏版都呈正向偏好,50k 信号更强
净偏好+7.0pt+12.5pt(胜−负)/200,不是“质量提高百分比”
非平局胜率54.4%57.8%只在裁判明确分出胜负的样本中计算
双侧精确符号检验p=0.301p=0.058忽略平局;50k 接近但未达到常用的p<0.05阈值
BLEU16.8117.5817.97参考译文质量有限,只作为方向性辅证
chrF++40.2441.2341.84与盲评方向一致,但差值不大
CJK 泄漏9/2001/2000/200蒸馏配方对未翻译汉字这一硬错误改善明显
空输出0/2000/2000/200三者持平

50k 与 10k 直接 A/B 的结果为 75 胜、54 负、71 平,非平局胜率 58.1%,双侧精确符号检验p=0.078。所以+10.5pt只能描述成扩大数据后出现了进一步改善的信号,尚不能排除抽样波动。不过,50k 在盲评、BLEU、chrF++ 和 CJK 泄漏四项观察上的方向一致,结果也不是靠少数漂亮案例撑起来的。

下面是能直接看到差异的样例:

中文原文基础 Qwen3-8Bdistill-50k 8B 学生(BF16+LoRA)改善点
#<#“混账!#<#“混账!Damn it!不再整句回吐中文,并清理语料伪影
比起只开出过精力药剂的初级宝箱,中级宝箱的效果持久而爽。Compared to the初级 treasure chest... the中级 treasure chest...Compared to the basic treasure chest... the intermediate treasure chest...消除中英文混杂,术语完整翻译
是周美琳接的,语气是裴七七没有听过的温柔,...a gentleness裴 QiQi had never heard before....a gentleness that Pei Qiqi had never heard before.消除汉字泄漏,保留人物拼写

这些样例表明,学生学会了一部分“完整翻译、不要回吐训练伪影”的行为。但它们毕竟是从 200 条结果中挑出的可解释案例,不能代替总体统计。现有证据支持的范围是:这套蒸馏配方在留出的中译英网文样本上减少了硬错误,并得到中等强度的正向偏好信号。新闻、技术文档、日译中和其他文学题材是否也会改善,还没有数据。

部署侧还有一条边界:+12.5pt来自 BF16 基座挂载 LoRA,不是最终的 Q4_K_M 文件。量化版已经完成另一套 407 段长文 E2E,持续生成和工程链路都能稳定运行;可长文输入与 200 条盲评不是同一测试集。在 llama.cpp 上重跑同一批 200 条、并和 BF16 输出逐条配对之前,+12.5pt不能直接算在量化成品头上。

当前我把它定位为“可部署候选”,还不是 35B 教师的等价替代。它可以在资源受限的中译英网文链路中承担批量初译,尤其适合减少汉字漏译这类硬错误。碰到文化词、人物口吻或高价值交付,仍然要由 35B 教师复核并配合人工校对。

7.4 长文本效果与长程一致性的边界

只测两三个字的漫画气泡显然不够,我又加入 75 句公版长文本,来自太宰治《走れメロス》和芥川龙之介《蜘蛛の糸》,每句约 15–40 个日文字符。DeepSeek A/B 中,Sakura 取得 50 胜、18 负、7 平,净胜 Qwen3-8B+42.7pt,比漫画短句组的+32.2pt更强。COMETKiwi 在两组上只给出千分位差异,分不出系统好坏,所以没有拿这个单一自动分数作裁判。

不过,句子长一点仍不等于跨章节一致。当前留出测试覆盖多本书和不同章节,可以看到Pei Qiqi等人物名在分散样本中的拼写比较稳定;生产流水线也已有作品级 SQLite 术语库、命中召回、定译检查和跨章节复用。但我还没有完成一本小说从第一章到最后一章的人工一致率标注,所以这里不给出一个凑出来的百分比。后续会分别统计人物名、称谓和世界观术语的首次出现、跨章复现与冲突次数。

7.5 文化适配:有改善,也有尚未迁移的能力

文化适配不等于“把脏话写得更重”。同一句黑帮威胁,通用 Qwen 的“别他妈把黑手党当软柿子捏”更有街头感,Sakura 的“别太小看黑手党了”更忠实,也更适合低年龄分级。Nemotron 因此只做最小改写,并把理由写进 ledger;改写完成后还会重新检查术语,一旦破坏专名就丢弃结果。

蒸馏实验也暴露了文化知识迁移不足。面对“这个认真的男人竟然还如此旺财”,基础 8B 和 distill-50k 都把“旺财”压成lucky,35B 教师给出的auspicious for wealth更接近“招财旺运”。Dense 学生已经明显减少漏译和汉字泄漏,但处理文化词时仍追不上 MoE 教师。目前文化适配有真实案例和保护机制,还缺一套独立、分级、由人类评分的专项测试集。以后需要分别评估忠实度、目标文化自然度、人物口吻和内容分级,不能全塞进一个语义相似度里。

8. 总结与未来计划

8.1 这次做成了什么

Babel Studio 把确定性程序和生成式模型接在了一起。术语库防止模型随意改名,检测框约束视觉模型的猜测范围,排版器在越界时安全失败,ledger 记录每次决策。敏感内容留在 DGX Spark,公开漫画可以借助 Stepfun;云端服务缺席时,还有本地回退。

开发中最耽误时间的,往往不是出错,而是先入为主地猜错原因。12 个空泡和译文长度无关,LoRA 退化也不是因为训练时间不够。没有气泡预算、事件记录、固定测试集和盲评,我可能还在沿着两个错误方向继续优化。Dense 蒸馏则把强教师的一部分行为压进约 5.03GB 的学生模型。+12.5pt净偏好、自动指标和硬错误统计给出了初步的正向证据,但学生没有学全教师处理文化词的能力,样本规模和单一模型裁判也限制了结论强度。

407 段 E2E 证明量化模型可以长时间稳定运行,也提醒我模型质量和交付安全是两回事。目标文字系统检查、上下文污染恢复、术语状态权限、全书回填和人工发布闸门,让已知错误不再静默进入成品。最终仍有 12 段等待人工校对。系统没有把它们藏进completed,而是如实显示为待审。

8.2 仍然存在的边界

不规则艺术字、跨格 SFX 和严重受损的复杂背景仍要人工处理,多模态复检也代替不了最终校对。书架式作品管理与逐气泡编辑器已经有设计和接口基础,但进入多人生产环境前,还要补上权限控制、版本冲突、批量编辑和人工审核闭环。

评测也有欠账。长程术语一致性和文化适配需要正式标注集,不能只靠短句盲评和个别案例外推。长文 E2E 仍有短句回译阈值误报与实体别名归并问题。蒸馏侧还缺更大规模的人类双盲、多裁判、多随机种子复测,以及 BF16+LoRA 与 Q4_K_M 在同一批样本上的等价性评估。

8.3 下一步

下一步先完成书架前端和逐气泡编辑,把needs_human从一个状态变成可以逐项处理的审核队列。短句将采用长度感知或分类阈值;人物别名、源文错别字和人工确认也要合并到同一实体。漫画视觉回归集会继续扩充,OCR、排版和复检误差分开统计。小说侧则要建立整本、跨章节的术语与人物口吻测试。

蒸馏实验先不急着继续堆数据。Q4_K_M 要在与 BF16 相同的 200 条上重跑,然后扩大样本,引入人工与多个裁判复评。只有确认 50k 的正向信号可以重复,才会继续观察 10 万条的边际收益,并尝试把最难的文化样本单独交给强教师生成。

我不打算把 Babel Studio 包装成“全自动翻译机”。它更像一间本地化工作室:做过什么都有记录,失败时留下证据,拿不准的地方就交给人。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询