From 3172fe2641cf9c63d955119cb50694be8cfd62d5 Mon Sep 17 00:00:00 2001 From: Nathalie Jonathan Date: Tue, 28 Jan 2025 19:46:17 -0800 Subject: [PATCH 1/3] Add OpenSearch DeepSeek Integration blog post Signed-off-by: Nathalie Jonathan --- _community_members/nathhjo.md | 24 ++ ...earch-Now-Supports-DeepSeek-Chat-Models.md | 235 ++++++++++++++++++ assets/media/community/members/nathhjo.jpg | Bin 0 -> 57881 bytes 3 files changed, 259 insertions(+) create mode 100644 _community_members/nathhjo.md create mode 100644 _posts/2025-01-28-OpenSearch-Now-Supports-DeepSeek-Chat-Models.md create mode 100644 assets/media/community/members/nathhjo.jpg diff --git a/_community_members/nathhjo.md b/_community_members/nathhjo.md new file mode 100644 index 000000000..92796f7fd --- /dev/null +++ b/_community_members/nathhjo.md @@ -0,0 +1,24 @@ +--- +name: Nathalie Jonathan +short_name: nathhjo +photo: "/assets/media/community/members/nathhjo.jpg" +title: 'OpenSearch Community Member: Nathalie Jonathan' +primary_title: Nathalie Jonathan +breadcrumbs: + icon: community + items: + - title: Community + url: /community/index.html + - title: Members + url: /community/members/index.html + - title: 'Nathalie Jonathan's Profile' + url: '/community/members/nathalie-jonathan.html' +github: nathaliellenaa +job_title_and_company: 'Software engineer at Amazon Web Services' +personas: + - author +permalink: '/community/members/nathalie-jonathan.html' +redirect_from: '/authors/nathhjo/' +--- + +**Nathalie Jonathan** is a Software Engineer at AWS working on OpenSearch ML Commons team. \ No newline at end of file diff --git a/_posts/2025-01-28-OpenSearch-Now-Supports-DeepSeek-Chat-Models.md b/_posts/2025-01-28-OpenSearch-Now-Supports-DeepSeek-Chat-Models.md new file mode 100644 index 000000000..5935221ab --- /dev/null +++ b/_posts/2025-01-28-OpenSearch-Now-Supports-DeepSeek-Chat-Models.md @@ -0,0 +1,235 @@ +--- +layout: post +title: "OpenSearch Now Supports DeepSeek Chat Models" +authors: + - seanzheng + - ylwu + - nathhjo + - kolchfa +date: 2025-01-28 +categories: + - technical-posts +meta_keywords: OpenSearch DeepSeek integration, LLM integration, RAG, AI search, machine learning, natural language processing, open-source LLM +meta_description: Explore how OpenSearch's integration with DeepSeek R1 LLM models enables cost-effective Retrieval-Augmented Generation (RAG) while maintaining high performance comparable to leading LLMs. +--- + +We’re excited to announce that OpenSearch now supports DeepSeek integration, bringing this powerful and cost-effective AI capabilities to our users. Deepseek R1 is a recently released open source LLM model. It provides **similar benchmarking performance** with other main stream LLMs like OpenAI O1 ([report](https://github.com/deepseek-ai/DeepSeek-R1/blob/main/DeepSeek_R1.pdf)) at a significantly **lower cost** ([DeepSeek API Pricing](https://api-docs.deepseek.com/quick_start/pricing)). And on top of that, it’s also offered as open source so can be downloaded and served in infrastructure of users’ choice. This creates an opportunity for OpenSearch users to implement more cost-effective and sustainable Retrieval-Augmented Generation (RAG). + +OpenSearch provides high flexibility to let users connect to any remote inference services like DeepSeek or OpenAI through ML connectors. User can use [pre-built connector blueprints](https://github.com/opensearch-project/ml-commons/tree/main/docs/remote_inference_blueprints) or customize connectors based on their requirements (read more details about [blueprints](https://opensearch.org/docs/latest/ml-commons-plugin/remote-models/blueprints/)). + +We added a new connector [blueprint](https://github.com/opensearch-project/ml-commons/blob/main/docs/remote_inference_blueprints/deepseek_connector_chat_blueprint.md) for DeepSeek R1 model. This integration, along with OpenSearch’s built-in vector database capability, makes it a lot easier and cheaper to build [RAG applications](https://opensearch.org/docs/latest/search-plugins/conversational-search) in OpenSearch. + +Following is an example of implementing RAG with DeepSeek in OpenSearch Vector Database. This example walks you through the process of creating connector for the [DeepSeek Chat Model](https://api-docs.deepseek.com/api/create-chat-completion) and [RAG pipeline](https://opensearch.org/docs/latest/search-plugins/search-pipelines/rag-processor/) in OpenSearch. + +### 1. Create connector for DeepSeek Chat +Create a connector for DeepSeek Chat Model, don’t forget to provide your own DeepSeek API key. Read more [details](https://opensearch.org/docs/latest/ml-commons-plugin/remote-models/index/). + +``` +POST /_plugins/_ml/connectors/_create +{ + "name": "DeepSeek Chat", + "description": "Test connector for DeepSeek Chat", + "version": "1", + "protocol": "http", + "parameters": { + "endpoint": "api.deepseek.com", + "model": "deepseek-chat" + }, + "credential": { + "deepSeek_key": "" + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://${parameters.endpoint}/v1/chat/completions", + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer ${credential.deepSeek_key}" + }, + "request_body": "{ \"model\": \"${parameters.model}\", \"messages\": ${parameters.messages} }" + } + ] +} +``` +Sample response +``` +{ + "connector_id": "n0dOqZQBQwAL8-GO1pYI" +} +``` + +### 2. Create model group +Create a model group for remote model. +``` +POST /_plugins/_ml/model_groups/_register +{ + "name": "remote_model_group_chat", + "description": "This is an example description" +} +``` +Sample response +``` +{ + "model_group_id": "b0cjqZQBQwAL8-GOVJZ4", + "status": "CREATED" +} +``` + +### 3. Register model to model group & deploy model +Register and deploy the model with the model ID and connector ID that is created in the previous steps. +``` +POST /_plugins/_ml/models/_register?deploy=true +{ + "name": "DeepSeek Chat model", + "function_name": "remote", + "model_group_id": "b0cjqZQBQwAL8-GOVJZ4", + "description": "DeepSeek Chat", + "connector_id": "n0dOqZQBQwAL8-GO1pYI" +} +``` +Sample response +``` +{ + "task_id": "oEdPqZQBQwAL8-GOCJbw", + "status": "CREATED", + "model_id": "oUdPqZQBQwAL8-GOCZYL" +} +``` +Test model to make sure the connector works as expected. +``` +POST /_plugins/_ml/models/oUdPqZQBQwAL8-GOCZYL/_predict +{ + "parameters": { + "messages": [ + { + "role": "system", + "content": "You are a helpful assistant." + }, + { + "role": "user", + "content": "Hello!" + } + ] + }, + "stream": false +} +``` +Sample response +``` +{ + "inference_results": [ + { + "output": [ + { + "name": "response", + "dataAsMap": { + "id": "9d9bd689-88a5-44b0-b73f-2daa92518761", + "object": "chat.completion", + "created": 1.738011126E9, + "model": "deepseek-chat", + "choices": [ + { + "index": 0.0, + "message": { + "role": "assistant", + "content": "Hello! How can I assist you today? 😊" + }, + "finish_reason": "stop" + } + ], + "usage": { + "prompt_tokens": 11.0, + "completion_tokens": 11.0, + "total_tokens": 22.0, + "prompt_tokens_details": { + "cached_tokens": 0.0 + }, + "prompt_cache_hit_tokens": 0.0, + "prompt_cache_miss_tokens": 11.0 + }, + "system_fingerprint": "fp_3a5770e1b4" + } + } + ], + "status_code": 200 + } + ] +} +``` + +### 4. Create a search pipeline +Create a search pipeline with a `retrieval_augmented_generation` processor. Read more [details](https://opensearch.org/docs/latest/search-plugins/conversational-search). +``` +PUT /_search/pipeline/rag_pipeline +{ + "response_processors": [ + { + "retrieval_augmented_generation": { + "tag": "openai_pipeline_demo", + "description": "Demo pipeline Using OpenAI Connector", + "model_id": "oUdPqZQBQwAL8-GOCZY", + "context_field_list": ["text"], + "system_prompt": "You are a helpful assistant", + "user_instructions": "Generate a concise and informative answer in less than 100 words for the given question" + } + } + ] +} +``` + +Assuming we created a k-NN index and ingested the supplementary data, we can now create a conversation memory. Read more [details](https://opensearch.org/docs/latest/search-plugins/knn/knn-index/). + +### 5. Create a conversation memory +Create a conversation memory to store all messages from a conversation. +``` +POST /_plugins/_ml/memory/ +{ + "name": "Conversation about NYC population" +} +``` +Sample response +``` +{ + "memory_id": "znCqcI0BfUsSoeNTntd7" +} +``` + +### 6. Use the pipeline for RAG +Send a query to OpenSearch and provide additional parameters in the `ext.generative_qa_parameters` object. +``` +GET /my_rag_test_data/_search +{ + "query": { + "match": { + "text": "What's the population of NYC metro area in 2023" + } + }, + "ext": { + "generative_qa_parameters": { + "llm_model": "gpt-3.5-turbo", + "llm_question": "What's the population of NYC metro area in 2023", + "memory_id": "znCqcI0BfUsSoeNTntd7", + "context_size": 5, + "message_size": 5, + "timeout": 15 + } + } +} +``` +Sample response +``` +{ + ... + "ext": { + "retrieval_augmented_generation": { + "answer": "The population of the New York City metro area in 2022 was 18,867,000.", + "message_id": "p3CvcI0BfUsSoeNTj9iH" + } + } +} +``` + +By integrating DeepSeek R1, OpenSearch continues its mission to democratize AI-powered search and analytics—offering developers **more choice, flexibility, and cost savings**. + +**Try DeepSeek R1 now!** diff --git a/assets/media/community/members/nathhjo.jpg b/assets/media/community/members/nathhjo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f3c08fa76424c71182f95706f00d45712dbc20e5 GIT binary patch literal 57881 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Ð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 Pj71#~3n%~p0095l*$B*l literal 0 HcmV?d00001 From 4e3452ce4508a87b6bbee5a385271bdbc0fd8723 Mon Sep 17 00:00:00 2001 From: Fanit Kolchina Date: Wed, 29 Jan 2025 09:19:32 -0500 Subject: [PATCH 2/3] Doc review Signed-off-by: Fanit Kolchina --- ...earch-Now-Supports-DeepSeek-Chat-Models.md | 109 ++++++++++++------ 1 file changed, 72 insertions(+), 37 deletions(-) diff --git a/_posts/2025-01-28-OpenSearch-Now-Supports-DeepSeek-Chat-Models.md b/_posts/2025-01-28-OpenSearch-Now-Supports-DeepSeek-Chat-Models.md index 5935221ab..3006f86ef 100644 --- a/_posts/2025-01-28-OpenSearch-Now-Supports-DeepSeek-Chat-Models.md +++ b/_posts/2025-01-28-OpenSearch-Now-Supports-DeepSeek-Chat-Models.md @@ -1,30 +1,31 @@ --- layout: post -title: "OpenSearch Now Supports DeepSeek Chat Models" +title: "OpenSearch now supports DeepSeek chat models" authors: - seanzheng - ylwu - nathhjo - kolchfa -date: 2025-01-28 +date: 2025-01-29 categories: - technical-posts meta_keywords: OpenSearch DeepSeek integration, LLM integration, RAG, AI search, machine learning, natural language processing, open-source LLM meta_description: Explore how OpenSearch's integration with DeepSeek R1 LLM models enables cost-effective Retrieval-Augmented Generation (RAG) while maintaining high performance comparable to leading LLMs. --- -We’re excited to announce that OpenSearch now supports DeepSeek integration, bringing this powerful and cost-effective AI capabilities to our users. Deepseek R1 is a recently released open source LLM model. It provides **similar benchmarking performance** with other main stream LLMs like OpenAI O1 ([report](https://github.com/deepseek-ai/DeepSeek-R1/blob/main/DeepSeek_R1.pdf)) at a significantly **lower cost** ([DeepSeek API Pricing](https://api-docs.deepseek.com/quick_start/pricing)). And on top of that, it’s also offered as open source so can be downloaded and served in infrastructure of users’ choice. This creates an opportunity for OpenSearch users to implement more cost-effective and sustainable Retrieval-Augmented Generation (RAG). +We're excited to announce that OpenSearch now supports DeepSeek integration, , providing powerful and cost-effective AI capabilities. DeepSeek R1 is a recently released open-source large language model (LLM) that delivers **similar benchmarking performance** to leading LLMs like OpenAI O1 ([report](https://github.com/deepseek-ai/DeepSeek-R1/blob/main/DeepSeek_R1.pdf)) at a significantly **lower cost** ([DeepSeek API pricing](https://api-docs.deepseek.com/quick_start/pricing)). Because DeepSeek R1 is open source, you can download and deploy it on your preferred infrastructure. This enables OpenSearch you to build more cost-effective and sustainable Retrieval-Augmented Generation (RAG) solutions. -OpenSearch provides high flexibility to let users connect to any remote inference services like DeepSeek or OpenAI through ML connectors. User can use [pre-built connector blueprints](https://github.com/opensearch-project/ml-commons/tree/main/docs/remote_inference_blueprints) or customize connectors based on their requirements (read more details about [blueprints](https://opensearch.org/docs/latest/ml-commons-plugin/remote-models/blueprints/)). +OpenSearch gives you the flexibility to connect to any remote inference service, such as DeepSeek or OpenAI, using ML connectors. You can use [prebuilt connector blueprints](https://github.com/opensearch-project/ml-commons/tree/main/docs/remote_inference_blueprints) or customize connectors based on your requirements. For more information about connector blueprints, see [Blueprints](https://opensearch.org/docs/latest/ml-commons-plugin/remote-models/blueprints/). -We added a new connector [blueprint](https://github.com/opensearch-project/ml-commons/blob/main/docs/remote_inference_blueprints/deepseek_connector_chat_blueprint.md) for DeepSeek R1 model. This integration, along with OpenSearch’s built-in vector database capability, makes it a lot easier and cheaper to build [RAG applications](https://opensearch.org/docs/latest/search-plugins/conversational-search) in OpenSearch. +We've added a new [connector blueprint](https://github.com/opensearch-project/ml-commons/blob/main/docs/remote_inference_blueprints/deepseek_connector_chat_blueprint.md) for the DeepSeek R1 model. This integration, combined with OpenSearch's built-in vector database capabilities, makes it easier and more cost-effective to build [RAG applications](https://opensearch.org/docs/latest/search-plugins/conversational-search) in OpenSearch. -Following is an example of implementing RAG with DeepSeek in OpenSearch Vector Database. This example walks you through the process of creating connector for the [DeepSeek Chat Model](https://api-docs.deepseek.com/api/create-chat-completion) and [RAG pipeline](https://opensearch.org/docs/latest/search-plugins/search-pipelines/rag-processor/) in OpenSearch. +The following example implements RAG with DeepSeek in OpenSearch's vector database. This example guides you through creating a connector for the [DeepSeek chat Model](https://api-docs.deepseek.com/api/create-chat-completion) and setting up an [RAG pipeline](https://opensearch.org/docs/latest/search-plugins/search-pipelines/rag-processor/) in OpenSearch. -### 1. Create connector for DeepSeek Chat -Create a connector for DeepSeek Chat Model, don’t forget to provide your own DeepSeek API key. Read more [details](https://opensearch.org/docs/latest/ml-commons-plugin/remote-models/index/). +### 1. Create a connector for DeepSeek -``` +First, create a connector for the DeepSeek chat model, providing your own DeepSeek API key: + +```json POST /_plugins/_ml/connectors/_create { "name": "DeepSeek Chat", @@ -52,33 +53,45 @@ POST /_plugins/_ml/connectors/_create ] } ``` -Sample response -``` + +The response contains a connector ID for the newly created connector: + +```json { "connector_id": "n0dOqZQBQwAL8-GO1pYI" } ``` -### 2. Create model group -Create a model group for remote model. -``` +For more information, see [Connecting to externally hosted models](https://opensearch.org/docs/latest/ml-commons-plugin/remote-models/index/). + +### 2. Create a model group + +Create a model group for the DeepSeek chat model: + +```json POST /_plugins/_ml/model_groups/_register { "name": "remote_model_group_chat", "description": "This is an example description" } ``` -Sample response -``` + +The response contains a model group ID: + +```json { "model_group_id": "b0cjqZQBQwAL8-GOVJZ4", "status": "CREATED" } ``` -### 3. Register model to model group & deploy model -Register and deploy the model with the model ID and connector ID that is created in the previous steps. -``` +For more information about model groups, see [Model access control](https://opensearch.org/docs/latest/ml-commons-plugin/model-access-control/). + +### 3. Register and deploy the model + +Register the model to the model group and deploy the model using the model group ID and connector ID created in the previous steps: + +```json POST /_plugins/_ml/models/_register?deploy=true { "name": "DeepSeek Chat model", @@ -88,16 +101,20 @@ POST /_plugins/_ml/models/_register?deploy=true "connector_id": "n0dOqZQBQwAL8-GO1pYI" } ``` -Sample response -``` + +The response contains the model ID: + +```json { "task_id": "oEdPqZQBQwAL8-GOCJbw", "status": "CREATED", "model_id": "oUdPqZQBQwAL8-GOCZYL" } ``` -Test model to make sure the connector works as expected. -``` + +To make sure the connector is working as expected, test the model: + +```json POST /_plugins/_ml/models/oUdPqZQBQwAL8-GOCZYL/_predict { "parameters": { @@ -115,8 +132,10 @@ POST /_plugins/_ml/models/oUdPqZQBQwAL8-GOCZYL/_predict "stream": false } ``` -Sample response -``` + +The response verifies that the connector is working as expected: + +```json { "inference_results": [ { @@ -159,8 +178,10 @@ Sample response ``` ### 4. Create a search pipeline -Create a search pipeline with a `retrieval_augmented_generation` processor. Read more [details](https://opensearch.org/docs/latest/search-plugins/conversational-search). -``` + +Create a search pipeline with a `retrieval_augmented_generation` processor: + +```json PUT /_search/pipeline/rag_pipeline { "response_processors": [ @@ -178,26 +199,34 @@ PUT /_search/pipeline/rag_pipeline } ``` -Assuming we created a k-NN index and ingested the supplementary data, we can now create a conversation memory. Read more [details](https://opensearch.org/docs/latest/search-plugins/knn/knn-index/). +For more information, see [Conversational search](https://opensearch.org/docs/latest/search-plugins/conversational-search). ### 5. Create a conversation memory -Create a conversation memory to store all messages from a conversation. -``` + +Assuming you created a k-NN index and ingested the data, you can now create a conversation memory. For more information about creating a k-NN index, see [k-NN index](https://opensearch.org/docs/latest/search-plugins/knn/knn-index/). For more information about ingesting data, see [Ingest RAG data into an index](https://opensearch.org/docs/latest/search-plugins/conversational-search/#step-4-ingest-rag-data-into-an-index). + +Create a conversation memory to store all messages from a conversation: + +```json POST /_plugins/_ml/memory/ { "name": "Conversation about NYC population" } ``` -Sample response -``` + +The response contains a memory ID for the created memory: + +```json { "memory_id": "znCqcI0BfUsSoeNTntd7" } ``` ### 6. Use the pipeline for RAG -Send a query to OpenSearch and provide additional parameters in the `ext.generative_qa_parameters` object. -``` + +Send a query to OpenSearch and provide additional parameters in the `ext.generative_qa_parameters` object: + +```json GET /my_rag_test_data/_search { "query": { @@ -217,8 +246,10 @@ GET /my_rag_test_data/_search } } ``` -Sample response -``` + +The response contains the model output: + +```json { ... "ext": { @@ -230,6 +261,10 @@ Sample response } ``` -By integrating DeepSeek R1, OpenSearch continues its mission to democratize AI-powered search and analytics—offering developers **more choice, flexibility, and cost savings**. +## Wrapping up + +By integrating DeepSeek R1, OpenSearch continues its mission to democratize AI-powered search and analytics—offering developers **more choice, greater flexibility, and lower costs**. **Try DeepSeek R1 now!** + +As always, we welcome your feedback, and we'd love to hear from you on the [OpenSearch forum](https://forum.opensearch.org/). \ No newline at end of file From 09f173487bedf664c01ae1f50f64e9250aac840e Mon Sep 17 00:00:00 2001 From: kolchfa-aws <105444904+kolchfa-aws@users.noreply.github.com> Date: Wed, 29 Jan 2025 09:43:45 -0500 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Nathan Bower Signed-off-by: kolchfa-aws <105444904+kolchfa-aws@users.noreply.github.com> --- _community_members/nathhjo.md | 2 +- ...8-OpenSearch-Now-Supports-DeepSeek-Chat-Models.md | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/_community_members/nathhjo.md b/_community_members/nathhjo.md index 92796f7fd..4b6159860 100644 --- a/_community_members/nathhjo.md +++ b/_community_members/nathhjo.md @@ -21,4 +21,4 @@ permalink: '/community/members/nathalie-jonathan.html' redirect_from: '/authors/nathhjo/' --- -**Nathalie Jonathan** is a Software Engineer at AWS working on OpenSearch ML Commons team. \ No newline at end of file +**Nathalie Jonathan** is a Software Engineer at AWS working on the OpenSearch ML Commons team. \ No newline at end of file diff --git a/_posts/2025-01-28-OpenSearch-Now-Supports-DeepSeek-Chat-Models.md b/_posts/2025-01-28-OpenSearch-Now-Supports-DeepSeek-Chat-Models.md index 3006f86ef..ae34d9d44 100644 --- a/_posts/2025-01-28-OpenSearch-Now-Supports-DeepSeek-Chat-Models.md +++ b/_posts/2025-01-28-OpenSearch-Now-Supports-DeepSeek-Chat-Models.md @@ -13,13 +13,13 @@ meta_keywords: OpenSearch DeepSeek integration, LLM integration, RAG, AI search, meta_description: Explore how OpenSearch's integration with DeepSeek R1 LLM models enables cost-effective Retrieval-Augmented Generation (RAG) while maintaining high performance comparable to leading LLMs. --- -We're excited to announce that OpenSearch now supports DeepSeek integration, , providing powerful and cost-effective AI capabilities. DeepSeek R1 is a recently released open-source large language model (LLM) that delivers **similar benchmarking performance** to leading LLMs like OpenAI O1 ([report](https://github.com/deepseek-ai/DeepSeek-R1/blob/main/DeepSeek_R1.pdf)) at a significantly **lower cost** ([DeepSeek API pricing](https://api-docs.deepseek.com/quick_start/pricing)). Because DeepSeek R1 is open source, you can download and deploy it on your preferred infrastructure. This enables OpenSearch you to build more cost-effective and sustainable Retrieval-Augmented Generation (RAG) solutions. +We're excited to announce that OpenSearch now supports DeepSeek integration, providing powerful and cost-effective AI capabilities. DeepSeek R1 is a recently released open-source large language model (LLM) that delivers **similar benchmarking performance** to leading LLMs like OpenAI O1 ([report](https://github.com/deepseek-ai/DeepSeek-R1/blob/main/DeepSeek_R1.pdf)) at a significantly **lower cost** ([DeepSeek API pricing](https://api-docs.deepseek.com/quick_start/pricing)). Because DeepSeek R1 is open source, you can download and deploy it to your preferred infrastructure. This enables you to build more cost-effective and sustainable retrieval-augmented generation (RAG) solutions. -OpenSearch gives you the flexibility to connect to any remote inference service, such as DeepSeek or OpenAI, using ML connectors. You can use [prebuilt connector blueprints](https://github.com/opensearch-project/ml-commons/tree/main/docs/remote_inference_blueprints) or customize connectors based on your requirements. For more information about connector blueprints, see [Blueprints](https://opensearch.org/docs/latest/ml-commons-plugin/remote-models/blueprints/). +OpenSearch gives you the flexibility to connect to any remote inference service, such as DeepSeek or OpenAI, using machine learning (ML) connectors. You can use [prebuilt connector blueprints](https://github.com/opensearch-project/ml-commons/tree/main/docs/remote_inference_blueprints) or customize connectors based on your requirements. For more information about connector blueprints, see [Blueprints](https://opensearch.org/docs/latest/ml-commons-plugin/remote-models/blueprints/). -We've added a new [connector blueprint](https://github.com/opensearch-project/ml-commons/blob/main/docs/remote_inference_blueprints/deepseek_connector_chat_blueprint.md) for the DeepSeek R1 model. This integration, combined with OpenSearch's built-in vector database capabilities, makes it easier and more cost-effective to build [RAG applications](https://opensearch.org/docs/latest/search-plugins/conversational-search) in OpenSearch. +We've added a new [connector blueprint](https://github.com/opensearch-project/ml-commons/blob/main/docs/remote_inference_blueprints/deepseek_connector_chat_blueprint.md) for the DeepSeek R1 model. This integration, combined with OpenSearch's built-in vector database capabilities, makes it easier and more cost effective to build [RAG applications](https://opensearch.org/docs/latest/search-plugins/conversational-search) in OpenSearch. -The following example implements RAG with DeepSeek in OpenSearch's vector database. This example guides you through creating a connector for the [DeepSeek chat Model](https://api-docs.deepseek.com/api/create-chat-completion) and setting up an [RAG pipeline](https://opensearch.org/docs/latest/search-plugins/search-pipelines/rag-processor/) in OpenSearch. +The following example shows you how to implement RAG with DeepSeek in OpenSearch's vector database. This example guides you through creating a connector for the [DeepSeek chat model](https://api-docs.deepseek.com/api/create-chat-completion) and setting up a [RAG pipeline](https://opensearch.org/docs/latest/search-plugins/search-pipelines/rag-processor/) in OpenSearch. ### 1. Create a connector for DeepSeek @@ -112,7 +112,7 @@ The response contains the model ID: } ``` -To make sure the connector is working as expected, test the model: +To ensure that the connector is working as expected, test the model: ```json POST /_plugins/_ml/models/oUdPqZQBQwAL8-GOCZYL/_predict @@ -203,7 +203,7 @@ For more information, see [Conversational search](https://opensearch.org/docs/la ### 5. Create a conversation memory -Assuming you created a k-NN index and ingested the data, you can now create a conversation memory. For more information about creating a k-NN index, see [k-NN index](https://opensearch.org/docs/latest/search-plugins/knn/knn-index/). For more information about ingesting data, see [Ingest RAG data into an index](https://opensearch.org/docs/latest/search-plugins/conversational-search/#step-4-ingest-rag-data-into-an-index). +Assuming that you created a k-NN index and ingested the data, you can now create a conversation memory. For more information about creating a k-NN index, see [k-NN index](https://opensearch.org/docs/latest/search-plugins/knn/knn-index/). For more information about ingesting data, see [Ingest RAG data into an index](https://opensearch.org/docs/latest/search-plugins/conversational-search/#step-4-ingest-rag-data-into-an-index). Create a conversation memory to store all messages from a conversation: