Back to Learn
ArticleBusiness· September 22, 2026

The AI Concierge Isn't the Hard Part

Everyone wants an AI concierge on their site. Most can't support one — not because the facts are missing, but because they're stored in a shape only a rendering plugin can use. The four ways legacy data defeats an AI agent, and why grounding is a schema problem long before it's a prompting one.

Streamlining data into a meaningful outcome

A tool-calling agent is a few hundred lines of code. Whether it is useful or a confident liar is decided earlier, by whether your site's data can answer a question at all — and on most existing sites, it can't.

Everyone wants a concierge. Most sites can't support one.

The pitch is easy to say out loud. A visitor lands on the site at 11pm and asks: "what do you have under $450k with three bedrooms that I could actually move into this spring?" They get a real answer instead of a contact form.


The technology for that part stopped being interesting a while ago. A tool-calling loop over a capable model, a streaming endpoint, a chat widget — that is an ordinary week of work. What decides whether the result is useful is something much less glamorous: whether the data behind the website can answer the question at all.


On most established sites it cannot. Not because the facts are missing — they are right there on the page, and a human reading it does fine — but because they are stored in a shape that only the rendering plugin can use. The page is the only place the truth is assembled. Everything underneath it is fragments held together by presentation logic.


Point an assistant at that and it will fill the gaps the way language models fill gaps: fluently, and wrong.

Four ways a legacy site defeats an agent

1. The entities aren't entities. A content plugin will happily model your domain as tags. The floorplan a buyer asks about isn't an object with beds, baths, square footage and a collection — it's a taxonomy term attached to a post. The neighborhood isn't a place with amenities and a location — it's a label used to filter a grid. So "which of your communities have a pool?" has no query behind it, because a community is not a thing that can have a pool. It is a string used for grouping.


2. Fields mean something other than their name. Every long-lived site accumulates these. A "Status" field that renders the neighborhood name, because the plugin had no neighborhood field and someone needed one. A "year remodeled" column quietly repurposed to hold the lot number. Staff learn the local dialect within a week and stop seeing it. An agent reads the label, believes it, and answers with total confidence. This is the failure mode that scares me most, because nothing looks broken.


3. The values are dirty and nothing rejects them. A 2,800 square-foot house listed with one bedroom. Near-duplicate records left behind by a redesign — the real page, the copy, and the copy of the copy. And the quiet one: blank fields. A price is blank because the home isn't priced yet, which every human reader correctly translates to "call us." A model may translate it to zero, or to free, or simply invent something plausible. A page that renders fine is not the same thing as data that computes.


4. There is no query layer at all. The inventory is reachable only through the plugin's own search widget, which builds its results in the browser out of markup. The site never queries its own data in a way a second consumer could reuse. So the only way to "give the AI your inventory" is to scrape your own front end — which means the assistant is reading a rendering of the truth, one step removed, and always a little stale.


There's a fifth worth naming: facts that exist only inside images and PDFs. Specs baked into a rendered floorplan graphic. A promotion whose actual terms live in a brochure. Humans can read those. Your agent can't, your structured data can't, and neither can the external AI assistants that increasingly decide whether you get mentioned at all.

What "grounded" actually demands

"Grounding" gets discussed as a prompting technique. It isn't. It's a data requirement, and it's specific. For every claim your assistant might make, there has to be:

  • A first-class record with a stable identifier. A row, not a tag. Something the agent can fetch again next turn and get the same thing.
  • Typed fields with honest names. The lot number lives in a field called lot number.
  • A canonical display form for anything ambiguous. Price is the classic case: the agent should never have to decide how to phrase a home that isn't priced yet. The data should hand it the exact words.
  • A real filter for every judgment you don't want the model making. "Move-in ready within 30 days" should be a query parameter, not something inferred from a status badge.
  • Live reads at answer time. Not a vector index refreshed nightly. Availability and price change; an assistant quoting yesterday's snapshot is a liability, not a feature.
  • One query layer shared with the website itself. So the page and the assistant cannot disagree about what's for sale.


That last one is the quiet requirement, and it's the one bolt-on architectures always fail. If the chatbot has its own copy of the data, you now have two inventories, and one of them is wrong.

The cleanup is the project

The order matters, and it is not the order people want. Re-model, then clean on the way in, then build one query layer — and only then wire up the model.


Model the real entities. The physical home, the floorplan, the community: proper objects with typed fields and real relationships, not taxonomy terms doing three jobs each. Expect to find the same concept existing twice in the old system — a floorplan as a content page for marketing, and a floorplan as a tag used to classify listings, with names that drifted apart years ago. Reconcile them into one thing with one identity.


Clean on the way in, not on the way out. Migration is the single moment when someone is looking at every record. Spend it. Resolve slug collisions deterministically, split addresses that ran the city onto the end with no delimiter, fix the fields that hold an internal ID where a name belongs, correct the mislabels, flag the impossible values. Do it in a rerunnable import script that records what it decided, not by hand in an admin panel. A cleanup you perform at read time is one you perform forever, and the agent will find the case you forgot.


Turn absences into values. Blank is the most dangerous cell in an AI-facing dataset, because it invites the model to fill it. "Not priced yet" becomes an explicit qualifier that the listing card, the detail page, the structured data and the agent all render identically.


Reconcile your counts to a number you can defend. We found the real property count was 68 — 63 published, 4 private, 1 draft — where the working number had been 59. If you can't say how many homes you have and why, your agent certainly can't.


Then build the query layer once. Search with facets, detail lookups, filters, the payment estimator. Server-side functions that the website's own pages call. This is the part that makes the AI work later, and it is worth building even if you never add an assistant at all.

Then the agent gets boring, which is the point

Once that exists, the AI layer is thin. The tool surface is the site's own query functions with validated inputs bolted on: search homes, get a home, list communities, get a community, list floorplans, get active promotions, estimate a payment, search the FAQs. The agent has no other reach. If a tool didn't return it, it doesn't exist.


Here's the part worth internalizing. Clean data is what lets you write prompt rules that are actually followable. Compare:

  • "Don't hallucinate prices." — a plea.
  • "Prices arrive from the tools already formatted for display. Use that string exactly. Never compute one, estimate a range, or turn 'Request Details' into a number." — an instruction the data makes possible.

The same shape repeats everywhere once the affordances exist:

  • Readiness: never judge whether a home is a 30-day move-in by reading its status — pass the timeframe filter and answer from the filtered result. You can only write that rule because the filter exists.
  • Arithmetic: the agent is forbidden to compute a monthly payment. It calls the same estimator the site's own payment card uses, and relays the same disclaimer. One source of math, one answer.
  • Eligibility: a promotion carries an explicit list of eligible homes, so the agent checks membership instead of reasoning about it — and where the list is silent, it is told to say "let me have someone confirm" rather than declaring a home ineligible. Bounded uncertainty beats a confident guess.
  • Freshness: availability is re-read each time it matters, so the model can be told not to trust its own earlier turn.


Every hallucination class you can name gets closed by a data affordance rather than a sterner paragraph. A large share of what gets called prompt engineering is really schema engineering wearing a different hat.

The payoff isn't only the concierge

The clean layer that makes the assistant honest turns out to be what several other things were waiting on:


  • Machine-readable listings. The same typed records emit structured data on every page. Your inventory becomes legible to search engines and to other companies' AI assistants for exactly the same reason it became legible to yours. One cleanup, two audiences.
  • Lead capture that isn't a blob of text. Because preferences are typed — budget, bedrooms, baths, community, timeline — a conversation produces a structured record, not a transcript someone has to read and re-key.
  • Proactive matching. A scheduled job can match new inventory against waiting buyers only if both sides are queryable. "A home just came up that fits what you told us" is a data join, not an AI feature.
  • A map of your own content gaps. Log every question the assistant couldn't answer confidently, strip the personal details, cluster them. That list tells you exactly what to write next — and what you write feeds back into grounding, so the assistant gets better without anyone touching the model.


None of those are chatbot features. They are data-model features that look like AI features once the data is true.

Before you wire up the model

If you're about to add an assistant to an existing site, run these first.

  1. Ask your own site one hard question and try to answer it with a query, not a page. "Which of our X have Y, under Z, available within 30 days?" If you can't express it as a query, an agent can't answer it — and no prompt will fix that.
  2. Write down your repurposed fields. Every team has them. The list is embarrassing and it takes twenty minutes. Do it before the migration, not during.
  3. Decide what each missing value means, and encode that meaning. Blank is not a value. "Not yet priced" is.
  4. Build the query layer for the website first. If your own pages don't use it, your agent shouldn't either. Shared code is what keeps the two from drifting apart.
  5. Then wire the model — and write its rules in terms of affordances. Filters, canonical strings, explicit lists. Not good intentions.
  6. Give it an honest exit. "I'll have someone confirm that" is a correct answer. A grounded assistant that hands off gracefully beats a fluent one that guesses, every time — and buyers can tell the difference immediately.


The concierge we ended up with is genuinely good. It answers real questions about real inventory, captures what it learns as structured preferences, and knows where its knowledge stops. But the intelligence didn't come from the model, the framework, or the prompt. It came from the unglamorous months spent making the data true.

The AI was the last ten percent. The other ninety was work that needed doing anyway.

In practice

Related case study

Got a project, a problem, or an idea worth building?

Let's talk