> ## Documentation Index
> Fetch the complete documentation index at: https://docs.awardee.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Retrieval preview

> See exactly which knowledge a chatbot would retrieve for a question, and why every other candidate was dropped. Read-only.

When a visitor asks a chatbot a question, the chatbot searches its knowledge and hands the best **chunks** (pieces of articles) to the model. `POST /chatbots/{id}/retrieval-preview` runs that same search for a question you supply and returns the full account: the chunks that were selected, every candidate that was dropped, the reason for each drop, and the scores behind it.

Nothing is recorded. No conversation is started, no answer is generated, and no credits are used. Use it to test how article changes affect retrieval before you publish them, or to diagnose why a chatbot answered from the wrong article.

## How the search works

Each stage narrows the candidates. The `outcome` on every candidate tells you which stage stopped it.

**1. Search**

Two searches run in parallel over the knowledge the chatbot can use: one by meaning (vector search) and one by keywords (full-text search). Their results are merged into up to 30 candidates, each with a `fused_score`.

**2. Rerank**

A reranking model scores every candidate against the question and keeps the top 20. Candidates outside the top 20 are dropped with outcome `below_rerank_cutoff`.

**3. Remove near-duplicates**

Chunks whose text is near-verbatim copies of a higher-ranked chunk are dropped with outcome `near_duplicate`. Similarity is measured on overlapping five-word sequences across the **whole chunk**, and a chunk is dropped at `0.7` or above. `duplicate_of` names the chunk that was kept.

**4. Select for relevance and variety**

The final five are chosen to be relevant without repeating each other in meaning. A chunk that scored higher than a selected chunk but was passed over because it said much the same thing gets outcome `diversity`. Everything else gets `lower_score`.

> [!NOTE]
>
> When there are 20 or fewer candidates, reranking is skipped, and so are the
> near-duplicate and variety steps (`reranked` is `false`). The top five by
> `fused_score` are selected.

## Making a request

```bash cURL theme={null}
curl https://api.awardee.com/v1/chatbots/0ece9570-720b-4616-a3be-e7992dc54a1f/retrieval-preview \
  -X POST \
  -H "Authorization: Bearer aw_live_4f8a3c7e2d1b9a5c6f8e3d2c1b4a9f7e" \
  -H "Content-Type: application/json" \
  -d '{ "query": "How do I clean the basket?" }'
```

```javascript JavaScript theme={null}
const res = await fetch(
  `https://api.awardee.com/v1/chatbots/${CHATBOT_ID}/retrieval-preview`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ query: "How do I clean the basket?" }),
  },
)
const preview = await res.json()
```

```python Python theme={null}
import requests

preview = requests.post(
    f"https://api.awardee.com/v1/chatbots/{CHATBOT_ID}/retrieval-preview",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json",
    },
    json={"query": "How do I clean the basket?"},
).json()
```

**query** `string` *required*

The question, up to 2,000 characters. It is searched exactly as written. In a
real conversation, a follow-up such as "and the lid?" is first rewritten into
a complete question, so write complete questions here.

**folder\_id** `string | null`

Search only this folder and its sub-folders. This is what the chatbot does
when it narrows its own search to one folder.

**language** `string | null`

Search only chunks in this language. Omit it to search all languages, as a
conversation does.

**qr\_code\_id** `string | null`

Search as if a visitor had just scanned this QR code: the chatbot's own
knowledge plus the knowledge linked to the code and to its group. The code
(or its group) must send visitors to this chatbot and be active, as in a real
scan; otherwise it is ignored and `scan_applied` is `false`.

**product\_id** `string | null`

The same as `qr_code_id`, for a product scanned through a GS1 Digital Link.

**object\_id** `string | null`

The same as `qr_code_id`, for an object.

The chatbot must have access to the knowledge you want to test, either directly or through the scan you pass. If the articles aren't connected to either, they won't appear in the results.

> [!NOTE]
>
> A QR group can't be passed on its own. To test a group's knowledge, pass the
> id of any QR code in the group: the code brings its group's knowledge with
> it, plus anything linked to the code itself.

## The response

```json theme={null}
{
  "query": "How do I clean the basket?",
  "folder_id": null,
  "language": null,
  "qr_code_id": null,
  "product_id": null,
  "object_id": null,
  "scan_applied": null,
  "reranked": true,
  "rerank_provider": "jina",
  "mmr_lambda": 0.7,
  "counts": {
    "vector_hits": 30,
    "fulltext_hits": 15,
    "candidates": 30,
    "selected": 5
  },
  "selected": [
    {
      "outcome": "selected",
      "rank": 1,
      "article_id": "2f6c1a9e-7b3d-4c8e-9a1f-5d2b7e4c3a10",
      "article_title": "Cleaning and Storage",
      "article_url": "https://help.example.com/kb/cleaning-and-storage",
      "chunk_index": 1,
      "language": "en",
      "text": "Cleaning\n\nWarning: Let the basket, pan, and inside of the appliance cool down...",
      "fused_score": 0.0312,
      "rerank_score": 0.307,
      "duplicate_of": null,
      "similarity": null,
      "scan_linked": false
    }
  ],
  "dropped": [
    {
      "outcome": "near_duplicate",
      "rank": null,
      "article_id": "9a4e2c7b-1d5f-4b8a-8c3e-6f1a2b9d7e45",
      "article_title": "Quick Start Guide",
      "article_url": "https://help.example.com/kb/quick-start-guide",
      "chunk_index": 4,
      "language": "en",
      "text": "Cleaning Steps\n\n- Press the power On/Off button to switch off the appliance...",
      "fused_score": 0.0164,
      "rerank_score": 0.188,
      "duplicate_of": {
        "article_id": "2f6c1a9e-7b3d-4c8e-9a1f-5d2b7e4c3a10",
        "chunk_index": 2
      },
      "similarity": 0.86,
      "scan_linked": false
    }
  ],
  "served_context": "<knowledge_base>\n<source title=\"Cleaning and Storage\" url=\"...\">\n...\n</source>\n</knowledge_base>",
  "tool_result": "Found 5 relevant results:\n\n[1] Cleaning and Storage (https://...)\nCleaning...",
  "scan_item_note": null
}
```

**selected** `array` *required*

The chunks the model would receive, in rank order.

**dropped** `array` *required*

Every other candidate, in the order the first search ranked them, with its
`outcome`: `below_rerank_cutoff`, `near_duplicate`, `diversity` or
`lower_score`.

**rerank\_score** `number | null`

How relevant the reranking model judged the chunk to the question. Compare it
between chunks of the same response; the absolute value has no fixed meaning.
`null` when the chunk didn't reach reranking or reranking was skipped.

**served\_context** `string` *required*

The exact knowledge text the model would read when the chatbot searches
automatically. Short selected chunks are joined by the sections either side of
them in the same article, so this can contain more than the selected chunks.

**tool\_result** `string | null`

What the model receives when it runs its own follow-up search for the same
question. Each selected chunk is cut to its **first 800 characters**, so
anything later in a chunk is not visible this way.

**scan\_applied** `boolean | null`

`true` when the scan you passed sends visitors to this chatbot, so its
knowledge was searched. `false` when it was ignored. `null` when you passed no
scan.

**scan\_linked** `boolean`

On each chunk: `true` when the chunk was reached through the scan's linked
knowledge rather than only the chatbot's own. These chunks get a small
ranking boost.

**scan\_item\_note** `string | null`

When the scan links two or more folders and the selected chunks come from
more than one of them, the note the model reads above the results. It names
the folders and tells the model to ask which one the visitor means if they
are separate things (different machines, rooms or products) and the question
doesn't make it clear. Each source in `served_context` then carries
`folder="…"`, and each result in `tool_result` carries `[folder: …]`;
`tool_result` starts with the same note. `null` otherwise.

## Writing articles that retrieve well

> [!TIP]
>
> Pair this endpoint with [chunks](https://docs.awardee.com/articles/chunks.md) to see how an article is
> cut before you test how it is found.

* **Keep repeated warnings short, or state them once.** A long warning repeated at the top of every part of a section fills the start of each chunk. The parts then look alike to the search and compete for the same five places, and the model's follow-up search (`tool_result`) may show the warning without the steps after it.
* **A chunk is only dropped as a duplicate when nearly all of it is shared.** Two chunks that open with the same warning but contain different steps are both kept. In testing, a chunk was dropped only when the shared text made up about 92% or more of it.
* **Put the answer near the top of a section.** It then lands early in a chunk, inside the first 800 characters.

## Limits

Each preview runs a real search, so it is limited to **150 requests per minute per organization**, on top of your organization's general API rate limits. Over the limit, the API responds `429` with `retry_after` in seconds. Requires the `chatbots.view` scope.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.