跳到主要内容
生长的档案
← 返回期刊架
NO.2026-0042026.09.16UPDATED 2026.09.1728 MIN READ

从 Book Skill 到翻译文库:四天把一个 Agent 技能改造成自己干活的线上书房

技术实战Agent网站建设

功能台里挂着两扇门,其中一扇后面就是这台翻译机。它是这座档案室里第一个「不用人守着也能干活」的项目——上游本来只是一个等人叫唤的技能,四天之后,它变成了一间自己推进的线上书房。

整理时间:2026-09-16 | 更新:2026-09-17 本次更新:D 方案(脚本直连 API)上线——第 4 节的吞吐数字按实测修正,新增第 7 节,复盘由七条扩为十条,末尾「下一步」重写。 开发周期:四天(09-14 → 09-17)| 线上:https://trs.andrew-li.top 上游引擎:deusyu/translate-book(Rainman Translate Book,MIT 许可)| 本项目:Andrew-li777/translate-book 说明:下文所有数字(块数、耗时、内存、成品体积)都来自项目自己的迭代记录与验证结果,非估算。


0. 起点:一个「要人叫才动」的技能

上游项目本质是一个 Agent Skill,不是服务。它解决的是一个很具体的问题:整本书怎么用 LLM 翻完而不崩。

输入(PDF / DOCX / EPUB)
  │
  ▼
Calibre ebook-convert → HTMLZ → HTML → Markdown
  │
  ▼
切块 chunk0001.md, chunk0002.md, …
  │  manifest.json 记录每块哈希
  ▼
并行子代理(默认 8 并发)
  │  每个子代理:读 1 块 → 翻译 → 写 output_chunk*.md
  ▼
校验(manifest 哈希比对,源↔译文 1:1 对应)
  │
  ▼
合并 → Pandoc → HTML(带目录)→ Calibre → DOCX / EPUB / PDF

它做对了三件关键的事:

  1. 一块一个独立子代理、一个全新上下文窗口——避免了「一本书塞进一次会话」必然出现的上下文堆积和输出截断。
  2. manifest 用 SHA-256 记录每块哈希——防止陈旧或损坏的译文被合并进成品。
  3. 断点续译 + 邻块上下文——每块能看到相邻块的只读片段,用于代词和实体消解。

但这三条都属于「引擎素质」。它还有四个缺口,全都指向同一件事——它只在你叫它的时候才动:

缺口 后果
无 Web 界面 每次翻译都要登服务器敲命令
无任务队列 传一本书、等它、再传下一本,无法排队
无增量状态 中断即从头,8 并发跑一半断了全白费
依赖人工触发 想翻 200 页的书就得全程守着

一句话:上游解决了「翻译质量」,没解决「谁来按按钮」。

这四天要做的事,就是给它补上后半句——然后在最后一天,把补上的东西再换掉一次。


1. 架构:不是重写引擎,是给它装一套自动化

第一个决策最重要:不重写引擎,只外包它的调度权。

浏览器 → Cloudflare(HTTPS) → Origin Rule(Hostname→8080) → Caddy(按 Host 分流)
                                                              ├→ :8788  translate-web
                                                              └→ :8787  scan

这样拆成三段,每段的职责边界必须干净:

层 位置 职责 明确不做什么
引擎 book/scripts/(11 个脚本 + .venv) 转换、切块、合并、构建成品 不碰网络、不碰队列、不知道 Web 存在
网站 web/(FastAPI 单页 + systemd) 上传、展示、任务编排、SSE 进度 不做翻译,LLM 工作全部交给外部
驱动 Hermes cron(3 分钟一轮) 只做「翻译 3 块 + 翻译书名」 不做队列扫描、不做合并构建

核心收益:任何一个环节都可以独立替换。Web 挂了翻译照跑;cron 挂了可以手动补跑;引擎升级不动 Web。

其中「网站不做翻译」这一条是反直觉的。最自然的写法是在 FastAPI 里内嵌一个后台翻译任务,但那样会把 LLM 长任务和 Web 请求生命周期绑在一起——重启服务就杀翻译,而这台机器只有 3.8GB 内存,Web 和重型解析抢内存是常态。所以 Web 只是个观察窗口 + 任务编排器,真正的翻译发生在别处。

当时写下「任何一个环节都可以独立替换」时,它只是一句设计信念。第四天它被兑现了一次:驱动层自己也被整个换掉,而 Web 和引擎都没动(见第 7 节)。


2. 移植:先让它在别人的服务器上活下来

上游跑在开发机上,本项目的运行环境是:Debian 12 / root / Python 3.11 / 3.8GB RAM + 2GB swap。移植过程中踩了三个坑,每一个都值得记下来。

坑一:仓库根本下载不下来

GitHub 直连超时,ghproxy 镜像也超时。这不是代码问题,是中国网络环境下单点镜像的必然结果。

解法:写一个多镜像脚本,按 github.com → ghproxy → ghfast.top 顺序依次尝试,任一成功即返回。最终 ghfast.top 拉下 11.8MB。

教训:别把「下载」当成命令,把它当成一个需要重试策略的步骤。

坑二:root 身份下 PDF 导出崩溃

merge_and_build.py 生成 HTML / DOCX / EPUB 全部正常,只有 PDF 失败。根因是 Calibre 的 ebook-convert 底层用 Qt WebEngine,而 Qt WebEngine 又基于 Chromium——以 root 身份运行会触发 Chromium 沙箱崩溃。

解法:在 calibre_html_publish.py 顶部加一行,把它做成永久修复而不是外部环境变量:

import os
os.environ.setdefault("QTWEBENGINE_DISABLE_SANDBOX", "1")

写在代码里而不是写在启动脚本里,是因为「任何方式运行都不用再记得加环境变量」。把坑焊死在代码里,而不是记在文档里。

坑三:并发从 8 降到 3

上游默认 8 并发子代理。这台机器上:每个子代理 = 一个独立的 agent 运行时进程,而 delegation.max_concurrent_children 本身就硬限制为 3。

进一步实测:内存安全线约 3.05GB,已见过 2.96GB 峰值。6 并发必 OOM。

所以 3 并发不是保守选择,而是同时踩在「配置硬上限」和「内存安全上限」上的唯一可行值。

移植结束时的验证:standard-alice.epub → 37 块;合并产出 HTML / DOCX(9.9MB) / EPUB(10MB) / PDF(12.5MB) 全部成功;真译一块 43 秒、17k tokens 输入、质量优秀。


3. 最难的一段:3 分钟窗口

把引擎跑通只是第一天的事。真正的难题出现在让它自动跑起来的时候:

⚠️ 核心约束:Hermes cron 单次会话有 3 分钟硬中断。扣掉启动、加载 skill、队列开销,每轮有效翻译时间只有约 150 秒。

而实测出现过单块翻译最坏 268 秒——比整个窗口还长。直接把翻译丢给 cron,等于每轮都在赌。

解法不是「让翻译更快」,而是按「谁受时间限制」重新分工:

工作类型 谁做 为什么
队列扫描 / pick / 记录 / 进度 / merge 请求 consumer.py(脚本,毫秒级) 纯机械操作,不受窗口影响
翻译 chunk + 翻译书名 cron agent(delegate_task 3 块并行) 必须用 LLM,且是唯一被窗口限制的部分
合并构建(分钟级) Web 后台线程(60 秒 watcher) 太慢,放 cron 里必被掐断

这是整个项目最重要的一条设计原则:不要把「慢的构建步骤」放进有时限的调度器里。

断点续译:靠幂等,不靠记忆

分工解决了「谁做」,但没解决「被掐断了怎么办」。答案是让每一步都幂等,而且只认一个事实来源:

  • 一个 chunk 的 output_chunk{i}.md 文件存在 = 这块已翻译。 这是唯一事实来源,run_state.json 只记录、不决策。
  • consumer.py pick 时如果发现 output 已存在就自动补记录(record_only)——即使上一轮在 3 分钟边界被打断,下一轮也只会「补登记」,绝不重译。
  • merge 前检查 run_state 是否全部 done;术语表变化时只精确重置受影响的块,不动已译部分。

这样就出现了一个很好的性质:最坏情况不是「白干一轮」,而是「这一轮只完成了两块」。268 秒那块在窗口内没写完,下一轮它已经落盘,直接跳过。

顺手修掉的一个死循环

pick 一开始有个隐蔽 bug:output 文件已存在(比如上一轮中断前刚好写完),但 run_state 还没来得及记录 → 下一轮 pick 仍然认为它「未译」→ 无限重译同一块。

根因是把两套状态当成了两套真相。 修法就是上面的 record_only:以文件为准,状态只是它的影子。

这一节绕来绕去,都在和同一个对手周旋:3 分钟。而它最终不是被优化掉的,是被整个绕开的——见第 7 节。


4. 规模化验证:200 块,无人值守跑完全书

机制对不对,得用真实的书来验。选了一本真实技术书——Bioinformatics Data Skills(Vince Buffalo,200 页级 PDF)。

上传 PDF → convert → 200 个 chunk
  → cron 每 5 分钟 × 3 块自动翻译
  → 无人值守 5.5 小时
  → 200 / 200 全部译完
  → 自动合并 → 5 格式成品

成品体积:PDF 10.1MB / DOCX 7.0MB / EPUB 5.8MB / HTML 1.28MB / Markdown 1.13MB。抽查第 9 章(Range 数据类型)的译文质量不错,代码块和图片引用完整保留。

一个 0 字节空块差点让整书失败

200 块全部译完,任务状态却卡在 failed——卡在 merge。

根因很朴素:chunk0200 是 convert 从 PDF 末尾空白页生成的 0 字节合法空块,子代理的译文自然也是空的;而 merge 的校验逻辑把「空输出」一律当成「这块没翻译」,于是拒绝合并。

⚠️ 教训:空 chunk 是合法产物,不是失败。 校验逻辑必须区分两种空——「源本来就空」和「源非空但输出为空」。后者才是事故,前者是 PDF 的正常结构。

修法是给 manifest.py 和 merge_and_build.py 打 source_empty 补丁,容忍源为空的块。补丁后重跑 merge,退出码 0,状态修正为 done。

整本书、200 块、5.5 小时的工作量,卡在最后一块的 0 字节上。 这类问题的特征很清楚:它不在主流程里,它在主流程的边界条件里。

提速:5 分钟 → 3 分钟,以及一个反直觉的结果

5.5 小时还是太长。瓶颈不在模型也不在磁盘,而在调度间隔:cron 间隔必须 ≥ 窗口时长(否则两轮会重叠,子代理并发翻倍直接 OOM),所以 5 分钟是安全但浪费的选择。

把 cron 间隔从 5 分钟压到 3 分钟——刚好等于窗口,不重叠:

配置 理论吞吐 200 块
5min × 3 块 36 块/h 5.5h(实测)
3min × 3 块 60 块/h 7h45m(实测,仅 26 块/h)

结果和算出来的相反。 理论吞吐从 36 涨到 60 块/h(1.67 倍),而 200 块的实测从 5.5 小时变成 7 小时 45 分——更慢了。

教训:「把参数算对」和「让系统跑快」是两件事。 至于为什么反而更慢,文档只给了数字、没给根因,这里就不替它下结论了。

还有一个更值得注意的事实:这个更慢的数字,当时并没有被发现。它是第四天为了给新方案建基线才被测准的——下一节就讲这件事。


5. 三个让「自动化」变成「产品」的小闭环

引擎能无人值守跑完一本书之后,剩下的三处设计决定了它是一台机器还是一个能用的产品。

术语表:改一个词,全书重译

专有名词是机器翻译最容易翻车的地方。所以每本书有独立术语表,而保存动作本身就是一次全链路触发:

PUT /api/books/{name}/glossary
  → 内容哈希变化
  → 算出 affected_chunks
  → 已完成书重置为 ready
  → 轮询引擎下一轮自动接手重译

实测有效:给《爱丽丝》注入术语后,重译块里出现了「爱丽丝」「白兔先生」——术语表真实影响翻译,不是摆设。

服务端校验也不客气:缺 target 字段或 alias == source 直接 400;gender 等必填项由后端补默认值。把校验做在写入端,比做在读取端便宜。

SSE:秒级进度,但保留轮询兜底

进度一开始是 15 秒轮询,体验很钝。换成 SSE 之后:

  • GET /api/jobs/{id}/stream,每 2 秒读一次 progress.json,有变化才推
  • 约 16 秒一次心跳(: ping)防中间层断连
  • 终态推送 done 后主动关闭
  • X-Accel-Buffering: no 防止反向代理缓冲住事件流

但轮询没有删掉,保留为兜底。实测 SSE 断线时 15 秒轮询能自动恢复,两套机制不冲突。同理,上传成功后立刻建立 SSE,done 事件刷新书库——实时是体验,兜底是可靠性,两者不该二选一。

顺带一提:这套 SSE 只读 progress.json,所以后来换掉翻译引擎时,它一行都没改。接口选对了,替换就是免费的。

访客模式:把「一刀切」换成「双模式」

最初整站是 Caddy 层的 basic auth,意味着任何人打开都是 401——包括你自己在手机上随手看看。

后来的两个提交把它改成应用层双模式:

身份 判定 权限
游客 无 Authorization 头 只读白名单:书库列表、详情、章节对照、全文搜索、封面、静态资源
管理员 Basic 凭据 bcrypt 校验通过 全功能:上传、下载、术语表、删除、回收站

游客规则的实现细节值得一提——它不是黑名单,是白名单:

  • 文件端点按扩展名放行(.md .txt .csv 与图片、.html),内部 .json/.yml 一律不给
  • /api/jobs/(任务详情、SSE)和 /api/trash 严格拒绝
  • /download/ 对游客一律拒绝

而且游客点击下载/上传/删除时弹登录框,而不是裸 403——前端直接拦住,别让人看到权限报错才明白自己没登录。凭据比对用常量时间比较(hmac.compare_digest)防时序攻击,另加按前缀独立计数的限流。

一句话:权限设计的重心不在「能不能看到」,而在「越界时给出什么反应」。


6. 网络与运维这一关

两次 521,两个不同的原因

trs.andrew-li.top 上线后公网 HTTPS 一直 521(源站不可达),而 scan 正常。同一个 Caddy、同一台机器,两次原因完全不同:

  1. 第一次:Cloudflare 猜不出源站端口,默认回源 443/80,而服务器上唯一监听的是 Caddy 的 8080 → 521。
  2. 第二次:配置 Origin Rule 时,匹配字段误用了 「URI 完整」——而 URI 匹配的是 URL 路径(/),永远不可能匹配到域名 → 规则形同不存在,仍然 521。

⚠️ 关键:Origin Rule 的匹配字段必须选 Hostname(Host 头),端口重写固定到 8080,Host 头保持原样,让 Caddy 按域名分流。

这两次踩坑的价值在于:第一次是知识盲区,第二次是「以为改对了」。错误信息一模一样,根因毫无关系。

服务自愈

translate-web.service 用 systemd 管理:Restart=on-failure + 开机自启 + 崩溃自愈。重启网关这类操作要走延迟定时器(systemd-run --user),因为直接 systemctl restart 会把自己的会话一起杀掉。


7. 第四天:把调度器整个拆掉

前三天做的所有事,都建立在同一个前提上:翻译必须发生在 cron 的 3 分钟窗口里。第四天,这个前提被推翻了。

先测准基线,才知道要绕开什么

准备新方案时,项目做了一件很值钱的事:把原方案的实测吞吐测准了。结果是 26 块/h——而不是之前按参数推导出来的 60 块/h。

方案 配置 吞吐 200 块
cron(原现状) 3min × 3 块 26 块/h 实测 7h45m 实测
每轮 6 块 5min × 6 块 72 块/h 理论 ❌ 不可行:并发上限 3,6 个子代理必 OOM
脚本直连 systemd 守护,3 并发 ~110 块/h 实测 ~2h(据实测外推)

理论 60、实测 26——差了 2.3 倍。差距不在模型,在调度器自己:每轮 cron 都要冷启动一次 agent 会话、加载 skill,再等子代理起来。这些开销不在参数表里。

教训:参数推导只能给出上限,实测才给出答案。 而讽刺的是,真正把这个数字测准的动机,不是为了知道现状有多慢,而是为了给下一个方案建基线——基线不测,你就不知道该绕开什么。

实现:一个守护进程,替换执行器

translate_direct.py 由 translate-direct.service 常驻,整体是「复用队列、只换执行器」:

主循环(每 10 秒轮询一遍队列):
  ① consumer.pick()             → 取本批 3 块(原队列逻辑原样复用)
  ② ThreadPool(3) 并发直调 API   → 写 output_chunk{i}.md
  ③ fix_images()                → 补回缺失的图片引用
  ④ consumer.finish()           → 记录 + 进度
  ⑤ 全书完成 → request_merge()   → 交 Web watcher 构建

关键参数都写死在脚本顶部、不散落:BATCH=3、单请求 TIMEOUT=180s、RETRIES=3、指数退避 15 秒、轮询间隔 10 秒。API 通道是 https://developer.amd.com.cn/radeon/api/v1/chat/completions,模型 DeepSeek-V4-Flash,key 从环境变量读,不硬编码。

队列、状态、进度、watcher 全部原样复用——所以换成它之后,Web 上的 SSE 进度无缝可见,前端一行代码没改。第 1 节那句「任何一个环节都可以独立替换」,到这里才真正兑现。

顺带一个跨期闭环:这条直连通道,正是本刊 第 002 期 里介绍的 AMD 开发者平台免费 API。那篇文章的结论是「平台入口开得好就直连」——这一次,被直连的不再是一个客户端工具,而是整条流水线本身。

A/B 测试意外测出了一个吞吐杀手

新方案最大的风险是质量一致性,所以原计划是做 10 块 A/B 对比(旧译文 vs 新译文)。结果这个测试暴露了一件完全没预料到的事:

reasoning_effort 单块耗时 结果
none 47–65s ✅ 快且稳
minimal 180s ❌ 超时
medium 141–144s ⚠️ 慢——白烧 1536 个 reasoning token
xhigh >180s ❌ 超时

一个 3KB 的小 chunk,medium 要花 141–144 秒,none 只要 47–65 秒,而质量等同(文档原话:章节标题甚至比原来翻得更准)。

教训:翻译是直译任务,不需要推理。 thinking effort 对翻译是纯负收益——默认改成 none,单这一项就是 2.7 倍提速。这个参数平时没人会盯,是 A/B 测试顺手照出来的。

结果

指标 cron 脚本直连
吞吐 26 块/h 实测 ~110 块/h 实测
单块耗时 — 47–65s
常驻内存 子代理峰值 ~1GB 10.8M(systemd MemoryMax=1G)
时间窗口 3 分钟硬中断 无
译文质量 基线 A/B 相当
成品 — 5 格式全生成

实测样本是一本 37 块规模的测试书:全书 22 分钟。速度约 4–6 倍、内存省约 800MB,而且不再有任何时间窗口。

两个只有直连才会踩的坑

坑一:合并永远不触发。 37 块全译完,任务停在 merging,成品却一直不生成。

根因:consumer.finish() 在「全部译完」时只把状态置为 merging,不写 merge_request.json;而 Web 的 merge watcher 要求 status == merging 且 merge_request.json 存在 两个条件同时成立。缺后者 → 永不触发。

修法:全部译完之后显式再调一次 request_merge();已卡住的任务手动补一个文件即可恢复。

教训:两个组件各自都「做对了一半」,合起来就是死锁。 状态机和触发条件是两份契约,得放在一起审。

坑二:直连会丢图片。 merge 报错——output_chunk0003.md 的图片引用与源不一致,少了 images/000002.png、images/000036.png。

根因:插图密集的长 chunk,模型会把整块 ![](images/xxx) 引用全部丢弃。而 merge 有图片校验,缺图即拒绝合并。

解法是新增 fix_images.py 做确定性后处理:逐行比对源 chunk 与 output 的图片引用,缺失的按源原样补回。

⚠️ 最值得记的一点:prompt 约束不是保证。 skill 蓝图里明明写着「必须原样保留图片引用」,直连时模型照样丢。而且这个坑只有直连才会踩——走 delegate_task 时子代理手里有 read_file 工具,会自己回读源文件核对,所以从不丢图。

同一份 prompt,换个执行路径就失效了。 这就是那条更普遍的原则:凡是「模型应该做对」的事,都要有确定性脚本兜底。

双引擎互斥

新引擎上线后,cron 没有删掉,而是降级为兜底:cron 的 prompt 里加了守卫——主引擎活着时 cron 只待命;主引擎挂了,cron 自动接管翻译。

一个能自动跑完长任务的系统,最后该保留的不是速度,是「主路径死了还有一条路」。


8. 复盘:十条被验证的原则

四天里所有的关键决策,收敛成十条:

1. 「引擎 + 界面 + 调度」三段式是这个场景的最优解。 上游引擎一行没改照样用,Web 只做编排,调度层只做最小的 LLM 工作——最后连调度层都能整个换掉而不牵动其他两层。

2. 机械操作和 LLM 工作必须彻底分离。 这是 3 分钟窗口下唯一站得住的分工。脚本毫秒级、不受窗口影响;LLM 工作才是有时限的那部分。

3. 慢的构建步骤不能放进有时限的调度器。 merge 分钟级 → 交给 Web 后台线程。到最后这一步做得更彻底:连调度器本身都绕开了。

4. 文件系统即数据库。 任务队列、进度、术语表、翻译状态全是 JSON 文件,不用 SQL/Redis。零依赖、崩溃可读、任何脚本都能直接读写——在 3.8GB 的内存上,没有多余服务可以跑。代价是并发写要用原子写(写临时文件 + rename)。

5. 幂等是断点续译的前提。 所有步骤可重入,且「一个 output 文件 = 唯一的已翻译事实」。状态记录只用来加速,不用来决策。

6. 空 chunk 是合法产物。 校验必须区分「源空」与「源非空但输出空」。边界条件不是主流程的边角料,它就是失败发生的地方。

7. 骨架和 JS 必须同步交付——最大的一次前端事故。 全选、删除所选、上传按钮、任务折叠、回收站全都无反应。根因不是逻辑写错,而是 index.html 有完整的 UI 骨架,app.js 根本没有对应的函数——功能从上线那一刻起就是死的。

第 7 条最值得记:它不报错、不崩溃、没有任何日志,只是静静地什么都不做。 加 HTML 骨架时必须同步加 JS,并且双向 grep 核对函数名——这是唯一能拦住它的办法。

8. 参数推导不等于实测吞吐。 60 块/h 是算出来的,26 块/h 是跑出来的。调度器的冷启动开销不写在任何参数表里——理论值和实测值差 2.3 倍,而且这个差距在换掉调度器之前一直被当成 60。

9. 让直译任务做推理是纯浪费。 同一个模型,reasoning_effort 从 medium 改成 none:2.7 倍提速、质量不变、超时消失。不是所有 LLM 调用都需要「想」,翻译就不需要。

10. prompt 约束不是保证,确定性后处理才是。 同一份「必须保留图片引用」的 prompt,一条执行路径从不丢图、另一条全丢——差别只在于前者有工具兜底。凡是「模型应该做对」的事,都要有脚本接住。


9. 现状与下一步

今天的样子(四天后的稳定态):

  • 上传 PDF / DOCX / EPUB(≤100MB)→ 后台转换 → 守护进程持续直连翻译 → 自动合并 → 5 格式成品一键下载
  • 双引擎:脚本直连为主引擎,cron 降级为自动接管的兜底
  • 藏书网格、任务队列(SSE 秒级进度)、章节对照阅读(左右同步滚动)、全文搜索(译文 / 原文 / 全部)、回收站、可收起侧栏
  • 游客只读参观 + 管理员全功能
  • 视觉上沿用功能台的同一套设计令牌(--paper / --ink / --accent / --line),所以它嵌进博客的功能台时不像外来物

下一步,按文档里的优先级:

  1. 跑一本真实长书,验长期稳定性——新引擎目前只在 37 块规模上验过,200 块级别还是外推。这是唯一还没被证明的一环。
  2. 图片修复从「追加到末尾」改为「按源行号插回原位」——当前实现为了稳健先把引用补到文末,位置准确率还有余量。
  3. 对照阅读细化(锚点跳转、字数 / 进度统计)
  4. 上传文件名清洗(超长与特殊字符,目前靠文件系统上限兜底)

更远的方向:翻译记忆(已译句子缓存,长系列书提速)、术语表批量导入导出、多用户与各自书库、浏览器内 EPUB 阅读器、翻译风格预设、双语对照导出、CI 回归、整栈 Docker 化、搜索换 SQLite FTS5、任务失败与磁盘水位告警。

四天里最大的收获其实不是那 4–6 倍。是发现「算出来的数字」和「跑出来的数字」之间隔着一整个调度器——而只有先把基线诚实地测出来,才看得见那个该被拆掉的东西。


参考链接


本文记录 translate-book 从 Agent Skill 到线上翻译文库的移植与自动化过程,2026-09-17 补充「脚本直连 API」引擎上线后的实测数据;所有性能数字与成品体积取自项目验证记录,200 块规模下的新引擎耗时为据实测外推而非实测。线上服务的功能与权限以实际部署为准。

COMMENTS / 评论

评论系统尚未开放。你可以通过 来访登记 直接与我联系。