diff --git a/sample-templates/README.md b/sample-templates/README.md new file mode 100644 index 000000000..939574c5a --- /dev/null +++ b/sample-templates/README.md @@ -0,0 +1,33 @@ +## Flow Framework Sample Templates + +This folder contains sample workflow templates that can be used with Flow Framework. + +Each template is provided in both YAML and JSON format with identical functionality. +The YAML templates include comments which give more insight into the template's usage. +Use the corresponding `Content-Type` (`application/yaml` or `application/json`) when providing them as the body of a REST request. + +You will need to update the `credentials` field with appropriate API keys. + +To create a workflow and provision the resources: + +``` +POST /_plugins/_flow_framework/workflow?provision=true +{ template as body } +``` + +This will return a `workflow_id`. To get the IDs of created resources, call the workflow status API. + +``` +GET /_plugins/_flow_framework/workflow//_status +``` + +For the Query Assist Agent API, the `agent_id` of the `root_agent` can be used to query it. + +``` +POST /_plugins/_ml/agents/_/_execute +{ + "parameters": { + "question": "How many 5xx logs do I have?" + } +} +``` \ No newline at end of file diff --git a/sample-templates/deploy-bedrock-claude-model.json b/sample-templates/deploy-bedrock-claude-model.json new file mode 100644 index 000000000..c7f4b22f4 --- /dev/null +++ b/sample-templates/deploy-bedrock-claude-model.json @@ -0,0 +1,72 @@ +{ + "name": "Deploy Claude Model", + "description": "Deploy a model using a connector to Claude", + "use_case": "PROVISION", + "version": { + "template": "1.0.0", + "compatibility": [ + "2.12.0", + "3.0.0" + ] + }, + "workflows": { + "provision": { + "nodes": [ + { + "id": "create_claude_connector", + "type": "create_connector", + "user_inputs": { + "name": "Claude Instant Runtime Connector", + "version": "1", + "protocol": "aws_sigv4", + "description": "The connector to BedRock service for Claude model", + "actions": [ + { + "headers": { + "x-amz-content-sha256": "required", + "content-type": "application/json" + }, + "method": "POST", + "request_body": "{ \"prompt\":\"${parameters.prompt}\", \"max_tokens_to_sample\":${parameters.max_tokens_to_sample}, \"temperature\":${parameters.temperature}, \"anthropic_version\":\"${parameters.anthropic_version}\" }", + "action_type": "predict", + "url": "https://bedrock-runtime.us-west-2.amazonaws.com/model/anthropic.claude-instant-v1/invoke" + } + ], + "credential": { + "access_key": "PUT_YOUR_ACCESS_KEY_HERE", + "secret_key": "PUT_YOUR_SECRET_KEY_HERE" + }, + "parameters": { + "endpoint": "bedrock-runtime.us-west-2.amazonaws.com", + "content_type": "application/json", + "auth": "Sig_V4", + "max_tokens_to_sample": "8000", + "service_name": "bedrock", + "temperature": "0.0001", + "response_filter": "$.completion", + "region": "us-west-2", + "anthropic_version": "bedrock-2023-05-31" + } + } + }, + { + "id": "register_claude_model", + "type": "register_remote_model", + "previous_node_inputs": { + "create_claude_connector": "connector_id" + }, + "user_inputs": { + "name": "claude-instant" + } + }, + { + "id": "deploy_claude_model", + "type": "deploy_model", + "previous_node_inputs": { + "register_claude_model": "model_id" + } + } + ] + } + } +} diff --git a/sample-templates/deploy-bedrock-claude-model.yml b/sample-templates/deploy-bedrock-claude-model.yml new file mode 100644 index 000000000..d10caa601 --- /dev/null +++ b/sample-templates/deploy-bedrock-claude-model.yml @@ -0,0 +1,76 @@ +# This template creates a connector to the BedRock service for Claude model +# It then registers a model using that connector and deploys it. +# +# To use: +# - update the "credential" fields under the create_claude_connector node. +# - if needed, update region +# +# After provisioning: +# - returns a workflow ID +# - use the status API to get the deployed model ID +--- +name: Deploy Claude Model +description: Deploy a model using a connector to Claude +use_case: PROVISION +version: + template: 1.0.0 + compatibility: + - 2.12.0 + - 3.0.0 +# This section defines the provision workflow. Nodes are connected in a graph. +# Either previous_node_inputs or explicit edges can be used to enforce ordering. +workflows: + provision: + # Each id field in a workflow must be unique. + nodes: + - id: create_claude_connector + type: create_connector + user_inputs: + name: Claude Instant Runtime Connector + version: '1' + protocol: aws_sigv4 + description: The connector to BedRock service for Claude model + actions: + - headers: + x-amz-content-sha256: required + content-type: application/json + method: POST + request_body: '{ + "prompt":"${parameters.prompt}", + "max_tokens_to_sample":${parameters.max_tokens_to_sample}, + "temperature":${parameters.temperature}, "anthropic_version":"${parameters.anthropic_version}" + }' + action_type: predict + url: https://bedrock-runtime.us-west-2.amazonaws.com/model/anthropic.claude-instant-v1/invoke + credential: + access_key: 'PUT_YOUR_ACCESS_KEY_HERE' + secret_key: 'PUT_YOUR_SECRET_KEY_HERE' + parameters: + endpoint: bedrock-runtime.us-west-2.amazonaws.com + content_type: application/json + auth: Sig_V4 + max_tokens_to_sample: '8000' + service_name: bedrock + temperature: '0.0001' + response_filter: "$.completion" + region: us-west-2 + anthropic_version: bedrock-2023-05-31 + - id: register_claude_model + type: register_remote_model + previous_node_inputs: + create_claude_connector: connector_id + user_inputs: + name: claude-instant + # Using deploy: true here would both registers and deploy the model + # and the deploy model step below could be deleted + # deploy: true + - id: deploy_claude_model + type: deploy_model + previous_node_inputs: + register_claude_model: model_id + # Because the above nodes use previous_node_inputs, these edges are automatically generated. + # edges: + # - source: create_claude_connector + # dest: register_claude_model + # - source: register_claude_model + # dest: deploy_claude_model diff --git a/sample-templates/deploy-openai-model.json b/sample-templates/deploy-openai-model.json new file mode 100644 index 000000000..ab4515486 --- /dev/null +++ b/sample-templates/deploy-openai-model.json @@ -0,0 +1,60 @@ +{ + "name": "Deploy OpenAI Model", + "description": "Deploy a model using a connector to OpenAI", + "use_case": "PROVISION", + "version": { + "template": "1.0.0", + "compatibility": [ + "2.12.0", + "3.0.0" + ] + }, + "workflows": { + "provision": { + "nodes": [ + { + "id": "create_openai_connector", + "type": "create_connector", + "user_inputs": { + "name": "OpenAI Chat Connector", + "description": "The connector to public OpenAI model service for GPT 3.5", + "version": "1", + "protocol": "http", + "parameters": { + "endpoint": "api.openai.com", + "model": "gpt-3.5-turbo", + "response_filter": "$.choices[0].message.content" + }, + "credential": { + "openAI_key": "PUT_YOUR_API_KEY_HERE" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://${parameters.endpoint}/v1/chat/completions" + } + ] + } + }, + { + "id": "register_openai_model", + "type": "register_remote_model", + "previous_node_inputs": { + "create_openai_connector": "connector_id" + }, + "user_inputs": { + "name": "openAI-gpt-3.5-turbo" + } + }, + { + "id": "deploy_openai_model", + "type": "deploy_model", + "previous_node_inputs": { + "register_openai_model": "model_id" + } + } + ] + } + } +} diff --git a/sample-templates/deploy-openai-model.yml b/sample-templates/deploy-openai-model.yml new file mode 100644 index 000000000..fe70c398e --- /dev/null +++ b/sample-templates/deploy-openai-model.yml @@ -0,0 +1,60 @@ +# This template creates a connector to the public OpenAI model service for GPT 3.5 +# It then registers a model using that connector and deploys it. +# +# To use: +# - update the "credential" field under the create_openai_connector node. +# +# After provisioning: +# - returns a workflow ID +# - use the status API to get the deployed model ID +--- +name: Deploy OpenAI Model +description: Deploy a model using a connector to OpenAI +use_case: PROVISION +version: + template: 1.0.0 + compatibility: + - 2.12.0 + - 3.0.0 +# This section defines the provision workflow. Nodes are connected in a graph. +# Either previous_node_inputs or explicit edges can be used to enforce ordering. +workflows: + provision: + # Each id field in a workflow must be unique. + nodes: + - id: create_openai_connector + type: create_connector + user_inputs: + name: OpenAI Chat Connector + description: The connector to public OpenAI model service for GPT 3.5 + version: '1' + protocol: http + parameters: + endpoint: api.openai.com + model: gpt-3.5-turbo + response_filter: '$.choices[0].message.content' + credential: + openAI_key: 'PUT_YOUR_API_KEY_HERE' + actions: + - action_type: predict + method: POST + url: https://${parameters.endpoint}/v1/chat/completions + - id: register_openai_model + type: register_remote_model + previous_node_inputs: + create_openai_connector: connector_id + user_inputs: + name: openAI-gpt-3.5-turbo + # Using deploy: true here would both registers and deploy the model + # and the deploy model step below could be deleted + # deploy: true + - id: deploy_openai_model + type: deploy_model + previous_node_inputs: + register_openai_model: model_id + # Because the above nodes use previous_node_inputs, these edges are automatically generated. + # edges: + # - source: create_openai_connector + # dest: register_openai_model + # - source: register_openai_model + # dest: deploy_openai_model diff --git a/sample-templates/deploy-sagemaker-mistral-model.json b/sample-templates/deploy-sagemaker-mistral-model.json new file mode 100644 index 000000000..dcded5472 --- /dev/null +++ b/sample-templates/deploy-sagemaker-mistral-model.json @@ -0,0 +1,64 @@ +{ + "name": "Deploy Mistral Model", + "description": "Deploy a model using a connector to SageMaker Mistral model", + "use_case": "PROVISION", + "version": { + "template": "1.0.0", + "compatibility": [ + "2.12.0", + "3.0.0" + ] + }, + "workflows": { + "provision": { + "nodes": [ + { + "id": "create_mistral_connector", + "type": "create_connector", + "user_inputs": { + "name": "sagemaker: mistral", + "description": "Test connector for Sagemaker mistral model", + "version": "1", + "protocol": "aws_sigv4", + "credential": { + "access_key": "PUT_YOUR_ACCESS_KEY_HERE", + "secret_key": "PUT_YOUR_SECRET_KEY_HERE" + }, + "parameters": { + "region": "us-east-1", + "service_name": "sagemaker" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "headers": { + "content-type": "application/json" + }, + "url": "https://PUT_YOUR_CUSTOM_SAGEMAKER_ENDPOINT_HERE", + "request_body": "{\"prompt\":\"${parameters.prompt}\"}" + } + ] + } + }, + { + "id": "register_mistral_model", + "type": "register_remote_model", + "previous_node_inputs": { + "create_mistral_connector": "connector_id" + }, + "user_inputs": { + "name": "mistral fine-tuned model" + } + }, + { + "id": "deploy_mistral_model", + "type": "deploy_model", + "previous_node_inputs": { + "register_mistral_model": "model_id" + } + } + ] + } + } +} diff --git a/sample-templates/deploy-sagemaker-mistral-model.yml b/sample-templates/deploy-sagemaker-mistral-model.yml new file mode 100644 index 000000000..f1d2e6cef --- /dev/null +++ b/sample-templates/deploy-sagemaker-mistral-model.yml @@ -0,0 +1,65 @@ +# This template creates a connector to the SageMaker service for a Mistral model +# It then registers a model using that connector and deploys it. +# +# To use: +# - update the "credential" fields under the create_mistral_connector node. +# - update the sagemaker endpoint +# - if needed, update region +# +# After provisioning: +# - returns a workflow ID +# - use the status API to get the deployed model ID +--- +name: Deploy Mistral Model +description: Deploy a model using a connector to SageMaker Mistral model +use_case: PROVISION +version: + template: 1.0.0 + compatibility: + - 2.12.0 + - 3.0.0 +# This section defines the provision workflow. Nodes are connected in a graph. +# Either previous_node_inputs or explicit edges can be used to enforce ordering. +workflows: + provision: + # Each id field in a workflow must be unique. + nodes: + - id: create_mistral_connector + type: create_connector + user_inputs: + name: 'sagemaker: mistral' + description: Test connector for Sagemaker mistral model + version: '1' + protocol: aws_sigv4 + credential: + access_key: 'PUT_YOUR_ACCESS_KEY_HERE' + secret_key: 'PUT_YOUR_SECRET_KEY_HERE' + parameters: + region: us-east-1 + service_name: sagemaker + actions: + - action_type: predict + method: POST + headers: + content-type: application/json + url: 'https://PUT_YOUR_CUSTOM_SAGEMAKER_ENDPOINT_HERE' + request_body: '{"prompt":"${parameters.prompt}"}' + - id: register_mistral_model + type: register_remote_model + previous_node_inputs: + create_mistral_connector: connector_id + user_inputs: + name: mistral fine-tuned model + # Using deploy: true here would both registers and deploy the model + # and the deploy model step below could be deleted + # deploy: true + - id: deploy_mistral_model + type: deploy_model + previous_node_inputs: + register_mistral_model: model_id + # Because the above nodes use previous_node_inputs, these edges are automatically generated. + # edges: + # - source: create_mistral_connector + # dest: register_mistral_model + # - source: register_mistral_model + # dest: deploy_mistral_model diff --git a/sample-templates/observability-chat-agent.json b/sample-templates/observability-chat-agent.json new file mode 100644 index 000000000..0b80aa70b --- /dev/null +++ b/sample-templates/observability-chat-agent.json @@ -0,0 +1,298 @@ +{ + "name": "Observability Chat Agent", + "description": "Create an Observability Chat Agent using OpenAI GPT 3.5 model", + "use_case": "REGISTER_AGENT", + "version": { + "template": "1.0.0", + "compatibility": [ + "2.12.0", + "3.0.0" + ] + }, + "workflows": { + "provision": { + "nodes": [ + { + "id": "create_openai_connector", + "type": "create_connector", + "user_inputs": { + "name": "OpenAI Chat Connector", + "description": "The connector to public OpenAI model service for GPT 3.5", + "version": "1", + "protocol": "http", + "parameters": { + "endpoint": "api.openai.com", + "model": "gpt-3.5-turbo" + }, + "credential": { + "openAI_key": "PUT_YOUR_API_KEY_HERE" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://${parameters.endpoint}/v1/chat/completions" + } + ] + } + }, + { + "id": "register_openai_model", + "type": "register_remote_model", + "previous_node_inputs": { + "create_openai_connector": "connector_id" + }, + "user_inputs": { + "name": "openAI-gpt-3.5-turbo", + "deploy": true + } + }, + { + "id": "register_sparse_model", + "type": "register_local_custom_model", + "user_inputs": { + "name": "neural-sparse/opensearch-neural-sparse-tokenizer-v1", + "version": "1.0.0", + "description": "This is a neural sparse tokenizer model: It tokenize input sentence into tokens and assign pre-defined weight from IDF to each. It serves only in query.", + "function_name": "SPARSE_TOKENIZE", + "model_format": "TORCH_SCRIPT", + "model_content_size_in_bytes": 567691, + "model_content_hash_value": "b3487da9c58ac90541b720f3b367084f271d280c7f3bdc3e6d9c9a269fb31950", + "created_time": 1696913667239, + "model_type": "sparse", + "embedding_dimension": "1", + "framework_type": "sentence_transformers", + "url": "https://artifacts.opensearch.org/models/ml-models/amazon/neural-sparse/opensearch-neural-sparse-tokenizer-v1/1.0.0/torch_script/opensearch-neural-sparse-tokenizer-v1-1.0.0.zip" + } + }, + { + "id": "deploy_sparse_model", + "type": "deploy_model", + "previous_node_inputs": { + "register_sparse_model": "model_id" + } + }, + { + "id": "cat_index_tool", + "type": "create_tool", + "user_inputs": { + "type": "CatIndexTool", + "name": "CatIndexTool", + "parameters": { + } + } + }, + { + "id": "index_mapping_tool", + "type": "create_tool", + "user_inputs": { + "type": "IndexMappingTool", + "name": "IndexMappingTool", + "parameters": { + } + } + }, + { + "id": "visualization_tool", + "type": "create_tool", + "user_inputs": { + "include_output_in_agent_response": true, + "type": "VisualizationTool", + "name": "VisualizationTool", + "parameters": { + "index": ".kibana" + } + } + }, + { + "id": "search_alerts_tool", + "type": "create_tool", + "user_inputs": { + "type": "SearchAlertsTool", + "name": "SearchAlertsTool", + "parameters": { + } + } + }, + { + "id": "search_monitors_tool", + "type": "create_tool", + "user_inputs": { + "type": "SearchMonitorsTool", + "name": "SearchMonitorsTool", + "parameters": { + } + } + }, + { + "id": "search_anomoly_detectors_tool", + "type": "create_tool", + "user_inputs": { + "type": "SearchAnomalyDetectorsTool", + "name": "SearchAnomalyDetectorsTool", + "parameters": { + } + } + }, + { + "id": "search_anomoly_results_tool", + "type": "create_tool", + "user_inputs": { + "type": "SearchAnomalyResultsTool", + "name": "SearchAnomalyResultsTool", + "parameters": { + } + } + }, + { + "id": "vector_db_tool", + "type": "create_tool", + "user_inputs": { + "type": "VectorDBTool", + "name": "VectorDBTool", + "parameters": { + "model_id": "ksNnFo0BY4jgIz2mWrHU", + "index": "my_test_data", + "embedding_field": "embedding", + "source_field": "[\"text\"]", + "input": "${parameters.question}" + } + } + }, + { + "id": "rag_tool", + "type": "create_tool", + "user_inputs": { + "type": "RAGTool", + "name": "RAGTool", + "parameters": { + "inference_model_id": "${{ register_openai_model.model_id }}", + "embedding_model_id": "ksNnFo0BY4jgIz2mWrHU", + "index": "my_test_data", + "embedding_field": "embedding", + "source_field": "[\"text\"]", + "input": "${parameters.question}", + "prompt": "\n\nHuman:\" turn\" You are a professional data analysist. You will always answer question based on the given context first. If the answer is not directly shown in the context, you will analyze the data and find the answer. If you don't know the answer, just say don't know. \n\n Context:\n${parameters.output_field}\n\nHuman:${parameters.input}\n\nAssistant:" + } + } + }, + { + "id": "neural_sparse_knowledge_base_tool", + "type": "create_tool", + "previous_node_inputs": { + "deploy_sparse_model": "model_id" + }, + "user_inputs": { + "name": "OpensearchKnowledgeBaseTool", + "type": "NeuralSparseSearchTool", + "description": "A tool to search the Opensearch knowledge base, the knowledge base consists of segments of OpenSearch documents. You should always search data with this tool when encountering general questions about Opensearch. But for questions about current concerete cluster, use this tool can not help you. If this tool provides useful info, give the answer and also quote the origin doc. If this tool can not provide knowledge you need, give answer based on your own knowledge. Action Input: ", + "parameters": { + "index": "knowledge_base", + "embedding_field": "sparse_embedding", + "source_field": "[\"title\",\"body\"]", + "doc_size": "10", + "input": "${parameters.question}" + } + } + }, + { + "id": "sub_agent", + "type": "register_agent", + "previous_node_inputs": { + "index_mapping_tool": "tools", + "cat_index_tool": "tools", + "visualization_tool": "tools", + "search_alerts_tool": "tools", + "search_monitors_tool": "tools", + "search_anomoly_detectors_tool": "tools", + "search_anomoly_results_tool": "tools", + "vector_db_tool": "tools", + "rag_tool": "tools", + "neural_sparse_knowledge_base_tool": "tools", + "register_openai_model": "model_id" + }, + "user_inputs": { + "parameters": { + }, + "app_type": "chatbot", + "name": "Sub Agent", + "description": "this is a test agent", + "llm.parameters": { + "max_iteration": "5", + "stop_when_no_tool_found": "true", + "response_filter": "$.completion" + }, + "memory": { + "type": "conversation_index" + }, + "type": "conversational" + } + }, + { + "id": "agent_tool", + "type": "create_tool", + "previous_node_inputs": { + "sub_agent": "agent_id" + }, + "user_inputs": { + "description": "Agent Tool", + "include_output_in_agent_response": true, + "type": "AgentTool", + "parameters": { + "max_iteration": "5" + }, + "name": "AgentTool" + } + }, + { + "id": "ml_model_tool", + "type": "create_tool", + "previous_node_inputs": { + "register_openai_model": "model_id" + }, + "user_inputs": { + "parameters": { + "prompt": "\n\nHuman:\" turn\" You are an AI that only speaks JSON. Do not write normal text. Output should follow example JSON format: \n\n {\"response\": [\"question1\", \"question2\"]}\n\n. \n\nHuman:\" turn\":You will be given a chat history between OpenSearch Assistant and a Human.\nUse the context provided to generate follow up questions the Human would ask to the Assistant.\nThe Assistant can answer general questions about logs, traces and metrics.\nAssistant can access a set of tools listed below to answer questions given by the Human:\nQuestion suggestions generator tool\nHere's the chat history between the human and the Assistant.\n${parameters.AgentTool.output}\nUse the following steps to generate follow up questions Human may ask after the response of the Assistant:\nStep 1. Use the chat history to understand what human is trying to search and explore.\nStep 2. Understand what capabilities the assistant has with the set of tools it has access to.\nStep 3. Use the above context and generate follow up questions.Step4:You are an AI that only speaks JSON. Do not write normal text. Output should follow example JSON format: \n\n {\"response\": [\"question1\", \"question2\"]} \n \n----------------\n\nAssistant:" + }, + "description": "A general tool to answer any question.", + "alias": "language_model_tool", + "include_output_in_agent_response": true, + "name": "QuestionSuggestor", + "type": "MLModelTool" + } + }, + { + "id": "root_agent", + "type": "register_agent", + "previous_node_inputs": { + "agent_tool": "tools", + "register_openai_model": "model_id", + "ml_model_tool": "tools" + }, + "user_inputs": { + "parameters": { + "prompt": "Answer the question as best you can." + }, + "app_type": "chatbot", + "name": "Root agent", + "description": "this is the root agent", + "tools_order": [ + "agent_tool", + "ml_model_tool" + ], + "memory": { + "type": "conversation_index" + }, + "type": "flow" + } + } + ], + "edges": [ + { + "source": "register_openai_model", + "dest": "rag_tool" + } + ] + } + } +} diff --git a/sample-templates/observability-chat-agent.yml b/sample-templates/observability-chat-agent.yml new file mode 100644 index 000000000..180c7df47 --- /dev/null +++ b/sample-templates/observability-chat-agent.yml @@ -0,0 +1,271 @@ +# This template creates connectors to OpenAI GPT 3.5 +# +# It then creates tools in the Agent Framework to create an observability chat agent. +# +# To use: +# - update the "credential" fields under the create_openai_connector node. +# - if needed, update region +# +# After provisioning: +# - returns a workflow ID +# - use the status API to get the deployed model IDs and agent IDs +# - use those models and agents to create a chat experience +--- +name: Observability Chat Agent +description: Create an Observability Chat Agent using OpenAI GPT 3.5 model +use_case: REGISTER_AGENT +version: + template: 1.0.0 + compatibility: + - 2.12.0 + - 3.0.0 +# This section defines the provision workflow. Nodes are connected in a graph. +# Either previous_node_inputs or explicit edges can be used to enforce ordering. +workflows: + provision: + nodes: + # + # SETUP EXTERNAL MODEL + # + # Create a connector to an OpenAI model and deploy the model + - id: create_openai_connector + type: create_connector + user_inputs: + name: OpenAI Chat Connector + description: The connector to public OpenAI model service for GPT 3.5 + version: '1' + protocol: http + parameters: + endpoint: api.openai.com + model: gpt-3.5-turbo + credential: + openAI_key: 'PUT_YOUR_API_KEY_HERE' + actions: + - action_type: predict + method: POST + url: https://${parameters.endpoint}/v1/chat/completions + - id: register_openai_model + type: register_remote_model + previous_node_inputs: + create_openai_connector: connector_id + user_inputs: + name: openAI-gpt-3.5-turbo + deploy: true + # + # SETUP LOCAL CUSTOM MODEL + # + # Create a connector to an OpenAI model and deploy the model + - id: register_sparse_model + type: register_local_custom_model + user_inputs: + name: neural-sparse/opensearch-neural-sparse-tokenizer-v1 + version: 1.0.0 + description: 'This is a neural sparse tokenizer model: It tokenize input sentence + into tokens and assign pre-defined weight from IDF to each. It serves only + in query.' + function_name: SPARSE_TOKENIZE + model_format: TORCH_SCRIPT + model_content_size_in_bytes: 567691 + model_content_hash_value: b3487da9c58ac90541b720f3b367084f271d280c7f3bdc3e6d9c9a269fb31950 + created_time: 1696913667239 + model_type: sparse + embedding_dimension: '1' + framework_type: sentence_transformers + url: https://artifacts.opensearch.org/models/ml-models/amazon/neural-sparse/opensearch-neural-sparse-tokenizer-v1/1.0.0/torch_script/opensearch-neural-sparse-tokenizer-v1-1.0.0.zip + - id: deploy_sparse_model + type: deploy_model + previous_node_inputs: + register_sparse_model: model_id + # + # SETUP A VARIETY OF TOOLS FOR THE AGENT + # + - id: cat_index_tool + type: create_tool + user_inputs: + type: CatIndexTool + name: CatIndexTool + parameters: {} + - id: index_mapping_tool + type: create_tool + user_inputs: + type: IndexMappingTool + name: IndexMappingTool + parameters: {} + - id: visualization_tool + type: create_tool + user_inputs: + include_output_in_agent_response: true + type: VisualizationTool + name: VisualizationTool + parameters: + index: ".kibana" + - id: search_alerts_tool + type: create_tool + user_inputs: + type: SearchAlertsTool + name: SearchAlertsTool + parameters: {} + - id: search_monitors_tool + type: create_tool + user_inputs: + type: SearchMonitorsTool + name: SearchMonitorsTool + parameters: {} + - id: search_anomoly_detectors_tool + type: create_tool + user_inputs: + type: SearchAnomalyDetectorsTool + name: SearchAnomalyDetectorsTool + parameters: {} + - id: search_anomoly_results_tool + type: create_tool + user_inputs: + type: SearchAnomalyResultsTool + name: SearchAnomalyResultsTool + parameters: {} + - id: vector_db_tool + type: create_tool + user_inputs: + type: VectorDBTool + name: VectorDBTool + parameters: + model_id: ksNnFo0BY4jgIz2mWrHU + index: my_test_data + embedding_field: embedding + source_field: '["text"]' + input: "${parameters.question}" + - id: rag_tool + type: create_tool + user_inputs: + type: RAGTool + name: RAGTool + parameters: + inference_model_id: "${{ register_openai_model.model_id }}" + embedding_model_id: ksNnFo0BY4jgIz2mWrHU + index: my_test_data + embedding_field: embedding + source_field: '["text"]' + input: "${parameters.question}" + prompt: "\n\nHuman:\" turn\" You are a professional data analysist. You + will always answer question based on the given context first. If the answer + is not directly shown in the context, you will analyze the data and find + the answer. If you don't know the answer, just say don't know. \n\n Context:\n${parameters.output_field}\n\nHuman:${parameters.input}\n\nAssistant:" + - id: neural_sparse_knowledge_base_tool + type: create_tool + previous_node_inputs: + deploy_sparse_model: model_id + user_inputs: + name: OpensearchKnowledgeBaseTool + type: NeuralSparseSearchTool + description: 'A tool to search the Opensearch knowledge base, the knowledge + base consists of segments of OpenSearch documents. You should always search + data with this tool when encountering general questions about Opensearch. + But for questions about current concerete cluster, use this tool can not + help you. If this tool provides useful info, give the answer and also quote + the origin doc. If this tool can not provide knowledge you need, give answer + based on your own knowledge. Action Input: ' + parameters: + index: knowledge_base + embedding_field: sparse_embedding + source_field: '["title","body"]' + doc_size: '10' + input: "${parameters.question}" + # + # CREATE A SUB AGENT THAT USES THE TOOLS + # + - id: sub_agent + type: register_agent + previous_node_inputs: + index_mapping_tool: tools + cat_index_tool: tools + index_mapping_tool: tools + visualization_tool: tools + search_alerts_tool: tools + search_monitors_tool: tools + search_anomoly_detectors_tool: tools + search_anomoly_results_tool: tools + vector_db_tool: tools + rag_tool: tools + neural_sparse_knowledge_base_tool: tools + register_openai_model: model_id + user_inputs: + parameters: {} + app_type: chatbot + name: Sub Agent + description: this is a test agent + llm.parameters: + max_iteration: '5' + stop_when_no_tool_found: 'true' + response_filter: "$.completion" + memory: + type: conversation_index + type: conversational + - id: agent_tool + type: create_tool + previous_node_inputs: + sub_agent: agent_id + user_inputs: + description: Agent Tool + include_output_in_agent_response: true + type: AgentTool + parameters: + max_iteration: '5' + name: AgentTool + # + # CREATE A SUGGESTOR TOOL + # + - id: ml_model_tool + type: create_tool + previous_node_inputs: + register_openai_model: model_id + user_inputs: + parameters: + prompt: "\n\nHuman:\" turn\" You are an AI that only speaks JSON. Do not + write normal text. Output should follow example JSON format: \n\n {\"response\": + [\"question1\", \"question2\"]}\n\n. \n\nHuman:\" turn\":You will be given + a chat history between OpenSearch Assistant and a Human.\nUse the context + provided to generate follow up questions the Human would ask to the Assistant.\nThe + Assistant can answer general questions about logs, traces and metrics.\nAssistant + can access a set of tools listed below to answer questions given by the + Human:\nQuestion suggestions generator tool\nHere's the chat history between + the human and the Assistant.\n${parameters.AgentTool.output}\nUse the + following steps to generate follow up questions Human may ask after the + response of the Assistant:\nStep 1. Use the chat history to understand + what human is trying to search and explore.\nStep 2. Understand what capabilities + the assistant has with the set of tools it has access to.\nStep 3. Use + the above context and generate follow up questions.Step4:You are an AI + that only speaks JSON. Do not write normal text. Output should follow + example JSON format: \n\n {\"response\": [\"question1\", \"question2\"]} + \n \n----------------\n\nAssistant:" + description: A general tool to answer any question. + alias: language_model_tool + include_output_in_agent_response: true + name: QuestionSuggestor + type: MLModelTool + # + # CREATE A ROOT AGENT USING SUB AGENT AND SUGGESTOR + - id: root_agent + type: register_agent + previous_node_inputs: + agent_tool: tools + register_openai_model: model_id + ml_model_tool: tools + user_inputs: + parameters: + prompt: Answer the question as best you can. + app_type: chatbot + name: Root agent + description: this is the root agent + tools_order: + - agent_tool + - ml_model_tool + memory: + type: conversation_index + type: flow + # + # SPECIAL CASE EDGE NOT INCLUDED IN PREVIOUS NODE INPUTS + # + edges: + - source: register_openai_model + dest: rag_tool diff --git a/sample-templates/query-assist-agent.json b/sample-templates/query-assist-agent.json new file mode 100644 index 000000000..c11717ad5 --- /dev/null +++ b/sample-templates/query-assist-agent.json @@ -0,0 +1,246 @@ +{ + "name": "Query Assist Agent", + "description": "Create a Query Assist Agent using Bedrock and Sagemaker models", + "use_case": "REGISTER_AGENT", + "version": { + "template": "1.0.0", + "compatibility": [ + "2.12.0", + "3.0.0" + ] + }, + "workflows": { + "provision": { + "nodes": [ + { + "id": "create_openai_connector", + "type": "create_connector", + "user_inputs": { + "name": "OpenAI Chat Connector", + "description": "The connector to public OpenAI model service for GPT 3.5", + "version": "1", + "protocol": "http", + "parameters": { + "endpoint": "api.openai.com", + "model": "gpt-3.5-turbo" + }, + "credential": { + "openAI_key": "PUT_YOUR_API_KEY_HERE" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://${parameters.endpoint}/v1/chat/completions" + } + ] + } + }, + { + "id": "register_openai_model", + "type": "register_remote_model", + "previous_node_inputs": { + "create_openai_connector": "connector_id" + }, + "user_inputs": { + "name": "openAI-gpt-3.5-turbo", + "deploy": true + } + }, + { + "id": "TransferQuestionToPPLAndExecuteTool", + "type": "create_tool", + "previous_node_inputs": { + "register_openai_model": "model_id" + }, + "user_inputs": { + "type": "PPLTool", + "name": "TransferQuestionToPPLAndExecuteTool", + "description": "Use this tool to transfer natural language to generate PPL and execute PPL to query inside. Use this tool after you know the index name, otherwise, call IndexRoutingTool first. The input parameters are: {index:IndexName, question:UserQuestion}", + "parameters": { + "response_filter": "$.completion", + "execute": false, + "model_type": "openai" + }, + "include_output_in_agent_response": true + } + }, + { + "id": "ppl_agent", + "type": "register_agent", + "previous_node_inputs": { + "TransferQuestionToPPLAndExecuteTool": "tools" + }, + "user_inputs": { + "parameters": { + }, + "app_type": "query_assist", + "name": "PPL agent", + "description": "this is the PPL agent", + "type": "flow" + } + }, + { + "id": "summarize_success_tool", + "type": "create_tool", + "previous_node_inputs": { + "register_openai_model": "model_id" + }, + "user_inputs": { + "type": "MLModelTool", + "Name": "SummarizeSuccessTool", + "description": "Use this tool to summarize a PPL success response in query assist", + "parameters": { + "prompt": "\n\nHuman: You will be given a search response, summarize it as a concise paragraph while considering the following:\nUser's question on index '${parameters.index}': ${parameters.question}\nPPL (Piped Processing Language) query used: ${parameters.query}\n\nGive some documents to support your point.\nNote that the output could be truncated, summarize what you see. Don't mention about total items returned and don't mention about the fact that output is truncated if you see 'Output is too long, truncated' in the response.\n\nSkip the introduction; go straight into the summarization.\n\nUse the following pieces of context to answer the users question.\nIf you don't know the answer, just say that you don't know, don't try to make up an answer.\n----------------\n${parameters.response}\n\nAssistant:", + "response_filter": "$.completion" + } + } + }, + { + "id": "response_summary_agent", + "type": "register_agent", + "previous_node_inputs": { + "summarize_success_tool": "tools" + }, + "user_inputs": { + "parameters": { + }, + "app_type": "query_assist", + "name": "Response summary agent", + "description": "this is the summarize success PPL response agent", + "type": "flow" + } + }, + { + "id": "summarize_error_tool", + "type": "create_tool", + "previous_node_inputs": { + "register_openai_model": "model_id" + }, + "user_inputs": { + "type": "MLModelTool", + "name": "SummarizeErrorTool", + "description": "Use this tool to summarize a PPL error response in query assist", + "include_output_in_agent_response": true, + "parameters": { + "prompt": "\n\nHuman: You will be given an API response with errors, summarize it as a concise paragraph. Do not try to answer the user's question.\nIf the error cannot be fixed, eg. no such field or function not supported, then give suggestions to rephrase the question.\nIt is imperative that you must not give suggestions on how to fix the error or alternative PPL query, or answers to the question.\n\nConsider the following:\nUser's question on index '${parameters.index}': ${parameters.question}\nPPL (Piped Processing Language) query used: ${parameters.query}\n\nSkip the introduction; go straight into the summarization.\n\nUse the following pieces of context to answer the users question.\nIf you don't know the answer, just say that you don't know, don't try to make up an answer.\n----------------\n${parameters.response}\n\nAssistant:", + "response_filter": "$.completion" + } + } + }, + { + "id": "suggestions_tool", + "type": "create_tool", + "previous_node_inputs": { + "register_openai_model": "model_id" + }, + "user_inputs": { + "type": "MLModelTool", + "name": "SuggestionsTool", + "description": "Use this tool to generate possible questions for an index in query assist", + "include_output_in_agent_response": true, + "parameters": { + "prompt": "\n\nHuman: OpenSearch index: ${parameters.index}\n\nRecommend 2 or 3 possible questions on this index given the fields below. Only give the questions, do not give descriptions of questions and do not give PPL queries.\n\nThe format for a field is\n```\n- field_name: field_type (sample field value)\n```\n\nFields:\n${parameters.fields}\n\nPut each question in a tag.\n\nAssistant:", + "response_filter": "$.completion" + } + } + }, + { + "id": "error_summary_agent", + "type": "register_agent", + "previous_node_inputs": { + "summarize_error_tool": "tools", + "suggestions_tool": "tools" + }, + "user_inputs": { + "parameters": { + }, + "app_type": "query_assist", + "name": "Error summary agent", + "description": "this is the agent for summarizing PPL error and give suggested questions", + "tools_order": [ + "summarize_error_tool", + "suggestions_tool" + ], + "type": "flow" + } + }, + { + "id": "ppl_agent_tool", + "type": "create_tool", + "previous_node_inputs": { + "ppl_agent": "agent_id" + }, + "user_inputs": { + "description": "PPL Agent Tool", + "include_output_in_agent_response": true, + "type": "AgentTool", + "parameters": { + "max_iteration": "5" + }, + "name": "PPLAgentTool" + } + }, + { + "id": "response_summary_agent_tool", + "type": "create_tool", + "previous_node_inputs": { + "response_summary_agent": "agent_id" + }, + "user_inputs": { + "description": "Response Summary Agent Tool", + "include_output_in_agent_response": true, + "type": "AgentTool", + "parameters": { + "max_iteration": "5" + }, + "name": "ResponseSummaryPPLAgentTool" + } + }, + { + "id": "error_summary_agent_tool", + "type": "create_tool", + "previous_node_inputs": { + "error_summary_agent": "agent_id" + }, + "user_inputs": { + "description": "Error Summary Agent Tool", + "include_output_in_agent_response": true, + "type": "AgentTool", + "parameters": { + "max_iteration": "5" + }, + "name": "ErrorSummaryAgentTool" + } + }, + { + "id": "root_agent", + "type": "register_agent", + "previous_node_inputs": { + "ppl_agent_tool": "tools", + "response_summary_agent_tool": "tools", + "error_summary_agent_tool": "tools", + "register_openai_model": "model_id" + }, + "user_inputs": { + "parameters": { + "prompt": "Answer the question as best you can." + }, + "app_type": "chatbot", + "name": "Root agent", + "description": "this is the root agent", + "tools_order": [ + "ppl_agent_tool", + "response_summary_agent_tool", + "error_summary_agent_tool" + ], + "memory": { + "type": "conversation_index" + }, + "type": "flow" + } + } + ] + } + } +} diff --git a/sample-templates/query-assist-agent.yml b/sample-templates/query-assist-agent.yml new file mode 100644 index 000000000..3c27da221 --- /dev/null +++ b/sample-templates/query-assist-agent.yml @@ -0,0 +1,264 @@ +# This template creates connectors to OpenAI GPT model. +# +# It then creates tools in the Agent Framework to create a query assist agent. +# +# To use: +# - update the "credential" fields under the create_openai_connector node. +# - if needed, update region +# +# After provisioning: +# - returns a workflow ID +# - use the status API to get the deployed model IDs and agent IDs +# - use those models and agents to create a chat experience +--- +name: Query Assist Agent +description: Create a Query Assist Agent using Bedrock and Sagemaker models +use_case: REGISTER_AGENT +version: + template: 1.0.0 + compatibility: + - 2.12.0 + - 3.0.0 +# This section defines the provision workflow. Nodes are connected in a graph. +# Either previous_node_inputs or explicit edges can be used to enforce ordering. +workflows: + provision: + nodes: + # + # SETUP EXTERNAL MODEL + # + # Create a connector to an OpenAI model and deploy the model + - id: create_openai_connector + type: create_connector + user_inputs: + name: OpenAI Chat Connector + description: The connector to public OpenAI model service for GPT 3.5 + version: '1' + protocol: http + parameters: + endpoint: api.openai.com + model: gpt-3.5-turbo + credential: + openAI_key: 'PUT_YOUR_API_KEY_HERE' + actions: + - action_type: predict + method: POST + url: https://${parameters.endpoint}/v1/chat/completions + - id: register_openai_model + type: register_remote_model + previous_node_inputs: + create_openai_connector: connector_id + user_inputs: + name: openAI-gpt-3.5-turbo + deploy: true + # + # SETUP PPL AGENT + # + # Create a PPLTool + - id: TransferQuestionToPPLAndExecuteTool + type: create_tool + previous_node_inputs: + register_openai_model: model_id + user_inputs: + type: PPLTool + name: TransferQuestionToPPLAndExecuteTool + description: 'Use this tool to transfer natural language to generate PPL and + execute PPL to query inside. Use this tool after you know the index name, + otherwise, call IndexRoutingTool first. The input parameters are: {index:IndexName, + question:UserQuestion}' + parameters: + response_filter: "$.completion" + execute: false + model_type: openai + include_output_in_agent_response: true + # Create a flow agent to use the PPLTool + - id: ppl_agent + type: register_agent + previous_node_inputs: + TransferQuestionToPPLAndExecuteTool: tools + user_inputs: + parameters: {} + app_type: query_assist + name: PPL agent + description: this is the PPL agent + type: flow + # + # SETUP RESPONPSE SUMMARY AGENT + # + # Create a tool to summarize successful results in natural language + - id: summarize_success_tool + type: create_tool + previous_node_inputs: + register_openai_model: model_id + user_inputs: + type: MLModelTool + Name: SummarizeSuccessTool + description: Use this tool to summarize a PPL success response in query assist + parameters: + prompt: |2- + + + Human: You will be given a search response, summarize it as a concise paragraph while considering the following: + User's question on index '${parameters.index}': ${parameters.question} + PPL (Piped Processing Language) query used: ${parameters.query} + + Give some documents to support your point. + Note that the output could be truncated, summarize what you see. Don't mention about total items returned and don't mention about the fact that output is truncated if you see 'Output is too long, truncated' in the response. + + Skip the introduction; go straight into the summarization. + + Use the following pieces of context to answer the users question. + If you don't know the answer, just say that you don't know, don't try to make up an answer. + ---------------- + ${parameters.response} + + Assistant: + response_filter: "$.completion" + # Create a flow agent to use the PPLTool + - id: response_summary_agent + type: register_agent + previous_node_inputs: + summarize_success_tool: tools + user_inputs: + parameters: {} + app_type: query_assist + name: Response summary agent + description: this is the summarize success PPL response agent + type: flow + # + # SETUP ERROR AND SUGGESTIONS AGENT + # + # Create a tool to summarize error results in natural language + - id: summarize_error_tool + type: create_tool + previous_node_inputs: + register_openai_model: model_id + user_inputs: + type: MLModelTool + name: SummarizeErrorTool + description: Use this tool to summarize a PPL error response in query assist + include_output_in_agent_response: true + parameters: + prompt: |2- + + + Human: You will be given an API response with errors, summarize it as a concise paragraph. Do not try to answer the user's question. + If the error cannot be fixed, eg. no such field or function not supported, then give suggestions to rephrase the question. + It is imperative that you must not give suggestions on how to fix the error or alternative PPL query, or answers to the question. + + Consider the following: + User's question on index '${parameters.index}': ${parameters.question} + PPL (Piped Processing Language) query used: ${parameters.query} + + Skip the introduction; go straight into the summarization. + + Use the following pieces of context to answer the users question. + If you don't know the answer, just say that you don't know, don't try to make up an answer. + ---------------- + ${parameters.response} + + Assistant: + response_filter: "$.completion" + # Create a tool to give suggestions for future questions + - id: suggestions_tool + type: create_tool + previous_node_inputs: + register_openai_model: model_id + user_inputs: + type: MLModelTool + name: SuggestionsTool + description: Use this tool to generate possible questions for an index in query + assist + include_output_in_agent_response: true + parameters: + prompt: |2- + + + Human: OpenSearch index: ${parameters.index} + + Recommend 2 or 3 possible questions on this index given the fields below. Only give the questions, do not give descriptions of questions and do not give PPL queries. + + The format for a field is + ``` + - field_name: field_type (sample field value) + ``` + + Fields: + ${parameters.fields} + + Put each question in a tag. + + Assistant: + response_filter: "$.completion" + # Create a flow agent to summarize the errors and suggest possible questions + - id: error_summary_agent + type: register_agent + previous_node_inputs: + summarize_error_tool: tools + suggestions_tool: tools + user_inputs: + parameters: {} + app_type: query_assist + name: Error summary agent + description: this is the agent for summarizing PPL error and give suggested questions + tools_order: + - summarize_error_tool + - suggestions_tool + type: flow + # + # WRAP AGENTS IN AGENT TOOLS FOR ROOT AGENT + # + - id: ppl_agent_tool + type: create_tool + previous_node_inputs: + ppl_agent: agent_id + user_inputs: + description: PPL Agent Tool + include_output_in_agent_response: true + type: AgentTool + parameters: + max_iteration: '5' + name: PPLAgentTool + - id: response_summary_agent_tool + type: create_tool + previous_node_inputs: + response_summary_agent: agent_id + user_inputs: + description: Response Summary Agent Tool + include_output_in_agent_response: true + type: AgentTool + parameters: + max_iteration: '5' + name: ResponseSummaryPPLAgentTool + - id: error_summary_agent_tool + type: create_tool + previous_node_inputs: + error_summary_agent: agent_id + user_inputs: + description: Error Summary Agent Tool + include_output_in_agent_response: true + type: AgentTool + parameters: + max_iteration: '5' + name: ErrorSummaryAgentTool + # The root agent will use the agent tools + - id: root_agent + type: register_agent + previous_node_inputs: + ppl_agent_tool: tools + response_summary_agent_tool: tools + error_summary_agent_tool: tools + register_openai_model: model_id + user_inputs: + parameters: + prompt: Answer the question as best you can. + app_type: chatbot + name: Root agent + description: this is the root agent + tools_order: + - ppl_agent_tool + - response_summary_agent_tool + - error_summary_agent_tool + memory: + type: conversation_index + type: flow