One catalog and two designs: an LLM that turns a shopper's request into a better query, and an agent that searches as one step of its own work, using a skill Vespa generates from the schema.
“Agentic search” is used for two different ideas, and they lead to different designs.
In the first, a person still does the searching. An LLM sits between the search box and the engine and turns what they type into a better query, or runs a few queries for them. This is search as the chatbot era imagined it, and it is judged like any search box: does the person get better results, and how long do they wait.
In the second, the user of search is an agent. It searches because the job it was given needs it: an assistant putting together a product comparison, a buying agent checking prices and ratings before it orders, a support agent looking up which parts fit a customer's device. Search is one of its tools, and one task can take many queries. What the agent needs from the search application is to know it well enough to write precise queries itself: the fields, how each one is matched, and the rank profiles with the inputs they take. Vespa serves exactly that as a skill generated from the schema (see agent-ready schemas). The skill exists for this second case.
The demo has a mode for each, on the same 3 million Amazon products. Planner is the first kind: one LLM call fills in a plan for one query. Agent is a small agent of the second kind. Its task is a shopping request, so that it fits behind a search box, but it learns the catalog from the same skill any other agent would read, and writes its own queries. Plain search sends the words straight to hybrid search with no LLM. The switch under the search box reruns the same request in another mode.
A shopper's request carries more than keywords. “Cheap wireless earbuds with great reviews” contains a text query (wireless earbuds), a price constraint (cheap) and a ranking preference (great reviews). Classic search treats all of it as text. Some requests go further: “the best robot vacuum in each price band” can't be answered by any single query, because the right categories and price ranges have to be found first.
The table compares the two modes per search, the way a search box is judged. That is the first kind's measure, and on time it favours the planner. For an agent working through a task, the LLM calls are part of work it is doing anyway, and each query it runs comes back in well under a second.
| Planner | Agent | |
|---|---|---|
| Built for | A person at a search box | An agent that searches as part of a task |
| Who writes the query | Vespa, from a plan the LLM fills in | The LLM, in YQL |
| LLM calls per search | One | One per step, usually three to six |
| Queries per search | One | Two to seven in our runs |
| What the LLM knows about the data | A paragraph in the planner config | A skill generated from the schema |
| Time per search in our runs | About 1.5 s | 9 to 23 s |
Planner mode runs a Vespa Searcher in an opt-in search chain. Before the query executes, the searcher asks an LLM for a constrained JSON plan — never free-form YQL:
{
"query": "wireless earbuds",
"rank_profile": "hybrid",
"filter": "+has_discount:true",
"range_filters": [{ "field": "stars", "min": 4.0 }],
"rank_features": { "query(w_rating)": 1.5 },
"reason": "Prioritizing discounted, highly rated items."
}The plan can rewrite the query text, pick a rank profile (hybrid, quality, trending or deals), add exact-match and range filters, and set boost weights such as query(w_rating). The searcher validates every field against a whitelist, applies the plan, re-embeds the rewritten text and lets the search run, all in one request. If the LLM times out or returns something invalid, the original query runs untouched: the planner fails open, so it can never break search. On this catalog it lifted judge-scored precision by 70 to 76% on constrained and vague queries while leaving plain keyword queries alone (see the evaluation page).
The price of that safety is a fixed shape. The planner is a translation layer: it can only express what the plan format has a slot for, and it gets one attempt, with no chance to look at the data first.
In agent mode the LLM drops the plan format and writes YQL, Vespa's query language, directly. It runs a query, reads the results and decides what to run next, putting independent queries in the same step so they run in parallel. When it has what it needs, it picks the products to show and says why. This is the loop any agent runs when it uses Vespa as a tool; here its task happens to be a shopping request.
An agent that writes queries has to know the data: which fields exist, how they match, which rank profiles take which inputs. Here that knowledge comes from the schema itself. Each field and rank profile in the Vespa schema carries a short explanation, written next to the definition it describes:
field price_band type string {
explanation: Price bucket: `budget` (under $20), `mid` ($20-100), ...
indexing: summary | attribute
}
rank-profile hybrid inherits base_functions {
explanation {
The usual choice. Text relevance (bm25 on title) blended with semantic closeness, ...
@input query(w_rating) 0 to 2. Boosts rating weighted by review count, ...
}
...
}Vespa turns the deployed schema into an agent skill, a markdown document served at /skills/v1/schemas/ap_product next to the search API. It lists every field with its type and how it is matched, every rank profile with its inputs, and the explanations. Because it is generated from what is actually deployed, it can't drift from the schema. The demo adds a handful of example queries, and the agent reads the result before writing its first query. The trace shows the full text it read.
Nothing in the skill is specific to this demo's agent. Any agent that can reach the application's endpoint can be pointed at /skills/v1/schemas and learn to query it the same way, without anyone writing a prompt about the data for it. The planner has no equivalent: what its LLM knows about the catalog is a paragraph someone wrote into its configuration.
One run of “the best robot vacuum in each price band”, abridged from the trace:
1 read the schema skill
2 group robot vacuums by category
→ "Vacuum Cleaners & Floor Care", "Vacuums & Floor Care",
"Smart Home: Vacuums and Mops", ...
3 best 3 per price band in those categories, 4+ stars
→ accessories are crowding out the cheaper bands
4 three queries in parallel over price ranges, excluding
replacement parts, filters, brushes and bags
5 two more: real units under $60, and the luxury band
6 answer: 10 products, best first in each bandNo single query could have produced this. The agent didn't know the category names or that accessories would swamp the results until earlier queries showed it. That took 7 queries and 20 seconds. In another run it wrote not where YQL wants !, got Vespa's parse error back, and fixed the query on the next step.
The right side of the demo shows the agent's work live: its short notes, the skill, and each YQL query streaming in as the LLM writes it, followed by the match count and a preview of the hits or groups. A query starts as soon as the LLM finishes writing it, so results come back while the next query is still being written.
The loop runs in the demo's backend, which enforces the limits whatever the LLM asks for. Queries must select from the product catalog, with at most 20 hits, a 3-second timeout and bounded groupings. Each search gets a fixed number of steps and queries per step, a token budget and a time limit. The final answer can only contain products a query actually returned, so the agent can't invent one.
That depends on who is searching. If people search and you want the search box to understand their requests, the planner fits: it adds about a second and a half, fails open, and its plan is easy to inspect. If agents are the ones searching, give them the skill and let them write their own queries, as agent mode does.
Judged as a search box, agent mode is the slower of the two, but that is not what it is for. It can explore before it commits, compare, look at the data from several angles at once, and find out things about the catalog that nobody put in a prompt. Both designs rely on the same thing in Vespa: filters, groupings, rank profiles and their inputs, exposed through one query API.
Run “the best robot vacuum in each price band” in Agent mode and watch the trace, then switch to Planner and Plain search to see what one query can do with the same words. For a request the planner handles well, try “leather wallet for men under $25”: unplanned, the $25 is just text; planned, it becomes a real price filter.