Projects Applied AI · Business
AI for the operations of a services company
An assistant that answers from the company’s internal documentation and a quote generator, in daily use at the office.
- Role
- Project lead · design, development and deployment
- Year
- 2025–2026
- Tools
- Python · SQLite FTS5 · OpenAI (embeddings and GPT) · OCR · Flask · Own VPS · Word and PDF
- Status
- In production · internal use
How to use it
A recreation with made-up data of how the assistant reasons: it identifies the building among its aliases, retrieves only that building’s documents and answers citing its sources. The second tab shows the quote generator.
At the office, the question “which day is the garage of such-and-such building cleaned?” could take twenty minutes of digging through contracts, emails and work reports. The problem wasn’t the AI: it was that the same building was written in a thousand different ways.
- 6 GB+
- Indexed documentation, from contracts to emails and scans
- 2,500+
- Residential buildings identified
- 5,000+
- Different ways of naming them, unified in one registry
- 30,000+
- Verified links between documents and buildings
The context
A Madrid cleaning, maintenance and gardening company: around 60 employees and hundreds of clients, almost all of them residents’ associations. The information needed for the work was spread across the ERP, contracts in Word and PDF, quotes, work reports, spreadsheets, paper scans and years of email.
The real problem: names
Before searching for anything, you had to know who each document is about. The same building appears as “C. P. Olmo 14”, “Calle del Olmo, 14 – portal”, “Comunidad Olmo n.º 14” or simply “Olmo” in an email subject. A normal search engine treats those four as four different things, and a language model, if it receives fragments from two similar buildings, mixes up the data without warning.
That is why the core piece isn’t the model but a building registry: each building has a canonical code and a list of aliases (over 5,000), and every document is linked to the building it belongs to. The links were verified against the production database.
How it answers
- Identify. It first detects which building the question is about and resolves it to its code.
- Retrieve in two ways at once. Search is hybrid: by keywords (BM25 on SQLite FTS5, with a different weight for each document field) and by meaning (OpenAI
text-embedding-3-smallembeddings). Keywords catch what embeddings blur, such as addresses, door numbers or office jargon. Meaning catches what the words don’t share. - Isolate. If the question is about one building, only that building’s documents get in. When in doubt, the system prefers returning fewer results to returning a wrong one.
- Answer with sources. The model writes only from what was retrieved and cites where each piece of data comes from. If it can’t find it, it says so.
It runs three queries in parallel so the user doesn’t wait, caches the embeddings of repeated questions and has a spending cap on embeddings so that a re-index can’t blow up the bill.
What you don’t see
- Scans: paper pages go through OCR and are reviewed; pages from the same document are grouped so the system reads them together, not as loose fragments.
- Tagged email: every imported email is classified (corporate, confidential HR) so it is handled with the level of confidentiality it requires.
- Controlled deployments: every published version carries a manifest with the SHA-256 fingerprint of each file, so you always know what is on the server and can roll back.
Quote generator
The second tool writes and lays out the office’s quotes. The key decision was to separate writing from calculation: the model writes the text, but the numbers and the layout (PDF and Word) are deterministic code. The same inputs always produce the same document, and an AI mistake can never change a price.
It also suggests prices based on the ERP’s real history and calculates cost and margin with staff rates, so whoever prepares the quote can see whether the job is profitable before sending it.
And more
An AI office suite (emails, summaries, analysis of tender documents, contract review and invoice extraction) and the company’s first route optimiser, which became RouteOpt.
What I take away
In a real company the hard part isn’t the model. It’s making the input data reliable (addresses, names, versions of the same document) and making the system say “I don’t know” rather than make things up.