Local LLM for Writing, Email Drafting and Document Summarisation

Local LLMs are capable writing assistants — for drafting emails, improving documents, summarising long texts, and editing prose. All of this runs on your own hardware with no API costs and no content leaving your machine. This guide covers practical workflows for each of these use cases: the right models, the prompts that work, and Python integrations for automating repetitive writing tasks.

Email Drafting

Local LLMs handle email drafting well. The key is giving the model enough context — who you are writing to, the relationship, what you need to communicate, and the tone you want. Vague prompts produce generic emails; specific prompts produce emails you can send with light editing.

In Open WebUI or the Ollama CLI:

Effective email prompt template: “Write a [tone] email to [recipient/role] about [topic]. Context: [relevant background]. Key points to include: [1], [2], [3]. Length: [short/medium]. Sign off as [name].”

The tone parameter does significant work: “professional but warm”, “direct and concise”, “apologetic but solution-focused”, “enthusiastic” — specify it explicitly and the output matches. Without tone guidance, models default to generic professional language that often feels flat.

For a Python workflow that drafts emails from a template:

import ollama

def draft_email(to_role: str, subject: str, key_points: list,
               tone: str = "professional", sender_name: str = "Alex") -> str:
    points_text = "\n".join(f"- {p}" for p in key_points)
    prompt = f"""Draft an email with these specifications:
Recipient: {to_role}
Subject: {subject}
Tone: {tone}
Key points to cover:
{points_text}
Sign off as: {sender_name}

Write only the email body and sign-off. No subject line."""

    response = ollama.chat(
        model="llama3.1",
        messages=[{
            "role": "system",
            "content": "You write clear, effective professional emails. Match the requested tone precisely. Be concise — cut filler phrases like 'I hope this email finds you well'."
        },
        {"role": "user", "content": prompt}],
        options={"temperature": 0.5}
    )
    return response["message"]["content"]

# Example
email = draft_email(
    to_role="client project manager",
    subject="Project timeline update",
    key_points=[
        "Phase 1 complete, on schedule",
        "Phase 2 starts Monday, runs 3 weeks",
        "Need access to staging environment by Friday"
    ],
    tone="professional and confident"
)
print(email)

Document Summarisation

Summarising long documents is one of the tasks where local LLMs add the most immediate value. Meeting transcripts, research papers, contracts, reports — paste the content and ask for what you need.

Key principle: specify the output format you want. “Summarise this” produces a paragraph. “Summarise as: (1) key decisions, (2) action items with owners, (3) open questions” produces structured output you can act on immediately.

import ollama

def summarise_document(text: str, summary_type: str = "general") -> str:
    prompts = {
        "general": "Summarise the key points in 3-5 bullet points.",
        "meeting": "Extract: (1) Decisions made, (2) Action items with owners and deadlines, (3) Open questions requiring follow-up.",
        "research": "Summarise: (1) Main thesis/finding, (2) Methodology in one sentence, (3) Key results, (4) Limitations mentioned.",
        "contract": "Identify: (1) Parties involved, (2) Key obligations of each party, (3) Important dates/deadlines, (4) Any unusual clauses.",
        "executive": "Write a 2-sentence executive summary followed by 3 key takeaways for a senior leader with no prior context."
    }
    system_prompt = prompts.get(summary_type, prompts["general"])

    # Handle long documents by chunking if needed
    max_chars = 24000  # ~6000 tokens, fits in 8K context
    if len(text) > max_chars:
        text = text[:max_chars] + "\n\n[Document truncated for length]"

    response = ollama.chat(
        model="llama3.1",
        messages=[
            {"role": "system", "content": "You create precise, useful summaries. Stick to information in the document — do not add information not present in the text."},
            {"role": "user", "content": f"{system_prompt}\n\nDocument:\n{text}"}
        ],
        options={"temperature": 0.2, "num_ctx": 8192}
    )
    return response["message"]["content"]

# Use
with open("meeting_notes.txt") as f:
    notes = f.read()
print(summarise_document(notes, summary_type="meeting"))

For very long documents that exceed context, chunk them into sections, summarise each section, then summarise the summaries. The quality degrades slightly at each level of summarisation but remains useful for most purposes.

Figure 1 — Writing Task Quick Reference: Model + Temp Settings

TaskBest modelTemperaturenum_ctxEmail draftingllama3.1 or mistral0.4–0.64096Document summarisationllama3.1 or qwen2.50.1–0.28192–32768Writing improvementllama3.1 or mistral-small0.3–0.54096–8192Creative writingllama3.1 or mixtral0.7–0.98192Grammar/proofreadingany 7B+ model0.0–0.14096

Writing Improvement and Editing

Local LLMs improve drafts effectively when given specific editing goals. The most useful editing prompts are those that specify what kind of improvement you want rather than asking generically to “make it better”:

Clarity: “Rewrite this to be clearer and more direct. Cut unnecessary words and restructure any sentences that are hard to follow. Keep all the information.”

Conciseness: “Cut this to half the length while keeping all key information. Remove filler phrases, redundant sentences, and anything that repeats a point already made.”

Tone adjustment: “Rewrite this in a [more formal / friendlier / more confident / more empathetic] tone. Keep the same information.”

Audience adaptation: “Rewrite this for a [non-technical executive / junior developer / general consumer] audience. Adjust vocabulary and assumed knowledge accordingly.”

A Python function that applies multiple editing passes:

import ollama

def improve_writing(text: str, goal: str = "clarity") -> str:
    goals = {
        "clarity": "Rewrite for maximum clarity and readability. Cut filler, simplify sentences, improve flow.",
        "concise": "Cut to 60% of original length. Keep all key information, remove everything else.",
        "formal": "Rewrite in formal professional tone. No contractions, precise language.",
        "friendly": "Rewrite in warm, approachable tone. Contractions are fine. Should feel like a helpful colleague.",
        "grammar": "Fix grammar, spelling, and punctuation only. Do not change wording or content."
    }
    instruction = goals.get(goal, goal)  # allow custom instructions
    response = ollama.chat(
        model="llama3.1",
        messages=[
            {"role": "system", "content": f"You are an expert editor. Task: {instruction}\n\nReturn only the rewritten text, no commentary."},
            {"role": "user", "content": text}
        ],
        options={"temperature": 0.3, "num_ctx": 8192}
    )
    return response["message"]["content"]

# Apply multiple passes
draft = "The thing we need to think about is that the project has some issues that need addressing..."
cleaned = improve_writing(draft, "clarity")
shortened = improve_writing(cleaned, "concise")
print(shortened)

Processing Batches of Documents

The real productivity gain from local LLMs for writing tasks comes from batch processing. Summarising 50 meeting notes, drafting 20 follow-up emails from call transcripts, extracting key clauses from 30 contracts — tasks that would take hours manually take minutes with a local LLM running overnight or in a background process. Combine the summarise_document function above with a loop over a directory of files, write results to a spreadsheet or database, and you have a repeatable pipeline. Because it is local, you can run this on sensitive client documents, internal reports, or personal files without any privacy concerns. The same setup that processes one document processes a thousand — scale is free once the pipeline is built.

Recommended Models for Writing Tasks

For general writing assistance — email drafting, editing, summarisation, tone adjustment — any capable 7B+ model works well. Llama 3.1 8B is the default recommendation: strong instruction following, clean English prose output, and fast enough for interactive use. For creative writing where prose quality matters more, Mistral Small 3 (24B) or Llama 3.1 70B produce noticeably better outputs at the cost of slower generation and higher memory requirements. For editing tasks (grammar fixing, conciseness editing) where the task is more mechanical, even a 3B model is adequate and much faster. The pattern: match model size to task complexity. Grammar fixing does not need 70B. Creative writing benefits from it. Finding the smallest model that meets your quality bar for each specific task is worth the experimentation — it typically halves or triples response speed at minimal quality cost.

Getting Consistent Results: Prompt Engineering for Writing

The gap between a mediocre and excellent local LLM writing assistant is almost entirely in how you prompt it. A few principles that consistently improve writing assistance quality. First, give the model a role: starting a system prompt with “You are an experienced business writer who specialises in clear, concise professional communication” produces better results than a generic assistant prompt. The role frames how the model selects vocabulary, tone, and structure. Second, give examples of what you want: if you have a style you want to match — your own past emails, a particular author’s prose, a company style guide — include a short example in your prompt as a reference. “Write in a style similar to this example: [paste example]” is often more effective than describing the style abstractly. Third, give negative guidance: “Do not start with ‘I hope this email finds you well’. Do not use passive voice. Do not include filler phrases like ‘as per’ or ‘please be advised’.” Negative constraints are often easier for models to follow than abstract positive style guidance.

For writing tasks you do repeatedly — weekly status updates, customer response templates, meeting summaries — invest time in building a system prompt that captures exactly what you want. Test it on ten examples, refine it, and save it as a named preset in Open WebUI or a saved configuration in your Python workflow. This upfront investment pays dividends across every future use of that template. The model does not change; the prompt is the variable you control, and a well-tuned prompt produces consistently useful outputs without manual intervention on each run.

Email Reply Drafting from Thread Context

One of the highest-value email automation tasks is drafting replies based on an email thread. Give the model the thread as context and specify what you want to communicate, and it handles the threading, appropriate references to previous messages, and tone matching. For customer support, this can reduce the cognitive load of responding to common queries significantly — the local model drafts a response based on the customer’s message and your knowledge base, you review and send. For internal communications, it turns the half-hour task of writing a thoughtful status update into a five-minute review and edit. The privacy of a local setup is particularly valuable here: customer emails, internal communications, and sensitive business context can all be included in the prompt without concern about that data going to external AI services. This removes the hesitation that often prevents people from using cloud AI for business email — with local inference, the privacy concern simply does not exist.

Building a Personal Writing Assistant

The most effective local writing assistant setup is one tailored to your specific writing style and use cases. Start by identifying the three to five writing tasks you do most often — the ones that take the most time or where you most want assistance. Build a specific prompt for each task, test it on real examples, and refine it until the outputs are consistently at least 80% of the way to what you would send without editing. Save these prompts as presets. Over the first two to three weeks of use, you will develop a library of effective prompts that covers your most common writing needs. After that, most sessions involve selecting a preset, pasting content, reviewing the output, and making minor edits rather than crafting prompts from scratch. This is the mature state of a local writing assistant: a tool that handles the first draft for common tasks reliably, freeing your attention for the parts of writing that genuinely require your judgment and voice.

When Cloud AI Still Makes Sense for Writing

Local LLMs for writing are not always the right choice, and being honest about the trade-offs helps set realistic expectations. For highly creative writing tasks requiring nuanced judgment — literary fiction, complex narrative structure, work where subtle voice and originality matter most — frontier cloud models like Claude or GPT-4o still produce meaningfully better outputs than what 7B-14B local models deliver. The quality gap is smaller on structured tasks (email, summaries, editing) and larger on creative and complex analytical tasks. If you are writing something where quality is paramount and the content is not sensitive, cloud AI may be worth the cost. Local AI wins on all privacy-sensitive content, high-volume batch tasks where API costs add up, and any writing work where an 80-90% quality result is sufficient — which covers the majority of professional writing tasks most people do daily.

Leave a Comment