PDFtoMD
AI WorkflowsCrewAIAutoGenLangGraph

PDF to Markdown for AI Agents: CrewAI, AutoGen, and LangGraph

Autonomous agents choke on raw PDFs. Here is how to feed CrewAI, AutoGen, and LangGraph structured Markdown so your agents reason over documents instead of stumbling on them.

9 min readBy Rafael Abellan

Autonomous agents are supposed to read a document, reason about it, and act. In practice, the reading step is where most agent pipelines quietly fall apart. You hand a CrewAI researcher a 40-page vendor contract as a raw PDF, and instead of extracting the payment terms, it burns half its context window on page headers, footers, coordinate noise, and mangled table cells. The agent then hallucinates a clause that was never there.

The fix is almost boring in its simplicity: give your agents Markdown, not PDFs. Clean Markdown preserves the one thing agents rely on most, which is structure. Headings tell the agent where a section starts. Lists tell it these items belong together. Tables stay as tables instead of collapsing into a wall of numbers. This article walks through how to feed structured Markdown into the three most popular agent frameworks: CrewAI, AutoGen, and LangGraph.

Why Raw PDFs Break Agents

A PDF is a layout format. It describes where ink goes on a page, not what the content means. When you extract text from a PDF naively, you get a stream of characters with no reliable sense of hierarchy. For a human reading the rendered page this is fine, because your eyes reconstruct the structure. For an agent working from extracted text, the structure is simply gone.

This matters more for agents than for a single chat prompt, and here is why. An agent does not read a document once. It reads, plans, calls a tool, re-reads a slice of the document, passes findings to another agent, and loops. Every one of those steps re-consumes the document text. If that text is noisy, the noise compounds at every hop. Three specific failures show up again and again:

  • Context bloat: Layout artifacts and repeated page furniture can eat 30 to 50 percent of the tokens in a document. In a multi-agent loop, you pay that tax on every pass.
  • Lost structure: Without headings and lists, an agent cannot cleanly cite section 4.2 or extract only the pricing table. It reasons over an undifferentiated blob.
  • Broken tables: Financial figures, specs, and comparison grids turn into scrambled numbers. An agent asked to sum a column gets the wrong answer and states it confidently.

Markdown solves all three at once. Headings become explicit, lists stay grouped, tables use pipe syntax that both models and parsers understand, and the page furniture is stripped away. If you want the deeper argument for why format beats raw text, see PDF to text vs PDF to Markdown for AI.

The Universal Pattern: Convert Once, Reuse Everywhere

Before touching any framework, internalize the pattern that makes all of them work well. Do not let each agent convert the PDF on demand. Convert the document to Markdown once, up front, then pass that clean text through your pipeline. This has three benefits: conversion happens a single time instead of per agent call, every agent sees the exact same structured input, and you can inspect and cache the Markdown before it ever reaches a model.

You can produce the Markdown in two ways. For quick prototyping, drop the PDF into pdftomd.cloud, get clean Markdown in a few seconds, and paste it in. For production pipelines, call a conversion API or library so the whole flow runs unattended. Either way, the agent code below assumes you already hold a Markdown string.

CrewAI: Give Each Role Clean Source Text

CrewAI organizes work around roles. You define agents like a Researcher and a Writer, give each a goal, and hand them tasks. The document you want them to reason over should arrive as Markdown in the task description or through a tool, never as a raw PDF path that a loader mangles at runtime.

Here is a minimal research crew that reasons over a converted document. Notice that the Markdown is loaded once and injected into the task context:

from crewai import Agent, Task, Crew

# Markdown produced once, up front (from pdftomd.cloud or an API)
with open("contract.md", "r", encoding="utf-8") as f:
    document_md = f.read()

researcher = Agent(
    role="Contract Analyst",
    goal="Extract payment terms and obligations accurately",
    backstory="You read legal documents and never invent clauses.",
    verbose=True,
)

analyze = Task(
    description=(
        "Using ONLY the Markdown document below, list every payment "
        "term, due date, and penalty. Cite the section heading for each.\n\n"
        "=== DOCUMENT (Markdown) ===\n"
        + document_md
    ),
    expected_output="A bulleted list of terms, each with its section heading.",
    agent=researcher,
)

crew = Crew(agents=[researcher], tasks=[analyze])
result = crew.kickoff()
print(result)

Because the source is Markdown, the instruction cite the section heading actually works. The model can see ## Payment Terms and anchor its answer to it. Feed the same document as raw extracted PDF text and that instruction becomes meaningless, since there are no headings to cite.

If your crew handles many documents, wrap the conversion in a custom tool so agents can request Markdown for any file by name. The key discipline is that the tool returns Markdown, not a PDF blob, so the agent reasons over structure rather than layout.

Turn any PDF into agent-ready Markdown in seconds, free to start.

AutoGen: Clean Documents for Conversational Agents

AutoGen builds systems out of conversational agents that message each other. A common setup pairs an AssistantAgent that reasons with a UserProxyAgent that can execute code or fetch data. Documents usually enter the conversation as a message, which means whatever you put in that message is what every downstream turn sees.

The rule is the same: inject Markdown, not raw PDF text. Here is a compact example where the proxy seeds the conversation with a converted document and the assistant summarizes it:

from autogen import AssistantAgent, UserProxyAgent

with open("report.md", "r", encoding="utf-8") as f:
    document_md = f.read()

assistant = AssistantAgent(
    name="analyst",
    llm_config={"model": "your-model", "temperature": 0},
)

user = UserProxyAgent(
    name="user",
    human_input_mode="NEVER",
    code_execution_config=False,
)

prompt = (
    "Summarize the quarterly report below. Preserve the table of "
    "figures exactly as a Markdown table in your answer.\n\n"
    + document_md
)

user.initiate_chat(assistant, message=prompt)

Setting temperature to 0 keeps extraction deterministic, which matters when agents pass numbers to each other. Because the report arrives as Markdown, the assistant can echo the figures table back as a clean Markdown table, and the next agent in the chain parses it reliably. This is the compounding benefit again: structure preserved at the entry point stays intact through every message hop.

One practical note for AutoGen: if a document is large, put it in a single seed message rather than letting agents re-fetch and re-convert it. Re-conversion inside a loop is the fastest way to blow up both latency and token cost.

LangGraph: Markdown as Graph State

LangGraph models an agent as a state machine. You define a typed state object, and nodes read from and write to it as the graph executes. This makes LangGraph the clearest illustration of the convert-once principle, because the converted document is literally a field in the shared state that every node can read without redoing the work.

from typing import TypedDict
from langgraph.graph import StateGraph, END

class DocState(TypedDict):
    document_md: str
    findings: str

def load_document(state: DocState) -> DocState:
    with open("spec.md", "r", encoding="utf-8") as f:
        state["document_md"] = f.read()
    return state

def analyze(state: DocState) -> DocState:
    md = state["document_md"]
    # Call your model here with md as structured context.
    # Headings and tables in md let the node target sections.
    state["findings"] = run_model(
        "Extract all API endpoints from this Markdown spec:\n" + md
    )
    return state

graph = StateGraph(DocState)
graph.add_node("load", load_document)
graph.add_node("analyze", analyze)
graph.set_entry_point("load")
graph.add_edge("load", "analyze")
graph.add_edge("analyze", END)

app = graph.compile()
result = app.invoke({"document_md": "", "findings": ""})

The load_document node runs once and stores clean Markdown in document_md. Every subsequent node reads that field. If you later add a verification node or a second analyst node, they inherit the same structured text for free. This is exactly the ingestion discipline that also powers LangChain and LlamaIndex pipelines, where clean Markdown chunks produce far better retrieval than raw PDF splits.

Choosing Where Conversion Happens

You have three practical options for producing the Markdown, and the right one depends on volume and privacy needs:

ApproachBest forTradeoff
Hosted converter (pdftomd.cloud)Prototyping, low to medium volumeFast, no setup, clean output
Conversion API in your pipelineProduction agents, unattended runsAutomated, scales with your app
Local libraryStrict data residency, offlineYou maintain and tune it yourself

Whatever you choose, keep conversion outside the agent loop. The agents should receive Markdown as an input, not perform document parsing as a reasoning step. Parsing is a deterministic preprocessing job, and mixing it into probabilistic reasoning is how you get unpredictable results.

Practical Tips for Agent Reliability

Cache the Markdown

Convert each document once and store the Markdown keyed by a hash of the file. When an agent needs the document again, serve it from cache. This removes redundant conversion work and guarantees every agent sees byte-identical input, which makes runs reproducible.

Preserve tables explicitly

When a task depends on tabular data, instruct the agent to keep tables in Markdown pipe syntax rather than summarizing them into prose. Structured tables survive being passed between agents. Prose descriptions of tables drift and lose precision at each hop.

Anchor answers to headings

Ask agents to cite the heading or section they drew a fact from. This only works if the source has real headings, which is precisely what Markdown conversion gives you. Citations also make agent output auditable, so a human can verify a claim against the original document.

Set temperature low for extraction

For extraction and analysis tasks, a temperature near 0 keeps agents faithful to the source. Save higher temperatures for genuinely creative steps like drafting a summary in a particular voice.

A Complete Multi-Agent Flow

Putting it together, a robust document-reasoning pipeline looks the same across all three frameworks:

  1. Convert: Turn the PDF into clean Markdown once, using a hosted converter or an API.
  2. Cache: Store the Markdown so every agent and every rerun uses identical input.
  3. Inject: Pass the Markdown into the crew, the conversation, or the graph state.
  4. Reason: Let agents extract, analyze, and cross-check, citing headings as they go.
  5. Verify: Add a final agent or node that checks claims against the source Markdown before you act on them.

Teams building document-heavy agents across legal review, financial analysis, and research find that this single change, converting to Markdown before ingestion, removes a whole class of silent failures. For more scenarios where clean document input matters, browse the use cases.

Frequently Asked Questions

Do I still need Markdown if my model reads PDFs natively?

Yes, for agents especially. Native PDF reading works for a one-shot question, but agents re-consume the document at every step of their loop. Markdown cuts the token cost of each pass and preserves the structure agents rely on for citations and table extraction. The savings and reliability gains compound across a multi-agent run.

Which framework handles documents best?

None of them parse documents well on their own, and that is the point. CrewAI, AutoGen, and LangGraph are orchestration layers, not document parsers. Give any of them clean Markdown and they all perform well. The differentiator is your ingestion step, not the framework.

How do I handle a document too large for the context window?

Convert to Markdown first, then chunk along heading boundaries so each chunk is a coherent section. Markdown makes this clean because the headings are explicit split points. You can then retrieve only the relevant chunks per agent step, which is the same approach used in retrieval pipelines.

Can I automate conversion inside my agent pipeline?

Yes. Call a conversion API in a preprocessing step before your agents run, or in a dedicated load node like the LangGraph example above. Keep it out of the reasoning loop so parsing stays deterministic and agents only ever see finished Markdown.

What about scanned PDFs?

Scanned or image-based PDFs need OCR before they yield usable text. A converter with OCR turns them into structured Markdown with headings and tables preserved, which is exactly what your agents need. Feeding a scanned PDF straight to an agent without OCR gives it nothing to reason over.

The Takeaway

Agents do not fail because CrewAI, AutoGen, or LangGraph are weak. They fail because they are asked to reason over documents that lost their structure the moment they were extracted from a PDF. Convert to clean Markdown once, cache it, inject it into your crew or graph, and your agents suddenly stop stumbling. They cite the right sections, extract tables correctly, and spend their context on reasoning instead of layout noise.

The change is small and the payoff is large. Convert your next document at pdftomd.cloud, hand the Markdown to your agents, and watch how much more reliably they read. The free tier gives you three conversions a month with no credit card, which is enough to prove the difference on your own documents before you wire it into production.

Rafael Abellan

About the author

Rafael Abellan

Founder, PDFtoMD

Rafael Abellan is the founder of Agência Triva and ships independent side projects in parallel. PDFtoMD came out of a personal frustration: he kept burning through Claude AI's token limit by uploading long PDFs, then losing hours waiting for the cap to reset. He built the tool to fix his own workflow, and now uses it every day.

Ready to convert your PDFs to Markdown?

Free account · 3 conversions/month · No credit card required