使用 LangGraph 和 Granite 构建智能体工作流

作者

Vrunda Gadesha

AI Advocate | Technical Content Author

现代 AI 系统的发展正在超越简单的提示与响应交互。当今的 AI 智能体能够执行结构化的多步骤推理、决策制定,并自主协调复杂任务。这种新兴功能被称为智能体工作流,这是机器学习的一项强大转变,使得智能体能够通通过一系列逻辑步骤来更有效地解决问题。

在本教程中,我们将探讨如何使用两个关键工具构建此类 AI 智能体工作流LangGraph(一个用于构建基于图形的推理路径的框架)和IBM Granite 模型(一个补充这种结构的强大模型)。工作流中的每个步骤称为“节点”,这些节点通常由大型语言模型驱动的智能体处理。这些智能体会根据模型输出或条件逻辑在状态之间转换,形成一个以决策为导向的动态图形。

为了实现这些工作流,我们将仔细研究两个基本组件:LangGraph 和 Granite。

了解 LangGraph

适用于可扩展的、AI 驱动的工作流框架

LangGraph 是一个强大的框架,旨在通过将 AI 模型表示为计算图中的状态智能体来简化 AI 驱动工作流的开发。它使开发人员能够构建可扩展、模块化的系统,其中每个行为或决策点都被定义为图形中的一个节点。

借助 LangGraph,您可以:

  • 将每个智能体的行为定义为一个独立的节点。
  • 使用算法或模型输出来确定下一步骤
  • 在节点之间传递状态以保留记忆和上下文
  • 轻松实现推理流程的可视化、调试和控制

当 LangGraph 之类的多智能体系统和框架应用于生成式 (gen AI)任务时,通常将任务执行结构化为顺序或条件工作流。无论您是使用 LangChain 、IBM Granite 模型、OpenAI 的 GPT 模型还是其他人工智能工具,LangGraph 都能帮助您优化工作流,实现更好的可扩展性和性能。

LangGraph 用于自动执行复杂工作流的关键组件

LangGraph 通过将复杂的工作流分解为模块化的智能组件,引入了一种编排 AI 技术的现代方法。与传统r 自动化或机器人流程自动化 (RPA) 不同,LangGraph 通过使用实时逻辑和记忆,实现了动态的、上下文感知的任务执行。以下是推动该框架的四个关键组件:

  • 节点: 节点代表单个逻辑或操作单元,例如调用 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_dialogue) :LLM 将场景改写为格式化的剧本对话,适合制作或进一步编辑。

这些节点按顺序连接到 LangGraph 中,模型在其中移动,同时传递可变状态字典。

这种工作流在创意生成和结构规划之间取得了平衡。它展示了:

  • 通过 LangGraph 协调 LLM
  • 多步骤叙事,尽量减少人工干预
  • 在人类想象力至关重要的领域实现创意自动化

它还具有良好的可扩展性,您可以通过添加修订步骤、多个场景生成器甚至基于角色的分支来轻松扩展。

先决条件

您需要一个 IBM® Cloud 帐户 才能创建 watsonx.ai 项目。

步骤

第 1 步:设置环境

虽然您可以选择多种工具,本教程将引导您如何设置 IBM 帐户以使用 Jupyter Notebook。

  1. 使用您的 IBM Cloud 帐户登录 watsonx.ai 。
  2. 创建 watsonx.ai 项目。 您可以从项目内部获取项目 ID。点击管理选项卡。然后,从常规页面的详细信息部分复制项目 ID。您需要此 ID 来完成本教程。
  3. 创建一个 Jupyter Notebook

此步骤将打开一个笔记本环境,可在其中复制本教程中的代码。或者,您可以将此笔记本下载到本地系统并将其作为资产上传到您的 watsonx.ai 项目。要查看更多 Granite 教程,请访问 IBM Granite 社区。本教程也可在 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 标志以静默运行安装程序,抑制冗长的输出,从而提供更简洁的笔记本界面。在本教程中,这些库对于下载模型和有效处理推理至关重要。

注意:如果您在虚拟环境中运行本教程,且没有预安装 langgrapg,请使用 pip install langgraph 在本地环境中安装。

!pip install -q transformers accelerate
通知 PiP 新版本的终端屏幕截图 输出片段:构建智能体工作流——库安装

第 4 步:导入所需库

此单元导入了构建和运行智能体工作流所需的所有核心库:

AutoTokenizerAutoModelForCausalLM 来自transformers :用于加载 Granite 模型并对输入提示进行词元化,以进行生成。

torch :提供模型推理所需的 GPU 加速和张量操作。

time: 启用可选的时间跟踪和性能监控。

StateGraphEND 来自langgraph.graph :这些用于定义和编译智能体工作流。

IPython.display ,base64: 用于在 Jupyter Notebook 中整齐地呈现输出,并在 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 模型和词元生成器

该单元从 Hugging Face 加载 IBM 的granite-4.0-tiny-preview Granite 模型及其对应的词元生成器:

model_id: 指定托管在 Hugging Face 上的预训练模型的标识符。

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.7top_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:" ).

状态更新:提取的genretone 值被重新插入到将传递给下一个节点的状态字典中。

该节点充当创意分类器,使后续节点能够以类型和风格为基本参数,生成与上下文相一致的大纲、结构和场景。

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 函数定义剧本生成工作流中的第二个节点。它建立在所选类型和风格的基础上,为故事生成简洁的剧情大纲。

输入:该函数接收包含以下内容的状态字典:

  • user_input:原始故事构思。
  • genre:在前一个节点中选择。
  • tone:在前一个节点中选择。

提示构建:模型被指示:

  • 作为创意写作助手。
  • 考虑用户的创意、类型和风格。
  • 生成适合短篇动画剧本的简短剧情大纲(3-5 句话)。

文本生成:提示信息被发送至generate_with_granite() 较高token limit (max_tokens=250) 为多句式大纲留出空间。

状态更新:生成的剧情大纲被添加到状态中,关键字为"outline" 准备好用于下一阶段的结构扩展。

这个节点将抽象的创作意图转化为叙事草图,为接下来详细的三幕结构提供了一个框架。它确保下游节点从一个连贯、富有想象力的基线开始工作。

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 函数定义了工作流中的第三步,剧情大纲在此转换为丰富的叙事化场景。这个场景生动地描绘了故事的转折点,将构思从概述转变为故事。

输入:该节点接收现在包含以下内容的状态字典:

  • genretone
  • 来自plot outline 来自前一个节点

提示构建:模型被指示:

  • 作为编剧
  • 生成一个转折点或高潮场景,方法是使用故事的genre ,toneoutline
  • 以散文格式撰写,以保持可读性适合动画的描述

场景要求:

  • 生动形象(适合动画)
  • 情感或叙事弧线的核心(例如,发现、冲突或解决)

文本生成:generate_with_granite 调用max_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 定义了叙事工作流中的第四个创意步骤:将叙事场景转化为格式化的角色对话。这一步弥合了散文和银幕剧本写作之间的差距,赋予角色声音。

输入:节点期望状态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 旨在用实时进度指示器包装每个工作流节点。它不会改变原始函数的逻辑,只是跟踪并打印执行状态和时间,使长工作流更加透明。

函数目的:用装饰器包装一个节点(例如 generate_scene_node),用于记录:

  • 正在运行的步骤
  • 步骤索引和总步数
  • 步骤所需时间

参数:

  • fn :实际节点函数(例如 write_dialogue_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 工作流

此单元通过使用 LangGraph(一个为 LLM 工作流设计的基于图的组合式编程框架)来定义生成短篇动画故事的工作流逻辑。中的每个步骤代表一项创造性任务,它们按特定顺序执行以生成最终剧本。

工作流的组件: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: 此命令是工作流的起点,用户在此提供创意或主题。用户输入作为故事管道的种子。

final_state: 此命令将触发完整的 LangGraph 管道。输入按顺序通过每个已注册的节点(select_genre、generate_outline、generate_scene 和 Write_dialage)。

显示结果:最终状态字典现在包含由各个节点填充的键:

  • "genre": 根据用户输入识别的类型。
  • "tone": 故事的基调。
  • "outline": 3-5 句话的剧情摘要。
  • "scene": 用散文格式写成的生动转折点场景。
  • "dialogue": 以剧本形式呈现的角色对话。

这一部分展示了用户意图如何通过逐步、模块化的 LLM 工作流转化为完整的迷你剧本。这是一个端到端的创意管道,具有交互性、可解释性和可定制性。

注意:如果使用的是 GPU 或 TPU,则代码运行大约需要 15–17 分钟。在本地虚拟环境中,根据用于运行代码的基础设施,生成输出大约需要 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 以散文格式撰写了一个生动的场景,捕捉了故事的转折点,这是用户原始意图中明确要求的用于开发短篇动画剧本的另一个元素。

所选时刻是莉莉在魔法森林中照料受伤的巨龙,以此建立角色间的情感共鸣和相互理解。这一时刻至关重要,它将故事转向了巨龙归家之旅。该场景意象丰富、情感充沛,遵循了“异想天开”和“暖心”的约束条件,同时在视觉上富有表现力,非常适合短篇动画形式。

模型能够在各个阶段保持类型和风格的一致性,这体现了 LangGraph 的工作流价值以及 Granite 推理能力。

4. 剧本格式的对话。最后,write_dialogue_node 将散文场景转换为剧本格式的结构化对话。用户提示——专注于为动画创作故事——隐含地要求叙事以适合制作或可视化的格式呈现。该节点通过在两个不同场景(小屋和魔法森林)中提供莉莉、德拉戈(龙)和老药剂师之间的格式良好的对话,实现了这一目标。对话保留了情感线索和角色意图,并按照动画剧本写作的惯例进行格式化(例如,角色名称大写,场景标题如[INT. LILY’S COTTAGE - DAY]) 输出保持简短、富有表现力且能引起情感共鸣,这对于在动画环境中吸引年轻观众至关重要。

每个工作流阶段将原始提示——“一个关于迷失的龙寻找家园的奇幻故事”——转化为一个结构化、富有创意和表现力的叙事输出。从类型选择到对话格式化,系统逐步构建连贯的叙事弧线。LangGraph 框架确保任务之间的转换存在逻辑连接,而 IBM Granite 模型能够生成具有连贯基调的上下文相关文本。最终呈现的是一个紧凑、可直接在屏幕上播放的短篇动画故事,完全由一行用户输入生成,这展示了智能体式工作流在创意 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 系列中较小的模型之一,但它仍然需要一个支持 GPU 的环境才能高效运行,尤其是在 LangGraph 工作流中执行多个节点时。

推荐设置:

  • 至少一个 NVIDIA V100 或 A100 GPU
  • 16 GB 或更高 GPU 显存,以获得稳定的性能
  • 已安装 Python 3.8+、torch、transformers 和 langgraph

性能注意事项:

  • 如果在不清除 GPU 内存的情况下顺序运行所有节点,可能会遇到 CUDA 内存不足错误。
  • 为了最小化内存问题:
    • 仅在生成过程中将模型移至 GPU,然后移回 CPU。
    • 保持生成词元数量适中(max_tokens=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 Consulting AI 服务

    IBM Consulting 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.