Contract intelligence for commodity trading
LLM pipelines that turn trading and storage contracts into structured data: option value per contract, and what changed between contract versions.
- result
- Two validated pipelines, handed over to the client team
- role
- AI/LLM consultant and developer at Trafigura (part-time, 20%)
- stack
- AWS Bedrock, LLM document extraction, multi-agent pipelines, document linking
The figures on this page are drawn for this site, and the contract clause in the worked example is invented. No client data, names or numbers are shown.
Problem
A commodity trading company signs thousands of contracts, and the terms that matter for money are buried in free text.
| Trading contracts | Storage contracts | |
|---|---|---|
| Hidden in the text | Optionality: one side may choose volume, timing, delivery or price | Fixed and variable costs, reserved capacity, dates |
| Why it matters | Every option has a value that should be priced | Fixed costs stay when utilisation drops: a case for renegotiation |
| Before | Analysts read each contract and valued it by hand | Amendments piled up; finding what changed meant rereading everything |
A worked example
7.2 Quantity. The Base Quantity is 25,000 MT per month. The Buyer may, by written notice no later than 15 days before each delivery month, increase or decrease the monthly quantity by up to 10% of the Base Quantity, at the Contract Price.
7.3 Any quantity not nominated in time shall be deemed to be the Base Quantity.
{
"optionality": "volume tolerance",
"holder": "buyer",
"range": "+/- 10% of 25,000 MT",
"exercise": "monthly, 15 days notice",
"price_basis": "contract price",
"source": "clause 7.2"
}
what the pricing library does with it
Values it as a strip of monthly options on 2,500 MT: worth more when prices are volatile, and owned by the buyer, not by us.
One sentence in a forty-page contract, and it is a financial option that nobody had priced. The pipeline finds these sentences, says who holds the option, and hands the terms to the people who can put a number on it.
Use case 1: option value per contract
- I worked with risk analysts to encode options-pricing theory into the extraction logic, so the output matches what the pricing models need rather than what is easiest to extract.
- Quality came from manual review: extraction results checked against the source contracts, errors grouped into patterns, prompts and schema refined, then run again on a larger sample.
Use case 2: storage contracts over time
Storage contracts combine fixed costs, paid whether the capacity is used or not, with variable costs. When utilisation drops, the fixed part stays. The business wanted two answers without rereading every contract: where are we paying for capacity we no longer use, and what has changed between the versions of an agreement?
The hard part: which documents belong together
Before two versions of a contract can be compared, you have to know they are the same contract, and the archive did not say. Agreements, amendments, addenda and general terms from many operators sat mixed together: scanned, renamed, renewed and extended over the years. Working out the family and lineage of each document was the core of this work.
No single field is reliable enough to do that, so the linker combines several signals:
| Signal | What it contributes |
|---|---|
| Who | Operator and entity names, normalised, with a small curated map for rebrands and transfers |
| Which contract | Reference numbers, and the base contract an amendment cites |
| Where | Site and terminal, to separate the contracts of one operator and to place documents with missing fields |
| When | Dates, to order the versions and resolve the terms that apply today |
Two lessons shaped it. Signals that look strong can be ambiguous across companies, so only distinctive ones are allowed to merge groups. And a wrong link is worse than a missed one, because it produces changes that never happened.
| Stage | What it does |
|---|---|
| 1. Extract | Scanned PDFs through OCR, then one structured record per document, with LLMs on AWS Bedrock |
| 2. Link | Contract families and lineage, from the signals above |
| 3. Compare | Field-level changes between versions: capacity, pricing, dates, key clauses |
| 4. Report | One Excel workbook for business users, JSON for systems |
Design choices that mattered
- Spend the expensive model only where it helps. The models ran on AWS Bedrock, inside the company’s cloud. Every document runs on a fast, cheap model. Only documents with missing key fields or low confidence are re-run on a stronger model, and it may only fill gaps, never overwrite. That captured most of the stronger model’s benefit at a fraction of its cost.
- Let the data check itself. Extracted values have to be consistent with each other: parts must add up to the stated total. When they do not, the document is flagged for review instead of passed on.
- Normalise before comparing. Units, currencies and names are brought to one form first, so a different spelling never shows up as a contract change.
- Prefer a missed link to a wrong one. Every linking rule was judged by precision and recall against a reference grouping. A rule that merged two unrelated contracts was dropped, even when it found more links.
Outcome
Both pipelines were validated on real contracts and handed over to the client team as documented code, with schema, run scripts and example outputs. The planned next step on their side is an internal web service built on top of them.
My role
AI/LLM consultant and developer at Trafigura in Geneva, one day a week alongside my PhD. I scoped the use cases with the business and risk teams, then designed and built both pipelines myself, from scratch and with no existing code to start from: extraction, linking, change detection and reporting. I ran the validation and wrote the handover.