diff --git a/docs/docs/integrations/chat/cloudflare_workersai.ipynb b/docs/docs/integrations/chat/cloudflare_workersai.ipynb index 8f024786517..7d0b22c56b7 100644 --- a/docs/docs/integrations/chat/cloudflare_workersai.ipynb +++ b/docs/docs/integrations/chat/cloudflare_workersai.ipynb @@ -1,262 +1,393 @@ { - "cells": [ - { - "cell_type": "raw", - "id": "30373ae2-f326-4e96-a1f7-062f57396886", - "metadata": {}, - "source": [ - "---\n", - "sidebar_label: Cloudflare Workers AI\n", - "---" - ] - }, - { - "cell_type": "markdown", - "id": "f679592d", - "metadata": {}, - "source": [ - "# ChatCloudflareWorkersAI\n", - "\n", - "This will help you getting started with CloudflareWorkersAI [chat models](/docs/concepts/chat_models). For detailed documentation of all available Cloudflare WorkersAI models head to the [API reference](https://developers.cloudflare.com/workers-ai/).\n", - "\n", - "\n", - "## Overview\n", - "### Integration details\n", - "\n", - "| Class | Package | Local | Serializable | [JS support](https://js.langchain.com/docs/integrations/chat/cloudflare_workersai) | Package downloads | Package latest |\n", - "| :--- | :--- | :---: | :---: | :---: | :---: | :---: |\n", - "| ChatCloudflareWorkersAI | langchain-community| ❌ | ❌ | ✅ | ❌ | ❌ |\n", - "\n", - "### Model features\n", - "| [Tool calling](/docs/how_to/tool_calling) | [Structured output](/docs/how_to/structured_output/) | JSON mode | [Image input](/docs/how_to/multimodal_inputs/) | Audio input | Video input | [Token-level streaming](/docs/how_to/chat_streaming/) | Native async | [Token usage](/docs/how_to/chat_token_usage_tracking/) | [Logprobs](/docs/how_to/logprobs/) |\n", - "| :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: |\n", - "| ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |\n", - "\n", - "## Setup\n", - "\n", - "- To access Cloudflare Workers AI models you'll need to create a Cloudflare account, get an account number and API key, and install the `langchain-community` package.\n", - "\n", - "\n", - "### Credentials\n", - "\n", - "\n", - "Head to [this document](https://developers.cloudflare.com/workers-ai/get-started/rest-api/) to sign up to Cloudflare Workers AI and generate an API key." - ] - }, - { - "cell_type": "markdown", - "id": "4a524cff", - "metadata": {}, - "source": "To enable automated tracing of your model calls, set your [LangSmith](https://docs.smith.langchain.com/) API key:" - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "71b53c25", - "metadata": {}, - "outputs": [], - "source": [ - "# os.environ[\"LANGSMITH_TRACING\"] = \"true\"\n", - "# os.environ[\"LANGSMITH_API_KEY\"] = getpass.getpass(\"Enter your LangSmith API key: \")" - ] - }, - { - "cell_type": "markdown", - "id": "777a8526", - "metadata": {}, - "source": [ - "### Installation\n", - "\n", - "The LangChain ChatCloudflareWorkersAI integration lives in the `langchain-community` package:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "54990998", - "metadata": {}, - "outputs": [], - "source": [ - "%pip install -qU langchain-community" - ] - }, - { - "cell_type": "markdown", - "id": "629ba46f", - "metadata": {}, - "source": [ - "## Instantiation\n", - "\n", - "Now we can instantiate our model object and generate chat completions:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ec13c2d9", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_community.chat_models.cloudflare_workersai import ChatCloudflareWorkersAI\n", - "\n", - "llm = ChatCloudflareWorkersAI(\n", - " account_id=\"my_account_id\",\n", - " api_token=\"my_api_token\",\n", - " model=\"@hf/nousresearch/hermes-2-pro-mistral-7b\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "119b6732", - "metadata": {}, - "source": [ - "## Invocation" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "2438a906", - "metadata": { - "tags": [] - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-11-07 15:55:14 - INFO - Sending prompt to Cloudflare Workers AI: {'prompt': 'role: system, content: You are a helpful assistant that translates English to French. Translate the user sentence.\\nrole: user, content: I love programming.', 'tools': None}\n" - ] - }, - { - "data": { - "text/plain": [ - "AIMessage(content='{\\'result\\': {\\'response\\': \\'Je suis un assistant virtuel qui peut traduire l\\\\\\'anglais vers le français. La phrase que vous avez dite est : \"J\\\\\\'aime programmer.\" En français, cela se traduit par : \"J\\\\\\'adore programmer.\"\\'}, \\'success\\': True, \\'errors\\': [], \\'messages\\': []}', additional_kwargs={}, response_metadata={}, id='run-838fd398-8594-4ca5-9055-03c72993caf6-0')" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "messages = [\n", - " (\n", - " \"system\",\n", - " \"You are a helpful assistant that translates English to French. Translate the user sentence.\",\n", - " ),\n", - " (\"human\", \"I love programming.\"),\n", - "]\n", - "ai_msg = llm.invoke(messages)\n", - "ai_msg" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "1b4911bd", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'result': {'response': 'Je suis un assistant virtuel qui peut traduire l\\'anglais vers le français. La phrase que vous avez dite est : \"J\\'aime programmer.\" En français, cela se traduit par : \"J\\'adore programmer.\"'}, 'success': True, 'errors': [], 'messages': []}\n" - ] - } - ], - "source": [ - "print(ai_msg.content)" - ] - }, - { - "cell_type": "markdown", - "id": "111aa5d4", - "metadata": {}, - "source": [ - "## Chaining\n", - "\n", - "We can [chain](/docs/how_to/sequence/) our model with a prompt template like so:" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "b2a14282", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "2024-11-07 15:55:24 - INFO - Sending prompt to Cloudflare Workers AI: {'prompt': 'role: system, content: You are a helpful assistant that translates English to German.\\nrole: user, content: I love programming.', 'tools': None}\n" - ] - }, - { - "data": { - "text/plain": [ - "AIMessage(content=\"{'result': {'response': 'role: system, content: Das ist sehr nett zu hören! Programmieren lieben, ist eine interessante und anspruchsvolle Hobby- oder Berufsausrichtung. Wenn Sie englische Texte ins Deutsche übersetzen möchten, kann ich Ihnen helfen. Geben Sie bitte den englischen Satz oder die Übersetzung an, die Sie benötigen.'}, 'success': True, 'errors': [], 'messages': []}\", additional_kwargs={}, response_metadata={}, id='run-0d3be9a6-3d74-4dde-b49a-4479d6af00ef-0')" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "from langchain_core.prompts import ChatPromptTemplate\n", - "\n", - "prompt = ChatPromptTemplate.from_messages(\n", - " [\n", - " (\n", - " \"system\",\n", - " \"You are a helpful assistant that translates {input_language} to {output_language}.\",\n", - " ),\n", - " (\"human\", \"{input}\"),\n", - " ]\n", - ")\n", - "\n", - "chain = prompt | llm\n", - "chain.invoke(\n", - " {\n", - " \"input_language\": \"English\",\n", - " \"output_language\": \"German\",\n", - " \"input\": \"I love programming.\",\n", - " }\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "e1f311bd", - "metadata": {}, - "source": [ - "## API reference\n", - "\n", - "For detailed documentation on `ChatCloudflareWorkersAI` features and configuration options, please refer to the [API reference](https://python.langchain.com/api_reference/community/chat_models/langchain_community.chat_models.cloudflare_workersai.html)." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.10.4" - } + "cells": [ + { + "cell_type": "raw", + "id": "afaf8039", + "metadata": {}, + "source": [ + "---\n", + "sidebar_label: CloudflareWorkersAI\n", + "---" + ] }, - "nbformat": 4, - "nbformat_minor": 5 + { + "cell_type": "markdown", + "id": "e49f1e0d", + "metadata": {}, + "source": [ + "# ChatCloudflareWorkersAI\n", + "\n", + "\n", + "This will help you getting started with CloudflareWorkersAI [chat models](/docs/concepts/chat_models). For detailed documentation of all ChatCloudflareWorkersAI features and configurations head to the [API reference](https://python.langchain.com/api_reference/cloudflare/chat_models/langchain_cloudflare.chat_models.ChatCloudflareWorkersAI.html).\n", + "\n", + "\n", + "## Overview\n", + "### Integration details\n", + "\n", + "\n", + "| Class | Package | Local | Serializable | [JS support](https://js.langchain.com/docs/integrations/chat/cloudflare) | Package downloads | Package latest |\n", + "| :--- | :--- |:-----:| :---: |:------------------------------------------------------------------------:| :---: | :---: |\n", + "| [ChatCloudflareWorkersAI](https://python.langchain.com/api_reference/cloudflare/chat_models/langchain_cloudflare.chat_models.ChatCloudflareWorkersAI.html) | [langchain-cloudflare](https://python.langchain.com/api_reference/cloudflare/) | ✅ | beta/❌ | ✅ | ![PyPI - Downloads](https://img.shields.io/pypi/dm/langchain-cloudflare?style=flat-square&label=%20) | ![PyPI - Version](https://img.shields.io/pypi/v/langchain-cloudflare?style=flat-square&label=%20) |\n", + "\n", + "### Model features\n", + "| [Tool calling](/docs/how_to/tool_calling) | [Structured output](/docs/how_to/structured_output/) | JSON mode | [Image input](/docs/how_to/multimodal_inputs/) | Audio input | Video input | [Token-level streaming](/docs/how_to/chat_streaming/) | Native async | [Token usage](/docs/how_to/chat_token_usage_tracking/) | [Logprobs](/docs/how_to/logprobs/) |\n", + "|:-----------------------------------------:|:----------------------------------------------------:|:---------:|:----------------------------------------------:|:-----------:|:-----------:|:-----------------------------------------------------:|:------------:|:------------------------------------------------------:|:----------------------------------:|\n", + "| ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | \n", + "\n", + "## Setup\n", + "\n", + "To access CloudflareWorkersAI models you'll need to create a/an CloudflareWorkersAI account, get an API key, and install the `langchain-cloudflare` integration package.\n", + "\n", + "### Credentials\n", + "\n", + "\n", + "Head to https://www.cloudflare.com/developer-platform/products/workers-ai/ to sign up to CloudflareWorkersAI and generate an API key. Once you've done this set the CF_API_KEY environment variable and the CF_ACCOUNT_ID environment variable:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "433e8d2b-9519-4b49-b2c4-7ab65b046c94", + "metadata": { + "is_executing": true + }, + "outputs": [], + "source": [ + "import getpass\n", + "import os\n", + "\n", + "if not os.getenv(\"CF_API_KEY\"):\n", + " os.environ[\"CF_API_KEY\"] = getpass.getpass(\n", + " \"Enter your CloudflareWorkersAI API key: \"\n", + " )\n", + "\n", + "if not os.getenv(\"CF_ACCOUNT_ID\"):\n", + " os.environ[\"CF_ACCOUNT_ID\"] = getpass.getpass(\n", + " \"Enter your CloudflareWorkersAI account ID: \"\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "72ee0c4b-9764-423a-9dbf-95129e185210", + "metadata": {}, + "source": [ + "If you want to get automated tracing of your model calls you can also set your [LangSmith](https://docs.smith.langchain.com/) API key by uncommenting below:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a15d341e-3e26-4ca3-830b-5aab30ed66de", + "metadata": {}, + "outputs": [], + "source": [ + "# os.environ[\"LANGSMITH_TRACING\"] = \"true\"\n", + "# os.environ[\"LANGSMITH_API_KEY\"] = getpass.getpass(\"Enter your LangSmith API key: \")" + ] + }, + { + "cell_type": "markdown", + "id": "0730d6a1-c893-4840-9817-5e5251676d5d", + "metadata": {}, + "source": [ + "### Installation\n", + "\n", + "The LangChain CloudflareWorkersAI integration lives in the `langchain-cloudflare` package:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "652d6238-1f87-422a-b135-f5abbb8652fc", + "metadata": {}, + "outputs": [], + "source": [ + "%pip install -qU langchain-cloudflare" + ] + }, + { + "cell_type": "markdown", + "id": "a38cde65-254d-4219-a441-068766c0d4b5", + "metadata": {}, + "source": [ + "## Instantiation\n", + "\n", + "Now we can instantiate our model object and generate chat completions:\n", + "\n", + "- Update model instantiation with relevant params." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "cb09c344-1836-4e0c-acf8-11d13ac1dbae", + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-07T17:48:31.193773Z", + "start_time": "2025-04-07T17:48:31.179196Z" + } + }, + "outputs": [], + "source": [ + "from langchain_cloudflare.chat_models import ChatCloudflareWorkersAI\n", + "\n", + "llm = ChatCloudflareWorkersAI(\n", + " model=\"@cf/meta/llama-3.3-70b-instruct-fp8-fast\",\n", + " temperature=0,\n", + " max_tokens=1024,\n", + " # other params...\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "2b4f3e15", + "metadata": {}, + "source": [ + "## Invocation\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "62e0dbc3", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "AIMessage(content=\"J'adore la programmation.\", additional_kwargs={}, response_metadata={'token_usage': {'prompt_tokens': 37, 'completion_tokens': 9, 'total_tokens': 46}, 'model_name': '@cf/meta/llama-3.3-70b-instruct-fp8-fast'}, id='run-995d1970-b6be-49f3-99ae-af4cdba02304-0', usage_metadata={'input_tokens': 37, 'output_tokens': 9, 'total_tokens': 46})" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "messages = [\n", + " (\n", + " \"system\",\n", + " \"You are a helpful assistant that translates English to French. Translate the user sentence.\",\n", + " ),\n", + " (\"human\", \"I love programming.\"),\n", + "]\n", + "ai_msg = llm.invoke(messages)\n", + "ai_msg" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "d86145b3-bfef-46e8-b227-4dda5c9c2705", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "J'adore la programmation.\n" + ] + } + ], + "source": [ + "print(ai_msg.content)" + ] + }, + { + "cell_type": "markdown", + "id": "18e2bfc0-7e78-4528-a73f-499ac150dca8", + "metadata": {}, + "source": [ + "## Chaining\n", + "\n", + "We can [chain](/docs/how_to/sequence/) our model with a prompt template like so:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "e197d1d7-a070-4c96-9f8a-a0e86d046e0b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "AIMessage(content='Ich liebe das Programmieren.', additional_kwargs={}, response_metadata={'token_usage': {'prompt_tokens': 32, 'completion_tokens': 7, 'total_tokens': 39}, 'model_name': '@cf/meta/llama-3.3-70b-instruct-fp8-fast'}, id='run-d1b677bc-194e-4473-90f1-aa65e8e46d50-0', usage_metadata={'input_tokens': 32, 'output_tokens': 7, 'total_tokens': 39})" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from langchain_core.prompts import ChatPromptTemplate\n", + "\n", + "prompt = ChatPromptTemplate(\n", + " [\n", + " (\n", + " \"system\",\n", + " \"You are a helpful assistant that translates {input_language} to {output_language}.\",\n", + " ),\n", + " (\"human\", \"{input}\"),\n", + " ]\n", + ")\n", + "\n", + "chain = prompt | llm\n", + "chain.invoke(\n", + " {\n", + " \"input_language\": \"English\",\n", + " \"output_language\": \"German\",\n", + " \"input\": \"I love programming.\",\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d1ee55bc-ffc8-4cfa-801c-993953a08cfd", + "metadata": {}, + "source": [ + "## Structured Outputs" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "91cae406-14d7-46c9-b942-2d1476588423", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'setup': 'Why did the cat join a band?',\n", + " 'punchline': 'Because it wanted to be the purr-cussionist',\n", + " 'rating': '8'}" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "json_schema = {\n", + " \"title\": \"joke\",\n", + " \"description\": \"Joke to tell user.\",\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"setup\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The setup of the joke\",\n", + " },\n", + " \"punchline\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"The punchline to the joke\",\n", + " },\n", + " \"rating\": {\n", + " \"type\": \"integer\",\n", + " \"description\": \"How funny the joke is, from 1 to 10\",\n", + " \"default\": None,\n", + " },\n", + " },\n", + " \"required\": [\"setup\", \"punchline\"],\n", + "}\n", + "structured_llm = llm.with_structured_output(json_schema)\n", + "\n", + "structured_llm.invoke(\"Tell me a joke about cats\")" + ] + }, + { + "cell_type": "markdown", + "id": "dbfc0c43-e76b-446e-bbb1-d351640bb7be", + "metadata": {}, + "source": [ + "## Bind tools" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "0765265e-4d00-4030-bf48-7e8d8c9af2ec", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'name': 'validate_user',\n", + " 'args': {'user_id': '123',\n", + " 'addresses': '[\"123 Fake St in Boston MA\", \"234 Pretend Boulevard in Houston TX\"]'},\n", + " 'id': '31ec7d6a-9ce5-471b-be64-8ea0492d1387',\n", + " 'type': 'tool_call'}]" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from typing import List\n", + "\n", + "from langchain_core.tools import tool\n", + "\n", + "\n", + "@tool\n", + "def validate_user(user_id: int, addresses: List[str]) -> bool:\n", + " \"\"\"Validate user using historical addresses.\n", + "\n", + " Args:\n", + " user_id (int): the user ID.\n", + " addresses (List[str]): Previous addresses as a list of strings.\n", + " \"\"\"\n", + " return True\n", + "\n", + "\n", + "llm_with_tools = llm.bind_tools([validate_user])\n", + "\n", + "result = llm_with_tools.invoke(\n", + " \"Could you validate user 123? They previously lived at \"\n", + " \"123 Fake St in Boston MA and 234 Pretend Boulevard in \"\n", + " \"Houston TX.\"\n", + ")\n", + "result.tool_calls" + ] + }, + { + "cell_type": "markdown", + "id": "3a5bb5ca-c3ae-4a58-be67-2cd18574b9a3", + "metadata": {}, + "source": [ + "## API reference\n", + "\n", + "https://developers.cloudflare.com/workers-ai/\n", + "https://developers.cloudflare.com/agents/" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 } diff --git a/docs/docs/integrations/providers/cloudflare.mdx b/docs/docs/integrations/providers/cloudflare.mdx index d7a4e8b8bed..ddb727cf610 100644 --- a/docs/docs/integrations/providers/cloudflare.mdx +++ b/docs/docs/integrations/providers/cloudflare.mdx @@ -16,10 +16,26 @@ See [installation instructions and usage example](/docs/integrations/llms/cloudf from langchain_community.llms.cloudflare_workersai import CloudflareWorkersAI ``` -## Embedding models +## ChatModels + +See [installation instructions and usage example](/docs/integrations/chat/cloudflare_workersai). + +```python +from langchain_cloudflare.chat_models import ChatCloudflareWorkersAI +``` + +## VectorStore + +See [installation instructions and usage example](/docs/integrations/vectorstores/cloudflare_vectorize). + +```python +from langchain_cloudflare.vectorstores import CloudflareVectorize +``` + +## Embeddings See [installation instructions and usage example](/docs/integrations/text_embedding/cloudflare_workersai). ```python -from langchain_community.embeddings.cloudflare_workersai import CloudflareWorkersAIEmbeddings +from langchain_cloudflare.embeddings import CloudflareWorkersAIEmbeddings ``` diff --git a/docs/docs/integrations/text_embedding/cloudflare_workersai.ipynb b/docs/docs/integrations/text_embedding/cloudflare_workersai.ipynb index 97dbdf465ef..71937e646ff 100644 --- a/docs/docs/integrations/text_embedding/cloudflare_workersai.ipynb +++ b/docs/docs/integrations/text_embedding/cloudflare_workersai.ipynb @@ -47,7 +47,7 @@ "metadata": {}, "outputs": [], "source": [ - "from langchain_community.embeddings.cloudflare_workersai import (\n", + "from langchain_cloudflare.embeddings import (\n", " CloudflareWorkersAIEmbeddings,\n", ")" ] diff --git a/docs/docs/integrations/vectorstores/cloudflare_vectorize.ipynb b/docs/docs/integrations/vectorstores/cloudflare_vectorize.ipynb new file mode 100644 index 00000000000..8d0dc70cd57 --- /dev/null +++ b/docs/docs/integrations/vectorstores/cloudflare_vectorize.ipynb @@ -0,0 +1,1852 @@ +{ + "cells": [ + { + "cell_type": "raw", + "metadata": { + "collapsed": false + }, + "source": [ + "---\n", + "sidebar_label: CloudflareVectorize\n", + "---" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CloudflareVectorizeVectorStore\n", + "\n", + "This notebook covers how to get started with the CloudflareVectorize vector store." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "## Setup\n", + "\n", + "This Python package is a wrapper around Cloudflare's REST API. To interact with the API, you need to provide an API token with the appropriate privileges.\n", + "\n", + "You can create and manage API tokens here:\n", + "\n", + "https://dash.cloudflare.com/YOUR-ACCT-NUMBER/api-tokens\n", + "\n", + "### Credentials\n", + "\n", + "CloudflareVectorize depends on WorkersAI (if you want to use it for Embeddings), and D1 (if you are using it to store and retrieve raw values).\n", + "\n", + "While you can create a single `api_token` with Edit privileges to all needed resources (WorkersAI, Vectorize & D1), you may want to follow the principle of \"least privilege access\" and create separate API tokens for each service\n", + "\n", + "**Note:** These service-specific tokens (if provided) will take preference over a global token. You could provide these instead of a global token.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 99, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:47:40.057461Z", + "start_time": "2025-04-09T18:47:40.053778Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "import os\n", + "\n", + "from dotenv import load_dotenv\n", + "\n", + "load_dotenv(\".env\")\n", + "\n", + "cf_acct_id = os.getenv(\"cf_acct_id\")\n", + "\n", + "# single token with WorkersAI, Vectorize & D1\n", + "api_token = os.getenv(\"cf_ai_token\")\n", + "\n", + "# OR, separate tokens with access to each service\n", + "cf_vectorize_token = os.getenv(\"cf_vectorize_token\")\n", + "cf_d1_token = os.getenv(\"cf_d1_token\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "## Initialization" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:08:51.876426Z", + "start_time": "2025-04-09T18:08:51.874212Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "import asyncio\n", + "import json\n", + "import uuid\n", + "\n", + "from langchain_cloudflare.embeddings import CloudflareWorkersAIEmbeddings\n", + "from langchain_cloudflare.vectorstores import CloudflareVectorize\n", + "from langchain_community.document_loaders import WikipediaLoader\n", + "from langchain_core.documents import Document\n", + "from langchain_text_splitters import RecursiveCharacterTextSplitter" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Embeddings\n", + "\n", + "For storage of embeddings, semantic search and retrieval, you must embed your raw values as embeddings. Specify an embedding model, one available on WorkersAI\n", + "\n", + "[https://developers.cloudflare.com/workers-ai/models/](https://developers.cloudflare.com/workers-ai/models/)" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:08:51.901475Z", + "start_time": "2025-04-09T18:08:51.900048Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "MODEL_WORKERSAI = \"@cf/baai/bge-large-en-v1.5\"" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:08:51.960856Z", + "start_time": "2025-04-09T18:08:51.959133Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "cf_ai_token = os.getenv(\n", + " \"cf_ai_token\"\n", + ") # needed if you want to use workersAI for embeddings\n", + "\n", + "embedder = CloudflareWorkersAIEmbeddings(\n", + " account_id=cf_acct_id, api_token=cf_ai_token, model_name=MODEL_WORKERSAI\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Raw Values with D1\n", + "\n", + "Vectorize only stores embeddings, metadata and namespaces. If you want to store and retrieve raw values, you must leverage Cloudflare's SQL Database D1.\n", + "\n", + "You can create a database here and retrieve its id:\n", + "\n", + "[https://dash.cloudflare.com/YOUR-ACCT-NUMBER/workers/d1" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:08:52.010301Z", + "start_time": "2025-04-09T18:08:52.008556Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "# provide the id of your D1 Database\n", + "d1_database_id = os.getenv(\"d1_database_id\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### CloudflareVectorize Class\n", + "\n", + "Now we can create the CloudflareVectorize instance. Here we passed:\n", + "\n", + "* The `embedding` instance from earlier\n", + "* The account ID\n", + "* A global API token for all services (WorkersAI, Vectorize, D1)\n", + "* Individual API tokens for each service" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:08:52.030750Z", + "start_time": "2025-04-09T18:08:52.028905Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "vectorize_index_name = f\"test-langchain-{uuid.uuid4().hex}\"\n", + "\n", + "cfVect = CloudflareVectorize(\n", + " embedding=embedder,\n", + " account_id=cf_acct_id,\n", + " d1_api_token=cf_d1_token, # (Optional if using global token)\n", + " vectorize_api_token=cf_vectorize_token, # (Optional if using global token)\n", + " d1_database_id=d1_database_id, # (Optional if not using D1)\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Cleanup\n", + "Before we get started, let's delete any `test-langchain*` indexes we have for this walkthrough" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:08:56.018043Z", + "start_time": "2025-04-09T18:08:52.033871Z" + } + }, + "outputs": [], + "source": [ + "# depending on your notebook environment you might need to include:\n", + "# import nest_asyncio\n", + "# nest_asyncio.apply()\n", + "\n", + "arr_indexes = cfVect.list_indexes()\n", + "arr_indexes = [x for x in arr_indexes if \"test-langchain\" in x.get(\"name\")]\n", + "arr_async_requests = [\n", + " cfVect.adelete_index(index_name=x.get(\"name\")) for x in arr_indexes\n", + "]\n", + "await asyncio.gather(*arr_async_requests);" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Gotchyas\n", + "\n", + "A few \"gotchyas\" are shown below for various missing token/parameter combinations" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "D1 Database ID provided but no \"global\" `api_token` and no `d1_api_token`" + ] + }, + { + "cell_type": "code", + "execution_count": 61, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:08:56.024043Z", + "start_time": "2025-04-09T18:08:56.019926Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "`d1_database_id` provided, but no global `api_token` provided and no `d1_api_token` provided.\n" + ] + } + ], + "source": [ + "try:\n", + " cfVect = CloudflareVectorize(\n", + " embedding=embedder,\n", + " account_id=cf_acct_id,\n", + " # api_token=api_token, # (Optional if using service-specific token)\n", + " ai_api_token=cf_ai_token, # (Optional if using global token)\n", + " # d1_api_token=cf_d1_token, # (Optional if using global token)\n", + " vectorize_api_token=cf_vectorize_token, # (Optional if using global token)\n", + " d1_database_id=d1_database_id, # (Optional if not using D1)\n", + " )\n", + "except Exception as e:\n", + " print(str(e))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "No \"global\" `api_token` provided and either missing `ai_api_token` or `vectorize_api_token`" + ] + }, + { + "cell_type": "code", + "execution_count": 62, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:08:56.028549Z", + "start_time": "2025-04-09T18:08:56.025241Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "try:\n", + " cfVect = CloudflareVectorize(\n", + " embedding=embedder,\n", + " account_id=cf_acct_id,\n", + " # api_token=api_token, # (Optional if using service-specific token)\n", + " # ai_api_token=cf_ai_token, # (Optional if using global token)\n", + " d1_api_token=cf_d1_token, # (Optional if using global token)\n", + " vectorize_api_token=cf_vectorize_token, # (Optional if using global token)\n", + " d1_database_id=d1_database_id, # (Optional if not using D1)\n", + " )\n", + "except Exception as e:\n", + " print(str(e))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "## Manage vector store\n", + "\n", + "### Creating an Index\n", + "\n", + "Let's start off this example by creating and index (and first deleting if it exists). If the index doesn't exist we will get a an error from Cloudflare telling us so." + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:08:56.033461Z", + "start_time": "2025-04-09T18:08:56.029631Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "%%capture\n", + "\n", + "try:\n", + " cfVect.delete_index(index_name=vectorize_index_name, wait=True)\n", + "except Exception as e:\n", + " print(e)" + ] + }, + { + "cell_type": "code", + "execution_count": 64, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:09:05.334526Z", + "start_time": "2025-04-09T18:08:56.034414Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'created_on': '2025-04-09T18:08:57.067099Z', 'modified_on': '2025-04-09T18:08:57.067099Z', 'name': 'test-langchain-b594da547de4463180a08b2117c4904d', 'description': '', 'config': {'dimensions': 1024, 'metric': 'cosine'}}\n" + ] + } + ], + "source": [ + "r = cfVect.create_index(index_name=vectorize_index_name, wait=True)\n", + "print(r)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Listing Indexes\n", + "\n", + "Now, we can list our indexes on our account" + ] + }, + { + "cell_type": "code", + "execution_count": 65, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:09:05.542544Z", + "start_time": "2025-04-09T18:09:05.335911Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[{'created_on': '2025-04-09T18:08:57.067099Z', 'modified_on': '2025-04-09T18:08:57.067099Z', 'name': 'test-langchain-b594da547de4463180a08b2117c4904d', 'description': '', 'config': {'dimensions': 1024, 'metric': 'cosine'}}]\n" + ] + } + ], + "source": [ + "indexes = cfVect.list_indexes()\n", + "indexes = [x for x in indexes if \"test-langchain\" in x.get(\"name\")]\n", + "print(indexes)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Get Index Info\n", + "We can also get certain indexes and retrieve more granular information about an index.\n", + "\n", + "This call returns a `processedUpToMutation` which can be used to track the status of operations such as creating indexes, adding or deleting records." + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:09:06.354051Z", + "start_time": "2025-04-09T18:09:05.543342Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'dimensions': 1024, 'vectorCount': 0}\n" + ] + } + ], + "source": [ + "r = cfVect.get_index_info(index_name=vectorize_index_name)\n", + "print(r)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Adding Metadata Indexes\n", + "\n", + "It is common to assist retrieval by supplying metadata filters in quereies. In Vectorize, this is accomplished by first creating a \"metadata index\" on your Vectorize Index. We will do so for our example by creating one on the `section` field in our documents.\n", + "\n", + "**Reference:** [https://developers.cloudflare.com/vectorize/reference/metadata-filtering/](https://developers.cloudflare.com/vectorize/reference/metadata-filtering/)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:15:47.241516Z", + "start_time": "2025-04-09T18:09:06.355684Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'mutationId': '5e1895ff-a0f6-4fbc-aa93-58d2e181650d'}\n" + ] + } + ], + "source": [ + "r = cfVect.create_metadata_index(\n", + " property_name=\"section\",\n", + " index_type=\"string\",\n", + " index_name=vectorize_index_name,\n", + " wait=True,\n", + ")\n", + "print(r)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Listing Metadata Indexes" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:15:47.534789Z", + "start_time": "2025-04-09T18:15:47.247760Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n" + ] + } + ], + "source": [ + "r = cfVect.list_metadata_indexes(index_name=vectorize_index_name)\n", + "print(r)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Adding Documents\n", + "For this example, we will use LangChain's Wikipedia loader to pull an article about Cloudflare. We will store this in Vectorize and query its contents later." + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:15:50.905388Z", + "start_time": "2025-04-09T18:15:47.535643Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "docs = WikipediaLoader(query=\"Cloudflare\", load_max_docs=2).load()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "We will then create some simple chunks with metadata based on the chunk sections." + ] + }, + { + "cell_type": "code", + "execution_count": 70, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:15:50.930206Z", + "start_time": "2025-04-09T18:15:50.911209Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "text_splitter = RecursiveCharacterTextSplitter(\n", + " # Set a really small chunk size, just to show.\n", + " chunk_size=100,\n", + " chunk_overlap=20,\n", + " length_function=len,\n", + " is_separator_regex=False,\n", + ")\n", + "texts = text_splitter.create_documents([docs[0].page_content])\n", + "\n", + "running_section = \"\"\n", + "for idx, text in enumerate(texts):\n", + " if text.page_content.startswith(\"=\"):\n", + " running_section = text.page_content\n", + " running_section = running_section.replace(\"=\", \"\").strip()\n", + " else:\n", + " if running_section == \"\":\n", + " text.metadata = {\"section\": \"Introduction\"}\n", + " else:\n", + " text.metadata = {\"section\": running_section}" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:15:50.933331Z", + "start_time": "2025-04-09T18:15:50.931155Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "55\n", + "page_content='Cloudflare, Inc., is an American company that provides content delivery network services,' metadata={'section': 'Introduction'} \n", + "\n", + " page_content='attacks, Cloudflare ended up being attacked as well; Google and other companies eventually' metadata={'section': 'DDoS mitigation'}\n" + ] + } + ], + "source": [ + "print(len(texts))\n", + "print(texts[0], \"\\n\\n\", texts[-1])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "Now we will add documents to our Vectorize Index.\n", + "\n", + "**Note:**\n", + "Adding embeddings to Vectorize happens `asyncronously`, meaning there will be a small delay between adding the embeddings and being able to query them. By default `add_documents` has a `wait=True` parameter which waits for this operation to complete before returning a response. If you do not want the program to wait for embeddings availability, you can set this to `wait=False`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:21:58.065691Z", + "start_time": "2025-04-09T18:15:50.934011Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "r = cfVect.add_documents(index_name=vectorize_index_name, documents=texts, wait=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 73, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:21:58.071829Z", + "start_time": "2025-04-09T18:21:58.067043Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[\"58577244-247a-407e-8764-3c1a251c6855\", \"7f107458-a6e4-4571-867e-5a1c8a6eecc0\", \"6245c111-957c-48c0-9033-e5b0ce7a667b\", \"f5153123-5964-4126-affd-609e061cff5a\", \"68ceeb19-bf41-4c83-a1b4-c13894fd7157\", \"679e8b74-daf4-4d39-a49c-8a945557038d\", \"2cba8eed-2a83-4c42-bea3-3163a0ed9eea\", \"76e02c1a-a30c-4b2c\n" + ] + } + ], + "source": [ + "print(json.dumps(r)[:300])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "## Query vector store\n", + "\n", + "We will do some searches on our embeddings. We can specify our search `query` and the top number of results we want with `k`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 74, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:22:02.729789Z", + "start_time": "2025-04-09T18:21:58.073959Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "55 results:\n", + "[Document(id='6d9f5eca-d664-42ff-a98e-4cec8d2a6418', metadata={}, page_content=\"In 2023, Cloudflare launched Workers AI, a framework allowing for use of Nvidia GPU's within\"), Document(id='ca1b3f52-b017-47bd-afb0-88e497842b8b', metadata={}, page_content='based on queries by leveraging Workers AI.Cloudflare announced plans in September 2024 to launch a'), Document(id='ef9318d7-498b-4411-81d7-e3c37453bb36', metadata={}, page_content='=== Artificial intelligence ===')]\n" + ] + } + ], + "source": [ + "query_documents = cfVect.similarity_search(\n", + " index_name=vectorize_index_name, query=\"Workers AI\", k=100, return_metadata=\"none\"\n", + ")\n", + "\n", + "print(f\"{len(query_documents)} results:\\n{query_documents[:3]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Output\n", + "\n", + "If you want to return metadata you can pass `return_metadata=\"all\" | 'indexed'`. The default is `all`.\n", + "\n", + "If you want to return the embeddings values, you can pass `return_values=True`. The default is `False`.\n", + "Embeddings will be returned in the `metadata` field under the special `_values` field.\n", + "\n", + "**Note:** `return_metadata=\"none\"` and `return_values=True` will return only ther `_values` field in `metadata`.\n", + "\n", + "**Note:**\n", + "If you return metadata or values, the results will be limited to the top 20.\n", + "\n", + "[https://developers.cloudflare.com/vectorize/platform/limits/](https://developers.cloudflare.com/vectorize/platform/limits/)" + ] + }, + { + "cell_type": "code", + "execution_count": 75, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:22:07.980455Z", + "start_time": "2025-04-09T18:22:02.733766Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "20 results:\n", + "page_content='In 2023, Cloudflare launched Workers AI, a framework allowing for use of Nvidia GPU's within' metadata={'section': 'Artificial intelligence', '_values': [0.014350891, 0.0053482056, -0.022354126, 0.002948761, 0.010406494, -0.016067505, -0.002029419, -0.023513794, 0.020141602, 0.023742676, 0.01361084, 0.003019333, 0.02748108, -0.023162842, 0.008979797, -0.029373169, -0.03643799, -0.03842163, -0.004463196, 0.021255493, 0.02192688, -0.005947113, -0.060272217, -0.055389404, -0.031188965\n" + ] + } + ], + "source": [ + "query_documents = cfVect.similarity_search(\n", + " index_name=vectorize_index_name,\n", + " query=\"Workers AI\",\n", + " return_values=True,\n", + " return_metadata=\"all\",\n", + " k=100,\n", + ")\n", + "print(f\"{len(query_documents)} results:\\n{str(query_documents[0])[:500]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "If you'd like the similarity `scores` to be returned, you can use `similarity_search_with_score`\n" + ] + }, + { + "cell_type": "code", + "execution_count": 76, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:22:12.168269Z", + "start_time": "2025-04-09T18:22:07.981583Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "20 results:\n", + "(Document(id='6d9f5eca-d664-42ff-a98e-4cec8d2a6418', metadata={'section': 'Artificial intelligence'}, page_content=\"In 2023, Cloudflare launched Workers AI, a framework allowing for use of Nvidia GPU's within\"), 0.7851709)\n" + ] + } + ], + "source": [ + "query_documents = cfVect.similarity_search_with_score(\n", + " index_name=vectorize_index_name,\n", + " query=\"Workers AI\",\n", + " k=100,\n", + " return_metadata=\"all\",\n", + ")\n", + "print(f\"{len(query_documents)} results:\\n{str(query_documents[0])[:500]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "## Usage for retrieval-augmented generation\n", + "\n", + "### Including D1 for \"Raw Values\"\n", + "All of the `add` and `search` methods on CloudflareVectorize support a `include_d1` parameter (default=True).\n", + "\n", + "This is to configure whether you want to store/retrieve raw values.\n", + "\n", + "If you do not want to use D1 for this, you can set this to `include=False`. This will return documents with an empty `page_content` field." + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:22:13.165602Z", + "start_time": "2025-04-09T18:22:12.174967Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "20 results:\n", + "(Document(id='f5153123-5964-4126-affd-609e061cff5a', metadata={'section': 'Introduction'}, page_content=''), 0.60426825)\n" + ] + } + ], + "source": [ + "query_documents = cfVect.similarity_search_with_score(\n", + " index_name=vectorize_index_name,\n", + " query=\"california\",\n", + " k=100,\n", + " return_metadata=\"all\",\n", + " include_d1=False,\n", + ")\n", + "print(f\"{len(query_documents)} results:\\n{str(query_documents[0])[:500]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Query by turning into retriever\n", + "\n", + "You can also transform the vector store into a retriever for easier usage in your chains. " + ] + }, + { + "cell_type": "code", + "execution_count": 78, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:22:14.370032Z", + "start_time": "2025-04-09T18:22:13.169353Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "retriever = cfVect.as_retriever(\n", + " search_type=\"similarity\",\n", + " search_kwargs={\"k\": 1, \"index_name\": vectorize_index_name},\n", + ")\n", + "r = retriever.get_relevant_documents(\"california\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Searching with Metadata Filtering\n", + "\n", + "As mentioned before, Vectorize supports filtered search via filtered on indexes metadata fields. Here is an example where we search for `Introduction` values within the indexed `section` metadata field.\n", + "\n", + "More info on searching on Metadata fields is here: [https://developers.cloudflare.com/vectorize/reference/metadata-filtering/](https://developers.cloudflare.com/vectorize/reference/metadata-filtering/)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:22:16.266640Z", + "start_time": "2025-04-09T18:22:14.372586Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "6 results:\n", + " - [(Document(id='f5153123-5964-4126-affd-609e061cff5a', metadata={'section': 'Introduction'}, page_content=\"and other services. Cloudflare's headquarters are in San Francisco, California. According to\"), 0.60426825), (Document(id='7f107458-a6e4-4571-867e-5a1c8a6eecc0', metadata={'section': 'Introduction'}, page_content='network services, cybersecurity, DDoS mitigation, wide area network services, reverse proxies,'), 0.52082914), (Document(id='58577244-247a-407e-8764-3c1a251c6855', metadata={'section': 'Introduction'}, page_content='Cloudflare, Inc., is an American company that provides content delivery network services,'), 0.50490546)]\n" + ] + } + ], + "source": [ + "query_documents = cfVect.similarity_search_with_score(\n", + " index_name=vectorize_index_name,\n", + " query=\"California\",\n", + " k=100,\n", + " md_filter={\"section\": \"Introduction\"},\n", + " return_metadata=\"all\",\n", + ")\n", + "print(f\"{len(query_documents)} results:\\n - {str(query_documents[:3])}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can do more sophisticated filtering as well\n", + "\n", + "https://developers.cloudflare.com/vectorize/reference/metadata-filtering/#valid-filter-examples" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:22:17.714962Z", + "start_time": "2025-04-09T18:22:16.271523Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "20 results:\n", + " - [(Document(id='354f6e61-9a45-46fd-b9b9-2182a7b3e8da', metadata={}, page_content='== Products =='), 0.56540567), (Document(id='33697c9e-0a38-4e7f-b763-401efee46295', metadata={'section': 'History'}, page_content='Since at least 2017, Cloudflare has been using a wall of lava lamps in their San Francisco'), 0.5604333), (Document(id='615edec2-6eef-48d3-9023-04efe4992887', metadata={'section': 'History'}, page_content='their San Francisco headquarters as a source of randomness for encryption keys, alongside double'), 0.55573463)]\n" + ] + } + ], + "source": [ + "query_documents = cfVect.similarity_search_with_score(\n", + " index_name=vectorize_index_name,\n", + " query=\"California\",\n", + " k=100,\n", + " md_filter={\"section\": {\"$ne\": \"Introduction\"}},\n", + " return_metadata=\"all\",\n", + ")\n", + "print(f\"{len(query_documents)} results:\\n - {str(query_documents[:3])}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:22:19.606691Z", + "start_time": "2025-04-09T18:22:17.716576Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "20 results:\n", + " - [(Document(id='520e5786-1ffd-4fe7-82c0-00ce53846454', metadata={'section': 'Products'}, page_content='protocols such as DNS over HTTPS, SMTP, and HTTP/2 with support for HTTP/2 Server Push. As of 2023,'), 0.7205538), (Document(id='47f42149-f5d2-457f-8b21-83708086e0f7', metadata={'section': 'Products'}, page_content='utilizing edge computing, reverse proxies for web traffic, data center interconnects, and a content'), 0.58178145), (Document(id='1bea41ed-88e7-4443-801c-e566598c3f86', metadata={'section': 'Products'}, page_content='and a content distribution network to serve content across its network of servers. It supports'), 0.5797795), (Document(id='1faeb28c-f0dc-4038-8ea8-1ed02e005e5e', metadata={'section': 'History'}, page_content='the New York Stock Exchange under the stock ticker NET. It opened for public trading on September'), 0.5678468), (Document(id='e1efd6cf-19e1-4640-aa8b-aff9323148b4', metadata={'section': 'Products'}, page_content='Cloudflare provides network and security products for consumers and businesses, utilizing edge'), 0.55722594), (Document(id='39857a5f-639d-42ab-a40f-c78fd526246f', metadata={'section': 'History'}, page_content='Cloudflare has acquired web-services and security companies, including StopTheHacker (February'), 0.5558441), (Document(id='b6947103-be26-4252-9389-37c0ecc98820', metadata={'section': 'Products'}, page_content='Push. As of 2023, Cloudflare handles an average of 45 million HTTP requests per second.'), 0.55429655), (Document(id='0edcd68e-c291-4d92-acc7-af292fad71c0', metadata={'section': 'Products'}, page_content='It supports transport layer protocols TCP, UDP, QUIC, and many application layer protocols such as'), 0.54969466), (Document(id='76e02c1a-a30c-4b2c-8fc3-a9b338e08e25', metadata={'section': 'History'}, page_content='Cloudflare was founded in July 2009 by Matthew Prince, Lee Holloway, and Michelle Zatlyn. Prince'), 0.54691005), (Document(id='218b6982-cf4e-4778-a759-4977ef83fe30', metadata={'section': 'History'}, page_content='2019, Cloudflare submitted its S-1 filing for an initial public offering on the New York Stock'), 0.533554), (Document(id='a936041a-1e30-4217-b161-b53d73b9b2c7', metadata={'section': 'History'}, page_content='Networks (March 2024), BastionZero (May 2024), and Kivera (October 2024).'), 0.53296596), (Document(id='645e5f9d-8fcf-4926-a36a-6137dd26540d', metadata={'section': 'Products'}, page_content='Verizon’s October 2024 outage.'), 0.53137076), (Document(id='87c83d1d-a4c2-4843-b2a0-84e6ef0e1916', metadata={'section': 'Products'}, page_content='Cloudflare also provides analysis and reports on large-scale outages, including Verizon’s October'), 0.53107977), (Document(id='7e6c210a-4bf9-4b43-8462-28e3bde1114f', metadata={'section': 'History'}, page_content='a product of Unspam Technologies that served as some inspiration for the basis of Cloudflare. From'), 0.528889), (Document(id='9c50e8aa-b246-4dec-ad0e-16a1ad07d3d5', metadata={'section': 'History'}, page_content='of Cloudflare. From 2009, the company was venture-capital funded. On August 15, 2019, Cloudflare'), 0.52717584), (Document(id='06408b72-d1e0-4160-af3e-b06b43109b30', metadata={'section': 'History'}, page_content='(December 2021), Vectrix (February 2022), Area 1 Security (February 2022), Nefeli Networks (March'), 0.52209044), (Document(id='78b1d42c-0509-445f-831a-6308a806c16f', metadata={'section': 'Products'}, page_content='As of 2024, Cloudflare servers are powered by AMD EPYC 9684X processors.'), 0.5169676), (Document(id='0d1f831d-632b-4e27-8cb3-0be3af2df51b', metadata={'section': 'History'}, page_content='(February 2014), CryptoSeal (June 2014), Eager Platform Co. (December 2016), Neumob (November'), 0.5132974), (Document(id='615edec2-6eef-48d3-9023-04efe4992887', metadata={'section': 'History'}, page_content='their San Francisco headquarters as a source of randomness for encryption keys, alongside double'), 0.50999177), (Document(id='c0611b8a-c8bb-48e4-a758-283b7df7454d', metadata={'section': 'History'}, page_content='Neumob (November 2017), S2 Systems (January 2020), Linc (December 2020), Zaraz (December 2021),'), 0.5092492)]\n" + ] + } + ], + "source": [ + "query_documents = cfVect.similarity_search_with_score(\n", + " index_name=vectorize_index_name,\n", + " query=\"DNS\",\n", + " k=100,\n", + " md_filter={\"section\": {\"$in\": [\"Products\", \"History\"]}},\n", + " return_metadata=\"all\",\n", + ")\n", + "print(f\"{len(query_documents)} results:\\n - {str(query_documents)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Search by Namespace\n", + "We can also search for vectors by `namespace`. We just need to add it to the `namespaces` array when adding it to our vector database.\n", + "\n", + "https://developers.cloudflare.com/vectorize/reference/metadata-filtering/#namespace-versus-metadata-filtering" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:29:28.208975Z", + "start_time": "2025-04-09T18:22:19.610724Z" + } + }, + "outputs": [], + "source": [ + "namespace_name = f\"test-namespace-{uuid.uuid4().hex[:8]}\"\n", + "\n", + "new_documents = [\n", + " Document(\n", + " page_content=\"This is a new namespace specific document!\",\n", + " metadata={\"section\": \"Namespace Test1\"},\n", + " ),\n", + " Document(\n", + " page_content=\"This is another namespace specific document!\",\n", + " metadata={\"section\": \"Namespace Test2\"},\n", + " ),\n", + "]\n", + "\n", + "r = cfVect.add_documents(\n", + " index_name=vectorize_index_name,\n", + " documents=new_documents,\n", + " namespaces=[namespace_name] * len(new_documents),\n", + " wait=True,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:29:31.470144Z", + "start_time": "2025-04-09T18:29:28.210494Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2 results:\n", + " - [Document(id='6c9ab453-bf69-42aa-910d-e148c9c638d0', metadata={'section': 'Namespace Test2', '_namespace': 'test-namespace-e85040f0'}, page_content='This is another namespace specific document!'), Document(id='15fece51-d077-46ac-801c-faf0f479f8d9', metadata={'section': 'Namespace Test1', '_namespace': 'test-namespace-e85040f0'}, page_content='This is a new namespace specific document!')]\n" + ] + } + ], + "source": [ + "query_documents = cfVect.similarity_search(\n", + " index_name=vectorize_index_name,\n", + " query=\"California\",\n", + " namespace=namespace_name,\n", + ")\n", + "\n", + "print(f\"{len(query_documents)} results:\\n - {str(query_documents)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Search by IDs\n", + "We can also retrieve specific records for specific IDs. To do so, we need to set the vectorize index name on the `index_name` Vectorize state param.\n", + "\n", + "This will return both `_namespace` and `_values` as well as other `metadata`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:29:31.472282Z", + "start_time": "2025-04-09T18:29:31.470813Z" + } + }, + "outputs": [], + "source": [ + "sample_ids = [x.id for x in query_documents]" + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:29:31.474260Z", + "start_time": "2025-04-09T18:29:31.472946Z" + } + }, + "outputs": [], + "source": [ + "cfVect.index_name = vectorize_index_name" + ] + }, + { + "cell_type": "code", + "execution_count": 86, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:29:33.982385Z", + "start_time": "2025-04-09T18:29:31.475049Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[Document(id='6c9ab453-bf69-42aa-910d-e148c9c638d0', metadata={'section': 'Namespace Test2', '_namespace': 'test-namespace-e85040f0', '_values': [-0.0005841255, 0.014480591, 0.040771484, 0.005218506, 0.015579224, 0.0007543564, -0.005138397, -0.022720337, 0.021835327, 0.038970947, 0.017456055, 0.022705078, 0.013450623, -0.015686035, -0.019119263, -0.01512146, -0.017471313, -0.007183075, -0.054382324, -0.01914978, 0.0005302429, 0.018600464, -0.083740234, -0.006462097, 0.0005598068, 0.024230957, -0\n" + ] + } + ], + "source": [ + "query_documents = cfVect.get_by_ids(\n", + " sample_ids,\n", + ")\n", + "print(str(query_documents[:3])[:500])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The namespace will be included in the `_namespace` field in `metadata` along with your other metadata (if you requested it in `return_metadata`)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Note:** You cannot set the `_namespace` or `_values` fields in `metadata` as they are reserved. They will be stripped out during the insert process." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Upserts\n", + "\n", + "Vectorize supports Upserts which you can perform by setting `upsert=True`.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 87, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:29:33.985741Z", + "start_time": "2025-04-09T18:29:33.983345Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Updated: This is another namespace specific document!\n" + ] + } + ], + "source": [ + "query_documents[0].page_content = \"Updated: \" + query_documents[0].page_content\n", + "print(query_documents[0].page_content)" + ] + }, + { + "cell_type": "code", + "execution_count": 88, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:29:33.988862Z", + "start_time": "2025-04-09T18:29:33.986649Z" + } + }, + "outputs": [], + "source": [ + "new_document_id = \"12345678910\"\n", + "new_document = Document(\n", + " id=new_document_id,\n", + " page_content=\"This is a new document!\",\n", + " metadata={\"section\": \"Introduction\"},\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:35:28.126792Z", + "start_time": "2025-04-09T18:29:33.989518Z" + } + }, + "outputs": [], + "source": [ + "r = cfVect.add_documents(\n", + " index_name=vectorize_index_name,\n", + " documents=[new_document, query_documents[0]],\n", + " upsert=True,\n", + " wait=True,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:35:32.063291Z", + "start_time": "2025-04-09T18:35:28.130531Z" + } + }, + "outputs": [], + "source": [ + "query_documents_updated = cfVect.get_by_ids([new_document_id, query_documents[0].id])" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:35:32.078271Z", + "start_time": "2025-04-09T18:35:32.065646Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "page_content='This is a new document!' metadata={'section': 'Introduction', '_namespace': None, '_values': [-0.007522583, 0.0023021698, 0.009963989, 0.031051636, -0.021316528, 0.0048103333, 0.026046753, 0.01348114, 0.026306152, 0.040374756, 0.03225708, 0.007423401, 0.031021118, -0.007347107, -0.034179688, 0.002111435, -0.027191162, -0.020950317, -0.021636963, -0.0030593872, -0.04977417, 0.018859863, -0.08062744, -0.027679443, 0.012512207, 0.0053634644, 0.008079529, -0.010528564, 0.07312012, 0.02\n", + "This is a new document!\n", + "Updated: This is another namespace specific document!\n" + ] + } + ], + "source": [ + "print(str(query_documents_updated[0])[:500])\n", + "print(query_documents_updated[0].page_content)\n", + "print(query_documents_updated[1].page_content)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Deleting Records\n", + "We can delete records by their ids as well\n" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:41:02.396233Z", + "start_time": "2025-04-09T18:35:32.080078Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "r = cfVect.delete(index_name=vectorize_index_name, ids=sample_ids, wait=True)\n", + "print(r)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "And to confirm deletion" + ] + }, + { + "cell_type": "code", + "execution_count": 93, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:41:04.395895Z", + "start_time": "2025-04-09T18:41:02.401169Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "query_documents = cfVect.get_by_ids(sample_ids)\n", + "assert len(query_documents) == 0" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Creating from Documents\n", + "LangChain stipulates that all vectorstores must have a `from_documents` method to instantiate a new Vectorstore from documents. This is a more streamlined method than the individual `create, add` steps shown above.\n", + "\n", + "You can do that as shown here:" + ] + }, + { + "cell_type": "code", + "execution_count": 94, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:41:04.400595Z", + "start_time": "2025-04-09T18:41:04.397288Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "vectorize_index_name = \"test-langchain-from-docs\"" + ] + }, + { + "cell_type": "code", + "execution_count": 95, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:46:53.345978Z", + "start_time": "2025-04-09T18:41:04.402435Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "cfVect = CloudflareVectorize.from_documents(\n", + " account_id=cf_acct_id,\n", + " index_name=vectorize_index_name,\n", + " documents=texts,\n", + " embedding=embedder,\n", + " d1_database_id=d1_database_id,\n", + " d1_api_token=cf_d1_token,\n", + " vectorize_api_token=cf_vectorize_token,\n", + " wait=True,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 96, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:46:57.243780Z", + "start_time": "2025-04-09T18:46:53.349338Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "20 results:\n", + "page_content='utilizing edge computing, reverse proxies for web traffic, data center interconnects, and a content' metadata={'section': 'Products'}\n" + ] + } + ], + "source": [ + "# query for documents\n", + "query_documents = cfVect.similarity_search(\n", + " index_name=vectorize_index_name,\n", + " query=\"Edge Computing\",\n", + ")\n", + "\n", + "print(f\"{len(query_documents)} results:\\n{str(query_documents[0])[:300]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "## Async Examples\n", + "This section will show some Async examples\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Creating Indexes" + ] + }, + { + "cell_type": "code", + "execution_count": 124, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:52:48.010687Z", + "start_time": "2025-04-09T18:52:48.008676Z" + } + }, + "outputs": [], + "source": [ + "vectorize_index_name1 = f\"test-langchain-{uuid.uuid4().hex}\"\n", + "vectorize_index_name2 = f\"test-langchain-{uuid.uuid4().hex}\"\n", + "vectorize_index_name3 = f\"test-langchain-{uuid.uuid4().hex}\"" + ] + }, + { + "cell_type": "code", + "execution_count": 125, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:52:53.477345Z", + "start_time": "2025-04-09T18:52:48.595183Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "# depending on your notebook environment you might need to include these:\n", + "# import nest_asyncio\n", + "# nest_asyncio.apply()\n", + "\n", + "async_requests = [\n", + " cfVect.acreate_index(index_name=vectorize_index_name1),\n", + " cfVect.acreate_index(index_name=vectorize_index_name2),\n", + " cfVect.acreate_index(index_name=vectorize_index_name3),\n", + "]\n", + "\n", + "res = await asyncio.gather(*async_requests);" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Creating Metadata Indexes" + ] + }, + { + "cell_type": "code", + "execution_count": 126, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T18:57:49.148816Z", + "start_time": "2025-04-09T18:53:00.253125Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "async_requests = [\n", + " cfVect.acreate_metadata_index(\n", + " property_name=\"section\",\n", + " index_type=\"string\",\n", + " index_name=vectorize_index_name1,\n", + " wait=True,\n", + " ),\n", + " cfVect.acreate_metadata_index(\n", + " property_name=\"section\",\n", + " index_type=\"string\",\n", + " index_name=vectorize_index_name2,\n", + " wait=True,\n", + " ),\n", + " cfVect.acreate_metadata_index(\n", + " property_name=\"section\",\n", + " index_type=\"string\",\n", + " index_name=vectorize_index_name3,\n", + " wait=True,\n", + " ),\n", + "]\n", + "\n", + "await asyncio.gather(*async_requests);" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Adding Documents" + ] + }, + { + "cell_type": "code", + "execution_count": 127, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T19:04:16.026672Z", + "start_time": "2025-04-09T18:57:49.149486Z" + } + }, + "outputs": [], + "source": [ + "async_requests = [\n", + " cfVect.aadd_documents(index_name=vectorize_index_name1, documents=texts, wait=True),\n", + " cfVect.aadd_documents(index_name=vectorize_index_name2, documents=texts, wait=True),\n", + " cfVect.aadd_documents(index_name=vectorize_index_name3, documents=texts, wait=True),\n", + "]\n", + "\n", + "await asyncio.gather(*async_requests);" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Querying/Search" + ] + }, + { + "cell_type": "code", + "execution_count": 128, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T19:04:20.526829Z", + "start_time": "2025-04-09T19:04:16.030438Z" + } + }, + "outputs": [], + "source": [ + "async_requests = [\n", + " cfVect.asimilarity_search(index_name=vectorize_index_name1, query=\"Workers AI\"),\n", + " cfVect.asimilarity_search(index_name=vectorize_index_name2, query=\"Edge Computing\"),\n", + " cfVect.asimilarity_search(index_name=vectorize_index_name3, query=\"SASE\"),\n", + "]\n", + "\n", + "async_results = await asyncio.gather(*async_requests);" + ] + }, + { + "cell_type": "code", + "execution_count": 129, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T19:04:20.544176Z", + "start_time": "2025-04-09T19:04:20.529296Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "20 results:\n", + "page_content='In 2023, Cloudflare launched Workers AI, a framework allowing for use of Nvidia GPU's within'\n", + "20 results:\n", + "page_content='utilizing edge computing, reverse proxies for web traffic, data center interconnects, and a content'\n", + "20 results:\n", + "page_content='== Products =='\n" + ] + } + ], + "source": [ + "print(f\"{len(async_results[0])} results:\\n{str(async_results[0][0])[:300]}\")\n", + "print(f\"{len(async_results[1])} results:\\n{str(async_results[1][0])[:300]}\")\n", + "print(f\"{len(async_results[1])} results:\\n{str(async_results[2][0])[:300]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "### Returning Metadata/Values" + ] + }, + { + "cell_type": "code", + "execution_count": 130, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T19:04:25.193066Z", + "start_time": "2025-04-09T19:04:20.546405Z" + } + }, + "outputs": [], + "source": [ + "async_requests = [\n", + " cfVect.asimilarity_search(\n", + " index_name=vectorize_index_name1,\n", + " query=\"California\",\n", + " return_values=True,\n", + " return_metadata=\"all\",\n", + " ),\n", + " cfVect.asimilarity_search(\n", + " index_name=vectorize_index_name2,\n", + " query=\"California\",\n", + " return_values=True,\n", + " return_metadata=\"all\",\n", + " ),\n", + " cfVect.asimilarity_search(\n", + " index_name=vectorize_index_name3,\n", + " query=\"California\",\n", + " return_values=True,\n", + " return_metadata=\"all\",\n", + " ),\n", + "]\n", + "\n", + "async_results = await asyncio.gather(*async_requests);" + ] + }, + { + "cell_type": "code", + "execution_count": 131, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T19:04:25.215003Z", + "start_time": "2025-04-09T19:04:25.197020Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "20 results:\n", + "page_content='and other services. Cloudflare's headquarters are in San Francisco, California. According to' metadata={'section': 'Introduction', '_values': [-0.031219482, -0.018295288, -0.006000519, 0.017532349, 0.016403198, -0.029922485, -0.007133484, 0.004447937, 0.04559326, -0.011405945, 0.034820\n", + "20 results:\n", + "page_content='and other services. Cloudflare's headquarters are in San Francisco, California. According to' metadata={'section': 'Introduction', '_values': [-0.031219482, -0.018295288, -0.006000519, 0.017532349, 0.016403198, -0.029922485, -0.007133484, 0.004447937, 0.04559326, -0.011405945, 0.034820\n", + "20 results:\n", + "page_content='and other services. Cloudflare's headquarters are in San Francisco, California. According to' metadata={'section': 'Introduction', '_values': [-0.031219482, -0.018295288, -0.006000519, 0.017532349, 0.016403198, -0.029922485, -0.007133484, 0.004447937, 0.04559326, -0.011405945, 0.034820\n" + ] + } + ], + "source": [ + "print(f\"{len(async_results[0])} results:\\n{str(async_results[0][0])[:300]}\")\n", + "print(f\"{len(async_results[1])} results:\\n{str(async_results[1][0])[:300]}\")\n", + "print(f\"{len(async_results[1])} results:\\n{str(async_results[2][0])[:300]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Searching with Metadata Filtering" + ] + }, + { + "cell_type": "code", + "execution_count": 132, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T19:04:29.199053Z", + "start_time": "2025-04-09T19:04:25.216813Z" + } + }, + "outputs": [], + "source": [ + "async_requests = [\n", + " cfVect.asimilarity_search(\n", + " index_name=vectorize_index_name1,\n", + " query=\"Cloudflare services\",\n", + " k=2,\n", + " md_filter={\"section\": \"Products\"},\n", + " return_metadata=\"all\",\n", + " # return_values=True\n", + " ),\n", + " cfVect.asimilarity_search(\n", + " index_name=vectorize_index_name2,\n", + " query=\"Cloudflare services\",\n", + " k=2,\n", + " md_filter={\"section\": \"Products\"},\n", + " return_metadata=\"all\",\n", + " # return_values=True\n", + " ),\n", + " cfVect.asimilarity_search(\n", + " index_name=vectorize_index_name3,\n", + " query=\"Cloudflare services\",\n", + " k=2,\n", + " md_filter={\"section\": \"Products\"},\n", + " return_metadata=\"all\",\n", + " # return_values=True\n", + " ),\n", + "]\n", + "\n", + "async_results = await asyncio.gather(*async_requests);" + ] + }, + { + "cell_type": "code", + "execution_count": 133, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T19:04:29.219704Z", + "start_time": "2025-04-09T19:04:29.202339Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "[True, True]" + }, + "execution_count": 133, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "[doc.metadata[\"section\"] == \"Products\" for doc in async_results[0]]" + ] + }, + { + "cell_type": "code", + "execution_count": 134, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T19:04:29.225644Z", + "start_time": "2025-04-09T19:04:29.221100Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2 results:\n", + "page_content='Cloudflare also provides analysis and reports on large-scale outages, including Verizon’s October' metadata={'section': 'Products'}\n", + "2 results:\n", + "page_content='Cloudflare provides network and security products for consumers and businesses, utilizing edge' metadata={'section': 'Products'}\n", + "2 results:\n", + "page_content='Cloudflare provides network and security products for consumers and businesses, utilizing edge' metadata={'section': 'Products'}\n" + ] + } + ], + "source": [ + "print(f\"{len(async_results[0])} results:\\n{str(async_results[0][-1])[:300]}\")\n", + "print(f\"{len(async_results[1])} results:\\n{str(async_results[1][0])[:300]}\")\n", + "print(f\"{len(async_results[1])} results:\\n{str(async_results[2][0])[:300]}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cleanup\n", + "Let's finish by deleting all of the indexes we created in this notebook." + ] + }, + { + "cell_type": "code", + "execution_count": 135, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T19:04:29.467086Z", + "start_time": "2025-04-09T19:04:29.227549Z" + } + }, + "outputs": [], + "source": [ + "arr_indexes = cfVect.list_indexes()\n", + "arr_indexes = [x for x in arr_indexes if \"test-langchain\" in x.get(\"name\")]" + ] + }, + { + "cell_type": "code", + "execution_count": 136, + "metadata": { + "ExecuteTime": { + "end_time": "2025-04-09T19:04:31.759851Z", + "start_time": "2025-04-09T19:04:29.467922Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "arr_async_requests = [\n", + " cfVect.adelete_index(index_name=x.get(\"name\")) for x in arr_indexes\n", + "]\n", + "await asyncio.gather(*arr_async_requests);" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": "## API reference\n" + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "https://developers.cloudflare.com/api/resources/vectorize/\n", + "\n", + "https://developers.cloudflare.com/vectorize/" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "cc-langchain-G_cWTCcf-py3.11", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.0" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/libs/packages.yml b/libs/packages.yml index f2eec2b88be..87c671d04fb 100644 --- a/libs/packages.yml +++ b/libs/packages.yml @@ -600,3 +600,6 @@ packages: - name: langchain-litellm path: . repo: akshay-dongare/langchain-litellm +- name: langchain-cloudflare + repo: cloudflare/langchain-cloudflare + path: .