diff --git a/.github/workflows/api_doc_build.yml b/.github/workflows/api_doc_build.yml index 6c412d3855b27..442a5ab18ed80 100644 --- a/.github/workflows/api_doc_build.yml +++ b/.github/workflows/api_doc_build.yml @@ -90,6 +90,10 @@ jobs: with: repository: langchain-ai/langchain-mongodb path: langchain-mongodb + - uses: actions/checkout@v4 + with: + repository: langchain-ai/langchain-redis + path: langchain-redis @@ -119,7 +123,8 @@ jobs: langchain/libs/partners/databricks \ langchain/libs/partners/ibm \ langchain/libs/partners/azure-dynamic-sessions \ - langchain/libs/partners/mongodb + langchain/libs/partners/mongodb \ + langchain/libs/partners/redis mv langchain-google/libs/genai langchain/libs/partners/google-genai mv langchain-google/libs/vertexai langchain/libs/partners/google-vertexai mv langchain-google/libs/community langchain/libs/partners/google-community @@ -139,6 +144,7 @@ jobs: mv langchain-ibm/libs/ibm langchain/libs/partners/ibm mv langchain-azure/libs/azure-dynamic-sessions langchain/libs/partners/azure-dynamic-sessions mv langchain-mongodb/libs/mongodb langchain/libs/partners/mongodb + mv langchain-redis/libs/redis langchain/libs/partners/redis - name: Rm old html run: diff --git a/docs/docs/concepts/retrieval.mdx b/docs/docs/concepts/retrieval.mdx index 1735f3565746b..a69fb8d4f9d54 100644 --- a/docs/docs/concepts/retrieval.mdx +++ b/docs/docs/concepts/retrieval.mdx @@ -65,7 +65,7 @@ Various techniques have been developed to leverage models for query re-writing, | Name | When to use | Description | |-----------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| [Multi-query](/docs/how_to/MultiQueryRetriever/) | When you want to ensure high recall in retrieval by providing multiple pharsings of a question. | Rewrite the user question with multiple pharsings, retrieve documents for each rewritten question, return the unique documents for all queries. | +| [Multi-query](/docs/how_to/MultiQueryRetriever/) | When you want to ensure high recall in retrieval by providing multiple phrasings of a question. | Rewrite the user question with multiple phrasings, retrieve documents for each rewritten question, return the unique documents for all queries. | | [Decomposition](https://github.com/langchain-ai/rag-from-scratch/blob/main/rag_from_scratch_5_to_9.ipynb) | When a question can be broken down into smaller subproblems. | Decompose a question into a set of subproblems / questions, which can either be solved sequentially (use the answer from first + retrieval to answer the second) or in parallel (consolidate each answer into final answer). | | [Step-back](https://github.com/langchain-ai/rag-from-scratch/blob/main/rag_from_scratch_5_to_9.ipynb) | When a higher-level conceptual understanding is required. | First prompt the LLM to ask a generic step-back question about higher-level concepts or principles, and retrieve relevant facts about them. Use this grounding to help answer the user question. [Paper](https://arxiv.org/pdf/2310.06117). | | [HyDE](https://github.com/langchain-ai/rag-from-scratch/blob/main/rag_from_scratch_5_to_9.ipynb) | If you have challenges retrieving relevant documents using the raw user inputs. | Use an LLM to convert questions into hypothetical documents that answer the question. Use the embedded hypothetical documents to retrieve real documents with the premise that doc-doc similarity search can produce more relevant matches. [Paper](https://arxiv.org/abs/2212.10496). | diff --git a/docs/docs/integrations/chat/ibm_watsonx.ipynb b/docs/docs/integrations/chat/ibm_watsonx.ipynb index 28a6b4072b04b..a3ef2d572397d 100644 --- a/docs/docs/integrations/chat/ibm_watsonx.ipynb +++ b/docs/docs/integrations/chat/ibm_watsonx.ipynb @@ -34,9 +34,9 @@ "## Overview\n", "\n", "### Integration details\n", - "| Class | Package | Local | Serializable | [JS support](https://js.langchain.com/docs/integrations/chat/openai) | Package downloads | Package latest |\n", + "| Class | Package | Local | Serializable | [JS support](https://js.langchain.com/docs/integrations/chat/ibm/) | Package downloads | Package latest |\n", "| :--- | :--- | :---: | :---: | :---: | :---: | :---: |\n", - "| ChatWatsonx | ❌ | ❌ | ❌ | ❌ | ![PyPI - Downloads](https://img.shields.io/pypi/dm/langchain-ibm?style=flat-square&label=%20) | ![PyPI - Version](https://img.shields.io/pypi/v/langchain-ibm?style=flat-square&label=%20) |\n", + "| [ChatWatsonx](https://python.langchain.com/api_reference/ibm/chat_models/langchain_ibm.chat_models.ChatWatsonx.html#langchain_ibm.chat_models.ChatWatsonx) | [langchain-ibm](https://python.langchain.com/api_reference/ibm/index.html) | ❌ | ❌ | ✅ | ![PyPI - Downloads](https://img.shields.io/pypi/dm/langchain-ibm?style=flat-square&label=%20) | ![PyPI - Version](https://img.shields.io/pypi/v/langchain-ibm?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 | 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", @@ -549,6 +549,16 @@ "source": [ "ai_msg.tool_calls" ] + }, + { + "cell_type": "markdown", + "id": "95fcbf93", + "metadata": {}, + "source": [ + "## API reference\n", + "\n", + "For detailed documentation of all `ChatWatsonx` features and configurations head to the [API reference](https://python.langchain.com/api_reference/ibm/chat_models/langchain_ibm.chat_models.ChatWatsonx.html)." + ] } ], "metadata": { diff --git a/docs/docs/integrations/llms/ibm_watsonx.ipynb b/docs/docs/integrations/llms/ibm_watsonx.ipynb index 640d59889995c..10360b7ff4dc1 100644 --- a/docs/docs/integrations/llms/ibm_watsonx.ipynb +++ b/docs/docs/integrations/llms/ibm_watsonx.ipynb @@ -14,33 +14,32 @@ }, { "cell_type": "markdown", - "id": "ea35b2b7", + "id": "5b8d9390", "metadata": {}, "source": [ - "## Setting up\n", + "## Overview\n", "\n", - "Install the package `langchain-ibm`." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "2f1fff4e", - "metadata": {}, - "outputs": [], - "source": [ - "!pip install -qU langchain-ibm" + "### Integration details\n", + "| Class | Package | Local | Serializable | [JS support](https://js.langchain.com/docs/integrations/llms/ibm/) | Package downloads | Package latest |\n", + "| :--- | :--- | :---: | :---: | :---: | :---: | :---: |\n", + "| [WatsonxLLM](https://python.langchain.com/api_reference/ibm/llms/langchain_ibm.llms.WatsonxLLM.html) | [langchain-ibm](https://python.langchain.com/api_reference/ibm/index.html) | ❌ | ❌ | ✅ | ![PyPI - Downloads](https://img.shields.io/pypi/dm/langchain-ibm?style=flat-square&label=%20) | ![PyPI - Version](https://img.shields.io/pypi/v/langchain-ibm?style=flat-square&label=%20) |" ] }, { "cell_type": "markdown", - "id": "f406e092", + "id": "ea35b2b7", "metadata": {}, "source": [ - "This cell defines the WML credentials required to work with watsonx Foundation Model inferencing.\n", + "## Setup\n", + "\n", + "To access IBM watsonx.ai models you'll need to create an IBM watsonx.ai account, get an API key, and install the `langchain-ibm` integration package.\n", + "\n", + "### Credentials\n", + "\n", + "The cell below defines the credentials required to work with watsonx Foundation Model inferencing.\n", "\n", "**Action:** Provide the IBM Cloud user API key. For details, see\n", - "[documentation](https://cloud.ibm.com/docs/account?topic=account-userapikey&interface=ui)." + "[Managing user API keys](https://cloud.ibm.com/docs/account?topic=account-userapikey&interface=ui)." ] }, { @@ -81,19 +80,39 @@ "os.environ[\"WATSONX_INSTANCE_ID\"] = \"your instance_id for accessing the CPD cluster\"" ] }, + { + "cell_type": "markdown", + "id": "f918d229", + "metadata": {}, + "source": [ + "### Installation\n", + "\n", + "The LangChain IBM integration lives in the `langchain-ibm` package:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f925c9aa", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install -qU langchain-ibm" + ] + }, { "cell_type": "markdown", "id": "e36acbef", "metadata": {}, "source": [ - "## Load the model\n", + "## Instantiation\n", "\n", "You might need to adjust model `parameters` for different models or tasks. For details, refer to [documentation](https://ibm.github.io/watsonx-ai-python-sdk/fm_model.html#metanames.GenTextParamsMetaNames)." ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 1, "id": "407cd500", "metadata": {}, "outputs": [], @@ -124,7 +143,7 @@ "In this example, we’ll use the `project_id` and Dallas url.\n", "\n", "\n", - "You need to specify `model_id` that will be used for inferencing. All available models you can find in [documentation](https://ibm.github.io/watsonx-ai-python-sdk/fm_model.html#ibm_watsonx_ai.foundation_models.utils.enums.ModelTypes)." + "You need to specify `model_id` that will be used for inferencing. All available models you can find in [documentation](https://ibm.github.io/watsonx-ai-python-sdk/fm_model.html#TextModels)." ] }, { @@ -241,84 +260,28 @@ "watsonx_llm = WatsonxLLM(watsonx_model=model)" ] }, - { - "cell_type": "markdown", - "id": "c25ecbd1", - "metadata": {}, - "source": [ - "## Create Chain\n", - "Create `PromptTemplate` objects which will be responsible for creating a random question." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "c7d80c05", - "metadata": {}, - "outputs": [], - "source": [ - "from langchain_core.prompts import PromptTemplate\n", - "\n", - "template = \"Generate a random question about {topic}: Question: \"\n", - "\n", - "prompt = PromptTemplate.from_template(template)" - ] - }, - { - "cell_type": "markdown", - "id": "79056d8e", - "metadata": {}, - "source": [ - "Provide a topic and run the chain." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "dc076c56", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'What is the difference between a dog and a wolf?'" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "llm_chain = prompt | watsonx_llm\n", - "\n", - "topic = \"dog\"\n", - "\n", - "llm_chain.invoke(topic)" - ] - }, { "cell_type": "markdown", "id": "f571001d", "metadata": {}, "source": [ - "## Calling the Model Directly\n", + "## Invocation\n", "To obtain completions, you can call the model directly using a string prompt." ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 3, "id": "beea2b5b", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "\"Man's best friend is his dog. \"" + "\"Man's best friend is his dog. Dogs are man's best friend because they are always there for you, they never judge you, and they love you unconditionally. Dogs are also great companions and can help reduce stress levels. \"" ] }, - "execution_count": 7, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -331,17 +294,17 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 4, "id": "8ab1a25a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "LLMResult(generations=[[Generation(text='The fastest dog in the world is the greyhound, which can run up to 45 miles per hour. This is about the same speed as a human running down a track. Greyhounds are very fast because they have long legs, a streamlined body, and a strong tail. They can run this fast for short distances, but they can also run for long distances, like a marathon. ', generation_info={'finish_reason': 'eos_token'})], [Generation(text='The Beagle is a scent hound, meaning it is bred to hunt by following a trail of scents.', generation_info={'finish_reason': 'eos_token'})]], llm_output={'token_usage': {'generated_token_count': 106, 'input_token_count': 13}, 'model_id': 'ibm/granite-13b-instruct-v2', 'deployment_id': ''}, run=[RunInfo(run_id=UUID('52cb421d-b63f-4c5f-9b04-d4770c664725')), RunInfo(run_id=UUID('df2ea606-1622-4ed7-8d5d-8f6e068b71c4'))])" + "LLMResult(generations=[[Generation(text='The fastest dog in the world is the greyhound. Greyhounds can run up to 45 mph, which is about the same speed as a Usain Bolt.', generation_info={'finish_reason': 'eos_token'})], [Generation(text='The Labrador Retriever is a breed of retriever that was bred for hunting. They are a very smart breed and are very easy to train. They are also very loyal and will make great companions. ', generation_info={'finish_reason': 'eos_token'})]], llm_output={'token_usage': {'generated_token_count': 82, 'input_token_count': 13}, 'model_id': 'ibm/granite-13b-instruct-v2', 'deployment_id': None}, run=[RunInfo(run_id=UUID('750b8a0f-8846-456d-93d0-e039e95b1276')), RunInfo(run_id=UUID('aa4c2a1c-5b08-4fcf-87aa-50228de46db5'))], type='LLMResult')" ] }, - "execution_count": 11, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -369,7 +332,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 5, "id": "3f63166a", "metadata": {}, "outputs": [ @@ -377,7 +340,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "My favorite breed of dog is a Labrador Retriever. Labradors are my favorite because they are extremely smart, very friendly, and love to be with people. They are also very playful and love to run around and have a lot of energy. " + "My favorite breed of dog is a Labrador Retriever. They are my favorite breed because they are my favorite color, yellow. They are also very smart and easy to train. " ] } ], @@ -387,6 +350,72 @@ "):\n", " print(chunk, end=\"\")" ] + }, + { + "cell_type": "markdown", + "id": "9fc88fdd", + "metadata": {}, + "source": [ + "## Chaining\n", + "Create `PromptTemplate` objects which will be responsible for creating a random question." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "ad63fa27", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_core.prompts import PromptTemplate\n", + "\n", + "template = \"Generate a random question about {topic}: Question: \"\n", + "\n", + "prompt = PromptTemplate.from_template(template)" + ] + }, + { + "cell_type": "markdown", + "id": "677699db", + "metadata": {}, + "source": [ + "Provide a topic and run the chain." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "868af75c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'What is the origin of the name \"Pomeranian\"?'" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "llm_chain = prompt | watsonx_llm\n", + "\n", + "topic = \"dog\"\n", + "\n", + "llm_chain.invoke(topic)" + ] + }, + { + "cell_type": "markdown", + "id": "59480270", + "metadata": {}, + "source": [ + "## API reference\n", + "\n", + "For detailed documentation of all `WatsonxLLM` features and configurations head to the [API reference](https://python.langchain.com/api_reference/ibm/llms/langchain_ibm.llms.WatsonxLLM.html)." + ] } ], "metadata": { @@ -405,7 +434,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.10.14" } }, "nbformat": 4, diff --git a/docs/docs/integrations/providers/databricks.md b/docs/docs/integrations/providers/databricks.md index 0acb3287b88bd..54a10c7c6a62c 100644 --- a/docs/docs/integrations/providers/databricks.md +++ b/docs/docs/integrations/providers/databricks.md @@ -20,6 +20,18 @@ First-party Databricks integrations are available in the langchain-databricks pa pip install langchain-databricks ``` +🚧 Upcoming Package Consolidation Notice + +This package (`langchain-databricks`) will soon be consolidated into a new package: `databricks-langchain`. The new package will serve as the primary hub for all Databricks Langchain integrations. + +What’s Changing? +In the coming months, `databricks-langchain` will include all features currently in `langchain-databricks`, as well as additional integrations to provide a unified experience for Databricks users. + +What You Need to Know +For now, continue to use `langchain-databricks` as usual. When `databricks-langchain` is ready, we’ll provide clear migration instructions to make the transition seamless. During the transition period, `langchain-databricks` will remain operational, and updates will be shared here with timelines and guidance. + +Thank you for your support as we work toward an improved, streamlined experience! + Chat Model ---------- diff --git a/docs/docs/integrations/providers/ibm.mdx b/docs/docs/integrations/providers/ibm.mdx index bb6f5ef065e70..c98df29e434e6 100644 --- a/docs/docs/integrations/providers/ibm.mdx +++ b/docs/docs/integrations/providers/ibm.mdx @@ -57,3 +57,13 @@ See a [usage example](/docs/integrations/text_embedding/ibm_watsonx). ```python from langchain_ibm import WatsonxEmbeddings ``` + +## Reranker + +### WatsonxRerank + +See a [usage example](/docs/integrations/retrievers/ibm_watsonx_ranker). + +```python +from langchain_ibm import WatsonxRerank +``` diff --git a/docs/docs/integrations/retrievers/ibm_watsonx_ranker.ipynb b/docs/docs/integrations/retrievers/ibm_watsonx_ranker.ipynb new file mode 100644 index 0000000000000..66b804e2dcd4d --- /dev/null +++ b/docs/docs/integrations/retrievers/ibm_watsonx_ranker.ipynb @@ -0,0 +1,467 @@ +{ + "cells": [ + { + "cell_type": "raw", + "id": "5a18a9c7", + "metadata": { + "vscode": { + "languageId": "raw" + } + }, + "source": [ + "---\n", + "sidebar_label: IBM watsonx.ai\n", + "---" + ] + }, + { + "cell_type": "markdown", + "id": "fc0db1bc", + "metadata": {}, + "source": [ + "# WatsonxRerank\n", + "\n", + ">WatsonxRerank is a wrapper for IBM [watsonx.ai](https://www.ibm.com/products/watsonx-ai) foundation models.\n", + "\n", + "This notebook shows how to use [watsonx's rerank endpoint](https://cloud.ibm.com/apidocs/watsonx-ai#text-rerank) in a retriever. This builds on top of ideas in the [ContextualCompressionRetriever](/docs/how_to/contextual_compression)." + ] + }, + { + "cell_type": "markdown", + "id": "398667f7", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "### Integration details\n", + "\n", + "| Class | Package | JS support | Package downloads | Package latest |\n", + "| :--- | :--- | :---: | :---: | :---: |\n", + "| [WatsonxRerank](https://python.langchain.com/api_reference/ibm/chat_models/langchain_ibm.rerank.WatsonxRerank.html) | [langchain-ibm](https://python.langchain.com/api_reference/ibm/index.html) | ❌ | ![PyPI - Downloads](https://img.shields.io/pypi/dm/langchain-ibm?style=flat-square&label=%20) | ![PyPI - Version](https://img.shields.io/pypi/v/langchain-ibm?style=flat-square&label=%20) |" + ] + }, + { + "cell_type": "markdown", + "id": "4049caf1", + "metadata": {}, + "source": [ + "## Setup\n", + "\n", + "To access IBM watsonx.ai models you'll need to create an IBM watsonx.ai account, get an API key, and install the `langchain-ibm` integration package.\n", + "\n", + "### Credentials\n", + "\n", + "The cell below defines the credentials required to work with watsonx Foundation Model inferencing.\n", + "\n", + "**Action:** Provide the IBM Cloud user API key. For details, see\n", + "[Managing user API keys](https://cloud.ibm.com/docs/account?topic=account-userapikey&interface=ui)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b658a43", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "from getpass import getpass\n", + "\n", + "watsonx_api_key = getpass()\n", + "os.environ[\"WATSONX_APIKEY\"] = watsonx_api_key" + ] + }, + { + "cell_type": "markdown", + "id": "6947421a", + "metadata": {}, + "source": [ + "Additionally you are able to pass additional secrets as an environment variable. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f599671b", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "\n", + "os.environ[\"WATSONX_URL\"] = \"your service instance url\"\n", + "os.environ[\"WATSONX_TOKEN\"] = \"your token for accessing the CPD cluster\"\n", + "os.environ[\"WATSONX_PASSWORD\"] = \"your password for accessing the CPD cluster\"\n", + "os.environ[\"WATSONX_USERNAME\"] = \"your username for accessing the CPD cluster\"\n", + "os.environ[\"WATSONX_INSTANCE_ID\"] = \"your instance_id for accessing the CPD cluster\"" + ] + }, + { + "cell_type": "markdown", + "id": "0f2c4918", + "metadata": {}, + "source": [ + "### Installation\n", + "\n", + "The LangChain IBM integration lives in the `langchain-ibm` package:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "4f5973bb-7897-4340-a8ce-c3365ee73b2f", + "metadata": {}, + "outputs": [], + "source": [ + "!pip install -qU langchain-ibm\n", + "!pip install -qU langchain-community\n", + "!pip install -qU langchain_text_splitters" + ] + }, + { + "cell_type": "markdown", + "id": "da97c16c", + "metadata": {}, + "source": [ + "For experiment purpose please also install `faiss` or `faiss-cpu` package:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b37bd138-4f3c-4d2c-bc4b-be705ce27a09", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "!pip install --upgrade --quiet faiss\n", + "\n", + "# OR (depending on Python version)\n", + "\n", + "!pip install --upgrade --quiet faiss-cpu" + ] + }, + { + "cell_type": "markdown", + "id": "5bab56bf", + "metadata": {}, + "source": [ + "Helper function for printing docs" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "6fa3d916", + "metadata": { + "jp-MarkdownHeadingCollapsed": true, + "tags": [] + }, + "outputs": [], + "source": [ + "def pretty_print_docs(docs):\n", + " print(\n", + " f\"\\n{'-' * 100}\\n\".join(\n", + " [f\"Document {i+1}:\\n\\n\" + d.page_content for i, d in enumerate(docs)]\n", + " )\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "f5057385", + "metadata": { + "jp-MarkdownHeadingCollapsed": true, + "tags": [] + }, + "source": [ + "## Instantiation\n", + "\n", + "### Set up the base vector store retriever\n", + "Let's start by initializing a simple vector store retriever and storing the 2023 State of the Union speech (in chunks). We can set up the retriever to retrieve a high number (20) of docs.\n", + "\n", + "Initialize the `WatsonxEmbeddings`. For more details see [WatsonxEmbeddings](/docs/integrations/text_embedding/ibm_watsonx).\n", + "\n", + "**Note**: \n", + "\n", + "- To provide context for the API call, you must add `project_id` or `space_id`. For more information see [documentation](https://www.ibm.com/docs/en/watsonx-as-a-service?topic=projects).\n", + "- Depending on the region of your provisioned service instance, use one of the urls described [here](https://ibm.github.io/watsonx-ai-python-sdk/setup_cloud.html#authentication).\n", + "\n", + "In this example, we’ll use the `project_id` and Dallas url.\n", + "\n", + "You need to specify `model_id` that will be used for embedding. All available models you can find in [documentation](https://ibm.github.io/watsonx-ai-python-sdk/fm_embeddings.html#EmbeddingModels)." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "029dc5e7", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_ibm import WatsonxEmbeddings\n", + "\n", + "wx_embeddings = WatsonxEmbeddings(\n", + " model_id=\"ibm/slate-125m-english-rtrvr\",\n", + " url=\"https://us-south.ml.cloud.ibm.com\",\n", + " project_id=\"PASTE YOUR PROJECT_ID HERE\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "b7648612", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Document 1:\n", + "\n", + "One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \n", + "\n", + "And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.\n", + "----------------------------------------------------------------------------------------------------\n", + "Document 2:\n", + "\n", + "I spoke with their families and told them that we are forever in debt for their sacrifice, and we will carry on their mission to restore the trust and safety every community deserves. \n", + "\n", + "I’ve worked on these issues a long time. \n", + "\n", + "I know what works: Investing in crime prevention and community police officers who’ll walk the beat, who’ll know the neighborhood, and who can restore trust and safety. \n", + "\n", + "So let’s not abandon our streets. Or choose between safety and equal justice.\n", + "----------------------------------------------------------------------------------------------------\n", + "Document 3:\n", + "\n", + "He met the Ukrainian people. \n", + "\n", + "From President Zelenskyy to every Ukrainian, their fearlessness, their courage, their determination, inspires the world. \n", + "\n", + "Groups of citizens blocking tanks with their bodies. Everyone from students to retirees teachers turned soldiers defending their homeland. \n", + "\n", + "In this struggle as President Zelenskyy said in his speech to the European Parliament “Light will win over darkness.” The Ukrainian Ambassador to the United States is here tonight.\n", + "----------------------------------------------------------------------------------------------------\n", + "Document 4:\n", + "\n", + "As I said last year, especially to our younger transgender Americans, I will always have your back as your President, so you can be yourself and reach your God-given potential. \n", + "\n", + "While it often appears that we never agree, that isn’t true. I signed 80 bipartisan bills into law last year. From preventing government shutdowns to protecting Asian-Americans from still-too-common hate crimes to reforming military justice.\n", + "----------------------------------------------------------------------------------------------------\n", + "Document 5:\n", + "\n", + "To all Americans, I will be honest with you, as I’ve always promised. A Russian dictator, invading a foreign country, has costs around the world. \n", + "\n", + "And I’m taking robust action to make sure the pain of our sanctions is targeted at Russia’s economy. And I will use every tool at our disposal to protect American businesses and consumers. \n", + "\n", + "Tonight, I can announce that the United States has worked with 30 other countries to release 60 Million barrels of oil from reserves around the world.\n" + ] + } + ], + "source": [ + "from langchain_community.document_loaders import TextLoader\n", + "from langchain_community.vectorstores import FAISS\n", + "from langchain_text_splitters import RecursiveCharacterTextSplitter\n", + "\n", + "documents = TextLoader(\"../../how_to/state_of_the_union.txt\").load()\n", + "text_splitter = RecursiveCharacterTextSplitter(chunk_size=500, chunk_overlap=100)\n", + "texts = text_splitter.split_documents(documents)\n", + "retriever = FAISS.from_documents(texts, wx_embeddings).as_retriever(\n", + " search_kwargs={\"k\": 20}\n", + ")\n", + "\n", + "query = \"What did the president say about Ketanji Brown Jackson\"\n", + "docs = retriever.invoke(query)\n", + "pretty_print_docs(docs[:5]) # Printing the first 5 documents" + ] + }, + { + "cell_type": "markdown", + "id": "f230c065", + "metadata": {}, + "source": [ + "## Usage\n", + "\n", + "### Doing reranking with WatsonxRerank\n", + "Now let's wrap our base retriever with a `ContextualCompressionRetriever`. We'll add an `WatsonxRerank`, uses the watsonx rerank endpoint to rerank the returned results.\n", + "Do note that it is mandatory to specify the model name in WatsonxRerank!" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "a6705dda", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_ibm import WatsonxRerank\n", + "\n", + "wx_rerank = WatsonxRerank(\n", + " model_id=\"ibm/slate-125m-english-rtrvr\",\n", + " url=\"https://us-south.ml.cloud.ibm.com\",\n", + " project_id=\"PASTE YOUR PROJECT_ID HERE\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "b83dfedb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Document 1:\n", + "\n", + "One of the most serious constitutional responsibilities a President has is nominating someone to serve on the United States Supreme Court. \n", + "\n", + "And I did that 4 days ago, when I nominated Circuit Court of Appeals Judge Ketanji Brown Jackson. One of our nation’s top legal minds, who will continue Justice Breyer’s legacy of excellence.\n", + "----------------------------------------------------------------------------------------------------\n", + "Document 2:\n", + "\n", + "As I said last year, especially to our younger transgender Americans, I will always have your back as your President, so you can be yourself and reach your God-given potential. \n", + "\n", + "While it often appears that we never agree, that isn’t true. I signed 80 bipartisan bills into law last year. From preventing government shutdowns to protecting Asian-Americans from still-too-common hate crimes to reforming military justice.\n", + "----------------------------------------------------------------------------------------------------\n", + "Document 3:\n", + "\n", + "To all Americans, I will be honest with you, as I’ve always promised. A Russian dictator, invading a foreign country, has costs around the world. \n", + "\n", + "And I’m taking robust action to make sure the pain of our sanctions is targeted at Russia’s economy. And I will use every tool at our disposal to protect American businesses and consumers. \n", + "\n", + "Tonight, I can announce that the United States has worked with 30 other countries to release 60 Million barrels of oil from reserves around the world.\n", + "----------------------------------------------------------------------------------------------------\n", + "Document 4:\n", + "\n", + "I spoke with their families and told them that we are forever in debt for their sacrifice, and we will carry on their mission to restore the trust and safety every community deserves. \n", + "\n", + "I’ve worked on these issues a long time. \n", + "\n", + "I know what works: Investing in crime prevention and community police officers who’ll walk the beat, who’ll know the neighborhood, and who can restore trust and safety. \n", + "\n", + "So let’s not abandon our streets. Or choose between safety and equal justice.\n", + "----------------------------------------------------------------------------------------------------\n", + "Document 5:\n", + "\n", + "He met the Ukrainian people. \n", + "\n", + "From President Zelenskyy to every Ukrainian, their fearlessness, their courage, their determination, inspires the world. \n", + "\n", + "Groups of citizens blocking tanks with their bodies. Everyone from students to retirees teachers turned soldiers defending their homeland. \n", + "\n", + "In this struggle as President Zelenskyy said in his speech to the European Parliament “Light will win over darkness.” The Ukrainian Ambassador to the United States is here tonight.\n" + ] + } + ], + "source": [ + "from langchain.retrievers.contextual_compression import ContextualCompressionRetriever\n", + "\n", + "compression_retriever = ContextualCompressionRetriever(\n", + " base_compressor=wx_rerank, base_retriever=retriever\n", + ")\n", + "\n", + "compressed_docs = compression_retriever.invoke(\n", + " \"What did the president say about Ketanji Jackson Brown\"\n", + ")\n", + "pretty_print_docs(compressed_docs[:5]) # Printing the first 5 compressed documents" + ] + }, + { + "cell_type": "markdown", + "id": "70727c2f", + "metadata": {}, + "source": [ + "## Use within a chain\n", + "\n", + "You can of course use this retriever within a QA pipeline\n", + "\n", + "Initialize the `ChatWatsonx`. For more details see [ChatWatsonx](/docs/integrations/chat/ibm_watsonx)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "08d2616a", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_ibm import ChatWatsonx\n", + "\n", + "wx_chat = ChatWatsonx(\n", + " model_id=\"meta-llama/llama-3-1-70b-instruct\",\n", + " url=\"https://us-south.ml.cloud.ibm.com\",\n", + " project_id=\"PASTE YOUR PROJECT_ID HERE\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "ae697ca4", + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.chains import RetrievalQA\n", + "\n", + "chain = RetrievalQA.from_chain_type(llm=wx_chat, retriever=compression_retriever)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "31f5ca54", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'query': 'What did the president say about Ketanji Brown Jackson',\n", + " 'result': 'The President said that he had nominated Circuit Court of Appeals Judge Ketanji Brown Jackson to serve on the United States Supreme Court, and described her as \"one of our nation\\'s top legal minds\" who will continue Justice Breyer\\'s legacy of excellence.'}" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chain.invoke(query)" + ] + }, + { + "cell_type": "markdown", + "id": "a2d2d396", + "metadata": {}, + "source": [ + "## API reference\n", + "\n", + "For detailed documentation of all `WatsonxRerank` features and configurations head to the [API reference](https://python.langchain.com/api_reference/ibm/chat_models/langchain_ibm.rerank.WatsonxRerank.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.14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/docs/integrations/text_embedding/ibm_watsonx.ipynb b/docs/docs/integrations/text_embedding/ibm_watsonx.ipynb index 9541c0d7f7e87..5767a60cb5155 100644 --- a/docs/docs/integrations/text_embedding/ibm_watsonx.ipynb +++ b/docs/docs/integrations/text_embedding/ibm_watsonx.ipynb @@ -15,24 +15,24 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Setting up\n", + "## Overview\n", + "### Integration details\n", "\n", - "Install the package `langchain-ibm`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "!pip install -qU langchain-ibm" + "import { ItemTable } from \"@theme/FeatureTables\";\n", + "\n", + "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ + "## Setup\n", + "\n", + "To access IBM watsonx.ai models you'll need to create an IBM watsonx.ai account, get an API key, and install the `langchain-ibm` integration package.\n", + "\n", + "### Credentials\n", + "\n", "This cell defines the WML credentials required to work with watsonx Embeddings.\n", "\n", "**Action:** Provide the IBM Cloud user API key. For details, see\n", @@ -78,14 +78,32 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Load the model\n", + "### Installation\n", + "\n", + "The LangChain IBM integration lives in the `langchain-ibm` package:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!pip install -qU langchain-ibm" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Instantiation\n", "\n", "You might need to adjust model `parameters` for different models." ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [], "source": [ @@ -173,7 +191,7 @@ "\n", "api_client = APIClient(...)\n", "\n", - "watsonx_llm = WatsonxEmbeddings(\n", + "watsonx_embedding = WatsonxEmbeddings(\n", " model_id=\"ibm/slate-125m-english-rtrvr\",\n", " watsonx_client=api_client,\n", ")" @@ -183,9 +201,63 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Usage\n", + "## Indexing and Retrieval\n", + "\n", + "Embedding models are often used in retrieval-augmented generation (RAG) flows, both as part of indexing data as well as later retrieving it. For more detailed instructions, please see our RAG tutorials under the [working with external knowledge tutorials](/docs/tutorials/#working-with-external-knowledge).\n", + "\n", + "Below, see how to index and retrieve data using the `embeddings` object we initialized above. In this example, we will index and retrieve a sample document in the `InMemoryVectorStore`." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'LangChain is the framework for building context-aware reasoning applications'" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Create a vector store with a sample text\n", + "from langchain_core.vectorstores import InMemoryVectorStore\n", + "\n", + "text = \"LangChain is the framework for building context-aware reasoning applications\"\n", + "\n", + "vectorstore = InMemoryVectorStore.from_texts(\n", + " [text],\n", + " embedding=watsonx_embedding,\n", + ")\n", + "\n", + "# Use the vectorstore as a retriever\n", + "retriever = vectorstore.as_retriever()\n", + "\n", + "# Retrieve the most similar text\n", + "retrieved_documents = retriever.invoke(\"What is LangChain?\")\n", + "\n", + "# show the retrieved document's content\n", + "retrieved_documents[0].page_content" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Direct Usage\n", + "\n", + "Under the hood, the vectorstore and retriever implementations are calling `embeddings.embed_documents(...)` and `embeddings.embed_query(...)` to create embeddings for the text(s) used in `from_texts` and retrieval `invoke` operations, respectively.\n", + "\n", + "You can directly call these methods to get embeddings for your own use cases.\n", "\n", - "### Embed query" + "### Embed single texts\n", + "\n", + "You can embed single texts or documents with `embed_query`:" ] }, { @@ -196,7 +268,7 @@ { "data": { "text/plain": [ - "[0.0094472, -0.024981909, -0.026013248, -0.040483925, -0.057804465]" + "[0.009447193, -0.024981951, -0.026013248, -0.040483937, -0.05780445]" ] }, "execution_count": 4, @@ -215,7 +287,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Embed documents" + "### Embed multiple texts\n", + "\n", + "You can embed multiple texts with `embed_documents`:" ] }, { @@ -226,7 +300,7 @@ { "data": { "text/plain": [ - "[0.009447193, -0.024981918, -0.026013244, -0.040483937, -0.057804447]" + "[0.009447167, -0.024981938, -0.02601326, -0.04048393, -0.05780444]" ] }, "execution_count": 5, @@ -240,6 +314,15 @@ "doc_result = watsonx_embedding.embed_documents(texts)\n", "doc_result[0][:5]" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## API Reference\n", + "\n", + "For detailed documentation of all `WatsonxEmbeddings` features and configurations head to the [API reference](https://python.langchain.com/api_reference/ibm/embeddings/langchain_ibm.embeddings.WatsonxEmbeddings.html)." + ] } ], "metadata": { @@ -258,7 +341,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.13" + "version": "3.10.14" } }, "nbformat": 4, diff --git a/docs/docs/integrations/vectorstores/milvus.ipynb b/docs/docs/integrations/vectorstores/milvus.ipynb index 34bda120d89aa..2cbc8d4e97362 100644 --- a/docs/docs/integrations/vectorstores/milvus.ipynb +++ b/docs/docs/integrations/vectorstores/milvus.ipynb @@ -314,7 +314,7 @@ "results = vector_store.similarity_search(\n", " \"LangChain provides abstractions to make working with LLMs easy\",\n", " k=2,\n", - " filter={\"source\": \"tweet\"},\n", + " expr='source == \"tweet\"',\n", ")\n", "for res in results:\n", " print(f\"* {res.page_content} [{res.metadata}]\")" @@ -346,7 +346,7 @@ ], "source": [ "results = vector_store.similarity_search_with_score(\n", - " \"Will it be hot tomorrow?\", k=1, filter={\"source\": \"news\"}\n", + " \"Will it be hot tomorrow?\", k=1, expr='source == \"news\"'\n", ")\n", "for res, score in results:\n", " print(f\"* [SIM={score:3f}] {res.page_content} [{res.metadata}]\")" diff --git a/docs/docs/tutorials/agents.ipynb b/docs/docs/tutorials/agents.ipynb index fc920248943c4..22d9a37bd91c4 100644 --- a/docs/docs/tutorials/agents.ipynb +++ b/docs/docs/tutorials/agents.ipynb @@ -33,7 +33,7 @@ "\n", "By themselves, language models can't take actions - they just output text.\n", "A big use case for LangChain is creating **agents**.\n", - "Agents are systems that use LLMs as reasoning engines to determine which actions to take and the inputs to pass them.\n", + "Agents are systems that use LLMs as reasoning engines to determine which actions to take and the inputs necessary to perform the action.\n", "After executing actions, the results can be fed back into the LLM to determine whether more actions are needed, or whether it is okay to finish.\n", "\n", "In this tutorial we will build an agent that can interact with a search engine. You will be able to ask this agent questions, watch it call the search tool, and have conversations with it.\n", @@ -371,7 +371,7 @@ "## Create the agent\n", "\n", "Now that we have defined the tools and the LLM, we can create the agent. We will be using [LangGraph](/docs/concepts/#langgraph) to construct the agent. \n", - "Currently we are using a high level interface to construct the agent, but the nice thing about LangGraph is that this high-level interface is backed by a low-level, highly controllable API in case you want to modify the agent logic.\n" + "Currently, we are using a high level interface to construct the agent, but the nice thing about LangGraph is that this high-level interface is backed by a low-level, highly controllable API in case you want to modify the agent logic.\n" ] }, { @@ -403,7 +403,7 @@ "source": [ "## Run the agent\n", "\n", - "We can now run the agent on a few queries! Note that for now, these are all **stateless** queries (it won't remember previous interactions). Note that the agent will return the **final** state at the end of the interaction (which includes any inputs, we will see later on how to get only the outputs).\n", + "We can now run the agent with a few queries! Note that for now, these are all **stateless** queries (it won't remember previous interactions). Note that the agent will return the **final** state at the end of the interaction (which includes any inputs, we will see later on how to get only the outputs).\n", "\n", "First up, let's see how it responds when there's no need to call a tool:" ] @@ -484,7 +484,7 @@ "source": [ "## Streaming Messages\n", "\n", - "We've seen how the agent can be called with `.invoke` to get back a final response. If the agent is executing multiple steps, that may take a while. In order to show intermediate progress, we can stream back messages as they occur." + "We've seen how the agent can be called with `.invoke` to get a final response. If the agent executes multiple steps, this may take a while. To show intermediate progress, we can stream back messages as they occur." ] }, { @@ -521,7 +521,7 @@ "source": [ "## Streaming tokens\n", "\n", - "In addition to streaming back messages, it is also useful to be streaming back tokens.\n", + "In addition to streaming back messages, it is also useful to stream back tokens.\n", "We can do this with the `.astream_events` method.\n", "\n", ":::important\n", @@ -680,7 +680,7 @@ "id": "ae908088", "metadata": {}, "source": [ - "If I want to start a new conversation, all I have to do is change the `thread_id` used" + "If you want to start a new conversation, all you have to do is change the `thread_id` used" ] }, { @@ -715,9 +715,9 @@ "## Conclusion\n", "\n", "That's a wrap! In this quick start we covered how to create a simple agent. \n", - "We've then shown how to stream back a response - not only the intermediate steps, but also tokens!\n", + "We've then shown how to stream back a response - not only with the intermediate steps, but also tokens!\n", "We've also added in memory so you can have a conversation with them.\n", - "Agents are a complex topic, and there's lot to learn! \n", + "Agents are a complex topic with lots to learn! \n", "\n", "For more information on Agents, please check out the [LangGraph](/docs/concepts/#langgraph) documentation. This has it's own set of concepts, tutorials, and how-to guides." ] diff --git a/docs/docs/tutorials/classification.ipynb b/docs/docs/tutorials/classification.ipynb index 2df9b4a1a53f1..2391e987e4d6e 100644 --- a/docs/docs/tutorials/classification.ipynb +++ b/docs/docs/tutorials/classification.ipynb @@ -22,11 +22,11 @@ "\n", "Tagging means labeling a document with classes such as:\n", "\n", - "- sentiment\n", - "- language\n", - "- style (formal, informal etc.)\n", - "- covered topics\n", - "- political tendency\n", + "- Sentiment\n", + "- Language\n", + "- Style (formal, informal etc.)\n", + "- Covered topics\n", + "- Political tendency\n", "\n", "![Image description](../../static/img/tagging.png)\n", "\n", @@ -130,7 +130,7 @@ "id": "ff3cf30d", "metadata": {}, "source": [ - "If we want JSON output, we can just call `.dict()`" + "If we want dictionary output, we can just call `.dict()`" ] }, { @@ -179,9 +179,9 @@ "\n", "Specifically, we can define:\n", "\n", - "- possible values for each property\n", - "- description to make sure that the model understands the property\n", - "- required properties to be returned" + "- Possible values for each property\n", + "- Description to make sure that the model understands the property\n", + "- Required properties to be returned" ] }, { diff --git a/docs/docs/tutorials/data_generation.ipynb b/docs/docs/tutorials/data_generation.ipynb index aa921414684fd..84a232f4ba2b3 100644 --- a/docs/docs/tutorials/data_generation.ipynb +++ b/docs/docs/tutorials/data_generation.ipynb @@ -37,7 +37,7 @@ "\n", "## Quickstart\n", "\n", - "In this notebook, we'll dive deep into generating synthetic medical billing records using the langchain library. This tool is particularly useful when you want to develop or test algorithms but don't want to use real patient data due to privacy concerns or data availability issues." + "In this notebook, we'll dive deep into generating synthetic medical billing records using the `langchain` library. This tool is particularly useful when you want to develop or test algorithms but don't want to use real patient data due to privacy concerns or data availability issues." ] }, { @@ -46,7 +46,7 @@ "metadata": {}, "source": [ "### Setup\n", - "First, you'll need to have the langchain library installed, along with its dependencies. Since we're using the OpenAI generator chain, we'll install that as well. Since this is an experimental lib, we'll need to include `langchain_experimental` in our installs. We'll then import the necessary modules." + "First, you'll need to have the `langchain` library installed, along with its dependencies. Since we're using the OpenAI generator chain, we'll install that as well. Since this is an experimental library, we'll need to include `langchain_experimental` in our installation. We'll then import the necessary modules." ] }, { @@ -99,7 +99,7 @@ "metadata": {}, "source": [ "## 1. Define Your Data Model\n", - "Every dataset has a structure or a \"schema\". The MedicalBilling class below serves as our schema for the synthetic data. By defining this, we're informing our synthetic data generator about the shape and nature of data we expect." + "Every dataset has a structure or a \"schema\". The `MedicalBilling` class below serves as our schema for the synthetic data. By defining this, we're informing our synthetic data generator about the shape and nature of data we expect." ] }, { @@ -126,7 +126,7 @@ "For instance, every record will have a `patient_id` that's an integer, a `patient_name` that's a string, and so on.\n", "\n", "## 2. Sample Data\n", - "To guide the synthetic data generator, it's useful to provide it with a few real-world-like examples. These examples serve as a \"seed\" - they're representative of the kind of data you want, and the generator will use them to create more data that looks similar.\n", + "To guide the synthetic data generator, it's useful to provide it with a few real-world-like examples. These examples serve as a \"seed\" - they're representative of the kind of data you want, and the generator will use them to create data that looks similar to your expectations.\n", "\n", "Here are some fictional medical billing records:" ] @@ -194,7 +194,7 @@ "- `example_prompt`: This prompt template is the format we want each example row to take in our prompt.\n", "\n", "## 4. Creating the Data Generator\n", - "With the schema and the prompt ready, the next step is to create the data generator. This object knows how to communicate with the underlying language model to get synthetic data." + "With the schema and the prompt ready, the next step is to create the data generator. This object knows how to communicate with the underlying language model to generate synthetic data." ] }, { @@ -219,7 +219,7 @@ "metadata": {}, "source": [ "## 5. Generate Synthetic Data\n", - "Finally, let's get our synthetic data!" + "Finally, let's generate our synthetic data!" ] }, { @@ -241,7 +241,7 @@ "id": "fa4402e9", "metadata": {}, "source": [ - "This command asks the generator to produce 10 synthetic medical billing records. The results are stored in `synthetic_results`. The output will be a list of the MedicalBilling pydantic models." + "This command asks the generator to produce 10 synthetic medical billing records. The results are stored in `synthetic_results`. The output will be a list of the `MedicalBilling` pydantic model." ] }, { @@ -400,7 +400,7 @@ "id": "93c7a4bb", "metadata": {}, "source": [ - "As we can see created examples are diversified and possess information we wanted them to have. Also, their style reflects the given preferences quite well." + "As we can see, the created examples are diversified and possess information we wanted them to have. Also, their style reflects our given preferences quite well." ] }, { diff --git a/docs/docs/tutorials/index.mdx b/docs/docs/tutorials/index.mdx index a4e1840bf9744..6e8fc50e9ab5a 100644 --- a/docs/docs/tutorials/index.mdx +++ b/docs/docs/tutorials/index.mdx @@ -4,7 +4,7 @@ sidebar_class_name: hidden --- # Tutorials -New to LangChain or to LLM app development in general? Read this material to quickly get up and running. +New to LangChain or LLM app development in general? Read this material to quickly get up and running. ## Basics - [Build a Simple LLM Application with LCEL](/docs/tutorials/llm_chain) @@ -45,7 +45,7 @@ You can peruse [LangSmith tutorials here](https://docs.smith.langchain.com/tutor ### Evaluation -LangSmith helps you evaluate the performance of your LLM applications. The below tutorial is a great way to get started: +LangSmith helps you evaluate the performance of your LLM applications. The tutorial below is a great way to get started: - [Evaluate your LLM application](https://docs.smith.langchain.com/tutorials/Developers/evaluation) diff --git a/docs/docs/tutorials/rag.ipynb b/docs/docs/tutorials/rag.ipynb index 8eb07fbb5cfdd..1f7a7799e4315 100644 --- a/docs/docs/tutorials/rag.ipynb +++ b/docs/docs/tutorials/rag.ipynb @@ -23,7 +23,7 @@ "\n", "RAG is a technique for augmenting LLM knowledge with additional data.\n", "\n", - "LLMs can reason about wide-ranging topics, but their knowledge is limited to the public data up to a specific point in time that they were trained on. If you want to build AI applications that can reason about private data or data introduced after a model's cutoff date, you need to augment the knowledge of the model with the specific information it needs. The process of bringing the appropriate information and inserting it into the model prompt is known as Retrieval Augmented Generation (RAG).\n", + "LLMs can reason about wide-ranging topics, but their knowledge is limited to the public data up to a specific point in time that they were trained on. If you want to build AI applications that can reason about private data or data introduced after a model's cutoff date, you need to augment the knowledge of the model with the specific information it needs. The process of bringing and inserting appropriate information into the model prompt is known as Retrieval Augmented Generation (RAG).\n", "\n", "LangChain has a number of components designed to help build Q&A applications, and RAG applications more generally. \n", "\n", @@ -40,14 +40,14 @@ "\n", "### Indexing\n", "1. **Load**: First we need to load our data. This is done with [Document Loaders](/docs/concepts/document_loaders).\n", - "2. **Split**: [Text splitters](/docs/concepts/text_splitters) break large `Documents` into smaller chunks. This is useful both for indexing data and for passing it in to a model, since large chunks are harder to search over and won't fit in a model's finite context window.\n", - "3. **Store**: We need somewhere to store and index our splits, so that they can later be searched over. This is often done using a [VectorStore](/docs/concepts/vectorstores) and [Embeddings](/docs/concepts/embedding_models) model.\n", + "2. **Split**: [Text splitters](/docs/concepts/text_splitters) break large `Documents` into smaller chunks. This is useful both for indexing data and passing it into a model, as large chunks are harder to search over and won't fit in a model's finite context window.\n", + "3. **Store**: We need somewhere to store and index our splits, so that they can be searched over later. This is often done using a [VectorStore](/docs/concepts/vectorstores) and [Embeddings](/docs/concepts/embedding_models) model.\n", "\n", "![index_diagram](../../static/img/rag_indexing.png)\n", "\n", "### Retrieval and generation\n", "4. **Retrieve**: Given a user input, relevant splits are retrieved from storage using a [Retriever](/docs/concepts/retrievers).\n", - "5. **Generate**: A [ChatModel](/docs/concepts/chat_models) / [LLM](/docs/concepts/text_llms) produces an answer using a prompt that includes the question and the retrieved data\n", + "5. **Generate**: A [ChatModel](/docs/concepts/chat_models) / [LLM](/docs/concepts/text_llms) produces an answer using a prompt that includes both the question with the retrieved data\n", "\n", "![retrieval_diagram](../../static/img/rag_retrieval_generation.png)\n", "\n", @@ -56,7 +56,7 @@ "\n", "### Jupyter Notebook\n", "\n", - "This guide (and most of the other guides in the documentation) uses [Jupyter notebooks](https://jupyter.org/) and assumes the reader is as well. Jupyter notebooks are perfect for learning how to work with LLM systems because oftentimes things can go wrong (unexpected output, API down, etc) and going through guides in an interactive environment is a great way to better understand them.\n", + "This guide (and most of the other guides in the documentation) uses [Jupyter notebooks](https://jupyter.org/) and assumes the reader is as well. Jupyter notebooks are perfect for learning how to work with LLM systems because oftentimes things can go wrong (unexpected output, API down, etc) and going through guides in an interactive environment is a great way to better understand LLM concepts.\n", "\n", "This and other tutorials are perhaps most conveniently run in a Jupyter notebook. See [here](https://jupyter.org/install) for instructions on how to install.\n", "\n", @@ -100,7 +100,7 @@ "### LangSmith\n", "\n", "Many of the applications you build with LangChain will contain multiple steps with multiple invocations of LLM calls.\n", - "As these applications get more and more complex, it becomes crucial to be able to inspect what exactly is going on inside your chain or agent.\n", + "As these applications get more complex, it becomes crucial to be able to inspect what exactly is going on inside your chain or agent.\n", "The best way to do this is with [LangSmith](https://smith.langchain.com).\n", "\n", "After you sign up at the link above, make sure to set your environment variables to start logging traces:\n", @@ -121,7 +121,7 @@ "```\n", "## Preview\n", "\n", - "In this guide we’ll build an app that answers questions about the content of a website. The specific website we will use is the [LLM Powered Autonomous\n", + "In this guide we’ll build an app that answers questions about the website's content. The specific website we will use is the [LLM Powered Autonomous\n", "Agents](https://lilianweng.github.io/posts/2023-06-23-agent/) blog post\n", "by Lilian Weng, which allows us to ask questions about the contents of\n", "the post.\n", @@ -248,7 +248,7 @@ "[WebBaseLoader](/docs/integrations/document_loaders/web_base),\n", "which uses `urllib` to load HTML from web URLs and `BeautifulSoup` to\n", "parse it to text. We can customize the HTML -\\> text parsing by passing\n", - "in parameters to the `BeautifulSoup` parser via `bs_kwargs` (see\n", + "in parameters into the `BeautifulSoup` parser via `bs_kwargs` (see\n", "[BeautifulSoup\n", "docs](https://beautiful-soup-4.readthedocs.io/en/latest/#beautifulsoup)).\n", "In this case only HTML tags with class “post-content”, “post-title”, or\n", @@ -329,19 +329,19 @@ "- [Integrations](/docs/integrations/document_loaders/): 160+\n", " integrations to choose from.\n", "- [Interface](https://python.langchain.com/api_reference/core/document_loaders/langchain_core.document_loaders.base.BaseLoader.html):\n", - " API reference  for the base interface.\n", + " API reference for the base interface.\n", "\n", "\n", "## 2. Indexing: Split {#indexing-split}\n", "\n", "\n", - "Our loaded document is over 42k characters long. This is too long to fit\n", - "in the context window of many models. Even for those models that could\n", + "Our loaded document is over 42k characters which is too long to fit\n", + "into the context window of many models. Even for those models that could\n", "fit the full post in their context window, models can struggle to find\n", "information in very long inputs.\n", "\n", "To handle this we’ll split the `Document` into chunks for embedding and\n", - "vector storage. This should help us retrieve only the most relevant bits\n", + "vector storage. This should help us retrieve only the most relevant parts\n", "of the blog post at run time.\n", "\n", "In this case we’ll split our documents into chunks of 1000 characters\n", @@ -353,7 +353,7 @@ "new lines until each chunk is the appropriate size. This is the\n", "recommended text splitter for generic text use cases.\n", "\n", - "We set `add_start_index=True` so that the character index at which each\n", + "We set `add_start_index=True` so that the character index where each\n", "split Document starts within the initial Document is preserved as\n", "metadata attribute “start_index”." ] @@ -595,7 +595,7 @@ " [variants of the\n", " embeddings](/docs/how_to/multi_vector),\n", " also in order to improve retrieval hit rate.\n", - " - `Max marginal relevance` selects for [relevance and\n", + " - `Maximal marginal relevance` selects for [relevance and\n", " diversity](https://www.cs.cmu.edu/~jgc/publication/The_Use_MMR_Diversity_Based_LTMIR_1998.pdf)\n", " among the retrieved documents to avoid passing in duplicate\n", " context.\n", @@ -610,7 +610,7 @@ "## 5. Retrieval and Generation: Generate {#retrieval-and-generation-generate}\n", "\n", "Let’s put it all together into a chain that takes a question, retrieves\n", - "relevant documents, constructs a prompt, passes that to a model, and\n", + "relevant documents, constructs a prompt, passes it into a model, and\n", "parses the output.\n", "\n", "We’ll use the gpt-4o-mini OpenAI chat model, but any LangChain `LLM`\n", @@ -733,7 +733,7 @@ "\n", "First: each of these components (`retriever`, `prompt`, `llm`, etc.) are instances of [Runnable](/docs/concepts#langchain-expression-language-lcel). This means that they implement the same methods-- such as sync and async `.invoke`, `.stream`, or `.batch`-- which makes them easier to connect together. They can be connected into a [RunnableSequence](https://python.langchain.com/api_reference/core/runnables/langchain_core.runnables.base.RunnableSequence.html)-- another Runnable-- via the `|` operator.\n", "\n", - "LangChain will automatically cast certain objects to runnables when met with the `|` operator. Here, `format_docs` is cast to a [RunnableLambda](https://python.langchain.com/api_reference/core/runnables/langchain_core.runnables.base.RunnableLambda.html), and the dict with `\"context\"` and `\"question\"` is cast to a [RunnableParallel](https://python.langchain.com/api_reference/core/runnables/langchain_core.runnables.base.RunnableParallel.html). The details are less important than the bigger point, which is that each object is a Runnable.\n", + "LangChain will automatically cast certain objects to runnables when met with the `|` operator. Here, `format_docs` is cast to a [RunnableLambda](https://python.langchain.com/api_reference/core/runnables/langchain_core.runnables.base.RunnableLambda.html), and the dict with `\"context\"` and `\"question\"` is cast to a [RunnableParallel](https://python.langchain.com/api_reference/core/runnables/langchain_core.runnables.base.RunnableParallel.html). The details are less important than the bigger point, which is that each object in the chain is a Runnable.\n", "\n", "Let's trace how the input question flows through the above runnables.\n", "\n", @@ -757,7 +757,7 @@ "\n", "### Built-in chains\n", "\n", - "If preferred, LangChain includes convenience functions that implement the above LCEL. We compose two functions:\n", + "If preferred, LangChain includes convenient functions that implement the above LCEL. We compose two functions:\n", "\n", "- [create_stuff_documents_chain](https://python.langchain.com/api_reference/langchain/chains/langchain.chains.combine_documents.stuff.create_stuff_documents_chain.html) specifies how retrieved context is fed into a prompt and LLM. In this case, we will \"stuff\" the contents into the prompt -- i.e., we will include all retrieved context without any summarization or other processing. It largely implements our above `rag_chain`, with input keys `context` and `input`-- it generates an answer using retrieved context and query.\n", "- [create_retrieval_chain](https://python.langchain.com/api_reference/langchain/chains/langchain.chains.retrieval.create_retrieval_chain.html) adds the retrieval step and propagates the retrieved context through the chain, providing it alongside the final answer. It has input key `input`, and includes `input`, `context`, and `answer` in its output." @@ -813,7 +813,7 @@ "metadata": {}, "source": [ "#### Returning sources\n", - "Often in Q&A applications it's important to show users the sources that were used to generate the answer. LangChain's built-in `create_retrieval_chain` will propagate retrieved source documents through to the output in the `\"context\"` key:" + "Often in Q&A applications it's important to show users the sources that were used to generate the answer. LangChain's built-in `create_retrieval_chain` will propagate retrieved source documents to the output under the `\"context\"` key:" ] }, { @@ -940,7 +940,7 @@ "- Generating an answer using the retrieved chunks as context\n", "\n", "There’s plenty of features, integrations, and extensions to explore in each of\n", - "the above sections. Along from the **Go deeper** sources mentioned\n", + "the above sections. Along with the **Go deeper** sources mentioned\n", "above, good next steps include:\n", "\n", "- [Return sources](/docs/how_to/qa_sources): Learn how to return source documents\n", diff --git a/docs/docs/versions/v0_3/index.mdx b/docs/docs/versions/v0_3/index.mdx index cd52380575480..f8cba890d7420 100644 --- a/docs/docs/versions/v0_3/index.mdx +++ b/docs/docs/versions/v0_3/index.mdx @@ -73,7 +73,7 @@ well as updating the `langchain_core.pydantic_v1` and `langchain.pydantic_v1` im | langchain-google-genai | 2.0.0 | >=2,<3 | | langchain-google-vertexai | 2.0.0 | >=2,<3 | | langchain-huggingface | 0.1.0 | >=0.1,<0.2 | -| langchain-ibm | 0.2.0 | >=0.2,<0.3 | +| langchain-ibm | 0.3.0 | >=0.3,<0.4 | | langchain-milvus | 0.1.6 | >=0.1.6,<0.2 | | langchain-mistralai | 0.2.0 | >=0.2,<0.3 | | langchain-mongodb | 0.2.0 | >=0.2,<0.3 | diff --git a/docs/scripts/partner_pkg_table.py b/docs/scripts/partner_pkg_table.py index 6706b82aa4552..6bc8b4badf7ac 100644 --- a/docs/scripts/partner_pkg_table.py +++ b/docs/scripts/partner_pkg_table.py @@ -63,6 +63,7 @@ "nomic", "google-common", "ollama", + "ibm", } @@ -76,6 +77,7 @@ "google-genai": "Google Generative AI", "aws": "AWS", "airbyte": "Airbyte", + "ibm": "IBM", } CUSTOM_PROVIDER_PAGES = { "azure-dynamic-sessions": "/docs/integrations/providers/microsoft/", diff --git a/docs/src/theme/ChatModelTabs.js b/docs/src/theme/ChatModelTabs.js index b6b403c2f8d75..9579e20077f68 100644 --- a/docs/src/theme/ChatModelTabs.js +++ b/docs/src/theme/ChatModelTabs.js @@ -131,7 +131,7 @@ export default function ChatModelTabs(props) { { value: "NVIDIA", label: "NVIDIA", - text: `from langchain import ChatNVIDIA\n\n${llmVarName} = ChatNVIDIA(${nvidiaParamsOrDefault})`, + text: `from langchain_nvidia_ai_endpoints import ChatNVIDIA\n\n${llmVarName} = ChatNVIDIA(${nvidiaParamsOrDefault})`, apiKeyName: "NVIDIA_API_KEY", packageName: "langchain-nvidia-ai-endpoints", default: false, diff --git a/docs/src/theme/FeatureTables.js b/docs/src/theme/FeatureTables.js index 095d45dbbb826..94b179113bb8c 100644 --- a/docs/src/theme/FeatureTables.js +++ b/docs/src/theme/FeatureTables.js @@ -215,7 +215,18 @@ const FEATURE_TABLES = { "multimodal": false, "local": false, "apiLink": "https://python.langchain.com/api_reference/upstage/chat_models/langchain_databricks.chat_models.ChatDatabricks.html" - } + }, + { + "name": "ChatWatsonx", + "package": "langchain-ibm", + "link": "ibm_watsonx", + "structured_output": true, + "tool_calling": true, + "json_mode": true, + "multimodal": false, + "local": false, + "apiLink": "https://python.langchain.com/api_reference/ibm/chat_models/langchain_ibm.chat_models.ChatWatsonx.html" + }, ], }, llms: { @@ -370,6 +381,12 @@ const FEATURE_TABLES = { package: "langchain-voyageai", apiLink: "https://python.langchain.com/api_reference/voyageai/embeddings/langchain_voyageai.embeddings.VoyageAIEmbeddings.html" }, + { + name: "IBM", + link: "ibm_watsonx", + package: "langchain-ibm", + apiLink: "https://python.langchain.com/api_reference/ibm/embeddings/langchain_ibm.embeddings.WatsonxEmbeddings.html" + }, ] }, document_retrievers: { diff --git a/libs/community/langchain_community/callbacks/bedrock_anthropic_callback.py b/libs/community/langchain_community/callbacks/bedrock_anthropic_callback.py index 0c4d4bbd8bebb..32c36f40768be 100644 --- a/libs/community/langchain_community/callbacks/bedrock_anthropic_callback.py +++ b/libs/community/langchain_community/callbacks/bedrock_anthropic_callback.py @@ -10,6 +10,7 @@ "anthropic.claude-v2:1": 0.008, "anthropic.claude-3-sonnet-20240229-v1:0": 0.003, "anthropic.claude-3-5-sonnet-20240620-v1:0": 0.003, + "anthropic.claude-3-5-sonnet-20241022-v2:0": 0.003, "anthropic.claude-3-haiku-20240307-v1:0": 0.00025, } @@ -19,6 +20,7 @@ "anthropic.claude-v2:1": 0.024, "anthropic.claude-3-sonnet-20240229-v1:0": 0.015, "anthropic.claude-3-5-sonnet-20240620-v1:0": 0.015, + "anthropic.claude-3-5-sonnet-20241022-v2:0": 0.015, "anthropic.claude-3-haiku-20240307-v1:0": 0.00125, } diff --git a/libs/community/langchain_community/llms/vllm.py b/libs/community/langchain_community/llms/vllm.py index dc8a7a76d24ed..66a0f17756b99 100644 --- a/libs/community/langchain_community/llms/vllm.py +++ b/libs/community/langchain_community/llms/vllm.py @@ -125,6 +125,8 @@ def _generate( """Run the LLM on the given prompt and input.""" from vllm import SamplingParams + lora_request = kwargs.pop("lora_request", None) + # build sampling parameters params = {**self._default_params, **kwargs, "stop": stop} @@ -135,7 +137,12 @@ def _generate( ) # call the model - outputs = self.client.generate(prompts, sample_params) + if lora_request: + outputs = self.client.generate( + prompts, sample_params, lora_request=lora_request + ) + else: + outputs = self.client.generate(prompts, sample_params) generations = [] for output in outputs: diff --git a/libs/community/langchain_community/vectorstores/redis/base.py b/libs/community/langchain_community/vectorstores/redis/base.py index e88938ce2c650..e18660a6e3243 100644 --- a/libs/community/langchain_community/vectorstores/redis/base.py +++ b/libs/community/langchain_community/vectorstores/redis/base.py @@ -866,7 +866,8 @@ def similarity_search_with_score( metadata = {"id": result.id} metadata.update(self._collect_metadata(result)) - doc = Document(page_content=result.content, metadata=metadata) + content_key = self._schema.content_key + doc = Document(page_content=getattr(result, content_key), metadata=metadata) distance = self._calculate_fp_distance(result.distance) docs_with_scores.append((doc, distance)) diff --git a/libs/core/langchain_core/messages/utils.py b/libs/core/langchain_core/messages/utils.py index 9bf617af17d48..0ea03e40d00d4 100644 --- a/libs/core/langchain_core/messages/utils.py +++ b/libs/core/langchain_core/messages/utils.py @@ -1210,13 +1210,14 @@ def _first_max_tokens( ] = None, ) -> list[BaseMessage]: messages = list(messages) + if not messages: + return messages idx = 0 for i in range(len(messages)): if token_counter(messages[:-i] if i else messages) <= max_tokens: idx = len(messages) - i break - - if idx < len(messages) - 1 and partial_strategy: + if partial_strategy and (idx < len(messages) - 1 or idx == 0): included_partial = False if isinstance(messages[idx].content, list): excluded = messages[idx].model_copy(deep=True) diff --git a/libs/core/langchain_core/output_parsers/json.py b/libs/core/langchain_core/output_parsers/json.py index e9d3669e44edb..18c1257a9adf3 100644 --- a/libs/core/langchain_core/output_parsers/json.py +++ b/libs/core/langchain_core/output_parsers/json.py @@ -115,7 +115,7 @@ def get_format_instructions(self) -> str: if "type" in reduced_schema: del reduced_schema["type"] # Ensure json in context is well-formed with double quotes. - schema_str = json.dumps(reduced_schema) + schema_str = json.dumps(reduced_schema, ensure_ascii=False) return JSON_FORMAT_INSTRUCTIONS.format(schema=schema_str) @property diff --git a/libs/core/langchain_core/tools/convert.py b/libs/core/langchain_core/tools/convert.py index e85435a86df69..bb8b85f5558cc 100644 --- a/libs/core/langchain_core/tools/convert.py +++ b/libs/core/langchain_core/tools/convert.py @@ -1,5 +1,5 @@ import inspect -from typing import Any, Callable, Literal, Optional, Union, get_type_hints +from typing import Any, Callable, Literal, Optional, Union, get_type_hints, overload from pydantic import BaseModel, Field, create_model @@ -10,19 +10,79 @@ from langchain_core.tools.structured import StructuredTool +@overload def tool( - *args: Union[str, Callable, Runnable], + *, + return_direct: bool = False, + args_schema: Optional[type] = None, + infer_schema: bool = True, + response_format: Literal["content", "content_and_artifact"] = "content", + parse_docstring: bool = False, + error_on_invalid_docstring: bool = True, +) -> Callable[[Union[Callable, Runnable]], BaseTool]: ... + + +@overload +def tool( + name_or_callable: str, + runnable: Runnable, + *, return_direct: bool = False, args_schema: Optional[type] = None, infer_schema: bool = True, response_format: Literal["content", "content_and_artifact"] = "content", parse_docstring: bool = False, error_on_invalid_docstring: bool = True, -) -> Callable: +) -> BaseTool: ... + + +@overload +def tool( + name_or_callable: Callable, + *, + return_direct: bool = False, + args_schema: Optional[type] = None, + infer_schema: bool = True, + response_format: Literal["content", "content_and_artifact"] = "content", + parse_docstring: bool = False, + error_on_invalid_docstring: bool = True, +) -> BaseTool: ... + + +@overload +def tool( + name_or_callable: str, + *, + return_direct: bool = False, + args_schema: Optional[type] = None, + infer_schema: bool = True, + response_format: Literal["content", "content_and_artifact"] = "content", + parse_docstring: bool = False, + error_on_invalid_docstring: bool = True, +) -> Callable[[Union[Callable, Runnable]], BaseTool]: ... + + +def tool( + name_or_callable: Optional[Union[str, Callable]] = None, + runnable: Optional[Runnable] = None, + *args: Any, + return_direct: bool = False, + args_schema: Optional[type] = None, + infer_schema: bool = True, + response_format: Literal["content", "content_and_artifact"] = "content", + parse_docstring: bool = False, + error_on_invalid_docstring: bool = True, +) -> Union[ + BaseTool, + Callable[[Union[Callable, Runnable]], BaseTool], +]: """Make tools out of functions, can be used with or without arguments. Args: - *args: The arguments to the tool. + name_or_callable: Optional name of the tool or the callable to be + converted to a tool. Must be provided as a positional argument. + runnable: Optional runnable to convert to a tool. Must be provided as a + positional argument. return_direct: Whether to return directly from the tool rather than continuing the agent loop. Defaults to False. args_schema: optional argument schema for user to specify. @@ -140,8 +200,19 @@ def invalid_docstring_3(bar: str, baz: int) -> str: return bar """ - def _make_with_name(tool_name: str) -> Callable: - def _make_tool(dec_func: Union[Callable, Runnable]) -> BaseTool: + def _create_tool_factory( + tool_name: str, + ) -> Callable[[Union[Callable, Runnable]], BaseTool]: + """Create a decorator that takes a callable and returns a tool. + + Args: + tool_name: The name that will be assigned to the tool. + + Returns: + A function that takes a callable or Runnable and returns a tool. + """ + + def _tool_factory(dec_func: Union[Callable, Runnable]) -> BaseTool: if isinstance(dec_func, Runnable): runnable = dec_func @@ -204,29 +275,64 @@ def invoke_wrapper( response_format=response_format, ) - return _make_tool - - if len(args) == 2 and isinstance(args[0], str) and isinstance(args[1], Runnable): - return _make_with_name(args[0])(args[1]) - elif len(args) == 1 and isinstance(args[0], str): - # if the argument is a string, then we use the string as the tool name - # Example usage: @tool("search", return_direct=True) - return _make_with_name(args[0]) - elif len(args) == 1 and callable(args[0]): - # if the argument is a function, then we use the function name as the tool name - # Example usage: @tool - return _make_with_name(args[0].__name__)(args[0]) - elif len(args) == 0: - # if there are no arguments, then we use the function name as the tool name - # Example usage: @tool(return_direct=True) - def _partial(func: Callable[[str], str]) -> BaseTool: - return _make_with_name(func.__name__)(func) + return _tool_factory - return _partial - else: - msg = "Too many arguments for tool decorator" + if len(args) != 0: + # Triggered if a user attempts to use positional arguments that + # do not exist in the function signature + # e.g., @tool("name", runnable, "extra_arg") + # Here, "extra_arg" is not a valid argument + msg = "Too many arguments for tool decorator. A decorator " raise ValueError(msg) + if runnable is not None: + # tool is used as a function + # tool_from_runnable = tool("name", runnable) + if not name_or_callable: + msg = "Runnable without name for tool constructor" + raise ValueError(msg) + if not isinstance(name_or_callable, str): + msg = "Name must be a string for tool constructor" + raise ValueError(msg) + return _create_tool_factory(name_or_callable)(runnable) + elif name_or_callable is not None: + if callable(name_or_callable) and hasattr(name_or_callable, "__name__"): + # Used as a decorator without parameters + # @tool + # def my_tool(): + # pass + return _create_tool_factory(name_or_callable.__name__)(name_or_callable) + elif isinstance(name_or_callable, str): + # Used with a new name for the tool + # @tool("search") + # def my_tool(): + # pass + # + # or + # + # @tool("search", parse_docstring=True) + # def my_tool(): + # pass + return _create_tool_factory(name_or_callable) + else: + msg = ( + f"The first argument must be a string or a callable with a __name__ " + f"for tool decorator. Got {type(name_or_callable)}" + ) + raise ValueError(msg) + else: + # Tool is used as a decorator with parameters specified + # @tool(parse_docstring=True) + # def my_tool(): + # pass + def _partial(func: Union[Callable, Runnable]) -> BaseTool: + """Partial function that takes a callable and returns a tool.""" + name_ = func.get_name() if isinstance(func, Runnable) else func.__name__ + tool_factory = _create_tool_factory(name_) + return tool_factory(func) + + return _partial + def _get_description_from_runnable(runnable: Runnable) -> str: """Generate a placeholder description of a runnable.""" diff --git a/libs/core/tests/unit_tests/messages/test_utils.py b/libs/core/tests/unit_tests/messages/test_utils.py index 9cd9543dc7c8e..ff251e3632078 100644 --- a/libs/core/tests/unit_tests/messages/test_utils.py +++ b/libs/core/tests/unit_tests/messages/test_utils.py @@ -301,6 +301,42 @@ def test_trim_messages_last_40_include_system_allow_partial_start_on_human() -> assert _MESSAGES_TO_TRIM == _MESSAGES_TO_TRIM_COPY +def test_trim_messages_allow_partial_one_message() -> None: + expected = [ + HumanMessage("Th", id="third"), + ] + + actual = trim_messages( + [HumanMessage("This is a funky text.", id="third")], + max_tokens=2, + token_counter=lambda messages: sum(len(m.content) for m in messages), + text_splitter=lambda x: list(x), + strategy="first", + allow_partial=True, + ) + + assert actual == expected + assert _MESSAGES_TO_TRIM == _MESSAGES_TO_TRIM_COPY + + +def test_trim_messages_last_allow_partial_one_message() -> None: + expected = [ + HumanMessage("t.", id="third"), + ] + + actual = trim_messages( + [HumanMessage("This is a funky text.", id="third")], + max_tokens=2, + token_counter=lambda messages: sum(len(m.content) for m in messages), + text_splitter=lambda x: list(x), + strategy="last", + allow_partial=True, + ) + + assert actual == expected + assert _MESSAGES_TO_TRIM == _MESSAGES_TO_TRIM_COPY + + def test_trim_messages_allow_partial_text_splitter() -> None: expected = [ HumanMessage("a 4 token text.", id="third"), diff --git a/libs/core/tests/unit_tests/output_parsers/test_json.py b/libs/core/tests/unit_tests/output_parsers/test_json.py index 96cf6d0cc4d6c..326cfc16cd9b1 100644 --- a/libs/core/tests/unit_tests/output_parsers/test_json.py +++ b/libs/core/tests/unit_tests/output_parsers/test_json.py @@ -3,7 +3,7 @@ from typing import Any import pytest -from pydantic import BaseModel +from pydantic import BaseModel, Field from langchain_core.exceptions import OutputParserException from langchain_core.output_parsers.json import ( @@ -603,3 +603,16 @@ class Joke(BaseModel): assert initial_joke_schema == retrieved_joke_schema assert openai_func.get("name", None) is not None + + +def test_unicode_handling() -> None: + """Tests if the JsonOutputParser is able to process unicodes.""" + + class Sample(BaseModel): + title: str = Field(description="科学文章的标题") + + parser = SimpleJsonOutputParser(pydantic_object=Sample) + format_instructions = parser.get_format_instructions() + assert ( + "科学文章的标题" in format_instructions + ), "Unicode characters should not be escaped" diff --git a/libs/langchain/langchain/agents/agent.py b/libs/langchain/langchain/agents/agent.py index 7cce580391438..500e884cd732a 100644 --- a/libs/langchain/langchain/agents/agent.py +++ b/libs/langchain/langchain/agents/agent.py @@ -1182,7 +1182,7 @@ def validate_runnable_agent(cls, values: Dict) -> Any: def _action_agent(self) -> Union[BaseSingleActionAgent, BaseMultiActionAgent]: """Type cast self.agent. - The .agent attribute type includes Runnable, but is converted to one of + If the `agent` attribute is a Runnable, it will be converted one of RunnableAgentType in the validate_runnable_agent root_validator. To support instantiating with a Runnable, here we explicitly cast the type diff --git a/libs/langchain/poetry.lock b/libs/langchain/poetry.lock index 7d952f6e23ebb..36eae1ddd11e2 100644 --- a/libs/langchain/poetry.lock +++ b/libs/langchain/poetry.lock @@ -356,21 +356,20 @@ lxml = ["lxml"] [[package]] name = "bleach" -version = "6.1.0" +version = "6.2.0" description = "An easy safelist-based HTML-sanitizing tool." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "bleach-6.1.0-py3-none-any.whl", hash = "sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6"}, - {file = "bleach-6.1.0.tar.gz", hash = "sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe"}, + {file = "bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e"}, + {file = "bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f"}, ] [package.dependencies] -six = ">=1.9.0" webencodings = "*" [package.extras] -css = ["tinycss2 (>=1.1.0,<1.3)"] +css = ["tinycss2 (>=1.1.0,<1.5)"] [[package]] name = "cassandra-driver" @@ -1989,7 +1988,7 @@ files = [ [[package]] name = "langchain-core" -version = "0.3.12" +version = "0.3.13" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.9,<4.0" @@ -2014,7 +2013,7 @@ url = "../core" [[package]] name = "langchain-openai" -version = "0.2.3" +version = "0.2.4" description = "An integration package connecting OpenAI and LangChain" optional = true python-versions = ">=3.9,<4.0" @@ -2022,7 +2021,7 @@ files = [] develop = true [package.dependencies] -langchain-core = "^0.3.12" +langchain-core = "^0.3.13" openai = "^1.52.0" tiktoken = ">=0.7,<1" @@ -4340,13 +4339,13 @@ files = [ [[package]] name = "tqdm" -version = "4.66.5" +version = "4.66.6" description = "Fast, Extensible Progress Meter" optional = true python-versions = ">=3.7" files = [ - {file = "tqdm-4.66.5-py3-none-any.whl", hash = "sha256:90279a3770753eafc9194a0364852159802111925aa30eb3f9d85b0e805ac7cd"}, - {file = "tqdm-4.66.5.tar.gz", hash = "sha256:e1020aef2e5096702d8a025ac7d16b1577279c9d63f8375b63083e9a5f0fcbad"}, + {file = "tqdm-4.66.6-py3-none-any.whl", hash = "sha256:223e8b5359c2efc4b30555531f09e9f2f3589bcd7fdd389271191031b49b7a63"}, + {file = "tqdm-4.66.6.tar.gz", hash = "sha256:4bdd694238bef1485ce839d67967ab50af8f9272aab687c0d7702a01da0be090"}, ] [package.dependencies] @@ -4400,13 +4399,13 @@ files = [ [[package]] name = "types-protobuf" -version = "5.28.0.20240924" +version = "5.28.3.20241029" description = "Typing stubs for protobuf" optional = false python-versions = ">=3.8" files = [ - {file = "types-protobuf-5.28.0.20240924.tar.gz", hash = "sha256:d181af8a256e5a91ce8d5adb53496e880efd9144c7d54483e3653332b60296f0"}, - {file = "types_protobuf-5.28.0.20240924-py3-none-any.whl", hash = "sha256:5cecf612ccdefb7dc95f7a51fb502902f20fc2e6681cd500184aaa1b3931d6a7"}, + {file = "types-protobuf-5.28.3.20241029.tar.gz", hash = "sha256:58e6c547601102e0601e3ad95ad326f85c27cda41dc9bd8c5f29ad2f3b6c6967"}, + {file = "types_protobuf-5.28.3.20241029-py3-none-any.whl", hash = "sha256:7536ea95a7f0a19710a5e0520dd096c985333ae49b7c5eb29e1367703096f17a"}, ] [[package]] @@ -4502,13 +4501,13 @@ urllib3 = ">=2" [[package]] name = "types-setuptools" -version = "75.2.0.20241019" +version = "75.2.0.20241025" description = "Typing stubs for setuptools" optional = false python-versions = ">=3.8" files = [ - {file = "types-setuptools-75.2.0.20241019.tar.gz", hash = "sha256:86ea31b5f6df2c6b8f2dc8ae3f72b213607f62549b6fa2ed5866e5299f968694"}, - {file = "types_setuptools-75.2.0.20241019-py3-none-any.whl", hash = "sha256:2e48ff3acd4919471e80d5e3f049cce5c177e108d5d36d2d4cee3fa4d4104258"}, + {file = "types-setuptools-75.2.0.20241025.tar.gz", hash = "sha256:2949913a518d5285ce00a3b7d88961c80a6e72ffb8f3da0a3f5650ea533bd45e"}, + {file = "types_setuptools-75.2.0.20241025-py3-none-any.whl", hash = "sha256:6721ac0f1a620321e2ccd87a9a747c4a383dc381f78d894ce37f2455b45fcf1c"}, ] [[package]] @@ -4812,93 +4811,93 @@ files = [ [[package]] name = "yarl" -version = "1.16.0" +version = "1.17.0" description = "Yet another URL library" optional = false python-versions = ">=3.9" files = [ - {file = "yarl-1.16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:32468f41242d72b87ab793a86d92f885355bcf35b3355aa650bfa846a5c60058"}, - {file = "yarl-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:234f3a3032b505b90e65b5bc6652c2329ea7ea8855d8de61e1642b74b4ee65d2"}, - {file = "yarl-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a0296040e5cddf074c7f5af4a60f3fc42c0237440df7bcf5183be5f6c802ed5"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de6c14dd7c7c0badba48157474ea1f03ebee991530ba742d381b28d4f314d6f3"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b140e532fe0266003c936d017c1ac301e72ee4a3fd51784574c05f53718a55d8"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:019f5d58093402aa8f6661e60fd82a28746ad6d156f6c5336a70a39bd7b162b9"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c42998fd1cbeb53cd985bff0e4bc25fbe55fd6eb3a545a724c1012d69d5ec84"}, - {file = "yarl-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c7c30fb38c300fe8140df30a046a01769105e4cf4282567a29b5cdb635b66c4"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e49e0fd86c295e743fd5be69b8b0712f70a686bc79a16e5268386c2defacaade"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:b9ca7b9147eb1365c8bab03c003baa1300599575effad765e0b07dd3501ea9af"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:27e11db3f1e6a51081a981509f75617b09810529de508a181319193d320bc5c7"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8994c42f4ca25df5380ddf59f315c518c81df6a68fed5bb0c159c6cb6b92f120"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:542fa8e09a581bcdcbb30607c7224beff3fdfb598c798ccd28a8184ffc18b7eb"}, - {file = "yarl-1.16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2bd6a51010c7284d191b79d3b56e51a87d8e1c03b0902362945f15c3d50ed46b"}, - {file = "yarl-1.16.0-cp310-cp310-win32.whl", hash = "sha256:178ccb856e265174a79f59721031060f885aca428983e75c06f78aa24b91d929"}, - {file = "yarl-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe8bba2545427418efc1929c5c42852bdb4143eb8d0a46b09de88d1fe99258e7"}, - {file = "yarl-1.16.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d8643975a0080f361639787415a038bfc32d29208a4bf6b783ab3075a20b1ef3"}, - {file = "yarl-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:676d96bafc8c2d0039cea0cd3fd44cee7aa88b8185551a2bb93354668e8315c2"}, - {file = "yarl-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d9525f03269e64310416dbe6c68d3b23e5d34aaa8f47193a1c45ac568cecbc49"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b37d5ec034e668b22cf0ce1074d6c21fd2a08b90d11b1b73139b750a8b0dd97"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f32c4cb7386b41936894685f6e093c8dfaf0960124d91fe0ec29fe439e201d0"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b8e265a0545637492a7e12fd7038370d66c9375a61d88c5567d0e044ded9202"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:789a3423f28a5fff46fbd04e339863c169ece97c827b44de16e1a7a42bc915d2"}, - {file = "yarl-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1d1f45e3e8d37c804dca99ab3cf4ab3ed2e7a62cd82542924b14c0a4f46d243"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:621280719c4c5dad4c1391160a9b88925bb8b0ff6a7d5af3224643024871675f"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ed097b26f18a1f5ff05f661dc36528c5f6735ba4ce8c9645e83b064665131349"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2f1fe2b2e3ee418862f5ebc0c0083c97f6f6625781382f828f6d4e9b614eba9b"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:87dd10bc0618991c66cee0cc65fa74a45f4ecb13bceec3c62d78ad2e42b27a16"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4199db024b58a8abb2cfcedac7b1292c3ad421684571aeb622a02f242280e8d6"}, - {file = "yarl-1.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:99a9dcd4b71dd5f5f949737ab3f356cfc058c709b4f49833aeffedc2652dac56"}, - {file = "yarl-1.16.0-cp311-cp311-win32.whl", hash = "sha256:a9394c65ae0ed95679717d391c862dece9afacd8fa311683fc8b4362ce8a410c"}, - {file = "yarl-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:5b9101f528ae0f8f65ac9d64dda2bb0627de8a50344b2f582779f32fda747c1d"}, - {file = "yarl-1.16.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:4ffb7c129707dd76ced0a4a4128ff452cecf0b0e929f2668ea05a371d9e5c104"}, - {file = "yarl-1.16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1a5e9d8ce1185723419c487758d81ac2bde693711947032cce600ca7c9cda7d6"}, - {file = "yarl-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d743e3118b2640cef7768ea955378c3536482d95550222f908f392167fe62059"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26768342f256e6e3c37533bf9433f5f15f3e59e3c14b2409098291b3efaceacb"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d1b0796168b953bca6600c5f97f5ed407479889a36ad7d17183366260f29a6b9"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:858728086914f3a407aa7979cab743bbda1fe2bdf39ffcd991469a370dd7414d"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5570e6d47bcb03215baf4c9ad7bf7c013e56285d9d35013541f9ac2b372593e7"}, - {file = "yarl-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66ea8311422a7ba1fc79b4c42c2baa10566469fe5a78500d4e7754d6e6db8724"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:649bddcedee692ee8a9b7b6e38582cb4062dc4253de9711568e5620d8707c2a3"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3a91654adb7643cb21b46f04244c5a315a440dcad63213033826549fa2435f71"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b439cae82034ade094526a8f692b9a2b5ee936452de5e4c5f0f6c48df23f8604"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:571f781ae8ac463ce30bacebfaef2c6581543776d5970b2372fbe31d7bf31a07"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa7943f04f36d6cafc0cf53ea89824ac2c37acbdb4b316a654176ab8ffd0f968"}, - {file = "yarl-1.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1a5cf32539373ff39d97723e39a9283a7277cbf1224f7aef0c56c9598b6486c3"}, - {file = "yarl-1.16.0-cp312-cp312-win32.whl", hash = "sha256:a5b6c09b9b4253d6a208b0f4a2f9206e511ec68dce9198e0fbec4f160137aa67"}, - {file = "yarl-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:1208ca14eed2fda324042adf8d6c0adf4a31522fa95e0929027cd487875f0240"}, - {file = "yarl-1.16.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5ace0177520bd4caa99295a9b6fb831d0e9a57d8e0501a22ffaa61b4c024283"}, - {file = "yarl-1.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7118bdb5e3ed81acaa2095cba7ec02a0fe74b52a16ab9f9ac8e28e53ee299732"}, - {file = "yarl-1.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38fec8a2a94c58bd47c9a50a45d321ab2285ad133adefbbadf3012c054b7e656"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8791d66d81ee45866a7bb15a517b01a2bcf583a18ebf5d72a84e6064c417e64b"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cf936ba67bc6c734f3aa1c01391da74ab7fc046a9f8bbfa230b8393b90cf472"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1aab176dd55b59f77a63b27cffaca67d29987d91a5b615cbead41331e6b7428"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:995d0759004c08abd5d1b81300a91d18c8577c6389300bed1c7c11675105a44d"}, - {file = "yarl-1.16.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1bc22e00edeb068f71967ab99081e9406cd56dbed864fc3a8259442999d71552"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:35b4f7842154176523e0a63c9b871168c69b98065d05a4f637fce342a6a2693a"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:7ace71c4b7a0c41f317ae24be62bb61e9d80838d38acb20e70697c625e71f120"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8f639e3f5795a6568aa4f7d2ac6057c757dcd187593679f035adbf12b892bb00"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e8be3aff14f0120ad049121322b107f8a759be76a6a62138322d4c8a337a9e2c"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:122d8e7986043d0549e9eb23c7fd23be078be4b70c9eb42a20052b3d3149c6f2"}, - {file = "yarl-1.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0fd9c227990f609c165f56b46107d0bc34553fe0387818c42c02f77974402c36"}, - {file = "yarl-1.16.0-cp313-cp313-win32.whl", hash = "sha256:595ca5e943baed31d56b33b34736461a371c6ea0038d3baec399949dd628560b"}, - {file = "yarl-1.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:921b81b8d78f0e60242fb3db615ea3f368827a76af095d5a69f1c3366db3f596"}, - {file = "yarl-1.16.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ab2b2ac232110a1fdb0d3ffcd087783edd3d4a6ced432a1bf75caf7b7be70916"}, - {file = "yarl-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7f8713717a09acbfee7c47bfc5777e685539fefdd34fa72faf504c8be2f3df4e"}, - {file = "yarl-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cdcffe1dbcb4477d2b4202f63cd972d5baa155ff5a3d9e35801c46a415b7f71a"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9a91217208306d82357c67daeef5162a41a28c8352dab7e16daa82e3718852a7"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ab3ed42c78275477ea8e917491365e9a9b69bb615cb46169020bd0aa5e2d6d3"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:707ae579ccb3262dfaef093e202b4c3fb23c3810e8df544b1111bd2401fd7b09"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad7a852d1cd0b8d8b37fc9d7f8581152add917a98cfe2ea6e241878795f917ae"}, - {file = "yarl-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3f1cc3d3d4dc574bebc9b387f6875e228ace5748a7c24f49d8f01ac1bc6c31b"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5ff96da263740779b0893d02b718293cc03400c3a208fc8d8cd79d9b0993e532"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:3d375a19ba2bfe320b6d873f3fb165313b002cef8b7cc0a368ad8b8a57453837"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:62c7da0ad93a07da048b500514ca47b759459ec41924143e2ddb5d7e20fd3db5"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:147b0fcd0ee33b4b5f6edfea80452d80e419e51b9a3f7a96ce98eaee145c1581"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:504e1fe1cc4f170195320eb033d2b0ccf5c6114ce5bf2f617535c01699479bca"}, - {file = "yarl-1.16.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:bdcf667a5dec12a48f669e485d70c54189f0639c2157b538a4cffd24a853624f"}, - {file = "yarl-1.16.0-cp39-cp39-win32.whl", hash = "sha256:e9951afe6557c75a71045148890052cb942689ee4c9ec29f5436240e1fcc73b7"}, - {file = "yarl-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:7d7aaa8ff95d0840e289423e7dc35696c2b058d635f945bf05b5cd633146b027"}, - {file = "yarl-1.16.0-py3-none-any.whl", hash = "sha256:e6980a558d8461230c457218bd6c92dfc1d10205548215c2c21d79dc8d0a96f3"}, - {file = "yarl-1.16.0.tar.gz", hash = "sha256:b6f687ced5510a9a2474bbae96a4352e5ace5fa34dc44a217b0537fec1db00b4"}, + {file = "yarl-1.17.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2d8715edfe12eee6f27f32a3655f38d6c7410deb482158c0b7d4b7fad5d07628"}, + {file = "yarl-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1803bf2a7a782e02db746d8bd18f2384801bc1d108723840b25e065b116ad726"}, + {file = "yarl-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2e66589110e20c2951221a938fa200c7aa134a8bdf4e4dc97e6b21539ff026d4"}, + {file = "yarl-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7069d411cfccf868e812497e0ec4acb7c7bf8d684e93caa6c872f1e6f5d1664d"}, + {file = "yarl-1.17.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cbf70ba16118db3e4b0da69dcde9d4d4095d383c32a15530564c283fa38a7c52"}, + {file = "yarl-1.17.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0bc53cc349675b32ead83339a8de79eaf13b88f2669c09d4962322bb0f064cbc"}, + {file = "yarl-1.17.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6aa18a402d1c80193ce97c8729871f17fd3e822037fbd7d9b719864018df746"}, + {file = "yarl-1.17.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d89c5bc701861cfab357aa0cd039bc905fe919997b8c312b4b0c358619c38d4d"}, + {file = "yarl-1.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b728bdf38ca58f2da1d583e4af4ba7d4cd1a58b31a363a3137a8159395e7ecc7"}, + {file = "yarl-1.17.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:5542e57dc15d5473da5a39fbde14684b0cc4301412ee53cbab677925e8497c11"}, + {file = "yarl-1.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e564b57e5009fb150cb513804d7e9e9912fee2e48835638f4f47977f88b4a39c"}, + {file = "yarl-1.17.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:eb3c4cff524b4c1c1dba3a6da905edb1dfd2baf6f55f18a58914bbb2d26b59e1"}, + {file = "yarl-1.17.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:05e13f389038842da930d439fbed63bdce3f7644902714cb68cf527c971af804"}, + {file = "yarl-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:153c38ee2b4abba136385af4467459c62d50f2a3f4bde38c7b99d43a20c143ef"}, + {file = "yarl-1.17.0-cp310-cp310-win32.whl", hash = "sha256:4065b4259d1ae6f70fd9708ffd61e1c9c27516f5b4fae273c41028afcbe3a094"}, + {file = "yarl-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:abf366391a02a8335c5c26163b5fe6f514cc1d79e74d8bf3ffab13572282368e"}, + {file = "yarl-1.17.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:19a4fe0279626c6295c5b0c8c2bb7228319d2e985883621a6e87b344062d8135"}, + {file = "yarl-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cadd0113f4db3c6b56868d6a19ca6286f5ccfa7bc08c27982cf92e5ed31b489a"}, + {file = "yarl-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:60d6693eef43215b1ccfb1df3f6eae8db30a9ff1e7989fb6b2a6f0b468930ee8"}, + {file = "yarl-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5bb8bf3843e1fa8cf3fe77813c512818e57368afab7ebe9ef02446fe1a10b492"}, + {file = "yarl-1.17.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d2a5b35fd1d8d90443e061d0c8669ac7600eec5c14c4a51f619e9e105b136715"}, + {file = "yarl-1.17.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c5bf17b32f392df20ab5c3a69d37b26d10efaa018b4f4e5643c7520d8eee7ac7"}, + {file = "yarl-1.17.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48f51b529b958cd06e78158ff297a8bf57b4021243c179ee03695b5dbf9cb6e1"}, + {file = "yarl-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fcaa06bf788e19f913d315d9c99a69e196a40277dc2c23741a1d08c93f4d430"}, + {file = "yarl-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:32f3ee19ff0f18a7a522d44e869e1ebc8218ad3ae4ebb7020445f59b4bbe5897"}, + {file = "yarl-1.17.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:a4fb69a81ae2ec2b609574ae35420cf5647d227e4d0475c16aa861dd24e840b0"}, + {file = "yarl-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7bacc8b77670322132a1b2522c50a1f62991e2f95591977455fd9a398b4e678d"}, + {file = "yarl-1.17.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:437bf6eb47a2d20baaf7f6739895cb049e56896a5ffdea61a4b25da781966e8b"}, + {file = "yarl-1.17.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:30534a03c87484092080e3b6e789140bd277e40f453358900ad1f0f2e61fc8ec"}, + {file = "yarl-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b30df4ff98703649915144be6f0df3b16fd4870ac38a09c56d5d9e54ff2d5f96"}, + {file = "yarl-1.17.0-cp311-cp311-win32.whl", hash = "sha256:263b487246858e874ab53e148e2a9a0de8465341b607678106829a81d81418c6"}, + {file = "yarl-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:07055a9e8b647a362e7d4810fe99d8f98421575e7d2eede32e008c89a65a17bd"}, + {file = "yarl-1.17.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:84095ab25ba69a8fa3fb4936e14df631b8a71193fe18bd38be7ecbe34d0f5512"}, + {file = "yarl-1.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:02608fb3f6df87039212fc746017455ccc2a5fc96555ee247c45d1e9f21f1d7b"}, + {file = "yarl-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13468d291fe8c12162b7cf2cdb406fe85881c53c9e03053ecb8c5d3523822cd9"}, + {file = "yarl-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8da3f8f368fb7e2f052fded06d5672260c50b5472c956a5f1bd7bf474ae504ab"}, + {file = "yarl-1.17.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec0507ab6523980bed050137007c76883d941b519aca0e26d4c1ec1f297dd646"}, + {file = "yarl-1.17.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08fc76df7fd8360e9ff30e6ccc3ee85b8dbd6ed5d3a295e6ec62bcae7601b932"}, + {file = "yarl-1.17.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d522f390686acb6bab2b917dd9ca06740c5080cd2eaa5aef8827b97e967319d"}, + {file = "yarl-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:147c527a80bb45b3dcd6e63401af8ac574125d8d120e6afe9901049286ff64ef"}, + {file = "yarl-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:24cf43bcd17a0a1f72284e47774f9c60e0bf0d2484d5851f4ddf24ded49f33c6"}, + {file = "yarl-1.17.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:c28a44b9e0fba49c3857360e7ad1473fc18bc7f6659ca08ed4f4f2b9a52c75fa"}, + {file = "yarl-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:350cacb2d589bc07d230eb995d88fcc646caad50a71ed2d86df533a465a4e6e1"}, + {file = "yarl-1.17.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:fd1ab1373274dea1c6448aee420d7b38af163b5c4732057cd7ee9f5454efc8b1"}, + {file = "yarl-1.17.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:4934e0f96dadc567edc76d9c08181633c89c908ab5a3b8f698560124167d9488"}, + {file = "yarl-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8d0a278170d75c88e435a1ce76557af6758bfebc338435b2eba959df2552163e"}, + {file = "yarl-1.17.0-cp312-cp312-win32.whl", hash = "sha256:61584f33196575a08785bb56db6b453682c88f009cd9c6f338a10f6737ce419f"}, + {file = "yarl-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:9987a439ad33a7712bd5bbd073f09ad10d38640425fa498ecc99d8aa064f8fc4"}, + {file = "yarl-1.17.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8deda7b8eb15a52db94c2014acdc7bdd14cb59ec4b82ac65d2ad16dc234a109e"}, + {file = "yarl-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:56294218b348dcbd3d7fce0ffd79dd0b6c356cb2a813a1181af730b7c40de9e7"}, + {file = "yarl-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1fab91292f51c884b290ebec0b309a64a5318860ccda0c4940e740425a67b6b7"}, + {file = "yarl-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cf93fa61ff4d9c7d40482ce1a2c9916ca435e34a1b8451e17f295781ccc034f"}, + {file = "yarl-1.17.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:261be774a0d71908c8830c33bacc89eef15c198433a8cc73767c10eeeb35a7d0"}, + {file = "yarl-1.17.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:deec9693b67f6af856a733b8a3e465553ef09e5e8ead792f52c25b699b8f9e6e"}, + {file = "yarl-1.17.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c804b07622ba50a765ca7fb8145512836ab65956de01307541def869e4a456c9"}, + {file = "yarl-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d013a7c9574e98c14831a8f22d27277688ec3b2741d0188ac01a910b009987a"}, + {file = "yarl-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e2cfcba719bd494c7413dcf0caafb51772dec168c7c946e094f710d6aa70494e"}, + {file = "yarl-1.17.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c068aba9fc5b94dfae8ea1cedcbf3041cd4c64644021362ffb750f79837e881f"}, + {file = "yarl-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:3616df510ffac0df3c9fa851a40b76087c6c89cbcea2de33a835fc80f9faac24"}, + {file = "yarl-1.17.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:755d6176b442fba9928a4df787591a6a3d62d4969f05c406cad83d296c5d4e05"}, + {file = "yarl-1.17.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c18f6e708d1cf9ff5b1af026e697ac73bea9cb70ee26a2b045b112548579bed2"}, + {file = "yarl-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5b937c216b6dee8b858c6afea958de03c5ff28406257d22b55c24962a2baf6fd"}, + {file = "yarl-1.17.0-cp313-cp313-win32.whl", hash = "sha256:d0131b14cb545c1a7bd98f4565a3e9bdf25a1bd65c83fc156ee5d8a8499ec4a3"}, + {file = "yarl-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:01c96efa4313c01329e88b7e9e9e1b2fc671580270ddefdd41129fa8d0db7696"}, + {file = "yarl-1.17.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0d44f67e193f0a7acdf552ecb4d1956a3a276c68e7952471add9f93093d1c30d"}, + {file = "yarl-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:16ea0aa5f890cdcb7ae700dffa0397ed6c280840f637cd07bffcbe4b8d68b985"}, + {file = "yarl-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cf5469dc7dcfa65edf5cc3a6add9f84c5529c6b556729b098e81a09a92e60e51"}, + {file = "yarl-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e662bf2f6e90b73cf2095f844e2bc1fda39826472a2aa1959258c3f2a8500a2f"}, + {file = "yarl-1.17.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8260e88f1446904ba20b558fa8ce5d0ab9102747238e82343e46d056d7304d7e"}, + {file = "yarl-1.17.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5dc16477a4a2c71e64c5d3d15d7ae3d3a6bb1e8b955288a9f73c60d2a391282f"}, + {file = "yarl-1.17.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46027e326cecd55e5950184ec9d86c803f4f6fe4ba6af9944a0e537d643cdbe0"}, + {file = "yarl-1.17.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fc95e46c92a2b6f22e70afe07e34dbc03a4acd07d820204a6938798b16f4014f"}, + {file = "yarl-1.17.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:16ca76c7ac9515320cd09d6cc083d8d13d1803f6ebe212b06ea2505fd66ecff8"}, + {file = "yarl-1.17.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:eb1a5b97388f2613f9305d78a3473cdf8d80c7034e554d8199d96dcf80c62ac4"}, + {file = "yarl-1.17.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:41fd5498975418cdc34944060b8fbeec0d48b2741068077222564bea68daf5a6"}, + {file = "yarl-1.17.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:146ca582ed04a5664ad04b0e0603934281eaab5c0115a5a46cce0b3c061a56a1"}, + {file = "yarl-1.17.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:6abb8c06107dbec97481b2392dafc41aac091a5d162edf6ed7d624fe7da0587a"}, + {file = "yarl-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:4d14be4613dd4f96c25feb4bd8c0d8ce0f529ab0ae555a17df5789e69d8ec0c5"}, + {file = "yarl-1.17.0-cp39-cp39-win32.whl", hash = "sha256:174d6a6cad1068f7850702aad0c7b1bca03bcac199ca6026f84531335dfc2646"}, + {file = "yarl-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:6af417ca2c7349b101d3fd557ad96b4cd439fdb6ab0d288e3f64a068eea394d0"}, + {file = "yarl-1.17.0-py3-none-any.whl", hash = "sha256:62dd42bb0e49423f4dd58836a04fcf09c80237836796025211bbe913f1524993"}, + {file = "yarl-1.17.0.tar.gz", hash = "sha256:d3f13583f378930377e02002b4085a3d025b00402d5a80911726d43a67911cd9"}, ] [package.dependencies] @@ -4928,4 +4927,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0" -content-hash = "40da6b8dcd1e7331230e9fd4e572ca5f2aa29a2732b26ebd5ad59b8530e2f6eb" +content-hash = "52b6e8f0985fd682a9d475a66d374b4588fddee44dc622efcc8cbb0ceccc6532" diff --git a/libs/langchain/pyproject.toml b/libs/langchain/pyproject.toml index 42aed52f2a9a2..6818c8363f6d5 100644 --- a/libs/langchain/pyproject.toml +++ b/libs/langchain/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "langchain" -version = "0.3.4" +version = "0.3.5" description = "Building applications with LLMs through composability" authors = [] license = "MIT" @@ -33,7 +33,7 @@ langchain-server = "langchain.server:main" [tool.poetry.dependencies] python = ">=3.9,<4.0" -langchain-core = "^0.3.12" +langchain-core = "^0.3.13" langchain-text-splitters = "^0.3.0" langsmith = "^0.1.17" pydantic = "^2.7.4" diff --git a/libs/partners/huggingface/langchain_huggingface/llms/huggingface_pipeline.py b/libs/partners/huggingface/langchain_huggingface/llms/huggingface_pipeline.py index b1261bcfc4e4b..3e743a64289fc 100644 --- a/libs/partners/huggingface/langchain_huggingface/llms/huggingface_pipeline.py +++ b/libs/partners/huggingface/langchain_huggingface/llms/huggingface_pipeline.py @@ -2,12 +2,12 @@ import importlib.util import logging -from typing import Any, Iterator, List, Mapping, Optional +from typing import Any, Dict, Iterator, List, Mapping, Optional from langchain_core.callbacks import CallbackManagerForLLMRun from langchain_core.language_models.llms import BaseLLM from langchain_core.outputs import Generation, GenerationChunk, LLMResult -from pydantic import ConfigDict +from pydantic import ConfigDict, model_validator DEFAULT_MODEL_ID = "gpt2" DEFAULT_TASK = "text-generation" @@ -55,8 +55,10 @@ class HuggingFacePipeline(BaseLLM): """ pipeline: Any = None #: :meta private: - model_id: str = DEFAULT_MODEL_ID - """Model name to use.""" + model_id: Optional[str] = None + """The model name. If not set explicitly by the user, + it will be inferred from the provided pipeline (if available). + If neither is provided, the DEFAULT_MODEL_ID will be used.""" model_kwargs: Optional[dict] = None """Keyword arguments passed to the model.""" pipeline_kwargs: Optional[dict] = None @@ -68,6 +70,17 @@ class HuggingFacePipeline(BaseLLM): extra="forbid", ) + @model_validator(mode="before") + @classmethod + def pre_init_validator(cls, values: Dict[str, Any]) -> Dict[str, Any]: + """Ensure model_id is set either by pipeline or user input.""" + if "model_id" not in values: + if "pipeline" in values and values["pipeline"]: + values["model_id"] = values["pipeline"].model.name_or_path + else: + values["model_id"] = DEFAULT_MODEL_ID + return values + @classmethod def from_model_id( cls, diff --git a/libs/partners/huggingface/tests/unit_tests/test_huggingface_pipeline.py b/libs/partners/huggingface/tests/unit_tests/test_huggingface_pipeline.py new file mode 100644 index 0000000000000..b4e1639493d12 --- /dev/null +++ b/libs/partners/huggingface/tests/unit_tests/test_huggingface_pipeline.py @@ -0,0 +1,50 @@ +from unittest.mock import MagicMock, patch + +from langchain_huggingface import HuggingFacePipeline + +DEFAULT_MODEL_ID = "gpt2" + + +def test_initialization_default() -> None: + """Test default initialization""" + + llm = HuggingFacePipeline() + + assert llm.model_id == DEFAULT_MODEL_ID + + +@patch("transformers.pipeline") +def test_initialization_with_pipeline(mock_pipeline: MagicMock) -> None: + """Test initialization with a pipeline object""" + + mock_pipe = MagicMock() + mock_pipe.model.name_or_path = "mock-model-id" + mock_pipeline.return_value = mock_pipe + + llm = HuggingFacePipeline(pipeline=mock_pipe) + + assert llm.model_id == "mock-model-id" + + +@patch("transformers.AutoTokenizer.from_pretrained") +@patch("transformers.AutoModelForCausalLM.from_pretrained") +@patch("transformers.pipeline") +def test_initialization_with_from_model_id( + mock_pipeline: MagicMock, mock_model: MagicMock, mock_tokenizer: MagicMock +) -> None: + """Test initialization with the from_model_id method""" + + mock_tokenizer.return_value = MagicMock(pad_token_id=0) + mock_model.return_value = MagicMock() + + mock_pipe = MagicMock() + mock_pipe.task = "text-generation" + mock_pipe.model = mock_model.return_value + mock_pipeline.return_value = mock_pipe + + llm = HuggingFacePipeline.from_model_id( + model_id="mock-model-id", + task="text-generation", + ) + + assert llm.model_id == "mock-model-id" diff --git a/libs/text-splitters/poetry.lock b/libs/text-splitters/poetry.lock index 4a68af4a76cc2..00296208416dd 100644 --- a/libs/text-splitters/poetry.lock +++ b/libs/text-splitters/poetry.lock @@ -208,21 +208,20 @@ lxml = ["lxml"] [[package]] name = "bleach" -version = "6.1.0" +version = "6.2.0" description = "An easy safelist-based HTML-sanitizing tool." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "bleach-6.1.0-py3-none-any.whl", hash = "sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6"}, - {file = "bleach-6.1.0.tar.gz", hash = "sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe"}, + {file = "bleach-6.2.0-py3-none-any.whl", hash = "sha256:117d9c6097a7c3d22fd578fcd8d35ff1e125df6736f554da4e432fdd63f31e5e"}, + {file = "bleach-6.2.0.tar.gz", hash = "sha256:123e894118b8a599fd80d3ec1a6d4cc7ce4e5882b1317a7e1ba69b56e95f991f"}, ] [package.dependencies] -six = ">=1.9.0" webencodings = "*" [package.extras] -css = ["tinycss2 (>=1.1.0,<1.3)"] +css = ["tinycss2 (>=1.1.0,<1.5)"] [[package]] name = "certifi" @@ -1171,7 +1170,7 @@ files = [ [[package]] name = "langchain-core" -version = "0.3.12" +version = "0.3.13" description = "Building applications with LLMs through composability" optional = false python-versions = ">=3.9,<4.0" @@ -2569,23 +2568,23 @@ win32 = ["pywin32"] [[package]] name = "setuptools" -version = "75.2.0" +version = "75.3.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-75.2.0-py3-none-any.whl", hash = "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8"}, - {file = "setuptools-75.2.0.tar.gz", hash = "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec"}, + {file = "setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd"}, + {file = "setuptools-75.3.0.tar.gz", hash = "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686"}, ] [package.extras] check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.12.*)", "pytest-mypy"] [[package]] name = "six" @@ -2981,4 +2980,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<4.0" -content-hash = "924c618410ef2ae8b7fa6003f53988a0d81546f9e249436ab334892a94b2be93" +content-hash = "985bbcb3e82965a3b68764c90270cece172f6a3a825e5e08644d4df63049cb44" diff --git a/libs/text-splitters/pyproject.toml b/libs/text-splitters/pyproject.toml index fb3cf11d948f9..f880c8a74c943 100644 --- a/libs/text-splitters/pyproject.toml +++ b/libs/text-splitters/pyproject.toml @@ -1,10 +1,10 @@ [build-system] -requires = ["poetry-core>=1.0.0"] +requires = [ "poetry-core>=1.0.0",] build-backend = "poetry.core.masonry.api" [tool.poetry] name = "langchain-text-splitters" -version = "0.3.0" +version = "0.3.1" description = "LangChain text splitting utilities" authors = [] license = "MIT" @@ -14,17 +14,7 @@ repository = "https://github.com/langchain-ai/langchain" [tool.mypy] disallow_untyped_defs = "True" [[tool.mypy.overrides]] -module = [ - "transformers", - "sentence_transformers", - "nltk.tokenize", - "konlpy.tag", - "bs4", - "pytest", - "spacy", - "spacy.lang.en", - "numpy", -] +module = [ "transformers", "sentence_transformers", "nltk.tokenize", "konlpy.tag", "bs4", "pytest", "spacy", "spacy.lang.en", "numpy",] ignore_missing_imports = "True" [tool.poetry.urls] @@ -33,20 +23,17 @@ ignore_missing_imports = "True" [tool.poetry.dependencies] python = ">=3.9,<4.0" -langchain-core = "^0.3.0" +langchain-core = "^0.3.13" [tool.ruff.lint] -select = ["E", "F", "I", "T201"] +select = [ "E", "F", "I", "T201",] [tool.coverage.run] -omit = ["tests/*"] +omit = [ "tests/*",] [tool.pytest.ini_options] addopts = "--strict-markers --strict-config --durations=5" -markers = [ - "requires: mark tests as requiring a specific library", - "compile: mark placeholder test used to compile integration tests without running them", -] +markers = [ "requires: mark tests as requiring a specific library", "compile: mark placeholder test used to compile integration tests without running them",] asyncio_mode = "auto" [tool.poetry.group.lint]