DEV Community

Allen Yang
Allen Yang

Posted on

How to Build an AI Agent for Automated Contract Review and Generation

How to Build an AI Agent for Automated Contract Review and Generation

Every Monday morning, a procurement team opens the same inbox and finds the same pile: supplier agreements. Master services agreements, NDAs, purchase orders, amendments — a dozen or more new documents, each one sent over as a PDF or a Word file by a vendor whose formatting matches nothing your team has seen before.

Here is what has to happen to each of them before the week is over:

  • someone reads the agreement and pulls out the key terms — who the parties are, how much it is worth, when it starts, how it can be ended;
  • the same terms are keyed by hand into a review tracker;
  • the agreement is checked against company policy and approved or sent back;
  • and for every vendor that passes, a brand-new contract has to be produced — the standard template opened, a dozen fields replaced, and an export to PDF — per vendor, every time.

At most companies this workflow is manual, repetitive, and error-prone. It is also exactly the kind of job an AI document agent was built for. In this article I'll walk through why, and then build one in .NET that reviews a batch of agreements, applies approval rules, and generates a signed-ready contract for every vendor that passes.

Contract intake: manual workflow vs. AI agent workflow


The manual workflow, and why it hurts

Strip the manual process down to its shape and it looks like this:

PDF contracts 
→ read each one 
→ key terms into Excel 
→ human approval 
→ re-type into a contract template 
→ export PDF per vendor
Enter fullscreen mode Exit fullscreen mode

It is the shape of a pipeline with a human in the middle of every hop, and that shape is what makes it expensive:

  • The same document gets read multiple times. Review, logging, and drafting each mean opening the agreement again. Three passes over the same text, by the same people.
  • Data is copied by hand. The vendor name, the contract value, the payment terms travel from a PDF into a spreadsheet cell by cell. Transposition errors happen. Fields get skipped. Nobody notices until the contract goes out wrong.
  • Every approved vendor means a fresh contract. Opening the template, replacing a dozen {{Placeholder}} fields, exporting a PDF — repeated once per vendor, with the formatting that legal and finance care about hanging on your ability to do it identically every time.
  • Volume spikes break the plan. A new supplier panel, a quarter-end push, an audit — the backlog multiplies and the team just works later.

None of these tasks are hard. They are simply numerous and uniform, which is precisely the profile of work that software should absorb.


The idea: an agent that reads, decides, and writes documents

The workflow collapses if one component can do three things:

  1. Understand a document — read a supplier agreement in whatever format the vendor sent, and pull out the parties, value, dates, and obligations.
  2. Decide — apply your company's approval rules to what it extracted.
  3. Manipulate — take a contract template and a list of approved vendors, and produce one well-formed, properly formatted contract per vendor.

That is the difference between an AI chatbot (reads text, talks back) and an AI agent (reads a document, acts on it, and produces a new document as the result). The pipeline becomes:

Documents 
→ AI review 
→ structured data 
→ business rules 
→ approved vendors 
→ contract generation
Enter fullscreen mode Exit fullscreen mode

The person who used to copy fields between files now approves exceptions and reviews the output. Everything in the middle is automated.


Building it in .NET with Spire.Agent.Office

In a .NET application, this workflow can be implemented with Spire.Agent.Office — a document AI agent SDK that exposes one AI() processor for Word, Excel, PowerPoint, and PDF documents. The design is simple: you load a document with the ordinary Spire API, attach the agent, and give it a natural-language instruction. The agent figures out the rest.

The setup is a NuGet package and a token:

dotnet add package Spire.Agent.Office
Enter fullscreen mode Exit fullscreen mode

Spire.Agent.Office activates its AI features with a SpireToken (free and commercial editions are available from the vendor site), and it works on .NET 10 across Windows, macOS, Linux, and Docker.

Step 1 — Configure the agent once

All four formats share one configuration. Create an AIOptions, set the token, and point WorkDir at the folder where sessions and generated files should land:

using Spire.Agent.Office.AI;
using Spire.Agent.Office.Extensions;

AIOptions agent = new AIOptions
{
    SpireToken = spireToken,       // from your Spire.Agent.Office account
    WorkDir    = @"C:\legal-ops\work",
    TimeoutMs  = 300_000
};
Enter fullscreen mode Exit fullscreen mode

WorkDir matters: it is where the agent keeps its session folders — we'll look inside one of them in a moment.

Step 2 — Review every agreement in the inbox

The core call is ExecuteInstruction(document, instruction, outputPath, attachments). Point it at a document object, describe what you want in plain language, and it returns an AIResult. Here we load each PDF that arrived this week and ask for a structured review brief:

using Spire.Pdf;

string reviewInstruction =
    "Review this supplier agreement and write a Markdown brief: a one-row table with " +
    "the parties, effective date, contract value, payment terms, liability cap, and " +
    "termination notice, then a bullet list of any clauses that look unusual for a " +
    "standard supplier agreement.";

foreach (string file in Directory.GetFiles(inboxPath, "*.pdf"))
{
    string briefPath = Path.Combine(
        briefsPath, Path.GetFileNameWithoutExtension(file) + ".md");

    using (PdfDocument agreement = new PdfDocument())
    {
        agreement.LoadFromFile(file);

        AIResult result = agreement.AI(agent).ExecuteInstruction(
            agreement, reviewInstruction, briefPath, Array.Empty<string>());

        if (result is null || !result.Success)
            throw new InvalidOperationException(
                $"Review failed for {Path.GetFileName(file)}: {result?.ErrorMessage}");
    }
}
Enter fullscreen mode Exit fullscreen mode

The agent reads the PDF in its native format — no text-extraction preprocessing, no per-layout rules. A few minutes of agent runtime replaces the read-and-copy part of the week.

Step 3 — Let business rules make the call

This is the step people usually skip, and it is the one that keeps an AI workflow defensible. The decision — which vendors pass — should not be left to a language model. It belongs in deterministic, auditable code:

// The agent extracts; your code decides.
var approved = new List<ReviewResult>();
foreach (ReviewResult r in ParseBriefs(briefsPath))          // from Step 2
{
    bool passes = r.PartyCount >= 2
               && r.LiabilityCap >= 1_000_000m               // our floor
               && r.TerminationNotice <= 60;                 // days
    if (passes) approved.Add(r);
}
WriteVendorList(@"C:\legal-ops\data\approved-vendors.xlsx", approved);
Enter fullscreen mode Exit fullscreen mode

(ParseBriefs and WriteVendorList are whatever you already use to read a tracker and emit a spreadsheet — or you can ask the agent to write the extracted fields straight to .xlsx, .json, or .csv. The important thing is where the decision lives: in code, where it can be reviewed, versioned, and quoted in an audit.)

Only vendors that pass move to the last step.

Step 4 — Generate one contract per approved vendor

Now the agent does the part a deterministic SDK would do with dozens of Replace calls: take one template plus the approval list and produce a contract for every row.

using Spire.Doc;

string[] attachments = { @"C:\legal-ops\data\approved-vendors.xlsx" };

using (Document contract = new Document())
{
    contract.LoadFromFile(@"C:\legal-ops\templates\supplier-contract.docx");

    AIResult result = contract.AI(agent).ExecuteInstruction(
        contract,
        "Issue one purchase contract per approved vendor: read 'approved-vendors.xlsx' " +
        "row by row, fill the {{Placeholder}} fields in this template with each vendor's " +
        "data, preserve the template layout and styling, and save each contract as an " +
        "independent PDF in the work directory.",
        null,                              // one file per vendor, written by the agent
        attachments);

    if (result is null || !result.Success)
        throw new InvalidOperationException(
            $"Contract generation failed: {result?.ErrorMessage}");
}
Enter fullscreen mode Exit fullscreen mode

The template carries the placeholders; the spreadsheet carries the data; one instruction drives every contract. Clause numbering, tables, and fonts survive because the output is produced by a deterministic document engine, not a language model improvising a file format. And note the null output path: with no single file for the agent to return, it writes one PDF per vendor — into its own session folder under WorkDir.


Under the hood: what the agent actually left on disk

Here is the part I find most interesting, and the reason an agent like this is trustworthy enough for a legal workflow. When you call ExecuteInstruction, the agent runs a session, and every session is written to disk under WorkDir:

C:\legal-ops\work\
└─ .office_use_tmp\
   └─ Word\
      └─ 0812093540_c6825d69dd\     ← one session per ExecuteInstruction call
         ├─ process.csx             ← the C# script the agent generated
         ├─ input.docx              ← the contract template it worked on
         ├─ approved-vendors.xlsx   ← the approval list it read
         ├─ output_Brightpath_Analytics_Ltd.pdf
         ├─ output_Evercrest_Digital_Solutions_Inc.pdf
         └─ output_Novalune_Systems_LLC.pdf
Enter fullscreen mode Exit fullscreen mode

Each session folder is flat and self-contained: the input documents, the generated script, and one output file per approved vendor — named after the vendor — sitting side by side. The session id is a timestamp plus a short hash, so folders don't collide when you run the agent in batches.

The agent doesn't mutate your files by magic. It plans the task, writes a real C# script (process.csx) that drives the Spire document APIs, executes it with the .NET scripting runtime, and stages the inputs and outputs in the session folder. The script is self-contained: it pulls in the Spire packages it needs with its own #r "nuget: ..." directives at the top, so it runs against the exact versions it names — independent of whatever your application happens to have loaded.

That last point is worth being concrete about, because process.csx is exactly what you would expect a .NET developer to write by hand:

// process.csx — the agent generated this script (abridged)
var workDir = Args[0];
using (var wb = new Workbook())
{
    wb.LoadFromFile(Path.Combine(workDir, "approved-vendors.xlsx"));
    // ... read each vendor row into `vendors`
}

foreach (var v in vendors)
{
    var doc = new Document();
    doc.LoadFromFile(Path.Combine(workDir, "input.docx"));
    doc.Replace("{{Vendor Name}}", v["Vendor Name"]);
    doc.Replace("{{Payment Terms}}", v["Payment Terms"]);
    doc.Replace("{{Contract Term}}", v["Contract Term"]);
    var fileName = "output_" + v["Vendor Name"].Replace(' ', '_') + ".pdf";
    doc.SaveToFile(Path.Combine(workDir, fileName), Spire.Doc.FileFormat.PDF);
    doc.Dispose();
}
Enter fullscreen mode Exit fullscreen mode

The agent read the approval workbook, loaded the template for every row, replaced the placeholders one by one, and exported a PDF per vendor — then left the script on disk for you to read. That is the deterministic document layer doing its job: the model decided what to fill, and the script is the ordinary Spire API code that filled it.

Three practical consequences:

  • It's inspectable. Open process.csx and you can read the exact operations that were run on your template — which placeholders were replaced, how the PDFs were exported. There is no opaque black box to take on faith.
  • It's auditable. The session folder is a complete record: input documents in, the script, output documents out. For contracts, that paper trail is the difference between automation you can defend and automation you can only hope about.
  • The output is a real document. Because the script drives a deterministic engine, the result is a well-formed .docx or .pdf, not a text blob. The model decides what to do; the engine guarantees how the file is built.

This is why a document agent is different from "AI that summarizes PDFs": it leaves a reproducible, inspectable trace, and it hands back files you can sign.


Why an agent instead of just an LLM?

If you have access to an LLM API, the temptation is to skip the document layer and "generate a contract" with a prompt. That fails in three ways that matter here:

  1. LLMs can't reliably read or write Office files. They see text, not the structure of a .docx or .pdf. Reading a Word template, keeping a table intact, and emitting a valid PDF means building your own extraction and reconstruction pipeline.
  2. Formatting is the deliverable. Contract templates carry clause numbering, tables, and fonts that legal and finance care about. A raw LLM returns text; the formatting you lose is exactly what matters to the recipient.
  3. You own the whole orchestration. Prompt design, parsing, file I/O, and error handling all become your code to maintain, on top of the LLM's non-determinism.

An agent pairs the model's language understanding with a deterministic document layer: the model decides what to extract and fill, and the document layer guarantees the file. That is the difference between a demo and a workflow a team can ship — and, as we just saw, the difference is literally inspectable on disk.


The pattern doesn't stop at contracts

Notice that the pipeline — understand → decide → manipulate → batch — has nothing contract-specific in it. The same agent, with a different instruction and a different template, handles the jobs teams automate next:

  • Resume screening: extract candidate details from a folder of PDF/DOCX resumes, apply hiring rules, generate offer letters.
  • Invoice processing: pull invoice number, vendor, amount, and tax from PDFs, flag exceptions, emit a payment report.
  • RFP response: read the requirements document, match them against your capability library, and draft a proposal.
  • Vendor quote comparison: normalize quotes from PDF and Excel, compare line by line, and produce a purchasing analysis.

Each one is the same architecture: an instruction in, a real document out, and a session folder on disk showing exactly what happened.


Wrapping up

Contract review and generation is one of the fastest places to get value from an AI document agent: a batch of PDFs in, a list of approved vendors decided by code, and one signed-ready contract per vendor out — with a reproducible process.csx session you can audit behind every file.

The workflow we built runs in seconds per document, replaces the read-and-copy part of a legal analyst's week, and keeps the two things an AI should never do out of the loop: the binary approval decision stays in code, and the final document stays a real, well-formed file.

If you want to try it, the Spire.Agent.Office getting-started tutorial walks through the integration, and the product overview covers the four agents (Word, Excel, PowerPoint, PDF) it exposes. The example above is the whole integration surface — everything else is the instruction.

Top comments (0)