把文字或图片变成一个可以旋转的生物 3D 模型,演示时很容易让人先看到“生成”两个字。真正让系统能交付的,却是生成失败以后怎么办、模型能不能再次打开、下一次演示是否还要重新付费。
不从零训练模型
这个项目的起点很现实:前端已有 LearningCell 的中文生物模型展示,3DCellForge 里也有图片转模型、缓存和本地导入的思路。与其从零做一个生成模型,不如先把展示系统、生成服务和模型管理接在一起,做出一条能被重复走完的链路。
第一阶段只保留三类输入:官方模型、本地 GLB/自包含 GLTF,以及经过 provider 生成的模型。这样即使没有第三方服务的额度,演示仍然可以用本地文件走完“导入—列表—旋转—刷新后再打开”的流程。没有这条兜底链路,现场任何一个网络波动都可能让系统看起来像没做完。
先把任务当成任务
生成接口通常要经过提交、排队、生成、完成或失败几个阶段,文件不会在一次请求里立刻出现。前端只显示一个转圈图标,会把这些状态全部藏起来;后端至少要保存任务 ID、输入摘要、provider、开始时间、结束时间和失败原因。
重复点击也需要处理。每次提交都带幂等键,同一输入在短时间内只创建一个任务;下载完成后用文件哈希命名,避免同一个模型被缓存成几份。第三方返回的临时 URL 不能直接当永久地址,任务完成后立即下载到自己的存储,之后页面只读本地缓存。
Provider 也不要直接散落在页面按钮里。可以让每个 provider 实现同一组最小动作:提交任务、查询状态、下载结果和解释错误。前端只认识排队、生成中、完成、失败四种状态,服务端再把不同厂商的状态码翻译进去。以后更换服务时,变化集中在适配层,不会把业务页面改成一张厂商文档的拼贴。
缓存不是优化,是演示条件
生成结果可复用,成本才可控。缓存目录应该和任务记录分开:文件保存模型,数据库记录它来自哪个任务、使用了什么输入和版本。删除历史记录时要明确是否同时删除文件,不能让页面显示一串已经不存在的模型。
缓存还要有生命周期。临时失败文件、过期下载地址和用户主动删除的模型不能无限积在磁盘里;正式模型则要保留校验值和生成版本,方便发现文件损坏。演示环境可以设置一个清理命令,先列出将删除的对象,再由人确认,而不是在定时任务里静默清空目录。
模型展示也要允许失败。GLB 解析失败、文件太大、纹理缺失、模型不适合移动端,都应该在列表里留下可读的原因,而不是让 viewer 直接空白。教学场景还要标注“AI 生成示意模型”,不能把生成结果写成教材级的科学结论。
成本和范围要写在第一版
第一版暂时不做复杂账号、商业化计费、大规模并发和自研模型。生成前可以显示大致消耗,设置每日次数上限,失败不无限重试,演示优先从缓存中读取。范围写得窄一点,反而能让验收标准变得清楚:输入一次,看到任务状态;完成后进入列表;刷新页面,模型还在。
我后来越来越相信,项目计划里最重要的部分,是把本期不做的事情列出来。至于以后能接多少 provider,可以等第一条链路稳定后再决定。第三方 API 会变,生成质量会波动,只有输入、任务状态、缓存和失败路径是我们可以控制的部分。
计划中的每个阶段都应该有一条能独立验收的路径:第一阶段用本地 GLB,第二阶段把模型接进列表,第三阶段才接真实 provider。这样即使后面的服务尚未开通,前面的结果也能作为可运行的交付物,而不是一串等待接口额度的任务清单。
科学性不能交给模型保证
生物模型用于科普展示时,形状漂亮并不代表结构准确。正式教学内容仍需要人工审核,生成模型只能当作示意素材。把这个限制写进产品提示和项目文档,不会削弱演示,反而能让观众知道系统的边界在哪里。
最后验收时,我会按一条完整链路走:打开官方模型,输入描述或导入图片,提交任务,查看进度,打开生成结果,刷新页面再打开一次。每一步都能被观察、失败也能被解释,这才是一个生成式项目从 Demo 变成系统的起点。