Gemma 4 Reads Vendor APIs: Building the Cheapest Flight Calendar for Travel Agencies

Using local Gemma 4 to auto-generate 13 vendor API mappings and Chronos-Bolt to fill blank dates, building a cheapest-fare flight calendar.
The article presents a live flight "cheapest-fare calendar" project: agents can see the lowest fare for each date before searching, reducing high-frequency queries to GDS and multiple vendors and lowering look-to-book costs. The system uses local Gemma 4 to automatically generate parsing mappings for 13 vendor response formats, successfully mapping 7 vendors and handwriting the rest; it uses Chronos-Bolt base combined with a day-of-week baseline to fill unsearched dates. Backtests show coverage rising from 36% to 41% and estimated-date error dropping from 18.7% to 16.2%, but the author also honestly reports a counterexample where the ensemble was worse on one subset. The project emphasizes the pattern of "the model proposes, code validates with real data," and how data sensitivity drove a localized, GPU-free tech stack.
There's a recurring scene in a travel agent's daily work: a customer asks over the phone, "Is Tuesday cheaper than Wednesday?" The agent has to send search requests one at a time, and each request fans out to 13 vendors simultaneously. It's slow, and it burns through vendor quota — the GDS look-to-book ratio is a real cost.
Developer adi-ray solved this problem with two open-source models: Gemma 4 parses responses from 13 different vendor API formats, and Chronos-Bolt fills in dates with no search history, ultimately producing a "which day is cheapest" flight calendar. The project was submitted to the Hacktoberfest Open-Source AI Challenge Week 2 (Side Hustle theme), and is already deployed to a real production environment, serving 557 routes and 23,626 priced dates.

The Problem: Every Search Burns Quota
This is a B2B flight booking portal where sub-agents can log in and search and book across 13 vendors — including GDS, low-cost carriers, NDC airlines, and wholesalers with fixed departure dates.
Watch what an agent does when they pick up the phone, and the pain point becomes obvious: ask about one date, run a search; ask about another date, run another search. Each search fans out to all vendors, which is slow for the customer and expensive for the platform.
Fare Calendar answers "which day is cheapest" before the agent even searches. It's a date picker that shows the lowest fare under each date. The information comes in two categories: "seen" with a solid dot means a real fare the agent actually retrieved within the past 3 days; "est." with a dashed underline means a model estimate, along with a possible range.
The entire system is built purely from the portal's own server logs, reflecting fares that its own vendors returned to its own agents — not results from public metasearch.
GDS (Global Distribution System) is an intermediary distribution network for travel products such as flights, hotels, and car rentals. Amadeus, Sabre, and Travelport are the three major players. Travel agencies and online booking platforms use GDS to aggregate inventory and prices from multiple vendors.
Look-to-book ratio is a core pricing mechanism of the GDS business model: vendors charge distributors based on "looks" (queries), not just "books" (completed orders), because each query consumes vendor real-time inventory computing resources. Typical look-to-book ratios in the industry can reach hundreds to one, meaning hundreds of searches produce just one booking. That means every time an agent probes dates repeatedly during a call, it creates a real vendor cost. Fare Calendar tries to reduce the frequency of this "exploratory searching," which directly targets that cost structure.
Core Idea: Let Gemma 4 Read Vendor APIs
Fares are buried in 13 different response formats: GDS SOAP XML, Navitaire XML, IATA NDC XML, and various JSON. Handwriting 13 parsers before the deadline wasn't realistic.
The developer's approach was to write a tiny mapping language that works for both JSON and XML, then have Gemma 4 write the mappings. Gemma sees only a trimmed sample of a given vendor's response.
The key point: what determines whether a mapping is good is the code, not Gemma. The code applies the mapping to 6 real responses and rejects it outright unless the following conditions are met: most responses produce data rows; the fare looks like a total per adult, not an ID or a base fare; and the route the agent actually searched appears.
Failure feedback is returned to Gemma in concrete form, for example: 'fareComponentList' doesn't exist under …originDestinationOptionList[*]; the keys there are ['fareComponentGroupList']. Did you mean 'fareComponentGroupList'?
The result: Gemma (local gemma4, 7.5B Q4, running via Ollama on a 4 GB laptop GPU) successfully mapped 7 vendors, with 1–6 attempts each. IndiGo, SpiceJet, and one NDC airline did not converge after 11 attempts, so they were handwritten and labeled as such.
Navitaire XML is the booking system response format that Navitaire (under Amadeus) provides to low-cost carriers. Its structure differs greatly from traditional GDS SOAP XML, with its own field naming and nesting hierarchy. NDC (New Distribution Capability) is an XML standard promoted by IATA, designed to let airlines bypass traditional GDS routes and deliver rich offers with ancillary services (baggage, seat selection) directly to agents. SOAP is an earlier XML-based web services protocol, and its responses are usually wrapped in multiple layers of envelopes.
The coexistence of these formats means the same "lowest fare" field might be called fareComponent, totalFare, amount, or be buried at different depths inside originDestinationOptionList depending on the vendor. Handwriting 13 parsers is not just time-consuming, but also requires maintenance every time a vendor tweaks their schema. Having a model generate mappings essentially automates the repetitive work of "understanding unfamiliar schemas," while code validation serves as the safety net.
Lessons from Making a 7.5B Small Model Work Reliably
Using a small model for production data processing came with more pitfalls than expected.
Turn off thinking mode. Gemma 4 enables thinking mode by default in Ollama. On the developer's GPU, this turns a 5-second answer into 58 seconds, and the answer is worse. Measured: with think=True, 58 seconds, 248 tokens, wrong answer; with think=False, 5 seconds, 9 tokens, correct answer.
Watch the context window. Ollama's default context silently truncates the beginning of long prompts, and that's exactly where the instructions are. All early failures looked like "Gemma ignored the spec," when in fact it never saw it.
Feedback must specify how to fix things. "Check your path" just makes the error repeat; "use ^^.segment.from" produces a corrected mapping.
Let the language compromise for the model. Gemma always writes field paths from the document root, so the extractor now automatically resolves those paths to the row's own ancestor node.
This pattern of "the model proposes a solution, and code validates it against real data" is the key to making a 7.5B model trustworthy enough to touch production data.
Chronos-Bolt Fills in the Blank Dates
Agents only search a handful of dates, so the rest need to be filled in. Filling in happens in three steps: first, a lead-time model separates "which day to fly" from "how far in advance to search," because fares rise closer to departure; then Chronos-Bolt base (open weights, zero-shot, runs on CPU) predicts a calendar for each unsearched interval, passing missing dates in as gaps rather than making them up; the predictions are averaged with a day-of-week baseline — the two make different errors, and the average beats either one alone.
Estimates are repriced using today's lead time and blended with that date's historical searches.
Chronos-Bolt is an open-weights time series foundation model released by Amazon. Based on the T5 architecture, it tokenizes numeric sequences and predicts future values in a manner similar to a language model. Zero-shot here means it doesn't need fine-tuning for a specific route or dataset; it predicts directly from the input historical sequence, so it can run on CPU without training a specialized model for each route.
Lead time refers to the number of days between the moment of search and the departure date. Flight pricing is highly sensitive to lead time — the same flight may differ by several times in price when searched three days before departure versus three months before. The "lead-time model" mentioned in the article first strips out this systematic upward pricing trend, leaving Chronos-Bolt responsible only for predicting the "remaining fluctuations," avoiding the model mistaking the simple rule "closer to departure means more expensive" for a calendar pattern. This is consistent with the detrending approach in traditional time series analysis.
Data Cleaning Accounts for Half the Work
Real data is far messier than expected. One wholesaler marked certain dates as ₹100 (seat pending confirmation), which in the "lowest fare" calendar meant it won every day, once pushing backtest error to 308%. Now fares below ₹500 and fares outside the 0.25×–4× range of the route median are discarded and counted.
Some carriers price connecting itineraries by segment, so a DEL→HYD→BOM search can masquerade as a cheap "DEL-HYD fare." The system keeps only the route actually searched. Some vendors also present "2 adults" as a single total, so only single-adult searches are used (85% of total traffic).
Backtest Results (The Honest Version)
The backtest used 14 cutoff dates (October 1–14). Calendars were built only from earlier logs, then compared against the lowest fares actual agents obtained over the following two days, covering 11,544 search dates.
| Seen fares only | Day-of-week baseline | Chronos-Bolt base + baseline | |
|---|---|---|---|
| Search dates showing a fare | 36% | 41% | 41% |
| Error when showing real recent fares | 1.0% | 1.0% | 1.0% |
| Error on estimated dates (591) | n/a | 18.7% | 16.2% |
When choosing a predictor on 5 cutoff dates and 498 estimated dates: day-of-week baseline 18.4%, Chronos-Bolt small alone 20.1%, Chronos-Bolt base alone 17.6%, small + baseline 17.9%, base + baseline 15.1%.
The calendar's value is mainly coverage: it gives agents numbers for 41% of the dates they will later search, up from 36%, while the "seen" fares are accurate. The estimates are rough, but measurably better than the obvious baseline — the Chronos-Bolt small used in the first deployment was actually worse than the simple "same day of week, recent weeks" baseline.
One honest caveat: on another 5-day subset containing only 63 estimated dates, the ensemble was actually slightly worse (20.3% vs 19.0%). This is one month of noisy historical data mixing GDS and fixed departure dates, and the backtest will keep being rerun as logs accumulate.
Why Open-Source Models Were the Only Viable Path
Data cannot leave. Vendor fares are negotiated prices, and vendor responses are trade secrets. Pasting them into a hosted LLM to "help write a parser" is simply not viable. Gemma 4 runs locally, and every vendor response stays on the laptop.
Zero cost per use. Mapping a vendor is a one-time job on a 4 GB laptop GPU. Forecasting across 557 routes takes a few minutes on CPU. The deployed API needs neither a GPU nor an AI vendor.
Model behavior can be changed. Turning off thinking, setting the context size, and forcing JSON output are all controllable switches. Closed APIs leave you guessing why answers degrade.
Swapping models is a one-line change. When Chronos-Bolt small lost to the baseline, the developer tried a model 4× larger that same afternoon, backtested 5 variants on real data, and shipped the winner at zero cost.
No lock-in. Mappings are pure JSON, the forecaster is configurable (FARECAL_FORECASTER, FARECAL_MODEL_ID), and Gemma can be replaced by any OpenAI-compatible local server.
On deployment, Chronos runs on the machine where the logs live and writes out a 565 KB forecasts.json; the API on Render uses FastAPI plus the standard library, with no PyTorch. One blueprint produces two services: a public demo (synthetic data, free plan) and a private service (Starter plus persistent disk, nightly forecast uploads, protected behind a signed session cookie after login, embeddable by the portal via API key).
Ollama is an open-source tool for running and managing local large models. It supports loading models in quantized formats (such as Q4, or 4-bit quantization) on consumer-grade GPUs and provides an OpenAI-compatible HTTP interface. Q4 quantization compresses a 7.5B model to run in about 4 GB of VRAM, at the cost of a slight loss in precision, but it remains usable for tasks like structured mapping.
"OpenAI-compatible local server" means application code only needs to change the base URL and model name to switch between backends such as Ollama, vLLM, and llama.cpp. This is exactly the no lock-in the article emphasizes: mapping results are pure JSON, the forecaster is configured via environment variables, and the model is replaceable, so no layer of the entire system depends on the continued availability or pricing of a single cloud provider. For teams that must handle trade-secret data locally, this replaceability is an architectural hard requirement, not a preference.
Implications for AI Application Development
This project isn't "a toy built with AI" — it's a case study that directly illustrates the real role of open-source models in production environments.
The core pattern is "model proposes, code validates": Gemma generates mappings, and code validates them against real responses and rejects unsatisfactory results. The model never touches runtime fare data. This solves the problem of small models being untrustworthy and lets a 7.5B-parameter model do practical work within 4 GB of VRAM.
Another point worth noting is that data sensitivity drove architectural choices. Negotiated vendor prices cannot leave the local environment, which directly determined the entire tech stack — local Gemma, local Chronos, CPU serving, no GPU dependency. For teams handling trade-secret data, this is a reusable reference architecture.
Finally, the backtest results themselves are worth learning from: the developer proactively reported the counterexample where the ensemble performed worse on a subset, rather than only showing the best-looking numbers. That level of honesty is not common in AI application marketing.
The project code is open source on GitHub (adi-ray/fare-calendar), including FastAPI, pandas, a dependency-free Web Component, and 60 tests. Real logs, fares, and private vendor mappings have been gitignored; the repository contains only synthetic data and public Amadeus mappings.
Related articles

uGAP: An AI Platform Unifying 100+ African Geospatial Datasets
uGAP is an African geospatial AI platform by a University of Cape Town team, unifying 120+ African datasets with a Python SDK for discovery, processing, and model training, already used in cyclone flood mapping.

Cursor Can Now Control Your Computer: AI Agents Can Drive Desktop Apps for Testing
Cursor adds desktop control: AI agents can drive desktop apps like the iOS Simulator to test their own features. We analyze the impact on dev workflows, possible technical approaches, and reliability concerns.

Vibecoding a Custom Inference Engine: High Hopes, Harsh Reality
A Reddit developer shares the real experience of vibecoding a custom inference engine: running GGUF Q4 models in the browser with WebGL2 and GLSL, only to fall into tokenizer debugging hell. This article analyzes the engineering challenges of browser-side LLM inference and why cloning llama.cpp is the more rational choice.