DEV Community

shashank ms
shashank ms

Posted on

LLMs for Creative Writing

I am going to walk through a creative writing pipeline that turns a one-sentence premise into a structured outline, a drafted scene, and a written critique. It is useful for fiction writers and narrative designers who need to iterate fast without fighting a blank page. We will wire every stage to Oxlo.ai using the OpenAI SDK so the code is a drop-in replacement you can run immediately.

What you'll need

  • An Oxlo.ai API key from https://portal.oxlo.ai
  • Python 3.10 or newer
  • The OpenAI SDK installed with pip install openai

1. Initialize the client

First, we instantiate the OpenAI client pointing at Oxlo.ai. I default to Llama 3.3 70B for reliable creative instruction following. Because Oxlo.ai uses request-based pricing, feeding long outlines back into the model does not balloon cost the way token-based billing does. See https://oxlo.ai/pricing for plan details.

from openai import OpenAI

client = OpenAI(base_url="https://api.oxlo.ai/v1", api_key="YOUR_OXLO_API_KEY")

# Verify connectivity with a short test call
response = client.chat.completions.create(
    model="llama-3.3-70b",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Say hello"},
    ],
    max_tokens=10,
)
print(response.choices[0].message.content)

2. Define the system prompt

This prompt anchors every stage of the pipeline so the model stays in a fiction-writing mindset.

SYSTEM_PROMPT = (
    "You are a fiction writing assistant. "
    "You help the user develop stories from premise to polished prose. "
    "Be concise but vivid. Focus on character motivation, sensory detail, and narrative tension. "
    "When asked for an outline, return a three-act structure with bullet points. "
    "When asked for a scene, write in the present tense with dialogue and interiority. "
    "When asked for a critique, evaluate pacing, voice, and emotional payoff, then suggest one concrete revision."
)

3. Generate a structured outline

Next, we write a function that feeds the user premise to Llama 3.3 70B and asks for a three-act outline.

def generate_outline(premise: str) -> str:
    user_message = (
        f"Premise: {premise}\n\n"
        "Return a three-act outline with 3 bullet points per act. "
        "Keep each bullet to one sentence."
    )
    response = client.chat.completions.create(
        model="llama-3.3-70b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_message},
        ],
    )
    return response.choices[0].message.content

4. Draft a scene

Now we pick one beat from the outline and expand it into a full scene. I switch to Qwen 3 32B here because its reasoning capabilities handle narrative flow well for long-form generation.

def draft_scene(outline: str, beat: str, word_count: int = 300) -> str:
    user_message = (
        f"Outline:\n{outline}\n\n"
        f"Write the following beat as a scene of roughly {word_count} words:\n{beat}\n\n"
        "Use present tense, include dialogue, and anchor the moment in a specific sensory detail."
    )
    response = client.chat.completions.create(
        model="qwen-3-32b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_message},
        ],
    )
    return response.choices[0].message.content

5. Critique the scene

Finally, we run a self-critique pass. I use DeepSeek V3 2 because its reasoning strengths work well for literary analysis, and it is available on the Oxlo.ai free tier if you want to experiment without cost. If you need even deeper reasoning, Kimi K2.6 is another strong option on Oxlo.ai.

def critique_scene(scene: str) -> str:
    user_message = (
        f"Scene:\n{scene}\n\n"
        "Provide a short critique covering pacing, voice, and emotional payoff. "
        "Then suggest one concrete revision."
    )
    response = client.chat.completions.create(
        model="deepseek-v3.2",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": user_message},
        ],
    )
    return response.choices[0].message.content

6. Wire the pipeline together

We chain the three stages so a single premise flows from outline to scene to critique. For this demo I grab the first bullet from the outline automatically.

def write_story(premise: str) -> dict:
    outline = generate_outline(premise)
    # extract the first bullet as our target beat
    lines = [line.strip() for line in outline.splitlines() if line.strip().startswith("-")]
    first_beat = lines[0].lstrip("- ").strip() if lines else "The inciting incident"
    scene = draft_scene(outline, first_beat)
    critique = critique_scene(scene)
    return {"outline": outline, "scene": scene, "critique": critique}

if __name__ == "__main__":
    result = write_story(
        "A retired astronaut discovers a radio signal coming from her old lunar landing site."
    )
    print("=== OUTLINE ===")
    print(result["outline"])
    print("\n=== SCENE ===")
    print(result["scene"])
    print("\n=== CRITIQUE ===")
    print(result["critique"])

Run it

Running the script against Oxlo.ai produces output similar to this:

=== OUTLINE ===
Act One:
- Dr. Elena Voss hears a faint beacon during a routine archival sweep.
- She realizes the signal matches the frequency of her old lunar module.
- She decides to hack into the retired observatory to triangulate the source.

Act Two:
...

=== SCENE ===
The radio crackles at 2:47 a.m. Elena leans forward, her coffee gone cold. The frequency is impossible. She checks the timestamp again, then reads the coordinates. Sea of Tranquility. Her boots were there thirty years ago. "Houston," she whispers, though Houston stopped listening years ago. She hits record.

=== CRITIQUE ===
Pacing: The opening hook is strong, but the transition from coffee to coordinates feels abrupt. Voice: The "Houston" line lands well. Emotional payoff: The loneliness reads clearly, but we could deepen it with a tactile memory of the lunar dust. Revision: Add one sentence describing the grit she still finds under her fingernails when she is stressed.

Next steps

Two concrete ways to extend this. First, add a fourth stage that feeds the critique back into the draft_scene function as revision notes to generate a second pass automatically. Second, store each artifact in a lightweight SQLite database so you can build a searchable story bible over time.

Top comments (0)