Dayward AI
Week 1 · D3About 5 hours

Character Consistency: Character Sheets, Reference Images, and Style Locking — Keeping the Same Person the Same Person in Every Shot

Wire up an image generation API, batch-produce character sheets and prop/scene assets from the shot data, lock down a look with reference images and fixed templates, and store the assets in a reusable library.

Today's goals 0/3

Sign in to tick these off and save your progress.

今日目标

  1. 能调通图像生成接口,按分镜数据批量产出角色定妆图与场景图
  2. 能说清角色一致性在接口层面靠什么实现,并用参考图把同一个角色固定下来
  3. 能把生成好的资产建成可检索的资产库,让后面的镜头直接复用而不是重新生成

昨天你已经拿到一份结构化的分镜数据:谁在哪一镜、说什么、画面是什么。今天要把这些字段变成真正能看的东西——图。读完回到页面顶部把三条目标勾掉。

小白版讲解

第二张图里的主角换了张脸

先说一个所有人第一次做 AI 短剧都会撞上的场面。

你写好提示词:二十五岁男性,短寸黑发,浓眉,蓝色外卖工服。生成第一张,很满意。接着生成第二张,同一段描述只把动作改成「站在便利店门口」——出来的人换了个下巴、眼距变宽、工服的蓝也不是同一个蓝。你把描述改得更细,加上「左眉尾一道浅疤」,第三张脸又变了,疤还跑到了右边。

这不是接口坏了,也不是你提示词写得不够好。原因很朴素:图像生成模型没有记忆。 它不知道「上一张」这件事的存在,每一次请求对它都是全新的、互不相关的一次采样。

拿剧组的活儿类比就很清楚。你请了一位速度极快的画师,一分钟画一张定妆稿,但他有个毛病:每画完一张就把上一张忘干净。 你说「跟刚才那张一样,换个角度」,他会问「刚才哪张」。他手上唯一能依据的东西,就是你此刻递给他的那张纸——纸上写什么他画什么,纸上没写的部分他就自己编。

「他自己编的部分」正是不一致的来源。你的描述里写了发型和工服,没写鼻梁高度、脸型宽窄、眼皮单双、工服的具体色号——这些没被约束的自由度,每次采样都会重新掷一遍。而人脸的辨识度恰恰集中在这些细节上:观众记不住「蓝色工服」,但两秒钟就能认出「这不是刚才那个人」。

工程上的代价比想象中大得多。一集竖屏短剧四十个分镜,主角出现在其中三十镜。如果靠反复重抽来碰一张脸对得上的图,按图像 ¥0.025 一张算,每镜抽十次也才 ¥7.5——钱不是问题,问题是人:你得盯着屏幕一张张比对、一张张重抽,三十镜就是一下午。这条流水线的目标是无人值守跑完一集,而「靠人肉挑图」是它最大的敌人。更糟的是这个成本随集数线性增长:五集就是五个下午,你根本没法做第二季。

所以角色一致性不是审美问题,是这条生产线能不能自动化的前提。那接口层面到底靠什么把同一个人固定下来?

三种锁人手段,各自锁得住什么

工程上能用的手段就三种,价格和效果差得很远。先把结论摆出来,再逐个解释。

手段锁住的是锁不住的是代价
提示词模板风格、光线、构图、画幅五官细节、脸型几乎为零,只是多拼一段字符串
随机种子同一提示词的可复现性换了提示词就全部失效为零,但适用面很窄
参考图人脸与形象服装道具的细节、极端角度每次请求多传一张图,还得先有那张图

提示词模板是最便宜的一种,本质是把「每张图都必须一样的那部分」抽成常量。风格、布光、景深、竖屏构图、无水印,这些描述在全课每一张图里都逐字相同。它锁得住的是画面的整体气质——不做这一步,你会得到一集里一半写实一半动漫的诡异成片。但它锁不住脸,因为脸的细节没法用一百个字穷尽。

随机种子(seed)最容易被误解。很多人以为固定 seed 就能锁住角色,实际上它锁住的只是可复现性:同一个模型、同一段提示词、同一个 seed,再跑一次能拿到同一张图。这在调试时非常有用——你换一个词看看画面怎么变,其他变量都不动。但短剧的每一镜提示词天然不同(动作不同、场景不同),提示词一变,同一个 seed 采样出来的就是完全不同的人。seed 是复现开关,不是一致性开关。 这条几乎每次面试都会被追问。

参考图才是真正解决人脸的手段。MiniMax 图像接口的字段是 subject_reference,请求体里长这样:一个数组,每个元素带 typeimage_filetype 目前只支持 characterimage_file 收公网 URL 或 Base64 Data URL,图片是 JPG 或 PNG 且小于 10MB。有两个限制必须记住:type 只有角色这一种,你没法用它锁一件道具;每次请求只能带一张参考图。注意这是图像接口的限制,不是所有接口都这样——视频接口那边就不同,下面单说。

下面是把三种手段叠在一起的写法:模板是常量,seed 固定,参考图从人物卡里取。

generate.js
// 全课共用的风格模板:每一张图都逐字拼上它,这是最便宜的一致性手段
const STYLE = '国产都市短剧质感,柔和影棚布光,浅景深,写实人像,竖屏构图,无文字水印'
 
async function generate({ prompt, referenceImage, seed }) {
  const res = await fetch(`${process.env.MINIMAX_BASE_URL}/v1/image_generation`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${process.env.MINIMAX_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'image-01',
      prompt: `${prompt}。${STYLE}`,
      aspect_ratio: '9:16',
      n: 1,
      seed,
      prompt_optimizer: false, // 默认就是 false;开了它会改写你的提示词,可复现性直接没了
      response_format: 'url',
      // type 只支持 character,且每次请求只能带一张参考图
      ...(referenceImage ? { subject_reference: [{ type: 'character', image_file: referenceImage }] } : {}),
    }),
  })
  const json = await res.json()
  // HTTP 200 不代表成功,业务错误码在 base_resp.status_code 里
  if (json.base_resp?.status_code) throw new Error(`图像接口失败 ${json.base_resp.status_code}`)
  return json.data.image_urls[0]
}

定妆流程:先定一张主视图,再由它派生

有了参考图这个工具,流程就顺理成章:先花力气抽一张最满意的基准图,再让后面所有图都参考它。

这正是剧组定妆的做法。美术组不会在开拍那天现场决定主角长什么样,而是提前拍一组定妆照,贴在墙上,全组以它为准。基准图就是那张贴墙上的照片。

具体分三步:

第一步,为每个角色生成基准图。这一步不带参考图(此时还没有),但要带固定 seed,并且值得多抽几张让人挑一次。这是整条流水线里唯一推荐人工介入的地方——一张图的挑选决定后面几十镜的形象,这笔时间花得值。挑完把路径写回人物卡的 referenceImage 字段。

第二步,以基准图为参考,派生出这个角色的多角度、多表情、多服装。正面、侧四分之三、愤怒、微笑,每张的提示词只改变体描述那一段,参考图始终是基准图。注意是「都参考基准图」,不是「参考上一张」——后者会让偏差逐张累积,第五张已经不是同一个人了,这个现象叫漂移。

第三步,把派生结果一并入库,后面每一镜要首帧时直接取,不再重新生成。

一个容易被忽略的细节:派生图之间也要固定同一个 seed。 参考图管脸,seed 管其余自由度的采样起点,两者叠加才让整组图看起来像同一天在同一个棚里拍的。

场景和道具同样会串戏

角色锁住之后,第二个翻车点是场景。

同一个「雨夜居民楼下」,第八镜的楼是六层的、第十二镜变成十二层,路灯从暖黄变成冷白——观众不会说「场景不一致」,他们会觉得这剧莫名其妙。道具更明显:那部推动全剧情节的手机,第三镜是黑色直板,第七镜变成折叠屏,剧情当场崩塌。

处理办法和角色是同一套思路,但顺序反过来:场景和道具不需要每镜生成,它们应该在开拍前一次性做好,然后被引用。

因为场景的复用率极高。一集四十镜通常只发生在三到五个场景里,也就是说三十多镜共享同一批底图。把这些底图提前生成、登记入库,一集就从「四十次场景生成」降到「五次」——这是这条流水线上最容易拿到的一次性省钱。

登记时要记一件容易漏的事:这张图是给哪一镜用的、当时的提示词是什么。 出问题时你要能回答「第十二镜那张楼是怎么生成出来的」,答不上来就只能重抽。

资产库的最小设计

现在可以给这些图一个正式的家了。它不需要数据库,四件东西就够:一个标识、一份元数据、一个文件、一次去重。

标识就是去重键,它决定了「什么算同一件资产」。关键判断是:键要由会改变画面的内容算出来,而不是由文件名或路径算出来。 用路径当键有两个反向的坏处:改一次目录结构,缓存全部失效,白花一遍钱;同一个路径下换了提示词,缓存又会错误命中,读者会看到「明明改了描述,图还是老的」——这就叫串戏。

所以参与哈希的应该是这几项:资产类别、归属对象、变体名、完整提示词、参考图路径、seed。任何一项变了都得重新生成;反过来六项都没变,就一定能安全复用。

assets.js
import { createHash } from 'node:crypto'
 
// 去重键 = 内容标识。六项里任何一项会改变画面,就必须参与哈希
export function assetKey({ kind, ownerId, variant, prompt, referenceImage, seed }) {
  const material = [kind, ownerId, variant, prompt, referenceImage ?? '', seed ?? ''].join(' ')
  return `${kind}-${createHash('sha1').update(material).digest('hex').slice(0, 12)}`
}
 
// 整个流水线里只有这一个地方会调图像接口,去重也只在这一个地方发生
export async function ensureAsset(lib, input) {
  const id = assetKey(input)
  const cached = lib.find(id)
  if (cached) {
    console.log(`复用 ${id}`)
    return cached // 一次都不调接口,也就一分钱都不花
  }
  const url = await generate(input)
  const record = { id, ...input, path: await download(url, input.outPath), at: new Date().toISOString() }
  lib.register(record)
  return record
}

元数据除了这六项,还要记文件路径、这次花了多少钱、生成时间。文件就落在 assets/ 目录下按类别分层,索引写成一个 assets/index.json,进程重启后照样认得。

这个设计刻意保持简陋,因为它只解决「同一次运行里不重复生成」这一件事。真正完整的缓存键设计要处理更多问题:模型换了版本算不算同一件资产、提示词模板改了要不要全部失效、缓存该不该有过期时间。这些在 D8 的工作流引擎里统一解决,今天先把最直接的那笔钱省下来。

生成失败与审核不通过

最后一节讲失败,因为批量生成一定会遇到失败,而处置方式错了会很贵。

图像接口的错误从 base_resp.status_code 读,先记住第一条:HTTP 200 不代表成功。 只判 HTTP 状态码,你会把一个业务错误当成正常响应,然后在解析 data.image_urls 时收到一个看不懂的空值报错,排查方向完全跑偏。

拿到状态码之后按「换个做法会不会好」分成三类:

  • 等一等会好1002 限流,以及各类服务端错误。退避之后重试通常能成,这一类可以由程序自己扛。
  • 改输入才会好2013 参数无效(多半是参考图地址不合法或提示词超了 1500 字符上限),10261027 命中内容安全审核。这两类重试一万次都是同一个错,白花钱还把限流额度耗光。
  • 必须叫人来1004 鉴权失败、1008 余额不足。程序解决不了,重试只会让告警延迟。
classify.js
// 判据不是状态码首位数字,是「换个做法会不会好」
const RULES = {
  1002: { kind: 'rate-limited', action: 'retry' }, // 等一等会好,程序自己扛
  2013: { kind: 'bad-request', action: 'fix-input' }, // 参考图地址不合法、提示词超长
  1026: { kind: 'content-blocked', action: 'fix-input' },
  1027: { kind: 'content-blocked', action: 'fix-input' },
  1004: { kind: 'auth', action: 'alert' }, // 程序解决不了,重试只会延迟告警
  1008: { kind: 'insufficient-balance', action: 'alert' },
}
 
export function classify(statusCode) {
  // 没见过的码一律当服务端故障处理:可以重试,但要记一条日志让人看见
  return RULES[statusCode] ?? { kind: 'server', action: 'retry' }
}

批量场景下还有一条口径:单张失败不要中断整批。 四十镜里第七张被审核拦了,正确做法是记下这一张、继续跑剩下三十三张,最后把失败清单一次性报出来。中断整批意味着前面六张的钱白花,而且重跑还得靠去重键才不会二次付费——这就是上一节那个键的第二个价值。

至于内容安全审核为什么会拦、提示词该怎么改、导出物要打什么标识,那是一整套合规话题,D11 会专门讲。今天只做到「分对类、不盲目重试、失败清单可读」这三件事。

源码导读

动手实验

🧪 D3 实验:从分镜数据批量产出角色定妆图与场景资产的生成器,外加一个资产库

Code location: labs/ai-drama-pipeline/day-03-character-assets

验收标准:

  1. MOCK=1 pnpm start 跑完,同一个角色目录下同时有基准图与三个变体,日志里三个变体后面都跟着「带参考图」。
  2. 报告里「第 4 步重复请求的场景重新生成了 N 张」这一行的 N 是 0,且日志里能看到两条复用记录。
  3. 报告的对照表里 6 个变体全部显示「不同」——同提示词、同 seed,唯一的差别是有没有带参考图。
  4. 资产索引里每条记录都带提示词、参考图路径与 seed,出问题时能照着复现。
  5. pnpm typecheck 通过,没有 any

starter/ 里挖了四个练习点,两个在资产库、两个在主流程,MOCK=1 下完全离线跑通。先原样跑一次,把报告最后三行的三个数字记下来:登记件数远少于生成次数、重复请求又生成了两张、对照组全部「相同」——这三个数字就是你的待办清单,每做完一个练习就有一个数字变正常。离线模式下占位图按提示词与参考图取色,所以「带没带参考图」会真的改变输出文件,指纹比对得出来。

  1. 为两个角色各生成一张基准定妆图,把路径写回人物卡的参考图字段,确认索引里出现两条 base 记录。
  2. 以基准图为参考派生三个变体,观察日志里每一行末尾都带上了「带参考图」标记。
  3. 批量生成分镜里用到的场景底图并登记入库,确认只生成了实际被引用的那几个场景。
  4. 把同一批场景原样再请求一遍,看到「复用」而不是「生成」,报告里重新生成的张数是 0。
  5. 关掉参考图跑同一组派生,对比两组指纹全部不同;接上真实密钥后把两组图并排打开,用眼睛判断哪一组还是同一个人。

面试题

今天 3 道题在下方题库区,侧重生成模型无记忆导致的一致性问题、参考图与种子各自能锁住什么、资产复用的缓存键设计。展开后先看「分析过程」再看要点——第 2 题的种子问题是这一章最容易答错的地方,几乎每次问到一致性都会顺着问下来。标注「国内高频 / 海外高频」方便按目标市场取舍。

检查清单与明日预告

  • 能调通图像生成接口,按分镜数据批量产出角色定妆图与场景图
  • 能说清角色一致性在接口层面靠什么实现,并用参考图把同一个角色固定下来
  • 能把生成好的资产建成可检索的资产库,让后面的镜头直接复用而不是重新生成
  • 能说清提示词模板、随机种子、参考图三者各自锁住什么、锁不住什么
  • 能解释为什么派生图要都参考基准图,而不是参考上一张
  • 实验的 5 条验收标准全部通过
  • 3 道面试题不看要点也能答出至少 2 道

明天(D4)我们把这些静态图变成会动的镜头:把今天挑好的定妆图当作视频的第一帧,让模型接着往下演六秒。顺序之所以是先图后视频,是因为视频生成是整条线上最慢最贵的一步——先用一分钱的图把形象定死,再花几块钱去动它,错一次的代价能低两个数量级。D4 的重点不是画质,而是异步任务客户端怎么写:提交拿标识、轮询查状态、取件换地址、下载落盘,四步每一步都会出错。

Interview questions

  • Where does the character consistency problem in image generation come from, and what engineering mitigations exist, with what trade-offs?生成模型的角色一致性问题是怎么来的?工程上有哪几种缓解手段,代价分别是什么?
    Common in ChinaCommon overseasBasic#image-generation#consistency

    How to reason about it · think before answering

    1. The differentiator is your first sentence. Saying 'the prompt wasn't detailed enough' reads as a user, not an engineer; the answer they want is that each request is an independent sample with no memory across calls.
    2. Follow the mechanism: a prompt only constrains the degrees of freedom you actually wrote down, and everything unwritten gets re-sampled — while face recognizability lives exactly in the details text cannot exhaust.
    3. Present the mitigations in three layers by what each one actually locks: a prompt template locks style and framing at near-zero cost; a fixed seed locks reproducibility for one identical prompt and stops helping the moment the prompt changes; a reference image locks the face, but only one per request, so two faces in one frame cannot both be locked.
    4. The trade-off discussion is where candidates separate: using a reference image means you must first produce a base image, which forces a human 'pick the reference sheet' step into an otherwise unattended pipeline.
    5. Volunteer the counter-intuitive rule: every derived image must reference the same base image, never the previous one. Chaining references accumulates drift, and by the fifth image it is a different person.
    6. Expect the follow-up: what if consistency still fails? The answer is cinematography — split two-character frames into reverse-angle singles and push secondary characters to wider shots, working around the API's limits with shot design.

    分析过程 · 先想清楚再作答

    1. 这题的区分度在第一句。答「提示词写得不够细」就掉到了使用者视角;面试官想听的是「模型每次请求都是独立采样、没有跨请求记忆」这个机制层面的原因。
    2. 顺着机制往下推就有了完整答案:提示词只约束了你写出来的那些自由度,没写的部分每次重新掷一遍;而人脸的辨识度恰好集中在脸型、眼距、鼻梁这些你没法用文字穷尽的细节上。
    3. 手段按「锁得住什么」分三层说,不要混在一起:提示词模板锁风格与构图,成本几乎为零;随机种子锁同一提示词的可复现性,换提示词即失效;参考图锁人脸,但每次请求只能带一张,双人同框锁不了两个人。
    4. 代价这一段才是拉开差距的地方:参考图要求你先有一张基准图,于是流程里必须插入一次「定妆并由人挑一张」的环节,这是整条自动化流水线上少数值得保留的人工卡点。
    5. 还要主动说一个反直觉的做法:派生图必须都参考同一张基准图,不能参考上一张。参考上一张会让偏差逐张累积,第五张已经不是同一个人了。
    6. 可以预期的追问:一致性做不到怎么兜底?答案是改镜头语言——把双人同框拆成正反打的单人镜头、次要角色用更远的景别,用拍法回避接口能力的边界。

    Key points

    • The root cause is that each request is an independent sample with no cross-request memory, so unconstrained degrees of freedom get re-rolled
    • A prompt template locks style and framing at near-zero cost but cannot lock facial detail
    • A fixed seed locks reproducibility for one identical prompt and stops helping once the prompt changes
    • A reference image locks the face, but you must first produce a base image and only one reference is allowed per request
    • Derive every variant from the same base image rather than chaining off the previous one, or drift accumulates image by image

    答题要点

    • 根因是模型每次请求独立采样、没有跨请求记忆,提示词没约束到的自由度会被重新掷一遍
    • 提示词模板锁风格与构图,成本几乎为零,但锁不住五官
    • 随机种子锁的是同一提示词的可复现性,提示词一变就失效
    • 参考图锁人脸,代价是必须先有基准图,且每次请求只能带一张,双人同框锁不了两个人
    • 派生图统一参考同一张基准图,不要链式参考上一张,否则偏差会逐张累积
  • Does fixing the random seed solve character consistency? What does a seed actually lock?固定随机种子能解决角色一致性吗?它到底锁住了什么?
    Common in ChinaCommon overseasIntermediate#image-generation#reproducibility

    How to reason about it · think before answering

    1. This is a yes/no trap dressed as a concept question; answering 'yes' ends it. The hinge is 'what does it actually lock' — they are testing whether you separate reproducibility from consistency.
    2. Define it first: a seed is the random starting point of sampling. With the model, prompt and other parameters unchanged, the same seed returns the same image, so what it locks is reproducibility.
    3. Then explain why that is not enough here: every shot has a different prompt because action, scene and shot size all change. Change the prompt and the sampling path changes with it, so the same seed yields a different person. A seed is a reproducibility switch, not a consistency switch.
    4. Do not dismiss it though. It earns its place twice: single-variable debugging, where you change one word and watch the image move; and stacked with a reference image, where the reference holds the face and the seed holds the remaining degrees of freedom so a whole set looks shot on the same day.
    5. One production note: for a seed to actually reproduce anything, turn the prompt optimizer off. It defaults to on, rewrites your prompt server-side, and you never see the rewrite — which destroys reproducibility.
    6. Expect the follow-up: is seed semantics the same across vendors? No guarantee — switching vendor or even model version can make the same seed produce something else, which is one more reason to keep a provider abstraction layer.

    分析过程 · 先想清楚再作答

    1. 这是一道判断题伪装成的概念题,答「能」直接出局。题眼是「到底锁住了什么」——面试官在测你有没有把复现和一致这两件事分开。
    2. 先给定义:seed 是采样的随机起点。在模型、提示词、其余参数都不变的前提下,同一个 seed 会给出同一张图,所以它锁住的是**可复现性**。
    3. 再说为什么在短剧场景里不够用:每一镜的提示词天然不同,动作、场景、景别都在变。提示词一变,采样路径就换了,同一个 seed 出来的是完全不同的人。所以 seed 是复现开关,不是一致性开关。
    4. 但不要把它说成没用。它在两个地方非常值钱:调试时做单变量对照,只改一个词看画面怎么变;以及跟参考图叠加使用,参考图管脸,seed 管其余自由度的采样起点,两者一起才让整组图像同一天在同一个棚里拍的。
    5. 生产视角补一句:想让 seed 真的可复现,必须把提示词优化开关关掉。那个开关默认是开的,它会在服务端改写你的提示词,改写结果你看不到,可复现性也就没了。
    6. 可以预期的追问:那不同厂商的 seed 语义一样吗?答案是不保证,换厂商甚至换模型版本都可能让同一个 seed 出别的图,所以 seed 不能作为跨厂商的一致性依据——这也是要有一层 provider 抽象的原因之一。

    Key points

    • No. A seed locks reproducibility: same model, same prompt, same other parameters plus same seed returns the same image
    • Every shot in a drama has a different prompt, and a changed prompt voids the seed, so it is not a consistency mechanism
    • Its real value is single-variable debugging, and stacking with a reference image — the reference holds the face, the seed holds the rest
    • For a seed to reproduce anything you must disable the server-side prompt optimizer, which is on by default and rewrites your input
    • Seed semantics do not carry across vendors or model versions, so a seed cannot underpin cross-provider consistency

    答题要点

    • 不能。seed 锁的是可复现性:模型、提示词与其余参数都不变时,同一个 seed 给出同一张图
    • 短剧每一镜的提示词天然不同,提示词一变 seed 就失效,所以它不是一致性手段
    • 它真正的用处是单变量调试,以及与参考图叠加——参考图管脸,seed 管其余自由度的采样起点
    • 要让 seed 可复现,必须关掉服务端的提示词优化开关,它默认开启且会改写你的输入
    • seed 语义不跨厂商也不跨模型版本,不能作为跨 provider 的一致性依据
  • How would you design the cache key for reusing generated assets so that you save money without serving the wrong asset?生成类资产要做复用,缓存键你会怎么设计,才能既省钱又不会串戏?
    Common in ChinaCommon overseasDeep dive#caching#cost#image-generation

    How to reason about it · think before answering

    1. This question is about two kinds of cache error with wildly asymmetric cost. A miss only costs money; a wrong hit puts last episode's prop into this one. The first is a number, the second is a content incident.
    2. The derivation is one sentence: the key must be computed from every input that changes the artifact, and nothing else. Include something irrelevant, like the output path, and one directory refactor invalidates everything and you pay again; omit something relevant, like the prompt, and a changed description silently serves the old image.
    3. Concretely, hash the asset kind, the owning entity id, the variant name, the full prompt, the reference image identity and the seed. Take a short digest as the id, and store those fields verbatim in the metadata so any artifact can be reproduced.
    4. Then name the boundaries yourself: does the model id and version belong in the key? Yes. What if the style template changes? It is part of the prompt, so it invalidates everything by construction — which is why templates should carry a version number, letting you choose the blast radius.
    5. One more production note: never cache failed generations, or you will faithfully reuse an empty result that safety review rejected. Cache hits also belong in the cost ledger, flagged as hits, otherwise you cannot report how much caching saved.
    6. Expect the follow-up: should the cache expire? Content assets usually should not expire on time; invalidate explicitly by version instead, because a time-based expiry regenerates a whole episode at the least convenient moment.

    分析过程 · 先想清楚再作答

    1. 这题考的是缓存的两类错误,而且两类的代价完全不对称。少命中只是多花钱,错命中会把上一集的道具塞进这一集——前者可量化,后者是内容事故。
    2. 推导链只有一句:**键必须由所有会改变产物的输入算出来,一项不多一项不少。** 多算了不该算的(比如输出路径),改一次目录结构缓存全部失效,白花一遍钱;少算了该算的(比如提示词),换了描述还命中老图,就是串戏。
    3. 落到这个场景,参与哈希的是:资产类别、归属对象、变体名、完整提示词、参考图标识、随机种子。用 sha1 之类取个短摘要当 id,元数据里再把这几项原样存一份,出问题能照着复现。
    4. 然后主动把边界说清楚,这是加分项:模型 id 与版本要不要进键?要。风格模板改了怎么办?它是提示词的一部分,进键之后天然全部失效——所以模板要谨慎改,或者给它一个版本号,让你能决定失效的范围。
    5. 生产视角还有一条:失败的生成不要写进缓存,否则你会稳定复用一张被审核拦下的空结果。命中缓存的那条路径也要记台账并标成命中,不然你算不出缓存到底省了多少钱。
    6. 可以预期的追问:缓存要不要过期?答案是内容型资产通常不设时间过期,而是靠版本号显式失效;时间过期会在你毫无预期的时候让一整集重新生成一遍。

    Key points

    • Derive the key from everything that changes the artifact: asset kind, owner id, variant, full prompt, reference image identity, seed, plus model id and version
    • Keep output paths and filenames out of the key, or one directory refactor invalidates the whole cache and you pay twice
    • Omitting inputs like the prompt causes wrong hits, which are content incidents and far costlier than misses
    • Store the hashed fields verbatim in metadata so any artifact is reproducible, and never cache failed generations
    • Record cache hits in the cost ledger flagged as hits, and invalidate explicitly by version rather than by time

    答题要点

    • 键由所有会改变产物的输入算出:资产类别、归属对象、变体名、完整提示词、参考图标识、随机种子,再加模型 id 与版本
    • 不要把输出路径或文件名放进键,改目录结构会让缓存整体失效,白付一遍钱
    • 少算提示词这类输入会导致错命中,那是内容事故,代价远高于少命中
    • 元数据里原样保存参与哈希的各项,出问题能复现;失败的生成不写缓存
    • 命中缓存也要记台账并标成命中,否则算不出缓存省了多少;失效靠显式版本号而不是时间过期

Comments

Sign in to join the discussion

No comments yet — be the first.