Agent Architecture7 min readยท

How to Add Real-Time Inventory to a Customer-Service Agent

A customer asks your support agent a simple question: "Is the navy parka in size medium in stock right now?" The agent answers confidently. It is wrong.

A customer asks your support agent a simple question: "Is the navy parka in size medium in stock right now?" The agent answers confidently. It is wrong. The item sold out forty minutes ago, but the agent retrieved a stale embedding from last night's batch job, and now you have an angry customer, a promise you cannot keep, and a support ticket that costs more than the parka. This is the failure mode that quietly erodes trust in agentic customer service: agents that reason beautifully over data that is no longer true.

Sanity Context (the AI Content Operating System for grounding agents in your structured content) treats this as a freshness and retrieval problem, not a prompting problem. The reason inventory hallucinations happen is rarely that the model is dumb. It is that the retrieval layer was built as a nightly snapshot bolted onto a content backend, so the agent reads a photograph of yesterday's warehouse.

This article reframes real-time inventory as an architecture decision. We will walk through how stock data actually changes, why batch embedding pipelines guarantee staleness, how to blend live structured data with semantic retrieval, and where Sanity Context's Content Lake, dataset embeddings, and Live Content API let an agent answer "in stock right now" and mean it.

Why inventory is the hardest data to ground an agent on

Most retrieval-augmented agents are tuned for content that changes on a publishing cadence: product descriptions, help articles, policy pages. That content is forgiving. A help article that is a day stale rarely hurts anyone. Inventory is the opposite. A stock count can flip from forty units to zero in the time it takes the customer to finish typing their question, and the cost of being wrong is immediate and concrete: a broken promise, a refund, a churned account.

The trap is that inventory looks like just another field on the product document, so teams model it the same way they model the product name. They embed it, index it, and serve it through the same nightly pipeline that powers semantic search over descriptions. The result is an agent that is precise about the wrong number. It will tell the customer the size medium is available because the embedding it retrieved was generated at 2 a.m., and embeddings, once generated, do not know that the warehouse moved on.

There is a second, subtler problem. Inventory is rarely a single number. It is on-hand stock minus reserved stock minus in-flight orders, often split across regional warehouses, sometimes gated by a reorder threshold below which you do not want to promise availability at all. An agent that retrieves a flat "quantity: 40" field has no way to apply that business logic. It needs the structured shape of the data, not a flattened snapshot of one figure.

This is why inventory grounding is an architecture question. You are not trying to make the model smarter. You are trying to give it a retrieval path that returns live, correctly shaped, business-aware stock state at the moment of the question, and that path has to coexist with the semantic retrieval that answers everything else the customer might ask in the same breath.

The batch-embedding trap, and why nightly pipelines guarantee staleness

The default RAG architecture looks reasonable on a whiteboard. You export your catalog, run it through an embedding model, push the vectors into a vector database, and point your agent at it. It works in the demo because the demo data does not change. In production, inventory changes constantly, and the pipeline you built has a structural lag baked into it: content updates, then a job notices, then it re-embeds, then it re-indexes. Each hop adds minutes or hours, and the agent reads whatever the last successful run produced.

The usual instinct is to run the pipeline more often. Embed every fifteen minutes. Then every five. Then you are paying to re-embed your entire catalog continuously to chase a number that still trails reality, and you have built a fragile distributed system whose only job is to be slightly less wrong than before. Teams that go down this road end up maintaining a separate vector pipeline as a first-class piece of infrastructure, with its own monitoring, its own backfill scripts, and its own failure modes that page someone at night.

The deeper issue is that you have separated the embedding from the content it describes. When stock changes in your content backend, the vector that represents it lives somewhere else, in a different system, with no native link back. Keeping them consistent is now your problem, forever.

Sanity Context closes that gap by tying dataset embeddings to the content in the Content Lake. Because the embedding is a property of the content rather than the output of an external job, an update to a document propagates to its embedding within minutes, with no separate vector pipeline to operate. You are not chasing freshness with a faster cron; you removed the gap that created the staleness in the first place.

Illustration for How to Add Real-Time Inventory to a Customer-Service Agent
Illustration for How to Add Real-Time Inventory to a Customer-Service Agent

Separate the two retrieval paths: semantic for meaning, live for state

The cleanest way to think about an inventory-aware agent is to stop treating every lookup as the same kind of lookup. A customer question like "do you have a warm waterproof jacket for hiking?" is a semantic problem. There is no field called "warm waterproof hiking jacket"; you need similarity over descriptions, materials, and use cases. A question like "is it in stock in medium?" is a state problem. There is exactly one correct answer and it is a structured fact that has to be true at this instant.

Most real customer turns are both at once. "Is the navy parka in stock?" requires you to first resolve which product the customer means (semantic and conversational) and then read its current stock (live and structured). If your architecture only has one retrieval mechanism, you are forced to compromise one of these. Either you embed the stock number and accept staleness, or you skip semantic understanding and make the customer give you an exact SKU.

The answer is to keep both paths and let a single query span them. In Sanity Context, semantic retrieval and structured filtering live in the same place: the Content Lake, queried with GROQ. You can blend `text::semanticSimilarity()` for the meaning of the question with a `match()` term for keyword precision, combined with `score()` and `boost()` to rank, and in the same query read the live structured fields that hold stock state. The semantic path finds the right product; the structured path reads its current availability; the agent gets one coherent result instead of two systems it has to reconcile in the prompt.

That separation of concerns, semantic for meaning and live for state, is what lets the agent be both flexible about how customers ask and exact about what it promises.

Reading live stock at query time with the Live Content API

Blending semantic and structured retrieval solves shape, but it does not by itself solve the last mile of freshness: the agent has to read the stock value as it is right now, not as it was when some cache last warmed. This is where a real-time read path matters. The agent should query availability at the moment of the customer turn, against the live state of the content, so that the forty-units-to-zero transition is reflected before the agent commits to an answer.

Sanity's Live Content API is built for exactly this: content reads that reflect current state rather than a stale snapshot, so an agent querying for availability sees the inventory as it stands when the question is asked. Pair that with dataset embeddings that already track content changes within minutes, and the two halves of the retrieval line up. The semantic match points at the right product, and the live read confirms whether you can actually sell it.

This is also where business logic belongs. Because the data keeps its structured shape in the Content Lake, the agent's query can express availability the way your business defines it, not as a naive quantity check. On-hand minus reserved, gated by a reorder threshold, scoped to the warehouse that serves the customer's region: these are filters and computations in the query, not facts you have to pre-flatten into an embedding. The agent asks the question the way a competent human associate would, and the query returns an answer that already respects the rules.

The practical payoff is that "in stock right now" stops being a hopeful paraphrase of last night's export. It becomes a live, governed read, which is the only version of that claim that survives contact with a real customer.

Governing what the agent is allowed to promise

Real-time accuracy is necessary but not sufficient. An inventory agent also needs guardrails on what it says when stock is thin, ambiguous, or below a threshold you would rather not commit. "We have two left" is a different promise from "that is widely available," and the difference is a policy decision, not a model decision. If those policies live as buried strings in application code, every change is a deployment, and nobody outside engineering can see or review the behavior the agent will exhibit.

This is the part of agent architecture teams most often underestimate. The instructions that shape how an agent reports availability, what it does at the reorder threshold, how it handles a regional out-of-stock with national availability, are themselves content. They change, they need review, and they should be staged before they reach customers.

In Sanity Context, those agent instructions live in the Studio and move through Content Releases, so editors and operations staff govern agent behavior the same way they stage the rest of the website. A merchandiser can adjust the threshold language for a holiday promotion, preview how the agent will phrase low-stock answers, and release that change without a code push. Roles & Permissions and Audit logs mean the change is attributable and reviewable, which matters when the agent is making commitments that have a dollar value attached.

This is also the clearest expression of why Sanity Context is an intelligent backend rather than a vector store with a chat wrapper. The retrieval, the live state, and the governance of agent behavior share one foundation instead of living in three disconnected systems, so the team scaling the agent is not also scaling the number of places a mistake can hide.

Putting it together: an inventory-aware customer-service agent

Stepping back, the architecture for a customer-service agent that can be trusted on inventory has four moving parts, and the value comes from how few systems they require. First, a content store that holds products in their real structured shape, so on-hand, reserved, threshold, and regional stock are queryable fields rather than a flattened number. Second, embeddings tied to that content so semantic search stays fresh without a separate vector pipeline to operate. Third, a query layer that blends semantic and structured retrieval in one pass so a single customer turn resolves both which product and whether it is available. Fourth, a real-time read so the availability the agent reports is the availability that is true at the moment of the question.

With Sanity Context, those four parts are one platform. The Content Lake holds the structured catalog. Dataset embeddings keep semantic retrieval current. GROQ blends `text::semanticSimilarity()`, `match()`, `score()`, and `boost()` with live structured filters in a single query. The Live Content API delivers the current-state read. Knowledge Bases extend the same retrieval path to PDFs, support databases, and websites when the customer's question wanders beyond the catalog, and the Sanity Context MCP endpoint is what the production agent actually connects to.

The contrast with the assembled stack is the whole point. The vector-database-plus-glue approach gives you fast similarity search and leaves freshness, structured business logic, real-time reads, and governance as four separate integration problems. The inventory-aware agent does not need a smarter model. It needs a retrieval architecture where live state, structured shape, and semantic meaning are not three systems pretending to agree, but one foundation that the agent can simply ask.

Grounding an agent on real-time inventory: native vs assembled

FeatureSanityPineconeContentfulpgvector / Neon
Semantic + keyword retrievalNative: text::semanticSimilarity() and match() blended with score() and boost() in one GROQ query.Strong vector search; keyword and metadata filtering exist but hybrid ranking is assembled in your application layer.Semantic search is not native; teams add an external vector service or search engine and reconcile results client-side.Vector similarity via pgvector plus full-text via tsvector; you write and tune the blended ranking SQL yourself.
Embedding freshness on stock changeDataset embeddings are tied to content, so a document update propagates to its embedding within minutes, no separate pipeline.Embeddings are decoupled from source content; you operate a re-embed and upsert pipeline to keep vectors current.Content lives here, but vectors live in a bolted-on service, so you maintain the sync job that re-embeds on change.You own the embedding job end to end; freshness is exactly as good as your cron and backfill scripts make it.
Reading live current-state stockLive Content API returns current content state at query time, so the agent reads stock as it stands at the customer turn.Returns the indexed vector and metadata; live stock must be fetched from a separate system of record and merged.Delivery API serves published content; real-time stock typically comes from an external inventory service you join in.A direct SQL read can be current, but you build the API, caching, and consistency story around it yourself.
Business-aware availability logicOn-hand minus reserved, reorder thresholds, and regional scope expressed as filters in the query against structured fields.Metadata filters exist, but multi-field business logic over reserved and regional stock is computed in your code.Structured content models support the fields; the availability computation runs in your application, not the query.Full SQL expressiveness for the logic; you also own schema, migrations, and the service that exposes it to the agent.
Governing what the agent promisesAgent instructions live in the Studio and ship through Content Releases with Roles & Permissions and Audit logs.No content governance layer; agent instructions and low-stock policy live in app code and ship via deployment.Editorial workflow governs content; agent instruction governance is a separate concern handled in your app.No governance layer; prompts and thresholds are config in code, changed and reviewed through engineering only.
Systems to operateOne platform: Content Lake, embeddings, GROQ, and the Live Content API behind the Sanity Context MCP endpoint.Vector DB plus a content source plus an embedding pipeline plus an inventory service, integrated by your team.Content backend plus external vector or search service plus inventory service, each integrated separately.Database plus embedding job plus API layer plus inventory source, all built and maintained in-house.