LangGraphとGraniteを使用したエージェント・ワークフローの構築

著者

Vrunda Gadesha

AI Advocate | Technical Content Author

最新のAIシステムは、単純なプロンプト・レスポンスの対話の枠を超えて進化しています。今日のAIエージェントは、構造化された多段階の推論、意思決定を実行し、複雑なタスクを自律的に調整できます。この新しい機能は、エージェント・ワークフローと呼ばれています。これは、エージェントが一連の論理的な手順を実行して問題をより効果的に解決するという、機械学習における力強い変化です。

このチュートリアルでは、グラフベースの推論パスを構築するためのフレームワークであるLangGraphと、この構造を補完する堅牢なモデルであるIBM® Granite®モデルという2つの主要ツールを使用して、このようなAIエージェント・ワークフローを構築する方法について説明します。通常ワークフローの各ステップ(「ノード」と呼ばれる)は、大規模な言語モデルを活用したエージェントによって処理されます。これらのエージェントは、アウトプットまたは条件付きロジックに基づいて状態間を移動し、動的な意思決定主導のグラフを形成します。

これらのエージェント・ワークフローを現実に使用するために、LangGraphとGraniteモデルという2つの重要なコンポーネントを詳しく調べます。

LangGraphを理解する

スケーラブルなAI駆動型ワークフローのためのフレームワーク

LangGraphは、AIモデルを計算グラフ内のステートフル・エージェントとして表現することで、AI駆動型ワークフローの開発を効率化するように設計された強力なフレームワークです。これにより、開発者は、各動作や意思決定ポイントがグラフ内のノードとして定義される、スケーラブルなモジュール式システムを構築できます。

LangGraphを使用すると、次のことができます。

  • 各エージェントの動作を個別のノードとして定義する
  • アルゴリズムまたはモデルアウトプットを使用して、次のステップを決定する
  • ノード間で状態を渡してメモリとコンテキストを保持する
  • 推論の流れを簡単に視覚化、デバッグ、制御する

マルチエージェント・システムとLangGraphのようなフレームワークは、生成AI(生成AI)タスクに適用される場合、通常、タスク実行を順次ワークフローまたは条件付きワークフローとして構造化します。LangChain、IBM Granite®モデル、OpenAIのGPTモデル、その他の人工知能ツールを使用している場合でも、LangGraphはワークフローを最適化して拡張性と性能を向上させるのに役立ちます。

複雑なワークフローを自動化するためのLangGraphの主要なコンポーネント

LangGraphは、複雑なワークフローをモジュール式のインテリジェントなコンポーネントに分解することで、AIテクノロジーをオーケストレーションする最新のアプローチを導入します。従来のオートメーションやロボティック・プロセス・オートメーション(RPA)とは異なり、LangGraphはリアルタイムのロジックとメモリを使用することで、動的なコンテキストを意識したタスクの実行を可能にします。このフレームワークをPower® する4つの主要コンポーネントはこちらです。

  • ノード: ノードは、AIツールの呼び出し、データソースのクエリ、特定のタスクの実行など、ロジックやアクションの個々の単位を表します。大規模なビジネス・プロセス内で反復的なタスクを自動化するのに最適です。
  • エッジ: エッジはノード間のフローを定義し、タスクがどのように連携し、実行されるかをガイドします。この構造により、柔軟な意思決定プロセスが可能になり、結果に基づいてワークフローを適応させることができます。
  • 条件付きエッジ(循環グラフ): 循環グラフにより、ループと条件付き分岐が可能になり、システムがロジックまたはアウトプットに基づいてノードを再検討できるようになります。この機能は、反復的なタスクを処理し、動的な環境において情報に基づいた意思決定を行うために不可欠です。
  • 状態(ステートフル・グラフ): 状態は共有メモリとして機能し、コンテキストを保持し、ノード間でのリアルタイム・データの使用を可能にします。この機能により、LangGraphは静的フローだけではなく、ワークフロー・オートメーションにおける適応型でインテリジェントな進歩をサポートできます。

これらのコンポーネントを組み合わせることで、LangGraphは組織がAI駆動型のワークフローを設計・実行する方法を変革し、AIツールと現実世界のビジネス・プロセス間にあるギャップを埋めることができます。

複雑なワークフローを自動化するためのLangGraphの主要なコンポーネント 図1 複雑なワークフローを自動化するためのLangGraphの主要なコンポーネント

Graniteモデル—現実世界の問題解決のための軽量LLM

granite-4.0-tiny-preview、IBM Research®によって開発された、複雑な問題や実用的な自然言語処理(NLP)タスクを解決するために設計された、軽量でありながら高性能なオープンソースの言語モデルです。GraniteはGPT-4などの商用モデルよりも小規模ですが、高速で効率的であり、Hugging Faceと完全に互換性があるため、パフォーマンスを犠牲にすることなく運用効率を求める開発者にとって最適な選択肢となります。

Graniteは以下の点で優れています。

  • 意図分類 -チャットボットやタスクベースのシステムにおけるユーザーの目標の特定
  • 創造的な生成 - 要約、ダイアログ、または短い形式のコンテンツの作成
  • 推論と要約 - RAGまたはデータ分析を含むワークフローに最適

このチュートリアルでは、Graniteモデルがエージェント・ワークフローのさまざまな段階で重要な役割を果たし、問題解決とコンテンツ生成の両方をサポートします。軽量設計のため、人間の介入が制限される可能性があり、多様なデータセットやプロバイダーにわたる堅牢なAIソリューションを構築するためにスケーラブルな設計パターンが不可欠な実際のアプリケーションに適しています。

ユースケース

このチュートリアルでは、短いアニメーション画面を作成するためのクリエイティブ・アシスタントとして機能するエージェント・ワークフローを構築します。

目的

ユーザーからストーリーのアイデアが与えられると、エージェントは次のことを行います。

  • ストーリーに適したジャンルとトーンを特定する
  • 簡単なプロットの概要を生成する
  • それを主要シーン(クライマックスや転換点など)に展開する
  • そのシーンのダイアログをスクリーンプレイ形式で作成する

このユースケースは、LangGraphのワークフローによって構造化された言語モデルの推論機能と生成機能の両方を表現するように設計されています。

ワークフローの動作

次の各ステップは、LangGraphノードとして実装されます。

  • ユーザーの入力: ユーザーは、ワークフローを開始するために大まかなストーリーのアイデアを提供します。
  • ジャンル検知(node_name - select_genre): LLMはインプットを分析して、ストーリーに適切なジャンルとトーンを推測します。
  • アウトライン生成(node_name - generate_outline): LLMは、選択したジャンルに基づいて短いプロットの概要を生成します。
  • シーン・ライティング(node_name - generate_scene): LLMは重要なシーンを散文で書き、物語に命を吹き込みます。
  • ダイアログ・ライティング(node_name - Write_dialog): LLMは、シーンを制作またはさらなる編集に適した、形式化されたスクリーンプレイ・ダイアログとして再書き込みします。

これらのノードはLangGraphに順番に接続され、モデルは変更可能な状態辞書を持ちながらノードを動きます。

クリエイティブな生成と構造計画のバランスを保ったワークフローです。これは、次のことを示しています。

  • LangGraphによるLLMコーディネート
  • 最小限の手動介入で多段階のストーリーテリング
  • 人間の想像力が不可欠な領域における創造的な自動化

また、拡張にも優れており、改訂ステップ、複数のシーン・ジェネレーター、さらには文字ベースの分岐を追加することで、簡単に拡張できます。

前提条件

watsonx.aiプロジェクトを作成するには、IBM® Cloudのアカウントが必要です。

手順

ステップ1. 環境を設定する

いくつかあるツールの中から選択することもできますが、このチュートリアルでは、Jupyter Notebookを使用するためにIBMアカウントを設定する方法について説明します。

  1. IBM Cloudアカウントを使用してwatsonx.aiにログインします。
  2. watsonx.aiプロジェクトを作成します。 プロジェクトIDはプロジェクト内から取得できます。管理(Manage)タブをクリックし、全般(General)ページの詳細(Details)セクションからプロジェクトIDをコピーします。このチュートリアルではこのIDが必要になります。
  3. Jupyter Notebookを作成します。

このステップでは、このチュートリアルのコードをコピーできるノートブック環境を開きます。あるいは、このノートブックをローカル・システムにダウンロードし、watsonx.aiプロジェクトにアセットとしてアップロードすることもできます。さらに詳しいGraniteチュートリアルを見るには、IBM Granite Communityをご覧ください。このチュートリアルはGithubでも公開されています。

ステップ2. watsonx.aiランタイム・サービスとAPIキーを設定する

  1. watsonx.aiランタイムサービス インスタンスを作成します(無料インスタンスであるLiteプランを選択します)。
  2. アプリケーション・プログラミング・インターフェース(API)キーを生成します。
  3. watsonx.aiで作成したプロジェクトに、watsonx.aiランタイム・サービスを関連付けます。

ステップ3. 必要なライブラリーのインストール

このセルにより、Hugging FaceでホストされているIBM Graniteモデルを使用するために必要なコア・ライブラリーをインストールします。

  • transformers: これは、以下を含む、事前にトレーニングされた言語モデルを読み込んで対話するためのメイン・ライブラリです。granite-4.0-tiny-preview .
  • accelerate: 効率的なモデルの読み込みとデバイスの配置を支援し、特にシームレスな方法でGPUを使用する場合に役立ちます。

-q flagはインストールを静的に実行し、よりクリーンなノートブック・インターフェイスのために冗長なアウトプットを抑制します。これらのライブラリは、モデルをダウンロードし、このチュートリアルで推論を効率的に処理するために不可欠です。

注: このチュートリアルを仮想環境で実行していて、langgrapgがプリインストールされていない場合は、pip install langgraphを使用してローカル環境にインストールしてください。

!pip install -q transformers accelerate
PiPの新しいバージョンを通知する端末のスクリーンショット 出力スニペット:エージェント・ワークフローの構築—ライブラリーのインストール

ステップ4. 必要なライブラリーのインポート

このセルは、エージェント・ワークフローの構築と実行に必要なすべてのコア・ライブラリをインポートします。

AutoTokenizer およびAutoModelForCausalLM からtransformers : Graniteモデルをロードし、生成用の入力プロンプトをトークン化するために使用されます。

torch : モデル推論に必要なGPUアクセラレーションとテンソルオペレーションを提供します。

time: オプションの時間追跡と性能監視を有効にします。

StateGraph およびEND からlanggraph.graph : これらは、エージェント的ワークフロー・グラフを定義およびコンパイルするために使用されます。

IPython.display ,base64: アウトプットを適切にレンダリングし、Jupyter Notebookで生成されたアウトプットのオプションのダウンロード主要な機能を有効にするために使用されます。

これらのインポートにより、モデルの対話、ワークフローの構造化、およびアウトプットのプレゼンテーションのための環境が準備されます。

# Import libraries
from transformers import AutoTokenizer, AutoModelForCausalLM
import torch
import time
from langgraph.graph import StateGraph, END
from IPython.display import display, HTML
import base64

ステップ5. Graniteモデルとトークナイザーをロードする

このセルは、IBMのgranite-4.0-tiny-preview Hugging Faceのモデルとそれに対応するトークン化機能:

model_id: Hugging Faceでホストされている事前トレーニング済みモデルのIDを指定します。

AutoTokenizer.from_pretrained(model_id): Graniteモデルに関連付けられたトークン化された機能をロードします。トークン化は、人間が読み取れるテキストをモデルのインプット・トークンに変換する役割を担います。

AutoModelForCausalLM.from_pretrained(...): 因果的(つまり、生成)言語モデリング用の実際の言語モデルをロードします。このモデルは、インプットに基づいてアウトプットを予測および生成できます。

torch_dtype=torch.float32 引数はデータ型をfloat32に明示的に設定します。これは、メモリ効率が高く、幅広い互換性があり、GPU制約のある環境で特に役立ちます。

このステップでは、Graniteモデルがエージェント・ワークフローの背後にある「推論エンジン」として効果的に初期化されます。

#Load Granite-4.0-Tiny-Preview model and tokenizer from Hugging Face
model_id = "ibm-granite/granite-4.0-tiny-preview"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id, torch_dtype=torch.float32)
ファスト・パスが利用できないことを示すアウトプット・スニペット 出力スニペット:エージェント・ワークフローの構築—Graniteモデルの読み込み

ステップ6. Graniteでテキストを生成するユーティリティー機能

この関数generate_with_granite は、Graniteモデルを使用してテキスト生成プロセスをラップします。モデルの応答をガイドするインプット・テキストであるプロンプトを受け入れます。

max_tokens :アウトプットで生成するトークンの最大数(デフォルト:200)。

use_gpu : GPU上で推論を実行するかどうかを示すフラグ(利用可能な場合)。

主な内容:

device = torch.device(...): 要求され、利用可能な場合はGPU(cuda)を動的に選択します。それ以外の場合は、デフォルトでCPUが使用されます。

model.to(device): モデルを適切なデバイスにジャストインタイムでロードし、メモリを節約します。

tokenizer(prompt, return_tensors="pt"): インプット文字列をトークンのテンソルに変換し、モデルで処理します。

model.generate(...): 以下のようなサンプリング・ストラテジーでテキスト生成を開始します。

  • do_sample=True: ランダム性を有効にして、よりクリエイティブなアウトプットを実現します。

  • temperature=0.7 およびtop_p=0.9: 生成されたテキストのダイバーシティーを制御します。

tokenizer.decode(...): トークンを読み取り可能なテキストに戻し、特別なトークンを削除します。

この関数は、エージェントワークフロー全体で再利用され、さまざまな意思決定または生成ノードでGraniteモデルを呼び出します。

def generate_with_granite(prompt: str, max_tokens: int = 200, use_gpu: bool = False) -> str:
    device = torch.device("cuda" if use_gpu and torch.cuda.is_available() else "cpu")

    # Move model to device only at generation time
    model.to(device)
    inputs = tokenizer(prompt, return_tensors="pt").to(device)

    outputs = model.generate(
        **inputs,
        max_new_tokens=max_tokens,
        do_sample=True,
        temperature=0.7,
        top_p=0.9,
        pad_token_id=tokenizer.eos_token_id
    )

    return tokenizer.decode(outputs[0], skip_special_tokens=True).strip()

 

ステップ7. ジャンルとトーンを選択するためのノードを作成する(ノード - 1)

この関数select_genre_node は、エージェント的スクリーンプレイ生成ワークフローの最初のノードを定義します。Graniteモデルを使用し、ユーザーのインプットに基づいてストーリーのジャンルとトーンを決定します。

インプット:state を含むディクショナリ"user_input" (例: 「子供向けの奇想天外なファンタジー物語を書きたい」)。

プロンプトの構築: プロンプトはモデルに次のことを要求します。

  • クリエイティブなアシスタントとして機能します。
  • ユーザーのインプットを分析します。
  • 特定のアウトプット形式を使用してジャンルとトーンを推奨します。Genre: <genre> およびTone: <tone>

テキスト生成:プロンプトがgenerate_with_granite() ユーティリティー関数を通じてクリエイティブな返答を生成する

アウトプット解析: 単純なループにより、行先頭文字列に基づいてモデルの応答からジャンルとトーンを抽出する("Genre:" および"Tone:" ).

状態の更新: 抽出済みのgenre およびtone 値は状態ディクショナリに戻され、次のノードに渡されます。

このノードはクリエイティブな分類子として機能し、後続ノードがジャンルとトーンを基本パラメーターとして使用して、文脈に沿った概要、構造、シーンを生成できるようにします。

def select_genre_node(state: dict) -> dict:
    prompt = f"""
You are a creative assistant. The user wants to write a short animated story.
Based on the following input, suggest a suitable genre and tone for the story.
User Input: {state['user_input']}

Respond in this format:
Genre: <genre>
Tone: <tone>
""".strip()

    response = generate_with_granite(prompt)

    # Basic parsing of output
    genre, tone = None, None
    for line in response.splitlines():
        if "Genre:" in line:
            genre = line.split("Genre:")[1].strip()
        elif "Tone:" in line:
            tone = line.split("Tone:")[1].strip()

    # Update state
    state["genre"] = genre
    state["tone"] = tone
    return state

ステップ8.プロットの概要を生成するためのノードを作成する(ノード - 2)

generate_outline_node 関数は、画面生成ワークフローの2番目のノードを定義します。選択したジャンルとトーンに基づいてストーリーの簡潔なストーリーのプロフィールを生成します

インプット: この関数は次の内容を含む状態ディクショナリを受け取ります。

  • user_input:: オリジナル・ストーリーのアイデア。
  • genre: 前のノードで選択済み。
  • tone: 前のノードで選択済み。

プロンプト構築: モデルは次のように指示を受けます。

  • クリエイティブなライティング・アシスタントとして機能します。
  • ユーザーのアイデア、ジャンル、トーンを考慮します。
  • 短いアニメーション・スクリーンプレイに適した簡単なプロット概要(3~5文)を生成します。

テキスト生成: プロンプト送信先は次のとおりです。generate_with_granite() 大幅に向上token limit (max_tokens=250) 複数の文のアウトラインのためのスペースを確保します。

状態の更新: 生成されたプロットの概要が、キー"outline" の下の状態に追加されます。これは構造拡張の次のフェーズで使用できるようになっています。

このノードは、抽象的なクリエイティブな意図をストーリー向けスケッチに変換し、その後に続く詳細な3幕構成の足場を提供します。これにより、ダウンストリーム・ノードが一貫した想像上のベースラインから動作することが保証されます。

def generate_outline_node(state: dict) -> dict:
    prompt = f"""
You are a creative writing assistant helping to write a short animated screenplay.
The user wants to write a story with the following details:
Genre: {state.get('genre')}
Tone: {state.get('tone')}
Idea: {state.get('user_input')}

Write a brief plot outline (3–5 sentences) for the story.
""".strip()

    response = generate_with_granite(prompt, max_tokens=250)
    state["outline"] = response
    return state

ステップ9.概要から主要なシーンを生成するためのノードを作成する(ノード - 3)

generate_scene_node 関数は、プロットの概要が豊かな物語のシーンに変換されるワークフローの3番目のステップを定義します。このシーンは、ストーリーの転換点を生き生きと視覚化する役割を果たし、アイデアを要約からストーリーテリングに動かします。

インプット: ノードは状態ディクショナリを取得します。これには次のものが含まれます。

  • genre およびtone
  • plot outline 前のノードから

プロンプト構築: モデルは次のように指示を受けます。

  • スクリーンライターとして機能
  • ストーリーの展開を使用して、転換点または最高潮のシーンを生成するgenre ,tone およびoutline
  • 読みやすさアニメーションに適した説明を維持するために散文形式で記述する

シーン要件:

  • 鮮やかで説明的(アニメーションに最適)
  • 感情またはナラティブの中心(例、発見、紛争、解決)

テキスト生成:generate_with_granitemax_tokens=300 と呼び出され、没入型のシーン構築に十分なスペースを確保します。

状態の更新: 生成されたシーンは、"scene" キーの下の状態ディクショナリに追加されます。

ワークフローに、物語の没入型の視覚的なストーリーテリングを導入します。このノードは、単にストーリーを要約するのではなく、感覚的かつ感情的な詳細でストーリーに命を吹き込みます。アニメーション短編の制作に不可欠なものです。

def generate_scene_node(state: dict) -> dict:
    prompt = f"""
You are a screenwriter.
Based on the following plot outline, write a key scene from the story.
Focus on a turning point or climax moment. Make the scene vivid, descriptive, and suitable for an animated short film.

Genre: {state.get('genre')}
Tone: {state.get('tone')}
Outline: {state.get('outline')}

Write the scene in prose format (not screenplay format).
""".strip()

    response = generate_with_granite(prompt, max_tokens=300)
    state["scene"] = response
    return state

ステップ10. 脚本形式でキャラクターのダイアログを書くためのノードを作成する(ノード - 4)

write_dialogue_node 関数は、ストーリーテリングのワークフローにおける4番目のクリエイティブステップである、ナラティブのシーンをフォーマットされた文字ダイアログに変換することを定義します。この段階は、散文とスクリーンですぐに使える脚本執筆とのギャップを埋めるもので、登場人物に声を与えます。

インプット: ノードが期待する状態scene で、生き生きとしたストーリーの瞬間(通常は転換点または最高潮)を盛り込みます。

プロンプト構築: モデルは次のようにガイドされます。

  • ダイアログ・ライターとして機能する
  • シーンからダイアログを抽出して適応させる
  • 以下を使用して、アウトプットを画面スタイルでフォーマットする。CHARACTER: Dialogue line

対話のガイドライン:

  • 短く、表現力豊かに保つ
  • アニメーションに適していることを確実にする(視覚的、感情的、簡潔)
  • わかりやすくするために必要に応じて名前を付けます

世代:generate_with_granite() 呼び出しではmax_tokens=300 を使用します。これは表現力と明瞭さのバランスが取れており、短いアニメーション・スクリプトに最適です。

状態の更新:ダイアログは、将来の操作(表示や編集など)のために、dialogue キーの下に状態として保存されます。

def write_dialogue_node(state: dict) -> dict:
    prompt = f"""
You are a dialogue writer for an animated screenplay.

Below is a scene from the story:
{state.get('scene')}

Write the dialogue between the characters in screenplay format.
Keep it short, expressive, and suitable for a short animated film.

Use character names (you may invent them if needed), and format as:

CHARACTER:
Dialogue line

CHARACTER:
Dialogue line
""".strip()

    response = generate_with_granite(prompt, max_tokens=300)
    state["dialogue"] = response
    return state

ステップ11. 各ノードに進捗レポートを追加する

このヘルパー関数with_progress は各ワークフロー・ノードをリアルタイムの進行インジケーターでラップするように設計されています。元の関数のロジックは変更されません。実行ステータスとタイミングを追跡して印刷するだけで、長いワークフローの透明性を高めることができます。

関数の目的: 次がログ記録されるデコレータでノード(例、gen_scene_node)をラップします。

  • どのステップが実行されているか
  • ステップのインデックスと合計数
  • ステップにかかる時間

パラメーター:

  • fn : 実際のノード関数(例:write_dialog_node)
  • label : その関数の人間が読み取れるラベル
  • index : シーケンスのステップ番号(例、2)
  • total : ワークフローのステップ数の合計

内部ラッパー:

  • 開始メッセージを印刷
  • 記録の開始時刻
  • 元の関数を呼び出します
  • 経過期間を示す完了メッセージを印刷します

戻り値: プログレス・メッセージを追加する以外は動作が同一の関数の修正版。

ワークフローが増加するにつれて、特に一部のステップ(生成や編集など)に時間がかかったり、メモリ過負荷などの問題が発生したりする可能性がある場合に、どのステップが実行されているかを追跡することが重要になります。この進行状況ラッパーは透明性を確保し、デバッグランタイム診断に役立ちます。

# Wrap with progress reporting

def with_progress(fn, label, index, total):
    def wrapper(state):
        print(f"\n[{index}/{total}] Starting: {label}")
        start = time.time()
        result = fn(state)
        duration = time.time() - start
        print(f"[{index}/{total}] Completed: {label} in {duration:.2f} seconds")
        return result
    return wrapper

ステップ12. LangGraphのワークフローを定義する

このセルは、LLMワークフロー用に設計された構成グラフベースのプログラミング・フレームワークであるLangGraphを使用して、短いアニメーション・ストーリーを生成するためのワークフロー・ロジックを定義します。グラフの各ステップはクリエイティブなタスクを表し、特定のシーケンスで実行され、最終的な画面が作成されます。

ワークフローのコンポーネント:StateGraph(dict) - 辞書ベースの状態でワークフローを初期化します(つまり、ワーキング・メモリはノードからノードに渡された命令です)。

進行状況追跡によるノード登録: 各ステップ(生成選択、アウトライン生成、シーン作成、ダイアログ作成)が、with_progress()ラッパーを備えたノードとして追加されます。

graph.add_node("select_genre", with_progress(select_genre_node, "Select Genre", 1, 4)) 

このアプローチにより、各ノードが実行時にそのランタイムと進行状況を確実にログに記録します。

ワークフロー・エッジ(ノード・シーケンス): クリエイティブ・パイプラインのシーケンスは明確に定義されています。

select_genre → generate_outline → generate_scene → write_dialogue

 

set_entry_point() およびset_finish_point(): これらは、ワークフローの開始ノードと終了ノードを定義します。

graph.compile(): ワークフローを実行可能な形式(ワークフロー)にコンパイルし、初期状態で呼び出すことができるようにします。

この構造により、モジュール式読み取り可能、かつデバッグ可能なLLMワークフローが可能になります。クリエイティブ・プロセスの各段階は分離されており、個別にプロファイリングすることができ、後から交換や拡張が可能です(例: 「シーンのレビュー」ステップや「アウトプットの要約」ノードの追加など)。そのworkflow をプロンプトで実行する準備が整いました。クリエイティブ・パイプラインを段階的に実行し、ライブの進捗状況を示します。

# Define LangGraph

graph = StateGraph(dict)
graph.add_node("select_genre", with_progress(select_genre_node, "Select Genre", 1, 4))
graph.add_node("generate_outline", with_progress(generate_outline_node, "Generate Outline", 2, 4))
graph.add_node("generate_scene", with_progress(generate_scene_node, "Generate Scene", 3, 4))
graph.add_node("write_dialogue", with_progress(write_dialogue_node, "Write Dialogue", 4, 4))

graph.set_entry_point("select_genre")
graph.add_edge("select_genre", "generate_outline")
graph.add_edge("generate_outline", "generate_scene")
graph.add_edge("generate_scene", "write_dialogue")
graph.set_finish_point("write_dialogue")

workflow = graph.compile()

 

ステップ13. LangGraphワークフローを実行し、出力を表示する

この最後のコード・セルでは、完全なクリエイティブ・ワークフローを実行し、ストーリー生成の各段階の成果を表示します。

initial_state: このコマンドはワークフローの開始点であり、ユーザーが創造的なアイデアやテーマを提供します。user_inputはストーリー・パイプラインのシードとして機能します。

final_state: このコマンドは、完全なLangGraphパイプラインをトリガーします。インプットは、登録されている各ノード(select_genre、gen_outline、gen_scene、write_dialog)に順番に渡されます。

成果の表示: 最終状態ディクショナリには、さまざまなノードによって入力されたキーが含まれるようになりました。

  • "genre": ユーザー・インプットに基づいて識別されたジャンル。
  • "tone": ストーリーのトーンの質。
  • "outline": 3~5文のプロット・サマリー。
  • "scene": 散文で書かれた。鮮烈な転機を描くシーン。
  • "dialogue": 脚本としてフォーマットされたキャラクターのセリフ。

このセクションでは、段階的なモジュール式LLMワークフローを通じて、ユーザーの意図が完全版のミニスクリプトに変換される方法を説明します。これは、インタラクティブであり解釈可能、かつカスタマイズ可能なエンドツーエンドのクリエイティブ・パイプラインです。

注: GPUまたはTPUを使用している場合、コードの実行には約15~17分かかります。cedeの実行に使用されるインフラストラクチャーに基づいて実行され、アウトプットが生成されるまでには、ローカル仮想環境で約65~70分かかります。

# Run workflow
initial_state = {
    "user_input": "I want to write a whimsical fantasy story for children about a lost dragon finding its home."
}
final_state = workflow.invoke(initial_state)

# Display Results
print("\n=== Final Output ===")
print("Genre:", final_state.get("genre"))
print("Tone:", final_state.get("tone"))
print("\nPlot Outline:\n", final_state.get("outline"))
print("\nKey Scene:\n", final_state.get("scene"))
print("\nDialogue:\n", final_state.get("dialogue"))
各ステップに要した時間(90~260秒)のアウトプット・スニペット
ファンタジー・ストーリーのプロット概要と主要シーンのアウトプット
ファンタジー・ストーリーのアウトプット・スニペット
ファンタジー・ストーリーのアウトプット・スニペット
ファンタジー・ストーリーのアウトプット・スニペット

システムがユーザーのプロンプト—「迷子になったドラゴンが自分の家を見つける、子供向けの奇想天外なファンタジー物語を書きたい」—を、どのように完全なアニメーション・ストーリーへと変換するのかを理解しましょう。各ステップは、ワークフローのクリエイティブ・ノードにガイドされ、Graniteモデルによって強化され、前のステップをベースに構築されます。

1. ジャンルとトーン。ワークフローは、「迷子のドラゴンが自分の家を見つけるという、子ども向けの風変わりなファンタジー物語を書きたい」といった、ユーザーの元のプロンプトを解釈することから始まりますこのインプットに基づいて、select_genre_nodeはこのストーリーを風変わりなファンタジーとして正しく分類し、適切に魅力的で心温まるトーンを特定します。この結果は正確かつ文脈に合致しており、「風変わりな」「子ども向け」「迷子のドラゴンが家を見つける」などのフレーズの使用は、ファンタジーでありながら優しいストーリーテリングのスタイルを明確に示しています。ジャンルとトーンは、ワークフローにおけるその後のすべての生成ステップを形成する基本的なパラメーターとして機能します。

2. プロットの概要とキャラクターの説明。次のステップでは、特定されたジャンル、トーン、ユーザーの独自のアイデアに基づいて、プロットの概要を作成するようモデルに要求します。アウトプットには、3~5文のストーリー概要だけでなく、キャラクターの補足説明も含まれます。これはおそらく、プロンプトの漏洩または以前のイテレーションで指示されたフォーマット設定が保持されているためです。

プロットの概要は、傷ついたドラゴンを発見し、老薬草医の指導を受けてそのドラゴンが魔法の森に戻るのを手伝う「リリー」という名前の少女を中心に展開します。このストーリーラインはユーザーの意図を正確に反映しており、癒し、相互の信頼、友情についてのエモーショナルな雰囲気を伴う子ども向けの魔法の旅に焦点を当てています。ドラゴン、リリー、薬草医の人物描写は深みを増し、曖昧なアイデアを、明確な役割、性格、ストーリー上の責任を備えた構造化されたコンセプトに変換します。このステップにより、ストーリーが抽象的な意図から、映像化に適した具体的な構造へと確実に変化します。

3. 重要ンシーン。プロット全体の概要を考慮すると、generate_scene_node ストーリーの転換点を捉えた鮮やかなシーンを散文形式で書きます。これは、ユーザーが当初、短編アニメーションのスクリプトを作成する意図として明示的に要求していたもう1つの要素です。

選ばれた瞬間は、リリーが魔法の森で傷ついたドラゴンの世話をし、登場人物間にエモーショナルな絆と相互理解が確立するシーンです。この瞬間は、ストーリーをドラゴンの帰還に向けて転換するために非常時重要です。このシーンはイメージと感情に富み、「風変わりな」と「心温まる」という制約を守りながらも、視覚的に表現力豊かであり、短編アニメーション形式に最適です。

各段階をまたいでトーンとジャンルの一貫性を維持できるこのモデルの能力は、LangGraphの状態受け渡しワークフローの価値と、 Granite®モデルの推論機能を実証しています。

4. 脚本形式のダイアログ。最後に、write_dialogue_node 散文シーンを脚本形式の構造化されたダイアログに変換します。アニメーション用のストーリーを作成することに重点を置いたユーザー・プロンプトは、暗黙的に、ストーリーが制作または視覚化に適した形式で提示されることを要求します。このノードは、コテージと魔法の森という2つの異なるシーンにわたって、リリー、ドラゴ(ドラゴン)、老薬草医の間での適切に形式化されたダイアログを提供することで、その目標を達成します。ダイアログは、エモーショナルな手がかりや登場人物の意図を保持しながら、アニメーションのスクリプトの記述規則に合わせて形式化されます(例えば、登場人物名は大文字で記述する、シーンのヘッダーは[INT. LILY’S COTTAGE - DAY]) 。アウトプットは短く、表現力豊かで感情に訴えかけるものであり、この要素はアニメーションの世界で若い視聴者を魅了するためには不可欠です。

ワークフローの各段階では、オリジナルのプロンプト「迷子のドラゴンが自分の家を見つけるという、子ども向けの風変わりなファンタジー物語」を、構造化された創造的で表現力豊かなストーリーのアウトプットとして変換します。ジャンルの選択からダイアログの形式化まで、システムは一貫したストーリーテリング・アークの構成を段階的に構築します。LangGraphフレームワークは、タスク間の移行が論理的に接続されていることを保証し、IBM® Graniteモデルは、一貫したトーンで文脈に応じたテキスト生成を可能にします。その結果、1行のユーザー・インプットからコンパクトで映像化に適した短いアニメーション向けのストーリーが生成され、クリエイティブなAIアプリケーションにおけるエージェント・ワークフローの実践的な力を実証しています。

ストーリーテリングの体験をさらに魅力的なものにするために、生成されたストーリー要素(ジャンル、トーン、プロット、シーン、ダイアログ)を美しく形式化するシンプルなHTMLベースのビジュアライゼーションもご活用いただけます。さらに、今後の使用や共有のために、ワンクリックでスクリプト全体をテキスト・ファイルとしてダウンロードすることもできます。ストーリーの生き生きとした映像化を実現させましょう!

# Beautification and Downloadable option creation for user

def display_output_with_download(final_state):
    genre = final_state.get("genre", "")
    tone = final_state.get("tone", "")
    outline = final_state.get("outline", "")
    scene = final_state.get("scene", "")
    dialogue = final_state.get("dialogue", "")

    # Combine scene and dialogue into a full script
    script = f"""Genre: {genre}
Tone: {tone}
Outline:
{outline}
Scene:
{scene}
Dialogue:
{dialogue}
"""

    # Encode to base64
    b64_script = base64.b64encode(script.encode()).decode()

    # Create downloadable HTML content
    html = f"""
    <h2>Genre & Tone</h2>
    <p><strong>Genre:</strong> {genre}</p>
    <p><strong>Tone:</strong> {tone}</p>

    <h2>Outline</h2>
    <pre>{outline}</pre>

    <h2>Scene</h2>
    <pre>{scene}</pre>

    <h2>Dialogue</h2>
    <pre>{dialogue}</pre>

    <a download="screenplay_script.txt" href="data:text/plain;base64,{b64_script}">
        <button style="margin-top: 20px; padding: 10px 20px; font-size: 16px;">Download Script as .txt</button>
    </a>
    """
    display(HTML(html))

# Run this after workflow.invoke()
display_output_with_download(final_state)

GPUの使用状況とインフラストラクチャーに関する注意

このチュートリアルでは、テキスト生成用モデルとしてGranite-4.0-Tiny-Previewを使用しています。これはGranite®ファミリーのうち比較的小規模なモデルの1つですが、特にLangGraphワークフローで複数のノードを実行する場合、効率的に実行するにはGPU対応環境が必要です。

推奨設定:

  • 少なくとも1つのNVIDIA V100またはA100 GPU
  • 安定した処理能力を実現する16 GB以上のGPUメモリー
  • Python 3.8+(Torch、Transformer、LangGraphをインストール済み)

処理能力に関する注意:

  • GPUメモリをクリアせずにすべてのノードを順番に実行すると、CUDAのメモリー不足エラーが発生する可能性があります。
  • メモリーの問題を最小限に抑える方法:
    • モデルを生成中のみGPUに渡し、その後CPUに戻します。
    • 生成トークンを控えめにします(トークンの最大値=200~300)。
    • 必要に応じて、改訂や詳細なシーンの拡張などのノードを削除または簡素化します。

このチュートリアルをホストされたノートブック環境(IBM® watsonx.aiやGoogle Colab Pro など)で実行している場合は、ランタイム設定でGPUが有効になっていることを確認します。

リソースが少ない環境では、次のことを考慮してください。

  • モデル推論をHugging Face Inference APIにオフロードします。
  • ワークフローの複雑さを削減します。
  • CPUを使用します(生成時間を長くする)。

まとめ

このチュートリアルでは、LangGraphとIBM®のGranite-4.0-Tiny-Preview言語モデルを使用して、モジュール式のエージェント型ストーリーテリング・ワークフローを構築しました。シンプルなクリエイティブ・プロンプトから始めて、ジャンルとトーンを分類し、プロットの概要を生成し、重要なシーンを書き、脚本形式のダイアログで終わる段階的なパイプラインを組み立てました。その過程で、次の方法を実演しました。

  • LangGraphを使用した動的ワークフローの構築
  • 創造的な推論のためのGranite®などの軽量LLMの統合
  • アドホック・モデルの読み込みによるGPUメモリー制約の処理
  • 使いやすい形式でのストーリー・アウトプットの表示とエクスポート

このエージェント・フレームワークは、映像化に向けたライティングに最適であるだけでなく、クリエイティブな作業やタスク・ルーティングの幅広いユースケースに応用できます。わずか数個のノードで、風変わりなアイデアを脚本向けのストーリーに変換できる小型のライティング・アシスタントを構築できました。

開発者、作家、研究者のいずれにとっても、このチュートリアルは、クリエイティブな領域におけるLLMベースのワークフロー・エンジニアリングを追求するための実践的な基礎を提供します。

独自エージェントの構築をご検討ですか?IBM® GraniteモデルとIBM® watsonx Orchestrateを活用して創造性を発揮させましょう。

関連ソリューション
ビジネス向けAIエージェント

生成AIを使用してワークフローとプロセスを自動化する強力なAIアシスタントとエージェントを構築、デプロイ、管理しましょう。

    watsonx Orchestrateの詳細はこちら
    IBM AIエージェント・ソリューション

    信頼できるAIソリューションでビジネスの未来を構築します。

    AIエージェント・ソリューションの詳細はこちら
    IBM®コンサルティング AIサービス

    IBMコンサルティングAIサービスは、企業がAIをトランスフォーメーションに活用する方法を再考するのに役立ちます。

    人工知能サービスの詳細はこちら
    次のステップ

    事前構築済みのアプリケーションとスキルをカスタマイズする場合でも、AIスタジオを使用してカスタム・エージェント・サービスを構築し、デプロイする場合でも、IBM watsonxプラットフォームが対応します。

    watsonx Orchestrateの詳細はこちら watsonx.aiの詳細はこちら
    脚注

    1 Lang Cao. 2024. GraphReason: Enhancing Reasoning Capabilities of Large Language Models through A Graph-Based Verification Approach. In Proceedings of the 2nd Workshop on Natural Language Reasoning and Structured Explanations (@ACL 2024), pages 1–12, Bangkok, Thailand. Association for Computational Linguistics.