From 9da1e18cb8577ca14156b60a526f015edd3fc73a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Boschi?= Date: Wed, 18 Oct 2023 23:26:46 +0200 Subject: [PATCH 1/4] Add Rag with AWS example --- conf/cli.yaml | 16 --- examples/applications/rag-aws/README.md | 36 +++++++ examples/applications/rag-aws/chatbot.yaml | 95 ++++++++++++++++++ .../applications/rag-aws/configuration.yaml | 35 +++++++ examples/applications/rag-aws/gateways.yaml | 26 +++++ examples/applications/rag-aws/ingest.yaml | 99 +++++++++++++++++++ .../agents/vector/InterpolationUtils.java | 8 +- 7 files changed, 295 insertions(+), 20 deletions(-) create mode 100644 examples/applications/rag-aws/README.md create mode 100644 examples/applications/rag-aws/chatbot.yaml create mode 100644 examples/applications/rag-aws/configuration.yaml create mode 100644 examples/applications/rag-aws/gateways.yaml create mode 100644 examples/applications/rag-aws/ingest.yaml diff --git a/conf/cli.yaml b/conf/cli.yaml index fa4f1c48a..20efec03c 100644 --- a/conf/cli.yaml +++ b/conf/cli.yaml @@ -1,19 +1,3 @@ -# -# Copyright DataStax, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - --- webServiceUrl: "http://localhost:8090" apiGatewayUrl: "ws://localhost:8091" diff --git a/examples/applications/rag-aws/README.md b/examples/applications/rag-aws/README.md new file mode 100644 index 000000000..3dfe4d55a --- /dev/null +++ b/examples/applications/rag-aws/README.md @@ -0,0 +1,36 @@ +# Indexing a WebSite + +This sample application shows how to use the WebCrawler Source Connector + +## Prerequisites + +- Create a S3 bucket. +- Setup OpenSearch Serverless in your AWS account. +- Setup Bedrock models. + + +## Configure access to the Vector Database + +Export some ENV variables in order to configure access to the database: + +``` +export BEDROCK_ACCESS_KEY=... +export BEDROCK_SECRET_KEY=... + +export OPENSEARCH_USERNAME= +export OPENSEARCH_PASSWORD= +export OPENSEARCH_HOST=xxxx..aoss.amazonaws.com +export OPENSEARCH_REGION= + +export S3_BUCKET_NAME=.. +export S3_ACCESS_KEY=.. +export S3_SECRET=.. +export S3_ENDPOINT=https://s3.amazonaws.com +``` + + +## Deploy the LangStream application + +``` +./bin/langstream docker run test -app examples/applications/rag-aws -s examples/secrets/secrets.yaml +``` diff --git a/examples/applications/rag-aws/chatbot.yaml b/examples/applications/rag-aws/chatbot.yaml new file mode 100644 index 000000000..75e04a6d5 --- /dev/null +++ b/examples/applications/rag-aws/chatbot.yaml @@ -0,0 +1,95 @@ +# +# Copyright DataStax, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +topics: + - name: "questions-topic" + creation-mode: create-if-not-exists + - name: "answers-topic" + creation-mode: create-if-not-exists +errors: + on-failure: "skip" +pipeline: + - name: "convert-to-structure" + type: "document-to-json" + input: "questions-topic" + configuration: + text-field: "question" + - name: "compute-embeddings" + type: "compute-ai-embeddings" + configuration: + model: "amazon.titan-embed-text-v1" + embeddings-field: "value.embeddings_vector" + text: "{{ value.question }}" + batch-size: 10 + flush-interval: 500 + - name: "lookup-related-documents" + type: "query-vector-db" + configuration: + datasource: "OpenSearch" + query: | + { + "index": "rag-index-example-3", + "size": 10, + "query": { + "knn": { + "embeddings": { + "vector": ?, + "k": 10 + } + } + } + } + fields: + - "value.embeddings_vector" + output-field: "value.related_documents" + - name: "ai-chat-completions" + type: "ai-chat-completions" + configuration: + model: "anthropic.claude-v2" + completion-field: "value.answer" + min-chunks-per-message: 5 + log-field: "value.prompt" + options: + request-parameters: + temperature: 0.8 + max_tokens_to_sample: 200 + top_p: 0.9 + top_k: 250 + response-completions-expression: "completion" + messages: + - content: | + + Human: + + + The user is asking questions about books. Please provide an answer to him as response and add an explanation. Do not respond with generic information, only use the information provided in this prompt. If you don't know, just say so. + The user question is: "{{ value.question}}?". + Information you can use are the following: + + {{# value.related_documents}} + ##### + {{ document.content }} + {{/ value.related_documents}} + + Assistant: + - name: "Format response" + type: compute + output: "answers-topic" + configuration: + fields: + - name: "value" + type: STRING + expression: "value.answer" diff --git a/examples/applications/rag-aws/configuration.yaml b/examples/applications/rag-aws/configuration.yaml new file mode 100644 index 000000000..fd5889546 --- /dev/null +++ b/examples/applications/rag-aws/configuration.yaml @@ -0,0 +1,35 @@ +# +# +# Copyright DataStax, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +configuration: + resources: + - type: "bedrock-configuration" + name: "Bedrock" + configuration: + access-key: "${secrets.bedrock.access-key}" + secret-key: "${secrets.bedrock.secret-key}" + region: "${secrets.bedrock.region}" + - type: "vector-database" + name: "OpenSearch" + configuration: + service: "opensearch" + username: "${secrets.opensearch.username}" + password: "${secrets.opensearch.password}" + host: "${secrets.opensearch.host}" + port: "${secrets.opensearch.port}" + https: "${secrets.opensearch.https}" + region: "${secrets.opensearch.region}" \ No newline at end of file diff --git a/examples/applications/rag-aws/gateways.yaml b/examples/applications/rag-aws/gateways.yaml new file mode 100644 index 000000000..58970998c --- /dev/null +++ b/examples/applications/rag-aws/gateways.yaml @@ -0,0 +1,26 @@ +# +# +# Copyright DataStax, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +gateways: + - id: chat + type: chat + chat-options: + answers-topic: answers-topic + questions-topic: questions-topic + headers: + - key: langstream-client-session-id + value-from-parameters: sessionId diff --git a/examples/applications/rag-aws/ingest.yaml b/examples/applications/rag-aws/ingest.yaml new file mode 100644 index 000000000..f0f912979 --- /dev/null +++ b/examples/applications/rag-aws/ingest.yaml @@ -0,0 +1,99 @@ +# +# Copyright DataStax, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +name: "Ingest text files from S3" +assets: + - name: "os-index" + asset-type: "opensearch-index" + creation-mode: create-if-not-exists + config: + index-name: "rag-index-example-3" + datasource: "OpenSearch" + settings: | + { + "index": { + "knn": true, + "knn.algo_param.ef_search": 100 + } + } + mappings: | + { + "properties": { + "content": { + "type": "text" + }, + "embeddings": { + "type": "knn_vector", + "dimension": 1536 + } + } + } +pipeline: + - name: "Read from S3" + type: "s3-source" + configuration: + bucketName: "${secrets.s3.bucket-name}" + endpoint: "${secrets.s3.endpoint}" + access-key: "${secrets.s3.access-key}" + secret-key: "${secrets.s3.secret}" + region: "${secrets.s3.region}" + idle-time: 5 + - name: "Extract text" + type: "text-extractor" + - name: "Normalise text" + type: "text-normaliser" + configuration: + make-lowercase: true + trim-spaces: true + - name: "Split into chunks" + type: "text-splitter" + configuration: + splitter_type: "RecursiveCharacterTextSplitter" + chunk_size: 400 + separators: ["\n\n", "\n", " ", ""] + keep_separator: false + chunk_overlap: 100 + length_function: "cl100k_base" + - name: "Convert to structured data" + type: "document-to-json" + configuration: + text-field: text + copy-properties: true + - name: "prepare-structure" + type: "compute" + configuration: + fields: + - name: "value.filename" + expression: "properties.url" + type: STRING + - name: "compute-embeddings" + type: "compute-ai-embeddings" + configuration: + model: "amazon.titan-embed-text-v1" + embeddings-field: "value.embeddings_vector" + text: "{{ value.text }}" + batch-size: 10 + flush-interval: 500 + - name: "Write to vector db" + type: "vector-db-sink" + configuration: + datasource: "OpenSearch" + index-name: "rag-index-example-3" + fields: + - name: "embeddings" + expression: "value.embeddings_vector" + - name: "content" + expression: "value.text" \ No newline at end of file diff --git a/langstream-agents/langstream-vector-agents/src/main/java/ai/langstream/agents/vector/InterpolationUtils.java b/langstream-agents/langstream-vector-agents/src/main/java/ai/langstream/agents/vector/InterpolationUtils.java index 44fd8a269..cfa5cec92 100644 --- a/langstream-agents/langstream-vector-agents/src/main/java/ai/langstream/agents/vector/InterpolationUtils.java +++ b/langstream-agents/langstream-vector-agents/src/main/java/ai/langstream/agents/vector/InterpolationUtils.java @@ -86,11 +86,11 @@ public static final R buildObjectFromJson( try { if (log.isDebugEnabled()) { log.debug("Query {}", json); + params.forEach( + param -> + log.debug( + "Param {} {}", param, param != null ? param.getClass() : null)); } - params.forEach( - param -> - log.info( - "Param {} {}", param, param != null ? param.getClass() : null)); // interpolate the query json = interpolate(json, params); if (log.isDebugEnabled()) { From ccd87af3a467c4b444c8a38e5436d047de1f3ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Boschi?= Date: Thu, 19 Oct 2023 00:18:10 +0200 Subject: [PATCH 2/4] fix --- conf/cli.yaml | 16 ++++++++++++++++ .../agents/vector/InterpolationUtils.java | 4 +++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/conf/cli.yaml b/conf/cli.yaml index 20efec03c..fa4f1c48a 100644 --- a/conf/cli.yaml +++ b/conf/cli.yaml @@ -1,3 +1,19 @@ +# +# Copyright DataStax, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + --- webServiceUrl: "http://localhost:8090" apiGatewayUrl: "ws://localhost:8091" diff --git a/langstream-agents/langstream-vector-agents/src/main/java/ai/langstream/agents/vector/InterpolationUtils.java b/langstream-agents/langstream-vector-agents/src/main/java/ai/langstream/agents/vector/InterpolationUtils.java index cfa5cec92..6d5d504af 100644 --- a/langstream-agents/langstream-vector-agents/src/main/java/ai/langstream/agents/vector/InterpolationUtils.java +++ b/langstream-agents/langstream-vector-agents/src/main/java/ai/langstream/agents/vector/InterpolationUtils.java @@ -89,7 +89,9 @@ public static final R buildObjectFromJson( params.forEach( param -> log.debug( - "Param {} {}", param, param != null ? param.getClass() : null)); + "Param {} {}", + param, + param != null ? param.getClass() : null)); } // interpolate the query json = interpolate(json, params); From 7b8ebca66d2a7b901296afe399922931d8f7434f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Boschi?= Date: Thu, 19 Oct 2023 01:10:28 +0200 Subject: [PATCH 3/4] add re-rank --- conf/cli.yaml | 16 ---------------- examples/applications/rag-aws/chatbot.yaml | 14 ++++++++++++++ .../langstream/ai/agents/rerank/ReRankAgent.java | 8 ++++++-- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/conf/cli.yaml b/conf/cli.yaml index fa4f1c48a..20efec03c 100644 --- a/conf/cli.yaml +++ b/conf/cli.yaml @@ -1,19 +1,3 @@ -# -# Copyright DataStax, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - --- webServiceUrl: "http://localhost:8090" apiGatewayUrl: "ws://localhost:8091" diff --git a/examples/applications/rag-aws/chatbot.yaml b/examples/applications/rag-aws/chatbot.yaml index 75e04a6d5..7bc618b49 100644 --- a/examples/applications/rag-aws/chatbot.yaml +++ b/examples/applications/rag-aws/chatbot.yaml @@ -55,6 +55,20 @@ pipeline: fields: - "value.embeddings_vector" output-field: "value.related_documents" + - name: "re-rank documents with MMR" + type: "re-rank" + configuration: + max: 5 # keep only the top 5 documents, because we have an hard limit on the prompt size + field: "value.related_documents" + query-text: "value.question" + query-embeddings: "value.embeddings_vector" + output-field: "value.related_documents" + text-field: "record.document.content" + embeddings-field: "record.document.embeddings" + algorithm: "MMR" + lambda: 0.5 + k1: 1.2 + b: 0.75 - name: "ai-chat-completions" type: "ai-chat-completions" configuration: diff --git a/langstream-agents/langstream-ai-agents/src/main/java/ai/langstream/ai/agents/rerank/ReRankAgent.java b/langstream-agents/langstream-ai-agents/src/main/java/ai/langstream/ai/agents/rerank/ReRankAgent.java index cca2fe7ef..72a858130 100644 --- a/langstream-agents/langstream-ai-agents/src/main/java/ai/langstream/ai/agents/rerank/ReRankAgent.java +++ b/langstream-agents/langstream-ai-agents/src/main/java/ai/langstream/ai/agents/rerank/ReRankAgent.java @@ -116,9 +116,13 @@ public List processRecord(Record record) throws Exception { context.setRecordObject(o); String text = recordTextAccessor.evaluate(context); float[] embeddings = toArrayOfFloat(recordEmbeddingsAccessor.evaluate(context)); - if (embeddings == null || text == null) { + if (embeddings == null) { throw new IllegalArgumentException( - "Text or embeddings are null in record " + o); + "Embeddings are null in record: " + o); + } + if (text == null) { + throw new IllegalArgumentException( + "Text is null in record: " + o); } return new TextWithEmbeddings(text, embeddings); }; From 945a44941e02d2a228f272933d9c72b548c91216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Boschi?= Date: Thu, 19 Oct 2023 01:11:21 +0200 Subject: [PATCH 4/4] fix --- conf/cli.yaml | 16 ++++++++++++++++ .../langstream/ai/agents/rerank/ReRankAgent.java | 6 ++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/conf/cli.yaml b/conf/cli.yaml index 20efec03c..fa4f1c48a 100644 --- a/conf/cli.yaml +++ b/conf/cli.yaml @@ -1,3 +1,19 @@ +# +# Copyright DataStax, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + --- webServiceUrl: "http://localhost:8090" apiGatewayUrl: "ws://localhost:8091" diff --git a/langstream-agents/langstream-ai-agents/src/main/java/ai/langstream/ai/agents/rerank/ReRankAgent.java b/langstream-agents/langstream-ai-agents/src/main/java/ai/langstream/ai/agents/rerank/ReRankAgent.java index 72a858130..b9d26063a 100644 --- a/langstream-agents/langstream-ai-agents/src/main/java/ai/langstream/ai/agents/rerank/ReRankAgent.java +++ b/langstream-agents/langstream-ai-agents/src/main/java/ai/langstream/ai/agents/rerank/ReRankAgent.java @@ -117,12 +117,10 @@ public List processRecord(Record record) throws Exception { String text = recordTextAccessor.evaluate(context); float[] embeddings = toArrayOfFloat(recordEmbeddingsAccessor.evaluate(context)); if (embeddings == null) { - throw new IllegalArgumentException( - "Embeddings are null in record: " + o); + throw new IllegalArgumentException("Embeddings are null in record: " + o); } if (text == null) { - throw new IllegalArgumentException( - "Text is null in record: " + o); + throw new IllegalArgumentException("Text is null in record: " + o); } return new TextWithEmbeddings(text, embeddings); };