Let's build a local agentic workflow
With local Language Models
Today I will show you how to build a Python CLI that monitors a folder for new invoice files and automatically extracts key information from them using two Language Models.
This a practical example of building agentic workflows that run entirely on your local machine: no API keys, no cloud costs, no private data shared with third-parties.
You can find all the source code for this example in the LiquidAI/cookbook repository.
Give it a star ⭐ on Github if you get value from it :-)
What will we cover today?
In this example, you will learn how to:
Chain multiple Liquid Foundational Models to build a complete workflow that processes visual data (invoice images) and extracts structured information
Set up local AI inference using Ollama to run Liquid models entirely on your machine without requiring cloud services or API keys
Build a file monitoring system that automatically processes new files dropped into a directory
Extract text from images using the LFM2-VL-3B vision-language model for optical character recognition
Transform unstructured text into structured data using the LFM2-1.2B-Extract model for information extraction
Understanding the architecture
When you drop an invoice photo into a watched directory, the tool uses a chain with 2 Liquid Foundational Models:
LFM2-VL-3B extracts a raw textual description from an invoice picture.
LFM2-1.2B-Extract tranforms the raw textual description into a structured record. This record is appended to a CSV file.
Environment setup
You will need
Ollama to serve the Language Models locally.
uv to manage Python dependencies and run the application efficiently without creating virtual environments manually.
Install Ollama
macOS
# Download and install from the website https://ollama.ai/download
# Or use Homebrew
brew install ollamaLinux
curl -fsSL https://ollama.ai/install.sh | shWindows:
Download the installer from https://ollama.ai/download
Install uv
macOS/Linux:
curl -LsSf https://astral.sh/uv/install.sh | shWindows:
powershell -ExecutionPolicy ByPass -c “irm https://astral.sh/uv/install.ps1 | iex”How to run it?
Let’s start by cloning the Liquid AI cookbook repository:
git clone https://github.com/Liquid4All/cookbook.git
cd cookbook/examples/invoice-parserThen, run the application using the invoices that are already in the repository:
uv run python src/invoice_parser/main.py \
--dir invoices/ \
--image-model hf.co/LiquidAI/LFM2-VL-3B-GGUF:F16 \
--extractor-model hf.co/LiquidAI/LFM2-1.2B-Extract-GGUF:F16 \
--process-existingFeel free to modify the path to the invoices directory and the model IDs to suit your needs.
Note
You can use the 1.6B version of the VLM model and the 350M version of the extractor model as follows:
uv run python src/invoice_parser/main.py \ --dir invoices/ \ --image-model hf.co/LiquidAI/LFM2-VL-1.6B-GGUF:F16 \ --extractor-model hf.co/LiquidAI/LFM2-350M-Extract-GGUF:F16 \ --process-existing
If you have make installed, you can run the application with the following command:
make runThe data extracted from the invoices is be saved in the same directory as the invoices, in a file called `bills.csv`.
If you open the file, you will see the following data:
Observations:
The first 3 invoices are properly extracted, with the correct amount and currency.
The fourth invoice is not properly extracted, where both amount and currency are not correct.
How to improve it?
We have created a local tool that works well 75% of the time on our very small sample of invoices, which is
good enough for a demo
not good enough for a production-ready application
To improve the tool you need to:
Collect more invoices, and/or use publicly available datasets on Hugging Face.
(possibly) Flag and correct (input, output) pairs that are not properly labeled.
Fine-tune the model(s) on the corrected (input, output) pairs.
Tip 💡
Our tool uses two Liquid Foundational Models:
LFM2-VL-3B for vision-language understanding
LFM2-1.2B-Extract for information extraction
LFM2-1.2B-Extract is a highly specialized model for structurd data extraction from text. So the problem is likely not here. On the other hand, LFM2-VL-3B is a more general-purpose model for vision-language understanding, which has not necessarily been trained on the task of invoice extraction. This is the first place to look for improvements.
In the following weeks I will complete this tutorial with the fine-tuning step. In the meantime, if you are interested in learning more about model customization for Vision Language Models, I recommend you to check out last week’s post:
Fine-tuning LFM2-VL-3B to identify car makers
Today is Part 4 of my hands-on tutorial on fine-tuning Visual Language Models for image classification tasks.
That’s it for today!
I encourage you to git clone the repository and adjust the code to your needs.
I hope you learned something new today,
Show love to your loved ones (because maybe we humans are just gazillion-parameter Language Models with emotions :-))
Talk to you next week
Pau





Perfect timing! Your earlier piece on local agents made me curious, eager to tri this.