Building a Fully Local Agentic Storytelling System with Hugging Face Models
This guide walks you through constructing a completely offline, API-independent storytelling agent using a compact Hugging Face model and the Griptape framework. We’ll develop an intelligent agent capable of utilizing tools, crafting an imaginative fictional universe, creating rich characters, and managing a multi-step process that culminates in a cohesive short story. By breaking down the implementation into modular segments, each part becomes clear, demonstrating how they integrate into a seamless creative workflow.
Setting Up the Environment and Local Model Driver
First, we prepare our environment by installing the necessary libraries, including Griptape and Hugging Face transformers. We then initialize a local prompt driver using a lightweight model, ensuring all operations run on your machine without external API dependencies. A helper function is defined to neatly format and display outputs, making it easier to track the progress of each stage.
!pip install -q "griptape[drivers-prompt-huggingface-pipeline]" "transformers" "accelerate" "sentencepiece"
import textwrap
from griptape.structures import Workflow, Agent
from griptape.tasks import PromptTask
from griptape.tools import CalculatorTool
from griptape.rules import Rule, Ruleset
from griptape.drivers.prompt.huggingface_pipeline import HuggingFacePipelinePromptDriver
local_driver = HuggingFacePipelinePromptDriver(
model="TinyLlama/TinyLlama-1.1B-Chat-v1.0",
max_tokens=256,
)
def display(title, content):
print(f"n{'='*20} {title} {'='*20}")
print(textwrap.fill(str(content), width=100))
Creating an Agent with Tool Integration
Next, we build an agent equipped with a calculator tool to handle arithmetic operations. We test this setup by asking the agent to compute a mathematical expression and provide a concise explanation of the steps involved. This confirms that the agent correctly delegates tasks to its tools and generates human-readable responses, all while operating locally.
math_agent = Agent(
prompt_driver=local_driver,
tools=[CalculatorTool()],
)
math_result = math_agent.run(
"Calculate (37*19)/7 and briefly explain the process."
)
display("Agent with Calculator Tool", math_result.output.value)
Generating a Fictional World and Characters
We then define a task to create a vivid fictional setting based on a given prompt, describing its geography, culture, and conflicts in detail. Building on this, we design a function to generate character profiles that depend on the world’s description. Each character is fleshed out with background, motivations, flaws, and secrets, establishing a rich narrative foundation.
world_task = PromptTask(
input="Craft an immersive fictional world using these themes: {{ args[0] }}.nInclude descriptions of geography, society, and tensions in 3-5 paragraphs.",
id="world",
prompt_driver=local_driver,
)
def create_character_task(task_id, character_name):
return PromptTask(
input=(
"Using the world description below, develop a detailed character named {{ name }}.n"
"World details:n{{ parent_outputs['world'] }}nn"
"Outline their history, goals, weaknesses, and a hidden secret."
),
id=task_id,
parent_ids=["world"],
prompt_driver=local_driver,
context={"name": character_name},
)
scotty_task = create_character_task("scotty", "Scotty")
annie_task = create_character_task("annie", "Annie")
Applying Narrative Style Rules and Crafting the Story
To ensure the story maintains a consistent tone and structure, we introduce a set of stylistic guidelines. These rules encourage a cinematic and emotionally resonant writing style, avoid graphic content, and set a target length between 400 and 700 words. The final storytelling task synthesizes the world and character descriptions into a complete narrative with a clear beginning, middle, and end, featuring a pivotal character decision near the climax.
style_guidelines = Ruleset(
name="NarrativeStyle",
rules=[
Rule("Compose in a cinematic, emotionally compelling manner."),
Rule("Exclude explicit gore or intense violence."),
Rule("Keep the story length between 400 and 700 words."),
],
)
story_task = PromptTask(
input=(
"Write a full short story incorporating the following elements.nn"
"World:n{{ parent_outputs['world'] }}nn"
"Character 1 (Scotty):n{{ parent_outputs['scotty'] }}nn"
"Character 2 (Annie):n{{ parent_outputs['annie'] }}nn"
"Ensure the story has a defined beginning, middle, and end, with a significant choice made by a character near the climax."
),
id="story",
parent_ids=["world", "scotty", "annie"],
prompt_driver=local_driver,
rulesets=[style_guidelines],
)
story_workflow = Workflow(tasks=[world_task, scotty_task, annie_task, story_task])
theme = "a tidally locked ocean planet with storm-powered floating cities"
story_workflow.run(theme)
Reviewing Outputs and Analyzing Story Metrics
After execution, we extract and display the generated world, character profiles, and the final story. Additionally, we calculate basic metrics such as word count, paragraph count, and a simple structure score to provide insight into the story’s composition. This analytical overview helps assess the narrative’s coherence and length.
world_description = world_task.output.value
scotty_profile = scotty_task.output.value
annie_profile = annie_task.output.value
final_story = story_task.output.value
display("Fictional World", world_description)
display("Character Profile: Scotty", scotty_profile)
display("Character Profile: Annie", annie_profile)
display("Completed Story", final_story)
def analyze_story(text):
paragraphs = [p for p in text.split("n") if p.strip()]
word_count = len(text.split())
structure_score = min(len(paragraphs), 10)
return {
"word_count": word_count,
"paragraph_count": len(paragraphs),
"structure_score_0_to_10": structure_score,
}
story_metrics = analyze_story(final_story)
display("Story Analysis", story_metrics)
Summary: Harnessing Local Models for Agentic Storytelling
This tutorial demonstrates how to seamlessly orchestrate complex reasoning, tool usage, and creative generation entirely on local hardware using Griptape and Hugging Face models. By modularizing tasks, applying rulesets, and structuring workflows, we create a powerful agentic system capable of producing well-formed narratives without relying on external APIs. This approach offers full control, reproducibility, and flexibility, paving the way for advanced local AI experiments in automated storytelling, multi-task coordination, and beyond.
