0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AI画像・動画生成を「再現できるジョブ」として管理するための設計メモ

0
Posted at

AIで画像や動画を生成していると、こんなファイルが増えていきます。

output-01.png
output-02.png
output-final.png
output-final-2.png
clip-good.mp4
clip-retry.mp4

問題はファイル名ではありません。

数日後に clip-good.mp4 を見て、

これ、どのプロンプトと参照画像で作った?

となることです。

複数の生成モデルを使う場合、この問題はさらに大きくなります。

そこで最近は、生成物だけではなく生成そのものをJobとして保存する方が扱いやすいと考えています。

最小構成のGeneration Job

まず、最低限残したい情報をTypeScriptで定義します。

type GenerationType =
  | "text-to-image"
  | "image-to-image"
  | "text-to-video"
  | "image-to-video";

type GenerationStatus =
  | "queued"
  | "processing"
  | "completed"
  | "failed"
  | "review";

interface GenerationJob {
  id: string;
  type: GenerationType;
  model: string;

  prompt: string;
  promptVersion: number;

  references: string[];

  settings: {
    aspectRatio?: string;
    duration?: number;
  };

  status: GenerationStatus;

  output?: string;
  createdAt: string;
}

重要なのは、output だけではなく、

  • model
  • prompt
  • promptVersion
  • references
  • settings

を一緒に保存することです。

Jobを作る

簡単なfactoryを用意します。

function createJob(
  type: GenerationType,
  model: string,
  prompt: string,
  references: string[] = []
): GenerationJob {
  return {
    id: crypto.randomUUID(),
    type,
    model,
    prompt,
    promptVersion: 1,
    references,
    settings: {},
    status: "queued",
    createdAt: new Date().toISOString()
  };
}

例えば商品画像から短い動画を作る場合、

const job = createJob(
  "image-to-video",
  "video-model-a",
  "Slow camera push-in. Keep the product design unchanged.",
  ["product-front.png"]
);

のようになります。

これだけでも、生成後に入力条件を追跡できます。

Promptを上書きしない

個人的に避けたいのが、再生成するたびに古いpromptを消してしまう設計です。

例えば、

v1: Slow camera movement

v2: Slow camera push-in

v3: Slow camera push-in, keep product unchanged

と変化した場合、最終版だけ残すと「なぜv3になったのか」が分かりません。

そこでRevisionを別にします。

interface PromptRevision {
  version: number;
  prompt: string;
  reason: string;
  createdAt: string;
}

保存例:

{
  "version": 3,
  "prompt": "Slow camera push-in, keep product unchanged.",
  "reason": "Previous output changed product details.",
  "createdAt": "2026-09-18T10:30:00Z"
}

reason を残すのがポイントです。

完成したpromptよりも、何が失敗して、なぜ変更したのかの方が次回役立つことがあります。

モデルを変更してもJobを分ける

複数モデルを比較するときも、

job-101
Model A
Prompt v3
Reference A

job-102
Model B
Prompt v3
Reference A

のようにJobを分けます。

PromptとReferenceを固定すれば、モデルを変更した結果も比較しやすくなります。

逆に、

Model A + Prompt v2 + Reference A

vs.

Model B + Prompt v6 + Reference B

では、何が結果に影響したのか判断しづらくなります。

ProviderとJobを分離する

モデルが増えてきたら、アプリケーション側から特定サービスを直接呼ばないようにします。

interface GenerationProvider {
  submit(job: GenerationJob): Promise<string>;
  getStatus(taskId: string): Promise<GenerationStatus>;
  getResult(taskId: string): Promise<string | null>;
}

各サービスはAdapterとして実装します。

Application
    |
GenerationJob
    |
Provider Interface
   /     |      \
 A       B       C

こうしておけば、モデルやサービスを変更してもJob管理側への影響を小さくできます。

ブラウザ型ツールを使う場合も考え方は同じ

必ずしも自分でAPI連携を実装する必要はありません。

例えば DoMax AI のように複数の画像・動画生成モデルをまとめて扱える環境を使う場合でも、

Task
↓
Model
↓
Prompt
↓
References
↓
Output
↓
Review

という情報を残しておくと、生成結果を後から整理しやすくなります。

ここで重要なのは「モデルをたくさん使うこと」ではなく、どの条件からその結果が生まれたのか追跡できることです。

completed と approved は分ける

もう1つ分けておきたいのが、

生成成功 = 公開可能

ではないという点です。

例えば状態を、

queued
  ↓
processing
  ↓
completed
  ↓
review
  ↓
approved

と分離できます。

completed はシステム上の成功。

approved は人間による確認済み。

商品画像なら形状や色、動画なら不自然なフレーム、さらに使用した参照素材の権利などもReview段階で確認します。

まとめ

AI画像・動画生成では、完成ファイルだけを保存すると制作過程が消えてしまいます。

最低でも、

model
prompt
prompt version
references
settings
output
review status

を1つのGeneration Jobとして関連付けておくと、後から再現しやすくなります。

特に複数モデルを使うようになると、「どのモデルが一番良いか」よりも、

どの入力条件で、どのモデルを使い、なぜその結果を採用したのか

を残せる仕組みの方が重要になってきます。

生成AIを単発の「Generateボタン」ではなく、追跡可能なJobとして扱う。

小さな実装ですが、生成回数が増えるほど効いてくる設計だと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?