Content Creation
Draft long-form content with a consistent voice.
← All modules in this stageThe mistake everyone makes with LLM writing: ask for a 1,500-word blog post in one shot, then complain it sounds bland. The fix is the same craft any human editor uses — work in stages, hold a clear voice, and let critique do real work.
By the end of this module you'll have
- A reusable outline → draft → edit pipeline that beats one-shot generation
- A working voice guide that holds tone across long pieces
- A simple critic prompt that flags clichés, fluff, and unsupported claims
Time: about 1 hour for the basics, ~5 hours with all three notebooks.
Prerequisites: Modules 3 (prompt basics), 6 (advanced prompting), 10 (conversations).
Why one-shot generation is bad
A single "write a 1,500-word post about X" produces:
- A flat structure (intro / three points / conclusion).
- A neutral, vaguely-corporate voice.
- Confident-sounding generalities and no specifics.
Asking for the outline first solves all three: you (or the model) can fix the structure cheaply, set the voice deliberately, and decide where to dig in for specifics.
A working three-stage pipeline
Save as write_post.py:
from anthropic import Anthropic
from dotenv import load_dotenv
load_dotenv()
client = Anthropic()
VOICE = """\
VOICE GUIDE
- Plain English, second person ("you"), British spelling.
- Short sentences. One idea per paragraph.
- No marketing words: "leverage", "robust", "seamless", "in today's fast-paced world".
- Use a concrete example wherever a generality could go.
"""
def call(messages, *, max_tokens=900):
return client.messages.create(
model="claude-sonnet-4-6", max_tokens=max_tokens, system=VOICE, messages=messages,
).content[0].text
def outline(topic: str, audience: str) -> str:
return call([{
"role": "user",
"content": (
f"Topic: {topic}\nAudience: {audience}\n\n"
"Produce a tight outline: a working title, a one-sentence promise to the reader, "
"and 4–6 H2 sections with one bullet each. No fluff. No 'introduction' or 'conclusion' headings."
),
}])
def draft(topic: str, audience: str, outline_text: str) -> str:
return call([{
"role": "user",
"content": (
f"Topic: {topic}\nAudience: {audience}\n\nOUTLINE:\n{outline_text}\n\n"
"Write the full post following the outline. ~1000 words. Concrete examples preferred over abstract claims. "
"If you'd normally hedge with 'often' or 'in many cases', either commit or rewrite the sentence."
),
}], max_tokens=1800)
def critique(post: str) -> str:
return call([{
"role": "user",
"content": (
"You are a strict editor. Read the draft. Output up to 8 issues, each as: "
"ISSUE (one line), WHY (one line), FIX (a rewritten sentence). "
"Only flag: clichés, hedging, vague claims, marketing-speak, contradictions. "
"Skip typos.\n\nDRAFT:\n" + post
),
}])
if __name__ == "__main__":
topic = "How to onboard a junior engineer in their first week"
audience = "Engineering managers at small companies"
o = outline(topic, audience); print("=== OUTLINE ===\n", o, "\n")
d = draft(topic, audience, o); print("=== DRAFT ===\n", d, "\n")
c = critique(d); print("=== CRITIQUE ===\n", c)
Read the outputs in order. The outline should already feel sharper than a generic blog post. The draft should follow it. The critique should mostly flag things you also noticed — that's calibration.
What just happened?
Three pieces are doing the work:
- The voice guide is a
systemprompt. It applies to every call, so the outline, draft, and critique all share the same voice rules. ChangeVOICEonce; the whole pipeline shifts. - The outline is the cheap stage. Mistakes here cost ~30 cents and 5 seconds. Mistakes in the draft cost ~10× more. Iterate on the outline.
- The critic is a different role, not a different model. The persona ("strict editor") is what changes the output, not the model id. You can mix and match — Sonnet to write, Haiku to critique, Opus for the final polish.
Holding voice across long pieces
The longer the piece, the more voice drifts. Three things that help:
- Anchor with examples. Give the model 1–2 paragraphs in your voice as part of the system prompt: "Here are two paragraphs that sound right: ..." Few-shot beats abstract style rules.
- Generate in chunks, not all at once. For a 5,000-word piece, draft section-by-section. Pass the previous section as context so transitions stay clean.
- Run a "voice diff" critique. A separate prompt: "List places where the draft drifts from the voice guide." Surfaces drift you'd miss reading top-to-bottom.
Things to watch for
| Failure mode | Fix |
|---|---|
| Bland, hedge-y prose | Add "Commit or rewrite" rule. Forbid "often", "many", "various". |
| Specifics that look real but aren't | Tell the model: "If a number, name, or quote is needed, write [TODO: verify]." |
| Voice drifts mid-piece | Anchor with example paragraphs in system, draft in chunks. |
| Repeats the same point | Critique pass: "list any duplicate ideas across sections." |
| Sounds the same on every topic | Give topic-specific framing in the user message: who, what, why now. |
Try changing one thing
- Replace the voice guide with one written for a very different brand (e.g. an irreverent fintech). Same pipeline, completely different output.
- Run the critique pass on a piece you wrote. It often surfaces hedge words and clichés you'd defend out loud.
- Use Haiku for
outlineandcritique, Sonnet fordraft. Compare quality vs cost. - Add a fourth stage:
revise(draft, critique) -> strthat applies the critic's fixes. Now you have a one-command, four-step writer.
Going deeper: open the notebooks
notebooks/01_introduction.ipynb— outline → draft → edit on real topics, voice guides (~1.5–2h)notebooks/02_intermediate.ipynb— long-form structure (chapters, sections), citation handling (~2–3h)notebooks/03_advanced.ipynb— editorial workflows for teams, fact-checking pipelines (~1.5–2.5h)
Module checklist
- [ ] You've run the three-stage pipeline end-to-end and read all three outputs
- [ ] You've written a voice guide for a project that matters to you
- [ ] You can describe why iterating on the outline is cheaper than iterating on the draft
- [ ] You've watched the critique pass flag at least one issue you'd missed
Next module
Module 14 · Production Patterns — taking everything you've built and making it survive real users.