Guaranteed 15% off your current AI inference bill for team spending up to $20000 / month.

Book a call →
Back to Blogs
Learn AI

Unlocking the Potential of LLMs for Academic Writing

We are going to build an academic writing assistant that takes a rough draft, identifies logical gaps, and reformats citations. It is aimed at graduate...

Unlocking the Potential of LLMs for Academic Writing

We are going to build an academic writing assistant that takes a rough draft, identifies logical gaps, and reformats citations. It is aimed at graduate students and researchers who need to tighten arguments without getting lost in stylistic minutiae.

What you'll need

You will need Python 3.10 or newer, the OpenAI SDK, and an Oxlo.ai API key from https://portal.oxlo.ai. Install the SDK with pip install openai. Because Oxlo.ai uses flat per-request pricing rather than token-based billing, you can pass in full drafts or long reference lists without worrying about prompt length inflating your cost. That makes it a practical choice for document-heavy academic workflows.

Step 1: Set up the client

Oxlo.ai exposes a standard OpenAI-compatible chat completions endpoint, which means I do not have to learn a new SDK or rewrite my inference logic. I only need to swap the base_url and plug in an Oxlo.ai API key. I verify the setup with Llama 3.3 70B, a solid general-purpose model that responds instantly with no cold start.

from openai import OpenAI

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

response = client.chat.completions.create(
    model="llama-3.3-70b",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Say 'Connection to Oxlo.ai is live.'"},
    ],
)

print(response.choices[0].message.content)

Step 2: Craft the system prompt

Before making production calls, I lock down the system prompt. It acts as a behavioral contract: the model must never hallucinate citations, must return structured feedback, and must ask for clarifying context when needed. Keeping this in a module-level constant makes A/B testing trivial.

SYSTEM_PROMPT = """You are an academic writing assistant. Your job is to help researchers improve clarity, argument structure, and citation formatting.

Rules:
1. Never invent or hallucinate citations. If a reference is missing, flag it.
2. When reviewing drafts, output feedback in exactly three sections: Argument Strength, Logical Gaps, Style and Flow.
3. When formatting citations, use APA 7th edition unless told otherwise.
4. Ask clarifying questions if the research domain or target venue is ambiguous.
5. Keep tone professional but concise."""

Step 3: Build the draft analyzer

The analyze_draft function is the workhorse. Researchers often paste entire sections of a literature review or methodology chapter, so the model needs a large context window. Kimi K2.6 supports 131K tokens of context and excels at chain-of-thought reasoning, which means it can track an argument across multiple paragraphs and flag where the evidence does not support the claim.

from openai import OpenAI

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

SYSTEM_PROMPT = """You are an academic writing assistant. Your job is to help researchers improve clarity, argument structure, and citation formatting.

Rules:
1. Never invent or hallucinate citations. If a reference is missing, flag it.
2. When reviewing drafts, output feedback in exactly three sections: Argument Strength, Logical Gaps, Style and Flow.
3. When formatting citations, use APA 7th edition unless told otherwise.
4. Ask clarifying questions if the research domain or target venue is ambiguous.
5. Keep tone professional but concise."""

def analyze_draft(draft_text: str) -> str:
    response = client.chat.completions.create(
        model="kimi-k2.6",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": f"Review the following draft and provide the three required sections.\n\nDraft:\n{draft_text}"},
        ],
    )
    return response.choices[0].message.content

sample_draft = (
    "Many researchers have studied neural networks. "
    "However, our model is better because it uses more layers. "
    "We did not compare against the most recent baseline."
)

print(analyze_draft(sample_draft))

Step 4: Add a citation formatter

PDF metadata is notoriously inconsistent. Some entries lack DOIs, others mix author names and institutions, and non-English references often lose diacritics when copied. By sending the raw text to Qwen 3 32B, I get consistent APA formatting and explicit warnings about missing fields rather than silent guesses.

from openai import OpenAI

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

SYSTEM_PROMPT = """You are an academic writing assistant. Your job is to help researchers improve clarity, argument structure, and citation formatting.

Rules:
1. Never invent or hallucinate citations. If a reference is missing, flag it.
2. When reviewing drafts, output feedback in exactly three sections: Argument Strength, Logical Gaps, Style and Flow.
3. When formatting citations, use APA 7th edition unless told otherwise.
4. Ask clarifying questions if the research domain or target venue is ambiguous.
5. Keep tone professional but concise."""

def format_citations(raw_refs: str) -> str:
    response = client.chat.completions.create(
        model="qwen-3-32b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": f"Format these references into APA 7th edition. Flag any missing fields.\n\n{raw_refs}"},
        ],
    )
    return response.choices[0].message.content

messy = """Smith, J., The AI Journal, 2023, Vol 10
Lee et al, arxiv 2024, https://arxiv.org/abs/2401.12345"""

print(format_citations(messy))

Step 5: Generate an outline

Generating an outline before drafting saves hours of restructuring later. DeepSeek V3.2 is optimized for coding and reasoning tasks, so it produces tightly organized hierarchies that respect typical IMRAD or machine-learning paper conventions. Since it is available on the Oxlo.ai free tier, I can iterate on the outline with zero cost until the structure feels right.

from openai import OpenAI

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

SYSTEM_PROMPT = """You are an academic writing assistant. Your job is to help researchers improve clarity, argument structure, and citation formatting.

Rules:
1. Never invent or hallucinate citations. If a reference is missing, flag it.
2. When reviewing drafts, output feedback in exactly three sections: Argument Strength, Logical Gaps, Style and Flow.
3. When formatting citations, use APA 7th edition unless told otherwise.
4. Ask clarifying questions if the research domain or target venue is ambiguous.
5. Keep tone professional but concise."""

def generate_outline(topic: str, venue: str, word_limit: int) -> str:
    response = client.chat.completions.create(
        model="deepseek-v3.2",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": (
                f"Create a paper outline for the topic '{topic}' "
                f"targeting the venue '{venue}' with a word limit of {word_limit}. "
                f"Include sections: Abstract, Introduction, Related Work, Method, Experiments, Conclusion."
            )},
        ],
    )
    return response.choices[0].message.content

print(generate_outline("Efficient MoE routing for long-context LLMs", "ICML", 5000))

Step 6: Wire everything into a CLI

Finally, I wrap the three utilities into a small CLI script with argparse. The script reads an input file and routes it to the correct function based on a mode flag. This keeps the interface simple enough to alias as a shell command or integrate into a Makefile.

import argparse
from openai import OpenAI

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

SYSTEM_PROMPT = """You are an academic writing assistant. Your job is to help researchers improve clarity, argument structure, and citation formatting.

Rules:
1. Never invent or hallucinate citations. If a reference is missing, flag it.
2. When reviewing drafts, output feedback in exactly three sections: Argument Strength, Logical Gaps, Style and Flow.
3. When formatting citations, use APA 7th edition unless told otherwise.
4. Ask clarifying questions if the research domain or target venue is ambiguous.
5. Keep tone professional but concise."""

def analyze_draft(draft_text: str) -> str:
    response = client.chat.completions.create(
        model="kimi-k2.6",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": f"Review the following draft and provide the three required sections.\n\nDraft:\n{draft_text}"},
        ],
    )
    return response.choices[0].message.content

def format_citations(raw_refs: str) -> str:
    response = client.chat.completions.create(
        model="qwen-3-32b",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": f"Format these references into APA 7th edition. Flag any missing fields.\n\n{raw_refs}"},
        ],
    )
    return response.choices[0].message.content

def generate_outline(topic: str, venue: str, word_limit: int) -> str:
    response = client.chat.completions.create(
        model="deepseek-v3.2",
        messages=[
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": (
                f"Create a paper outline for the topic '{topic}' "
                f"targeting the venue '{venue}' with a word limit of {word_limit}. "
                f"Include sections: Abstract, Introduction, Related Work, Method, Experiments, Conclusion."
            )},
        ],
    )
    return response.choices[0].message.content

def main():
    parser = argparse.ArgumentParser(description="Academic writing assistant via Oxlo.ai")
    parser.add_argument("mode", choices=["analyze", "cite", "outline"], help="Task to run")
    parser.add_argument("--input", "-i", required=True, help="Path to input text file")
    parser.add_argument("--venue", default="general", help="Target venue for outline mode")
    parser.add_argument("--words", type=int, default=3000, help="Word limit for outline mode")
    args = parser.parse_args()

    with open(args.input, "r", encoding="utf-8") as f:
        text = f.read()

    if args.mode == "analyze":
        result = analyze_draft(text)
    elif args.mode == "cite":
        result = format_citations(text)
    elif args.mode == "outline":
        result = generate_outline(text.strip(), args.venue, args.words)

    print("\n--- RESULT ---\n")
    print(result)

if __name__ == "__main__":
    main()

Run it

Create a file named draft.txt containing the sample draft from Step 3. Then run the analyze command. You should see structured feedback printed to stdout.

python academic_writer.py analyze -i draft.txt

Expected output:

--- RESULT ---

Argument Strength:
The draft states that the proposed model is better because it uses more layers, but it does not justify why additional layers translate to improved performance in this specific domain. The claim is asserted rather than supported.

Logical Gaps:
There is no comparison against the most recent baseline, which undermines the validity of the improvement claim. The reader cannot assess relative performance.

Style and Flow:
The transition between the general statement about neural networks and the specific model claim is abrupt. A brief contextual bridge would improve readability.

Wrap-up and next steps

Two concrete next steps. First, add a retrieval layer: parse uploaded PDFs with pymupdf and feed relevant excerpts into the prompt so the assistant can ground its critique in real sources. Second, enable streaming by passing stream=True to client.chat.completions.create and printing chunks as they arrive, which improves perceived latency during long reasoning responses. If you want to productize this, consider adding a Gradio or Streamlit frontend so labmates can paste text without touching the terminal. You could also cache repeated outline requests with a simple SQLite store, further driving down your already predictable per-request costs on Oxlo.ai.

Ready to build with Oxlo.ai?

Get started building high-performance AI inference applications today.

Get started
Ox Assistant
Online
OxBot
OxBot

Hi there! Try our cost calculator to see what you'd save with Oxlo.ai.