Query Planning tool
plugins.ml_commons.agentic_search_enabled: true
Introduced in 3.2
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.
The QueryPlanningTool
generates an OpenSearch query domain-specific language (DSL) query from a natural language question.
Step 1: Enable the agentic search feature flag
To use the QueryPlanningTool
, you must first enable the agentic_search_enabled
setting:
PUT _cluster/settings
{
"persistent" : {
"plugins.ml_commons.agentic_search_enabled" : true
}
}
OpenSearch responds with an acknowledgment:
{
"acknowledged": true,
"persistent": {
"plugins": {
"ml_commons": {
"agentic_search_enabled": "true"
}
}
},
"transient": {}
}
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
, andsession_token
with your own values. - You can use any model that supports the
converse
API, such as Claude 3.7 Sonnet. - You can also use other model providers by referencing the supported connector blueprints.
POST /_plugins/_ml/models/_register?deploy=true
{
"name": "agentic_search_base_model",
"function_name": "remote",
"description": "Agentic search base model",
"connector": {
"name": "Amazon Bedrock Claude 3.7 Sonnet Connector",
"description": "Connector for the base agent with tools",
"version": 1,
"protocol": "aws_sigv4",
"parameters": {
"region": "us-east-1",
"service_name": "bedrock",
"model": "anthropic.claude-3-sonnet-20240229-v1:0",
"system_prompt": "Please help answer the user question."
},
"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}/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:-} }"
}
]
}
}
OpenSearch responds with the model ID:
{
"task_id": "_9iSxJgBOh0h20Y9XYTH",
"status": "CREATED",
"model_id": "ANiSxJgBOh0h20Y9XYXl"
}
Step 3: Register an agent
You can use any OpenSearch agent type 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.
When registering the agent, you can override parameters set during model registration, such as system_prompt
.
POST /_plugins/_ml/agents/_register
{
"name": "Agentic Search with Claude 3.7",
"type": "flow",
"description": "A test agent for query planning.",
"tools": [
{
"type": "QueryPlanningTool",
"description": "A general tool to answer any question.",
"parameters": {
"model_id": "ANiSxJgBOh0h20Y9XYXl",
"response_filter": "$.output.message.content[0].text"
}
}
]
}
For parameter descriptions, see Register parameters.
OpenSearch responds with an agent ID:
{
"agent_id": "RNjQi5gBOh0h20Y9-RX1"
}
Step 4: Execute the agent
Execute the agent by sending the following request:
POST /_plugins/_ml/agents/RNjQi5gBOh0h20Y9-RX1/_execute
{
"parameters": {
"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.query_text}, 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\"}}} \n",
"query_text": "How many iris flowers of type setosa are there?"
}
}
OpenSearch returns the inference results, which include the generated query DSL:
{
"inference_results": [
{
"output": [
{
"name": "response",
"result": "{'query':{'term':{'species':'setosa'}}}"
}
]
}
]
}
Register parameters
The following table lists all tool parameters that are available when registering an agent.
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. |
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. Currently, only llmGenerated is supported. Defaults to llmGenerated . |
system_prompt | String | Optional | A system prompt that provides high-level instructions to the LLM. Defaults to “You are an OpenSearch Query DSL generation assistant, translating natural language questions to OpenSeach DSL Queries”. |
user_prompt | String | Optional | A user prompt template for the LLM. It can contain placeholders for execution-time parameters like ${parameters.query_text} . |
Execute parameters
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.
There are three layers of parameters to consider:
-
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.user_prompt}
. The names of these variables depend on the specific model’s API. TheQueryPlanningTool
provides values for these variables. -
Tool parameters: The
QueryPlanningTool
uses its own set of parameters, such asuser_prompt
andsystem_prompt
, to construct the final string that will be passed to the connector. The tool takes theuser_prompt
string and resolves any variables within it, and the resulting string is then used to fill the appropriate variable (for example,${parameters.user_prompt}
) in the connector’srequest_body
. -
Prompt variables: These are the variables inside the
user_prompt
, which have the format${parameters.your_variable_name}
. These must be provided in the_execute
API call. For example, if youruser_prompt
is “Generate a query for: ${parameters.query_text}”, then you must provide aquery_text
parameter when you run the agent.
In summary, the required parameters for an _execute
call are the prompt variables. The tool’s own parameters (like user_prompt
) can be overridden at execution time to change how the final prompt is constructed.
For example, if you are using the default user_prompt
, it contains the variable ${parameters.question}
. Therefore, question
becomes a required execution parameter:
POST /_plugins/_ml/agents/your_agent_id/_execute
{
"parameters": {
"question": "How many iris flowers of type setosa are there?"
}
}
Improving query accuracy
To help the language model generate more accurate query DSL, you can provide additional context within the user_prompt
. This context can include information like:
- Index mappings.
- Relevant field names.
- Sample documents or queries.
You can pass this information by defining variables in your user_prompt
and providing the corresponding values in the parameters
of your _execute
call.
Example of an enriched user_prompt
Here is an example of how you can structure a user_prompt
to include an index mapping and guide the model to generate a more precise query:
POST /_plugins/_ml/agents/your_agent_id/_execute
{
"parameters": {
"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\"}}}"
}
}
Note: 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.
Next steps
This is an experimental feature. See the following GitHub issues for information about future enhancements: