Engineering

How we built Diamond: from a Python prototype to our own stack

The Ask Diamond button in the bottom right corner of the omgexp.com home page, circled and labelled.

A few months ago I wrote about how we built this website in-house by directing an AI. This is the sequel, and it has a different main character. It is the story of Diamond, the assistant in the corner of every page, and of Johnny, the person who built it.

The short version: the site worked, enquiries grew, and we needed a way to answer the same good questions at any hour without making anyone wait. Diamond is how we did that.

Meeting Johnny

I met Johnny at an industry event. We got talking about AI, and what stood out was not the buzzwords but the curiosity. He had already been building things on his own time and wanted to try them on a real business with real customers.

He has been working with us for the past few months, and Diamond is his first project with us. Johnny designed the assistant, built the first working version, and did the unglamorous part too: testing it against the questions our team actually gets every day. The same assistant now runs on the websites across our group of companies, not just this one.

The first version was Python

Johnny's prototype was written in Python. It was a small web service with a simple database for conversations, a knowledge base built from our website's pages, and a chat widget that could sit on any site.

The core idea was right from day one, and it is still the idea today. The assistant should never answer from general knowledge of the internet. It should find the passages on our own website that match the question, answer only from those, and show which pages it used. For an airline sales agent, a confident wrong answer about a fare or a visa is worse than no answer at all.

The prototype proved the idea. What it did not fit was the way the rest of our website runs. Everything else we operate is a static site plus a handful of small serverless functions on AWS, written in JavaScript. A separate Python server would have been one more thing to host, patch, monitor and pay for, all to run one feature.

Rebuilding it on our native stack

So we took Johnny's logic and rebuilt it as part of our own stack, using Claude Opus 5 inside Cursor, the same way we built the website. The prototype became the specification: its prompts, its retrieval rules and its widget behaviour were ported piece by piece into Node.js, then checked against the original.

The result is a single AWS Lambda function in Node.js 22. It sits behind the same API as our enquiry forms, stores conversations in DynamoDB next to our other data, and needs no server of its own. When nobody is chatting, it costs almost nothing. When traffic spikes, it scales without anyone touching it.

The port was also a chance to fix things. Rebuilding every piece with a careful reviewer surfaced a few retrieval quirks in the original: long overview pages sometimes outranked the page with the specific answer, and source references could get cut off. Those were fixed on the way across, and every fix now has an automated check so it cannot quietly come back.

How Diamond answers a question

Every time we publish the website, a build step reads every page, including the latest fares, flight times and travel articles, and turns it into a searchable index of short passages. Diamond's knowledge is therefore always exactly what the website says, no more and no less.

When a question comes in, Diamond ranks those passages with a keyword search that pays extra attention to headings, so a question about Paro flight times lands on the Paro schedule rather than a page that mentions Paro in passing. The best passages go to Google's Gemini model with strict instructions: answer only from these passages, in the visitor's language, and cite them. Any source the model names that was not actually retrieved is dropped before the answer reaches the screen.

Diamond answering a question about Paro flight times on a phone, with a See the sources link circled.
A real answer, taken from the Paro page. Every answer lists the pages it came from.

Guardrails and handing over

The rules Diamond follows are fixed in code, and nobody can edit them from the admin panel. It never invents fares, schedules or availability. It never claims a seat is held or a booking is made. It never asks for card numbers or passport details. It has no access to reservations, so anything about an existing booking goes straight to our team.

Knowing when to stop is the other half of the job. When a question needs a quote, involves a group, or goes beyond what the website covers, Diamond says so and offers a way through: a button to call our office, or a short form inside the chat. Those forms feed the same enquiry system as the rest of the site, so the team sees one conversation from start to finish, not two disconnected ones.

Diamond answering in Thai about holding a seat before paying, with buttons to call the office or ask the team to get in touch.
In Thai, on Book and Hold: the answer, then a call button and a contact form for the team to take over.

Diamond speaks Thai and English and answers in whichever language you use. Behind the scenes, our team can change its name, picture and opening line from the admin panel, switch it off entirely, and read every conversation with a short summary, which has quietly become one of our best sources of ideas for what the website should explain better.

What real phones taught us

As with the website, the lessons came from real devices. On a phone the chat opens full screen, and an early version reopened itself on every new page after you had minimised it. It now remembers your choice. Long lists of sources pushed the answer off the screen, so they now sit behind a single tap. Small things, but they are the difference between a helper and an interruption.

What I would tell you

Diamond is not impressive because it uses AI. Everyone uses AI now. It is useful because it is narrow: it only knows what we publish, it shows its sources, and it knows when to hand over to a person. That discipline started with Johnny's prototype, and rebuilding it on our own stack made it something we can run for years.

And if you would rather talk to a person, you still can. Diamond is named after a real member of our team, and he is at our office. Call us on +66 2 630 4600.

To try it, open any page and look for Ask Diamond in the bottom right corner. To read how the website itself was made, see how we built this site.