{
  "schema_version": 2,
  "id": "develop/ai/context-engine/intent-router/concepts",
  "title": "Redis Intent Router concepts",
  "url": "https://redis.io/docs/latest/develop/ai/context-engine/intent-router/concepts/",
  "summary": "Understand Routers, intents, examples, targets, scores, and access grants.",
  "tags": [
    "docs",
    "develop",
    "ai"
  ],
  "last_updated": "2026-10-27T19:49:54-07:00",
  "page_type": "content",
  "content_hash": "1b36bce744dde72b4c237e7188416314ecd03bfae0ffcb9beb46daa4cc0d440d",
  "sections": [
    {
      "id": "overview",
      "title": "Overview",
      "role": "overview",
      "text": "Intent Router classifies each incoming user message by matching it against example phrases you group into intents. This page explains the parts you work with and how they fit together, so the task pages make sense when you reach them.\n\nIt covers Routers, which hold a set of intents and control who can use them, and intents, with their examples, targets, and revisions. It then explains how matching scores a query, when a change takes effect, and which agent-key actions each operation needs."
    },
    {
      "id": "routers",
      "title": "Routers",
      "role": "content",
      "text": "A **Router** is the unit you create, configure, and secure. It holds a set of intents and their examples, an embedding model, and a default minimum score. Each Router has its own access grants, so use separate Routers for workloads that must not share intents.\n\nA Router has an opaque identifier that starts with `rtr_`. Its embedding model is fixed when you create it and can't change afterward, because every stored example is embedded with it.\n\nA Router is in one of these states:\n\n| State | Meaning |\n| ----- | ------- |\n| `PROVISIONING` | The data plane is building the Router's search index. Data requests return `409` until it is ready. |\n| `READY` | The Router serves requests. You can suspend or delete it. |\n| `FAILED` | Provisioning failed. `failureReason` explains why. A failed Router can only be deleted. |\n| `SUSPENDED` | An administrator paused the Router. Data requests return `423` until it is resumed to `READY`. |\n| `DELETING` | The data plane is removing the Router and its data. Data requests return `404`. |\n\nAdministrators manage Routers through the **control plane**. Applications use the **data plane** to author intents and match queries. The two planes don't call each other, and a Router serves only after the data plane has applied its current configuration. See [Manage Routers](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/manage-routers) to create one, and [service limits and errors](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/limits) for the errors a Router returns when it isn't serving."
    },
    {
      "id": "intents",
      "title": "Intents",
      "role": "content",
      "text": "An **intent** is a named classification. Its name is unique within the Router and can contain letters, digits, `.`, `_`, and `-`, starting with a letter or digit. An intent has:\n\n- **Examples**: phrasings that should match the intent.\n- A **description**: when the intent should win, in your words. Optional.\n- A **target**: what a match dispatches to. Optional.\n- A **minimum score**: how close a query must be for this intent to match. Optional.\n- **Metadata**: labels such as an owner or tags. Optional.\n\nAn intent without examples never matches.\n\nIntents and examples are ordered lists. Redis Intent Router returns them in the order you created them, not sorted by name."
    },
    {
      "id": "examples",
      "title": "Examples",
      "role": "example",
      "text": "An **example** is one phrasing of an intent, such as \"where is my order\" for `track_order`. Redis embeds each example when you write it.\n\nAdd several varied phrasings per intent. Matching compares a query with every example, so more varied examples cover more of the ways people ask. An example identifier starts with `exm_` and is derived from the text, so adding the same phrasing twice keeps one example."
    },
    {
      "id": "targets",
      "title": "Targets",
      "role": "content",
      "text": "A **target** tells your application what to do when an intent matches:\n\n| Field | Meaning |\n| ----- | ------- |\n| `type` | The dispatch mechanism, such as `tool`, `pipeline`, `handler`, `prompt`, or `agent`. The set is open: use any identifier without whitespace. |\n| `ref` | The callee within that type's namespace, such as `orders.track`. |\n| `args` | Optional dispatch arguments, as a JavaScript Object Notation (JSON) object. |\n\nThe Router checks that `args` is valid JSON and passes it through untouched. It knows how an intent is dispatched, never what the target does.\n\nMetadata is for descriptive labels. Put dispatch data in the target: metadata rejects the keys `type`, `ref`, `target`, and `args`."
    },
    {
      "id": "revisions",
      "title": "Revisions",
      "role": "content",
      "text": "Every intent has a `revision` that changes with every write to the intent, including a `PUT` that changes nothing. Adding or deleting examples through the example operations doesn't change it. Send the revision back as `expectedRevision` to make a write conditional: the write fails with `412 Precondition Failed` if someone else changed the intent first."
    },
    {
      "id": "matching",
      "title": "Matching",
      "role": "content",
      "text": "To **match** a query, Redis Intent Router embeds the text, finds the nearest examples in the Router's vector index (50 by default), and groups them by intent. By default an intent scores as its closest example, so one good example is enough for a match. Then it drops intents below their minimum score and returns the rest, best first.\n\nA score is 1 minus the cosine distance between the query and the example, kept between 0 and 1, and higher is closer. Every threshold in the API points the same way: **higher is stricter**.\n\nThe minimum score that applies to an intent, from highest to lowest precedence:\n\n1. The `minScore` in the match request.\n1. The intent's own `minScore`, when it is above `0`.\n1. The Router's `minScore`, which is `0.7` unless you set another.\n\nAn intent `minScore` of `0` means \"use the Router's\", never \"match everything\". Only the match request can lower the threshold to `0`.\n\nA query with no sufficiently close intent returns `200` with an empty list. That is a normal result, not an error.\n\nSee [Match queries](https://redis.io/docs/latest/develop/ai/context-engine/intent-router/match) to tune thresholds and result limits."
    },
    {
      "id": "authoring-and-consistency",
      "title": "Authoring and consistency",
      "role": "security",
      "text": "Writes keep matching available. When you replace an intent, Redis writes the new examples first and removes the old ones afterward, so a concurrent match never sees an empty intent. Writing the same intent twice produces the same intent, with a new `revision`.\n\nA write that adds several intents validates all of them first, and writes nothing if any is invalid."
    },
    {
      "id": "access",
      "title": "Access",
      "role": "content",
      "text": "Two credentials guard the service:\n\n- An **admin token** manages Routers on the control plane. Platform teams hold it.\n- An **agent key** authenticates an application's data-plane requests as a bearer token. It carries a grant for each Router it can use. Redis Iris issues agent keys through its Identity Service, not through the Intent Router API.\n\nA grant lists one or more actions on one Router. A key without the action an operation needs gets `403`.\n\n| Action | What it allows |\n| ------ | -------------- |\n| `read` | Match queries, read intents and examples, and check the Router's health. |\n| `write` | Create, change, and delete intents and examples, and clear the Router. Includes `read`. |\n| `full` | Includes `write`. No operation needs more than `write` today. |\n\nGrants apply to a whole Router. Don't rely on intent names or metadata to separate audiences. Use a separate Router instead."
    }
  ],
  "examples": []
}
