I thought I’d seen every way a PDF could be formatted, until I spent three weeks chasing edge cases for a wholesale client. With B2B document extraction, no two customers use the same layout. One puts the PO Number in the header; the next buries it in a table footer under the label “Order Ref.”
Traditional automation is brittle. I rebuilt a document processing pipeline twice, first with the old rule-based method and then with a local Large Language Model (LLM). If you are trying to scale backend order processing, it helps to know where rules fall apart and where AI earns its keep.
The traditional trap: pytesseract and regex
The standard move for years has been simple: OCR the PDF into a string, then run a series of Regular Expressions (Regex) to find your data. It works perfectly until it doesn’t. I’ve written before about how to scale document extraction systems, but the logic layer stays the bottleneck.
The catch is that Regex is deterministic. It needs a pattern. If a customer changes “PO #” to “Purchase Order,” your script returns None. You end up with a “Regex graveyard” in your code that looks like this:
# The "Naive" Approach: A never-ending list of patterns
import re
def bbioon_extract_po(text):
patterns = [
r"PO Number:\s*(\d+)",
r"Order ID:\s*(\d+)",
r"Reference:\s*(\d+)",
r"Order #\s*(\d+)"
]
for pattern in patterns:
match = re.search(pattern, text, re.IGNORECASE)
if match:
return match.group(1)
return None
Maintenance becomes a nightmare. For 200 customers you might need 200 variations. Every time a client updates their invoice template, your site breaks and you are back in the debugger at 2 AM.
The pivot: B2B document extraction with LLaMA 3
The second time I built this, I kept pytesseract for the OCR heavy lifting but swapped the Regex logic for a local LLM running on Ollama. Instead of hunting for patterns, I asked the model to read the context.
LLMs are good at semantic recognition. They know that “Ref” and “PO” in a business document usually point to the same thing. Here is how that looks in a Python microservice calling a local LLaMA 3 model:
import ollama
def bbioon_llm_extraction(raw_text):
prompt = f"""
Extract the following fields from this B2B order text:
- Customer ID
- PO Number
- Delivery Date
Format the output as valid JSON.
Text: {raw_text}
"""
response = ollama.chat(model='llama3', messages=[
{'role': 'user', 'content': prompt}
])
return response['message']['content']
Now Layout A and Layout B both work, with no new rules and no broken deployments. The model “gets” it because it has seen thousands of business documents before.
The catch: when to avoid the LLM
Before you refactor everything, look at the trade-offs. LLMs are slow. A Regex search takes microseconds. An LLM inference through Ollama can take 20 to 40 seconds depending on your hardware. If you are processing 10,000 orders a day, you need a serious GPU cluster or a solid queuing system such as RabbitMQ to handle the load.
LLMs are also probabilistic, so they can hallucinate. In regulated industries like pharma or banking, explainability is mandatory, and you cannot always explain why a model picked a specific number. A Regex rule, by contrast, is an open book.
If this B2B document extraction work is eating your dev hours, I can take it off your plate. I’ve been wrestling with WordPress and custom backend integrations since the 4.x days.
Final recommendation
Don’t reach for the shiny AI tool just because it is there. If your document layouts are stable and you only have five of them, stick to Regex, since it is faster and cheaper. But if you are dealing with hundreds of messy, unpredictable B2B PDFs, the maintenance cost of rules will eventually kill the project. That is when you move the logic to LLaMA 3 and stop chasing strings.