diff --git a/_ml-commons-plugin/agents-tools/tools/query-planning-tool.md b/_ml-commons-plugin/agents-tools/tools/query-planning-tool.md index ac035720e28..1bec951294d 100644 --- a/_ml-commons-plugin/agents-tools/tools/query-planning-tool.md +++ b/_ml-commons-plugin/agents-tools/tools/query-planning-tool.md @@ -14,20 +14,71 @@ grand_parent: Agents and tools {: .label .label-purple } -The `QueryPlanningTool` generates an OpenSearch query domain-specific language (DSL) query from a natural language question. It is a core component of [agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/), which enables natural language query processing through agent-driven workflows. +The `QueryPlanningTool` generates an OpenSearch query domain-specific language (DSL) query from a natural language question. It is a core component of [agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/index/), which enables natural language query processing through agent-driven workflows. The `QueryPlanningTool` supports two approaches for generating DSL queries from natural language questions: - **Using LLM knowledge only (default)**: The large language model (LLM) generates queries using only its training knowledge and any system/user prompts you provide. This approach relies entirely on the model's understanding of DSL syntax and your specific prompting instructions. -- **Using search templates**: The LLM uses predefined search templates as additional context when generating queries. You provide a collection of search templates with descriptions, and the LLM uses these as examples and guidance to create more accurate queries. If the LLM determines that none of the provided templates are suitable for the user's question, it falls back to a default `match_all` query. +- **Using search templates**: The LLM uses predefined search templates as additional context when generating queries. You provide a collection of search templates with descriptions, and the LLM uses these as examples and guidance to create more accurate queries. If the LLM determines that none of the provided templates are suitable for the user's question, the LLM attempts to generate the query independently. The `user_templates` approach is particularly useful when you have established query patterns for your specific use case or domain: it helps the LLM to generate queries that follow your preferred structure and to use appropriate field names from your index mappings. -## Step 1: Register and deploy a model +## Step 1: Create an index and ingest sample data + +First, create an index for the `iris` dataset: + +```json +PUT /iris-index +{ + "mappings": { + "properties": { + "petal_length_in_cm": { + "type": "float" + }, + "petal_width_in_cm": { + "type": "float" + }, + "sepal_length_in_cm": { + "type": "float" + }, + "sepal_width_in_cm": { + "type": "float" + }, + "species": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + } +} +``` +{% include copy-curl.html %} + +Next, ingest sample documents into the index: + +```json +POST _bulk +{ "index": { "_index": "iris-index", "_id": "1" } } +{ "petal_length_in_cm": 1.4, "petal_width_in_cm": 0.2, "sepal_length_in_cm": 5.1, "sepal_width_in_cm": 3.5, "species": "setosa" } +{ "index": { "_index": "iris-index", "_id": "2" } } +{ "petal_length_in_cm": 4.5, "petal_width_in_cm": 1.5, "sepal_length_in_cm": 6.4, "sepal_width_in_cm": 2.9, "species": "versicolor" } +{ "index": { "_index": "iris-index", "_id": "3" } } +{ "petal_length_in_cm": 6.0, "petal_width_in_cm": 2.5, "sepal_length_in_cm": 5.9, "sepal_width_in_cm": 3.0, "species": "virginica" } +``` +{% include copy-curl.html %} + +## Step 2: Register and deploy a model The following request registers a remote model from Amazon Bedrock and deploys it to your cluster. The API call creates the connector and model in one step. Replace the `region`, `access_key`, `secret_key`, and `session_token` with your own values. You can use any model that supports the `converse` API, such as [Anthropic Claude 4](https://www.anthropic.com/news/claude-4) or [GPT 5](https://openai.com/index/introducing-gpt-5). You can use other model providers by creating a connector to this model (see [Connector blueprints]({{site.url}}{{site.baseurl}}/ml-commons-plugin/remote-models/connectors/#connector-blueprints)). +**Important**: When creating connectors for the `QueryPlanningTool`, the request body must include the `system_prompt` and `user_prompt` parameters. These parameters are required for the tool to properly inject the system and user prompts into the model's request. + The following example registers and deploys the Anthropic Claude 4 model: ```json @@ -59,7 +110,7 @@ POST /_plugins/_ml/models/_register?deploy=true "headers": { "content-type": "application/json" }, - "request_body": """{ "system": [{"text": "${parameters.query_planner_system_prompt}"}], "messages": [{"role":"user","content":[{"text":"${parameters.query_planner_user_prompt}"}]}]}""" + "request_body": "{ \"system\": [{\"text\": \"${parameters.system_prompt}\"}], \"messages\": [${parameters._chat_history:-}{\"role\":\"user\",\"content\":[{\"text\":\"${parameters.user_prompt}\"}]}${parameters._interactions:-}]${parameters.tool_configs:-} }" } ] } @@ -70,35 +121,34 @@ POST /_plugins/_ml/models/_register?deploy=true The following example registers and deploys the OpenAI GPT 5 model: ```json -POST /_plugins/_ml/models/_register?deploy=true +POST /_plugins/_ml/models/_register { - "name": "My OpenAI model: gpt-5", - "function_name": "remote", - "description": "test model", - "connector": { - "name": "My openai connector: gpt-5", - "description": "The connector to openai chat model", - "version": 1, - "protocol": "http", - "parameters": { - "model": "gpt-5", - "response_filter": "$.choices[0].message.content" - }, - "credential": { - "openAI_key": "OPENAI KEY" - }, - "actions": [ - { - "action_type": "predict", - "method": "POST", - "url": "https://api.openai.com/v1/chat/completions", - "headers": { - "Authorization": "Bearer ${credential.openAI_key}" + "name": "My OpenAI model: gpt-5", + "function_name": "remote", + "description": "test model", + "connector": { + "name": "My openai connector: gpt-5", + "description": "The connector to openai chat model", + "version": 1, + "protocol": "http", + "parameters": { + "model": "gpt-5" }, - "request_body": """{ "model": "${parameters.model}", "messages": [{"role":"system","content":"${parameters.query_planner_system_prompt}"},{"role":"user","content":"${parameters.query_planner_user_prompt}"}], "reasoning_effort":"minimal"}""" - } - ] - } + "credential": { + "openAI_key": "your-openai-api-key" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions", + "headers": { + "Authorization": "Bearer ${credential.openAI_key}" + }, + "request_body": "{ \"model\": \"${parameters.model}\", \"messages\": [{\"role\":\"developer\",\"content\":\"${parameters.system_prompt}\"},${parameters._chat_history:-}{\"role\":\"user\",\"content\":\"${parameters.user_prompt}\"}${parameters._interactions:-}], \"reasoning_effort\":\"low\"${parameters.tool_configs:-}}" + } + ] + } } ``` {% include copy-curl.html %} @@ -113,7 +163,7 @@ OpenSearch responds with the model ID: } ``` -## Step 2: Register an agent +## Step 3: Register an agent You can use any [OpenSearch agent type]({{site.url}}{{site.baseurl}}/ml-commons-plugin/agents-tools/agents/) to run the `QueryPlanningTool`. The following example uses a `flow` agent, which runs a sequence of tools in order and returns the last tool's output. @@ -130,7 +180,6 @@ POST /_plugins/_ml/agents/_register "tools": [ { "type": "QueryPlanningTool", - "description": "A general tool to answer any question.", "parameters": { "model_id": "ANiSxJgBOh0h20Y9XYXl" } @@ -140,7 +189,7 @@ POST /_plugins/_ml/agents/_register ``` {% include copy-curl.html %} -When registering the agent, you can override parameters that you specified during model registration, such as `query_planner_system_prompt` and `query_planner_user_prompt`. +When registering the agent, you can override parameters that you specified during model registration, such as `system_prompt` and `user_prompt`. ### Using search templates @@ -169,7 +218,7 @@ POST /_scripts/flower_species_search_template {% include copy-curl.html %} ```json -POST /_scripts/flower_species_search_template_2 +POST /_scripts/flower_petal_length_range_template { "script": { "lang": "mustache", @@ -177,8 +226,11 @@ POST /_scripts/flower_species_search_template_2 "from": "{% raw %} {{from}}{{^from}}0{{/from}} {% endraw %} ", "size": "{% raw %} {{size}}{{^size}}10{{/size}} {% endraw %} ", "query": { - "term": { - "species": "{% raw %} {{species}} {% endraw %} " + "range": { + "petal_length_in_cm": { + "gte": "{% raw %} {{min_length}} {% endraw %} ", + "lte": "{% raw %} {{max_length}} {% endraw %} " + } } } } @@ -208,8 +260,8 @@ POST /_plugins/_ml/agents/_register "template_description": "This template searches for flowers that match the given species using a match query." }, { - "template_id": "flower_species_search_template_2", - "template_description": "This template searches for flowers that match the given species using a term query." + "template_id": "flower_petal_length_range_template", + "template_description": "This template searches for flowers within a specific petal length range using a range query." } ] } @@ -219,7 +271,7 @@ POST /_plugins/_ml/agents/_register ``` {% include copy-curl.html %} -The LLM uses the `template_description` as additional context to help it choose the best template to use when generating an OpenSearch DSL query based on the user-provided `question`. If the LLM determines that none of the provided search templates are applicable to the given `question`, then the LLM uses a default `match_all` query. Note that the LLM doesn't directly populate template variables or render the template; instead, it analyzes the template's query structure and uses it as a guide to generate a new, contextually appropriate OpenSearch DSL query. +The LLM uses the `template_description` as the only context to help it choose the best template to use when generating an OpenSearch DSL query based on the user-provided `question`. Make sure to provide a good description of the templates to help the LLM make appropriate choices. Note that the LLM doesn't directly populate template variables or render the template; instead, it analyzes the template's query structure and uses it as a guide to generate a new, contextually appropriate OpenSearch DSL query. For parameter descriptions, see [Register parameters](#register-parameters). @@ -231,7 +283,7 @@ OpenSearch responds with an agent ID: } ``` -## Step 3: Execute the agent +## Step 4: Execute the agent Execute the agent by sending the following request: @@ -239,9 +291,8 @@ Execute the agent by sending the following request: POST /_plugins/_ml/agents/RNjQi5gBOh0h20Y9-RX1/_execute { "parameters": { - "query_planner_user_prompt": """You are an OpenSearch Query DSL generation assistant, generate an OpenSearch Query DSL to retrieve the most relevant documents for the user provided natural language question: ${parameters.question}, please return the query dsl only, no other texts. Please don't use size:0, because that would limit the query to return no result. please return a query to find the most relevant documents related to users question. For example: {"query":{"match":{"species":"setosa"}}} -""", - "question": "How many iris flowers of type setosa are there?" + "question": "How many iris flowers of type setosa are there?", + "index_name": "iris-index" } } @@ -271,68 +322,206 @@ The following table lists all tool parameters that are available when registerin Parameter | Type | Required/Optional | Description :--- | :--- | :--- | :--- -`model_id` | String | Required | The model ID of the large language model (LLM) to use for generating the query DSL. +`model_id` | String | Required | The model ID of the LLM used to generate the query DSL. When used within a `conversational` agent, if this value is not provided, the agent's own `llm.model_id` is used by default. `response_filter` | String | Optional | A JSONPath expression used to extract the generated query from the LLM's response. -`generation_type` | String | Optional | The type of query generation. Valid values are `llmGenerated` (use LLM knowledge only) and `user_templates` (provide search templates as additional context). Default is `llmGenerated`. -`query_planner_system_prompt` | String | Optional | A system prompt that provides high-level instructions to the LLM. Default is `You are an OpenSearch Query DSL generation assistant, translating natural language questions to OpenSeach DSL Queries`. -`query_planner_user_prompt` | String | Optional | A user prompt template for the LLM. Can contain placeholders for execution-time parameters like `${parameters.question}`. -`search_templates` | Array | Optional | Applicable only when `generation_type` is set to `user_templates`. A list of search templates for an LLM to use as context when generating an OpenSearch DSL query. Each entry within the `search_templates` array must include a `template_id` and a `template_description` (provides the LLM with additional context about the template contents). - -## Execute parameters +`generation_type` | String | Optional | Determines how queries are generated. Use `llmGenerated` to rely solely on the LLM's built-in knowledge or `user_templates` to provide predefined search templates that guide query generation for consistent results. Default is `llmGenerated`. +`query_planner_system_prompt` | String | Optional | A system prompt that provides high-level instructions to the LLM. +`query_planner_user_prompt` | String | Optional | A user prompt template that defines how the natural language question and context are presented to the LLM for query generation. +`search_templates` | Array | Optional | Applicable only when `generation_type` is `user_templates`. A list of search templates that provide the LLM with predefined query patterns for generating query DSL. Each template must include a `template_id` (unique identifier) and `template_description` (explains the template's purpose and use case to help the LLM choose appropriately). -The execution parameters for the `QueryPlanningTool` are flexible and depend on both the tool's configuration and the underlying language model's requirements as defined in its connector. +All parameters that were configured either in the connector or in the agent registration can be overridden during agent execution. +{: .note} -There are three layers of parameters to consider: +## Execute parameters -1. **Connector parameters**: When you create a connector, the `request_body` defines the JSON payload sent to the model. This payload can contain variables like `${parameters.prompt}` or `${parameters.query_planner_user_prompt}`. The names of these variables depend on the specific model's API. The `QueryPlanningTool` provides values for these variables. +The `QueryPlanningTool` accepts the following execution parameters. -2. **Tool parameters**: The `QueryPlanningTool` uses its own set of parameters, such as `query_planner_user_prompt` and `query_planner_system_prompt`, to construct the final string that will be passed to the connector. The tool takes the `query_planner_user_prompt` string and resolves any variables within it, and the resulting string is then used to fill the appropriate variable (for example, `${parameters.query_planner_user_prompt}`) in the connector's `request_body`. +Parameter | Type | Required/Optional | Description +:--- | :--- | :--- | :--- +`question` | String | Required | A complete natural language query with all necessary context to generate OpenSearch DSL. Include the question, any specific requirements, filters, or constraints. Examples: `Find all products with price greater than 100 dollars`, `Show me documents about machine learning published in 2023`, `Search for users with status active and age between 25 and 35`. +`index_name` | String | Required | The name of the index for which the query needs to be generated. +`embedding_model_id` | String | Optional | The model ID used to perform semantic search. -3. **Prompt variables**: These are the variables inside the `query_planner_user_prompt`, which have the format `${parameters.your_variable_name}`. These must be provided in the `_execute` API call. For example, if your `user_prompt` is "Generate a query for: ${parameters.question}", then you must provide a `question` parameter when you run the agent. +## Customizing the prompts -In summary, the required parameters for an `_execute` call are the **prompt variables**. The tool's own parameters (like `query_planner_user_prompt`) can be overridden at execution time to change how the final prompt is constructed. +You can provide your own `query_planner_system_prompt` and `query_planner_user_prompt` to customize how the LLM generates OpenSearch DSL queries. -For example, if you are using the default `query_planner_user_prompt`, it contains the variable `${parameters.question}`. Therefore, `question` becomes a required execution parameter: +When creating custom prompts, ensure that they include clear output formatting rules so that they work properly with agentic search. The system prompt should specify that the LLM must return only a valid JSON object without any additional text, code fences, or explanations. +{: .important} +**Custom prompt configuration**: +Provide your custom prompts during tool registration in agents as follows: ```json -POST /_plugins/_ml/agents/your_agent_id/_execute +POST /_plugins/_ml/agents/_register { - "parameters": { - "question": "How many iris flowers of type setosa are there?" - } + "name": "Flow Agent for Agentic Search", + "type": "flow", + "description": "Flow agent for agentic search", + "tools": [ + { + "type": "QueryPlanningTool", + "parameters": { + "model_id": "your_model_id", + "response_filter": "", + "query_planner_system_prompt": "", + "query_planner_user_prompt": "" + } + } + ] } ``` {% include copy-curl.html %} -### Improving query accuracy +The following is the default system prompt: -To help the language model generate more accurate query DSL, you can provide additional context within the `query_planner_user_prompt`. This context can include information like: +
+ + Prompt + + {: .text-delta} -- Index mappings. -- Relevant field names. -- Sample documents or queries. +```json +==== PURPOSE ==== +You are an OpenSearch DSL expert. Convert a natural-language question into a strict JSON OpenSearch query body. -You can pass this information by defining variables in your `query_planner_user_prompt` and providing the corresponding values in the `parameters` of your `_execute` call. +==== RULES ==== +Use only fields present in the provided mapping; never invent names. +Choose query types based on user intent and field types: -**Example of an enriched `query_planner_user_prompt`** +match: single-token full-text on analyzed text fields. -Here is an example of how you can structure a `query_planner_user_prompt` to include an index mapping and guide the model to generate a more precise query: +match_phrase: multi-token phrases on analyzed text fields (search string contains spaces, hyphens, commas, etc.). -```json -POST /_plugins/_ml/agents/your_agent_id/_execute -{ - "parameters": { - "query_planner_user_prompt": "You are an OpenSearch Query DSL generation expert. Use the following index mapping to inform your query: ${parameters.index_mapping}. Based on this mapping, generate a query for the user's question: ${parameters.question}. Only use fields mentioned in the mapping.", - "question": "Find all movies directed by John Doe", - "index_mapping": """{"properties":{"title":{"type":"text"},"director":{"type":"keyword"},"year":{"type":"integer"}}}""" - } -} +multi_match: when multiple analyzed text fields are equally relevant. + +term / terms: exact match on keyword, numeric, boolean. + +range: numeric/date comparisons (gt, lt, gte, lte). + +bool with must, should, must_not, filter: AND/OR/NOT logic. + +wildcard / prefix on keyword: "starts with" / pattern matching. + +exists: field presence/absence. + +nested query / nested agg: ONLY if the mapping for that exact path (or a parent) has "type":"nested". + +neural: semantic similarity on a 'semantic' or 'knn_vector' field (dense). Use "query_text" and "k"; include "model_id" unless bound in mapping. + +neural (top-level): allowed when it's the only relevance clause needed; otherwise wrap in a bool when combining with filters/other queries. + +Mechanics: + +Put exact constraints (term, terms, range, exists, prefix, wildcard) in bool.filter (non-scoring). Put full-text relevance (match, match_phrase, multi_match) in bool.must. + +Top N items/products/documents: return top hits (set "size": N as an integer) and sort by the relevant metric(s). Do not use aggregations for item lists. + +Neural retrieval size: set "k" ≥ "size" (e.g. heuristic, k = max(size*5, 100) and k<=ef_search). + +Spelling tolerance: match_phrase does NOT support fuzziness; use match or multi_match with "fuzziness": "AUTO" when tolerant matching is needed. + +Text operators (OR vs AND): default to OR for natural-language queries; to tighten, use minimum_should_match (e.g., "75%"). Use AND only when every token is essential; if order/adjacency matters, use match_phrase. + +Numeric note: use ONLY integers for size and k (not floats). + +Aggregations (counts, averages, grouped summaries, distributions): + +Use aggregations when the user asks for grouped summaries (e.g., counts by category, averages by brand, or top N categories/brands). + +terms on field.keyword or numeric for grouping / top N groups (not items). + +Metric aggs (avg, min, max, sum, stats, cardinality) on numeric fields. + +date_histogram, histogram, range for distributions. + +Always set "size": 0 when only aggregations are needed. + +Use sub-aggregations + order for "top N groups by metric". + +If grouping/filtering exactly on a text field, use its .keyword sub-field when present. + +DATE RULES + +Use range on date/date_nanos in bool.filter. + +Emit ISO 8601 UTC ('Z') bounds; don't set time_zone for explicit UTC. (now is UTC) + +Date math: now±N{y|M|w|d|h|m|s}. + +Rounding: "/UNIT" floors to start (now/d, now/w, now/M, now/y). + +End boundaries: prefer the next unit’s start. + +Formats: only add "format" when inputs aren’t default; epoch_millis allowed. + +Buckets: use date_histogram with calendar_interval or fixed_interval. + +NEURAL / SEMANTIC SEARCH +When to use: conceptual/semantic intent, or when user asks for semantic/neural/vector/embedding search. +When not to use: purely structured/exact queries, or when no semantic/knn_vector field or model_id is available. +How to query: + +Use the "neural" clause against the chosen field. + +Required: "query_text" and "k". + +Model rules: + +For "semantic" fields, omit model_id unless overriding. + +For "knn_vector", include model_id unless default is bound. + +If no model id, do not generate neural clause. + +Top-level allowed if no filters/other queries. Otherwise wrap in bool with filters in bool.filter. + +Size: set "k" ≥ "size" (heuristic: k = max(size*5, 100)). + +FIELD SELECTION & PROXYING +Goal: pick the smallest set of mapping fields that best capture the user's intent. + +When provided, and present in the mapping, prioritize query_fields. + +Proxy Rule: If at least one field is loosely related, proceed with the best proxy; do NOT fallback to match_all due to ambiguity. + +Steps: harvest candidates, pick mapping fields, ignore irrelevant ones. + +Micro Self-Check: verify fields exist; if not, swap to proxies. Only if no relevant fields exist at all, fallback to match_all. + +==== OUTPUT FORMAT ==== + +Return EXACTLY ONE JSON object (valid OpenSearch request body). + +No escapes, no code fences, no quotes around the whole object. + +If nothing relevant exists, return exactly: +{"size":10,"query":{"match_all":{}}} + +==== EXAMPLES ==== +(Then follows Examples 1–13 exactly as in your original text, but without escapes.) + +==== TEMPLATE USE ==== +Use this search template provided by the user as reference to generate the query: ${parameters.template} +Note that this template might contain terms that are not relevant to the question at hand; in that case ignore the template. ``` -{% include copy-curl.html %} -When passing complex JSON objects like an `index_mapping` as a parameter, ensure that the JSON string is properly escaped to be a valid single-line string within the parent JSON document. -{: .note} +
+ +The following is the default user prompt: + +```json +Question: ${parameters.question} +Mapping: ${parameters.index_mapping:-} +Query Fields: ${parameters.query_fields:-} +Sample Document from index: ${parameters.sample_document:-} +In UTC: ${parameters.current_time:-} format: yyyy-MM-dd'T'HH:mm:ss'Z' +Embedding Model ID for Neural Search: ${parameters.embedding_model_id:- not provided} + +==== OUTPUT ==== +GIVE THE OUTPUT PART ONLY IN YOUR RESPONSE (a single JSON object) +Output: +``` ## Related pages -- [Agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/) \ No newline at end of file +- [Agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/index) \ No newline at end of file diff --git a/_query-dsl/specialized/agentic.md b/_query-dsl/specialized/agentic.md index c78af14b65c..2a49145469d 100644 --- a/_query-dsl/specialized/agentic.md +++ b/_query-dsl/specialized/agentic.md @@ -9,11 +9,16 @@ nav_order: 2 **Introduced 3.2** {: .label .label-purple } -Use the `agentic` query to ask questions in natural language and have OpenSearch automatically plan and execute the retrieval. The `agentic` query works in conjunction with a preconfigured agent that reads the question, plans the search, and returns relevant results. For more information about agentic search, see [Agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/). +Use the `agentic` query to ask questions in natural language and have OpenSearch automatically plan and execute the retrieval. The `agentic` query works in conjunction with a preconfigured agent that reads the question, plans the search, and returns relevant results. For more information about agentic search, see [Agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/index/). -**Prerequisite**
-Before using an `agentic` query, you must configure an agent with the [`QueryPlanningTool`]({{site.url}}{{site.baseurl}}/ml-commons-plugin/agents-tools/tools/query-planning-tool/) and create a search pipeline with an `agentic_query_translator` search request processor. -{: .note} +## Prerequisite + +Before using an `agentic` query, you must fulfill the following prerequisites: + +1. Configure an agent with the [`QueryPlanningTool`]({{site.url}}{{site.baseurl}}/ml-commons-plugin/agents-tools/tools/query-planning-tool/). The `QueryPlanningTool` is required for generating query domain-specific language (DSL) queries from natural language questions. Optionally, you can configure the agent with additional tools for enhanced functionality. +1. Create a search pipeline with an [`agentic_query_translator` search request processor]({{site.url}}{{site.baseurl}}/search-plugins/search-pipelines/agentic-query-translator-processor/). + +For detailed setup instructions, see [Agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/index/). ## Request body fields @@ -21,8 +26,9 @@ The `agentic` query accepts the following fields. Field | Data type | Required/Optional | Description :--- | :--- | :--- | :--- -`query_text` | String | Required | The natural language question or request. -`query_fields` | Array | Optional | A list of fields that the agent should consider when generating the search query. If not provided, the agent considers all available fields in the index mapping. +`query_text` | String | Required | The natural language question to be answered by the agent. +`query_fields` | Array | Optional | A list of index fields that the agent should consider when generating the search query. If omitted, the agent infers the applicable fields based on the index mappings and content. +`memory_id` | String | Optional | Applicable for `conversational` agents only. Provides a memory ID from a previous response to continue the conversation with prior context. See [Using conversational agents for agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/agent-converse/). | ## Example @@ -48,10 +54,11 @@ When executed, the agentic search request performs the following steps: 3. The generated DSL query is executed as a search request in OpenSearch. 4. Returns the search results based on the generated query. -For a complete example, see [Agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/). +For a complete example, see [Agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/index/). ## Next steps -- Learn how to set up agentic search in [Agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/). -- Learn about configuring agents in [Agents]({{site.url}}{{site.baseurl}}/ml-commons-plugin/agents-tools/agents/). -- Learn about the [QueryPlanningTool]({{site.url}}{{site.baseurl}}/ml-commons-plugin/agents-tools/tools/query-planning-tool/). \ No newline at end of file +- Learn how to configure agentic search in [Agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/index/). +- Learn about agent types in [Agent types]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/index/#agent-types). +- Learn about the [`QueryPlanningTool`]({{site.url}}{{site.baseurl}}/ml-commons-plugin/agents-tools/tools/query-planning-tool/). +- View the reference documentation for the [`agentic_query_translator` search request processor]({{site.url}}{{site.baseurl}}/search-plugins/search-pipelines/agentic-query-translator-processor/). \ No newline at end of file diff --git a/_search-plugins/search-pipelines/agentic-context-processor.md b/_search-plugins/search-pipelines/agentic-context-processor.md index 1ba822103a7..bafabbeef6a 100644 --- a/_search-plugins/search-pipelines/agentic-context-processor.md +++ b/_search-plugins/search-pipelines/agentic-context-processor.md @@ -19,14 +19,16 @@ The `agentic_context` search response processor adds agent execution context inf 4. The context information is added to the search response extensions. 5. Type validation ensures that all context attributes are strings. +This processor works with both conversational and flow agents, but the available context information differs by agent type. Flow agents provide `dsl_query` (the generated DSL) only, while conversational agents provide `dsl_query`, `memory_id`, and `agent_steps_summary`. For more information, see [Agent types]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/index/#agent-types). + ## Request body fields The following table lists all available request fields. Field | Data type | Description :--- | :--- | :--- -`agent_steps_summary` | Boolean | Whether to include the agent's execution steps summary in the response. Default is `false`. Optional. -`dsl_query` | Boolean | Whether to include the generated DSL query in the response. Default is `false`. Optional. +`agent_steps_summary` | Boolean | Whether to include the agent's execution step summary in the response. Available for conversational agents only. Optional. Default is `false`. +`dsl_query` | Boolean | Whether to include the generated DSL query in the response. Available for both conversational and flow agents. Optional. Default is `false`. ## Response fields @@ -34,9 +36,9 @@ When enabled, the processor adds the following fields to the search response ext Field | Description :--- | :--- -`agent_steps_summary` | A summary of the steps that the agent took to translate the natural language query (included when `agent_steps_summary` is `true`). -`memory_id` | The conversation memory ID for maintaining context across queries. Only provide this in the `agentic` query if you want to continue the previous conversation. -`dsl_query` | The generated DSL query that was executed (included when `dsl_query` is `true`). +`agent_steps_summary` | A summary of the steps that the agent took to translate the natural language query (included when `agent_steps_summary` is `true`). Available for conversational agents only. +`memory_id` | The conversation memory ID for maintaining context across queries. Available for conversational agents only. Only provide this in the `agentic` query if you want to continue the previous conversation. +`dsl_query` | The generated DSL query that was executed (included when `dsl_query` is `true`). Available for both conversational and flow agents. ## Example @@ -98,6 +100,6 @@ The response contains the steps taken by the agent to translate the query, the m ## Related pages -- [Agentic search queries]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search) -- [Agents]({{site.url}}{{site.baseurl}}/ml-commons-plugin/agents-tools/agents/index/) +- [Agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/index/) +- [Agentic query]({{site.url}}{{site.baseurl}}/query-dsl/specialized/agentic/) - [Agentic query translator processor]({{site.url}}{{site.baseurl}}/search-plugins/search-pipelines/agentic-query-translator-processor/) \ No newline at end of file diff --git a/_search-plugins/search-pipelines/agentic-query-translator-processor.md b/_search-plugins/search-pipelines/agentic-query-translator-processor.md index ce119059dcb..d4b96fe840d 100644 --- a/_search-plugins/search-pipelines/agentic-query-translator-processor.md +++ b/_search-plugins/search-pipelines/agentic-query-translator-processor.md @@ -11,7 +11,7 @@ grand_parent: Search pipelines **Introduced 3.2** {: .label .label-purple } -The `agentic_query_translator` search request processor enables natural language search by translating user queries into OpenSearch query domain-specific language (DSL) queries using machine learning (ML) agents. It works with [agentic search queries]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search) to provide conversational search capabilities: +The `agentic_query_translator` search request processor enables natural language search by translating user queries into OpenSearch query domain-specific language (DSL) queries using machine learning (ML) agents. It works with [agentic search queries]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/index/) to provide conversational search capabilities: 1. The processor sends the user's natural language query to the specified ML agent. 2. The agent translates the query into OpenSearch DSL. @@ -127,6 +127,6 @@ The response contains the matching documents: ## Related pages -- [Agentic search queries]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search) -- [Agents]({{site.url}}{{site.baseurl}}/ml-commons-plugin/agents-tools/agents/index/) +- [Agentic search queries]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/index/) +- [Agentic query]({{site.url}}{{site.baseurl}}/query-dsl/specialized/agentic/) - [Agentic context processor]({{site.url}}{{site.baseurl}}/search-plugins/search-pipelines/agentic-context-processor/) \ No newline at end of file diff --git a/_vector-search/ai-search/agentic-search.md b/_vector-search/ai-search/agentic-search.md deleted file mode 100644 index 3d97af0e0bd..00000000000 --- a/_vector-search/ai-search/agentic-search.md +++ /dev/null @@ -1,177 +0,0 @@ ---- -layout: default -title: Agentic search -parent: AI search -nav_order: 30 -has_children: false ---- - -# Agentic search - -This is an experimental feature and is not recommended for use in a production environment. For updates on the progress of the feature or if you want to leave feedback, join the discussion on the [OpenSearch forum](https://forum.opensearch.org/). -{: .warning} - -**Introduced 3.2** -{: .label .label-purple } - -Agentic search lets users ask questions in natural language and have OpenSearch plan and execute the retrieval automatically. A preconfigured **agent** reads the question, plans the search, and returns relevant results. - -**Prerequisite**
-Before using agentic search, you must configure an agent with the [`QueryPlanningTool`]({{site.url}}{{site.baseurl}}/ml-commons-plugin/agents-tools/tools/query-planning-tool/). - -## Configuring semantic search - -1. [Enable the agentic search feature flag](#step-1-enable-the-agentic-search-feature-flag). -2. [Create an index for ingestion](#step-2-create-an-index-for-ingestion). -3. [Ingest documents into the index](#step-3-ingest-documents-into-the-index). -4. [Create a search pipeline](#step-4-create-a-search-pipeline). -5. [Search the index](#step-5-search-the-index). - -### Step 1: Enable the agentic search feature flag - -Because this is an experimental feature in version 3.2, you must enable the feature flag: - -```json -PUT _cluster/settings -{ - "persistent" : { - "plugins.neural_search.agentic_search_enabled": true, - } -} -``` -{% include copy-curl.html %} - - - -### Step 2: Create an index for ingestion - -Create an index for ingestion: - -```json -PUT /iris-index -{ - "mappings": { - "properties": { - "petal_length_in_cm": { - "type": "float" - }, - "petal_width_in_cm": { - "type": "float" - }, - "sepal_length_in_cm": { - "type": "float" - }, - "sepal_width_in_cm": { - "type": "float" - }, - "species": { - "type": "text", - "fields": { - "keyword": { - "type": "keyword", - "ignore_above": 256 - } - } - } - } - } -} -``` -{% include copy-curl.html %} - -### Step 3: Ingest documents into the index - -To ingest documents into the index created in the previous step, send the following requests: - -```json -POST _bulk -{ "index": { "_index": "iris-index", "_id": "1" } } -{ "petal_length_in_cm": 1.4, "petal_width_in_cm": 0.2, "sepal_length_in_cm": 5.1, "sepal_width_in_cm": 3.5, "species": "setosa" } -{ "index": { "_index": "iris-index", "_id": "2" } } -{ "petal_length_in_cm": 4.5, "petal_width_in_cm": 1.5, "sepal_length_in_cm": 6.4, "sepal_width_in_cm": 2.9, "species": "versicolor" } -``` -{% include copy-curl.html %} - -### Step 4: Create a search pipeline - -Create a search pipeline with an agentic query translator search request processor and pass the agent ID created with the QueryPlanningTool: - -```json -PUT _search/pipeline/agentic-pipeline -{ - "request_processors": [ - { - "agentic_query_translator": { - "agent_id": "-E2Av5gBrRE4_QBCgKwl" - } - } - ] -} -``` -{% include copy-curl.html %} - -### Step 5: Search the index - -To perform agentic search, use the agentic query clause with your narural language question. - -The following example request uses an agentic query to search for a natural language question: - -```json -GET iris-index/_search?search_pipeline=agentic-pipeline -{ - "query": { - "agentic": { - "query_text": "List all the flowers present", - "query_fields": ["species", "petal_length_in_cm"] - } - } -} -``` -{% include copy-curl.html %} - -The request contains the following fields: -1. `query_text`: The natural language question. -2. `query_fields` (optional): A list of fields that the agent should consider when generating the search query. - - -The agentic search request executes the agent with the QueryPlanningTool and sends the natural language question, along with the index mapping and a default prompt, to a large language model (LLM) to generate a query domain-specific language (DSL) query. The returned DSL query is then executed as a search request in OpenSearch: - -```json -"hits": { - "total": { - "value": 2, - "relation": "eq" - }, - "max_score": 1.0, - "hits": [ - { - "_index": "iris-index", - "_id": "1", - "_score": 1.0, - "_source": { - "petal_length_in_cm": 1.4, - "petal_width_in_cm": 0.2, - "sepal_length_in_cm": 5.1, - "sepal_width_in_cm": 3.5, - "species": "setosa" - } - }, - { - "_index": "iris-index", - "_id": "2", - "_score": 1.0, - "_source": { - "petal_length_in_cm": 4.5, - "petal_width_in_cm": 1.5, - "sepal_length_in_cm": 6.4, - "sepal_width_in_cm": 2.9, - "species": "versicolor" - } - } - ] - } -``` - -## Next steps - -This is an experimental feature. See [[RFC] Design for Agentic Search #1479](https://github.com/opensearch-project/neural-search/issues/1479) and [[RFC] Agentic Search in OpenSearch #4005](https://github.com/opensearch-project/ml-commons/issues/4005) for information about future enhancements. \ No newline at end of file diff --git a/_vector-search/ai-search/agentic-search/agent-converse.md b/_vector-search/ai-search/agentic-search/agent-converse.md new file mode 100644 index 00000000000..f6f2df26896 --- /dev/null +++ b/_vector-search/ai-search/agentic-search/agent-converse.md @@ -0,0 +1,386 @@ +--- +layout: default +title: Using conversational agents +parent: Agentic search +grand_parent: AI search +nav_order: 70 +has_children: false +--- + +# Using conversational agents for agentic search + +Conversational agents provide advanced agentic search capabilities with detailed reasoning traces and conversation memory. Unlike flow agents, which run tools sequentially and only return the generated query domain-specific language (DSL) query, conversational agents provide additional context through the `agentic_context` response processor, including a step-by-step reasoning summary and a memory ID for continuing conversations across multiple queries. + +This guide demonstrates how to configure conversational agents with multiple tools and use their advanced features for complex search scenarios. + +## Step 1: Create a product index + +Create a sample index with product data that includes various attributes like name, price, color, and category: + +```json +PUT /products-index +{ + "settings": { + "number_of_shards": "4", + "number_of_replicas": "2" + }, + "mappings": { + "properties": { + "product_name": { "type": "text" }, + "description": { "type": "text" }, + "price": { "type": "float" }, + "currency": { "type": "keyword" }, + "rating": { "type": "float" }, + "review_count": { "type": "integer" }, + "in_stock": { "type": "boolean" }, + "color": { "type": "keyword" }, + "size": { "type": "keyword" }, + "category": { "type": "keyword" }, + "brand": { "type": "keyword" }, + "tags": { "type": "keyword" } + } + } +} +``` +{% include copy-curl.html %} + +## Step 2: Ingest sample data + +Add sample product documents to the index: + +```json +POST _bulk +{ "index": { "_index": "products-index", "_id": "1" } } +{ "product_name": "Nike Air Max 270", "description": "Comfortable running shoes with Air Max technology", "price": 150.0, "currency": "USD", "rating": 4.5, "review_count": 1200, "in_stock": true, "color": "white", "size": "10", "category": "shoes", "brand": "Nike", "tags": ["running", "athletic", "comfortable"] } +{ "index": { "_index": "products-index", "_id": "2" } } +{ "product_name": "Adidas Ultraboost 22", "description": "Premium running shoes with Boost midsole", "price": 180.0, "currency": "USD", "rating": 4.7, "review_count": 850, "in_stock": true, "color": "black", "size": "9", "category": "shoes", "brand": "Adidas", "tags": ["running", "premium", "boost"] } +{ "index": { "_index": "products-index", "_id": "3" } } +{ "product_name": "Converse Chuck Taylor", "description": "Classic canvas sneakers", "price": 65.0, "currency": "USD", "rating": 4.2, "review_count": 2100, "in_stock": true, "color": "white", "size": "8", "category": "shoes", "brand": "Converse", "tags": ["casual", "classic", "canvas"] } +{ "index": { "_index": "products-index", "_id": "4" } } +{ "product_name": "Puma RS-X", "description": "Retro-inspired running shoes with modern comfort", "price": 120.0, "currency": "USD", "rating": 4.3, "review_count": 750, "in_stock": true, "color": "black", "size": "9", "category": "shoes", "brand": "Puma", "tags": ["retro", "running", "comfortable"] } +``` +{% include copy-curl.html %} + +## Step 3: Create a model + +Review the [model configuration]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/agent-customization/#model-configuration) and choose a model to use. + +Here we register a GPT model that will be used by both the conversational agent and the `QueryPlanningTool`: + +```json +POST /_plugins/_ml/models/_register +{ + "name": "My OpenAI model: gpt-5", + "function_name": "remote", + "description": "test model", + "connector": { + "name": "My openai connector: gpt-5", + "description": "The connector to openai chat model", + "version": 1, + "protocol": "http", + "parameters": { + "model": "gpt-5" + }, + "credential": { + "openAI_key": "your-openai-api-key" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions", + "headers": { + "Authorization": "Bearer ${credential.openAI_key}" + }, + "request_body": "{ \"model\": \"${parameters.model}\", \"messages\": [{\"role\":\"developer\",\"content\":\"${parameters.system_prompt}\"},${parameters._chat_history:-}{\"role\":\"user\",\"content\":\"${parameters.user_prompt}\"}${parameters._interactions:-}], \"reasoning_effort\":\"low\"${parameters.tool_configs:-}}" + } + ] + } +} +``` + +## Step 4: Register an agent + +Register a conversational agent with multiple tools---`ListIndexTool` to discover available indexes, `IndexMappingTool` to understand index structure, `WebSearchTool` for external data access, and the required `QueryPlanningTool` to generate OpenSearch DSL. + +See [Customizing agentic search agents]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/agent-customization/) for advanced configurations. The agent must include a `QueryPlanningTool`: + +```json +POST /_plugins/_ml/agents/_register +{ + "name": "E-commerce Search Agent", + "type": "conversational", + "description": "Intelligent e-commerce search with product discovery", + "llm": { + "model_id": "your-model-id", + "parameters": { + "max_iteration": 20 + } + }, + "memory": { + "type": "conversation_index" + }, + "parameters": { + "_llm_interface": "openai/v1/chat/completions" + }, + "tools": [ + { + "type": "ListIndexTool", + "name": "ListIndexTool" + }, + { + "type": "IndexMappingTool", + "name": "IndexMappingTool" + }, + { + "type": "WebSearchTool", + "parameters": { + "engine": "duckduckgo" + } + }, + { + "type": "QueryPlanningTool" + } + ], + "app_type": "os_chat" +} +``` +{% include copy-curl.html %} + +## Step 5: Configure a search pipeline + +Create a search pipeline with both request and response processors. The [`agentic_query_translator` request processor]({{site.url}}{{site.baseurl}}/search-plugins/search-pipelines/agentic-query-translator-processor/) translates natural language queries into OpenSearch DSL, while the [`agentic_context` response processor]({{site.url}}{{site.baseurl}}/search-plugins/search-pipelines/agentic-context-processor/) adds agent execution context information for monitoring and conversation continuity: + +```json +PUT _search/pipeline/agentic-pipeline +{ + "request_processors": [ + { + "agentic_query_translator": { + "agent_id": "your-ecommerce-agent-id" + } + } + ], + "response_processors": [ + { + "agentic_context": { + "agent_steps_summary": true, + "dsl_query": true + } + } + ] +} +``` +{% include copy-curl.html %} + +## Step 6: Run an agentic search + +To run a search, send a natural language search query. The agent analyzes the request, discovers appropriate indexes, and generates an optimized DSL query: + +```json +GET /_search?search_pipeline=agentic-pipeline +{ + "query": { + "agentic": { + "query_text": "Find me white shoes under 150 dollars" + } + } +} +``` +{% include copy-curl.html %} + +The response includes matching products and detailed agent information in the `ext` object, showing the agent's reasoning process and the generated DSL query: + +```json +{ + "took": 12146, + "timed_out": false, + "_shards": { + "total": 1, + "successful": 1, + "skipped": 0, + "failed": 0 + }, + "hits": { + "total": { + "value": 2, + "relation": "eq" + }, + "max_score": null, + "hits": [ + { + "_index": "products-index", + "_id": "3", + "_score": 0.0, + "_source": { + "product_name": "Converse Chuck Taylor", + "description": "Classic canvas sneakers", + "price": 65.0, + "currency": "USD", + "rating": 4.2, + "review_count": 2100, + "in_stock": true, + "color": "white", + "size": "8", + "category": "shoes", + "brand": "Converse", + "tags": [ + "casual", + "classic", + "canvas" + ] + }, + "sort": [ + 65.0, + 0.0 + ] + }, + { + "_index": "products-index", + "_id": "1", + "_score": 0.0, + "_source": { + "product_name": "Nike Air Max 270", + "description": "Comfortable running shoes with Air Max technology", + "price": 150.0, + "currency": "USD", + "rating": 4.5, + "review_count": 1200, + "in_stock": true, + "color": "white", + "size": "10", + "category": "shoes", + "brand": "Nike", + "tags": [ + "running", + "athletic", + "comfortable" + ] + }, + "sort": [ + 150.0, + 0.0 + ] + } + ] + }, + "ext": { + "agent_steps_summary": "I have these tools available: [ListIndexTool, IndexMappingTool, query_planner_tool]\nFirst I used: ListIndexTool — input: \"[]\"; context gained: \"Found indices; 'products-index' appears most relevant for product queries\"\nSecond I used: query_planner_tool — qpt.question: \"Find white shoes under 150 dollars.\"; index_name_provided: \"products-index\"\nThird I used: query_planner_tool — qpt.question: \"Find white shoes priced under 150 dollars.\"; index_name_provided: \"products-index\"\nValidation: qpt output is valid JSON and aligns with the request for white shoes under 150 dollars in the products-index.", + "memory_id": "XRzFl5kB-5P992SCeeqO", + "dsl_query": "{\"size\":10.0,\"query\":{\"bool\":{\"filter\":[{\"term\":{\"category\":\"shoes\"}},{\"term\":{\"color\":\"white\"}},{\"range\":{\"price\":{\"lte\":150.0}}}]}},\"sort\":[{\"price\":{\"order\":\"asc\"}},{\"_score\":{\"order\":\"desc\"}}]}" + } +} +``` + +## Step 7: Run an agentic search with a memory ID + +Send a follow-up query using the `memory_id` from the previous response: + +```json +GET /_search?search_pipeline=agentic-pipeline +{ + "query": { + "agentic": { + "query_text": "Actually, show black ones instead", + "memory_id": "" + } + } +} +``` +{% include copy-curl.html %} + +The agent remembers the context and applies it to the new request. It successfully interprets "black ones instead" and maintains the $150 budget from the previous context: + +```json +{ + "took": 8942, + "timed_out": false, + "_shards": { + "total": 1, + "successful": 1, + "skipped": 0, + "failed": 0 + }, + "hits": { + "total": { + "value": 1, + "relation": "eq" + }, + "max_score": null, + "hits": [ + { + "_index": "products-index", + "_id": "4", + "_score": 0.0, + "_source": { + "product_name": "Puma RS-X", + "description": "Retro-inspired running shoes with modern comfort", + "price": 120.0, + "currency": "USD", + "rating": 4.3, + "review_count": 750, + "in_stock": true, + "color": "black", + "size": "9", + "category": "shoes", + "brand": "Puma", + "tags": [ + "retro", + "running", + "comfortable" + ] + }, + "sort": [ + 120.0, + 0.0 + ] + } + ] + }, + "ext": { + "agent_steps_summary": "I have these tools available: [ListIndexTool, IndexMappingTool, query_planner_tool]\nFirst I used: query_planner_tool — qpt.question: \"Find black shoes priced under 150 dollars.\"; index_name_provided: \"products-index\"\nValidation: qpt output is valid JSON and aligns with the request for black shoes under 150 dollars in the products-index.", + "memory_id": "XRzFl5kB-5P992SCeeqO", + "dsl_query": "{\"size\":10.0,\"query\":{\"bool\":{\"filter\":[{\"term\":{\"category\":\"shoes\"}},{\"term\":{\"color\":\"black\"}},{\"range\":{\"price\":{\"lte\":150.0}}}]}},\"sort\":[{\"price\":{\"order\":\"asc\"}},{\"_score\":{\"order\":\"desc\"}}]}" + } +} +``` + +## Using hints to guide the LLM + +You can guide the large language model (LLM) to generate the DSL query you prefer by providing hints in the `query_text`. The agent considers these hints when planning the search. + +The following query provides specific hints about sorting and aggregations to guide the agent's DSL generation: + +```json +GET /_search?search_pipeline=agentic-pipeline +{ + "query": { + "agentic": { + "query_text": "Find expensive running shoes, sort by rating descending, and use aggregations to show average price by brand" + } + } +} +``` +{% include copy-curl.html %} + +In contrast, the following query uses simple language without specific DSL hints: + +```json +GET /_search?search_pipeline=agentic-pipeline +{ + "query": { + "agentic": { + "query_text": "Show me running shoes" + } + } +} +``` +{% include copy-curl.html %} + +The first query will likely generate more complex DSL with sorting and aggregations, while the second will be simpler. Use specific terms like "sort by", "aggregate", "filter by", "group by", etc. to guide the agent's query generation. + +## Next steps + +- [Agentic query translator processor]({{site.url}}{{site.baseurl}}/search-plugins/search-pipelines/agentic-query-translator-processor/) -- Learn more about the request processor that translates natural language queries into OpenSearch DSL. +- [Agentic context processor]({{site.url}}{{site.baseurl}}/search-plugins/search-pipelines/agentic-context-processor/) -- Learn more about the response processor that adds agent execution context information for monitoring and conversation continuity. +- [Customizing agentic search agents]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/agent-customization/) -- Configure advanced agent behaviors with different models, tools, and prompts. \ No newline at end of file diff --git a/_vector-search/ai-search/agentic-search/agent-customization.md b/_vector-search/ai-search/agentic-search/agent-customization.md new file mode 100644 index 00000000000..cd324917c8b --- /dev/null +++ b/_vector-search/ai-search/agentic-search/agent-customization.md @@ -0,0 +1,413 @@ +--- +layout: default +title: Customizing agents +parent: Agentic search +grand_parent: AI search +nav_order: 10 +has_children: false +--- + +# Customizing agentic search agents + +You can customize agentic search agents by configuring their models, tools, and prompts: + +- [Model configuration](#model-configuration): Choose different large language models (LLMs) optimized for various tasks. +- [Tool orchestration](#tool-orchestration): Combine multiple tools for automated workflows. +- [Prompt engineering](#prompt-engineering-and-customization): Fine-tune agent behavior using custom prompts. + +## Model configuration + +Select the appropriate language model based on your performance requirements and use case. + +You can also configure different models for the conversational agent and the `QueryPlanningTool`. Set the agent's model by specifying the `llm.model_id`, and set the query planner model by specifying `parameters.model_id` in the `QueryPlanningTool`: + +```json +{ + "name": "Agentic Search Agent", + "type": "conversational", + "description": "Agent using separate models for conversation and query planning", + "llm": { + "model_id": "your-conversational-model-id", + "parameters": { + "max_iteration": 15 + } + }, + "memory": { + "type": "conversation_index" + }, + "parameters": { + "_llm_interface": "" + }, + "tools": [ + { + "type": "QueryPlanningTool", + "parameters": { + "model_id": "your-query-planner-model-id" + } + } + ], + "app_type": "os_chat" +} +``` +{% include copy.html %} + +Set the `` to the interface for your provider (for example, `openai/v1/chat/completions`), then choose a specific model from the following options. + +### OpenAI GPT models + +The following OpenAI GPT models are supported. + +#### GPT-5 (Recommended) + +GPT-5 provides advanced reasoning capabilities and is recommended for production use cases. + +**Model registration**: + +```json +POST /_plugins/_ml/models/_register +{ + "name": "My OpenAI model: gpt-5", + "function_name": "remote", + "description": "test model", + "connector": { + "name": "My openai connector: gpt-5", + "description": "The connector to openai chat model", + "version": 1, + "protocol": "http", + "parameters": { + "model": "gpt-5" + }, + "credential": { + "openAI_key": "your-openai-api-key" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions", + "headers": { + "Authorization": "Bearer ${credential.openAI_key}" + }, + "request_body": "{ \"model\": \"${parameters.model}\", \"messages\": [{\"role\":\"developer\",\"content\":\"${parameters.system_prompt}\"},${parameters._chat_history:-}{\"role\":\"user\",\"content\":\"${parameters.user_prompt}\"}${parameters._interactions:-}], \"reasoning_effort\":\"low\"${parameters.tool_configs:-}}" + } + ] + } +} +``` +{% include copy-curl.html %} + +**Reasoning modes**: + +- `minimal`: Fastest response time, suitable for simple use cases +- `low`(recommended): Slightly more reasoning, suitable for most queries +- `medium`: Enhanced reasoning for sophisticated tasks +- `high`: Maximum reasoning power for the most complex scenarios + +As you select higher reasoning modes, overall latency increases. Choose the lowest mode that meets your accuracy needs. +{: .tip} + +### Anthropic Claude models + +Anthropic Claude models are available through Amazon Bedrock integration and provide analytical capabilities for complex search scenarios. + +#### Claude 4 Sonnet + +**Amazon Bedrock connector setup**: + +```json +POST /_plugins/_ml/connectors/_create +{ + "name": "Bedrock Claude 4 Sonnet Connector", + "description": "Amazon Bedrock connector for Claude 4 Sonnet", + "version": 1, + "protocol": "aws_sigv4", + "parameters": { + "region": "your-aws-region", + "service_name": "bedrock", + "model": "us.anthropic.claude-sonnet-4-20250514-v1:0" + }, + "credential": { + "access_key": "your-aws-access-key", + "secret_key": "your-aws-secret-key", + "session_token": "your-aws-session-token" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://bedrock-runtime.${parameters.region}.amazonaws.com/model/${parameters.model}/converse", + "headers": { + "content-type": "application/json" + }, + "request_body": "{ \"system\": [{\"text\": \"${parameters.system_prompt}\"}], \"messages\": [${parameters._chat_history:-}{\"role\":\"user\",\"content\":[{\"text\":\"${parameters.user_prompt}\"}]}${parameters._interactions:-}]${parameters.tool_configs:-} }" + } + ] +} +``` +{% include copy-curl.html %} + +### Agent interface configuration + +When registering agents, configure the `_llm_interface` parameter to specify how the agent parses LLM output when using function calling. Choose the interface that matches your model type: + +- `"bedrock/converse/claude"`: Anthropic Claude models hosted on Amazon Bedrock +- `"openai/v1/chat/completions"`: OpenAI chat completion models + +Each interface defines a default response schema and function call parser optimized for that model family. + +## Tool orchestration + +You must configure a `QueryPlanningTool` for agentic search. You can configure additional tools to extend your agent's functionality. + +### QueryPlanningTool + +The [`QueryPlanningTool`]({{site.url}}{{site.baseurl}}/ml-commons-plugin/agents-tools/tools/query-planning-tool/) is required for agentic search functionality. It translates natural language queries into OpenSearch query domain-specific language (DSL). + +### Additional tools + +You can configure additional [tools]({{site.url}}{{site.baseurl}}/ml-commons-plugin/agents-tools/tools/index/) to extend your agent's functionality. + +The conversational agent automatically selects and orchestrates the appropriate tools based on the query context. + +#### Complete agent configuration + +The following example shows how to register an agent with multiple tools: + +```json +POST /_plugins/_ml/agents/_register +{ + "name": "Advanced Agentic Search Agent", + "type": "conversational", + "description": "Multi-tool agentic search with index discovery and web integration", + "llm": { + "model_id": "your-conversational-model-id", + "parameters": { + "max_iteration": 15 + } + }, + "memory": { + "type": "conversation_index" + }, + "parameters": { + "_llm_interface": "openai/v1/chat/completions" + }, + "tools": [ + { + "type": "ListIndexTool", + "name": "ListIndexTool" + }, + { + "type": "IndexMappingTool", + "name": "IndexMappingTool" + }, + { + "type": "WebSearchTool", + "name": "DuckduckgoWebSearchTool", + "parameters": { + "engine": "duckduckgo" + } + }, + { + "type": "QueryPlanningTool", + "parameters": { + "model_id": "your-query-planner-model-id" + } + } + ], + "app_type": "os_chat" +} +``` +{% include copy-curl.html %} + +### Intelligent index selection + +When you include a `ListIndexTool`, `IndexMappingTool`, or other relevant tools, your agent can automatically choose the correct index and generate queries for that index. + +To search without specifying an index, send the following request: + +```json +GET /_search?search_pipeline=agentic-pipeline +{ + "query": { + "agentic": { + "query_text": "Find products with high ratings and low prices" + } + } +} +``` +{% include copy-curl.html %} + +The agent automatically discovers product indexes, analyzes their structure, and generates appropriate queries. + +If you don't specify an index in your search query, the search runs against all shards in the cluster, which can be expensive. For better performance, specify the target index when possible. +{: .tip} + +## Prompt engineering and customization + +Configure your agent's behavior and output format using custom prompts that guide the model's reasoning process. + +To customize the `QueryPlanningTool` prompt, see [`QueryPlanningTool`]({{site.url}}{{site.baseurl}}/ml-commons-plugin/agents-tools/tools/query-planning-tool/). + +### System prompt optimization + +Customize your agent's behavior with tailored system prompts that fit for your specific use case. + +### Agent output format + +The agent must have the following output format: + +```json +{ + "dsl_query": "", + "agent_steps_summary": "" +} +``` +{% include copy.html %} + +**Custom prompt configuration**: + +When customizing prompts, ensure that both your system and user prompts guide the model to always return results in the preceding agent output format. Proper prompt engineering is crucial for consistent output formatting. + +Provide your custom prompts during agent registration as follows: + +```json +POST /_plugins/_ml/agents/_register +{ + "name": "Custom Prompt Agent", + "type": "conversational", + "description": "Agent with custom system and user prompts", + "llm": { + "model_id": "your-model-id", + "parameters": { + "max_iteration": 15, + "system_prompt": "", + "user_prompt": "" + } + }, + "memory": { + "type": "conversation_index" + }, + "parameters": { + "_llm_interface": "openai/v1/chat/completions" + }, + "tools": [ + { + "type": "QueryPlanningTool", + "parameters": { + "model_id": "your-query-planner-model-id" + } + } + ], + "app_type": "os_chat" +} +``` +{% include copy-curl.html %} + +### Prompt best practices + +Follow these guidelines to create effective prompts that produce consistent, accurate results: + +- **Be specific**: Clearly define the expected agent output format with `dsl_query` and `agent_steps_summary` fields. +- **Include examples**: Provide sample queries and expected responses in the correct agent output format. +- **Set constraints**: Specify field names, data types, and query limits. +- **Optimize for JSON**: Ensure that your prompts guide the model to produce valid JSON with the required agent output structure. + +### Default system prompt + +The following system prompt is used by default. You can customize this to modify your agent's behavior: + +
+ + Prompt + + {: .text-delta} + +```json +==== PURPOSE ==== +Produce correct OpenSearch DSL by orchestrating tools. You MUST call the Query Planner Tool (query_planner_tool, "qpt") to author the DSL. +Your job: (a) gather only essential factual context, (b) compose a self-contained natural-language question for qpt, (c) validate coverage of qpt's DSL and iterate if needed, then (d) return a strict JSON result with the DSL and a brief step trace. + +==== OUTPUT CONTRACT (STRICT) ==== +Return ONLY a valid JSON object with exactly these keys: +{"dsl_query": , "agent_steps_summary": ""} +- No markdown, no extra text, no code fences. Double-quote all keys/strings. +- Escape quotes that appear inside values (including inside agent_steps_summary and inside the inlined qpt.question you report there). +- The output MUST parse as JSON. + +==== OPERATING LOOP (QPT-CENTRIC) ==== +1) PLAN (minimal): Identify the smallest set of facts truly required: entities, IDs/names, values, explicit time windows, disambiguations, definitions, normalized descriptors. +2) COLLECT (as needed): Use tools to fetch ONLY those facts. Do NOT mention schema fields, analyzers, or DSL constructs to the qpt. +3) SELECT index_name: + - If provided by the caller, use it as-is. + - Otherwise, discover and choose a single best index (e.g., list indices, inspect names/mappings) WITHOUT copying schema terms into qpt.question. +4) COMPOSE qpt.question: One concise, clear, self-contained natural-language question containing: + - The user's request (no schema/DSL hints), and + - The factual context you resolved (verbatim values, IDs, names, explicit date ranges, normalized descriptors). + This question is the ONLY context (besides index_name) that qpt relies on. +5) CALL qpt with {question, index_name, embedding_model_id(if available)}. +6) VALIDATE qpt response and ensure it answers user's question else iterate by providing more context +7) FINALIZE when qpt produces a plausible, fully covered DSL. + +==== CONTEXT RULES ==== +- Use tools to resolve needed facts. +- When tools return user-specific values, RESTATE them verbatim in qpt.question in pure natural language. +- NEVER mention schema/field names, analyzers, or DSL constructs in qpt.question. +- Resolve ambiguous references BEFORE the final qpt call. + +==== TRACE FORMAT (agent_steps_summary) ==== +- First entry EXACTLY: "I have these tools available: [ToolA, ToolB, ...]" +- Then one entry per step: + "First I used: — input: ; context gained: " + "Second I used: …" + … + "N-th I used: query_planner_tool — qpt.question: ; index_name_provided: " +- Keep brief and factual. Do NOT restate the DSL. After the final qpt step you may add a short validation note. + +==== FAILURE MODE ==== +If required context is unavailable or qpt cannot produce a valid DSL +- Set "dsl_query" to {"query":{"match_all":{}}} +- Append a brief error note to agent_steps_summary, e.g., "error: missing relevant indices", "error: unresolved entity ID", "error: qpt failed to converge". + +==== STYLE & SAFETY ==== +- qpt.question must be purely natural-language and context-only. +- Be minimal and deterministic; avoid speculation. +- Use only the concise step summary. +- Always produce valid JSON per the contract. + +==== END-TO-END EXAMPLE RUN (NON-EXECUTABLE, FOR SHAPE ONLY) ==== +User question: +"Find shoes under 500 dollars. I am so excited for shoes yay!" + +Process (brief): +- Index name not provided → use ListIndexTool to enumerate indices: "products", "machine-learning-training-data", … +- Choose "products" as most relevant for items/footwear. +- Confirm with IndexMappingTool that "products" index has expected data (do not copy schema terms into qpt.question). +- Compose qpt.question with natural-language constraints only. +- Call qpt and validate. + +qpt.question (self-contained, no schema terms): +"Find shoes under 500 dollars." + +qpt.output: +"{\"query\":{\"bool\":{\"must\":[{\"match\":{\"category\":\"shoes\"}}],\"filter\":[{\"range\":{\"price\":{\"lte\":500}}}]}}}" + +Final response JSON: +{ + "dsl_query": {\"query\":{\"bool\":{\"must\":[{\"match\":{\"category\":\"shoes\"}}],\"filter\":[{\"range\":{\"price\":{\"lte\":500}}}]}}}}, + "agent_steps_summary": "I have these tools available: [ListIndexTool, IndexMappingTool, query_planner_tool]\nFirst I used: ListIndexTool — input: \"\"; context gained: \"Of the available indices, products index seems promising\"\nSecond I used: IndexMappingTool — input: \"products\"; context gained: \"index contains relevant fields\"\nThird I used: query_planner_tool — qpt.question: \"Find shoes under 500 dollars.\"; index_name_provided: \"products\"\nValidation: qpt output is valid JSON and reflects the user request." +} +``` + +
+ +### Default user prompt + +The default user prompt template passes the natural language question and available parameters to the agent: + +```json +"NLQ is: ${parameters.question} and index_name is: ${parameters.index_name:-}, model ID for neural search is: ${parameters.embedding_model_id:-}" +``` + +## Next steps + +- For a comprehensive example of using customized agents in practice, see [Inspecting agentic search and continuing conversations]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/agent-converse/). diff --git a/_vector-search/ai-search/agentic-search/flow-agent.md b/_vector-search/ai-search/agentic-search/flow-agent.md new file mode 100644 index 00000000000..30558ecfc03 --- /dev/null +++ b/_vector-search/ai-search/agentic-search/flow-agent.md @@ -0,0 +1,230 @@ +--- +layout: default +title: Using flow agents +parent: Agentic search +grand_parent: AI search +nav_order: 20 +has_children: false +--- + +# Using flow agents for agentic search + +Flow agents provide a streamlined alternative to conversational agents. While conversational agents use multiple tools for flexible, context-aware search, flow agents focus solely on query planning. This reduces large language model (LLM) calls, improves response times, and lowers costs. + +Flow agents are sufficient for most use cases. Use flow agents when low latency and cost efficiency are priorities, queries are simple, and conversation memory isn't required. Use conversational agents for complex searches, multi-tool workflows, persistent context, or the highest query quality. + +Flow agents differ from conversational agents in the following ways: + +- Flow agents use only one tool---the `QueryPlanningTool`. +- You must explicitly specify the target index name in the search request. +- Flow agents don't provide agent step summaries or reasoning traces (only the generated query domain-specific language [DSL] query is available when using the `agentic_context` response processor). +- Flow agents don't have conversation memory and cannot maintain context across multiple interactions. + +## Step 1: Create a product index + +Create a sample index with product data that includes various attributes like name, price, color, and category: + +```json +PUT /products-index +{ + "settings": { + "number_of_shards": "4", + "number_of_replicas": "2" + }, + "mappings": { + "properties": { + "product_name": { "type": "text" }, + "description": { "type": "text" }, + "price": { "type": "float" }, + "currency": { "type": "keyword" }, + "rating": { "type": "float" }, + "review_count": { "type": "integer" }, + "in_stock": { "type": "boolean" }, + "color": { "type": "keyword" }, + "size": { "type": "keyword" }, + "category": { "type": "keyword" }, + "brand": { "type": "keyword" }, + "tags": { "type": "keyword" } + } + } +} +``` +{% include copy-curl.html %} + +## Step 2: Ingest sample data + +Add sample product documents to the index: + +```json +POST _bulk +{ "index": { "_index": "products-index", "_id": "1" } } +{ "product_name": "Nike Air Max 270", "description": "Comfortable running shoes with Air Max technology", "price": 150.0, "currency": "USD", "rating": 4.5, "review_count": 1200, "in_stock": true, "color": "white", "size": "10", "category": "shoes", "brand": "Nike", "tags": ["running", "athletic", "comfortable"] } +{ "index": { "_index": "products-index", "_id": "2" } } +{ "product_name": "Adidas Ultraboost 22", "description": "Premium running shoes with Boost midsole", "price": 180.0, "currency": "USD", "rating": 4.7, "review_count": 850, "in_stock": true, "color": "black", "size": "9", "category": "shoes", "brand": "Adidas", "tags": ["running", "premium", "boost"] } +{ "index": { "_index": "products-index", "_id": "3" } } +{ "product_name": "Converse Chuck Taylor", "description": "Classic canvas sneakers", "price": 65.0, "currency": "USD", "rating": 4.2, "review_count": 2100, "in_stock": true, "color": "white", "size": "8", "category": "shoes", "brand": "Converse", "tags": ["casual", "classic", "canvas"] } +{ "index": { "_index": "products-index", "_id": "4" } } +{ "product_name": "Puma RS-X", "description": "Retro-inspired running shoes with modern comfort", "price": 120.0, "currency": "USD", "rating": 4.3, "review_count": 750, "in_stock": true, "color": "black", "size": "9", "category": "shoes", "brand": "Puma", "tags": ["retro", "running", "comfortable"] } +``` +{% include copy-curl.html %} + +## Step 3: Create a model for the agent and QueryPlanningTool + +Register a single model that will be used by both the conversational agent and the `QueryPlanningTool`. This model analyzes natural language questions, coordinates tool usage, and generates the OpenSearch DSL. For available model options, see [Model configurations]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/agent-customization/#model-configuration): + +```json +POST /_plugins/_ml/models/_register +{ + "name": "My OpenAI model: gpt-5", + "function_name": "remote", + "description": "test model", + "connector": { + "name": "My openai connector: gpt-5", + "description": "The connector to openai chat model", + "version": 1, + "protocol": "http", + "parameters": { + "model": "gpt-5" + }, + "credential": { + "openAI_key": "" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions", + "headers": { + "Authorization": "Bearer ${credential.openAI_key}" + }, + "request_body": "{ \"model\": \"${parameters.model}\", \"messages\": [{\"role\":\"developer\",\"content\":\"${parameters.system_prompt}\"},${parameters._chat_history:-}{\"role\":\"user\",\"content\":\"${parameters.user_prompt}\"}${parameters._interactions:-}], \"reasoning_effort\":\"low\"${parameters.tool_configs:-}}" + } + ] + } +} +``` +{% include copy-curl.html %} + +## Step 4: Register a flow agent + +Next, register a flow agent. You must include a `response_filter` in the `QueryPlanningTool` parameters so the agent extracts the generated DSL correctly from your model provider's response: + +```json +POST /_plugins/_ml/agents/_register +{ + "name": "Flow Agent for Agentic Search", + "type": "flow", + "description": "Flow agent for agentic search", + "tools": [ + { + "type": "QueryPlanningTool", + "parameters": { + "model_id": "your_model_id_from_step_3", + "response_filter": "" + } + } + ] +} +``` +{% include copy-curl.html %} + +Use the following response filters based on your model provider: + +- **OpenAI**: `"response_filter": "$.choices[0].message.content"` +- **Anthropic Claude (Amazon Bedrock Converse API)**: `"response_filter": "$.output.message.content[0].text"` + +## Step 5: Create an agentic pipeline with the flow agent + +Create a search pipeline that uses your flow agent to translate natural language queries into DSL. You can optionally include a response processor to view the generated DSL query: + +```json +PUT _search/pipeline/agentic-pipeline +{ + "request_processors": [ + { + "agentic_query_translator": { + "agent_id": "your_flow_agentId_from_step_4" + } + } + ], + "response_processors": [ + { + "agentic_context": { + "dsl_query": true + } + } + ] +} +``` +{% include copy-curl.html %} + +## Step 6: Run an agentic search + +To run an agentic search, use the `agentic` query clause. Flow agents *require the index name*, so you must include it in your search request. Flow agents don't support conversation memory, so you cannot include the `memory_id` parameter: + +```json +GET products-index/_search?search_pipeline=agentic-pipeline +{ + "query": { + "agentic": { + "query_text": "Find me white shoes under 150 dollars" + } + } +} +``` +{% include copy-curl.html %} + +The flow agent processes the natural language query and returns matching products along with the generated DSL query in the response: + +```json +{ + "took": 3965, + "timed_out": false, + "_shards": { + "total": 1, + "successful": 1, + "skipped": 0, + "failed": 0 + }, + "hits": { + "total": { + "value": 1, + "relation": "eq" + }, + "max_score": null, + "hits": [ + { + "_index": "products-index", + "_id": "3", + "_score": null, + "_source": { + "product_name": "Converse Chuck Taylor", + "description": "Classic canvas sneakers", + "price": 65.0, + "currency": "USD", + "rating": 4.2, + "review_count": 2100, + "in_stock": true, + "color": "white", + "size": "8", + "category": "shoes", + "brand": "Converse", + "tags": [ + "casual", + "classic", + "canvas" + ] + }, + "sort": [ + 4.2, + 2100 + ] + } + ] + }, + "ext": { + "dsl_query": "{\"size\":10.0,\"query\":{\"bool\":{\"filter\":[{\"term\":{\"category\":\"shoes\"}},{\"term\":{\"color\":\"white\"}},{\"range\":{\"price\":{\"lt\":150.0}}}]}},\"sort\":[{\"rating\":{\"order\":\"desc\"}},{\"review_count\":{\"order\":\"desc\"}}]}" + } +} +``` + diff --git a/_vector-search/ai-search/agentic-search/index.md b/_vector-search/ai-search/agentic-search/index.md new file mode 100644 index 00000000000..acb2fcd414d --- /dev/null +++ b/_vector-search/ai-search/agentic-search/index.md @@ -0,0 +1,256 @@ +--- +layout: default +title: Agentic search +parent: AI search +nav_order: 75 +has_children: true +has_toc: false +redirect_from: + - /vector-search/ai-search/agentic-search/ +--- + +# Agentic search +**Introduced 3.2** +{: .label .label-purple } + +Agentic search lets you ask questions in natural language and have OpenSearch plan and execute the retrieval automatically. A preconfigured agent reads the question, plans the search, and returns relevant results. + +You can configure agentic search using the API or the OpenSearch Dashboards UI. This guide describes configuring agentic search using the API. To learn how to configure it in OpenSearch Dashboards, see [Building Agentic Search Flows]({{site.url}}{{site.baseurl}}/vector-search/ai-search/building-agentic-search-flows/). + +## Agent types + +Agentic search supports two types of agents, each optimized for different use cases. + +### Conversational agents + +Conversational agents provide the most flexible and powerful agentic search experience. They support multiple tools, conversation memory, and detailed reasoning traces. Use conversational agents when you need: + +- **Multi-tool workflows**: Automatic index discovery, schema analysis, and external data integration. +- **Conversation memory**: The ability to continue conversations across multiple queries using memory IDs. +- **Complex reasoning**: Detailed step-by-step reasoning traces and tool orchestration. +- **Highest query quality**: Maximum flexibility for handling complex or ambiguous queries. + +### Flow agents + +Flow agents offer a streamlined alternative focused solely on query planning. They provide faster response times and lower costs by using only the `QueryPlanningTool`. Use flow agents when you need: + +- **Low latency**: Faster query processing with fewer large language model (LLM) calls. +- **Cost efficiency**: Reduced computational overhead and API costs. +- **Simple queries**: Straightforward search requirements without complex reasoning. +- **Known indexes**: When you can specify target indexes directly in requests. + +The following tutorial uses a conversational agent. To learn about flow agents, see [Using flow agents for agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/flow-agent/). + +## Prerequisite + +Before using agentic search, you must configure an agent with the [`QueryPlanningTool`]({{site.url}}{{site.baseurl}}/ml-commons-plugin/agents-tools/tools/query-planning-tool/). + +## Step 1: Create an index for ingestion + +Create an index for ingestion: + +```json +PUT /iris-index +{ + "mappings": { + "properties": { + "petal_length_in_cm": { + "type": "float" + }, + "petal_width_in_cm": { + "type": "float" + }, + "sepal_length_in_cm": { + "type": "float" + }, + "sepal_width_in_cm": { + "type": "float" + }, + "species": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + } +} +``` +{% include copy-curl.html %} + +## Step 2: Ingest documents into the index + +To ingest documents into the index created in the previous step, send the following requests: + +```json +POST _bulk +{ "index": { "_index": "iris-index", "_id": "1" } } +{ "petal_length_in_cm": 1.4, "petal_width_in_cm": 0.2, "sepal_length_in_cm": 5.1, "sepal_width_in_cm": 3.5, "species": "setosa" } +{ "index": { "_index": "iris-index", "_id": "2" } } +{ "petal_length_in_cm": 4.5, "petal_width_in_cm": 1.5, "sepal_length_in_cm": 6.4, "sepal_width_in_cm": 2.9, "species": "versicolor" } +``` +{% include copy-curl.html %} + +## Step 3: Create a model for the agent and QueryPlanningTool + +Register a single model that will be used by both the conversational agent and the `QueryPlanningTool`. This model analyzes natural language questions, coordinates tool usage, and generates the OpenSearch query domain-specific language (DSL). For available model options, see [Model configurations]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/agent-customization/#model-configuration): + +```json +POST /_plugins/_ml/models/_register +{ + "name": "My OpenAI model: gpt-5", + "function_name": "remote", + "description": "test model", + "connector": { + "name": "My openai connector: gpt-5", + "description": "The connector to openai chat model", + "version": 1, + "protocol": "http", + "parameters": { + "model": "gpt-5" + }, + "credential": { + "openAI_key": "" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions", + "headers": { + "Authorization": "Bearer ${credential.openAI_key}" + }, + "request_body": "{ \"model\": \"${parameters.model}\", \"messages\": [{\"role\":\"developer\",\"content\":\"${parameters.system_prompt}\"},${parameters._chat_history:-}{\"role\":\"user\",\"content\":\"${parameters.user_prompt}\"}${parameters._interactions:-}], \"reasoning_effort\":\"low\"${parameters.tool_configs:-}}" + } + ] + } +} +``` +{% include copy-curl.html %} + +## Step 4: Create an agent + +Create a conversational agent with the `QueryPlannerTool` (required). You can add other tools as needed: + +```json +POST /_plugins/_ml/agents/_register +{ + "name": "GPT 5 Agent for Agentic Search", + "type": "conversational", + "description": "Use this for Agentic Search", + "llm": { + "model_id": , + "parameters": { + "max_iteration": 15, + "embedding_model_id": "" + } + }, + "memory": { + "type": "conversation_index" + }, + "parameters": { + "_llm_interface": "openai/v1/chat/completions" + }, + "tools": [ + { + "type": "QueryPlanningTool" + } + ], + "app_type": "os_chat" +} +``` +{% include copy-curl.html %} + +## Step 5: Create a search pipeline + +Create a search pipeline with an agentic query translator search request processor and pass the agent ID created in the previous step: + +```json +PUT _search/pipeline/agentic-pipeline +{ + "request_processors": [ + { + "agentic_query_translator": { + "agent_id": "" + } + } + ] +} +``` +{% include copy-curl.html %} + +## Step 6: Search the index + +To perform agentic search, use an `agentic` query. The `query_text` parameter contains the natural language question, and the `query_fields` parameter lists the fields that the agent should consider when generating the search query: + +```json +GET iris-index/_search?search_pipeline=agentic-pipeline +{ + "query": { + "agentic": { + "query_text": "List all the flowers present", + "query_fields": ["species", "petal_length_in_cm"] + } + } +} +``` +{% include copy-curl.html %} + +The agentic search request executes the agent with the `QueryPlanningTool` and sends the natural language question, along with the index mapping and a default prompt, to an LLM to generate a DSL query. The returned DSL query is then executed as a search request in OpenSearch: + +```json +"hits": { + "total": { + "value": 2, + "relation": "eq" + }, + "max_score": 1.0, + "hits": [ + { + "_index": "iris-index", + "_id": "1", + "_score": 1.0, + "_source": { + "petal_length_in_cm": 1.4, + "petal_width_in_cm": 0.2, + "sepal_length_in_cm": 5.1, + "sepal_width_in_cm": 3.5, + "species": "setosa" + } + }, + { + "_index": "iris-index", + "_id": "2", + "_score": 1.0, + "_source": { + "petal_length_in_cm": 4.5, + "petal_width_in_cm": 1.5, + "sepal_length_in_cm": 6.4, + "sepal_width_in_cm": 2.9, + "species": "versicolor" + } + } + ] +} +``` + +## Advanced configurations + +After setting up basic agentic search, you can enhance your implementation with these advanced features: + +- [Customize agentic search agents]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/agent-customization/) -- Learn how to customize your agentic search agent with different models, tools, and configurations. + +- [Use flow agents]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/flow-agent/) -- Use streamlined flow agents for faster, more cost-effective query planning when you don't need conversation memory or complex tool orchestration. + +- [Configure semantic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/neural-search/) -- Configure agents to automatically choose between keyword and semantic vector searches based on user intent, providing more relevant results for conceptual questions. + +- [Add search templates]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/search-templates/) -- Add predefined search templates to handle complex query patterns that would be challenging for LLMs to generate consistently, ensuring predictable query structure and improved reliability. + +- [Build agentic search flows]({{site.url}}{{site.baseurl}}/vector-search/ai-search/building-agentic-search-flows/) -- Configure agents and execute agentic search using AI search flows in OpenSearch Dashboards. + +## Next steps + +- [Inspecting agentic search and continuing conversations]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/agent-converse/) -- Inspect agent behavior, view generated DSL, and continue conversations using a memory ID. \ No newline at end of file diff --git a/_vector-search/ai-search/agentic-search/neural-search.md b/_vector-search/ai-search/agentic-search/neural-search.md new file mode 100644 index 00000000000..c1775a946c9 --- /dev/null +++ b/_vector-search/ai-search/agentic-search/neural-search.md @@ -0,0 +1,487 @@ +--- +layout: default +title: Configuring agents for semantic search +parent: Agentic search +grand_parent: AI search +nav_order: 90 +has_children: false +--- + +# Configuring agents for semantic search + +When you have vector indexes with embeddings and want agentic search to automatically perform semantic searches based on user intent, you need to configure your agent with embedding model information. This allows the agent to generate `neural` queries that search for semantic similarity rather than exact text matches, providing more relevant results for conceptual questions. + +When you configure agents for semantic search, the agents choose between traditional keyword searches and semantic vector searches at query time. To enable semantic search in agentic search, you need to provide embedding model information. You can either add the `embedding_model_id` parameter to your agent's configuration or include the embedding model ID directly in your natural language query. + +## Step 1: Configure a vector index + +First, configure a vector index. + +### Step 1(a): Create an embedding model + +Register an embedding model that will convert text into vector representations for semantic search: + +```json +POST /_plugins/_ml/models/_register +{ + "name": "Bedrock embedding model", + "function_name": "remote", + "description": "Bedrock text embedding model v2", + "connector": { + "name": "Amazon Bedrock Connector: embedding", + "description": "The connector to bedrock Titan embedding model", + "version": 1, + "protocol": "aws_sigv4", + "parameters": { + "region": "your-aws-region", + "service_name": "bedrock", + "model": "amazon.titan-embed-text-v2:0", + "dimensions": 1024, + "normalize": true, + "embeddingTypes": [ + "float" + ] + }, + "credential": { + "access_key": "your-access-key", + "secret_key": "your-secret-key", + "session_token": "your-session-token" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://bedrock-runtime.${parameters.region}.amazonaws.com/model/${parameters.model}/invoke", + "headers": { + "content-type": "application/json", + "x-amz-content-sha256": "required" + }, + "request_body": "{ \"inputText\": \"${parameters.inputText}\", \"dimensions\": ${parameters.dimensions}, \"normalize\": ${parameters.normalize}, \"embeddingTypes\": ${parameters.embeddingTypes} }", + "pre_process_function": "connector.pre_process.bedrock.embedding", + "post_process_function": "connector.post_process.bedrock.embedding" + } + ] + } +} +``` +{% include copy-curl.html %} + +### Step 1(b): Create an ingest pipeline + +Create an ingest pipeline that automatically generates embeddings for text fields during document ingestion: + +```json +PUT /_ingest/pipeline/my_bedrock_embedding_pipeline +{ + "description": "text embedding pipeline", + "processors": [ + { + "text_embedding": { + "model_id": "fxzel5kB-5P992SCH-qM", + "field_map": { + "content_text": "content_embedding" + } + } + } + ] +} +``` +{% include copy-curl.html %} + +### Step 1(c): Create a vector index with an ingest pipeline + +Create a vector index with mappings for both text content and vector embeddings, using the ingest pipeline to automatically process documents: + +```json +PUT /research_papers +{ + "settings": { + "index": { + "default_pipeline": "my_bedrock_embedding_pipeline", + "knn": "true" + } + }, + "mappings": { + "properties": { + "content_embedding": { + "type": "knn_vector", + "dimension": 1024, + "method": { + "name": "hnsw", + "engine": "lucene" + } + }, + "published_date": { + "type": "date" + }, + "rating": { + "type": "integer" + } + } + } +} +``` +{% include copy-curl.html %} + +### Step 1(d): Ingest data into the vector index + +Add research paper documents to the index. The ingest pipeline will automatically generate embeddings for the `content_text` field: + +```json +POST /_bulk +{ "index": { "_index": "research_papers", "_id": "1" } } +{ "content_text": "Autonomous robotic systems for warehouse automation and industrial manufacturing", "published_date": "2024-05-15", "rating": 5 } +{ "index": { "_index": "research_papers", "_id": "2" } } +{ "content_text": "Gene expression analysis and CRISPR-Cas9 genome editing applications in cancer research", "published_date": "2024-06-02", "rating": 4 } +{ "index": { "_index": "research_papers", "_id": "3" } } +{ "content_text": "Reinforcement learning algorithms for sequential decision making and optimization problems", "published_date": "2024-03-20", "rating": 5 } +{ "index": { "_index": "research_papers", "_id": "4" } } +{ "content_text": "Climate change impact on coral reef ecosystems and marine biodiversity conservation", "published_date": "2024-04-10", "rating": 4 } +{ "index": { "_index": "research_papers", "_id": "5" } } +{ "content_text": "Tectonic plate movements and earthquake prediction using geological fault analysis", "published_date": "2024-01-22", "rating": 4 } +``` +{% include copy-curl.html %} + +## Step 2: Configure agentic search + +Next, configure agentic search. + +### Step 2(a): Create a model for agentic search + +Register a model that will be used by both the conversational agent and the `QueryPlanningTool`: + +```json +POST /_plugins/_ml/models/_register +{ + "name": "My OpenAI model: gpt-5", + "function_name": "remote", + "description": "Model for agentic search with neural queries", + "connector": { + "name": "My openai connector: gpt-5", + "description": "The connector to openai chat model", + "version": 1, + "protocol": "http", + "parameters": { + "model": "gpt-5" + }, + "credential": { + "openAI_key": "" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions", + "headers": { + "Authorization": "Bearer ${credential.openAI_key}" + }, + "request_body": "{ \"model\": \"${parameters.model}\", \"messages\": [{\"role\":\"developer\",\"content\":\"${parameters.system_prompt}\"},${parameters._chat_history:-}{\"role\":\"user\",\"content\":\"${parameters.user_prompt}\"}${parameters._interactions:-}], \"reasoning_effort\":\"low\"${parameters.tool_configs:-}}" + } + ] + } +} +``` +{% include copy-curl.html %} + +### Step 2(b): Create an agent with an embedding model ID + +Create an agent with the `embedding_model_id` specified in the agent registration. This allows the agent to automatically generate neural queries when semantic search is needed: + +```json +POST /_plugins/_ml/agents/_register +{ + "name": "GPT 5 Agent for Agentic Search", + "type": "conversational", + "description": "Use this for Agentic Search", + "llm": { + "model_id": "your-agent-model-id", + "parameters": { + "max_iteration": 15, + "embedding_model_id": "your-embedding-model-id-from-step1" + } + }, + "memory": { + "type": "conversation_index" + }, + "parameters": { + "_llm_interface": "openai/v1/chat/completions" + }, + "tools": [ + { + "type": "QueryPlanningTool", + "parameters": { + "model_id": "your-qpt-model-id" + } + } + ], + "app_type": "os_chat" +} +``` +{% include copy-curl.html %} + +### Step 2(c): Create a search pipeline + +Create a search pipeline that uses your agent for agentic search: + +```json +PUT _search/pipeline/my_pipeline +{ + "request_processors": [ + { + "agentic_query_translator": { + "agent_id": "your-agent-id-from-step-2b" + } + } + ] +} +``` +{% include copy-curl.html %} + +## Step 3: Run an agentic search + +Run various configurations of agentic search. + +### Run a semantic search + +Perform agentic search with a question that requires semantic understanding: + +```json +POST /research_papers/_search?search_pipeline=my_pipeline +{ + "query": { + "agentic": { + "query_text": "Show me 3 robots training related research papers " + } + } +} +``` +{% include copy-curl.html %} + +The agent successfully identifies that semantic search is needed. The `ext` object demonstrates that the `QueryPlanningTool` successfully generated a `neural` query using the embedding model ID. The response includes matching research papers ranked by semantic similarity: + +```json +{ + "took": 10509, + "timed_out": false, + "_shards": { + "total": 1, + "successful": 1, + "skipped": 0, + "failed": 0 + }, + "hits": { + "total": { + "value": 5, + "relation": "eq" + }, + "max_score": 0.40031588, + "hits": [ + { + "_index": "research_papers", + "_id": "1", + "_score": 0.40031588, + "_source": { + "content_text": "Autonomous robotic systems for warehouse automation and industrial manufacturing", + "rating": 5, + "content_embedding": [""], + "published_date": "2024-05-15" + } + }, + { + "_index": "research_papers", + "_id": "3", + "_score": 0.36390686, + "_source": { + "content_text": "Reinforcement learning algorithms for sequential decision making and optimization problems", + "rating": 5, + "content_embedding": [""], + "published_date": "2024-03-20" + } + }, + { + "_index": "research_papers", + "_id": "5", + "_score": 0.34401828, + "_source": { + "content_text": "Tectonic plate movements and earthquake prediction using geological fault analysis", + "rating": 4, + "content_embedding": [""], + "published_date": "2024-01-22" + } + } + ] + }, + "ext": { + "agent_steps_summary": "I have these tools available: [ListIndexTool, IndexMappingTool, query_planner_tool]\nFirst I used: ListIndexTool — input: \"[]\"; context gained: \"Found indices; 'research_papers' appears relevant\"\nSecond I used: IndexMappingTool — input: \"[\"research_papers\"]\"; context gained: \"Index has text content and an embedding field suitable for neural search\"\nThird I used: query_planner_tool — qpt.question: \"Show me 3 research papers related to robots training.\"; index_name_provided: \"research_papers\"\nValidation: qpt output is valid and limits results to 3 using neural search with the provided model.", + "memory_id": "jhzpl5kB-5P992SCwOqe", + "dsl_query": "{\"size\":3.0,\"query\":{\"neural\":{\"content_embedding\":{\"model_id\":\"fxzel5kB-5P992SCH-qM\",\"k\":100.0,\"query_text\":\"robots training\"}}}}" + } +} +``` + +### Run a traditional search with filters + +Next, perform agentic search with a question that requires filtering rather than semantic understanding: + +```json +POST /research_papers/_search?search_pipeline=my_pipeline +{ + "query": { + "agentic": { + "query_text": "Show me papers published after 2024 May" + } + } +} +``` +{% include copy-curl.html %} + +The agent recognizes the query as a date-based filter query and generates a traditional `range` query instead of a `neural` query: + +```json +{ + "took": 8522, + "timed_out": false, + "_shards": { + "total": 1, + "successful": 1, + "skipped": 0, + "failed": 0 + }, + "hits": { + "total": { + "value": 1, + "relation": "eq" + }, + "max_score": null, + "hits": [ + { + "_index": "research_papers", + "_id": "2", + "_score": null, + "_source": { + "content_text": "Gene expression analysis and CRISPR-Cas9 genome editing applications in cancer research", + "rating": 4, + "content_embedding": [""], + "published_date": "2024-06-02" + }, + "sort": [ + 1717286400000 + ] + } + ] + }, + "ext": { + "agent_steps_summary": "I have these tools available: [ListIndexTool, IndexMappingTool, query_planner_tool]\nFirst I used: query_planner_tool — qpt.question: \"Show me papers published after May 2024.\"; index_name_provided: \"research_papers\"\nValidation: qpt output is valid JSON and matches the user request with the specified date filter and sorting.", + "memory_id": "vBzyl5kB-5P992SCI-o1", + "dsl_query": "{\"size\":10.0,\"query\":{\"bool\":{\"filter\":[{\"range\":{\"published_date\":{\"gt\":\"2024-05-31T23:59:59Z\"}}}]}},\"sort\":[{\"published_date\":{\"order\":\"desc\"}}]}" + } +} +``` + +### Specify embedding models in query text + +For maximum flexibility, you can register an agent without specifying an embedding model ID and then specify the embedding model ID in the `query_text` directly when sending a query. + +Create an agent without specifying the embedding model ID in the agent parameters: + +```json +POST /_plugins/_ml/agents/_register +{ + "name": "GPT 5 Agent for Agentic Search", + "type": "conversational", + "description": "Use this for Agentic Search", + "llm": { + "model_id": "your-agent-model-id", + "parameters": { + "max_iteration": 15 + } + }, + "memory": { + "type": "conversation_index" + }, + "parameters": { + "_llm_interface": "openai/v1/chat/completions" + }, + "tools": [ + { + "type": "QueryPlanningTool", + "parameters": { + "model_id": "your-qpt-model-id" + } + } + ], + "app_type": "os_chat" +} +``` + +Send an agentic search request that includes the embedding model ID directly in the natural language `query_text`: + +```json +POST /research_papers/_search?search_pipeline=my_pipeline +{ + "query": { + "agentic": { + "query_text": "Show me 3 robots training related research papers use this model id for neural search:fxzel5kB-5P992SCH-qM " + } + } +} +``` +{% include copy-curl.html %} + +The agent successfully extracts the embedding model ID directly from the query text and generates the appropriate neural DSL query: + +```json +{ + "took": 14989, + "timed_out": false, + "_shards": { + "total": 1, + "successful": 1, + "skipped": 0, + "failed": 0 + }, + "hits": { + "max_score": 0.38957736, + "hits": [ + { + "_index": "research_papers", + "_id": "1", + "_score": 0.38957736, + "_source": { + "content_text": "Autonomous robotic systems for warehouse automation and industrial manufacturing", + "rating": 5, + "content_embedding": [], + "published_date": "2024-05-15" + } + }, + { + "_index": "research_papers", + "_id": "3", + "_score": 0.36386627, + "_source": { + "content_text": "Reinforcement learning algorithms for sequential decision making and optimization problems", + "rating": 5, + "content_embedding": [], + "published_date": "2024-03-20" + } + }, + { + "_index": "research_papers", + "_id": "2", + "_score": 0.35789147, + "_source": { + "content_text": "Gene expression analysis and CRISPR-Cas9 genome editing applications in cancer research", + "rating": 4, + "content_embedding": [], + "published_date": "2024-06-02" + } + } + ] + }, + "ext": { + "agent_steps_summary": "I have these tools available: [ListIndexTool, IndexMappingTool, query_planner_tool]\nFirst I used: ListIndexTool — input: \"\"; context gained: \"Found indices, including research_papers with 5 documents\"\nSecond I used: IndexMappingTool — input: \"research_papers\"; context gained: \"Index exists and contains text and embedding fields suitable for neural search\"\nThird I used: query_planner_tool — qpt.question: \"Show me 3 research papers related to robot training.\"; index_name_provided: \"research_papers\"\nValidation: qpt output is valid neural search DSL using the provided model ID and limits results to 3.", + "memory_id": "whz1l5kB-5P992SCPOqn", + "dsl_query": "{\"size\":3.0,\"query\":{\"neural\":{\"content_embedding\":{\"model_id\":\"fxzel5kB-5P992SCH-qM\",\"k\":100.0,\"query_text\":\"research papers related to robot training\"}}},\"sort\":[{\"_score\":{\"order\":\"desc\"}}],\"track_total_hits\":false}" + } +} +``` \ No newline at end of file diff --git a/_vector-search/ai-search/agentic-search/search-templates.md b/_vector-search/ai-search/agentic-search/search-templates.md new file mode 100644 index 00000000000..3c4fa9a686e --- /dev/null +++ b/_vector-search/ai-search/agentic-search/search-templates.md @@ -0,0 +1,477 @@ +--- +layout: default +title: Adding search templates +parent: Agentic search +grand_parent: AI search +nav_order: 100 +has_children: false +--- + +# Adding search templates + +The `QueryPlanningTool` can accept a list of [search templates]({{site.url}}{{site.baseurl}}/search-plugins/search-template/) during its registration. During search, the `QueryPlanningTool` chooses an appropriate search template based on the user's question and template descriptions, and the large language model (LLM) generates a query based on the selected search template. + +This approach allows you to solve complex use cases that would otherwise be challenging for the LLM alone: + +- Enhances query response consistency in agentic search. Most of the query domain-specific language (DSL) query is provided by the search template, with only minor portions or placeholders provided by the LLM. +- Handles complex use cases in which the LLM struggles to generate correct queries. +- Ensures predictable query structure and naming conventions. + +## Best practices + +When creating search templates for agentic search, follow these guidelines: + +- Write detailed descriptions for each template to help the LLM choose appropriately. +- Use descriptive placeholder names that clearly indicate what should be filled. +- Create templates for different query patterns you commonly use. +- Validate that templates work correctly with various inputs before deployment. + +## Step 1: Create an index + +Create a stores index with nested inventory data to demonstrate complex aggregation scenarios: + +```json +PUT /stores +{ + "mappings": { + "properties": { + "store_id": { "type": "keyword" }, + "name": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, + "address": { + "properties": { + "city": { "type": "keyword" }, + "state": { "type": "keyword" } + } + }, + "location": { "type": "geo_point" }, + "inventory": { + "type": "nested", + "properties": { + "sku": { "type": "keyword" }, + "qty": { "type": "integer" } + } + } + } + } +} +``` +{% include copy-curl.html %} + +## Step 2: Ingest documents + +Add sample store documents containing inventory data for different cities and products: + +```json +POST /_bulk +{ "index": { "_index": "stores", "_id": "S-SEA-001" } } +{ "store_id": "S-SEA-001", "name": "Downtown Seattle", "address": { "city": "Seattle", "state": "WA" }, "location": { "lat": 47.608, "lon": -122.335 }, "inventory": [ { "sku": "iphone_17_air", "qty": 12 }, { "sku": "iphone_17", "qty": 11 }, { "sku": "vision_pro", "qty": 3 } ] } +{ "index": { "_index": "stores", "_id": "S-SEA-002" } } +{ "store_id": "S-SEA-002", "name": "Capitol Hill", "address": { "city": "Seattle", "state": "WA" }, "location": { "lat": 47.623, "lon": -122.319 }, "inventory": [ { "sku": "iphone_17_air", "qty": 5 }, { "sku": "iphone_17", "qty": 25 }, { "sku": "vision_pro", "qty": 4 } ] } +{ "index": { "_index": "stores", "_id": "S-SEA-003" } } +{ "store_id": "S-SEA-003", "name": "South Lake Union", "address": { "city": "Seattle", "state": "WA" }, "location": { "lat": 47.626, "lon": -122.338 }, "inventory": [ { "sku": "iphone_17_air", "qty": 6 }, { "sku": "iphone_17", "qty": 9 }, { "sku": "vision_pro", "qty": 20 } ] } +{ "index": { "_index": "stores", "_id": "S-BEL-001" } } +{ "store_id": "S-BEL-001", "name": "Bellevue Square", "address": { "city": "Bellevue", "state": "WA" }, "location": { "lat": 47.616, "lon": -122.203 }, "inventory": [ { "sku": "iphone_17_air", "qty": 14 }, { "sku": "iphone_17", "qty": 4 }, { "sku": "vision_pro", "qty": 1 } ] } +{ "index": { "_index": "stores", "_id": "S-SEA-004" } } +{ "store_id": "S-SEA-004", "name": "Ballard", "address": { "city": "Seattle", "state": "WA" }, "location": { "lat": 47.668, "lon": -122.382 }, "inventory": [ { "sku": "iphone_17_air", "qty": 9 }, { "sku": "iphone_17", "qty": 7 }, { "sku": "vision_pro", "qty": 12 } ] } + +``` +{% include copy-curl.html %} + +## Step 3: Register search templates + +Register a search template that returns stores in a city whose combined inventory across three SKUs meets a minimum threshold: + +```json +POST /_scripts/store_sum_skus +{ + "script": { + "lang": "mustache", + "source": { + "size": 0, + "query": { "term": { "address.city": "{% raw %}{{city}}{% endraw %}" } }, + "aggs": { + "by_store": { + "terms": { + "field": "store_id", + "size": "{% raw %}{{bucket_size}}{{^bucket_size}}200{{/bucket_size}}{% endraw %}", + "order": { "inv>skus>q": "desc" } + }, + "aggs": { + "inv": { + "nested": { "path": "inventory" }, + "aggs": { + "skus": { + "filter": { "terms": { "inventory.sku": ["{% raw %}{{sku1}}{% endraw %}","{% raw %}{{sku2}}{% endraw %}","{% raw %}{{sku3}}{% endraw %}"] } }, + "aggs": { "q": { "sum": { "field": "inventory.qty" } } } + } + } + }, + "keep": { + "bucket_selector": { + "buckets_path": { "t": "inv>skus>q" }, + "script": { "source": "params.t >= {% raw %}{{min_total}}{{^min_total}}30{{/min_total}}{% endraw %}" } + } + }, + "store": { + "top_hits": { + "size": 1, + "_source": { "includes": ["store_id","name","address.city"] } + } + } + } + } + } + } + } +} +``` +{% include copy-curl.html %} + +Register a search template that counts stores in a city that have at least a minimum quantity of a specific SKU: + +```json +POST /_scripts/stores_with_give_sku +{ + "script": { + "lang": "mustache", + "source": { + "size": 0, + "query": { "term": { "address.city": "{% raw %}{{city}}{% endraw %}" } }, + "aggs": { + "s": { + "terms": { + "field": "store_id", + "size": "{% raw %}{{bs}}{{^bs}}200{{/bs}}{% endraw %}" + }, + "aggs": { + "i": { + "nested": { "path": "inventory" }, + "aggs": { + "f": { + "filter": { "term": { "inventory.sku": "{% raw %}{{sku}}{% endraw %}" } }, + "aggs": { "q": { "sum": { "field": "inventory.qty" } } } + } + } + }, + "m": { + "bucket_script": { + "buckets_path": { "x": "i>f>q" }, + "script": { "source": "{% raw %}params.x >= {{min}}{{^min}}10{{/min}} ? 1 : 0{% endraw %}" } + } + } + } + }, + "cnt": { "sum_bucket": { "buckets_path": "s>m" } } + } + } + } +} +``` +{% include copy-curl.html %} + +## Step 4: Register an agent with the QueryPlanningTool + +Next, register an agent with the `QueryPlanningTool`, and configure the tool to use your search templates. + +### Step 4(a): Create a model for the agent and QueryPlanningTool + +Register a model for both the conversational agent and the `QueryPlanningTool`: + +```json +POST /_plugins/_ml/models/_register +{ + "name": "My OpenAI model: gpt-5", + "function_name": "remote", + "description": "Model for agentic search with templates", + "connector": { + "name": "My openai connector: gpt-5", + "description": "The connector to openai chat model", + "version": 1, + "protocol": "http", + "parameters": { + "model": "gpt-5" + }, + "credential": { + "openAI_key": "" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://api.openai.com/v1/chat/completions", + "headers": { + "Authorization": "Bearer ${credential.openAI_key}" + }, + "request_body": "{ \"model\": \"${parameters.model}\", \"messages\": [{\"role\":\"developer\",\"content\":\"${parameters.system_prompt}\"},${parameters._chat_history:-}{\"role\":\"user\",\"content\":\"${parameters.user_prompt}\"}${parameters._interactions:-}], \"reasoning_effort\":\"low\"${parameters.tool_configs:-}}" + } + ] + } +} +``` +{% include copy-curl.html %} + +### Step 4(b): Register an agent with search templates + +Register an agent with the `QueryPlanningTool` configured to use your search templates: + +```json +POST /_plugins/_ml/agents/_register +{ + "name": "Store Search Agent with Templates", + "type": "conversational", + "description": "Agent for store inventory searches using templates", + "llm": { + "model_id": "your-model-id-from-step-4a", + "parameters": { + "max_iteration": 15 + } + }, + "memory": { + "type": "conversation_index" + }, + "parameters": { + "_llm_interface": "openai/v1/chat/completions" + }, + "tools": [ + { + "type": "QueryPlanningTool", + "parameters": { + "model_id": "your-model-id-from-step-4a", + "generation_type": "user_templates", + "search_templates": [ + { + "template_id": "store_sum_skus", + "template_description": "Return stores in a given city where the combined quantity across a list of SKUs meets or exceeds a threshold." + }, + { + "template_id": "stores_with_give_sku", + "template_description": "List stores in a given city that have at least min_qty units of a specific SKU." + } + ] + } + } + ], + "app_type": "os_chat" +} +``` +{% include copy-curl.html %} + +## Step 5: Create a search pipeline + +Create a search pipeline that uses your agent with search templates: + +```json +PUT _search/pipeline/agentic-pipeline +{ + "request_processors": [ + { + "agentic_query_translator": { + "agent_id": "your-agent-id-from-step-4b" + } + } + ], + "response_processors": [ + { + "agentic_context": { + "agent_steps_summary": true, + "dsl_query": true + } + } + ] +} +``` +{% include copy-curl.html %} + +## Step 6: Test a complex question + +Send a complex query that requires advanced aggregations: + +```json +POST /stores/_search?search_pipeline=agentic-pipeline +{ + "query": { + "agentic": { + "query_text": "List all stores in Seattle that have at least 30 combined units across these SKUs: iphone_17_air, iphone_17, and vision_pro." + } + } +} +``` +{% include copy-curl.html %} + +Without search templates, complex queries involving advanced aggregations and scripts often fail because LLMs struggle to generate the correct syntax. For example, if you did not add search templates when creating an agent in Step 4(b), the preceding request would return a script execution error similar to the following: + +
+ + Error response + + {: .text-delta} + +```json +{ + "error": { + "root_cause": [ + { + "type": "script_exception", + "reason": "runtime error", + "script_stack": [ + "for (item in params._source.inventory) { ", + " ^---- HERE" + ], + "script": "int total = 0; for (item in params._source.inventory) { if (params.skus.contains(item.sku)) { if (item.qty instanceof Integer || item.qty instanceof Long) { total += (int)item.qty; } else if (item.qty instanceof String) { try { total += Integer.parseInt(it ...", + "lang": "painless", + "position": { + "offset": 42, + "start": 15, + "end": 56 + } + } + ], + "type": "search_phase_execution_exception", + "reason": "all shards failed", + "phase": "query", + "grouped": true, + "failed_shards": [ + { + "shard": 0, + "index": "stores", + "node": "u3NEXA8PS8W8EJcT_9suGg", + "reason": { + "type": "script_exception", + "reason": "runtime error", + "script_stack": [ + "for (item in params._source.inventory) { ", + " ^---- HERE" + ], + "script": "int total = 0; for (item in params._source.inventory) { if (params.skus.contains(item.sku)) { if (item.qty instanceof Integer || item.qty instanceof Long) { total += (int)item.qty; } else if (item.qty instanceof String) { try { total += Integer.parseInt(it ...", + "lang": "painless", + "position": { + "offset": 42, + "start": 15, + "end": 56 + }, + "caused_by": { + "type": "null_pointer_exception", + "reason": "Cannot invoke \"Object.getClass()\" because \"callArgs[0]\" is null" + } + } + } + ] + }, + "status": 400 +} +``` + +
+ +However, with search templates, the agent can handle sophisticated queries by selecting the appropriate template and filling in the parameters. The LLM correctly identifies and uses the `store_sum_skus` template, fills the template parameters (such as `city: "Seattle"` and `sku1: "iphone_17_air"`), and generates a valid query with nested aggregations and bucket selectors. The response contains stores (`S-SEA-002` and `S-SEA-003`) with a combined inventory of ≥ 30 units: + +```json +{ + "took": 21658, + "timed_out": false, + "terminated_early": true, + "_shards": { + "total": 1, + "successful": 1, + "skipped": 0, + "failed": 0 + }, + "hits": { + "total": { + "value": 4, + "relation": "eq" + }, + "max_score": null, + "hits": [] + }, + "aggregations": { + "by_store": { + "doc_count_error_upper_bound": 0, + "sum_other_doc_count": 0, + "buckets": [ + { + "key": "S-SEA-002", + "doc_count": 1, + "inv": { + "doc_count": 3, + "skus": { + "doc_count": 3, + "sum_qty": { + "value": 34.0 + } + } + }, + "store": { + "hits": { + "total": { + "value": 1, + "relation": "eq" + }, + "max_score": 1.0, + "hits": [ + { + "_index": "stores", + "_id": "S-SEA-002", + "_score": 1.0, + "_source": { + "store_id": "S-SEA-002", + "address": { + "city": "Seattle" + }, + "name": "Capitol Hill" + } + } + ] + } + } + }, + { + "key": "S-SEA-003", + "doc_count": 1, + "inv": { + "doc_count": 3, + "skus": { + "doc_count": 3, + "sum_qty": { + "value": 35.0 + } + } + }, + "store": { + "hits": { + "total": { + "value": 1, + "relation": "eq" + }, + "max_score": 1.0, + "hits": [ + { + "_index": "stores", + "_id": "S-SEA-003", + "_score": 1.0, + "_source": { + "store_id": "S-SEA-003", + "address": { + "city": "Seattle" + }, + "name": "South Lake Union" + } + } + ] + } + } + } + ] + } + }, + "ext": { + "agent_steps_summary": "I have these tools available: [ListIndexTool, IndexMappingTool, query_planner_tool]\nFirst I used: query_planner_tool — qpt.question: \"List all stores in Seattle that have at least a combined total of 30 units across the following SKUs: \\\"iphone_17_air\\\", \\\"iphone_17\\\", and \\\"vision_pro\\\". The location must be Seattle. Sum the inventory counts for only these three SKUs per store and return stores where the sum is greater than or equal to 30.\"; index_name_provided: \"stores\"\nValidation: qpt output is valid JSON; adjusted numeric literals to integers and sizes to integers.", + "memory_id": "-BxpmJkB-5P992SCQ-qU", + "dsl_query":"{\"size\":0.0,\"query\":{\"term\":{\"address.city\":\"Seattle\"}},\"aggs\":{\"by_store\":{\"terms\":{\"field\":\"store_id\",\"size\":200.0},\"aggs\":{\"inv\":{\"nested\":{\"path\":\"inventory\"},\"aggs\":{\"skus\":{\"filter\":{\"terms\":{\"inventory.sku\":[\"iphone_17_air\",\"iphone_17\",\"vision_pro\"]}},\"aggs\":{\"sum_qty\":{\"sum\":{\"field\":\"inventory.qty\"}}}}}},\"keep\":{\"bucket_selector\":{\"buckets_path\":{\"total\":\"inv\>skus\>sum_qty\"},\"script\":{\"source\":\"params.total \>\= 30\"}}},\"store\":{\"top_hits\":{\"size\":1.0,\"_source\":{\"includes\":[\"store_id\",\"name\",\"address.city\"]}}}}}}}" + } +} +``` + +## Related documentation + +- [Search templates]({{site.url}}{{site.baseurl}}/search-plugins/search-template/) diff --git a/_vector-search/ai-search/building-agentic-search-flows.md b/_vector-search/ai-search/building-agentic-search-flows.md new file mode 100644 index 00000000000..9890570ad54 --- /dev/null +++ b/_vector-search/ai-search/building-agentic-search-flows.md @@ -0,0 +1,51 @@ +--- +layout: default +title: Configuring agentic search +parent: Building AI search workflows in OpenSearch Dashboards +grand_parent: AI search +nav_order: 20 +--- + +# Configuring agentic search +**Introduced 3.3** +{: .label .label-purple } + +This is an experimental UI feature. For updates on the progress of the feature or if you want to leave feedback, join the discussion on the [OpenSearch forum](https://forum.opensearch.org/). +{: .warning} + +[Agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/) lets you ask questions in natural language and have OpenSearch agents plan and execute the retrieval automatically. OpenSearch Dashboards offers an intuitive UI for configuring agents, equipping agents with different tools, and executing agentic searches. + +## Prerequisites + +Before configuring agentic search, ensure that you fulfill the following prerequisites. + +### Provision ML resources + +To configure new agents, be sure to first provision appropriate models. For working examples, see [Model configuration]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/agent-customization/#model-configuration). + +### Ingest data + +Ensure that you have a sufficient number of documents in your cluster to reasonably evaluate your agentic searches. For more information, see [Agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/). + +## Example: Product search with GPT-5 + +This example uses a deployed OpenAI GPT-5 model described in [this documentation]({{site.url}}{{site.baseurl}}/vector-search/ai-search/agentic-search/agent-customization/#gpt-5-recommended). +{: .note} + +To build and test your agentic search workflow in OpenSearch Dashboards, follow these steps: + +1. Go to **OpenSearch Dashboards** and select **OpenSearch Plugins** > **AI Search Flows** from the top menu. +1. On the **Workflows** page, select the **New workflow** tab, as shown in the following image. In the **Agentic Search** template, select **Create**. + ![New workflow page]({{site.url}}{{site.baseurl}}/images/dashboards-flow-framework/new-workflow-page.png) +1. Provide a unique workflow **Name** and an optional **Description**, as shown in the following image. Then select **Create** to create your workflow. You are automatically directed to the workflow editor, where you can begin configuring the agent. + ![Quick configure modal]({{site.url}}{{site.baseurl}}/images/dashboards-flow-framework/agentic-search-quick-configure-modal.png) +1. Under **Configure agent**, select **Create new agent**, as shown in the following image. Once you configure an agent, you can select or update existing agents. For full agent customization, toggle to the `JSON` view and edit directly. + ![Agentic search workflow editor]({{site.url}}{{site.baseurl}}/images/dashboards-flow-framework/agentic-search-editor.png) +1. Under **Agent**, enter a unique **Name** and **Description** for the agent, as shown in the following image. Under **Tools** > **Query Planning** > **Query planning model**, select **OpenAI GPT-5**. Then select **Create agent**. + ![Agent configuration]({{site.url}}{{site.baseurl}}/images/dashboards-flow-framework/agent-configuration.png) +1. Under **Test flow** > **Index**, select the index you'd like to search, as shown in the following image. Under **Test flow** > **Query**, enter a natural language query. Optionally, specify query fields for the agent to search in your selected index. To edit the full `agentic` search query directly, toggle to the `JSON` view. Then select **Search**. The agent may take several seconds to execute. + ![Agent searching]({{site.url}}{{site.baseurl}}/images/dashboards-flow-framework/agent-searching.png) +1. Under **Generated query**, view the query domain-specific language (DSL) that the agent generated and ran against your cluster. + ![Agent query]({{site.url}}{{site.baseurl}}/images/dashboards-flow-framework/agentic-search-agent-query.png) +1. Under **Search results**, select **Raw response**, the formatted table of **Hits**, or **Aggregations** to view the results. + ![Search results]({{site.url}}{{site.baseurl}}/images/dashboards-flow-framework/agentic-search-results.png) diff --git a/_vector-search/ai-search/workflow-builder.md b/_vector-search/ai-search/workflow-builder.md index 94fb1e229a5..8e9da457c9e 100644 --- a/_vector-search/ai-search/workflow-builder.md +++ b/_vector-search/ai-search/workflow-builder.md @@ -13,7 +13,11 @@ redirect_from: # Building AI search workflows in OpenSearch Dashboards -In OpenSearch Dashboards, you can iteratively build and test workflows containing ingest and search pipelines using AI Search Flows. Using a UI editor to build workflows simplifies the creation of artificial intelligence and machine learning (AI/ML) use cases that include ML inference processors, such as vector search and retrieval-augmented generation (RAG). For example configurations of available AI search types (including semantic search, hybrid search, RAG, and multimodal search), see [Configuring AI search types]({{site.url}}{{site.baseurl}}/vector-search/ai-search/building-flows/). +In OpenSearch Dashboards, you can iteratively build and test workflows containing ingest and search pipelines using AI Search Flows. Using a UI editor to build workflows simplifies the creation of artificial intelligence and machine learning (AI/ML) use cases that include ML inference processors, such as vector search and retrieval-augmented generation (RAG). + +For example configurations of available AI search types (including semantic search, hybrid search, RAG, and multimodal search), see [Configuring AI search types]({{site.url}}{{site.baseurl}}/vector-search/ai-search/building-flows/). + +For examples of configuring agentic search flows, see [Configuring agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/building-agentic-search-flows/). Once your workflow is finalized, you can export it as a [workflow template]({{site.url}}{{site.baseurl}}/automating-configurations/workflow-templates/) to recreate identical resources across multiple clusters. @@ -57,7 +61,6 @@ The workflow editor is organized like an integrated development environment (IDE - **Resources**: Lists OpenSearch resources linked to the workflow, including up to one ingest pipeline, one index, and one search pipeline. To view resource details, select **Inspect**. - **Preview**: A read-only visualization of how data moves through your ingest and search flows. As you make changes to your flow, this view updates automatically. You can also switch to the **JSON** tab to see the underlying template configuration. - ## Example: Semantic search with RAG The following example uses a deployed [Titan Text Embedding](https://docs.aws.amazon.com/bedrock/latest/userguide/titan-embedding-models.html) model and an [Anthropic Claude model hosted on Amazon Bedrock](https://aws.amazon.com/bedrock/claude/) to build an [ingest pipeline]({{site.url}}{{site.baseurl}}/ingest-pipelines/), [index]({{site.url}}{{site.baseurl}}/getting-started/intro/#index), and [search pipeline]({{site.url}}{{site.baseurl}}/search-plugins/search-pipelines/index/) for performing vector search and RAG. @@ -107,10 +110,12 @@ We strongly recommend using models with full model interfaces. For a list of exa ![Test search flow]({{site.url}}{{site.baseurl}}/images/dashboards-flow-framework/search-test-flow.png) 12. To view the search results, select **Run test**. You can view the results either as a formatted list of hits or as the raw JSON search response. 13. Depending on your use case, you can modify configurations in the following ways: + - Experiment with different query parameters. - Try different queries. - Modify existing processors under **Transform query** or **Transform results**. - Add or remove processors under **Transform query** or **Transform results**. + 14. To export your workflow, select **Export** in the header. The displayed data represents the [Workflow template]({{site.url}}{{site.baseurl}}/automating-configurations/workflow-templates/), which contains the full configuration for the OpenSearch resources you've created, including the ingest pipeline, index, and search pipeline. You can download the template in JSON or YAML format by selecting the button on the right. To build identical resources in other OpenSearch clusters, use the [Provision Workflow API]({{site.url}}{{site.baseurl}}/automating-configurations/api/provision-workflow/). ## Advanced data transformations @@ -135,3 +140,5 @@ In **Outputs**, you can configure the values passed _from_ the model. There are - For models and model interfaces recommended for use with AI Search Flows, see [Models](https://github.com/opensearch-project/dashboards-flow-framework/blob/main/documentation/models.md). - For example configurations for different AI/ML use cases, see [Configuring AI search types]({{site.url}}{{site.baseurl}}/tutorials/ai-search-flows/building-flows/). + +- For examples of configuring agentic search flows, see [Configuring agentic search]({{site.url}}{{site.baseurl}}/vector-search/ai-search/building-agentic-search-flows/). diff --git a/images/dashboards-flow-framework/agent-configuration.png b/images/dashboards-flow-framework/agent-configuration.png new file mode 100644 index 00000000000..bc8175257e6 Binary files /dev/null and b/images/dashboards-flow-framework/agent-configuration.png differ diff --git a/images/dashboards-flow-framework/agent-searching.png b/images/dashboards-flow-framework/agent-searching.png new file mode 100644 index 00000000000..521c3f473a0 Binary files /dev/null and b/images/dashboards-flow-framework/agent-searching.png differ diff --git a/images/dashboards-flow-framework/agentic-search-agent-query.png b/images/dashboards-flow-framework/agentic-search-agent-query.png new file mode 100644 index 00000000000..b0174910f7d Binary files /dev/null and b/images/dashboards-flow-framework/agentic-search-agent-query.png differ diff --git a/images/dashboards-flow-framework/agentic-search-editor.png b/images/dashboards-flow-framework/agentic-search-editor.png new file mode 100644 index 00000000000..96c5a944511 Binary files /dev/null and b/images/dashboards-flow-framework/agentic-search-editor.png differ diff --git a/images/dashboards-flow-framework/agentic-search-quick-configure-modal.png b/images/dashboards-flow-framework/agentic-search-quick-configure-modal.png new file mode 100644 index 00000000000..ffbf85c86dc Binary files /dev/null and b/images/dashboards-flow-framework/agentic-search-quick-configure-modal.png differ diff --git a/images/dashboards-flow-framework/agentic-search-results.png b/images/dashboards-flow-framework/agentic-search-results.png new file mode 100644 index 00000000000..79450ff1e05 Binary files /dev/null and b/images/dashboards-flow-framework/agentic-search-results.png differ diff --git a/images/dashboards-flow-framework/new-workflow-page.png b/images/dashboards-flow-framework/new-workflow-page.png index e51c42ec7d8..5daaef1dafd 100644 Binary files a/images/dashboards-flow-framework/new-workflow-page.png and b/images/dashboards-flow-framework/new-workflow-page.png differ