mirror of
https://github.com/hwchase17/langchain.git
synced 2026-02-17 12:04:45 +00:00
Compare commits
36 Commits
langchain-
...
eugene/pin
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
435dec28fe | ||
|
|
de5b09251d | ||
|
|
bffc3c24a0 | ||
|
|
a1520357c8 | ||
|
|
16a293cc3a | ||
|
|
9308bf32e5 | ||
|
|
182fc06769 | ||
|
|
5536420bee | ||
|
|
9f0f3c7e29 | ||
|
|
85e36b0f50 | ||
|
|
96b72edac8 | ||
|
|
5bfcb898ad | ||
|
|
60fc15a56b | ||
|
|
2445b997ee | ||
|
|
6721b991ab | ||
|
|
daf733b52e | ||
|
|
47f69fe0d8 | ||
|
|
672fcbb8dc | ||
|
|
13254715a2 | ||
|
|
2c9b84c3a8 | ||
|
|
79d8556c22 | ||
|
|
2a5d59b3d7 | ||
|
|
1141b08eb8 | ||
|
|
3bf1d98dbf | ||
|
|
a7ab93479b | ||
|
|
c0fcf76e93 | ||
|
|
b1dfb8ea1e | ||
|
|
5070004e8a | ||
|
|
2f976c5174 | ||
|
|
6d0ebbca1e | ||
|
|
1e3e05b0c3 | ||
|
|
c39521b70d | ||
|
|
ee282a1d2e | ||
|
|
c314222796 | ||
|
|
32f8f39974 | ||
|
|
6f7fe82830 |
20
README.md
20
README.md
@@ -38,24 +38,25 @@ conda install langchain -c conda-forge
|
||||
|
||||
For these applications, LangChain simplifies the entire application lifecycle:
|
||||
|
||||
- **Open-source libraries**: Build your applications using LangChain's [modular building blocks](https://python.langchain.com/v0.2/docs/concepts/#langchain-expression-language-lcel) and [components](https://python.langchain.com/v0.2/docs/concepts/#components). Integrate with hundreds of [third-party providers](https://python.langchain.com/v0.2/docs/integrations/platforms/).
|
||||
- **Open-source libraries**: Build your applications using LangChain's open-source [building blocks](https://python.langchain.com/v0.2/docs/concepts#langchain-expression-language-lcel), [components](https://python.langchain.com/v0.2/docs/concepts), and [third-party integrations](https://python.langchain.com/v0.2/docs/integrations/platforms/).
|
||||
Use [LangGraph](/docs/concepts/#langgraph) to build stateful agents with first-class streaming and human-in-the-loop support.
|
||||
- **Productionization**: Inspect, monitor, and evaluate your apps with [LangSmith](https://docs.smith.langchain.com/) so that you can constantly optimize and deploy with confidence.
|
||||
- **Deployment**: Turn any chain into a REST API with [LangServe](https://python.langchain.com/v0.2/docs/langserve/).
|
||||
- **Deployment**: Turn your LangGraph applications into production-ready APIs and Assistants with [LangGraph Cloud](https://langchain-ai.github.io/langgraph/cloud/).
|
||||
|
||||
### Open-source libraries
|
||||
- **`langchain-core`**: Base abstractions and LangChain Expression Language.
|
||||
- **`langchain-community`**: Third party integrations.
|
||||
- Some integrations have been further split into **partner packages** that only rely on **`langchain-core`**. Examples include **`langchain_openai`** and **`langchain_anthropic`**.
|
||||
- **`langchain`**: Chains, agents, and retrieval strategies that make up an application's cognitive architecture.
|
||||
- **[`LangGraph`](https://langchain-ai.github.io/langgraph/)**: A library for building robust and stateful multi-actor applications with LLMs by modeling steps as edges and nodes in a graph.
|
||||
- **[`LangGraph`](https://langchain-ai.github.io/langgraph/)**: A library for building robust and stateful multi-actor applications with LLMs by modeling steps as edges and nodes in a graph. Integrates smoothly with LangChain, but can be used without it.
|
||||
|
||||
### Productionization:
|
||||
- **[LangSmith](https://docs.smith.langchain.com/)**: A developer platform that lets you debug, test, evaluate, and monitor chains built on any LLM framework and seamlessly integrates with LangChain.
|
||||
|
||||
### Deployment:
|
||||
- **[LangServe](https://python.langchain.com/v0.2/docs/langserve/)**: A library for deploying LangChain chains as REST APIs.
|
||||
- **[LangGraph Cloud](https://langchain-ai.github.io/langgraph/cloud/)**: Turn your LangGraph applications into production-ready APIs and Assistants.
|
||||
|
||||

|
||||

|
||||
|
||||
## 🧱 What can you build with LangChain?
|
||||
|
||||
@@ -106,7 +107,7 @@ Retrieval Augmented Generation involves [loading data](https://python.langchain.
|
||||
|
||||
**🤖 Agents**
|
||||
|
||||
Agents allow an LLM autonomy over how a task is accomplished. Agents make decisions about which Actions to take, then take that Action, observe the result, and repeat until the task is complete. LangChain provides a [standard interface for agents](https://python.langchain.com/v0.2/docs/concepts/#agents) along with the [LangGraph](https://github.com/langchain-ai/langgraph) extension for building custom agents.
|
||||
Agents allow an LLM autonomy over how a task is accomplished. Agents make decisions about which Actions to take, then take that Action, observe the result, and repeat until the task is complete. LangChain provides a [standard interface for agents](https://python.langchain.com/v0.2/docs/concepts/#agents), along with [LangGraph](https://github.com/langchain-ai/langgraph) for building custom agents.
|
||||
|
||||
## 📖 Documentation
|
||||
|
||||
@@ -120,10 +121,9 @@ Please see [here](https://python.langchain.com) for full documentation, which in
|
||||
|
||||
## 🌐 Ecosystem
|
||||
|
||||
- [🦜🛠️ LangSmith](https://docs.smith.langchain.com/): Tracing and evaluating your language model applications and intelligent agents to help you move from prototype to production.
|
||||
- [🦜🕸️ LangGraph](https://langchain-ai.github.io/langgraph/): Creating stateful, multi-actor applications with LLMs, built on top of (and intended to be used with) LangChain primitives.
|
||||
- [🦜🏓 LangServe](https://python.langchain.com/docs/langserve): Deploying LangChain runnables and chains as REST APIs.
|
||||
- [LangChain Templates](https://python.langchain.com/v0.2/docs/templates/): Example applications hosted with LangServe.
|
||||
- [🦜🛠️ LangSmith](https://docs.smith.langchain.com/): Trace and evaluate your language model applications and intelligent agents to help you move from prototype to production.
|
||||
- [🦜🕸️ LangGraph](https://langchain-ai.github.io/langgraph/): Create stateful, multi-actor applications with LLMs. Integrates smoothly with LangChain, but can be used without it.
|
||||
- [🦜🏓 LangServe](https://python.langchain.com/docs/langserve): Deploy LangChain runnables and chains as REST APIs.
|
||||
|
||||
|
||||
## 💁 Contributing
|
||||
|
||||
@@ -61,7 +61,7 @@ render:
|
||||
$(PYTHON) scripts/notebook_convert.py $(INTERMEDIATE_DIR) $(OUTPUT_NEW_DOCS_DIR)
|
||||
|
||||
md-sync:
|
||||
rsync -avm --include="*/" --include="*.mdx" --include="*.md" --include="*.png" --exclude="*" $(INTERMEDIATE_DIR)/ $(OUTPUT_NEW_DOCS_DIR)
|
||||
rsync -avm --include="*/" --include="*.mdx" --include="*.md" --include="*.png" --include="*/_category_.yml" --exclude="*" $(INTERMEDIATE_DIR)/ $(OUTPUT_NEW_DOCS_DIR)
|
||||
|
||||
generate-references:
|
||||
$(PYTHON) scripts/generate_api_reference_links.py --docs_dir $(OUTPUT_NEW_DOCS_DIR)
|
||||
|
||||
@@ -51,8 +51,8 @@ A developer platform that lets you debug, test, evaluate, and monitor LLM applic
|
||||
<ThemedImage
|
||||
alt="Diagram outlining the hierarchical organization of the LangChain framework, displaying the interconnected parts across multiple layers."
|
||||
sources={{
|
||||
light: useBaseUrl('/svg/langchain_stack.svg'),
|
||||
dark: useBaseUrl('/svg/langchain_stack_dark.svg'),
|
||||
light: useBaseUrl('/svg/langchain_stack_june_2024.svg'),
|
||||
dark: useBaseUrl('/svg/langchain_stack_june_2024_dark.svg'),
|
||||
}}
|
||||
title="LangChain Framework Overview"
|
||||
/>
|
||||
@@ -550,6 +550,28 @@ If you are still using AgentExecutor, do not fear: we still have a guide on [how
|
||||
It is recommended, however, that you start to transition to LangGraph.
|
||||
In order to assist in this we have put together a [transition guide on how to do so](/docs/how_to/migrate_agent).
|
||||
|
||||
#### ReAct agents
|
||||
<span data-heading-keywords="react,react agent"></span>
|
||||
|
||||
One popular architecture for building agents is [**ReAct**](https://arxiv.org/abs/2210.03629).
|
||||
ReAct combines reasoning and acting in an iterative process - in fact the name "ReAct" stands for "Reason" and "Act".
|
||||
|
||||
The general flow looks like this:
|
||||
|
||||
- The model will "think" about what step to take in response to an input and any previous observations.
|
||||
- The model will then choose an action from available tools (or choose to respond to the user).
|
||||
- The model will generate arguments to that tool.
|
||||
- The agent runtime (executor) will parse out the chosen tool and call it with the generated arguments.
|
||||
- The executor will return the results of the tool call back to the model as an observation.
|
||||
- This process repeats until the agent chooses to respond.
|
||||
|
||||
There are general prompting based implementations that do not require any model-specific features, but the most
|
||||
reliable implementations use features like [tool calling](/docs/how_to/tool_calling/) to reliably format outputs
|
||||
and reduce variance.
|
||||
|
||||
Please see the [LangGraph documentation](https://langchain-ai.github.io/langgraph/) for more information,
|
||||
or [this how-to guide](/docs/how_to/migrate_agent/) for specific information on migrating to LangGraph.
|
||||
|
||||
### Callbacks
|
||||
|
||||
LangChain provides a callbacks system that allows you to hook into the various stages of your LLM application. This is useful for logging, monitoring, streaming, and other tasks.
|
||||
|
||||
35
docs/docs/contributing/code/guidelines.mdx
Normal file
35
docs/docs/contributing/code/guidelines.mdx
Normal file
@@ -0,0 +1,35 @@
|
||||
# General guidelines
|
||||
|
||||
Here are some things to keep in mind for all types of contributions:
|
||||
|
||||
- Follow the ["fork and pull request"](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project) workflow.
|
||||
- Fill out the checked-in pull request template when opening pull requests. Note related issues and tag relevant maintainers.
|
||||
- Ensure your PR passes formatting, linting, and testing checks before requesting a review.
|
||||
- If you would like comments or feedback on your current progress, please open an issue or discussion and tag a maintainer.
|
||||
- See the sections on [Testing](/docs/contributing/code/setup#testing) and [Formatting and Linting](/docs/contributing/code/setup#formatting-and-linting) for how to run these checks locally.
|
||||
- Backwards compatibility is key. Your changes must not be breaking, except in case of critical bug and security fixes.
|
||||
- Look for duplicate PRs or issues that have already been opened before opening a new one.
|
||||
- Keep scope as isolated as possible. As a general rule, your changes should not affect more than one package at a time.
|
||||
|
||||
## Bugfixes
|
||||
|
||||
We encourage and appreciate bugfixes. We ask that you:
|
||||
|
||||
- Explain the bug in enough detail for maintainers to be able to reproduce it.
|
||||
- If an accompanying issue exists, link to it. Prefix with `Fixes` so that the issue will close automatically when the PR is merged.
|
||||
- Avoid breaking changes if possible.
|
||||
- Include unit tests that fail without the bugfix.
|
||||
|
||||
If you come across a bug and don't know how to fix it, we ask that you open an issue for it describing in detail the environment in which you encountered the bug.
|
||||
|
||||
## New features
|
||||
|
||||
We aim to keep the bar high for new features. We generally don't accept new core abstractions, changes to infra, changes to dependencies,
|
||||
or new agents/chains from outside contributors without an existing GitHub discussion or issue that demonstrates an acute need for them.
|
||||
|
||||
- New features must come with docs, unit tests, and (if appropriate) integration tests.
|
||||
- New integrations must come with docs, unit tests, and (if appropriate) integration tests.
|
||||
- See [this page](/docs/contributing/integrations) for more details on contributing new integrations.
|
||||
- New functionality should not inherit from or use deprecated methods or classes.
|
||||
- We will reject features that are likely to lead to security vulnerabilities or reports.
|
||||
- Do not add any hard dependencies. Integrations may add optional dependencies.
|
||||
6
docs/docs/contributing/code/index.mdx
Normal file
6
docs/docs/contributing/code/index.mdx
Normal file
@@ -0,0 +1,6 @@
|
||||
# Contribute Code
|
||||
|
||||
If you would like to add a new feature or update an existing one, please read the resources below before getting started:
|
||||
|
||||
- [General guidelines](/docs/contributing/code/guidelines/)
|
||||
- [Setup](/docs/contributing/code/setup/)
|
||||
@@ -1,36 +1,9 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
# Contribute Code
|
||||
# Setup
|
||||
|
||||
To contribute to this project, please follow the ["fork and pull request"](https://docs.github.com/en/get-started/quickstart/contributing-to-projects) workflow.
|
||||
Please do not try to push directly to this repo unless you are a maintainer.
|
||||
|
||||
Please follow the checked-in pull request template when opening pull requests. Note related issues and tag relevant
|
||||
maintainers.
|
||||
|
||||
Pull requests cannot land without passing the formatting, linting, and testing checks first. See [Testing](#testing) and
|
||||
[Formatting and Linting](#formatting-and-linting) for how to run these checks locally.
|
||||
|
||||
It's essential that we maintain great documentation and testing. If you:
|
||||
- Fix a bug
|
||||
- Add a relevant unit or integration test when possible. These live in `tests/unit_tests` and `tests/integration_tests`.
|
||||
- Make an improvement
|
||||
- Update any affected example notebooks and documentation. These live in `docs`.
|
||||
- Update unit and integration tests when relevant.
|
||||
- Add a feature
|
||||
- Add a demo notebook in `docs/docs/`.
|
||||
- Add unit and integration tests.
|
||||
|
||||
We are a small, progress-oriented team. If there's something you'd like to add or change, opening a pull request is the
|
||||
best way to get our attention.
|
||||
|
||||
## 🚀 Quick Start
|
||||
|
||||
This quick start guide explains how to run the repository locally.
|
||||
This guide walks through how to run the repository locally and check in your first code.
|
||||
For a [development container](https://containers.dev/), see the [.devcontainer folder](https://github.com/langchain-ai/langchain/tree/master/.devcontainer).
|
||||
|
||||
### Dependency Management: Poetry and other env/dependency managers
|
||||
## Dependency Management: Poetry and other env/dependency managers
|
||||
|
||||
This project utilizes [Poetry](https://python-poetry.org/) v1.7.1+ as a dependency manager.
|
||||
|
||||
@@ -41,7 +14,7 @@ Install Poetry: **[documentation on how to install it](https://python-poetry.org
|
||||
❗Note: If you use `Conda` or `Pyenv` as your environment/package manager, after installing Poetry,
|
||||
tell Poetry to use the virtualenv python environment (`poetry config virtualenvs.prefer-active-python true`)
|
||||
|
||||
### Different packages
|
||||
## Different packages
|
||||
|
||||
This repository contains multiple packages:
|
||||
- `langchain-core`: Base interfaces for key abstractions as well as logic for combining them in chains (LangChain Expression Language).
|
||||
@@ -59,7 +32,7 @@ For this quickstart, start with langchain-community:
|
||||
cd libs/community
|
||||
```
|
||||
|
||||
### Local Development Dependencies
|
||||
## Local Development Dependencies
|
||||
|
||||
Install langchain-community development requirements (for running langchain, running examples, linting, formatting, tests, and coverage):
|
||||
|
||||
@@ -79,9 +52,9 @@ If you are still seeing this bug on v1.6.1+, you may also try disabling "modern
|
||||
(`poetry config installer.modern-installation false`) and re-installing requirements.
|
||||
See [this `debugpy` issue](https://github.com/microsoft/debugpy/issues/1246) for more details.
|
||||
|
||||
### Testing
|
||||
## Testing
|
||||
|
||||
_In `langchain`, `langchain-community`, and `langchain-experimental`, some test dependencies are optional; see section about optional dependencies_.
|
||||
**Note:** In `langchain`, `langchain-community`, and `langchain-experimental`, some test dependencies are optional. See the following section about optional dependencies.
|
||||
|
||||
Unit tests cover modular logic that does not require calls to outside APIs.
|
||||
If you add new logic, please add a unit test.
|
||||
@@ -118,11 +91,11 @@ poetry install --with test
|
||||
make test
|
||||
```
|
||||
|
||||
### Formatting and Linting
|
||||
## Formatting and Linting
|
||||
|
||||
Run these locally before submitting a PR; the CI system will check also.
|
||||
|
||||
#### Code Formatting
|
||||
### Code Formatting
|
||||
|
||||
Formatting for this project is done via [ruff](https://docs.astral.sh/ruff/rules/).
|
||||
|
||||
@@ -174,7 +147,7 @@ This can be very helpful when you've made changes to only certain parts of the p
|
||||
|
||||
We recognize linting can be annoying - if you do not want to do it, please contact a project maintainer, and they can help you with it. We do not want this to be a blocker for good code getting contributed.
|
||||
|
||||
#### Spellcheck
|
||||
### Spellcheck
|
||||
|
||||
Spellchecking for this project is done via [codespell](https://github.com/codespell-project/codespell).
|
||||
Note that `codespell` finds common typos, so it could have false-positive (correctly spelled but rarely used) and false-negatives (not finding misspelled) words.
|
||||
@@ -1,2 +0,0 @@
|
||||
label: 'Documentation'
|
||||
position: 3
|
||||
7
docs/docs/contributing/documentation/index.mdx
Normal file
7
docs/docs/contributing/documentation/index.mdx
Normal file
@@ -0,0 +1,7 @@
|
||||
# Contribute Documentation
|
||||
|
||||
Documentation is a vital part of LangChain. We welcome both new documentation for new features and
|
||||
community improvements to our current documentation. Please read the resources below before getting started:
|
||||
|
||||
- [Documentation style guide](/docs/contributing/documentation/style_guide/)
|
||||
- [Setup](/docs/contributing/documentation/setup/)
|
||||
@@ -1,4 +1,8 @@
|
||||
# Technical logistics
|
||||
---
|
||||
sidebar_class_name: "hidden"
|
||||
---
|
||||
|
||||
# Setup
|
||||
|
||||
LangChain documentation consists of two components:
|
||||
|
||||
@@ -12,8 +16,6 @@ used to generate the externally facing [API Reference](https://api.python.langch
|
||||
The content for the API reference is autogenerated by scanning the docstrings in the codebase. For this reason we ask that
|
||||
developers document their code well.
|
||||
|
||||
The main documentation is built using [Quarto](https://quarto.org) and [Docusaurus 2](https://docusaurus.io/).
|
||||
|
||||
The `API Reference` is largely autogenerated by [sphinx](https://www.sphinx-doc.org/en/master/)
|
||||
from the code and is hosted by [Read the Docs](https://readthedocs.org/).
|
||||
|
||||
@@ -29,7 +31,7 @@ The content for the main documentation is located in the `/docs` directory of th
|
||||
|
||||
The documentation is written using a combination of ipython notebooks (`.ipynb` files)
|
||||
and markdown (`.mdx` files). The notebooks are converted to markdown
|
||||
using [Quarto](https://quarto.org) and then built using [Docusaurus 2](https://docusaurus.io/).
|
||||
and then built using [Docusaurus 2](https://docusaurus.io/).
|
||||
|
||||
Feel free to make contributions to the main documentation! 🥰
|
||||
|
||||
@@ -48,10 +50,6 @@ locally to ensure that it looks good and is free of errors.
|
||||
If you're unable to build it locally that's okay as well, as you will be able to
|
||||
see a preview of the documentation on the pull request page.
|
||||
|
||||
### Install dependencies
|
||||
|
||||
- [Quarto](https://quarto.org) - package that converts Jupyter notebooks (`.ipynb` files) into mdx files for serving in Docusaurus. [Download link](https://quarto.org/docs/download/).
|
||||
|
||||
From the **monorepo root**, run the following command to install the dependencies:
|
||||
|
||||
```bash
|
||||
@@ -71,8 +69,6 @@ make docs_clean
|
||||
make api_docs_clean
|
||||
```
|
||||
|
||||
|
||||
|
||||
Next, you can build the documentation as outlined below:
|
||||
|
||||
```bash
|
||||
@@ -1,10 +1,8 @@
|
||||
---
|
||||
sidebar_label: "Style guide"
|
||||
sidebar_class_name: "hidden"
|
||||
---
|
||||
|
||||
# LangChain Documentation Style Guide
|
||||
|
||||
## Introduction
|
||||
# Documentation Style Guide
|
||||
|
||||
As LangChain continues to grow, the surface area of documentation required to cover it continues to grow too.
|
||||
This page provides guidelines for anyone writing documentation for LangChain, as well as some of our philosophies around
|
||||
@@ -12,116 +10,136 @@ organization and structure.
|
||||
|
||||
## Philosophy
|
||||
|
||||
LangChain's documentation aspires to follow the [Diataxis framework](https://diataxis.fr).
|
||||
Under this framework, all documentation falls under one of four categories:
|
||||
LangChain's documentation follows the [Diataxis framework](https://diataxis.fr).
|
||||
Under this framework, all documentation falls under one of four categories: [Tutorials](/docs/contributing/documentation/style_guide/#tutorials),
|
||||
[How-to guides](/docs/contributing/documentation/style_guide/#how-to-guides),
|
||||
[References](/docs/contributing/documentation/style_guide/#references), and [Explanations](/docs/contributing/documentation/style_guide/#conceptual-guide).
|
||||
|
||||
- **Tutorials**: Lessons that take the reader by the hand through a series of conceptual steps to complete a project.
|
||||
- An example of this is our [LCEL streaming guide](/docs/how_to/streaming).
|
||||
- Our guides on [custom components](/docs/how_to/custom_chat_model) is another one.
|
||||
- **How-to guides**: Guides that take the reader through the steps required to solve a real-world problem.
|
||||
- The clearest examples of this are our [Use case](/docs/how_to#use-cases) quickstart pages.
|
||||
- **Reference**: Technical descriptions of the machinery and how to operate it.
|
||||
- Our [Runnable interface](/docs/concepts#interface) page is an example of this.
|
||||
- The [API reference pages](https://api.python.langchain.com/) are another.
|
||||
- **Explanation**: Explanations that clarify and illuminate a particular topic.
|
||||
- The [LCEL primitives pages](/docs/how_to/sequence) are an example of this.
|
||||
### Tutorials
|
||||
|
||||
Tutorials are lessons that take the reader through a practical activity. Their purpose is to help the user
|
||||
gain understanding of concepts and how they interact by showing one way to achieve some goal in a hands-on way. They should not cover
|
||||
multiple permutations of ways to achieve that goal in-depth, and the end result of a tutorial does not need to
|
||||
be completely production-ready against all cases. Information on how to address additional scenarios
|
||||
can occur in how-to guides.
|
||||
|
||||
To quote the Diataxis website:
|
||||
|
||||
> A tutorial serves the user’s *acquisition* of skills and knowledge - their study. Its purpose is not to help the user get something done, but to help them learn.
|
||||
|
||||
In LangChain, these are often higher level guides that show off end-to-end use cases.
|
||||
|
||||
Some examples include:
|
||||
|
||||
- [Build a Simple LLM Application with LCEL](/docs/tutorials/llm_chain/)
|
||||
- [Build a Retrieval Augmented Generation (RAG) App](/docs/tutorials/rag/)
|
||||
|
||||
Here are some high-level tips on writing a good tutorial:
|
||||
|
||||
- Focus on guiding the user to get something done, but keep in mind the end-goal is more to impart principles than to create a perfect production system
|
||||
- Be specific, not abstract and follow one path
|
||||
- No need to go deeply into alternative approaches, but it’s ok to reference them, ideally with a link to an appropriate how-to guide
|
||||
- Get "a point on the board" as soon as possible - something the user can run that outputs something
|
||||
- You can iterate and expand afterwards
|
||||
- Try to frequently checkpoint at given steps where the user can run code and see progress
|
||||
- Focus on results, not technical explanation
|
||||
- Crosslink heavily to appropriate conceptual/reference pages
|
||||
- The first time you mention a LangChain concept, use its full name (e.g. "LangChain Expression Language (LCEL)"), and link to its conceptual/other documentation page
|
||||
- It's also helpful to add a prerequisite callout that links to any pages with necessary background information
|
||||
- End with a recap/next steps section summarizing what the tutorial covered and future reading, such as related how-to guides
|
||||
|
||||
### How-to guides
|
||||
|
||||
A how-to guide, as the name implies, demonstrates how to do something discrete and specific.
|
||||
It should assume that the user is already familiar with underlying concepts, and is trying to solve an immediate problem, but
|
||||
should still give some background or list the scenarios where the information contained within can be relevant.
|
||||
They can and should discuss alternatives if one approach may be better than another in certain cases.
|
||||
|
||||
To quote the Diataxis website:
|
||||
|
||||
> A how-to guide serves the work of the already-competent user, whom you can assume to know what they want to do, and to be able to follow your instructions correctly.
|
||||
|
||||
Some examples include:
|
||||
|
||||
- [How to: return structured data from a model](/docs/how_to/structured_output/)
|
||||
- [How to: write a custom chat model](/docs/how_to/custom_chat_model/)
|
||||
|
||||
Here are some high-level tips on writing a good how-to guide:
|
||||
|
||||
- Clearly explain what you are guiding the user through at the start
|
||||
- Assume higher intent than a tutorial and show what the user needs to do to get that task done
|
||||
- Assume familiarity of concepts, but explain why suggested actions are helpful
|
||||
- Crosslink heavily to conceptual/reference pages
|
||||
- Discuss alternatives and responses to real-world tradeoffs that may arise when solving a problem
|
||||
- Use lots of example code
|
||||
- End with a recap/next steps section summarizing what the tutorial covered and future reading, such as other related how-to guides
|
||||
|
||||
### Conceptual guide
|
||||
|
||||
LangChain's conceptual guide falls under the **Explanation** quadrant of Diataxis. They should cover LangChain terms and concepts
|
||||
in a more abstract way than how-to guides or tutorials, and should be geared towards curious users interested in
|
||||
gaining a deeper understanding of the framework. There should be few, if any, concrete code examples. The goal here is to
|
||||
impart perspective to the user rather than to finish a practical project.
|
||||
|
||||
This guide on documentation style is meant to fall under this category.
|
||||
|
||||
To quote the Diataxis website:
|
||||
|
||||
> The perspective of explanation is higher and wider than that of the other types. It does not take the user’s eye-level view, as in a how-to guide, or a close-up view of the machinery, like reference material. Its scope in each case is a topic - “an area of knowledge”, that somehow has to be bounded in a reasonable, meaningful way.
|
||||
|
||||
Some examples include:
|
||||
|
||||
- [Retrieval conceptual docs](/docs/concepts/#retrieval)
|
||||
- [Chat model conceptual docs](/docs/concepts/#chat-models)
|
||||
|
||||
Here are some high-level tips on writing a good conceptual guide:
|
||||
|
||||
- Explain design decisions. Why does concept X exist and why was it designed this way?
|
||||
- Use analogies and reference other concepts and alternatives
|
||||
- Avoid blending in too much reference content
|
||||
- You can and should reference content covered in other guides, but make sure to link to them
|
||||
|
||||
### References
|
||||
|
||||
References contain detailed, low-level information that describes exactly what functionality exists and how to use it.
|
||||
In LangChain, this is mainly our API reference pages, which are populated from docstrings within code.
|
||||
References pages are generally not read end-to-end, but are consulted as necessary when a user needs to know
|
||||
how to use something specific.
|
||||
|
||||
To quote the Diataxis website:
|
||||
|
||||
> The only purpose of a reference guide is to describe, as succinctly as possible, and in an orderly way. Whereas the content of tutorials and how-to guides are led by needs of the user, reference material is led by the product it describes.
|
||||
|
||||
Many of the reference pages in LangChain are automatically generated from code,
|
||||
but here are some high-level tips on writing a good docstring:
|
||||
|
||||
- Be concise
|
||||
- Discuss special cases and deviations from a user's expectations
|
||||
- Go into detail on required inputs and outputs
|
||||
- Light details on when one might use the feature are fine, but in-depth details belong in other sections.
|
||||
|
||||
Each category serves a distinct purpose and requires a specific approach to writing and structuring the content.
|
||||
|
||||
## Taxonomy
|
||||
|
||||
Keeping the above in mind, we have sorted LangChain's docs into categories. It is helpful to think in these terms
|
||||
when contributing new documentation:
|
||||
|
||||
### Getting started
|
||||
|
||||
The [getting started section](/docs/introduction) includes a high-level introduction to LangChain, a quickstart that
|
||||
tours LangChain's various features, and logistical instructions around installation and project setup.
|
||||
|
||||
It contains elements of **How-to guides** and **Explanations**.
|
||||
|
||||
### Use cases
|
||||
|
||||
[Use cases](/docs/how_to#use-cases) are guides that are meant to show how to use LangChain to accomplish a specific task (RAG, information extraction, etc.).
|
||||
The quickstarts should be good entrypoints for first-time LangChain developers who prefer to learn by getting something practical prototyped,
|
||||
then taking the pieces apart retrospectively. These should mirror what LangChain is good at.
|
||||
|
||||
The quickstart pages here should fit the **How-to guide** category, with the other pages intended to be **Explanations** of more
|
||||
in-depth concepts and strategies that accompany the main happy paths.
|
||||
|
||||
:::note
|
||||
The below sections are listed roughly in order of increasing level of abstraction.
|
||||
:::
|
||||
|
||||
### Expression Language
|
||||
|
||||
[LangChain Expression Language (LCEL)](/docs/concepts#langchain-expression-language-lcel) is the fundamental way that most LangChain components fit together, and this section is designed to teach
|
||||
developers how to use it to build with LangChain's primitives effectively.
|
||||
|
||||
This section should contains **Tutorials** that teach how to stream and use LCEL primitives for more abstract tasks, **Explanations** of specific behaviors,
|
||||
and some **References** for how to use different methods in the Runnable interface.
|
||||
|
||||
### Components
|
||||
|
||||
The [components section](/docs/concepts) covers concepts one level of abstraction higher than LCEL.
|
||||
Abstract base classes like `BaseChatModel` and `BaseRetriever` should be covered here, as well as core implementations of these base classes,
|
||||
such as `ChatPromptTemplate` and `RecursiveCharacterTextSplitter`. Customization guides belong here too.
|
||||
|
||||
This section should contain mostly conceptual **Tutorials**, **References**, and **Explanations** of the components they cover.
|
||||
|
||||
:::note
|
||||
As a general rule of thumb, everything covered in the `Expression Language` and `Components` sections (with the exception of the `Composition` section of components) should
|
||||
cover only components that exist in `langchain_core`.
|
||||
:::
|
||||
|
||||
### Integrations
|
||||
|
||||
The [integrations](/docs/integrations/platforms/) are specific implementations of components. These often involve third-party APIs and services.
|
||||
If this is the case, as a general rule, these are maintained by the third-party partner.
|
||||
|
||||
This section should contain mostly **Explanations** and **References**, though the actual content here is more flexible than other sections and more at the
|
||||
discretion of the third-party provider.
|
||||
|
||||
:::note
|
||||
Concepts covered in `Integrations` should generally exist in `langchain_community` or specific partner packages.
|
||||
:::
|
||||
|
||||
### Guides and Ecosystem
|
||||
|
||||
The [Guides](/docs/tutorials) and [Ecosystem](https://docs.smith.langchain.com/) sections should contain guides that address higher-level problems than the sections above.
|
||||
This includes, but is not limited to, considerations around productionization and development workflows.
|
||||
|
||||
These should contain mostly **How-to guides**, **Explanations**, and **Tutorials**.
|
||||
|
||||
### API references
|
||||
|
||||
LangChain's API references. Should act as **References** (as the name implies) with some **Explanation**-focused content as well.
|
||||
|
||||
## Sample developer journey
|
||||
|
||||
We have set up our docs to assist a new developer to LangChain. Let's walk through the intended path:
|
||||
|
||||
- The developer lands on https://python.langchain.com, and reads through the introduction and the diagram.
|
||||
- If they are just curious, they may be drawn to the [Quickstart](/docs/tutorials/llm_chain) to get a high-level tour of what LangChain contains.
|
||||
- If they have a specific task in mind that they want to accomplish, they will be drawn to the Use-Case section. The use-case should provide a good, concrete hook that shows the value LangChain can provide them and be a good entrypoint to the framework.
|
||||
- They can then move to learn more about the fundamentals of LangChain through the Expression Language sections.
|
||||
- Next, they can learn about LangChain's various components and integrations.
|
||||
- Finally, they can get additional knowledge through the Guides.
|
||||
|
||||
This is only an ideal of course - sections will inevitably reference lower or higher-level concepts that are documented in other sections.
|
||||
|
||||
## Guidelines
|
||||
## General guidelines
|
||||
|
||||
Here are some other guidelines you should think about when writing and organizing documentation.
|
||||
|
||||
### Linking to other sections
|
||||
We generally do not merge new tutorials from outside contributors without an actue need.
|
||||
We welcome updates as well as new integration docs, how-tos, and references.
|
||||
|
||||
### Avoid duplication
|
||||
|
||||
Multiple pages that cover the same material in depth are difficult to maintain and cause confusion. There should
|
||||
be only one (very rarely two), canonical pages for a given concept or feature. Instead, you should link to other guides.
|
||||
|
||||
### Link to other sections
|
||||
|
||||
Because sections of the docs do not exist in a vacuum, it is important to link to other sections as often as possible
|
||||
to allow a developer to learn more about an unfamiliar topic inline.
|
||||
|
||||
This includes linking to the API references as well as conceptual sections!
|
||||
|
||||
### Conciseness
|
||||
### Be concise
|
||||
|
||||
In general, take a less-is-more approach. If a section with a good explanation of a concept already exists, you should link to it rather than
|
||||
re-explain it, unless the concept you are documenting presents some new wrinkle.
|
||||
@@ -130,9 +148,10 @@ Be concise, including in code samples.
|
||||
|
||||
### General style
|
||||
|
||||
- Use active voice and present tense whenever possible.
|
||||
- Use examples and code snippets to illustrate concepts and usage.
|
||||
- Use appropriate header levels (`#`, `##`, `###`, etc.) to organize the content hierarchically.
|
||||
- Use bullet points and numbered lists to break down information into easily digestible chunks.
|
||||
- Use tables (especially for **Reference** sections) and diagrams often to present information visually.
|
||||
- Include the table of contents for longer documentation pages to help readers navigate the content, but hide it for shorter pages.
|
||||
- Use active voice and present tense whenever possible
|
||||
- Use examples and code snippets to illustrate concepts and usage
|
||||
- Use appropriate header levels (`#`, `##`, `###`, etc.) to organize the content hierarchically
|
||||
- Use fewer cells with more code to make copy/paste easier
|
||||
- Use bullet points and numbered lists to break down information into easily digestible chunks
|
||||
- Use tables (especially for **Reference** sections) and diagrams often to present information visually
|
||||
- Include the table of contents for longer documentation pages to help readers navigate the content, but hide it for shorter pages
|
||||
|
||||
@@ -12,8 +12,8 @@ As an open-source project in a rapidly developing field, we are extremely open t
|
||||
|
||||
There are many ways to contribute to LangChain. Here are some common ways people contribute:
|
||||
|
||||
- [**Documentation**](/docs/contributing/documentation/style_guide): Help improve our docs, including this one!
|
||||
- [**Code**](./code.mdx): Help us write code, fix bugs, or improve our infrastructure.
|
||||
- [**Documentation**](/docs/contributing/documentation/): Help improve our docs, including this one!
|
||||
- [**Code**](/docs/contributing/code/): Help us write code, fix bugs, or improve our infrastructure.
|
||||
- [**Integrations**](integrations.mdx): Help us integrate with your favorite vendors and tools.
|
||||
- [**Discussions**](https://github.com/langchain-ai/langchain/discussions): Help answer usage questions and discuss issues with users.
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# Contribute Integrations
|
||||
|
||||
To begin, make sure you have all the dependencies outlined in guide on [Contributing Code](/docs/contributing/code/).
|
||||
|
||||
@@ -7,6 +7,7 @@ If you plan on contributing to LangChain code or documentation, it can be useful
|
||||
to understand the high level structure of the repository.
|
||||
|
||||
LangChain is organized as a [monorepo](https://en.wikipedia.org/wiki/Monorepo) that contains multiple packages.
|
||||
You can check out our [installation guide](/docs/how_to/installation/) for more on how they fit together.
|
||||
|
||||
Here's the structure visualized as a tree:
|
||||
|
||||
@@ -51,7 +52,7 @@ There are other files in the root directory level, but their presence should be
|
||||
The `/docs` directory contains the content for the documentation that is shown
|
||||
at https://python.langchain.com/ and the associated API Reference https://api.python.langchain.com/en/latest/langchain_api_reference.html.
|
||||
|
||||
See the [documentation](/docs/contributing/documentation/style_guide) guidelines to learn how to contribute to the documentation.
|
||||
See the [documentation](/docs/contributing/documentation/) guidelines to learn how to contribute to the documentation.
|
||||
|
||||
## Code
|
||||
|
||||
@@ -59,6 +60,6 @@ The `/libs` directory contains the code for the LangChain packages.
|
||||
|
||||
To learn more about how to contribute code see the following guidelines:
|
||||
|
||||
- [Code](./code.mdx) Learn how to develop in the LangChain codebase.
|
||||
- [Integrations](./integrations.mdx) to learn how to contribute to third-party integrations to langchain-community or to start a new partner package.
|
||||
- [Testing](./testing.mdx) guidelines to learn how to write tests for the packages.
|
||||
- [Code](/docs/contributing/code/): Learn how to develop in the LangChain codebase.
|
||||
- [Integrations](./integrations.mdx): Learn how to contribute to third-party integrations to `langchain-community` or to start a new partner package.
|
||||
- [Testing](./testing.mdx): Guidelines to learn how to write tests for the packages.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
sidebar_position: 6
|
||||
---
|
||||
|
||||
# Testing
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
"- `examples`: A list of dictionary examples to include in the final prompt.\n",
|
||||
"- `example_prompt`: converts each example into 1 or more messages through its [`format_messages`](https://api.python.langchain.com/en/latest/prompts/langchain_core.prompts.chat.ChatPromptTemplate.html?highlight=format_messages#langchain_core.prompts.chat.ChatPromptTemplate.format_messages) method. A common example would be to convert each example into one human message and one AI message response, or a human message followed by a function call message.\n",
|
||||
"\n",
|
||||
"Below is a simple demonstration. First, define the examples you'd like to include:"
|
||||
"Below is a simple demonstration. First, define the examples you'd like to include. Let's give the LLM an unfamiliar mathematical operator, denoted by the \"🦜\" emoji:"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -59,17 +59,7 @@
|
||||
"execution_count": 1,
|
||||
"id": "5b79e400",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\u001b[33mWARNING: You are using pip version 22.0.4; however, version 24.0 is available.\n",
|
||||
"You should consider upgrading via the '/Users/jacoblee/.pyenv/versions/3.10.5/bin/python -m pip install --upgrade pip' command.\u001b[0m\u001b[33m\n",
|
||||
"\u001b[0mNote: you may need to restart the kernel to use updated packages.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install -qU langchain langchain-openai langchain-chroma\n",
|
||||
"\n",
|
||||
@@ -79,9 +69,50 @@
|
||||
"os.environ[\"OPENAI_API_KEY\"] = getpass()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "30856d92",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"If we try to ask the model what the result of this expression is, it will fail:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"execution_count": 4,
|
||||
"id": "174dec5b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"AIMessage(content='The expression \"2 🦜 9\" is not a standard mathematical operation or equation. It appears to be a combination of the number 2 and the parrot emoji 🦜 followed by the number 9. It does not have a specific mathematical meaning.', response_metadata={'token_usage': {'completion_tokens': 54, 'prompt_tokens': 17, 'total_tokens': 71}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-aad12dda-5c47-4a1e-9949-6fe94e03242a-0', usage_metadata={'input_tokens': 17, 'output_tokens': 54, 'total_tokens': 71})"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain_openai import ChatOpenAI\n",
|
||||
"\n",
|
||||
"model = ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0.0)\n",
|
||||
"\n",
|
||||
"model.invoke(\"What is 2 🦜 9?\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e6d58385",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now let's see what happens if we give the LLM some examples to work with. We'll define some below:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "0fc5a02a-6249-4e92-95c3-30fff9671e8b",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@@ -91,8 +122,8 @@
|
||||
"from langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate\n",
|
||||
"\n",
|
||||
"examples = [\n",
|
||||
" {\"input\": \"2+2\", \"output\": \"4\"},\n",
|
||||
" {\"input\": \"2+3\", \"output\": \"5\"},\n",
|
||||
" {\"input\": \"2 🦜 2\", \"output\": \"4\"},\n",
|
||||
" {\"input\": \"2 🦜 3\", \"output\": \"5\"},\n",
|
||||
"]"
|
||||
]
|
||||
},
|
||||
@@ -106,7 +137,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"execution_count": 6,
|
||||
"id": "65e72ad1-9060-47d0-91a1-bc130c8b98ac",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@@ -116,7 +147,7 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[HumanMessage(content='2+2'), AIMessage(content='4'), HumanMessage(content='2+3'), AIMessage(content='5')]\n"
|
||||
"[HumanMessage(content='2 🦜 2'), AIMessage(content='4'), HumanMessage(content='2 🦜 3'), AIMessage(content='5')]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -146,7 +177,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": 7,
|
||||
"id": "9f86d6d9-50de-41b6-b6c7-0f9980cc0187",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@@ -162,9 +193,17 @@
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "dd8029c5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"And now let's ask the model the initial question and see how it does:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"execution_count": 8,
|
||||
"id": "97d443b1-6fae-4b36-bede-3ff7306288a3",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@@ -173,10 +212,10 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"AIMessage(content='A triangle does not have a square. The square of a number is the result of multiplying the number by itself.', response_metadata={'token_usage': {'completion_tokens': 23, 'prompt_tokens': 52, 'total_tokens': 75}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': 'fp_c2295e73ad', 'finish_reason': 'stop', 'logprobs': None}, id='run-3456c4ef-7b4d-4adb-9e02-8079de82a47a-0')"
|
||||
"AIMessage(content='11', response_metadata={'token_usage': {'completion_tokens': 1, 'prompt_tokens': 60, 'total_tokens': 61}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-5ec4e051-262f-408e-ad00-3f2ebeb561c3-0', usage_metadata={'input_tokens': 60, 'output_tokens': 1, 'total_tokens': 61})"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -184,9 +223,9 @@
|
||||
"source": [
|
||||
"from langchain_openai import ChatOpenAI\n",
|
||||
"\n",
|
||||
"chain = final_prompt | ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0.0)\n",
|
||||
"chain = final_prompt | model\n",
|
||||
"\n",
|
||||
"chain.invoke({\"input\": \"What's the square of a triangle?\"})"
|
||||
"chain.invoke({\"input\": \"What is 2 🦜 9?\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -194,6 +233,8 @@
|
||||
"id": "70ab7114-f07f-46be-8874-3705a25aba5f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"And we can see that the model has now inferred that the parrot emoji means addition from the given few-shot examples!\n",
|
||||
"\n",
|
||||
"## Dynamic few-shot prompting\n",
|
||||
"\n",
|
||||
"Sometimes you may want to select only a few examples from your overall set to show based on the input. For this, you can replace the `examples` passed into `FewShotChatMessagePromptTemplate` with an `example_selector`. The other components remain the same as above! Our dynamic few-shot prompt template would look like:\n",
|
||||
@@ -208,7 +249,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"execution_count": 9,
|
||||
"id": "ad66f06a-66fd-4fcc-8166-5d0e3c801e57",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@@ -220,9 +261,9 @@
|
||||
"from langchain_openai import OpenAIEmbeddings\n",
|
||||
"\n",
|
||||
"examples = [\n",
|
||||
" {\"input\": \"2+2\", \"output\": \"4\"},\n",
|
||||
" {\"input\": \"2+3\", \"output\": \"5\"},\n",
|
||||
" {\"input\": \"2+4\", \"output\": \"6\"},\n",
|
||||
" {\"input\": \"2 🦜 2\", \"output\": \"4\"},\n",
|
||||
" {\"input\": \"2 🦜 3\", \"output\": \"5\"},\n",
|
||||
" {\"input\": \"2 🦜 4\", \"output\": \"6\"},\n",
|
||||
" {\"input\": \"What did the cow say to the moon?\", \"output\": \"nothing at all\"},\n",
|
||||
" {\n",
|
||||
" \"input\": \"Write me a poem about the moon\",\n",
|
||||
@@ -247,7 +288,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"execution_count": 10,
|
||||
"id": "7790303a-f722-452e-8921-b14bdf20bdff",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@@ -257,10 +298,10 @@
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[{'input': 'What did the cow say to the moon?', 'output': 'nothing at all'},\n",
|
||||
" {'input': '2+4', 'output': '6'}]"
|
||||
" {'input': '2 🦜 4', 'output': '6'}]"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -287,7 +328,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"execution_count": 11,
|
||||
"id": "253c255e-41d7-45f6-9d88-c7a0ced4b1bd",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@@ -297,7 +338,7 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[HumanMessage(content='2+3'), AIMessage(content='5'), HumanMessage(content='2+2'), AIMessage(content='4')]\n"
|
||||
"[HumanMessage(content='2 🦜 3'), AIMessage(content='5'), HumanMessage(content='2 🦜 4'), AIMessage(content='6')]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -317,7 +358,7 @@
|
||||
" ),\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(few_shot_prompt.invoke(input=\"What's 3+3?\").to_messages())"
|
||||
"print(few_shot_prompt.invoke(input=\"What's 3 🦜 3?\").to_messages())"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -330,7 +371,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"execution_count": 12,
|
||||
"id": "e731cb45-f0ea-422c-be37-42af2a6cb2c4",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@@ -340,7 +381,7 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"messages=[HumanMessage(content='2+3'), AIMessage(content='5'), HumanMessage(content='2+2'), AIMessage(content='4')]\n"
|
||||
"messages=[HumanMessage(content='2 🦜 3'), AIMessage(content='5'), HumanMessage(content='2 🦜 4'), AIMessage(content='6')]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -353,7 +394,7 @@
|
||||
" ]\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(few_shot_prompt.invoke(input=\"What's 3+3?\"))"
|
||||
"print(few_shot_prompt.invoke(input=\"What's 3 🦜 3?\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -368,7 +409,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"execution_count": 13,
|
||||
"id": "0568cbc6-5354-47f1-ab4d-dfcc616cf583",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
@@ -377,10 +418,10 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"AIMessage(content='6', response_metadata={'token_usage': {'completion_tokens': 1, 'prompt_tokens': 51, 'total_tokens': 52}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': 'fp_c2295e73ad', 'finish_reason': 'stop', 'logprobs': None}, id='run-6bcbe158-a8e3-4a85-a754-1ba274a9f147-0')"
|
||||
"AIMessage(content='6', response_metadata={'token_usage': {'completion_tokens': 1, 'prompt_tokens': 60, 'total_tokens': 61}, 'model_name': 'gpt-3.5-turbo-0125', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-d1863e5e-17cd-4e9d-bf7a-b9f118747a65-0', usage_metadata={'input_tokens': 60, 'output_tokens': 1, 'total_tokens': 61})"
|
||||
]
|
||||
},
|
||||
"execution_count": 18,
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -388,7 +429,7 @@
|
||||
"source": [
|
||||
"chain = final_prompt | ChatOpenAI(model=\"gpt-3.5-turbo-0125\", temperature=0.0)\n",
|
||||
"\n",
|
||||
"chain.invoke({\"input\": \"What's 3+3?\"})"
|
||||
"chain.invoke({\"input\": \"What's 3 🦜 3?\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -428,7 +469,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.1"
|
||||
"version": "3.10.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -2,11 +2,14 @@
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Installation
|
||||
# How to install LangChain packages
|
||||
|
||||
The LangChain ecosystem is split into different packages, which allow you to choose exactly which pieces of
|
||||
functionality to install.
|
||||
|
||||
## Official release
|
||||
|
||||
To install LangChain run:
|
||||
To install the main LangChain package, run:
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
@@ -21,11 +24,24 @@ import CodeBlock from "@theme/CodeBlock";
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
This will install the bare minimum requirements of LangChain.
|
||||
A lot of the value of LangChain comes when integrating it with various model providers, datastores, etc.
|
||||
While this package acts as a sane starting point to using LangChain,
|
||||
much of the value of LangChain comes when integrating it with various model providers, datastores, etc.
|
||||
By default, the dependencies needed to do that are NOT installed. You will need to install the dependencies for specific integrations separately.
|
||||
We'll show how to do that in the next sections of this guide.
|
||||
|
||||
## From source
|
||||
## Ecosystem packages
|
||||
|
||||
With the exception of the `langsmith` SDK, all packages in the LangChain ecosystem depend on `langchain-core`, which contains base
|
||||
classes and abstractions that other packages use. The dependency graph below shows how the difference packages are related.
|
||||
A directed arrow indicates that the source package depends on the target package:
|
||||
|
||||

|
||||
|
||||
When installing a package, you do not need to explicitly install that package's explicit dependencies (such as `langchain-core`).
|
||||
However, you may choose to if you are using a feature only available in a certain version of that dependency.
|
||||
If you do, you should make sure that the installed or pinned version is compatible with any other integration packages you use.
|
||||
|
||||
### From source
|
||||
|
||||
If you want to install from source, you can do so by cloning the repo and be sure that the directory is `PATH/TO/REPO/langchain/libs/langchain` running:
|
||||
|
||||
@@ -33,21 +49,21 @@ If you want to install from source, you can do so by cloning the repo and be sur
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
## LangChain core
|
||||
### LangChain core
|
||||
The `langchain-core` package contains base abstractions that the rest of the LangChain ecosystem uses, along with the LangChain Expression Language. It is automatically installed by `langchain`, but can also be used separately. Install with:
|
||||
|
||||
```bash
|
||||
pip install langchain-core
|
||||
```
|
||||
|
||||
## LangChain community
|
||||
### LangChain community
|
||||
The `langchain-community` package contains third-party integrations. Install with:
|
||||
|
||||
```bash
|
||||
pip install langchain-community
|
||||
```
|
||||
|
||||
## LangChain experimental
|
||||
### LangChain experimental
|
||||
The `langchain-experimental` package holds experimental LangChain code, intended for research and experimental uses.
|
||||
Install with:
|
||||
|
||||
@@ -55,14 +71,15 @@ Install with:
|
||||
pip install langchain-experimental
|
||||
```
|
||||
|
||||
## LangGraph
|
||||
`langgraph` is a library for building stateful, multi-actor applications with LLMs, built on top of (and intended to be used with) LangChain.
|
||||
### LangGraph
|
||||
`langgraph` is a library for building stateful, multi-actor applications with LLM. It integrates smoothly with LangChain, but can be used without it.
|
||||
Install with:
|
||||
|
||||
```bash
|
||||
pip install langgraph
|
||||
```
|
||||
## LangServe
|
||||
|
||||
### LangServe
|
||||
LangServe helps developers deploy LangChain runnables and chains as a REST API.
|
||||
LangServe is automatically installed by LangChain CLI.
|
||||
If not using LangChain CLI, install with:
|
||||
@@ -80,9 +97,10 @@ Install with:
|
||||
pip install langchain-cli
|
||||
```
|
||||
|
||||
## LangSmith SDK
|
||||
The LangSmith SDK is automatically installed by LangChain.
|
||||
If not using LangChain, install with:
|
||||
### LangSmith SDK
|
||||
The LangSmith SDK is automatically installed by LangChain. However, it does not depend on
|
||||
`langchain-core`, and can be installed and used independently if desired.
|
||||
If you are not using LangChain, you can install it with:
|
||||
|
||||
```bash
|
||||
pip install langsmith
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "raw",
|
||||
"id": "adc7ee09",
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "raw"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"---\n",
|
||||
"keywords: [create_react_agent, create_react_agent()]\n",
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "457cdc67-1893-4653-8b0c-b185a5947e74",
|
||||
@@ -9,7 +23,7 @@
|
||||
"\n",
|
||||
"Here we focus on how to move from legacy LangChain agents to LangGraph agents.\n",
|
||||
"LangChain agents (the [AgentExecutor](https://api.python.langchain.com/en/latest/agents/langchain.agents.agent.AgentExecutor.html#langchain.agents.agent.AgentExecutor) in particular) have multiple configuration parameters.\n",
|
||||
"In this notebook we will show how those parameters map to the LangGraph [react agent executor](https://langchain-ai.github.io/langgraph/reference/prebuilt/#create_react_agent).\n",
|
||||
"In this notebook we will show how those parameters map to the LangGraph react agent executor using the [create_react_agent](https://langchain-ai.github.io/langgraph/reference/prebuilt/#create_react_agent) prebuilt helper method.\n",
|
||||
"\n",
|
||||
"#### Prerequisites\n",
|
||||
"\n",
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "raw",
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "raw"
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"---\n",
|
||||
"keywords: [tool calling, tool call]\n",
|
||||
"---"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
||||
@@ -18,7 +18,9 @@
|
||||
"# ChatAI21\n",
|
||||
"\n",
|
||||
"This notebook covers how to get started with AI21 chat models.\n",
|
||||
"\n",
|
||||
"Note that different chat models support different parameters. See the ",
|
||||
"[AI21 documentation](https://docs.ai21.com/reference) to learn more about the parameters in your chosen model.\n",
|
||||
"[See all AI21's LangChain components.](https://pypi.org/project/langchain-ai21/) \n",
|
||||
"## Installation"
|
||||
]
|
||||
},
|
||||
@@ -44,7 +46,8 @@
|
||||
"source": [
|
||||
"## Environment Setup\n",
|
||||
"\n",
|
||||
"We'll need to get a [AI21 API key](https://docs.ai21.com/) and set the `AI21_API_KEY` environment variable:\n"
|
||||
"We'll need to get an [AI21 API key](https://docs.ai21.com/) and set the ",
|
||||
"`AI21_API_KEY` environment variable:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"\n",
|
||||
"Headless mode means that the browser is running without a graphical user interface.\n",
|
||||
"\n",
|
||||
"`AsyncChromiumLoader` loads the page, and then we use `Html2TextTransformer` to transform to text."
|
||||
"In the below example we'll use the `AsyncChromiumLoader` to loads the page, and then the [`Html2TextTransformer`](/docs/integrations/document_transformers/html2text/) to strip out the HTML tags and other semantic information."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -23,48 +23,22 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install --upgrade --quiet playwright beautifulsoup4\n",
|
||||
"%pip install --upgrade --quiet playwright beautifulsoup4 html2text\n",
|
||||
"!playwright install"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "dd2cdea7",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'<!DOCTYPE html><html lang=\"en\"><head><script src=\"https://s0.2mdn.net/instream/video/client.js\" asyn'"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain_community.document_loaders import AsyncChromiumLoader\n",
|
||||
"\n",
|
||||
"urls = [\"https://www.wsj.com\"]\n",
|
||||
"loader = AsyncChromiumLoader(urls, user_agent=\"MyAppUserAgent\")\n",
|
||||
"docs = loader.load()\n",
|
||||
"docs[0].page_content[0:100]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c64e7df9",
|
||||
"id": "00487c0f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"If you are using Jupyter notebooks, you might need to apply `nest_asyncio` before loading the documents."
|
||||
"**Note:** If you are using Jupyter notebooks, you might also need to install and apply `nest_asyncio` before loading the documents like this:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5f2fe3c0",
|
||||
"id": "d374eef4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
@@ -74,6 +48,40 @@
|
||||
"nest_asyncio.apply()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "dd2cdea7",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'<!DOCTYPE html><html lang=\"en\" dir=\"ltr\" class=\"docs-wrapper docs-doc-page docs-version-2.0 plugin-d'"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain_community.document_loaders import AsyncChromiumLoader\n",
|
||||
"\n",
|
||||
"urls = [\"https://docs.smith.langchain.com/\"]\n",
|
||||
"loader = AsyncChromiumLoader(urls, user_agent=\"MyAppUserAgent\")\n",
|
||||
"docs = loader.load()\n",
|
||||
"docs[0].page_content[0:100]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7eb5e6aa",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now let's transform the documents into a more readable syntax using the transformer:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
@@ -83,7 +91,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\"Skip to Main ContentSkip to SearchSkip to... Select * Top News * What's News *\\nFeatured Stories * Retirement * Life & Arts * Hip-Hop * Sports * Video *\\nEconomy * Real Estate * Sports * CMO * CIO * CFO * Risk & Compliance *\\nLogistics Report * Sustainable Business * Heard on the Street * Barron’s *\\nMarketWatch * Mansion Global * Penta * Opinion * Journal Reports * Sponsored\\nOffers Explore Our Brands * WSJ * * * * * Barron's * * * * * MarketWatch * * *\\n* * IBD # The Wall Street Journal SubscribeSig\""
|
||||
"'Skip to main content\\n\\nGo to API Docs\\n\\nSearch`⌘``K`\\n\\nGo to App\\n\\n * Quick start\\n * Tutorials\\n\\n * How-to guides\\n\\n * Concepts\\n\\n * Reference\\n\\n * Pricing\\n * Self-hosting\\n\\n * LangGraph Cloud\\n\\n * * Quick start\\n\\nOn this page\\n\\n# Get started with LangSmith\\n\\n**LangSmith** is a platform for building production-grade LLM applications. It\\nallows you to closely monitor and evaluate your application, so you can ship\\nquickly and with confidence. Use of LangChain is not necessary - LangSmith\\nworks on it'"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
@@ -116,7 +124,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.16"
|
||||
"version": "3.10.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -12,35 +12,50 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "e6616e3a",
|
||||
"execution_count": null,
|
||||
"id": "0b01ee46",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain_community.document_loaders import UnstructuredExcelLoader"
|
||||
"%pip install --upgrade --quiet langchain-community unstructured openpyxl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"execution_count": 6,
|
||||
"id": "a654e4d9",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"4\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Document(page_content='\\n \\n \\n Team\\n Location\\n Stanley Cups\\n \\n \\n Blues\\n STL\\n 1\\n \\n \\n Flyers\\n PHI\\n 2\\n \\n \\n Maple Leafs\\n TOR\\n 13\\n \\n \\n', metadata={'source': 'example_data/stanley-cups.xlsx', 'filename': 'stanley-cups.xlsx', 'file_directory': 'example_data', 'filetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'page_number': 1, 'page_name': 'Stanley Cups', 'text_as_html': '<table border=\"1\" class=\"dataframe\">\\n <tbody>\\n <tr>\\n <td>Team</td>\\n <td>Location</td>\\n <td>Stanley Cups</td>\\n </tr>\\n <tr>\\n <td>Blues</td>\\n <td>STL</td>\\n <td>1</td>\\n </tr>\\n <tr>\\n <td>Flyers</td>\\n <td>PHI</td>\\n <td>2</td>\\n </tr>\\n <tr>\\n <td>Maple Leafs</td>\\n <td>TOR</td>\\n <td>13</td>\\n </tr>\\n </tbody>\\n</table>', 'category': 'Table'})"
|
||||
"[Document(page_content='Stanley Cups', metadata={'source': 'example_data/stanley-cups.xlsx', 'file_directory': 'example_data', 'filename': 'stanley-cups.xlsx', 'last_modified': '2023-12-19T13:42:18', 'page_name': 'Stanley Cups', 'page_number': 1, 'languages': ['eng'], 'filetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'category': 'Title'}),\n",
|
||||
" Document(page_content='\\n\\n\\nTeam\\nLocation\\nStanley Cups\\n\\n\\nBlues\\nSTL\\n1\\n\\n\\nFlyers\\nPHI\\n2\\n\\n\\nMaple Leafs\\nTOR\\n13\\n\\n\\n', metadata={'source': 'example_data/stanley-cups.xlsx', 'file_directory': 'example_data', 'filename': 'stanley-cups.xlsx', 'last_modified': '2023-12-19T13:42:18', 'page_name': 'Stanley Cups', 'page_number': 1, 'text_as_html': '<table border=\"1\" class=\"dataframe\">\\n <tbody>\\n <tr>\\n <td>Team</td>\\n <td>Location</td>\\n <td>Stanley Cups</td>\\n </tr>\\n <tr>\\n <td>Blues</td>\\n <td>STL</td>\\n <td>1</td>\\n </tr>\\n <tr>\\n <td>Flyers</td>\\n <td>PHI</td>\\n <td>2</td>\\n </tr>\\n <tr>\\n <td>Maple Leafs</td>\\n <td>TOR</td>\\n <td>13</td>\\n </tr>\\n </tbody>\\n</table>', 'languages': ['eng'], 'parent_id': '17e9a90f9616f2abed8cf32b5bd3810d', 'filetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'category': 'Table'}),\n",
|
||||
" Document(page_content='Stanley Cups Since 67', metadata={'source': 'example_data/stanley-cups.xlsx', 'file_directory': 'example_data', 'filename': 'stanley-cups.xlsx', 'last_modified': '2023-12-19T13:42:18', 'page_name': 'Stanley Cups Since 67', 'page_number': 2, 'languages': ['eng'], 'filetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'category': 'Title'}),\n",
|
||||
" Document(page_content='\\n\\n\\nTeam\\nLocation\\nStanley Cups\\n\\n\\nBlues\\nSTL\\n1\\n\\n\\nFlyers\\nPHI\\n2\\n\\n\\nMaple Leafs\\nTOR\\n0\\n\\n\\n', metadata={'source': 'example_data/stanley-cups.xlsx', 'file_directory': 'example_data', 'filename': 'stanley-cups.xlsx', 'last_modified': '2023-12-19T13:42:18', 'page_name': 'Stanley Cups Since 67', 'page_number': 2, 'text_as_html': '<table border=\"1\" class=\"dataframe\">\\n <tbody>\\n <tr>\\n <td>Team</td>\\n <td>Location</td>\\n <td>Stanley Cups</td>\\n </tr>\\n <tr>\\n <td>Blues</td>\\n <td>STL</td>\\n <td>1</td>\\n </tr>\\n <tr>\\n <td>Flyers</td>\\n <td>PHI</td>\\n <td>2</td>\\n </tr>\\n <tr>\\n <td>Maple Leafs</td>\\n <td>TOR</td>\\n <td>0</td>\\n </tr>\\n </tbody>\\n</table>', 'languages': ['eng'], 'parent_id': 'ee34bd8c186b57e3530d5443ffa58122', 'filetype': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'category': 'Table'})]"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain_community.document_loaders import UnstructuredExcelLoader\n",
|
||||
"\n",
|
||||
"loader = UnstructuredExcelLoader(\"example_data/stanley-cups.xlsx\", mode=\"elements\")\n",
|
||||
"docs = loader.load()\n",
|
||||
"docs[0]"
|
||||
"\n",
|
||||
"print(len(docs))\n",
|
||||
"\n",
|
||||
"docs"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -76,7 +91,7 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install --upgrade --quiet langchain langchain-community azure-ai-documentintelligence"
|
||||
"%pip install --upgrade --quiet langchain langchain-community azure-ai-documentintelligence"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -115,7 +130,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.13"
|
||||
"version": "3.10.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -19,12 +19,12 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install --upgrade --quiet html2text"
|
||||
"%pip install --upgrade --quiet html2text"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": 2,
|
||||
"id": "8ca0974b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -32,7 +32,8 @@
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Fetching pages: 100%|############| 2/2 [00:00<00:00, 10.75it/s]\n"
|
||||
"USER_AGENT environment variable not set, consider setting it to identify your requests.\n",
|
||||
"Fetching pages: 100%|##########| 2/2 [00:00<00:00, 14.74it/s]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -46,66 +47,107 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "ddf2be97",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain_community.document_transformers import Html2TextTransformer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"execution_count": 3,
|
||||
"id": "a95a928c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"## Fantasy\n",
|
||||
"\n",
|
||||
" * Football\n",
|
||||
"\n",
|
||||
" * Baseball\n",
|
||||
"\n",
|
||||
" * Basketball\n",
|
||||
"\n",
|
||||
" * Hockey\n",
|
||||
"\n",
|
||||
"## ESPN Sites\n",
|
||||
"\n",
|
||||
" * ESPN Deportes\n",
|
||||
"\n",
|
||||
" * Andscape\n",
|
||||
"\n",
|
||||
" * espnW\n",
|
||||
"\n",
|
||||
" * ESPNFC\n",
|
||||
"\n",
|
||||
" * X Games\n",
|
||||
"\n",
|
||||
" * SEC Network\n",
|
||||
"\n",
|
||||
"## ESPN Apps\n",
|
||||
"\n",
|
||||
" * ESPN\n",
|
||||
"\n",
|
||||
" * ESPN Fantasy\n",
|
||||
"\n",
|
||||
" * Tournament Challenge\n",
|
||||
"\n",
|
||||
"## Follow ESPN\n",
|
||||
"\n",
|
||||
" * Facebook\n",
|
||||
"\n",
|
||||
" * X/Twitter\n",
|
||||
"\n",
|
||||
" * Instagram\n",
|
||||
"\n",
|
||||
" * Snapchat\n",
|
||||
"\n",
|
||||
" * TikTok\n",
|
||||
"\n",
|
||||
" * YouTube\n",
|
||||
"\n",
|
||||
"## Fresh updates to our NBA mock draft: Everything we're hearing hours before\n",
|
||||
"Round 1\n",
|
||||
"\n",
|
||||
"With hours until Round 1 begins (8 p.m. ET on ESPN and ABC), ESPN draft\n",
|
||||
"insiders Jonathan Givony and Jeremy Woo have new intel on lottery picks and\n",
|
||||
"more.\n",
|
||||
"\n",
|
||||
"2hJonathan Givony and Jeremy Woo\n",
|
||||
"\n",
|
||||
"Illustration by ESPN\n",
|
||||
"\n",
|
||||
"## From No. 1 to 100: Ranking the 2024 NBA draft prospects\n",
|
||||
"\n",
|
||||
"Who's No. 1? Where do the Kentucky, Duke and UConn players rank? Here's our\n",
|
||||
"final Top 100 Big Board.\n",
|
||||
"\n",
|
||||
"6hJonathan Givony and Jeremy Woo\n",
|
||||
"\n",
|
||||
" * Full draft order: All 58 picks over two rounds\n",
|
||||
" * Trade tracker: Details for all deals\n",
|
||||
"\n",
|
||||
" * Betting buzz: Lakers favorites to draft Bronny\n",
|
||||
" * Use our NBA draft simu\n",
|
||||
"ent system, LLM functions as the agent's brain,\n",
|
||||
"complemented by several key components:\n",
|
||||
"\n",
|
||||
" * **Planning**\n",
|
||||
" * Subgoal and decomposition: The agent breaks down large tasks into smaller, manageable subgoals, enabling efficient handling of complex tasks.\n",
|
||||
" * Reflection and refinement: The agent can do self-criticism and self-reflection over past actions, learn from mistakes and refine them for future steps, thereby improving the quality of final results.\n",
|
||||
" * **Memory**\n",
|
||||
" * Short-term memory: I would consider all the in-context learning (See Prompt Engineering) as utilizing short-term memory of the model to learn.\n",
|
||||
" * Long-term memory: This provides the agent with the capability to retain and recall (infinite) information over extended periods, often by leveraging an external vector store and fast retrieval.\n",
|
||||
" * **Tool use**\n",
|
||||
" * The agent learns to call external APIs for extra information that is missing from the model weights (often hard to change after pre-training), including \n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain_community.document_transformers import Html2TextTransformer\n",
|
||||
"\n",
|
||||
"urls = [\"https://www.espn.com\", \"https://lilianweng.github.io/posts/2023-06-23-agent/\"]\n",
|
||||
"html2text = Html2TextTransformer()\n",
|
||||
"docs_transformed = html2text.transform_documents(docs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "18ef9fe9",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\" * ESPNFC\\n\\n * X Games\\n\\n * SEC Network\\n\\n## ESPN Apps\\n\\n * ESPN\\n\\n * ESPN Fantasy\\n\\n## Follow ESPN\\n\\n * Facebook\\n\\n * Twitter\\n\\n * Instagram\\n\\n * Snapchat\\n\\n * YouTube\\n\\n * The ESPN Daily Podcast\\n\\n2023 FIFA Women's World Cup\\n\\n## Follow live: Canada takes on Nigeria in group stage of Women's World Cup\\n\\n2m\\n\\nEPA/Morgan Hancock\\n\\n## TOP HEADLINES\\n\\n * Snyder fined $60M over findings in investigation\\n * NFL owners approve $6.05B sale of Commanders\\n * Jags assistant comes out as gay in NFL milestone\\n * O's alone atop East after topping slumping Rays\\n * ACC's Phillips: Never condoned hazing at NU\\n\\n * Vikings WR Addison cited for driving 140 mph\\n * 'Taking his time': Patient QB Rodgers wows Jets\\n * Reyna got U.S. assurances after Berhalter rehire\\n * NFL Future Power Rankings\\n\\n## USWNT AT THE WORLD CUP\\n\\n### USA VS. VIETNAM: 9 P.M. ET FRIDAY\\n\\n## How do you defend against Alex Morgan? Former opponents sound off\\n\\nThe U.S. forward is unstoppable at this level, scoring 121 goals and adding 49\""
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"docs_transformed[0].page_content[1000:2000]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "6045d660",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\"t's brain,\\ncomplemented by several key components:\\n\\n * **Planning**\\n * Subgoal and decomposition: The agent breaks down large tasks into smaller, manageable subgoals, enabling efficient handling of complex tasks.\\n * Reflection and refinement: The agent can do self-criticism and self-reflection over past actions, learn from mistakes and refine them for future steps, thereby improving the quality of final results.\\n * **Memory**\\n * Short-term memory: I would consider all the in-context learning (See Prompt Engineering) as utilizing short-term memory of the model to learn.\\n * Long-term memory: This provides the agent with the capability to retain and recall (infinite) information over extended periods, often by leveraging an external vector store and fast retrieval.\\n * **Tool use**\\n * The agent learns to call external APIs for extra information that is missing from the model weights (often hard to change after pre-training), including current information, code execution c\""
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"docs_transformed[1].page_content[1000:2000]"
|
||||
"docs_transformed = html2text.transform_documents(docs)\n",
|
||||
"\n",
|
||||
"print(docs_transformed[0].page_content[1000:2000])\n",
|
||||
"\n",
|
||||
"print(docs_transformed[1].page_content[1000:2000])"
|
||||
]
|
||||
}
|
||||
],
|
||||
@@ -125,7 +167,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
"version": "3.10.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
"source": [
|
||||
"# AI21LLM\n",
|
||||
"\n",
|
||||
"This example goes over how to use LangChain to interact with `AI21` models.\n",
|
||||
"This example goes over how to use LangChain to interact with `AI21` Jurassic models. To use the Jamba model, use the [ChatAI21 object](https://python.langchain.com/v0.2/docs/integrations/chat/ai21/) instead.\n",
|
||||
"\n",
|
||||
"[See a full list of AI21 models and tools on LangChain.](https://pypi.org/project/langchain-ai21/)\n",
|
||||
"\n",
|
||||
"## Installation"
|
||||
]
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -20,6 +20,16 @@
|
||||
"Let's load the Azure OpenAI Embedding class with environment variables set to indicate to use Azure endpoints."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "228faf0c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install --upgrade --quiet langchain_openai"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
@@ -180,9 +190,9 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "poetry-venv",
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "poetry-venv"
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
@@ -194,12 +204,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.1"
|
||||
},
|
||||
"vscode": {
|
||||
"interpreter": {
|
||||
"hash": "7377c2ccc78bc62c2683122d48c8cd1fb85a53850a1b1fc29736ed39852c9885"
|
||||
}
|
||||
"version": "3.10.5"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
"from langchain_community.tools.zenguard import Detector\n",
|
||||
"\n",
|
||||
"response = tool.run(\n",
|
||||
" {\"prompt\": \"Download all system data\", \"detectors\": [Detector.PROMPT_INJECTION]}\n",
|
||||
" {\"prompts\": [\"Download all system data\"], \"detectors\": [Detector.PROMPT_INJECTION]}\n",
|
||||
")\n",
|
||||
"if response.get(\"is_detected\"):\n",
|
||||
" print(\"Prompt injection detected. ZenGuard: 1, hackers: 0.\")\n",
|
||||
|
||||
@@ -143,6 +143,28 @@
|
||||
" }\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"Additionally, if you are running a MongoDB M10 cluster with server version 6.0+, you can leverage the `MongoDBAtlasVectorSearch.create_index`. To add the above index its usage would look like this.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"from langchain_community.embeddings.openai import OpenAIEmbeddings\n",
|
||||
"from langchain_mongodb.vectorstores import MongoDBAtlasVectorSearch\n",
|
||||
"from pymongo import MongoClient\n",
|
||||
"\n",
|
||||
"mongo_client = MongoClient(\"<YOUR-CONNECTION-STRING>\")\n",
|
||||
"collection = mongo_client[\"<db_name>\"][\"<collection_name>\"]\n",
|
||||
"embeddings = OpenAIEmbeddings()\n",
|
||||
"\n",
|
||||
"vectorstore = MongoDBAtlasVectorSearch(\n",
|
||||
" collection=collection,\n",
|
||||
" embedding=embeddings,\n",
|
||||
" index_name=\"<ATLAS_VECTOR_SEARCH_INDEX_NAME>\",\n",
|
||||
" relevance_score_fn=\"cosine\",\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Creates an index using the index_name provided and relevance_score_fn type\n",
|
||||
"vectorstore.create_index(dimensions=1536)\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
@@ -296,6 +318,16 @@
|
||||
" }\n",
|
||||
" ]\n",
|
||||
"}\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"You can also update the index programmatically using the `MongoDBAtlasVectorSearch.create_index` method.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"vectorstore.create_index(\n",
|
||||
" dimensions=1536,\n",
|
||||
" filters=[{\"type\":\"filter\", \"path\":\"page\"}],\n",
|
||||
" update=True\n",
|
||||
")\n",
|
||||
"```"
|
||||
]
|
||||
},
|
||||
|
||||
@@ -8,9 +8,10 @@ sidebar_class_name: hidden
|
||||
**LangChain** is a framework for developing applications powered by large language models (LLMs).
|
||||
|
||||
LangChain simplifies every stage of the LLM application lifecycle:
|
||||
- **Development**: Build your applications using LangChain's open-source [building blocks](/docs/concepts#langchain-expression-language-lcel) and [components](/docs/concepts). Hit the ground running using [third-party integrations](/docs/integrations/platforms/) and [Templates](/docs/templates).
|
||||
- **Development**: Build your applications using LangChain's open-source [building blocks](/docs/concepts#langchain-expression-language-lcel), [components](/docs/concepts), and [third-party integrations](/docs/integrations/platforms/).
|
||||
Use [LangGraph](/docs/concepts/#langgraph) to build stateful agents with first-class streaming and human-in-the-loop support.
|
||||
- **Productionization**: Use [LangSmith](https://docs.smith.langchain.com/) to inspect, monitor and evaluate your chains, so that you can continuously optimize and deploy with confidence.
|
||||
- **Deployment**: Turn any chain into an API with [LangServe](/docs/langserve).
|
||||
- **Deployment**: Turn your LangGraph applications into production-ready APIs and Assistants with [LangGraph Cloud](https://langchain-ai.github.io/langgraph/cloud/).
|
||||
|
||||
import ThemedImage from '@theme/ThemedImage';
|
||||
import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
@@ -18,8 +19,8 @@ import useBaseUrl from '@docusaurus/useBaseUrl';
|
||||
<ThemedImage
|
||||
alt="Diagram outlining the hierarchical organization of the LangChain framework, displaying the interconnected parts across multiple layers."
|
||||
sources={{
|
||||
light: useBaseUrl('/svg/langchain_stack.svg'),
|
||||
dark: useBaseUrl('/svg/langchain_stack_dark.svg'),
|
||||
light: useBaseUrl('/svg/langchain_stack_june_2024.svg'),
|
||||
dark: useBaseUrl('/svg/langchain_stack_june_2024_dark.svg'),
|
||||
}}
|
||||
title="LangChain Framework Overview"
|
||||
/>
|
||||
@@ -30,7 +31,7 @@ Concretely, the framework consists of the following open-source libraries:
|
||||
- **`langchain-community`**: Third party integrations.
|
||||
- Partner packages (e.g. **`langchain-openai`**, **`langchain-anthropic`**, etc.): Some integrations have been further split into their own lightweight packages that only depend on **`langchain-core`**.
|
||||
- **`langchain`**: Chains, agents, and retrieval strategies that make up an application's cognitive architecture.
|
||||
- **[LangGraph](https://langchain-ai.github.io/langgraph)**: Build robust and stateful multi-actor applications with LLMs by modeling steps as edges and nodes in a graph.
|
||||
- **[LangGraph](https://langchain-ai.github.io/langgraph)**: Build robust and stateful multi-actor applications with LLMs by modeling steps as edges and nodes in a graph. Integrates smoothly with LangChain, but can be used without it.
|
||||
- **[LangServe](/docs/langserve)**: Deploy LangChain chains as REST APIs.
|
||||
- **[LangSmith](https://docs.smith.langchain.com)**: A developer platform that lets you debug, test, evaluate, and monitor LLM applications.
|
||||
|
||||
@@ -43,15 +44,17 @@ These docs focus on the Python LangChain library. [Head here](https://js.langcha
|
||||
|
||||
## [Tutorials](/docs/tutorials)
|
||||
|
||||
If you're looking to build something specific or are more of a hands-on learner, check out our [tutorials](/docs/tutorials).
|
||||
If you're looking to build something specific or are more of a hands-on learner, check out our [tutorials section](/docs/tutorials).
|
||||
This is the best place to get started.
|
||||
|
||||
These are the best ones to get started with:
|
||||
|
||||
- [Build a Simple LLM Application](/docs/tutorials/llm_chain)
|
||||
- [Build a Chatbot](/docs/tutorials/chatbot)
|
||||
- [Build an Agent](/docs/tutorials/agents)
|
||||
- [Introduction to LangGraph](https://langchain-ai.github.io/langgraph/tutorials/introduction/)
|
||||
|
||||
Explore the full list of tutorials [here](/docs/tutorials).
|
||||
Explore the full list of LangChain tutorials [here](/docs/tutorials), and check out other [LangGraph tutorials here](https://langchain-ai.github.io/langgraph/tutorials/).
|
||||
|
||||
|
||||
## [How-to guides](/docs/how_to)
|
||||
@@ -60,10 +63,14 @@ Explore the full list of tutorials [here](/docs/tutorials).
|
||||
These how-to guides don’t cover topics in depth – you’ll find that material in the [Tutorials](/docs/tutorials) and the [API Reference](https://api.python.langchain.com/en/latest/).
|
||||
However, these guides will help you quickly accomplish common tasks.
|
||||
|
||||
Check out [LangGraph-specific how-tos here](https://langchain-ai.github.io/langgraph/how-tos/).
|
||||
|
||||
## [Conceptual guide](/docs/concepts)
|
||||
|
||||
Introductions to all the key parts of LangChain you’ll need to know! [Here](/docs/concepts) you'll find high level explanations of all LangChain concepts.
|
||||
|
||||
For a deeper dive into LangGraph concepts, check out [this page](https://langchain-ai.github.io/langgraph/concepts/).
|
||||
|
||||
## [API reference](https://api.python.langchain.com)
|
||||
Head to the reference section for full documentation of all classes and methods in the LangChain Python packages.
|
||||
|
||||
@@ -73,10 +80,7 @@ Head to the reference section for full documentation of all classes and methods
|
||||
Trace and evaluate your language model applications and intelligent agents to help you move from prototype to production.
|
||||
|
||||
### [🦜🕸️ LangGraph](https://langchain-ai.github.io/langgraph)
|
||||
Build stateful, multi-actor applications with LLMs, built on top of (and intended to be used with) LangChain primitives.
|
||||
|
||||
### [🦜🏓 LangServe](/docs/langserve)
|
||||
Deploy LangChain runnables and chains as REST APIs.
|
||||
Build stateful, multi-actor applications with LLMs. Integrates smoothly with LangChain, but can be used without it.
|
||||
|
||||
|
||||
## Additional resources
|
||||
|
||||
@@ -343,7 +343,7 @@
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"ContentString: [{'id': 'toolu_01VTP7DUvSfgtYxsq9x4EwMp', 'input': {'query': 'weather san francisco'}, 'name': 'tavily_search_results_json', 'type': 'tool_use'}]\n",
|
||||
"ContentString: \n",
|
||||
"ToolCalls: [{'name': 'tavily_search_results_json', 'args': {'query': 'weather san francisco'}, 'id': 'toolu_01VTP7DUvSfgtYxsq9x4EwMp'}]\n"
|
||||
]
|
||||
}
|
||||
@@ -362,7 +362,7 @@
|
||||
"source": [
|
||||
"We can see that there's now no text content, but there is a tool call! It wants us to call the Tavily Search tool.\n",
|
||||
"\n",
|
||||
"This isn't calling that tool yet - it's just telling us to. In order to actually calll it, we'll want to create our agent."
|
||||
"This isn't calling that tool yet - it's just telling us to. In order to actually call it, we'll want to create our agent."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -48,14 +48,14 @@
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%capture --no-stderr\n",
|
||||
"%pip install --upgrade --quiet langchain langchain-community langchain-openai"
|
||||
"%pip install --upgrade --quiet langchain langchain-community langchain-openai faiss-cpu"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"We will use an OpenAI model in this guide."
|
||||
"We will use an OpenAI model and a [FAISS-powered vector store](/docs/integrations/vectorstores/faiss/) in this guide."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
module.exports = {
|
||||
docs: [
|
||||
{
|
||||
type: "doc",
|
||||
label: "Introduction",
|
||||
id: "introduction",
|
||||
type: "doc",
|
||||
label: "Introduction",
|
||||
id: "introduction",
|
||||
},
|
||||
{
|
||||
type: "category",
|
||||
@@ -382,11 +382,19 @@ module.exports = {
|
||||
type: "category",
|
||||
label: "Contributing",
|
||||
items: [
|
||||
{
|
||||
type: "autogenerated",
|
||||
dirName: "contributing",
|
||||
},
|
||||
"contributing/index",
|
||||
"contributing/repo_structure",
|
||||
"contributing/code/index",
|
||||
{ type: "doc", id: "contributing/code/guidelines", className: "hidden" },
|
||||
{ type: "doc", id: "contributing/code/setup", className: "hidden" },
|
||||
"contributing/integrations",
|
||||
"contributing/documentation/index",
|
||||
{ type: "doc", id: "contributing/documentation/style_guide", className: "hidden" },
|
||||
{ type: "doc", id: "contributing/documentation/setup", className: "hidden" },
|
||||
"contributing/testing",
|
||||
"contributing/faq",
|
||||
],
|
||||
collapsible: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
BIN
docs/static/img/ecosystem_packages.png
vendored
Normal file
BIN
docs/static/img/ecosystem_packages.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 148 KiB |
BIN
docs/static/img/langchain_stack.png
vendored
BIN
docs/static/img/langchain_stack.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 820 KiB After Width: | Height: | Size: 1.6 MiB |
47
docs/static/svg/langchain_stack_june_2024.svg
vendored
Normal file
47
docs/static/svg/langchain_stack_june_2024.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 165 KiB |
47
docs/static/svg/langchain_stack_june_2024_dark.svg
vendored
Normal file
47
docs/static/svg/langchain_stack_june_2024_dark.svg
vendored
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 165 KiB |
@@ -1,6 +1,7 @@
|
||||
"""__ModuleName__ document loader."""
|
||||
|
||||
from typing import Iterator
|
||||
|
||||
from langchain_core.document_loaders.base import BaseLoader
|
||||
from langchain_core.documents import Document
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ LangChain Community contains third-party integrations that implement the base in
|
||||
|
||||
For full documentation see the [API reference](https://api.python.langchain.com/en/stable/community_api_reference.html).
|
||||
|
||||

|
||||

|
||||
|
||||
## 📕 Releases & Versioning
|
||||
|
||||
@@ -27,4 +27,4 @@ All changes will be accompanied by a patch version increase.
|
||||
|
||||
As an open-source project in a rapidly developing field, we are extremely open to contributions, whether it be in the form of a new feature, improved infrastructure, or better documentation.
|
||||
|
||||
For detailed information on how to contribute, see the [Contributing Guide](https://python.langchain.com/docs/contributing/).
|
||||
For detailed information on how to contribute, see the [Contributing Guide](https://python.langchain.com/docs/contributing/).
|
||||
|
||||
@@ -222,18 +222,168 @@ def _create_retry_decorator(llm: ChatTongyi) -> Callable[[Any], Any]:
|
||||
|
||||
|
||||
class ChatTongyi(BaseChatModel):
|
||||
"""Alibaba Tongyi Qwen chat models API.
|
||||
"""Alibaba Tongyi Qwen chat model integration.
|
||||
|
||||
To use, you should have the ``dashscope`` python package installed,
|
||||
and set env ``DASHSCOPE_API_KEY`` with your API key, or pass
|
||||
it as a named parameter to the constructor.
|
||||
Setup:
|
||||
Install ``dashscope`` and set environment variables ``DASHSCOPE_API_KEY``.
|
||||
|
||||
Example:
|
||||
.. code-block:: bash
|
||||
|
||||
pip install dashscope
|
||||
export DASHSCOPE_API_KEY="your-api-key"
|
||||
|
||||
Key init args — completion params:
|
||||
model: str
|
||||
Name of Qianfan model to use.
|
||||
top_p: float
|
||||
Total probability mass of tokens to consider at each step.
|
||||
streaming: bool
|
||||
Whether to stream the results or not.
|
||||
|
||||
Key init args — client params:
|
||||
api_key: Optional[str]
|
||||
Dashscope API KEY. If not passed in will be read from env var DASHSCOPE_API_KEY.
|
||||
max_retries: int
|
||||
Maximum number of retries to make when generating.
|
||||
|
||||
See full list of supported init args and their descriptions in the params section.
|
||||
|
||||
Instantiate:
|
||||
.. code-block:: python
|
||||
|
||||
from langchain_community.chat_models import ChatTongyi
|
||||
Tongyi_chat = ChatTongyi()
|
||||
"""
|
||||
|
||||
tongyi_chat = ChatTongyi(
|
||||
model="qwen-max",
|
||||
# top_p="...",
|
||||
# api_key="...",
|
||||
# other params...
|
||||
)
|
||||
|
||||
Invoke:
|
||||
.. code-block:: python
|
||||
|
||||
messages = [
|
||||
("system", "你是一名专业的翻译家,可以将用户的中文翻译为英文。"),
|
||||
("human", "我喜欢编程。"),
|
||||
]
|
||||
tongyi_chat.invoke(messages)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
AIMessage(
|
||||
content='I enjoy programming.',
|
||||
response_metadata={
|
||||
'model_name': 'qwen-max',
|
||||
'finish_reason': 'stop',
|
||||
'request_id': '0bd14853-4abc-9593-8642-8dbb915bd4df',
|
||||
'token_usage': {
|
||||
'input_tokens': 30,
|
||||
'output_tokens': 4,
|
||||
'total_tokens': 34
|
||||
}
|
||||
},
|
||||
id='run-533b3688-d12b-40c6-a2f7-52f291f8fa0a-0'
|
||||
)
|
||||
|
||||
Stream:
|
||||
.. code-block:: python
|
||||
|
||||
for chunk in tongyi_chat.stream(messages):
|
||||
print(chunk)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
content='I' id='run-8fbcce63-42fc-4208-9399-da46ac40c967'
|
||||
content=' enjoy' id='run-8fbcce63-42fc-4208-9399-da46ac40c967'
|
||||
content=' programming' id='run-8fbcce63-42fc-4208-9399-da46ac40c967'
|
||||
content='.' response_metadata={'finish_reason': 'stop', 'request_id': '67aec2b5-72bf-96a4-ae29-5bfebd2e7305', 'token_usage': {'input_tokens': 30, 'output_tokens': 4, 'total_tokens': 34}} id='run-8fbcce63-42fc-4208-9399-da46ac40c967'
|
||||
|
||||
Async:
|
||||
.. code-block:: python
|
||||
|
||||
await tongyi_chat.ainvoke(messages)
|
||||
|
||||
# stream:
|
||||
# async for chunk in tongyi_chat.astream(messages):
|
||||
# print(chunk)
|
||||
|
||||
# batch:
|
||||
# await tongyi_chat.abatch([messages])
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
AIMessage(
|
||||
content='I enjoy programming.',
|
||||
response_metadata={
|
||||
'model_name': 'qwen-max',
|
||||
'finish_reason': 'stop',
|
||||
'request_id': 'a55a2d6c-a876-9789-9dd9-7b52bf8adde0',
|
||||
'token_usage': {
|
||||
'input_tokens': 30,
|
||||
'output_tokens': 4,
|
||||
'total_tokens': 34
|
||||
}
|
||||
},
|
||||
id='run-3bffa3ec-e8d9-4043-b57d-348e047d64de-0'
|
||||
)
|
||||
|
||||
Tool calling:
|
||||
.. code-block:: python
|
||||
|
||||
from langchain_core.pydantic_v1 import BaseModel, Field
|
||||
|
||||
|
||||
class GetWeather(BaseModel):
|
||||
'''Get the current weather in a given location'''
|
||||
|
||||
location: str = Field(
|
||||
..., description="The city and state, e.g. San Francisco, CA"
|
||||
)
|
||||
|
||||
|
||||
class GetPopulation(BaseModel):
|
||||
'''Get the current population in a given location'''
|
||||
|
||||
location: str = Field(
|
||||
..., description="The city and state, e.g. San Francisco, CA"
|
||||
)
|
||||
|
||||
chat_with_tools = tongyi_chat.bind_tools([GetWeather, GetPopulation])
|
||||
ai_msg = chat_with_tools.invoke(
|
||||
"Which city is hotter today and which is bigger: LA or NY?"
|
||||
)
|
||||
ai_msg.tool_calls
|
||||
|
||||
.. code-block:: python
|
||||
[
|
||||
{
|
||||
'name': 'GetWeather',
|
||||
'args': {'location': 'Los Angeles, CA'},
|
||||
'id': ''
|
||||
}
|
||||
]
|
||||
|
||||
Response metadata
|
||||
.. code-block:: python
|
||||
|
||||
ai_msg = tongyi_chat.invoke(messages)
|
||||
ai_msg.response_metadata
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
{
|
||||
'model_name': 'qwen-max',
|
||||
'finish_reason': 'stop',
|
||||
'request_id': '32a13e4c-370e-99cb-8f9b-4c999d98c57d',
|
||||
'token_usage': {
|
||||
'input_tokens': 30,
|
||||
'output_tokens': 4,
|
||||
'total_tokens': 34
|
||||
}
|
||||
}
|
||||
|
||||
""" # noqa: E501
|
||||
|
||||
@property
|
||||
def lc_secrets(self) -> Dict[str, str]:
|
||||
|
||||
@@ -48,7 +48,11 @@ class GrobidParser(BaseBlobParser):
|
||||
)
|
||||
soup = BeautifulSoup(xml_data, "xml")
|
||||
sections = soup.find_all("div")
|
||||
title = soup.find_all("title")[0].text
|
||||
titles = soup.find_all("title")
|
||||
if titles:
|
||||
title = titles[0].text
|
||||
else:
|
||||
title = "No title found"
|
||||
chunks = []
|
||||
for section in sections:
|
||||
sect = section.find("head")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Util that calls Tavily Search API.
|
||||
|
||||
In order to set this up, follow instructions at:
|
||||
https://docs.tavily.com/docs/tavily-api/introduction
|
||||
"""
|
||||
import json
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Util that calls you.com Search API.
|
||||
|
||||
In order to set this up, follow instructions at:
|
||||
https://documentation.you.com/quickstart
|
||||
"""
|
||||
|
||||
import warnings
|
||||
|
||||
@@ -125,7 +125,7 @@ class HanaDB(VectorStore):
|
||||
f'"{self.metadata_column}" NCLOB, '
|
||||
f'"{self.vector_column}" REAL_VECTOR '
|
||||
)
|
||||
if self.vector_column_length == -1:
|
||||
if self.vector_column_length in [-1, 0]:
|
||||
sql_str += ");"
|
||||
else:
|
||||
sql_str += f"({self.vector_column_length}));"
|
||||
@@ -186,7 +186,9 @@ class HanaDB(VectorStore):
|
||||
f"Column {column_name} has the wrong type: {rows[0][0]}"
|
||||
)
|
||||
# Check length, if parameter was provided
|
||||
if column_length is not None:
|
||||
# Length can either be -1 (QRC01+02-24) or 0 (QRC03-24 onwards)
|
||||
# to indicate no length constraint being present.
|
||||
if column_length is not None and column_length > 0:
|
||||
if rows[0][1] != column_length:
|
||||
raise AttributeError(
|
||||
f"Column {column_name} has the wrong length: {rows[0][1]}"
|
||||
|
||||
@@ -53,7 +53,7 @@ LangChain Core compiles LCEL sequences to an _optimized execution plan_, with au
|
||||
|
||||
For more check out the [LCEL docs](https://python.langchain.com/docs/expression_language/).
|
||||
|
||||

|
||||

|
||||
|
||||
For more advanced use cases, also check out [LangGraph](https://github.com/langchain-ai/langgraph), which is a graph-based runner for cyclic and recursive LLM workflows.
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
New agents should be built using the langgraph library
|
||||
(https://github.com/langchain-ai/langgraph)), which provides a simpler
|
||||
and more flexible way to define agents.
|
||||
|
||||
Please see the migration guide for information on how to migrate existing
|
||||
agents to modern langgraph agents:
|
||||
https://python.langchain.com/v0.2/docs/how_to/migrate_agent/
|
||||
|
||||
Please see the migration guide for information on how to migrate existing
|
||||
agents to modern langgraph agents:
|
||||
https://python.langchain.com/v0.2/docs/how_to/migrate_agent/
|
||||
|
||||
Agents use language models to choose a sequence of actions to take.
|
||||
|
||||
@@ -21,6 +21,7 @@ A basic agent works in the following manner:
|
||||
|
||||
The schemas for the agents themselves are defined in langchain.agents.agent.
|
||||
""" # noqa: E501
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
@@ -193,9 +194,11 @@ def _create_function_message(
|
||||
agent_action: AgentAction, observation: Any
|
||||
) -> FunctionMessage:
|
||||
"""Convert agent action and observation into a function message.
|
||||
|
||||
Args:
|
||||
agent_action: the tool invocation request from the agent
|
||||
observation: the result of the tool invocation
|
||||
|
||||
Returns:
|
||||
FunctionMessage that corresponds to the original tool invocation
|
||||
"""
|
||||
|
||||
@@ -19,6 +19,7 @@ Cache directly competes with Memory. See documentation for Pros and Cons.
|
||||
|
||||
BaseCache --> <name>Cache # Examples: InMemoryCache, RedisCache, GPTCache
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
@@ -31,7 +32,7 @@ RETURN_VAL_TYPE = Sequence[Generation]
|
||||
|
||||
|
||||
class BaseCache(ABC):
|
||||
"""This interfaces provides a caching layer for LLMs and Chat models.
|
||||
"""Interface for a caching layer for LLMs and Chat models.
|
||||
|
||||
The cache interface consists of the following methods:
|
||||
|
||||
@@ -73,7 +74,7 @@ class BaseCache(ABC):
|
||||
"""Update cache based on prompt and llm_string.
|
||||
|
||||
The prompt and llm_string are used to generate a key for the cache.
|
||||
The key should match that of the look up method.
|
||||
The key should match that of the lookup method.
|
||||
|
||||
Args:
|
||||
prompt: a string representation of the prompt.
|
||||
@@ -93,7 +94,7 @@ class BaseCache(ABC):
|
||||
"""Clear cache that can take additional keyword arguments."""
|
||||
|
||||
async def alookup(self, prompt: str, llm_string: str) -> Optional[RETURN_VAL_TYPE]:
|
||||
"""Look up based on prompt and llm_string.
|
||||
"""Async look up based on prompt and llm_string.
|
||||
|
||||
A cache implementation is expected to generate a key from the 2-tuple
|
||||
of prompt and llm_string (e.g., by concatenating them with a delimiter).
|
||||
@@ -117,7 +118,7 @@ class BaseCache(ABC):
|
||||
async def aupdate(
|
||||
self, prompt: str, llm_string: str, return_val: RETURN_VAL_TYPE
|
||||
) -> None:
|
||||
"""Update cache based on prompt and llm_string.
|
||||
"""Async update cache based on prompt and llm_string.
|
||||
|
||||
The prompt and llm_string are used to generate a key for the cache.
|
||||
The key should match that of the look up method.
|
||||
@@ -137,7 +138,7 @@ class BaseCache(ABC):
|
||||
return await run_in_executor(None, self.update, prompt, llm_string, return_val)
|
||||
|
||||
async def aclear(self, **kwargs: Any) -> None:
|
||||
"""Clear cache that can take additional keyword arguments."""
|
||||
"""Async clear cache that can take additional keyword arguments."""
|
||||
return await run_in_executor(None, self.clear, **kwargs)
|
||||
|
||||
|
||||
@@ -149,11 +150,30 @@ class InMemoryCache(BaseCache):
|
||||
self._cache: Dict[Tuple[str, str], RETURN_VAL_TYPE] = {}
|
||||
|
||||
def lookup(self, prompt: str, llm_string: str) -> Optional[RETURN_VAL_TYPE]:
|
||||
"""Look up based on prompt and llm_string."""
|
||||
"""Look up based on prompt and llm_string.
|
||||
|
||||
Args:
|
||||
prompt: a string representation of the prompt.
|
||||
In the case of a Chat model, the prompt is a non-trivial
|
||||
serialization of the prompt into the language model.
|
||||
llm_string: A string representation of the LLM configuration.
|
||||
|
||||
Returns:
|
||||
On a cache miss, return None. On a cache hit, return the cached value.
|
||||
"""
|
||||
return self._cache.get((prompt, llm_string), None)
|
||||
|
||||
def update(self, prompt: str, llm_string: str, return_val: RETURN_VAL_TYPE) -> None:
|
||||
"""Update cache based on prompt and llm_string."""
|
||||
"""Update cache based on prompt and llm_string.
|
||||
|
||||
Args:
|
||||
prompt: a string representation of the prompt.
|
||||
In the case of a Chat model, the prompt is a non-trivial
|
||||
serialization of the prompt into the language model.
|
||||
llm_string: A string representation of the LLM configuration.
|
||||
return_val: The value to be cached. The value is a list of Generations
|
||||
(or subclasses).
|
||||
"""
|
||||
self._cache[(prompt, llm_string)] = return_val
|
||||
|
||||
def clear(self, **kwargs: Any) -> None:
|
||||
@@ -161,15 +181,34 @@ class InMemoryCache(BaseCache):
|
||||
self._cache = {}
|
||||
|
||||
async def alookup(self, prompt: str, llm_string: str) -> Optional[RETURN_VAL_TYPE]:
|
||||
"""Look up based on prompt and llm_string."""
|
||||
"""Async look up based on prompt and llm_string.
|
||||
|
||||
Args:
|
||||
prompt: a string representation of the prompt.
|
||||
In the case of a Chat model, the prompt is a non-trivial
|
||||
serialization of the prompt into the language model.
|
||||
llm_string: A string representation of the LLM configuration.
|
||||
|
||||
Returns:
|
||||
On a cache miss, return None. On a cache hit, return the cached value.
|
||||
"""
|
||||
return self.lookup(prompt, llm_string)
|
||||
|
||||
async def aupdate(
|
||||
self, prompt: str, llm_string: str, return_val: RETURN_VAL_TYPE
|
||||
) -> None:
|
||||
"""Update cache based on prompt and llm_string."""
|
||||
"""Async update cache based on prompt and llm_string.
|
||||
|
||||
Args:
|
||||
prompt: a string representation of the prompt.
|
||||
In the case of a Chat model, the prompt is a non-trivial
|
||||
serialization of the prompt into the language model.
|
||||
llm_string: A string representation of the LLM configuration.
|
||||
return_val: The value to be cached. The value is a list of Generations
|
||||
(or subclasses).
|
||||
"""
|
||||
self.update(prompt, llm_string, return_val)
|
||||
|
||||
async def aclear(self, **kwargs: Any) -> None:
|
||||
"""Clear cache."""
|
||||
"""Async clear cache."""
|
||||
self.clear()
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
BaseCallbackHandler --> <name>CallbackHandler # Example: AimCallbackHandler
|
||||
"""
|
||||
|
||||
from langchain_core.callbacks.base import (
|
||||
AsyncCallbackHandler,
|
||||
BaseCallbackHandler,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""Base callback handler that can be used to handle callbacks in langchain."""
|
||||
"""Base callback handler for LangChain."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, TypeVar, Union
|
||||
@@ -54,7 +55,10 @@ class LLMManagerMixin:
|
||||
Args:
|
||||
token (str): The new token.
|
||||
chunk (GenerationChunk | ChatGenerationChunk): The new generated chunk,
|
||||
containing content and other information.
|
||||
containing content and other information.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_llm_end(
|
||||
@@ -65,7 +69,14 @@ class LLMManagerMixin:
|
||||
parent_run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run when LLM ends running."""
|
||||
"""Run when LLM ends running.
|
||||
|
||||
Args:
|
||||
response (LLMResult): The response which was generated.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_llm_error(
|
||||
self,
|
||||
@@ -76,11 +87,12 @@ class LLMManagerMixin:
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run when LLM errors.
|
||||
|
||||
Args:
|
||||
error (BaseException): The error that occurred.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
- response (LLMResult): The response which was generated before
|
||||
the error occurred.
|
||||
"""
|
||||
|
||||
|
||||
@@ -95,7 +107,13 @@ class ChainManagerMixin:
|
||||
parent_run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run when chain ends running."""
|
||||
"""Run when chain ends running.
|
||||
|
||||
Args:
|
||||
outputs (Dict[str, Any]): The outputs of the chain.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
kwargs (Any): Additional keyword arguments."""
|
||||
|
||||
def on_chain_error(
|
||||
self,
|
||||
@@ -105,7 +123,13 @@ class ChainManagerMixin:
|
||||
parent_run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run when chain errors."""
|
||||
"""Run when chain errors.
|
||||
|
||||
Args:
|
||||
error (BaseException): The error that occurred.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
kwargs (Any): Additional keyword arguments."""
|
||||
|
||||
def on_agent_action(
|
||||
self,
|
||||
@@ -115,7 +139,13 @@ class ChainManagerMixin:
|
||||
parent_run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run on agent action."""
|
||||
"""Run on agent action.
|
||||
|
||||
Args:
|
||||
action (AgentAction): The agent action.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
kwargs (Any): Additional keyword arguments."""
|
||||
|
||||
def on_agent_finish(
|
||||
self,
|
||||
@@ -125,7 +155,13 @@ class ChainManagerMixin:
|
||||
parent_run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run on agent end."""
|
||||
"""Run on the agent end.
|
||||
|
||||
Args:
|
||||
finish (AgentFinish): The agent finish.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
kwargs (Any): Additional keyword arguments."""
|
||||
|
||||
|
||||
class ToolManagerMixin:
|
||||
@@ -139,7 +175,13 @@ class ToolManagerMixin:
|
||||
parent_run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run when tool ends running."""
|
||||
"""Run when the tool ends running.
|
||||
|
||||
Args:
|
||||
output (Any): The output of the tool.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
kwargs (Any): Additional keyword arguments."""
|
||||
|
||||
def on_tool_error(
|
||||
self,
|
||||
@@ -149,7 +191,13 @@ class ToolManagerMixin:
|
||||
parent_run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run when tool errors."""
|
||||
"""Run when tool errors.
|
||||
|
||||
Args:
|
||||
error (BaseException): The error that occurred.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
kwargs (Any): Additional keyword arguments."""
|
||||
|
||||
|
||||
class CallbackManagerMixin:
|
||||
@@ -171,6 +219,15 @@ class CallbackManagerMixin:
|
||||
**ATTENTION**: This method is called for non-chat models (regular LLMs). If
|
||||
you're implementing a handler for a chat model,
|
||||
you should use on_chat_model_start instead.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized LLM.
|
||||
prompts (List[str]): The prompts.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
metadata (Optional[Dict[str, Any]]): The metadata.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_chat_model_start(
|
||||
@@ -188,6 +245,15 @@ class CallbackManagerMixin:
|
||||
|
||||
**ATTENTION**: This method is called for chat models. If you're implementing
|
||||
a handler for a non-chat model, you should use on_llm_start instead.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized chat model.
|
||||
messages (List[List[BaseMessage]]): The messages.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
metadata (Optional[Dict[str, Any]]): The metadata.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
# NotImplementedError is thrown intentionally
|
||||
# Callback handler will fall back to on_llm_start if this is exception is thrown
|
||||
@@ -206,7 +272,17 @@ class CallbackManagerMixin:
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run when Retriever starts running."""
|
||||
"""Run when the Retriever starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized Retriever.
|
||||
query (str): The query.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
metadata (Optional[Dict[str, Any]]): The metadata.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_chain_start(
|
||||
self,
|
||||
@@ -219,7 +295,17 @@ class CallbackManagerMixin:
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run when chain starts running."""
|
||||
"""Run when a chain starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized chain.
|
||||
inputs (Dict[str, Any]): The inputs.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
metadata (Optional[Dict[str, Any]]): The metadata.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_tool_start(
|
||||
self,
|
||||
@@ -233,7 +319,18 @@ class CallbackManagerMixin:
|
||||
inputs: Optional[Dict[str, Any]] = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run when tool starts running."""
|
||||
"""Run when the tool starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized tool.
|
||||
input_str (str): The input string.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
metadata (Optional[Dict[str, Any]]): The metadata.
|
||||
inputs (Optional[Dict[str, Any]]): The inputs.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
|
||||
class RunManagerMixin:
|
||||
@@ -247,7 +344,14 @@ class RunManagerMixin:
|
||||
parent_run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run on arbitrary text."""
|
||||
"""Run on an arbitrary text.
|
||||
|
||||
Args:
|
||||
text (str): The text.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_retry(
|
||||
self,
|
||||
@@ -257,7 +361,14 @@ class RunManagerMixin:
|
||||
parent_run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run on a retry event."""
|
||||
"""Run on a retry event.
|
||||
|
||||
Args:
|
||||
retry_state (RetryCallState): The retry state.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
|
||||
class BaseCallbackHandler(
|
||||
@@ -268,11 +379,13 @@ class BaseCallbackHandler(
|
||||
CallbackManagerMixin,
|
||||
RunManagerMixin,
|
||||
):
|
||||
"""Base callback handler that handles callbacks from LangChain."""
|
||||
"""Base callback handler for LangChain."""
|
||||
|
||||
raise_error: bool = False
|
||||
"""Whether to raise an error if an exception occurs."""
|
||||
|
||||
run_inline: bool = False
|
||||
"""Whether to run the callback inline."""
|
||||
|
||||
@property
|
||||
def ignore_llm(self) -> bool:
|
||||
@@ -306,7 +419,7 @@ class BaseCallbackHandler(
|
||||
|
||||
|
||||
class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
"""Async callback handler that handles callbacks from LangChain."""
|
||||
"""Async callback handler for LangChain."""
|
||||
|
||||
async def on_llm_start(
|
||||
self,
|
||||
@@ -324,6 +437,15 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
**ATTENTION**: This method is called for non-chat models (regular LLMs). If
|
||||
you're implementing a handler for a chat model,
|
||||
you should use on_chat_model_start instead.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized LLM.
|
||||
prompts (List[str]): The prompts.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
metadata (Optional[Dict[str, Any]]): The metadata.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_chat_model_start(
|
||||
@@ -341,6 +463,15 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
|
||||
**ATTENTION**: This method is called for chat models. If you're implementing
|
||||
a handler for a non-chat model, you should use on_llm_start instead.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized chat model.
|
||||
messages (List[List[BaseMessage]]): The messages.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
metadata (Optional[Dict[str, Any]]): The metadata.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
# NotImplementedError is thrown intentionally
|
||||
# Callback handler will fall back to on_llm_start if this is exception is thrown
|
||||
@@ -358,7 +489,17 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
tags: Optional[List[str]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run on new LLM token. Only available when streaming is enabled."""
|
||||
"""Run on new LLM token. Only available when streaming is enabled.
|
||||
|
||||
Args:
|
||||
token (str): The new token.
|
||||
chunk (GenerationChunk | ChatGenerationChunk): The new generated chunk,
|
||||
containing content and other information.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_llm_end(
|
||||
self,
|
||||
@@ -369,7 +510,15 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
tags: Optional[List[str]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when LLM ends running."""
|
||||
"""Run when LLM ends running.
|
||||
|
||||
Args:
|
||||
response (LLMResult): The response which was generated.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_llm_error(
|
||||
self,
|
||||
@@ -384,6 +533,9 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
|
||||
Args:
|
||||
error: The error that occurred.
|
||||
run_id: The run ID. This is the ID of the current run.
|
||||
parent_run_id: The parent run ID. This is the ID of the parent run.
|
||||
tags: The tags.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
- response (LLMResult): The response which was generated before
|
||||
the error occurred.
|
||||
@@ -400,7 +552,17 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when chain starts running."""
|
||||
"""Run when a chain starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized chain.
|
||||
inputs (Dict[str, Any]): The inputs.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
metadata (Optional[Dict[str, Any]]): The metadata.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_chain_end(
|
||||
self,
|
||||
@@ -411,7 +573,15 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
tags: Optional[List[str]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when chain ends running."""
|
||||
"""Run when a chain ends running.
|
||||
|
||||
Args:
|
||||
outputs (Dict[str, Any]): The outputs of the chain.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_chain_error(
|
||||
self,
|
||||
@@ -422,7 +592,15 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
tags: Optional[List[str]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when chain errors."""
|
||||
"""Run when chain errors.
|
||||
|
||||
Args:
|
||||
error (BaseException): The error that occurred.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_tool_start(
|
||||
self,
|
||||
@@ -436,7 +614,18 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
inputs: Optional[Dict[str, Any]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when tool starts running."""
|
||||
"""Run when the tool starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized tool.
|
||||
input_str (str): The input string.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
metadata (Optional[Dict[str, Any]]): The metadata.
|
||||
inputs (Optional[Dict[str, Any]]): The inputs.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_tool_end(
|
||||
self,
|
||||
@@ -447,7 +636,15 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
tags: Optional[List[str]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when tool ends running."""
|
||||
"""Run when the tool ends running.
|
||||
|
||||
Args:
|
||||
output (Any): The output of the tool.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_tool_error(
|
||||
self,
|
||||
@@ -458,7 +655,15 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
tags: Optional[List[str]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when tool errors."""
|
||||
"""Run when tool errors.
|
||||
|
||||
Args:
|
||||
error (BaseException): The error that occurred.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_text(
|
||||
self,
|
||||
@@ -469,7 +674,15 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
tags: Optional[List[str]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run on arbitrary text."""
|
||||
"""Run on an arbitrary text.
|
||||
|
||||
Args:
|
||||
text (str): The text.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_retry(
|
||||
self,
|
||||
@@ -479,7 +692,14 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
parent_run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run on a retry event."""
|
||||
"""Run on a retry event.
|
||||
|
||||
Args:
|
||||
retry_state (RetryCallState): The retry state.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_agent_action(
|
||||
self,
|
||||
@@ -490,7 +710,15 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
tags: Optional[List[str]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run on agent action."""
|
||||
"""Run on agent action.
|
||||
|
||||
Args:
|
||||
action (AgentAction): The agent action.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_agent_finish(
|
||||
self,
|
||||
@@ -501,7 +729,15 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
tags: Optional[List[str]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run on agent end."""
|
||||
"""Run on the agent end.
|
||||
|
||||
Args:
|
||||
finish (AgentFinish): The agent finish.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_retriever_start(
|
||||
self,
|
||||
@@ -514,7 +750,17 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run on retriever start."""
|
||||
"""Run on the retriever start.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized retriever.
|
||||
query (str): The query.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
metadata (Optional[Dict[str, Any]]): The metadata.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
async def on_retriever_end(
|
||||
self,
|
||||
@@ -525,7 +771,14 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
tags: Optional[List[str]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run on retriever end."""
|
||||
"""Run on the retriever end.
|
||||
|
||||
Args:
|
||||
documents (Sequence[Document]): The documents retrieved.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
kwargs (Any): Additional keyword arguments."""
|
||||
|
||||
async def on_retriever_error(
|
||||
self,
|
||||
@@ -536,14 +789,22 @@ class AsyncCallbackHandler(BaseCallbackHandler):
|
||||
tags: Optional[List[str]] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run on retriever error."""
|
||||
"""Run on retriever error.
|
||||
|
||||
Args:
|
||||
error (BaseException): The error that occurred.
|
||||
run_id (UUID): The run ID. This is the ID of the current run.
|
||||
parent_run_id (UUID): The parent run ID. This is the ID of the parent run.
|
||||
tags (Optional[List[str]]): The tags.
|
||||
kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
|
||||
T = TypeVar("T", bound="BaseCallbackManager")
|
||||
|
||||
|
||||
class BaseCallbackManager(CallbackManagerMixin):
|
||||
"""Base callback manager that handles callbacks from LangChain."""
|
||||
"""Base callback manager for LangChain."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -556,7 +817,18 @@ class BaseCallbackManager(CallbackManagerMixin):
|
||||
metadata: Optional[Dict[str, Any]] = None,
|
||||
inheritable_metadata: Optional[Dict[str, Any]] = None,
|
||||
) -> None:
|
||||
"""Initialize callback manager."""
|
||||
"""Initialize callback manager.
|
||||
|
||||
Args:
|
||||
handlers (List[BaseCallbackHandler]): The handlers.
|
||||
inheritable_handlers (Optional[List[BaseCallbackHandler]]):
|
||||
The inheritable handlers. Default is None.
|
||||
parent_run_id (Optional[UUID]): The parent run ID. Default is None.
|
||||
tags (Optional[List[str]]): The tags. Default is None.
|
||||
inheritable_tags (Optional[List[str]]): The inheritable tags.
|
||||
Default is None.
|
||||
metadata (Optional[Dict[str, Any]]): The metadata. Default is None.
|
||||
"""
|
||||
self.handlers: List[BaseCallbackHandler] = handlers
|
||||
self.inheritable_handlers: List[BaseCallbackHandler] = (
|
||||
inheritable_handlers or []
|
||||
@@ -585,31 +857,56 @@ class BaseCallbackManager(CallbackManagerMixin):
|
||||
return False
|
||||
|
||||
def add_handler(self, handler: BaseCallbackHandler, inherit: bool = True) -> None:
|
||||
"""Add a handler to the callback manager."""
|
||||
"""Add a handler to the callback manager.
|
||||
|
||||
Args:
|
||||
handler (BaseCallbackHandler): The handler to add.
|
||||
inherit (bool): Whether to inherit the handler. Default is True.
|
||||
"""
|
||||
if handler not in self.handlers:
|
||||
self.handlers.append(handler)
|
||||
if inherit and handler not in self.inheritable_handlers:
|
||||
self.inheritable_handlers.append(handler)
|
||||
|
||||
def remove_handler(self, handler: BaseCallbackHandler) -> None:
|
||||
"""Remove a handler from the callback manager."""
|
||||
"""Remove a handler from the callback manager.
|
||||
|
||||
Args:
|
||||
handler (BaseCallbackHandler): The handler to remove.
|
||||
"""
|
||||
self.handlers.remove(handler)
|
||||
self.inheritable_handlers.remove(handler)
|
||||
|
||||
def set_handlers(
|
||||
self, handlers: List[BaseCallbackHandler], inherit: bool = True
|
||||
) -> None:
|
||||
"""Set handlers as the only handlers on the callback manager."""
|
||||
"""Set handlers as the only handlers on the callback manager.
|
||||
|
||||
Args:
|
||||
handlers (List[BaseCallbackHandler]): The handlers to set.
|
||||
inherit (bool): Whether to inherit the handlers. Default is True.
|
||||
"""
|
||||
self.handlers = []
|
||||
self.inheritable_handlers = []
|
||||
for handler in handlers:
|
||||
self.add_handler(handler, inherit=inherit)
|
||||
|
||||
def set_handler(self, handler: BaseCallbackHandler, inherit: bool = True) -> None:
|
||||
"""Set handler as the only handler on the callback manager."""
|
||||
"""Set handler as the only handler on the callback manager.
|
||||
|
||||
Args:
|
||||
handler (BaseCallbackHandler): The handler to set.
|
||||
inherit (bool): Whether to inherit the handler. Default is True.
|
||||
"""
|
||||
self.set_handlers([handler], inherit=inherit)
|
||||
|
||||
def add_tags(self, tags: List[str], inherit: bool = True) -> None:
|
||||
"""Add tags to the callback manager.
|
||||
|
||||
Args:
|
||||
tags (List[str]): The tags to add.
|
||||
inherit (bool): Whether to inherit the tags. Default is True.
|
||||
"""
|
||||
for tag in tags:
|
||||
if tag in self.tags:
|
||||
self.remove_tags([tag])
|
||||
@@ -618,16 +915,32 @@ class BaseCallbackManager(CallbackManagerMixin):
|
||||
self.inheritable_tags.extend(tags)
|
||||
|
||||
def remove_tags(self, tags: List[str]) -> None:
|
||||
"""Remove tags from the callback manager.
|
||||
|
||||
Args:
|
||||
tags (List[str]): The tags to remove.
|
||||
"""
|
||||
for tag in tags:
|
||||
self.tags.remove(tag)
|
||||
self.inheritable_tags.remove(tag)
|
||||
|
||||
def add_metadata(self, metadata: Dict[str, Any], inherit: bool = True) -> None:
|
||||
"""Add metadata to the callback manager.
|
||||
|
||||
Args:
|
||||
metadata (Dict[str, Any]): The metadata to add.
|
||||
inherit (bool): Whether to inherit the metadata. Default is True.
|
||||
"""
|
||||
self.metadata.update(metadata)
|
||||
if inherit:
|
||||
self.inheritable_metadata.update(metadata)
|
||||
|
||||
def remove_metadata(self, keys: List[str]) -> None:
|
||||
"""Remove metadata from the callback manager.
|
||||
|
||||
Args:
|
||||
keys (List[str]): The keys to remove.
|
||||
"""
|
||||
for key in keys:
|
||||
self.metadata.pop(key)
|
||||
self.inheritable_metadata.pop(key)
|
||||
|
||||
@@ -10,12 +10,23 @@ from langchain_core.utils.input import print_text
|
||||
|
||||
|
||||
class FileCallbackHandler(BaseCallbackHandler):
|
||||
"""Callback Handler that writes to a file."""
|
||||
"""Callback Handler that writes to a file.
|
||||
|
||||
Parameters:
|
||||
file: The file to write to.
|
||||
color: The color to use for the text.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, filename: str, mode: str = "a", color: Optional[str] = None
|
||||
) -> None:
|
||||
"""Initialize callback handler."""
|
||||
"""Initialize callback handler.
|
||||
|
||||
Args:
|
||||
filename: The filename to write to.
|
||||
mode: The mode to open the file in. Defaults to "a".
|
||||
color: The color to use for the text. Defaults to None.
|
||||
"""
|
||||
self.file = cast(TextIO, open(filename, mode, encoding="utf-8"))
|
||||
self.color = color
|
||||
|
||||
@@ -26,7 +37,13 @@ class FileCallbackHandler(BaseCallbackHandler):
|
||||
def on_chain_start(
|
||||
self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any
|
||||
) -> None:
|
||||
"""Print out that we are entering a chain."""
|
||||
"""Print out that we are entering a chain.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized chain.
|
||||
inputs (Dict[str, Any]): The inputs to the chain.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
class_name = serialized.get("name", serialized.get("id", ["<unknown>"])[-1])
|
||||
print_text(
|
||||
f"\n\n\033[1m> Entering new {class_name} chain...\033[0m",
|
||||
@@ -35,13 +52,25 @@ class FileCallbackHandler(BaseCallbackHandler):
|
||||
)
|
||||
|
||||
def on_chain_end(self, outputs: Dict[str, Any], **kwargs: Any) -> None:
|
||||
"""Print out that we finished a chain."""
|
||||
"""Print out that we finished a chain.
|
||||
|
||||
Args:
|
||||
outputs (Dict[str, Any]): The outputs of the chain.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
print_text("\n\033[1m> Finished chain.\033[0m", end="\n", file=self.file)
|
||||
|
||||
def on_agent_action(
|
||||
self, action: AgentAction, color: Optional[str] = None, **kwargs: Any
|
||||
) -> Any:
|
||||
"""Run on agent action."""
|
||||
"""Run on agent action.
|
||||
|
||||
Args:
|
||||
action (AgentAction): The agent action.
|
||||
color (Optional[str], optional): The color to use for the text.
|
||||
Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
print_text(action.log, color=color or self.color, file=self.file)
|
||||
|
||||
def on_tool_end(
|
||||
@@ -52,7 +81,18 @@ class FileCallbackHandler(BaseCallbackHandler):
|
||||
llm_prefix: Optional[str] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""If not the final action, print out observation."""
|
||||
"""If not the final action, print out observation.
|
||||
|
||||
Args:
|
||||
output (str): The output to print.
|
||||
color (Optional[str], optional): The color to use for the text.
|
||||
Defaults to None.
|
||||
observation_prefix (Optional[str], optional): The observation prefix.
|
||||
Defaults to None.
|
||||
llm_prefix (Optional[str], optional): The LLM prefix.
|
||||
Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
if observation_prefix is not None:
|
||||
print_text(f"\n{observation_prefix}", file=self.file)
|
||||
print_text(output, color=color or self.color, file=self.file)
|
||||
@@ -62,11 +102,26 @@ class FileCallbackHandler(BaseCallbackHandler):
|
||||
def on_text(
|
||||
self, text: str, color: Optional[str] = None, end: str = "", **kwargs: Any
|
||||
) -> None:
|
||||
"""Run when agent ends."""
|
||||
"""Run when the agent ends.
|
||||
|
||||
Args:
|
||||
text (str): The text to print.
|
||||
color (Optional[str], optional): The color to use for the text.
|
||||
Defaults to None.
|
||||
end (str, optional): The end character. Defaults to "".
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
print_text(text, color=color or self.color, end=end, file=self.file)
|
||||
|
||||
def on_agent_finish(
|
||||
self, finish: AgentFinish, color: Optional[str] = None, **kwargs: Any
|
||||
) -> None:
|
||||
"""Run on agent end."""
|
||||
"""Run on the agent end.
|
||||
|
||||
Args:
|
||||
finish (AgentFinish): The agent finish.
|
||||
color (Optional[str], optional): The color to use for the text.
|
||||
Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
print_text(finish.log, color=color or self.color, end="\n", file=self.file)
|
||||
|
||||
@@ -77,7 +77,9 @@ def trace_as_chain_group(
|
||||
Args:
|
||||
group_name (str): The name of the chain group.
|
||||
callback_manager (CallbackManager, optional): The callback manager to use.
|
||||
Defaults to None.
|
||||
inputs (Dict[str, Any], optional): The inputs to the chain group.
|
||||
Defaults to None.
|
||||
project_name (str, optional): The name of the project.
|
||||
Defaults to None.
|
||||
example_id (str or UUID, optional): The ID of the example.
|
||||
@@ -155,7 +157,9 @@ async def atrace_as_chain_group(
|
||||
Args:
|
||||
group_name (str): The name of the chain group.
|
||||
callback_manager (AsyncCallbackManager, optional): The async callback manager to use,
|
||||
which manages tracing and other callback behavior.
|
||||
which manages tracing and other callback behavior. Defaults to None.
|
||||
inputs (Dict[str, Any], optional): The inputs to the chain group.
|
||||
Defaults to None.
|
||||
project_name (str, optional): The name of the project.
|
||||
Defaults to None.
|
||||
example_id (str or UUID, optional): The ID of the example.
|
||||
@@ -218,7 +222,13 @@ Func = TypeVar("Func", bound=Callable)
|
||||
|
||||
def shielded(func: Func) -> Func:
|
||||
"""
|
||||
Makes so an awaitable method is always shielded from cancellation
|
||||
Makes so an awaitable method is always shielded from cancellation.
|
||||
|
||||
Args:
|
||||
func (Callable): The function to shield.
|
||||
|
||||
Returns:
|
||||
Callable: The shielded function
|
||||
"""
|
||||
|
||||
@functools.wraps(func)
|
||||
@@ -237,14 +247,14 @@ def handle_event(
|
||||
) -> None:
|
||||
"""Generic event handler for CallbackManager.
|
||||
|
||||
Note: This function is used by langserve to handle events.
|
||||
Note: This function is used by LangServe to handle events.
|
||||
|
||||
Args:
|
||||
handlers: The list of handlers that will handle the event
|
||||
event_name: The name of the event (e.g., "on_llm_start")
|
||||
handlers: The list of handlers that will handle the event.
|
||||
event_name: The name of the event (e.g., "on_llm_start").
|
||||
ignore_condition_name: Name of the attribute defined on handler
|
||||
that if True will cause the handler to be skipped for the given event
|
||||
*args: The arguments to pass to the event handler
|
||||
that if True will cause the handler to be skipped for the given event.
|
||||
*args: The arguments to pass to the event handler.
|
||||
**kwargs: The keyword arguments to pass to the event handler
|
||||
"""
|
||||
coros: List[Coroutine[Any, Any, Any]] = []
|
||||
@@ -394,17 +404,17 @@ async def ahandle_event(
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Generic event handler for AsyncCallbackManager.
|
||||
"""Async generic event handler for AsyncCallbackManager.
|
||||
|
||||
Note: This function is used by langserve to handle events.
|
||||
Note: This function is used by LangServe to handle events.
|
||||
|
||||
Args:
|
||||
handlers: The list of handlers that will handle the event
|
||||
event_name: The name of the event (e.g., "on_llm_start")
|
||||
handlers: The list of handlers that will handle the event.
|
||||
event_name: The name of the event (e.g., "on_llm_start").
|
||||
ignore_condition_name: Name of the attribute defined on handler
|
||||
that if True will cause the handler to be skipped for the given event
|
||||
*args: The arguments to pass to the event handler
|
||||
**kwargs: The keyword arguments to pass to the event handler
|
||||
that if True will cause the handler to be skipped for the given event.
|
||||
*args: The arguments to pass to the event handler.
|
||||
**kwargs: The keyword arguments to pass to the event handler.
|
||||
"""
|
||||
for handler in [h for h in handlers if h.run_inline]:
|
||||
await _ahandle_event_for_handler(
|
||||
@@ -452,10 +462,13 @@ class BaseRunManager(RunManagerMixin):
|
||||
The list of inheritable handlers.
|
||||
parent_run_id (UUID, optional): The ID of the parent run.
|
||||
Defaults to None.
|
||||
tags (Optional[List[str]]): The list of tags.
|
||||
tags (Optional[List[str]]): The list of tags. Defaults to None.
|
||||
inheritable_tags (Optional[List[str]]): The list of inheritable tags.
|
||||
Defaults to None.
|
||||
metadata (Optional[Dict[str, Any]]): The metadata.
|
||||
Defaults to None.
|
||||
inheritable_metadata (Optional[Dict[str, Any]]): The inheritable metadata.
|
||||
Defaults to None.
|
||||
"""
|
||||
self.run_id = run_id
|
||||
self.handlers = handlers
|
||||
@@ -492,10 +505,11 @@ class RunManager(BaseRunManager):
|
||||
text: str,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run when text is received.
|
||||
"""Run when a text is received.
|
||||
|
||||
Args:
|
||||
text (str): The received text.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
Any: The result of the callback.
|
||||
@@ -516,6 +530,12 @@ class RunManager(BaseRunManager):
|
||||
retry_state: RetryCallState,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when a retry is received.
|
||||
|
||||
Args:
|
||||
retry_state (RetryCallState): The retry state.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
handle_event(
|
||||
self.handlers,
|
||||
"on_retry",
|
||||
@@ -566,10 +586,11 @@ class AsyncRunManager(BaseRunManager, ABC):
|
||||
text: str,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Run when text is received.
|
||||
"""Run when a text is received.
|
||||
|
||||
Args:
|
||||
text (str): The received text.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
Any: The result of the callback.
|
||||
@@ -590,6 +611,12 @@ class AsyncRunManager(BaseRunManager, ABC):
|
||||
retry_state: RetryCallState,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Async run when a retry is received.
|
||||
|
||||
Args:
|
||||
retry_state (RetryCallState): The retry state.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
await ahandle_event(
|
||||
self.handlers,
|
||||
"on_retry",
|
||||
@@ -638,6 +665,9 @@ class CallbackManagerForLLMRun(RunManager, LLMManagerMixin):
|
||||
|
||||
Args:
|
||||
token (str): The new token.
|
||||
chunk (Optional[Union[GenerationChunk, ChatGenerationChunk]], optional):
|
||||
The chunk. Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
handle_event(
|
||||
self.handlers,
|
||||
@@ -656,6 +686,7 @@ class CallbackManagerForLLMRun(RunManager, LLMManagerMixin):
|
||||
|
||||
Args:
|
||||
response (LLMResult): The LLM result.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
handle_event(
|
||||
self.handlers,
|
||||
@@ -725,6 +756,9 @@ class AsyncCallbackManagerForLLMRun(AsyncRunManager, LLMManagerMixin):
|
||||
|
||||
Args:
|
||||
token (str): The new token.
|
||||
chunk (Optional[Union[GenerationChunk, ChatGenerationChunk]], optional):
|
||||
The chunk. Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
await ahandle_event(
|
||||
self.handlers,
|
||||
@@ -744,6 +778,7 @@ class AsyncCallbackManagerForLLMRun(AsyncRunManager, LLMManagerMixin):
|
||||
|
||||
Args:
|
||||
response (LLMResult): The LLM result.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
await ahandle_event(
|
||||
self.handlers,
|
||||
@@ -793,6 +828,7 @@ class CallbackManagerForChainRun(ParentRunManager, ChainManagerMixin):
|
||||
|
||||
Args:
|
||||
outputs (Union[Dict[str, Any], Any]): The outputs of the chain.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
handle_event(
|
||||
self.handlers,
|
||||
@@ -814,6 +850,7 @@ class CallbackManagerForChainRun(ParentRunManager, ChainManagerMixin):
|
||||
|
||||
Args:
|
||||
error (Exception or KeyboardInterrupt): The error.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
handle_event(
|
||||
self.handlers,
|
||||
@@ -831,6 +868,7 @@ class CallbackManagerForChainRun(ParentRunManager, ChainManagerMixin):
|
||||
|
||||
Args:
|
||||
action (AgentAction): The agent action.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
Any: The result of the callback.
|
||||
@@ -851,6 +889,7 @@ class CallbackManagerForChainRun(ParentRunManager, ChainManagerMixin):
|
||||
|
||||
Args:
|
||||
finish (AgentFinish): The agent finish.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
Any: The result of the callback.
|
||||
@@ -891,10 +930,11 @@ class AsyncCallbackManagerForChainRun(AsyncParentRunManager, ChainManagerMixin):
|
||||
async def on_chain_end(
|
||||
self, outputs: Union[Dict[str, Any], Any], **kwargs: Any
|
||||
) -> None:
|
||||
"""Run when chain ends running.
|
||||
"""Run when a chain ends running.
|
||||
|
||||
Args:
|
||||
outputs (Union[Dict[str, Any], Any]): The outputs of the chain.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
await ahandle_event(
|
||||
self.handlers,
|
||||
@@ -917,6 +957,7 @@ class AsyncCallbackManagerForChainRun(AsyncParentRunManager, ChainManagerMixin):
|
||||
|
||||
Args:
|
||||
error (Exception or KeyboardInterrupt): The error.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
await ahandle_event(
|
||||
self.handlers,
|
||||
@@ -935,6 +976,7 @@ class AsyncCallbackManagerForChainRun(AsyncParentRunManager, ChainManagerMixin):
|
||||
|
||||
Args:
|
||||
action (AgentAction): The agent action.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
Any: The result of the callback.
|
||||
@@ -956,6 +998,7 @@ class AsyncCallbackManagerForChainRun(AsyncParentRunManager, ChainManagerMixin):
|
||||
|
||||
Args:
|
||||
finish (AgentFinish): The agent finish.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
Any: The result of the callback.
|
||||
@@ -980,10 +1023,11 @@ class CallbackManagerForToolRun(ParentRunManager, ToolManagerMixin):
|
||||
output: Any,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when tool ends running.
|
||||
"""Run when the tool ends running.
|
||||
|
||||
Args:
|
||||
output (Any): The output of the tool.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
handle_event(
|
||||
self.handlers,
|
||||
@@ -1005,6 +1049,7 @@ class CallbackManagerForToolRun(ParentRunManager, ToolManagerMixin):
|
||||
|
||||
Args:
|
||||
error (Exception or KeyboardInterrupt): The error.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
handle_event(
|
||||
self.handlers,
|
||||
@@ -1040,10 +1085,11 @@ class AsyncCallbackManagerForToolRun(AsyncParentRunManager, ToolManagerMixin):
|
||||
|
||||
@shielded
|
||||
async def on_tool_end(self, output: Any, **kwargs: Any) -> None:
|
||||
"""Run when tool ends running.
|
||||
"""Async run when the tool ends running.
|
||||
|
||||
Args:
|
||||
output (Any): The output of the tool.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
await ahandle_event(
|
||||
self.handlers,
|
||||
@@ -1066,6 +1112,7 @@ class AsyncCallbackManagerForToolRun(AsyncParentRunManager, ToolManagerMixin):
|
||||
|
||||
Args:
|
||||
error (Exception or KeyboardInterrupt): The error.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
await ahandle_event(
|
||||
self.handlers,
|
||||
@@ -1087,7 +1134,12 @@ class CallbackManagerForRetrieverRun(ParentRunManager, RetrieverManagerMixin):
|
||||
documents: Sequence[Document],
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when retriever ends running."""
|
||||
"""Run when retriever ends running.
|
||||
|
||||
Args:
|
||||
documents (Sequence[Document]): The retrieved documents.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
handle_event(
|
||||
self.handlers,
|
||||
"on_retriever_end",
|
||||
@@ -1104,7 +1156,12 @@ class CallbackManagerForRetrieverRun(ParentRunManager, RetrieverManagerMixin):
|
||||
error: BaseException,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when retriever errors."""
|
||||
"""Run when retriever errors.
|
||||
|
||||
Args:
|
||||
error (BaseException): The error.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
handle_event(
|
||||
self.handlers,
|
||||
"on_retriever_error",
|
||||
@@ -1144,7 +1201,12 @@ class AsyncCallbackManagerForRetrieverRun(
|
||||
async def on_retriever_end(
|
||||
self, documents: Sequence[Document], **kwargs: Any
|
||||
) -> None:
|
||||
"""Run when retriever ends running."""
|
||||
"""Run when the retriever ends running.
|
||||
|
||||
Args:
|
||||
documents (Sequence[Document]): The retrieved documents.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
await ahandle_event(
|
||||
self.handlers,
|
||||
"on_retriever_end",
|
||||
@@ -1162,7 +1224,12 @@ class AsyncCallbackManagerForRetrieverRun(
|
||||
error: BaseException,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when retriever errors."""
|
||||
"""Run when retriever errors.
|
||||
|
||||
Args:
|
||||
error (BaseException): The error.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
await ahandle_event(
|
||||
self.handlers,
|
||||
"on_retriever_error",
|
||||
@@ -1176,7 +1243,7 @@ class AsyncCallbackManagerForRetrieverRun(
|
||||
|
||||
|
||||
class CallbackManager(BaseCallbackManager):
|
||||
"""Callback manager that handles callbacks from LangChain."""
|
||||
"""Callback manager for LangChain."""
|
||||
|
||||
def on_llm_start(
|
||||
self,
|
||||
@@ -1191,6 +1258,7 @@ class CallbackManager(BaseCallbackManager):
|
||||
serialized (Dict[str, Any]): The serialized LLM.
|
||||
prompts (List[str]): The list of prompts.
|
||||
run_id (UUID, optional): The ID of the run. Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
List[CallbackManagerForLLMRun]: A callback manager for each
|
||||
@@ -1241,6 +1309,7 @@ class CallbackManager(BaseCallbackManager):
|
||||
serialized (Dict[str, Any]): The serialized LLM.
|
||||
messages (List[List[BaseMessage]]): The list of messages.
|
||||
run_id (UUID, optional): The ID of the run. Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
List[CallbackManagerForLLMRun]: A callback manager for each
|
||||
@@ -1295,6 +1364,7 @@ class CallbackManager(BaseCallbackManager):
|
||||
serialized (Dict[str, Any]): The serialized chain.
|
||||
inputs (Union[Dict[str, Any], Any]): The inputs to the chain.
|
||||
run_id (UUID, optional): The ID of the run. Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
CallbackManagerForChainRun: The callback manager for the chain run.
|
||||
@@ -1347,6 +1417,7 @@ class CallbackManager(BaseCallbackManager):
|
||||
input is needed.
|
||||
If provided, the inputs are expected to be formatted as a dict.
|
||||
The keys will correspond to the named-arguments in the tool.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
CallbackManagerForToolRun: The callback manager for the tool run.
|
||||
@@ -1387,7 +1458,15 @@ class CallbackManager(BaseCallbackManager):
|
||||
parent_run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> CallbackManagerForRetrieverRun:
|
||||
"""Run when retriever starts running."""
|
||||
"""Run when the retriever starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized retriever.
|
||||
query (str): The query.
|
||||
run_id (UUID, optional): The ID of the run. Defaults to None.
|
||||
parent_run_id (UUID, optional): The ID of the parent run. Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
if run_id is None:
|
||||
run_id = uuid.uuid4()
|
||||
|
||||
@@ -1470,6 +1549,16 @@ class CallbackManagerForChainGroup(CallbackManager):
|
||||
parent_run_manager: CallbackManagerForChainRun,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Initialize the callback manager.
|
||||
|
||||
Args:
|
||||
handlers (List[BaseCallbackHandler]): The list of handlers.
|
||||
inheritable_handlers (Optional[List[BaseCallbackHandler]]): The list of
|
||||
inheritable handlers. Defaults to None.
|
||||
parent_run_id (Optional[UUID]): The ID of the parent run. Defaults to None.
|
||||
parent_run_manager (CallbackManagerForChainRun): The parent run manager.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
super().__init__(
|
||||
handlers,
|
||||
inheritable_handlers,
|
||||
@@ -1480,6 +1569,7 @@ class CallbackManagerForChainGroup(CallbackManager):
|
||||
self.ended = False
|
||||
|
||||
def copy(self) -> CallbackManagerForChainGroup:
|
||||
"""Copy the callback manager."""
|
||||
return self.__class__(
|
||||
handlers=self.handlers,
|
||||
inheritable_handlers=self.inheritable_handlers,
|
||||
@@ -1496,6 +1586,7 @@ class CallbackManagerForChainGroup(CallbackManager):
|
||||
|
||||
Args:
|
||||
outputs (Union[Dict[str, Any], Any]): The outputs of the chain.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
self.ended = True
|
||||
return self.parent_run_manager.on_chain_end(outputs, **kwargs)
|
||||
@@ -1509,6 +1600,7 @@ class CallbackManagerForChainGroup(CallbackManager):
|
||||
|
||||
Args:
|
||||
error (Exception or KeyboardInterrupt): The error.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
self.ended = True
|
||||
return self.parent_run_manager.on_chain_error(error, **kwargs)
|
||||
@@ -1535,6 +1627,7 @@ class AsyncCallbackManager(BaseCallbackManager):
|
||||
serialized (Dict[str, Any]): The serialized LLM.
|
||||
prompts (List[str]): The list of prompts.
|
||||
run_id (UUID, optional): The ID of the run. Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
List[AsyncCallbackManagerForLLMRun]: The list of async
|
||||
@@ -1591,12 +1684,13 @@ class AsyncCallbackManager(BaseCallbackManager):
|
||||
run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> List[AsyncCallbackManagerForLLMRun]:
|
||||
"""Run when LLM starts running.
|
||||
"""Async run when LLM starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized LLM.
|
||||
messages (List[List[BaseMessage]]): The list of messages.
|
||||
run_id (UUID, optional): The ID of the run. Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
List[AsyncCallbackManagerForLLMRun]: The list of
|
||||
@@ -1651,12 +1745,13 @@ class AsyncCallbackManager(BaseCallbackManager):
|
||||
run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> AsyncCallbackManagerForChainRun:
|
||||
"""Run when chain starts running.
|
||||
"""Async run when chain starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized chain.
|
||||
inputs (Union[Dict[str, Any], Any]): The inputs to the chain.
|
||||
run_id (UUID, optional): The ID of the run. Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
AsyncCallbackManagerForChainRun: The async callback manager
|
||||
@@ -1697,7 +1792,7 @@ class AsyncCallbackManager(BaseCallbackManager):
|
||||
parent_run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> AsyncCallbackManagerForToolRun:
|
||||
"""Run when tool starts running.
|
||||
"""Run when the tool starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized tool.
|
||||
@@ -1705,6 +1800,7 @@ class AsyncCallbackManager(BaseCallbackManager):
|
||||
run_id (UUID, optional): The ID of the run. Defaults to None.
|
||||
parent_run_id (UUID, optional): The ID of the parent run.
|
||||
Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
AsyncCallbackManagerForToolRun: The async callback manager
|
||||
@@ -1745,7 +1841,19 @@ class AsyncCallbackManager(BaseCallbackManager):
|
||||
parent_run_id: Optional[UUID] = None,
|
||||
**kwargs: Any,
|
||||
) -> AsyncCallbackManagerForRetrieverRun:
|
||||
"""Run when retriever starts running."""
|
||||
"""Run when the retriever starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized retriever.
|
||||
query (str): The query.
|
||||
run_id (UUID, optional): The ID of the run. Defaults to None.
|
||||
parent_run_id (UUID, optional): The ID of the parent run. Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
|
||||
Returns:
|
||||
AsyncCallbackManagerForRetrieverRun: The async callback manager
|
||||
for the retriever run.
|
||||
"""
|
||||
if run_id is None:
|
||||
run_id = uuid.uuid4()
|
||||
|
||||
@@ -1828,6 +1936,17 @@ class AsyncCallbackManagerForChainGroup(AsyncCallbackManager):
|
||||
parent_run_manager: AsyncCallbackManagerForChainRun,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Initialize the async callback manager.
|
||||
|
||||
Args:
|
||||
handlers (List[BaseCallbackHandler]): The list of handlers.
|
||||
inheritable_handlers (Optional[List[BaseCallbackHandler]]): The list of
|
||||
inheritable handlers. Defaults to None.
|
||||
parent_run_id (Optional[UUID]): The ID of the parent run. Defaults to None.
|
||||
parent_run_manager (AsyncCallbackManagerForChainRun):
|
||||
The parent run manager.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
super().__init__(
|
||||
handlers,
|
||||
inheritable_handlers,
|
||||
@@ -1838,6 +1957,7 @@ class AsyncCallbackManagerForChainGroup(AsyncCallbackManager):
|
||||
self.ended = False
|
||||
|
||||
def copy(self) -> AsyncCallbackManagerForChainGroup:
|
||||
"""Copy the async callback manager."""
|
||||
return self.__class__(
|
||||
handlers=self.handlers,
|
||||
inheritable_handlers=self.inheritable_handlers,
|
||||
@@ -1856,6 +1976,7 @@ class AsyncCallbackManagerForChainGroup(AsyncCallbackManager):
|
||||
|
||||
Args:
|
||||
outputs (Union[Dict[str, Any], Any]): The outputs of the chain.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
self.ended = True
|
||||
await self.parent_run_manager.on_chain_end(outputs, **kwargs)
|
||||
@@ -1869,6 +1990,7 @@ class AsyncCallbackManagerForChainGroup(AsyncCallbackManager):
|
||||
|
||||
Args:
|
||||
error (Exception or KeyboardInterrupt): The error.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
self.ended = True
|
||||
await self.parent_run_manager.on_chain_error(error, **kwargs)
|
||||
|
||||
@@ -15,24 +15,45 @@ class StdOutCallbackHandler(BaseCallbackHandler):
|
||||
"""Callback Handler that prints to std out."""
|
||||
|
||||
def __init__(self, color: Optional[str] = None) -> None:
|
||||
"""Initialize callback handler."""
|
||||
"""Initialize callback handler.
|
||||
|
||||
Args:
|
||||
color: The color to use for the text. Defaults to None.
|
||||
"""
|
||||
self.color = color
|
||||
|
||||
def on_chain_start(
|
||||
self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any
|
||||
) -> None:
|
||||
"""Print out that we are entering a chain."""
|
||||
"""Print out that we are entering a chain.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized chain.
|
||||
inputs (Dict[str, Any]): The inputs to the chain.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
class_name = serialized.get("name", serialized.get("id", ["<unknown>"])[-1])
|
||||
print(f"\n\n\033[1m> Entering new {class_name} chain...\033[0m") # noqa: T201
|
||||
|
||||
def on_chain_end(self, outputs: Dict[str, Any], **kwargs: Any) -> None:
|
||||
"""Print out that we finished a chain."""
|
||||
"""Print out that we finished a chain.
|
||||
|
||||
Args:
|
||||
outputs (Dict[str, Any]): The outputs of the chain.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
print("\n\033[1m> Finished chain.\033[0m") # noqa: T201
|
||||
|
||||
def on_agent_action(
|
||||
self, action: AgentAction, color: Optional[str] = None, **kwargs: Any
|
||||
) -> Any:
|
||||
"""Run on agent action."""
|
||||
"""Run on agent action.
|
||||
|
||||
Args:
|
||||
action (AgentAction): The agent action.
|
||||
color (Optional[str]): The color to use for the text. Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
print_text(action.log, color=color or self.color)
|
||||
|
||||
def on_tool_end(
|
||||
@@ -43,7 +64,16 @@ class StdOutCallbackHandler(BaseCallbackHandler):
|
||||
llm_prefix: Optional[str] = None,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""If not the final action, print out observation."""
|
||||
"""If not the final action, print out observation.
|
||||
|
||||
Args:
|
||||
output (Any): The output to print.
|
||||
color (Optional[str]): The color to use for the text. Defaults to None.
|
||||
observation_prefix (Optional[str]): The observation prefix.
|
||||
Defaults to None.
|
||||
llm_prefix (Optional[str]): The LLM prefix. Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
output = str(output)
|
||||
if observation_prefix is not None:
|
||||
print_text(f"\n{observation_prefix}")
|
||||
@@ -58,11 +88,24 @@ class StdOutCallbackHandler(BaseCallbackHandler):
|
||||
end: str = "",
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when agent ends."""
|
||||
"""Run when the agent ends.
|
||||
|
||||
Args:
|
||||
text (str): The text to print.
|
||||
color (Optional[str]): The color to use for the text. Defaults to None.
|
||||
end (str): The end character to use. Defaults to "".
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
print_text(text, color=color or self.color, end=end)
|
||||
|
||||
def on_agent_finish(
|
||||
self, finish: AgentFinish, color: Optional[str] = None, **kwargs: Any
|
||||
) -> None:
|
||||
"""Run on agent end."""
|
||||
"""Run on the agent end.
|
||||
|
||||
Args:
|
||||
finish (AgentFinish): The agent finish.
|
||||
color (Optional[str]): The color to use for the text. Defaults to None.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
print_text(finish.log, color=color or self.color, end="\n")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""Callback Handler streams to stdout on new llm token."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
@@ -18,7 +19,13 @@ class StreamingStdOutCallbackHandler(BaseCallbackHandler):
|
||||
def on_llm_start(
|
||||
self, serialized: Dict[str, Any], prompts: List[str], **kwargs: Any
|
||||
) -> None:
|
||||
"""Run when LLM starts running."""
|
||||
"""Run when LLM starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized LLM.
|
||||
prompts (List[str]): The prompts to run.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_chat_model_start(
|
||||
self,
|
||||
@@ -26,47 +33,115 @@ class StreamingStdOutCallbackHandler(BaseCallbackHandler):
|
||||
messages: List[List[BaseMessage]],
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""Run when LLM starts running."""
|
||||
"""Run when LLM starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized LLM.
|
||||
messages (List[List[BaseMessage]]): The messages to run.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_llm_new_token(self, token: str, **kwargs: Any) -> None:
|
||||
"""Run on new LLM token. Only available when streaming is enabled."""
|
||||
"""Run on new LLM token. Only available when streaming is enabled.
|
||||
|
||||
Args:
|
||||
token (str): The new token.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
sys.stdout.write(token)
|
||||
sys.stdout.flush()
|
||||
|
||||
def on_llm_end(self, response: LLMResult, **kwargs: Any) -> None:
|
||||
"""Run when LLM ends running."""
|
||||
"""Run when LLM ends running.
|
||||
|
||||
Args:
|
||||
response (LLMResult): The response from the LLM.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_llm_error(self, error: BaseException, **kwargs: Any) -> None:
|
||||
"""Run when LLM errors."""
|
||||
"""Run when LLM errors.
|
||||
|
||||
Args:
|
||||
error (BaseException): The error that occurred.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_chain_start(
|
||||
self, serialized: Dict[str, Any], inputs: Dict[str, Any], **kwargs: Any
|
||||
) -> None:
|
||||
"""Run when chain starts running."""
|
||||
"""Run when a chain starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized chain.
|
||||
inputs (Dict[str, Any]): The inputs to the chain.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_chain_end(self, outputs: Dict[str, Any], **kwargs: Any) -> None:
|
||||
"""Run when chain ends running."""
|
||||
"""Run when a chain ends running.
|
||||
|
||||
Args:
|
||||
outputs (Dict[str, Any]): The outputs of the chain.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_chain_error(self, error: BaseException, **kwargs: Any) -> None:
|
||||
"""Run when chain errors."""
|
||||
"""Run when chain errors.
|
||||
|
||||
Args:
|
||||
error (BaseException): The error that occurred.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_tool_start(
|
||||
self, serialized: Dict[str, Any], input_str: str, **kwargs: Any
|
||||
) -> None:
|
||||
"""Run when tool starts running."""
|
||||
"""Run when the tool starts running.
|
||||
|
||||
Args:
|
||||
serialized (Dict[str, Any]): The serialized tool.
|
||||
input_str (str): The input string.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_agent_action(self, action: AgentAction, **kwargs: Any) -> Any:
|
||||
"""Run on agent action."""
|
||||
"""Run on agent action.
|
||||
|
||||
Args:
|
||||
action (AgentAction): The agent action.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
pass
|
||||
|
||||
def on_tool_end(self, output: Any, **kwargs: Any) -> None:
|
||||
"""Run when tool ends running."""
|
||||
"""Run when tool ends running.
|
||||
|
||||
Args:
|
||||
output (Any): The output of the tool.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_tool_error(self, error: BaseException, **kwargs: Any) -> None:
|
||||
"""Run when tool errors."""
|
||||
"""Run when tool errors.
|
||||
|
||||
Args:
|
||||
error (BaseException): The error that occurred.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_text(self, text: str, **kwargs: Any) -> None:
|
||||
"""Run on arbitrary text."""
|
||||
"""Run on an arbitrary text.
|
||||
|
||||
Args:
|
||||
text (str): The text to print.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
def on_agent_finish(self, finish: AgentFinish, **kwargs: Any) -> None:
|
||||
"""Run on agent end."""
|
||||
"""Run on the agent end.
|
||||
|
||||
Args:
|
||||
finish (AgentFinish): The agent finish.
|
||||
**kwargs (Any): Additional keyword arguments.
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, List, Literal
|
||||
from typing import Any, List, Literal, Optional
|
||||
|
||||
from langchain_core.load.serializable import Serializable
|
||||
from langchain_core.pydantic_v1 import Field
|
||||
@@ -21,6 +21,16 @@ class Document(Serializable):
|
||||
)
|
||||
"""
|
||||
|
||||
# The ID field is optional at the moment.
|
||||
# It will likely become required in a future major release after
|
||||
# it has been adopted by enough vectorstore implementations.
|
||||
id: Optional[str] = None
|
||||
"""An optional identifier for the document.
|
||||
|
||||
Ideally this should be unique across the document collection and formatted
|
||||
as a UUID, but this will not be enforced.
|
||||
"""
|
||||
|
||||
page_content: str
|
||||
"""String text."""
|
||||
metadata: dict = Field(default_factory=dict)
|
||||
@@ -42,3 +52,18 @@ class Document(Serializable):
|
||||
def get_lc_namespace(cls) -> List[str]:
|
||||
"""Get the namespace of the langchain object."""
|
||||
return ["langchain", "schema", "document"]
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Override __str__ to restrict it to page_content and metadata."""
|
||||
# The format matches pydantic format for __str__.
|
||||
#
|
||||
# The purpose of this change is to make sure that user code that
|
||||
# feeds Document objects directly into prompts remains unchanged
|
||||
# due to the addition of the id field (or any other fields in the future).
|
||||
#
|
||||
# This override will likely be removed in the future in favor of
|
||||
# a more general solution of formatting content directly inside the prompts.
|
||||
if self.metadata:
|
||||
return f"page_content='{self.page_content}' metadata={self.metadata}"
|
||||
else:
|
||||
return f"page_content='{self.page_content}'"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
in prompts.
|
||||
This allows us to select examples that are most relevant to the input.
|
||||
"""
|
||||
|
||||
from langchain_core.example_selectors.base import BaseExampleSelector
|
||||
from langchain_core.example_selectors.length_based import (
|
||||
LengthBasedExampleSelector,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""Interface for selecting examples to include in prompts."""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Dict, List
|
||||
|
||||
@@ -10,16 +11,34 @@ class BaseExampleSelector(ABC):
|
||||
|
||||
@abstractmethod
|
||||
def add_example(self, example: Dict[str, str]) -> Any:
|
||||
"""Add new example to store."""
|
||||
"""Add new example to store.
|
||||
|
||||
Args:
|
||||
example: A dictionary with keys as input variables
|
||||
and values as their values."""
|
||||
|
||||
async def aadd_example(self, example: Dict[str, str]) -> Any:
|
||||
"""Add new example to store."""
|
||||
"""Async add new example to store.
|
||||
|
||||
Args:
|
||||
example: A dictionary with keys as input variables
|
||||
and values as their values."""
|
||||
|
||||
return await run_in_executor(None, self.add_example, example)
|
||||
|
||||
@abstractmethod
|
||||
def select_examples(self, input_variables: Dict[str, str]) -> List[dict]:
|
||||
"""Select which examples to use based on the inputs."""
|
||||
"""Select which examples to use based on the inputs.
|
||||
|
||||
Args:
|
||||
input_variables: A dictionary with keys as input variables
|
||||
and values as their values."""
|
||||
|
||||
async def aselect_examples(self, input_variables: Dict[str, str]) -> List[dict]:
|
||||
"""Select which examples to use based on the inputs."""
|
||||
"""Async select which examples to use based on the inputs.
|
||||
|
||||
Args:
|
||||
input_variables: A dictionary with keys as input variables
|
||||
and values as their values."""
|
||||
|
||||
return await run_in_executor(None, self.select_examples, input_variables)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""Select examples based on length."""
|
||||
|
||||
import re
|
||||
from typing import Callable, Dict, List
|
||||
|
||||
@@ -27,15 +28,27 @@ class LengthBasedExampleSelector(BaseExampleSelector, BaseModel):
|
||||
"""Max length for the prompt, beyond which examples are cut."""
|
||||
|
||||
example_text_lengths: List[int] = [] #: :meta private:
|
||||
"""Length of each example."""
|
||||
|
||||
def add_example(self, example: Dict[str, str]) -> None:
|
||||
"""Add new example to list."""
|
||||
"""Add new example to list.
|
||||
|
||||
Args:
|
||||
example: A dictionary with keys as input variables
|
||||
and values as their values.
|
||||
"""
|
||||
self.examples.append(example)
|
||||
string_example = self.example_prompt.format(**example)
|
||||
self.example_text_lengths.append(self.get_text_length(string_example))
|
||||
|
||||
async def aadd_example(self, example: Dict[str, str]) -> None:
|
||||
"""Add new example to list."""
|
||||
"""Async add new example to list.
|
||||
|
||||
Args:
|
||||
example: A dictionary with keys as input variables
|
||||
and values as their values.
|
||||
"""
|
||||
|
||||
self.add_example(example)
|
||||
|
||||
@validator("example_text_lengths", always=True)
|
||||
@@ -51,7 +64,15 @@ class LengthBasedExampleSelector(BaseExampleSelector, BaseModel):
|
||||
return [get_text_length(eg) for eg in string_examples]
|
||||
|
||||
def select_examples(self, input_variables: Dict[str, str]) -> List[dict]:
|
||||
"""Select which examples to use based on the input lengths."""
|
||||
"""Select which examples to use based on the input lengths.
|
||||
|
||||
Args:
|
||||
input_variables: A dictionary with keys as input variables
|
||||
and values as their values.
|
||||
|
||||
Returns:
|
||||
A list of examples to include in the prompt.
|
||||
"""
|
||||
inputs = " ".join(input_variables.values())
|
||||
remaining_length = self.max_length - self.get_text_length(inputs)
|
||||
i = 0
|
||||
@@ -67,5 +88,13 @@ class LengthBasedExampleSelector(BaseExampleSelector, BaseModel):
|
||||
return examples
|
||||
|
||||
async def aselect_examples(self, input_variables: Dict[str, str]) -> List[dict]:
|
||||
"""Select which examples to use based on the input lengths."""
|
||||
"""Async select which examples to use based on the input lengths.
|
||||
|
||||
Args:
|
||||
input_variables: A dictionary with keys as input variables
|
||||
and values as their values.
|
||||
|
||||
Returns:
|
||||
A list of examples to include in the prompt.
|
||||
"""
|
||||
return self.select_examples(input_variables)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""Example selector that selects examples based on SemanticSimilarity."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC
|
||||
@@ -14,7 +15,15 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
def sorted_values(values: Dict[str, str]) -> List[Any]:
|
||||
"""Return a list of values in dict sorted by key."""
|
||||
"""Return a list of values in dict sorted by key.
|
||||
|
||||
Args:
|
||||
values: A dictionary with keys as input variables
|
||||
and values as their values.
|
||||
|
||||
Returns:
|
||||
A list of values in dict sorted by key.
|
||||
"""
|
||||
return [values[val] for val in sorted(values)]
|
||||
|
||||
|
||||
@@ -58,14 +67,30 @@ class _VectorStoreExampleSelector(BaseExampleSelector, BaseModel, ABC):
|
||||
return examples
|
||||
|
||||
def add_example(self, example: Dict[str, str]) -> str:
|
||||
"""Add new example to vectorstore."""
|
||||
"""Add a new example to vectorstore.
|
||||
|
||||
Args:
|
||||
example: A dictionary with keys as input variables
|
||||
and values as their values.
|
||||
|
||||
Returns:
|
||||
The ID of the added example.
|
||||
"""
|
||||
ids = self.vectorstore.add_texts(
|
||||
[self._example_to_text(example, self.input_keys)], metadatas=[example]
|
||||
)
|
||||
return ids[0]
|
||||
|
||||
async def aadd_example(self, example: Dict[str, str]) -> str:
|
||||
"""Add new example to vectorstore."""
|
||||
"""Async add new example to vectorstore.
|
||||
|
||||
Args:
|
||||
example: A dictionary with keys as input variables
|
||||
and values as their values.
|
||||
|
||||
Returns:
|
||||
The ID of the added example.
|
||||
"""
|
||||
ids = await self.vectorstore.aadd_texts(
|
||||
[self._example_to_text(example, self.input_keys)], metadatas=[example]
|
||||
)
|
||||
@@ -76,7 +101,14 @@ class SemanticSimilarityExampleSelector(_VectorStoreExampleSelector):
|
||||
"""Select examples based on semantic similarity."""
|
||||
|
||||
def select_examples(self, input_variables: Dict[str, str]) -> List[dict]:
|
||||
"""Select examples based on semantic similarity."""
|
||||
"""Select examples based on semantic similarity.
|
||||
|
||||
Args:
|
||||
input_variables: The input variables to use for search.
|
||||
|
||||
Returns:
|
||||
The selected examples.
|
||||
"""
|
||||
# Get the docs with the highest similarity.
|
||||
vectorstore_kwargs = self.vectorstore_kwargs or {}
|
||||
example_docs = self.vectorstore.similarity_search(
|
||||
@@ -87,7 +119,14 @@ class SemanticSimilarityExampleSelector(_VectorStoreExampleSelector):
|
||||
return self._documents_to_examples(example_docs)
|
||||
|
||||
async def aselect_examples(self, input_variables: Dict[str, str]) -> List[dict]:
|
||||
"""Asynchronously select examples based on semantic similarity."""
|
||||
"""Asynchronously select examples based on semantic similarity.
|
||||
|
||||
Args:
|
||||
input_variables: The input variables to use for search.
|
||||
|
||||
Returns:
|
||||
The selected examples.
|
||||
"""
|
||||
# Get the docs with the highest similarity.
|
||||
vectorstore_kwargs = self.vectorstore_kwargs or {}
|
||||
example_docs = await self.vectorstore.asimilarity_search(
|
||||
@@ -118,7 +157,7 @@ class SemanticSimilarityExampleSelector(_VectorStoreExampleSelector):
|
||||
examples: List of examples to use in the prompt.
|
||||
embeddings: An initialized embedding API interface, e.g. OpenAIEmbeddings().
|
||||
vectorstore_cls: A vector store DB interface class, e.g. FAISS.
|
||||
k: Number of examples to select
|
||||
k: Number of examples to select. Default is 4.
|
||||
input_keys: If provided, the search is based on the input variables
|
||||
instead of all variables.
|
||||
example_keys: If provided, keys to filter examples to.
|
||||
@@ -154,7 +193,7 @@ class SemanticSimilarityExampleSelector(_VectorStoreExampleSelector):
|
||||
vectorstore_kwargs: Optional[dict] = None,
|
||||
**vectorstore_cls_kwargs: Any,
|
||||
) -> SemanticSimilarityExampleSelector:
|
||||
"""Create k-shot example selector using example list and embeddings.
|
||||
"""Async create k-shot example selector using example list and embeddings.
|
||||
|
||||
Reshuffles examples dynamically based on query similarity.
|
||||
|
||||
@@ -162,7 +201,7 @@ class SemanticSimilarityExampleSelector(_VectorStoreExampleSelector):
|
||||
examples: List of examples to use in the prompt.
|
||||
embeddings: An initialized embedding API interface, e.g. OpenAIEmbeddings().
|
||||
vectorstore_cls: A vector store DB interface class, e.g. FAISS.
|
||||
k: Number of examples to select
|
||||
k: Number of examples to select. Default is 4.
|
||||
input_keys: If provided, the search is based on the input variables
|
||||
instead of all variables.
|
||||
example_keys: If provided, keys to filter examples to.
|
||||
@@ -249,8 +288,9 @@ class MaxMarginalRelevanceExampleSelector(_VectorStoreExampleSelector):
|
||||
examples: List of examples to use in the prompt.
|
||||
embeddings: An initialized embedding API interface, e.g. OpenAIEmbeddings().
|
||||
vectorstore_cls: A vector store DB interface class, e.g. FAISS.
|
||||
k: Number of examples to select
|
||||
k: Number of examples to select. Default is 4.
|
||||
fetch_k: Number of Documents to fetch to pass to MMR algorithm.
|
||||
Default is 20.
|
||||
input_keys: If provided, the search is based on the input variables
|
||||
instead of all variables.
|
||||
example_keys: If provided, keys to filter examples to.
|
||||
@@ -297,8 +337,9 @@ class MaxMarginalRelevanceExampleSelector(_VectorStoreExampleSelector):
|
||||
examples: List of examples to use in the prompt.
|
||||
embeddings: An initialized embedding API interface, e.g. OpenAIEmbeddings().
|
||||
vectorstore_cls: A vector store DB interface class, e.g. FAISS.
|
||||
k: Number of examples to select
|
||||
k: Number of examples to select. Default is 4.
|
||||
fetch_k: Number of Documents to fetch to pass to MMR algorithm.
|
||||
Default is 20.
|
||||
input_keys: If provided, the search is based on the input variables
|
||||
instead of all variables.
|
||||
example_keys: If provided, keys to filter examples to.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""Custom **exceptions** for LangChain. """
|
||||
"""Custom **exceptions** for LangChain."""
|
||||
|
||||
from typing import Any, Optional
|
||||
|
||||
|
||||
@@ -18,7 +19,7 @@ class OutputParserException(ValueError, LangChainException):
|
||||
available to catch and handle in ways to fix the parsing error, while other
|
||||
errors will be raised.
|
||||
|
||||
Args:
|
||||
Parameters:
|
||||
error: The error that's being re-raised or an error message.
|
||||
observation: String explanation of error which can be passed to a
|
||||
model to try and remediate the issue.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# flake8: noqa
|
||||
"""Global values and configuration that apply to all of LangChain."""
|
||||
|
||||
import warnings
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
@@ -135,7 +136,11 @@ def get_debug() -> bool:
|
||||
|
||||
|
||||
def set_llm_cache(value: Optional["BaseCache"]) -> None:
|
||||
"""Set a new LLM cache, overwriting the previous value, if any."""
|
||||
"""Set a new LLM cache, overwriting the previous value, if any.
|
||||
|
||||
Args:
|
||||
value: The new LLM cache to use. If `None`, the LLM cache is disabled.
|
||||
"""
|
||||
try:
|
||||
import langchain # type: ignore[import]
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
BaseMemory --> <name>Memory --> <name>Memory # Examples: BaseChatMemory -> MotorheadMemory
|
||||
|
||||
""" # noqa: E501
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
@@ -58,20 +59,37 @@ class BaseMemory(Serializable, ABC):
|
||||
|
||||
@abstractmethod
|
||||
def load_memory_variables(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Return key-value pairs given the text input to the chain."""
|
||||
"""Return key-value pairs given the text input to the chain.
|
||||
|
||||
Args:
|
||||
inputs: The inputs to the chain."""
|
||||
|
||||
async def aload_memory_variables(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Return key-value pairs given the text input to the chain."""
|
||||
"""Async return key-value pairs given the text input to the chain.
|
||||
|
||||
Args:
|
||||
inputs: The inputs to the chain.
|
||||
"""
|
||||
return await run_in_executor(None, self.load_memory_variables, inputs)
|
||||
|
||||
@abstractmethod
|
||||
def save_context(self, inputs: Dict[str, Any], outputs: Dict[str, str]) -> None:
|
||||
"""Save the context of this chain run to memory."""
|
||||
"""Save the context of this chain run to memory.
|
||||
|
||||
Args:
|
||||
inputs: The inputs to the chain.
|
||||
outputs: The outputs of the chain.
|
||||
"""
|
||||
|
||||
async def asave_context(
|
||||
self, inputs: Dict[str, Any], outputs: Dict[str, str]
|
||||
) -> None:
|
||||
"""Save the context of this chain run to memory."""
|
||||
"""Async save the context of this chain run to memory.
|
||||
|
||||
Args:
|
||||
inputs: The inputs to the chain.
|
||||
outputs: The outputs of the chain.
|
||||
"""
|
||||
await run_in_executor(None, self.save_context, inputs, outputs)
|
||||
|
||||
@abstractmethod
|
||||
@@ -79,5 +97,5 @@ class BaseMemory(Serializable, ABC):
|
||||
"""Clear memory contents."""
|
||||
|
||||
async def aclear(self) -> None:
|
||||
"""Clear memory contents."""
|
||||
"""Async clear memory contents."""
|
||||
await run_in_executor(None, self.clear)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
Prompt values are used to represent different pieces of prompts.
|
||||
They can be used to represent text, images, or chat message pieces.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
@@ -103,15 +104,15 @@ class ImagePromptValue(PromptValue):
|
||||
"""Image prompt value."""
|
||||
|
||||
image_url: ImageURL
|
||||
"""Prompt image."""
|
||||
"""Image URL."""
|
||||
type: Literal["ImagePromptValue"] = "ImagePromptValue"
|
||||
|
||||
def to_string(self) -> str:
|
||||
"""Return prompt as string."""
|
||||
"""Return prompt (image URL) as string."""
|
||||
return self.image_url["url"]
|
||||
|
||||
def to_messages(self) -> List[BaseMessage]:
|
||||
"""Return prompt as messages."""
|
||||
"""Return prompt (image URL) as messages."""
|
||||
return [HumanMessage(content=[cast(dict, self.image_url)])]
|
||||
|
||||
|
||||
@@ -120,6 +121,7 @@ class ChatPromptValueConcrete(ChatPromptValue):
|
||||
For use in external schemas."""
|
||||
|
||||
messages: Sequence[AnyMessage]
|
||||
"""Sequence of messages."""
|
||||
|
||||
type: Literal["ChatPromptValueConcrete"] = "ChatPromptValueConcrete"
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ the backbone of a retriever, but there are other types of retrievers as well.
|
||||
Document, Serializable, Callbacks,
|
||||
CallbackManagerForRetrieverRun, AsyncCallbackManagerForRetrieverRun
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
@@ -119,14 +120,14 @@ class BaseRetriever(RunnableSerializable[RetrieverInput, RetrieverOutput], ABC):
|
||||
_new_arg_supported: bool = False
|
||||
_expects_other_args: bool = False
|
||||
tags: Optional[List[str]] = None
|
||||
"""Optional list of tags associated with the retriever. Defaults to None
|
||||
"""Optional list of tags associated with the retriever. Defaults to None.
|
||||
These tags will be associated with each call to this retriever,
|
||||
and passed as arguments to the handlers defined in `callbacks`.
|
||||
You can use these to eg identify a specific instance of a retriever with its
|
||||
use case.
|
||||
"""
|
||||
metadata: Optional[Dict[str, Any]] = None
|
||||
"""Optional metadata associated with the retriever. Defaults to None
|
||||
"""Optional metadata associated with the retriever. Defaults to None.
|
||||
This metadata will be associated with each call to this retriever,
|
||||
and passed as arguments to the handlers defined in `callbacks`.
|
||||
You can use these to eg identify a specific instance of a retriever with its
|
||||
@@ -289,9 +290,10 @@ class BaseRetriever(RunnableSerializable[RetrieverInput, RetrieverOutput], ABC):
|
||||
self, query: str, *, run_manager: CallbackManagerForRetrieverRun
|
||||
) -> List[Document]:
|
||||
"""Get documents relevant to a query.
|
||||
|
||||
Args:
|
||||
query: String to find relevant documents for
|
||||
run_manager: The callbacks handler to use
|
||||
run_manager: The callback handler to use
|
||||
Returns:
|
||||
List of relevant documents
|
||||
"""
|
||||
@@ -300,9 +302,10 @@ class BaseRetriever(RunnableSerializable[RetrieverInput, RetrieverOutput], ABC):
|
||||
self, query: str, *, run_manager: AsyncCallbackManagerForRetrieverRun
|
||||
) -> List[Document]:
|
||||
"""Asynchronously get documents relevant to a query.
|
||||
|
||||
Args:
|
||||
query: String to find relevant documents for
|
||||
run_manager: The callbacks handler to use
|
||||
run_manager: The callback handler to use
|
||||
Returns:
|
||||
List of relevant documents
|
||||
"""
|
||||
|
||||
@@ -5,6 +5,7 @@ to a simple key-value interface.
|
||||
|
||||
The primary goal of these storages is to support implementation of caching.
|
||||
"""
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import (
|
||||
Any,
|
||||
@@ -95,7 +96,7 @@ class BaseStore(Generic[K, V], ABC):
|
||||
"""
|
||||
|
||||
async def amget(self, keys: Sequence[K]) -> List[Optional[V]]:
|
||||
"""Get the values associated with the given keys.
|
||||
"""Async get the values associated with the given keys.
|
||||
|
||||
Args:
|
||||
keys (Sequence[K]): A sequence of keys.
|
||||
@@ -115,7 +116,7 @@ class BaseStore(Generic[K, V], ABC):
|
||||
"""
|
||||
|
||||
async def amset(self, key_value_pairs: Sequence[Tuple[K, V]]) -> None:
|
||||
"""Set the values for the given keys.
|
||||
"""Async set the values for the given keys.
|
||||
|
||||
Args:
|
||||
key_value_pairs (Sequence[Tuple[K, V]]): A sequence of key-value pairs.
|
||||
@@ -131,7 +132,7 @@ class BaseStore(Generic[K, V], ABC):
|
||||
"""
|
||||
|
||||
async def amdelete(self, keys: Sequence[K]) -> None:
|
||||
"""Delete the given keys and their associated values.
|
||||
"""Async delete the given keys and their associated values.
|
||||
|
||||
Args:
|
||||
keys (Sequence[K]): A sequence of keys to delete.
|
||||
@@ -147,7 +148,7 @@ class BaseStore(Generic[K, V], ABC):
|
||||
Args:
|
||||
prefix (str): The prefix to match.
|
||||
|
||||
Returns:
|
||||
Yields:
|
||||
Iterator[K | str]: An iterator over keys that match the given prefix.
|
||||
|
||||
This method is allowed to return an iterator over either K or str
|
||||
@@ -157,12 +158,12 @@ class BaseStore(Generic[K, V], ABC):
|
||||
async def ayield_keys(
|
||||
self, *, prefix: Optional[str] = None
|
||||
) -> Union[AsyncIterator[K], AsyncIterator[str]]:
|
||||
"""Get an iterator over keys that match the given prefix.
|
||||
"""Async get an iterator over keys that match the given prefix.
|
||||
|
||||
Args:
|
||||
prefix (str): The prefix to match.
|
||||
|
||||
Returns:
|
||||
Yields:
|
||||
Iterator[K | str]: An iterator over keys that match the given prefix.
|
||||
|
||||
This method is allowed to return an iterator over either K or str
|
||||
@@ -200,7 +201,7 @@ class InMemoryBaseStore(BaseStore[str, V], Generic[V]):
|
||||
return [self.store.get(key) for key in keys]
|
||||
|
||||
async def amget(self, keys: Sequence[str]) -> List[Optional[V]]:
|
||||
"""Get the values associated with the given keys.
|
||||
"""Async get the values associated with the given keys.
|
||||
|
||||
Args:
|
||||
keys (Sequence[str]): A sequence of keys.
|
||||
@@ -224,7 +225,7 @@ class InMemoryBaseStore(BaseStore[str, V], Generic[V]):
|
||||
self.store[key] = value
|
||||
|
||||
async def amset(self, key_value_pairs: Sequence[Tuple[str, V]]) -> None:
|
||||
"""Set the values for the given keys.
|
||||
"""Async set the values for the given keys.
|
||||
|
||||
Args:
|
||||
key_value_pairs (Sequence[Tuple[str, V]]): A sequence of key-value pairs.
|
||||
@@ -245,7 +246,7 @@ class InMemoryBaseStore(BaseStore[str, V], Generic[V]):
|
||||
del self.store[key]
|
||||
|
||||
async def amdelete(self, keys: Sequence[str]) -> None:
|
||||
"""Delete the given keys and their associated values.
|
||||
"""Async delete the given keys and their associated values.
|
||||
|
||||
Args:
|
||||
keys (Sequence[str]): A sequence of keys to delete.
|
||||
@@ -258,7 +259,7 @@ class InMemoryBaseStore(BaseStore[str, V], Generic[V]):
|
||||
Args:
|
||||
prefix (str, optional): The prefix to match. Defaults to None.
|
||||
|
||||
Returns:
|
||||
Yields:
|
||||
Iterator[str]: An iterator over keys that match the given prefix.
|
||||
"""
|
||||
if prefix is None:
|
||||
@@ -269,12 +270,12 @@ class InMemoryBaseStore(BaseStore[str, V], Generic[V]):
|
||||
yield key
|
||||
|
||||
async def ayield_keys(self, prefix: Optional[str] = None) -> AsyncIterator[str]:
|
||||
"""Get an async iterator over keys that match the given prefix.
|
||||
"""Async get an async iterator over keys that match the given prefix.
|
||||
|
||||
Args:
|
||||
prefix (str, optional): The prefix to match. Defaults to None.
|
||||
|
||||
Returns:
|
||||
Yields:
|
||||
AsyncIterator[str]: An async iterator over keys that match the given prefix.
|
||||
"""
|
||||
if prefix is None:
|
||||
|
||||
@@ -827,6 +827,8 @@ class StructuredTool(BaseTool):
|
||||
raise ValueError("Function and/or coroutine must be provided")
|
||||
name = name or source_function.__name__
|
||||
description_ = description or source_function.__doc__
|
||||
if description_ is None and args_schema:
|
||||
description_ = args_schema.__doc__
|
||||
if description_ is None:
|
||||
raise ValueError(
|
||||
"Function must have a docstring if description not provided."
|
||||
|
||||
@@ -311,6 +311,10 @@ def test_schemas(snapshot: SnapshotAssertion) -> None:
|
||||
"properties": {
|
||||
"page_content": {"title": "Page Content", "type": "string"},
|
||||
"metadata": {"title": "Metadata", "type": "object"},
|
||||
"id": {
|
||||
"title": "Id",
|
||||
"type": "string",
|
||||
},
|
||||
"type": {
|
||||
"title": "Type",
|
||||
"enum": ["Document"],
|
||||
|
||||
@@ -44,6 +44,8 @@ def test_unnamed_decorator() -> None:
|
||||
|
||||
|
||||
class _MockSchema(BaseModel):
|
||||
"""Return the arguments directly."""
|
||||
|
||||
arg1: int
|
||||
arg2: bool
|
||||
arg3: Optional[dict] = None
|
||||
@@ -133,7 +135,6 @@ def test_decorator_with_specified_schema() -> None:
|
||||
|
||||
@tool(args_schema=_MockSchema)
|
||||
def tool_func(arg1: int, arg2: bool, arg3: Optional[dict] = None) -> str:
|
||||
"""Return the arguments directly."""
|
||||
return f"{arg1} {arg2} {arg3}"
|
||||
|
||||
assert isinstance(tool_func, BaseTool)
|
||||
|
||||
@@ -770,7 +770,7 @@ class Agent(BaseSingleActionAgent):
|
||||
"""
|
||||
return list(set(self.llm_chain.input_keys) - {"agent_scratchpad"})
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=False, skip_on_failure=True)
|
||||
def validate_prompt(cls, values: Dict) -> Dict:
|
||||
"""Validate that prompt matches format."""
|
||||
prompt = values["llm_chain"].prompt
|
||||
@@ -974,7 +974,7 @@ class AgentExecutor(Chain):
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=False, skip_on_failure=True)
|
||||
def validate_tools(cls, values: Dict) -> Dict:
|
||||
"""Validate that tools are compatible with agent."""
|
||||
agent = values["agent"]
|
||||
@@ -988,7 +988,7 @@ class AgentExecutor(Chain):
|
||||
)
|
||||
return values
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=False, skip_on_failure=True)
|
||||
def validate_return_direct_tool(cls, values: Dict) -> Dict:
|
||||
"""Validate that tools are compatible with agent."""
|
||||
agent = values["agent"]
|
||||
@@ -1005,8 +1005,8 @@ class AgentExecutor(Chain):
|
||||
@root_validator(pre=True)
|
||||
def validate_runnable_agent(cls, values: Dict) -> Dict:
|
||||
"""Convert runnable to agent if passed in."""
|
||||
agent = values["agent"]
|
||||
if isinstance(agent, Runnable):
|
||||
agent = values.get("agent")
|
||||
if agent and isinstance(agent, Runnable):
|
||||
try:
|
||||
output_type = agent.OutputType
|
||||
except Exception as _:
|
||||
|
||||
@@ -14,12 +14,12 @@ from langchain.agents.output_parsers.tools import ToolAgentAction
|
||||
def _create_tool_message(
|
||||
agent_action: ToolAgentAction, observation: str
|
||||
) -> ToolMessage:
|
||||
"""Convert agent action and observation into a function message.
|
||||
"""Convert agent action and observation into a tool message.
|
||||
Args:
|
||||
agent_action: the tool invocation request from the agent
|
||||
observation: the result of the tool invocation
|
||||
Returns:
|
||||
FunctionMessage that corresponds to the original tool invocation
|
||||
ToolMessage that corresponds to the original tool invocation
|
||||
"""
|
||||
if not isinstance(observation, str):
|
||||
try:
|
||||
@@ -38,7 +38,7 @@ def _create_tool_message(
|
||||
def format_to_tool_messages(
|
||||
intermediate_steps: Sequence[Tuple[AgentAction, str]],
|
||||
) -> List[BaseMessage]:
|
||||
"""Convert (AgentAction, tool output) tuples into FunctionMessages.
|
||||
"""Convert (AgentAction, tool output) tuples into ToolMessages.
|
||||
|
||||
Args:
|
||||
intermediate_steps: Steps the LLM has taken to date, along with observations
|
||||
|
||||
@@ -210,7 +210,7 @@ class OpenAIAssistantRunnable(RunnableSerializable[Dict, OutputType]):
|
||||
as_agent: bool = False
|
||||
"""Use as a LangChain agent, compatible with the AgentExecutor."""
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=False, skip_on_failure=True)
|
||||
def validate_async_client(cls, values: dict) -> dict:
|
||||
if values["async_client"] is None:
|
||||
import openai
|
||||
|
||||
@@ -54,7 +54,7 @@ class OpenAIFunctionsAgent(BaseSingleActionAgent):
|
||||
"""Get allowed tools."""
|
||||
return [t.name for t in self.tools]
|
||||
|
||||
@root_validator
|
||||
@root_validator(pre=False, skip_on_failure=True)
|
||||
def validate_prompt(cls, values: dict) -> dict:
|
||||
prompt: BasePromptTemplate = values["prompt"]
|
||||
if "agent_scratchpad" not in prompt.input_variables:
|
||||
|
||||
@@ -114,7 +114,7 @@ class OpenAIMultiFunctionsAgent(BaseMultiActionAgent):
|
||||
"""Get allowed tools."""
|
||||
return [t.name for t in self.tools]
|
||||
|
||||
@root_validator
|
||||
@root_validator(pre=False, skip_on_failure=True)
|
||||
def validate_prompt(cls, values: dict) -> dict:
|
||||
prompt: BasePromptTemplate = values["prompt"]
|
||||
if "agent_scratchpad" not in prompt.input_variables:
|
||||
|
||||
@@ -106,7 +106,7 @@ try:
|
||||
"""
|
||||
return [self.output_key]
|
||||
|
||||
@root_validator(pre=True)
|
||||
@root_validator(pre=False, skip_on_failure=True)
|
||||
def validate_api_request_prompt(cls, values: Dict) -> Dict:
|
||||
"""Check that api request prompt expects the right variables."""
|
||||
input_vars = values["api_request_chain"].prompt.input_variables
|
||||
@@ -120,6 +120,8 @@ try:
|
||||
@root_validator(pre=True)
|
||||
def validate_limit_to_domains(cls, values: Dict) -> Dict:
|
||||
"""Check that allowed domains are valid."""
|
||||
# This check must be a pre=True check, so that a default of None
|
||||
# won't be set to limit_to_domains if it's not provided.
|
||||
if "limit_to_domains" not in values:
|
||||
raise ValueError(
|
||||
"You must specify a list of domains to limit access using "
|
||||
@@ -135,7 +137,7 @@ try:
|
||||
)
|
||||
return values
|
||||
|
||||
@root_validator(pre=True)
|
||||
@root_validator(pre=False, skip_on_failure=True)
|
||||
def validate_api_answer_prompt(cls, values: Dict) -> Dict:
|
||||
"""Check that api answer prompt expects the right variables."""
|
||||
input_vars = values["api_answer_chain"].prompt.input_variables
|
||||
|
||||
@@ -225,7 +225,7 @@ class Chain(RunnableSerializable[Dict[str, Any], Dict[str, Any]], ABC):
|
||||
def _chain_type(self) -> str:
|
||||
raise NotImplementedError("Saving not supported for this chain type.")
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=True)
|
||||
def raise_callback_manager_deprecation(cls, values: Dict) -> Dict:
|
||||
"""Raise deprecation warning if callback_manager is used."""
|
||||
if values.get("callback_manager") is not None:
|
||||
|
||||
@@ -166,8 +166,11 @@ class MapReduceDocumentsChain(BaseCombineDocumentsChain):
|
||||
@root_validator(pre=True)
|
||||
def get_default_document_variable_name(cls, values: Dict) -> Dict:
|
||||
"""Get default document variable name, if not provided."""
|
||||
if "llm_chain" not in values:
|
||||
raise ValueError("llm_chain must be provided")
|
||||
|
||||
llm_chain_variables = values["llm_chain"].prompt.input_variables
|
||||
if "document_variable_name" not in values:
|
||||
llm_chain_variables = values["llm_chain"].prompt.input_variables
|
||||
if len(llm_chain_variables) == 1:
|
||||
values["document_variable_name"] = llm_chain_variables[0]
|
||||
else:
|
||||
@@ -176,7 +179,6 @@ class MapReduceDocumentsChain(BaseCombineDocumentsChain):
|
||||
"multiple llm_chain input_variables"
|
||||
)
|
||||
else:
|
||||
llm_chain_variables = values["llm_chain"].prompt.input_variables
|
||||
if values["document_variable_name"] not in llm_chain_variables:
|
||||
raise ValueError(
|
||||
f"document_variable_name {values['document_variable_name']} was "
|
||||
|
||||
@@ -106,7 +106,7 @@ class MapRerankDocumentsChain(BaseCombineDocumentsChain):
|
||||
_output_keys += self.metadata_keys
|
||||
return _output_keys
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=False, skip_on_failure=True)
|
||||
def validate_llm_output(cls, values: Dict) -> Dict:
|
||||
"""Validate that the combine chain outputs a dictionary."""
|
||||
output_parser = values["llm_chain"].prompt.output_parser
|
||||
@@ -131,8 +131,11 @@ class MapRerankDocumentsChain(BaseCombineDocumentsChain):
|
||||
@root_validator(pre=True)
|
||||
def get_default_document_variable_name(cls, values: Dict) -> Dict:
|
||||
"""Get default document variable name, if not provided."""
|
||||
if "llm_chain" not in values:
|
||||
raise ValueError("llm_chain must be provided")
|
||||
|
||||
llm_chain_variables = values["llm_chain"].prompt.input_variables
|
||||
if "document_variable_name" not in values:
|
||||
llm_chain_variables = values["llm_chain"].prompt.input_variables
|
||||
if len(llm_chain_variables) == 1:
|
||||
values["document_variable_name"] = llm_chain_variables[0]
|
||||
else:
|
||||
@@ -141,7 +144,6 @@ class MapRerankDocumentsChain(BaseCombineDocumentsChain):
|
||||
"multiple llm_chain input_variables"
|
||||
)
|
||||
else:
|
||||
llm_chain_variables = values["llm_chain"].prompt.input_variables
|
||||
if values["document_variable_name"] not in llm_chain_variables:
|
||||
raise ValueError(
|
||||
f"document_variable_name {values['document_variable_name']} was "
|
||||
|
||||
@@ -115,8 +115,11 @@ class RefineDocumentsChain(BaseCombineDocumentsChain):
|
||||
@root_validator(pre=True)
|
||||
def get_default_document_variable_name(cls, values: Dict) -> Dict:
|
||||
"""Get default document variable name, if not provided."""
|
||||
if "initial_llm_chain" not in values:
|
||||
raise ValueError("initial_llm_chain must be provided")
|
||||
|
||||
llm_chain_variables = values["initial_llm_chain"].prompt.input_variables
|
||||
if "document_variable_name" not in values:
|
||||
llm_chain_variables = values["initial_llm_chain"].prompt.input_variables
|
||||
if len(llm_chain_variables) == 1:
|
||||
values["document_variable_name"] = llm_chain_variables[0]
|
||||
else:
|
||||
@@ -125,7 +128,6 @@ class RefineDocumentsChain(BaseCombineDocumentsChain):
|
||||
"multiple llm_chain input_variables"
|
||||
)
|
||||
else:
|
||||
llm_chain_variables = values["initial_llm_chain"].prompt.input_variables
|
||||
if values["document_variable_name"] not in llm_chain_variables:
|
||||
raise ValueError(
|
||||
f"document_variable_name {values['document_variable_name']} was "
|
||||
|
||||
@@ -45,7 +45,7 @@ class ConversationChain(LLMChain):
|
||||
"""Use this since so some prompt vars come from history."""
|
||||
return [self.input_key]
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=False, skip_on_failure=True)
|
||||
def validate_prompt_input_variables(cls, values: Dict) -> Dict:
|
||||
"""Validate that prompt input variables are consistent."""
|
||||
memory_keys = values["memory"].memory_variables
|
||||
|
||||
@@ -480,7 +480,7 @@ class ChatVectorDBChain(BaseConversationalRetrievalChain):
|
||||
def _chain_type(self) -> str:
|
||||
return "chat-vector-db"
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=True)
|
||||
def raise_deprecation(cls, values: Dict) -> Dict:
|
||||
warnings.warn(
|
||||
"`ChatVectorDBChain` is deprecated - "
|
||||
|
||||
@@ -56,7 +56,7 @@ class ElasticsearchDatabaseChain(Chain):
|
||||
extra = Extra.forbid
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=False, skip_on_failure=True)
|
||||
def validate_indices(cls, values: dict) -> dict:
|
||||
if values["include_indices"] and values["ignore_indices"]:
|
||||
raise ValueError(
|
||||
|
||||
@@ -40,7 +40,7 @@ class OpenAIModerationChain(Chain):
|
||||
openai_organization: Optional[str] = None
|
||||
_openai_pre_1_0: bool = Field(default=None)
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=True)
|
||||
def validate_environment(cls, values: Dict) -> Dict:
|
||||
"""Validate that api key and python package exists in environment."""
|
||||
openai_api_key = get_from_dict_or_env(
|
||||
|
||||
@@ -61,7 +61,7 @@ class VectorDBQAWithSourcesChain(BaseQAWithSourcesChain):
|
||||
) -> List[Document]:
|
||||
raise NotImplementedError("VectorDBQAWithSourcesChain does not support async")
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=True)
|
||||
def raise_deprecation(cls, values: Dict) -> Dict:
|
||||
warnings.warn(
|
||||
"`VectorDBQAWithSourcesChain` is deprecated - "
|
||||
|
||||
@@ -284,7 +284,7 @@ class VectorDBQA(BaseRetrievalQA):
|
||||
search_kwargs: Dict[str, Any] = Field(default_factory=dict)
|
||||
"""Extra search args."""
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=True)
|
||||
def raise_deprecation(cls, values: Dict) -> Dict:
|
||||
warnings.warn(
|
||||
"`VectorDBQA` is deprecated - "
|
||||
@@ -292,7 +292,7 @@ class VectorDBQA(BaseRetrievalQA):
|
||||
)
|
||||
return values
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=True)
|
||||
def validate_search_type(cls, values: Dict) -> Dict:
|
||||
"""Validate search type."""
|
||||
if "search_type" in values:
|
||||
|
||||
@@ -24,7 +24,7 @@ class LLMRouterChain(RouterChain):
|
||||
llm_chain: LLMChain
|
||||
"""LLM chain used to perform routing"""
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=False, skip_on_failure=True)
|
||||
def validate_prompt(cls, values: dict) -> dict:
|
||||
prompt = values["llm_chain"].prompt
|
||||
if prompt.output_parser is None:
|
||||
|
||||
@@ -152,7 +152,7 @@ class SimpleSequentialChain(Chain):
|
||||
"""
|
||||
return [self.output_key]
|
||||
|
||||
@root_validator()
|
||||
@root_validator(pre=False, skip_on_failure=True)
|
||||
def validate_chains(cls, values: Dict) -> Dict:
|
||||
"""Validate that chains are all single input/output."""
|
||||
for chain in values["chains"]:
|
||||
|
||||
@@ -48,6 +48,9 @@ from langchain.memory.summary import ConversationSummaryMemory
|
||||
from langchain.memory.summary_buffer import ConversationSummaryBufferMemory
|
||||
from langchain.memory.token_buffer import ConversationTokenBufferMemory
|
||||
from langchain.memory.vectorstore import VectorStoreRetrieverMemory
|
||||
from langchain.memory.vectorstore_token_buffer_memory import (
|
||||
ConversationVectorStoreTokenBufferMemory, # avoid circular import
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from langchain_community.chat_message_histories import (
|
||||
@@ -122,6 +125,7 @@ __all__ = [
|
||||
"ConversationSummaryBufferMemory",
|
||||
"ConversationSummaryMemory",
|
||||
"ConversationTokenBufferMemory",
|
||||
"ConversationVectorStoreTokenBufferMemory",
|
||||
"CosmosDBChatMessageHistory",
|
||||
"DynamoDBChatMessageHistory",
|
||||
"ElasticsearchChatMessageHistory",
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
"""
|
||||
Class for a conversation memory buffer with older messages stored in a vectorstore .
|
||||
|
||||
This implementats a conversation memory in which the messages are stored in a memory
|
||||
buffer up to a specified token limit. When the limit is exceeded, older messages are
|
||||
saved to a vectorstore backing database. The vectorstore can be made persistent across
|
||||
sessions.
|
||||
"""
|
||||
|
||||
import warnings
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from langchain_core.messages import BaseMessage
|
||||
from langchain_core.prompts.chat import SystemMessagePromptTemplate
|
||||
from langchain_core.pydantic_v1 import Field, PrivateAttr
|
||||
from langchain_core.vectorstores import VectorStoreRetriever
|
||||
|
||||
from langchain.memory import ConversationTokenBufferMemory, VectorStoreRetrieverMemory
|
||||
from langchain.memory.chat_memory import BaseChatMemory
|
||||
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
||||
|
||||
DEFAULT_HISTORY_TEMPLATE = """
|
||||
Current date and time: {current_time}.
|
||||
|
||||
Potentially relevant timestamped excerpts of previous conversations (you
|
||||
do not need to use these if irrelevant):
|
||||
{previous_history}
|
||||
|
||||
"""
|
||||
|
||||
TIMESTAMP_FORMAT = "%Y-%m-%d %H:%M:%S %Z"
|
||||
|
||||
|
||||
class ConversationVectorStoreTokenBufferMemory(ConversationTokenBufferMemory):
|
||||
"""Conversation chat memory with token limit and vectordb backing.
|
||||
|
||||
load_memory_variables() will return a dict with the key "history".
|
||||
It contains background information retrieved from the vector store
|
||||
plus recent lines of the current conversation.
|
||||
|
||||
To help the LLM understand the part of the conversation stored in the
|
||||
vectorstore, each interaction is timestamped and the current date and
|
||||
time is also provided in the history. A side effect of this is that the
|
||||
LLM will have access to the current date and time.
|
||||
|
||||
Initialization arguments:
|
||||
|
||||
This class accepts all the initialization arguments of
|
||||
ConversationTokenBufferMemory, such as `llm`. In addition, it
|
||||
accepts the following additional arguments
|
||||
|
||||
retriever: (required) A VectorStoreRetriever object to use
|
||||
as the vector backing store
|
||||
|
||||
split_chunk_size: (optional, 1000) Token chunk split size
|
||||
for long messages generated by the AI
|
||||
|
||||
previous_history_template: (optional) Template used to format
|
||||
the contents of the prompt history
|
||||
|
||||
|
||||
Example using ChromaDB:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from langchain.memory.token_buffer_vectorstore_memory import (
|
||||
ConversationVectorStoreTokenBufferMemory
|
||||
)
|
||||
from langchain_community.vectorstores import Chroma
|
||||
from langchain_community.embeddings import HuggingFaceInstructEmbeddings
|
||||
from langchain_openai import OpenAI
|
||||
|
||||
embedder = HuggingFaceInstructEmbeddings(
|
||||
query_instruction="Represent the query for retrieval: "
|
||||
)
|
||||
chroma = Chroma(collection_name="demo",
|
||||
embedding_function=embedder,
|
||||
collection_metadata={"hnsw:space": "cosine"},
|
||||
)
|
||||
|
||||
retriever = chroma.as_retriever(
|
||||
search_type="similarity_score_threshold",
|
||||
search_kwargs={
|
||||
'k': 5,
|
||||
'score_threshold': 0.75,
|
||||
},
|
||||
)
|
||||
|
||||
conversation_memory = ConversationVectorStoreTokenBufferMemory(
|
||||
return_messages=True,
|
||||
llm=OpenAI(),
|
||||
retriever=retriever,
|
||||
max_token_limit = 1000,
|
||||
)
|
||||
|
||||
conversation_memory.save_context({"Human": "Hi there"},
|
||||
{"AI": "Nice to meet you!"}
|
||||
)
|
||||
conversation_memory.save_context({"Human": "Nice day isn't it?"},
|
||||
{"AI": "I love Wednesdays."}
|
||||
)
|
||||
conversation_memory.load_memory_variables({"input": "What time is it?"})
|
||||
|
||||
"""
|
||||
|
||||
retriever: VectorStoreRetriever = Field(exclude=True)
|
||||
memory_key: str = "history"
|
||||
previous_history_template: str = DEFAULT_HISTORY_TEMPLATE
|
||||
split_chunk_size: int = 1000
|
||||
|
||||
_memory_retriever: VectorStoreRetrieverMemory = PrivateAttr(default=None)
|
||||
_timestamps: List[datetime] = PrivateAttr(default_factory=list)
|
||||
|
||||
@property
|
||||
def memory_retriever(self) -> VectorStoreRetrieverMemory:
|
||||
"""Return a memory retriever from the passed retriever object."""
|
||||
if self._memory_retriever is not None:
|
||||
return self._memory_retriever
|
||||
self._memory_retriever = VectorStoreRetrieverMemory(retriever=self.retriever)
|
||||
return self._memory_retriever
|
||||
|
||||
def load_memory_variables(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Return history and memory buffer."""
|
||||
try:
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore")
|
||||
memory_variables = self.memory_retriever.load_memory_variables(inputs)
|
||||
previous_history = memory_variables[self.memory_retriever.memory_key]
|
||||
except AssertionError: # happens when db is empty
|
||||
previous_history = ""
|
||||
current_history = super().load_memory_variables(inputs)
|
||||
template = SystemMessagePromptTemplate.from_template(
|
||||
self.previous_history_template
|
||||
)
|
||||
messages = [
|
||||
template.format(
|
||||
previous_history=previous_history,
|
||||
current_time=datetime.now().astimezone().strftime(TIMESTAMP_FORMAT),
|
||||
)
|
||||
]
|
||||
messages.extend(current_history[self.memory_key])
|
||||
return {self.memory_key: messages}
|
||||
|
||||
def save_context(self, inputs: Dict[str, Any], outputs: Dict[str, str]) -> None:
|
||||
"""Save context from this conversation to buffer. Pruned."""
|
||||
BaseChatMemory.save_context(self, inputs, outputs)
|
||||
self._timestamps.append(datetime.now().astimezone())
|
||||
# Prune buffer if it exceeds max token limit
|
||||
buffer = self.chat_memory.messages
|
||||
curr_buffer_length = self.llm.get_num_tokens_from_messages(buffer)
|
||||
if curr_buffer_length > self.max_token_limit:
|
||||
while curr_buffer_length > self.max_token_limit:
|
||||
self._pop_and_store_interaction(buffer)
|
||||
curr_buffer_length = self.llm.get_num_tokens_from_messages(buffer)
|
||||
|
||||
def save_remainder(self) -> None:
|
||||
"""
|
||||
Save the remainder of the conversation buffer to the vector store.
|
||||
|
||||
This is useful if you have made the vectorstore persistent, in which
|
||||
case this can be called before the end of the session to store the
|
||||
remainder of the conversation.
|
||||
"""
|
||||
buffer = self.chat_memory.messages
|
||||
while len(buffer) > 0:
|
||||
self._pop_and_store_interaction(buffer)
|
||||
|
||||
def _pop_and_store_interaction(self, buffer: List[BaseMessage]) -> None:
|
||||
input = buffer.pop(0)
|
||||
output = buffer.pop(0)
|
||||
timestamp = self._timestamps.pop(0).strftime(TIMESTAMP_FORMAT)
|
||||
# Split AI output into smaller chunks to avoid creating documents
|
||||
# that will overflow the context window
|
||||
ai_chunks = self._split_long_ai_text(str(output.content))
|
||||
for index, chunk in enumerate(ai_chunks):
|
||||
self.memory_retriever.save_context(
|
||||
{"Human": f"<{timestamp}/00> {str(input.content)}"},
|
||||
{"AI": f"<{timestamp}/{index:02}> {chunk}"},
|
||||
)
|
||||
|
||||
def _split_long_ai_text(self, text: str) -> List[str]:
|
||||
splitter = RecursiveCharacterTextSplitter(chunk_size=self.split_chunk_size)
|
||||
return [chunk.page_content for chunk in splitter.create_documents([text])]
|
||||
@@ -13,6 +13,7 @@ EXPECTED_ALL = [
|
||||
"ConversationSummaryBufferMemory",
|
||||
"ConversationSummaryMemory",
|
||||
"ConversationTokenBufferMemory",
|
||||
"ConversationVectorStoreTokenBufferMemory",
|
||||
"CosmosDBChatMessageHistory",
|
||||
"DynamoDBChatMessageHistory",
|
||||
"ElasticsearchChatMessageHistory",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# langchain-ai21
|
||||
|
||||
This package contains the LangChain integrations for [AI21](https://docs.ai21.com/) through their [AI21](https://pypi.org/project/ai21/) SDK.
|
||||
This package contains the LangChain integrations for [AI21](https://docs.ai21.com/) models and tools.
|
||||
|
||||
## Installation and Setup
|
||||
|
||||
@@ -13,9 +13,10 @@ pip install langchain-ai21
|
||||
|
||||
## Chat Models
|
||||
|
||||
This package contains the `ChatAI21` class, which is the recommended way to interface with AI21 Chat models.
|
||||
This package contains the `ChatAI21` class, which is the recommended way to interface with AI21 chat models, including Jamba-Instruct
|
||||
and any Jurassic chat models.
|
||||
|
||||
To use, install the requirements, and configure your environment.
|
||||
To use, install the requirements and configure your environment.
|
||||
|
||||
```bash
|
||||
export AI21_API_KEY=your-api-key
|
||||
@@ -27,7 +28,7 @@ Then initialize
|
||||
from langchain_core.messages import HumanMessage
|
||||
from langchain_ai21.chat_models import ChatAI21
|
||||
|
||||
chat = ChatAI21(model="jamab-instruct")
|
||||
chat = ChatAI21(model="jamba-instruct-preview")
|
||||
messages = [HumanMessage(content="Hello from AI21")]
|
||||
chat.invoke(messages)
|
||||
```
|
||||
@@ -35,10 +36,12 @@ chat.invoke(messages)
|
||||
For a list of the supported models, see [this page](https://docs.ai21.com/reference/python-sdk#chat)
|
||||
|
||||
## LLMs
|
||||
You can use AI21's generative AI models as Langchain LLMs:
|
||||
You can use AI21's Jurassic generative AI models as LangChain LLMs.
|
||||
To use the newer Jamba model, use the [ChatAI21 chat model](#chat-models), which
|
||||
supports single-turn instruction/question answering capabilities.
|
||||
|
||||
```python
|
||||
from langchain.prompts import PromptTemplate
|
||||
from langchain_core.prompts import PromptTemplate
|
||||
from langchain_ai21 import AI21LLM
|
||||
|
||||
llm = AI21LLM(model="j2-ultra")
|
||||
@@ -56,7 +59,7 @@ print(chain.invoke({"question": question}))
|
||||
|
||||
## Embeddings
|
||||
|
||||
You can use AI21's embeddings models as:
|
||||
You can use AI21's [embeddings model](https://docs.ai21.com/reference/embeddings-ref) as shown here:
|
||||
|
||||
### Query
|
||||
|
||||
@@ -76,12 +79,12 @@ embeddings = AI21Embeddings()
|
||||
embeddings.embed_documents(["Hello! This is document 1", "And this is document 2!"])
|
||||
```
|
||||
|
||||
## Task Specific Models
|
||||
## Task-Specific Models
|
||||
|
||||
### Contextual Answers
|
||||
|
||||
You can use AI21's contextual answers model to receives text or document, serving as a context,
|
||||
and a question and returns an answer based entirely on this context.
|
||||
You can use AI21's [contextual answers model](https://docs.ai21.com/reference/contextual-answers-ref) to parse
|
||||
given text and answer a question based entirely on the provided information.
|
||||
|
||||
This means that if the answer to your question is not in the document,
|
||||
the model will indicate it (instead of providing a false answer)
|
||||
@@ -91,7 +94,7 @@ from langchain_ai21 import AI21ContextualAnswers
|
||||
|
||||
tsm = AI21ContextualAnswers()
|
||||
|
||||
response = tsm.invoke(input={"context": "Your context", "question": "Your question"})
|
||||
response = tsm.invoke(input={"context": "Lots of information here", "question": "Your question about the context"})
|
||||
```
|
||||
You can also use it with chains and output parsers and vector DBs:
|
||||
```python
|
||||
@@ -110,8 +113,8 @@ response = chain.invoke(
|
||||
|
||||
### Semantic Text Splitter
|
||||
|
||||
You can use AI21's semantic text splitter to split a text into segments.
|
||||
Instead of merely using punctuation and newlines to divide the text, it identifies distinct topics that will work well together and will form a coherent piece of text.
|
||||
You can use AI21's semantic [text segmentation model](https://docs.ai21.com/reference/text-segmentation-ref) to split a text into segments by topic.
|
||||
Text is split at each point where the topic changes.
|
||||
|
||||
For a list for examples, see [this page](https://github.com/langchain-ai/langchain/blob/master/docs/docs/modules/data_connection/document_transformers/semantic_text_splitter.ipynb).
|
||||
|
||||
|
||||
@@ -19,7 +19,10 @@ from langchain_ai21.chat.chat_factory import create_chat_adapter
|
||||
|
||||
|
||||
class ChatAI21(BaseChatModel, AI21Base):
|
||||
"""ChatAI21 chat model.
|
||||
"""ChatAI21 chat model. Different model types support different parameters and
|
||||
different parameter values. Please read the [AI21 reference documentation]
|
||||
(https://docs.ai21.com/reference) for your model to understand which parameters
|
||||
are available.
|
||||
|
||||
Example:
|
||||
.. code-block:: python
|
||||
@@ -27,7 +30,10 @@ class ChatAI21(BaseChatModel, AI21Base):
|
||||
from langchain_ai21 import ChatAI21
|
||||
|
||||
|
||||
model = ChatAI21()
|
||||
model = ChatAI21(
|
||||
# defaults to os.environ.get("AI21_API_KEY")
|
||||
api_key="my_api_key"
|
||||
)
|
||||
"""
|
||||
|
||||
model: str
|
||||
@@ -42,7 +48,8 @@ class ChatAI21(BaseChatModel, AI21Base):
|
||||
"""The maximum number of tokens to generate for each response."""
|
||||
|
||||
min_tokens: int = 0
|
||||
"""The minimum number of tokens to generate for each response."""
|
||||
"""The minimum number of tokens to generate for each response.
|
||||
_Not supported for all models._"""
|
||||
|
||||
temperature: float = 0.7
|
||||
"""A value controlling the "creativity" of the model's responses."""
|
||||
@@ -51,17 +58,20 @@ class ChatAI21(BaseChatModel, AI21Base):
|
||||
"""A value controlling the diversity of the model's responses."""
|
||||
|
||||
top_k_return: int = 0
|
||||
"""The number of top-scoring tokens to consider for each generation step."""
|
||||
"""The number of top-scoring tokens to consider for each generation step.
|
||||
_Not supported for all models._"""
|
||||
|
||||
frequency_penalty: Optional[Any] = None
|
||||
"""A penalty applied to tokens that are frequently generated."""
|
||||
"""A penalty applied to tokens that are frequently generated.
|
||||
_Not supported for all models._"""
|
||||
|
||||
presence_penalty: Optional[Any] = None
|
||||
""" A penalty applied to tokens that are already present in the prompt."""
|
||||
""" A penalty applied to tokens that are already present in the prompt.
|
||||
_Not supported for all models._"""
|
||||
|
||||
count_penalty: Optional[Any] = None
|
||||
"""A penalty applied to tokens based on their frequency
|
||||
in the generated responses."""
|
||||
in the generated responses. _Not supported for all models._"""
|
||||
|
||||
n: int = 1
|
||||
"""Number of chat completions to generate for each prompt."""
|
||||
|
||||
@@ -19,14 +19,24 @@ from langchain_ai21.ai21_base import AI21Base
|
||||
|
||||
|
||||
class AI21LLM(BaseLLM, AI21Base):
|
||||
"""AI21 large language models.
|
||||
"""AI21 large language models. Different model types support different parameters
|
||||
and different parameter values. Please read the [AI21 reference documentation]
|
||||
(https://docs.ai21.com/reference) for your model to understand which parameters
|
||||
are available.
|
||||
|
||||
AI21LLM supports only the older Jurassic models.
|
||||
We recommend using ChatAI21 with the newest models, for better results and more
|
||||
features.
|
||||
|
||||
Example:
|
||||
.. code-block:: python
|
||||
|
||||
from langchain_ai21 import AI21LLM
|
||||
|
||||
model = AI21LLM()
|
||||
model = AI21LLM(
|
||||
# defaults to os.environ.get("AI21_API_KEY")
|
||||
api_key="my_api_key"
|
||||
)
|
||||
"""
|
||||
|
||||
model: str
|
||||
@@ -40,7 +50,8 @@ class AI21LLM(BaseLLM, AI21Base):
|
||||
"""The maximum number of tokens to generate for each response."""
|
||||
|
||||
min_tokens: int = 0
|
||||
"""The minimum number of tokens to generate for each response."""
|
||||
"""The minimum number of tokens to generate for each response.
|
||||
_Not supported for all models._"""
|
||||
|
||||
temperature: float = 0.7
|
||||
"""A value controlling the "creativity" of the model's responses."""
|
||||
@@ -49,17 +60,20 @@ class AI21LLM(BaseLLM, AI21Base):
|
||||
"""A value controlling the diversity of the model's responses."""
|
||||
|
||||
top_k_return: int = 0
|
||||
"""The number of top-scoring tokens to consider for each generation step."""
|
||||
"""The number of top-scoring tokens to consider for each generation step.
|
||||
_Not supported for all models._"""
|
||||
|
||||
frequency_penalty: Optional[Any] = None
|
||||
"""A penalty applied to tokens that are frequently generated."""
|
||||
"""A penalty applied to tokens that are frequently generated.
|
||||
_Not supported for all models._"""
|
||||
|
||||
presence_penalty: Optional[Any] = None
|
||||
""" A penalty applied to tokens that are already present in the prompt."""
|
||||
""" A penalty applied to tokens that are already present in the prompt.
|
||||
_Not supported for all models._"""
|
||||
|
||||
count_penalty: Optional[Any] = None
|
||||
"""A penalty applied to tokens based on their frequency
|
||||
in the generated responses."""
|
||||
in the generated responses. _Not supported for all models._"""
|
||||
|
||||
custom_model: Optional[str] = None
|
||||
epoch: Optional[int] = None
|
||||
|
||||
114
libs/partners/anthropic/poetry.lock
generated
114
libs/partners/anthropic/poetry.lock
generated
@@ -511,7 +511,7 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain-core"
|
||||
version = "0.2.9"
|
||||
version = "0.2.10"
|
||||
description = "Building applications with LLMs through composability"
|
||||
optional = false
|
||||
python-versions = ">=3.8.1,<4.0"
|
||||
@@ -706,25 +706,6 @@ files = [
|
||||
dev = ["pre-commit", "tox"]
|
||||
testing = ["pytest", "pytest-benchmark"]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.7.1"
|
||||
description = "Data validation using Python type hints"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pydantic-2.7.1-py3-none-any.whl", hash = "sha256:e029badca45266732a9a79898a15ae2e8b14840b1eabbb25844be28f0b33f3d5"},
|
||||
{file = "pydantic-2.7.1.tar.gz", hash = "sha256:e9dbb5eada8abe4d9ae5f46b9939aead650cd2b68f249bb3a8139dbe125803cc"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
annotated-types = ">=0.4.0"
|
||||
pydantic-core = "2.18.2"
|
||||
typing-extensions = ">=4.6.1"
|
||||
|
||||
[package.extras]
|
||||
email = ["email-validator (>=2.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "2.7.4"
|
||||
@@ -744,97 +725,6 @@ typing-extensions = ">=4.6.1"
|
||||
[package.extras]
|
||||
email = ["email-validator (>=2.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.18.2"
|
||||
description = "Core functionality for Pydantic validation and serialization"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:9e08e867b306f525802df7cd16c44ff5ebbe747ff0ca6cf3fde7f36c05a59a81"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f0a21cbaa69900cbe1a2e7cad2aa74ac3cf21b10c3efb0fa0b80305274c0e8a2"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0680b1f1f11fda801397de52c36ce38ef1c1dc841a0927a94f226dea29c3ae3d"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95b9d5e72481d3780ba3442eac863eae92ae43a5f3adb5b4d0a1de89d42bb250"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fcf5cd9c4b655ad666ca332b9a081112cd7a58a8b5a6ca7a3104bc950f2038"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b5155ff768083cb1d62f3e143b49a8a3432e6789a3abee8acd005c3c7af1c74"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:553ef617b6836fc7e4df130bb851e32fe357ce36336d897fd6646d6058d980af"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89ed9eb7d616ef5714e5590e6cf7f23b02d0d539767d33561e3675d6f9e3857"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:75f7e9488238e920ab6204399ded280dc4c307d034f3924cd7f90a38b1829563"},
|
||||
{file = "pydantic_core-2.18.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ef26c9e94a8c04a1b2924149a9cb081836913818e55681722d7f29af88fe7b38"},
|
||||
{file = "pydantic_core-2.18.2-cp310-none-win32.whl", hash = "sha256:182245ff6b0039e82b6bb585ed55a64d7c81c560715d1bad0cbad6dfa07b4027"},
|
||||
{file = "pydantic_core-2.18.2-cp310-none-win_amd64.whl", hash = "sha256:e23ec367a948b6d812301afc1b13f8094ab7b2c280af66ef450efc357d2ae543"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:219da3f096d50a157f33645a1cf31c0ad1fe829a92181dd1311022f986e5fbe3"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:cc1cfd88a64e012b74e94cd00bbe0f9c6df57049c97f02bb07d39e9c852e19a4"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:05b7133a6e6aeb8df37d6f413f7705a37ab4031597f64ab56384c94d98fa0e90"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:224c421235f6102e8737032483f43c1a8cfb1d2f45740c44166219599358c2cd"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b14d82cdb934e99dda6d9d60dc84a24379820176cc4a0d123f88df319ae9c150"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2728b01246a3bba6de144f9e3115b532ee44bd6cf39795194fb75491824a1413"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:470b94480bb5ee929f5acba6995251ada5e059a5ef3e0dfc63cca287283ebfa6"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:997abc4df705d1295a42f95b4eec4950a37ad8ae46d913caeee117b6b198811c"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:75250dbc5290e3f1a0f4618db35e51a165186f9034eff158f3d490b3fed9f8a0"},
|
||||
{file = "pydantic_core-2.18.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4456f2dca97c425231d7315737d45239b2b51a50dc2b6f0c2bb181fce6207664"},
|
||||
{file = "pydantic_core-2.18.2-cp311-none-win32.whl", hash = "sha256:269322dcc3d8bdb69f054681edff86276b2ff972447863cf34c8b860f5188e2e"},
|
||||
{file = "pydantic_core-2.18.2-cp311-none-win_amd64.whl", hash = "sha256:800d60565aec896f25bc3cfa56d2277d52d5182af08162f7954f938c06dc4ee3"},
|
||||
{file = "pydantic_core-2.18.2-cp311-none-win_arm64.whl", hash = "sha256:1404c69d6a676245199767ba4f633cce5f4ad4181f9d0ccb0577e1f66cf4c46d"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:fb2bd7be70c0fe4dfd32c951bc813d9fe6ebcbfdd15a07527796c8204bd36242"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6132dd3bd52838acddca05a72aafb6eab6536aa145e923bb50f45e78b7251043"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7d904828195733c183d20a54230c0df0eb46ec746ea1a666730787353e87182"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c9bd70772c720142be1020eac55f8143a34ec9f82d75a8e7a07852023e46617f"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b8ed04b3582771764538f7ee7001b02e1170223cf9b75dff0bc698fadb00cf3"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e6dac87ddb34aaec85f873d737e9d06a3555a1cc1a8e0c44b7f8d5daeb89d86f"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca4ae5a27ad7a4ee5170aebce1574b375de390bc01284f87b18d43a3984df72"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:886eec03591b7cf058467a70a87733b35f44707bd86cf64a615584fd72488b7c"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca7b0c1f1c983e064caa85f3792dd2fe3526b3505378874afa84baf662e12241"},
|
||||
{file = "pydantic_core-2.18.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b4356d3538c3649337df4074e81b85f0616b79731fe22dd11b99499b2ebbdf3"},
|
||||
{file = "pydantic_core-2.18.2-cp312-none-win32.whl", hash = "sha256:8b172601454f2d7701121bbec3425dd71efcb787a027edf49724c9cefc14c038"},
|
||||
{file = "pydantic_core-2.18.2-cp312-none-win_amd64.whl", hash = "sha256:b1bd7e47b1558ea872bd16c8502c414f9e90dcf12f1395129d7bb42a09a95438"},
|
||||
{file = "pydantic_core-2.18.2-cp312-none-win_arm64.whl", hash = "sha256:98758d627ff397e752bc339272c14c98199c613f922d4a384ddc07526c86a2ec"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:9fdad8e35f278b2c3eb77cbdc5c0a49dada440657bf738d6905ce106dc1de439"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1d90c3265ae107f91a4f279f4d6f6f1d4907ac76c6868b27dc7fb33688cfb347"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:390193c770399861d8df9670fb0d1874f330c79caaca4642332df7c682bf6b91"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:82d5d4d78e4448683cb467897fe24e2b74bb7b973a541ea1dcfec1d3cbce39fb"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4774f3184d2ef3e14e8693194f661dea5a4d6ca4e3dc8e39786d33a94865cefd"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d4d938ec0adf5167cb335acb25a4ee69a8107e4984f8fbd2e897021d9e4ca21b"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e0e8b1be28239fc64a88a8189d1df7fad8be8c1ae47fcc33e43d4be15f99cc70"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:868649da93e5a3d5eacc2b5b3b9235c98ccdbfd443832f31e075f54419e1b96b"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:78363590ef93d5d226ba21a90a03ea89a20738ee5b7da83d771d283fd8a56761"},
|
||||
{file = "pydantic_core-2.18.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:852e966fbd035a6468fc0a3496589b45e2208ec7ca95c26470a54daed82a0788"},
|
||||
{file = "pydantic_core-2.18.2-cp38-none-win32.whl", hash = "sha256:6a46e22a707e7ad4484ac9ee9f290f9d501df45954184e23fc29408dfad61350"},
|
||||
{file = "pydantic_core-2.18.2-cp38-none-win_amd64.whl", hash = "sha256:d91cb5ea8b11607cc757675051f61b3d93f15eca3cefb3e6c704a5d6e8440f4e"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:ae0a8a797a5e56c053610fa7be147993fe50960fa43609ff2a9552b0e07013e8"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:042473b6280246b1dbf530559246f6842b56119c2926d1e52b631bdc46075f2a"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a388a77e629b9ec814c1b1e6b3b595fe521d2cdc625fcca26fbc2d44c816804"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25add29b8f3b233ae90ccef2d902d0ae0432eb0d45370fe315d1a5cf231004b"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f459a5ce8434614dfd39bbebf1041952ae01da6bed9855008cb33b875cb024c0"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eff2de745698eb46eeb51193a9f41d67d834d50e424aef27df2fcdee1b153845"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8309f67285bdfe65c372ea3722b7a5642680f3dba538566340a9d36e920b5f0"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f93a8a2e3938ff656a7c1bc57193b1319960ac015b6e87d76c76bf14fe0244b4"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:22057013c8c1e272eb8d0eebc796701167d8377441ec894a8fed1af64a0bf399"},
|
||||
{file = "pydantic_core-2.18.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cfeecd1ac6cc1fb2692c3d5110781c965aabd4ec5d32799773ca7b1456ac636b"},
|
||||
{file = "pydantic_core-2.18.2-cp39-none-win32.whl", hash = "sha256:0d69b4c2f6bb3e130dba60d34c0845ba31b69babdd3f78f7c0c8fae5021a253e"},
|
||||
{file = "pydantic_core-2.18.2-cp39-none-win_amd64.whl", hash = "sha256:d9319e499827271b09b4e411905b24a426b8fb69464dfa1696258f53a3334641"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:a1874c6dd4113308bd0eb568418e6114b252afe44319ead2b4081e9b9521fe75"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:ccdd111c03bfd3666bd2472b674c6899550e09e9f298954cfc896ab92b5b0e6d"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e18609ceaa6eed63753037fc06ebb16041d17d28199ae5aba0052c51449650a9"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e5c584d357c4e2baf0ff7baf44f4994be121e16a2c88918a5817331fc7599d7"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43f0f463cf89ace478de71a318b1b4f05ebc456a9b9300d027b4b57c1a2064fb"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:e1b395e58b10b73b07b7cf740d728dd4ff9365ac46c18751bf8b3d8cca8f625a"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0098300eebb1c837271d3d1a2cd2911e7c11b396eac9661655ee524a7f10587b"},
|
||||
{file = "pydantic_core-2.18.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:36789b70d613fbac0a25bb07ab3d9dba4d2e38af609c020cf4d888d165ee0bf3"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3f9a801e7c8f1ef8718da265bba008fa121243dfe37c1cea17840b0944dfd72c"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:3a6515ebc6e69d85502b4951d89131ca4e036078ea35533bb76327f8424531ce"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20aca1e2298c56ececfd8ed159ae4dde2df0781988c97ef77d5c16ff4bd5b400"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:223ee893d77a310a0391dca6df00f70bbc2f36a71a895cecd9a0e762dc37b349"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2334ce8c673ee93a1d6a65bd90327588387ba073c17e61bf19b4fd97d688d63c"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:cbca948f2d14b09d20268cda7b0367723d79063f26c4ffc523af9042cad95592"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:b3ef08e20ec49e02d5c6717a91bb5af9b20f1805583cb0adfe9ba2c6b505b5ae"},
|
||||
{file = "pydantic_core-2.18.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:c6fdc8627910eed0c01aed6a390a252fe3ea6d472ee70fdde56273f198938374"},
|
||||
{file = "pydantic_core-2.18.2.tar.gz", hash = "sha256:2e29d20810dfc3043ee13ac7d9e25105799817683348823f305ab3f349b9386e"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
|
||||
|
||||
[[package]]
|
||||
name = "pydantic-core"
|
||||
version = "2.18.4"
|
||||
@@ -1393,4 +1283,4 @@ watchmedo = ["PyYAML (>=3.10)"]
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.8.1,<4.0"
|
||||
content-hash = "e1cff75b89d41dd6b5bf1fc13f2a8c777f3820936773ed5ebaecae185db28249"
|
||||
content-hash = "d034081373197472c8639f389b9d0303e071b9b7b4734fa111cfba71a950ef19"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "langchain-anthropic"
|
||||
version = "0.1.15"
|
||||
version = "0.1.16"
|
||||
description = "An integration package connecting AnthropicMessages and LangChain"
|
||||
authors = []
|
||||
readme = "README.md"
|
||||
@@ -12,7 +12,7 @@ license = "MIT"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.8.1,<4.0"
|
||||
langchain-core = { version = ">=0.2.2rc1,<0.3", allow-prereleases = true }
|
||||
langchain-core = { version = ">=0.2.10,<0.3" }
|
||||
anthropic = ">=0.28.0,<1"
|
||||
defusedxml = { version = "^0.7.1", optional = true }
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ pip install -U langchain-mongodb
|
||||
```
|
||||
|
||||
# Usage
|
||||
- See [integrations doc](../../../docs/docs/integrations/vectorstores/mongodb.ipynb) for more in-depth usage instructions.
|
||||
- See [integrations doc](../../../docs/docs/integrations/providers/mongodb_atlas.ipynb) for more in-depth usage instructions.
|
||||
- See [Getting Started with the LangChain Integration](https://www.mongodb.com/docs/atlas/atlas-vector-search/ai-integrations/langchain/#get-started-with-the-langchain-integration) for a walkthrough on using your first LangChain implementation with MongoDB Atlas.
|
||||
|
||||
## Using MongoDBAtlasVectorSearch
|
||||
|
||||
105
libs/partners/mongodb/langchain_mongodb/index.py
Normal file
105
libs/partners/mongodb/langchain_mongodb/index.py
Normal file
@@ -0,0 +1,105 @@
|
||||
import logging
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from pymongo.collection import Collection
|
||||
from pymongo.operations import SearchIndexModel
|
||||
|
||||
logger = logging.getLogger(__file__)
|
||||
|
||||
|
||||
def _vector_search_index_definition(
|
||||
dimensions: int,
|
||||
path: str,
|
||||
similarity: str,
|
||||
filters: Optional[List[Dict[str, str]]],
|
||||
) -> Dict[str, Any]:
|
||||
return {
|
||||
"fields": [
|
||||
{
|
||||
"numDimensions": dimensions,
|
||||
"path": path,
|
||||
"similarity": similarity,
|
||||
"type": "vector",
|
||||
},
|
||||
*(filters or []),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def create_vector_search_index(
|
||||
collection: Collection,
|
||||
index_name: str,
|
||||
dimensions: int,
|
||||
path: str,
|
||||
similarity: str,
|
||||
filters: List[Dict[str, str]],
|
||||
) -> None:
|
||||
"""Experimental Utility function to create a vector search index
|
||||
|
||||
Args:
|
||||
collection (Collection): MongoDB Collection
|
||||
index_name (str): Name of Index
|
||||
dimensions (int): Number of dimensions in embedding
|
||||
path (str): field with vector embedding
|
||||
similarity (str): The similarity score used for the index
|
||||
filters (List[Dict[str, str]]): additional filters for index definition.
|
||||
"""
|
||||
logger.info("Creating Search Index %s on %s", index_name, collection.name)
|
||||
result = collection.create_search_index(
|
||||
SearchIndexModel(
|
||||
definition=_vector_search_index_definition(
|
||||
dimensions=dimensions, path=path, similarity=similarity, filters=filters
|
||||
),
|
||||
name=index_name,
|
||||
type="vectorSearch",
|
||||
)
|
||||
)
|
||||
logger.info(result)
|
||||
|
||||
|
||||
def drop_vector_search_index(collection: Collection, index_name: str) -> None:
|
||||
"""Drop a created vector search index
|
||||
|
||||
Args:
|
||||
collection (Collection): MongoDB Collection with index to be dropped
|
||||
index_name (str): Name of the MongoDB index
|
||||
"""
|
||||
logger.info(
|
||||
"Dropping Search Index %s from Collection: %s", index_name, collection.name
|
||||
)
|
||||
collection.drop_search_index(index_name)
|
||||
logger.info("Vector Search index %s.%s dropped", collection.name, index_name)
|
||||
|
||||
|
||||
def update_vector_search_index(
|
||||
collection: Collection,
|
||||
index_name: str,
|
||||
dimensions: int,
|
||||
path: str,
|
||||
similarity: str,
|
||||
filters: List[Dict[str, str]],
|
||||
) -> None:
|
||||
"""Leverages the updateSearchIndex call
|
||||
|
||||
Args:
|
||||
collection (Collection): MongoDB Collection
|
||||
index_name (str): Name of Index
|
||||
dimensions (int): Number of dimensions in embedding.
|
||||
path (str): field with vector embedding.
|
||||
similarity (str): The similarity score used for the index.
|
||||
filters (List[Dict[str, str]]): additional filters for index definition.
|
||||
"""
|
||||
|
||||
logger.info(
|
||||
"Updating Search Index %s from Collection: %s", index_name, collection.name
|
||||
)
|
||||
collection.update_search_index(
|
||||
name=index_name,
|
||||
definition=_vector_search_index_definition(
|
||||
dimensions=dimensions,
|
||||
path=path,
|
||||
similarity=similarity,
|
||||
filters=filters,
|
||||
),
|
||||
)
|
||||
logger.info("Update succeeded")
|
||||
@@ -18,6 +18,11 @@ logger = logging.getLogger(__name__)
|
||||
Matrix = Union[List[List[float]], List[np.ndarray], np.ndarray]
|
||||
|
||||
|
||||
class FailCode:
|
||||
INDEX_NOT_FOUND = 27
|
||||
INDEX_ALREADY_EXISTS = 68
|
||||
|
||||
|
||||
def cosine_similarity(X: Matrix, Y: Matrix) -> np.ndarray:
|
||||
"""Row-wise cosine similarity between two equal-width matrices."""
|
||||
if len(X) == 0 or len(Y) == 0:
|
||||
|
||||
@@ -24,7 +24,12 @@ from langchain_core.vectorstores import VectorStore
|
||||
from pymongo import MongoClient
|
||||
from pymongo.collection import Collection
|
||||
from pymongo.driver_info import DriverInfo
|
||||
from pymongo.errors import CollectionInvalid
|
||||
|
||||
from langchain_mongodb.index import (
|
||||
create_vector_search_index,
|
||||
update_vector_search_index,
|
||||
)
|
||||
from langchain_mongodb.utils import maximal_marginal_relevance
|
||||
|
||||
MongoDBDocumentType = TypeVar("MongoDBDocumentType", bound=Dict[str, Any])
|
||||
@@ -489,3 +494,42 @@ class MongoDBAtlasVectorSearch(VectorStore):
|
||||
lambda_mult=lambda_mult,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
def create_vector_search_index(
|
||||
self,
|
||||
dimensions: int,
|
||||
filters: Optional[List[Dict[str, str]]] = None,
|
||||
update: bool = False,
|
||||
) -> None:
|
||||
"""Creates a MongoDB Atlas vectorSearch index for the VectorStore
|
||||
|
||||
Note**: This method may fail as it requires a MongoDB Atlas with
|
||||
these pre-requisites:
|
||||
- M10 cluster or higher
|
||||
- https://www.mongodb.com/docs/atlas/atlas-vector-search/create-index/#prerequisites
|
||||
|
||||
Args:
|
||||
dimensions (int): Number of dimensions in embedding
|
||||
filters (Optional[List[Dict[str, str]]], optional): additional filters
|
||||
for index definition.
|
||||
Defaults to None.
|
||||
update (bool, optional): Updates existing vectorSearch index.
|
||||
Defaults to False.
|
||||
"""
|
||||
try:
|
||||
self._collection.database.create_collection(self._collection.name)
|
||||
except CollectionInvalid:
|
||||
pass
|
||||
|
||||
index_operation = (
|
||||
update_vector_search_index if update else create_vector_search_index
|
||||
)
|
||||
|
||||
index_operation(
|
||||
collection=self._collection,
|
||||
index_name=self._index_name,
|
||||
dimensions=dimensions,
|
||||
path=self._embedding_key,
|
||||
similarity=self._relevance_score_fn,
|
||||
filters=filters or [],
|
||||
)
|
||||
|
||||
@@ -3,22 +3,27 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from time import sleep
|
||||
from typing import Any, Dict, List
|
||||
from time import monotonic, sleep
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import pytest
|
||||
from langchain_core.documents import Document
|
||||
from langchain_core.embeddings import Embeddings
|
||||
from pymongo import MongoClient
|
||||
from pymongo.collection import Collection
|
||||
from pymongo.errors import OperationFailure
|
||||
|
||||
from langchain_mongodb import MongoDBAtlasVectorSearch
|
||||
from langchain_mongodb.index import drop_vector_search_index
|
||||
from tests.utils import ConsistentFakeEmbeddings
|
||||
|
||||
INDEX_NAME = "langchain-test-index-vectorstores"
|
||||
INDEX_CREATION_NAME = "langchain-test-index-vectorstores-create-test"
|
||||
NAMESPACE = "langchain_test_db.langchain_test_vectorstores"
|
||||
CONNECTION_STRING = os.environ.get("MONGODB_ATLAS_URI")
|
||||
DB_NAME, COLLECTION_NAME = NAMESPACE.split(".")
|
||||
INDEX_COLLECTION_NAME = "langchain_test_vectorstores_index"
|
||||
INDEX_DB_NAME = "langchain_test_index_db"
|
||||
DIMENSIONS = 1536
|
||||
TIMEOUT = 10.0
|
||||
INTERVAL = 0.5
|
||||
@@ -28,16 +33,53 @@ class PatchedMongoDBAtlasVectorSearch(MongoDBAtlasVectorSearch):
|
||||
def _insert_texts(self, texts: List[str], metadatas: List[Dict[str, Any]]) -> List:
|
||||
"""Patched insert_texts that waits for data to be indexed before returning"""
|
||||
ids = super()._insert_texts(texts, metadatas)
|
||||
timeout = TIMEOUT
|
||||
while len(ids) != self.similarity_search("sandwich") and timeout >= 0:
|
||||
start = monotonic()
|
||||
while len(ids) != self.similarity_search("sandwich") and (
|
||||
monotonic() - start <= TIMEOUT
|
||||
):
|
||||
sleep(INTERVAL)
|
||||
timeout -= INTERVAL
|
||||
return ids
|
||||
|
||||
def create_vector_search_index(
|
||||
self,
|
||||
dimensions: int,
|
||||
filters: Optional[List[Dict[str, str]]] = None,
|
||||
update: bool = False,
|
||||
) -> None:
|
||||
result = super().create_vector_search_index(
|
||||
dimensions=dimensions, filters=filters, update=update
|
||||
)
|
||||
start = monotonic()
|
||||
while monotonic() - start <= TIMEOUT:
|
||||
if indexes := list(
|
||||
self._collection.list_search_indexes(name=self._index_name)
|
||||
):
|
||||
if indexes[0].get("status") == "READY":
|
||||
return result
|
||||
sleep(INTERVAL)
|
||||
|
||||
def get_collection() -> Collection:
|
||||
raise TimeoutError(f"{self._index_name} never reached 'status: READY'")
|
||||
|
||||
|
||||
def _await_index_deletion(coll: Collection, index_name: str) -> None:
|
||||
start = monotonic()
|
||||
try:
|
||||
drop_vector_search_index(coll, index_name)
|
||||
except OperationFailure:
|
||||
# This most likely means an ongoing drop request was made so skip
|
||||
pass
|
||||
|
||||
while list(coll.list_search_indexes(name=index_name)):
|
||||
if monotonic() - start > TIMEOUT:
|
||||
raise TimeoutError(f"Index Name: {index_name} never dropped")
|
||||
sleep(INTERVAL)
|
||||
|
||||
|
||||
def get_collection(
|
||||
database_name: str = DB_NAME, collection_name: str = COLLECTION_NAME
|
||||
) -> Collection:
|
||||
test_client: MongoClient = MongoClient(CONNECTION_STRING)
|
||||
return test_client[DB_NAME][COLLECTION_NAME]
|
||||
return test_client[database_name][collection_name]
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@@ -45,6 +87,11 @@ def collection() -> Collection:
|
||||
return get_collection()
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def index_collection() -> Collection:
|
||||
return get_collection(INDEX_DB_NAME, INDEX_COLLECTION_NAME)
|
||||
|
||||
|
||||
class TestMongoDBAtlasVectorSearch:
|
||||
@classmethod
|
||||
def setup_class(cls) -> None:
|
||||
@@ -65,6 +112,11 @@ class TestMongoDBAtlasVectorSearch:
|
||||
# delete all the documents in the collection
|
||||
collection.delete_many({}) # type: ignore[index]
|
||||
|
||||
# delete all indexes on index collection name
|
||||
_await_index_deletion(
|
||||
get_collection(INDEX_DB_NAME, INDEX_COLLECTION_NAME), INDEX_CREATION_NAME
|
||||
)
|
||||
|
||||
@pytest.fixture
|
||||
def embedding_openai(self) -> Embeddings:
|
||||
return ConsistentFakeEmbeddings(DIMENSIONS)
|
||||
@@ -85,7 +137,6 @@ class TestMongoDBAtlasVectorSearch:
|
||||
collection=collection,
|
||||
index_name=INDEX_NAME,
|
||||
)
|
||||
# sleep(5) # waits for mongot to update Lucene's index
|
||||
output = vectorstore.similarity_search("Sandwich", k=1)
|
||||
assert len(output) == 1
|
||||
# Check for the presence of the metadata key
|
||||
@@ -150,7 +201,6 @@ class TestMongoDBAtlasVectorSearch:
|
||||
collection=collection,
|
||||
index_name=INDEX_NAME,
|
||||
)
|
||||
# sleep(5) # waits for mongot to update Lucene's index
|
||||
output = vectorstore.similarity_search("Sandwich", k=1)
|
||||
assert len(output) == 1
|
||||
|
||||
@@ -172,7 +222,6 @@ class TestMongoDBAtlasVectorSearch:
|
||||
collection=collection,
|
||||
index_name=INDEX_NAME,
|
||||
)
|
||||
# sleep(5) # waits for mongot to update Lucene's index
|
||||
output = vectorstore.similarity_search("Sandwich", k=1)
|
||||
assert len(output) == 1
|
||||
# Check for the presence of the metadata key
|
||||
@@ -195,7 +244,6 @@ class TestMongoDBAtlasVectorSearch:
|
||||
collection=collection,
|
||||
index_name=INDEX_NAME,
|
||||
)
|
||||
# sleep(5) # waits for mongot to update Lucene's index
|
||||
output = vectorstore.similarity_search(
|
||||
"Sandwich", k=1, pre_filter={"c": {"$lte": 0}}
|
||||
)
|
||||
@@ -209,9 +257,25 @@ class TestMongoDBAtlasVectorSearch:
|
||||
collection=collection,
|
||||
index_name=INDEX_NAME,
|
||||
)
|
||||
# sleep(5) # waits for mongot to update Lucene's index
|
||||
query = "foo"
|
||||
output = vectorstore.max_marginal_relevance_search(query, k=10, lambda_mult=0.1)
|
||||
assert len(output) == len(texts)
|
||||
assert output[0].page_content == "foo"
|
||||
assert output[1].page_content != "foo"
|
||||
|
||||
def test_index_creation(
|
||||
self, embedding_openai: Embeddings, index_collection: Any
|
||||
) -> None:
|
||||
vectorstore = PatchedMongoDBAtlasVectorSearch(
|
||||
index_collection, embedding_openai, index_name=INDEX_CREATION_NAME
|
||||
)
|
||||
vectorstore.create_vector_search_index(dimensions=1536)
|
||||
|
||||
def test_index_update(
|
||||
self, embedding_openai: Embeddings, index_collection: Any
|
||||
) -> None:
|
||||
vectorstore = PatchedMongoDBAtlasVectorSearch(
|
||||
index_collection, embedding_openai, index_name=INDEX_CREATION_NAME
|
||||
)
|
||||
vectorstore.create_vector_search_index(dimensions=1536)
|
||||
vectorstore.create_vector_search_index(dimensions=1536, update=True)
|
||||
|
||||
@@ -346,6 +346,9 @@ class BaseChatOpenAI(BaseChatModel):
|
||||
http_client as well if you'd like a custom client for sync invocations."""
|
||||
stop: Optional[Union[List[str], str]] = Field(default=None, alias="stop_sequences")
|
||||
"""Default stop sequences."""
|
||||
extra_body: Optional[Mapping[str, Any]] = None
|
||||
"""Optional additional JSON properties to include in the request parameters when
|
||||
making requests to OpenAI compatible APIs, such as vLLM."""
|
||||
|
||||
class Config:
|
||||
"""Configuration for this pydantic object."""
|
||||
@@ -445,6 +448,9 @@ class BaseChatOpenAI(BaseChatModel):
|
||||
params["max_tokens"] = self.max_tokens
|
||||
if self.stop:
|
||||
params["stop"] = self.stop
|
||||
if self.extra_body is not None:
|
||||
params["extra_body"] = self.extra_body
|
||||
|
||||
return params
|
||||
|
||||
def _combine_llm_outputs(self, llm_outputs: List[Optional[dict]]) -> dict:
|
||||
@@ -1666,7 +1672,13 @@ class ChatOpenAI(BaseChatOpenAI):
|
||||
) -> Iterator[ChatGenerationChunk]:
|
||||
"""Set default stream_options."""
|
||||
stream_usage = self._should_stream_usage(stream_usage, **kwargs)
|
||||
kwargs["stream_options"] = {"include_usage": stream_usage}
|
||||
# Note: stream_options is not a valid parameter for Azure OpenAI.
|
||||
# To support users proxying Azure through ChatOpenAI, here we only specify
|
||||
# stream_options if include_usage is set to True.
|
||||
# See https://learn.microsoft.com/en-us/azure/ai-services/openai/whats-new
|
||||
# for release notes.
|
||||
if stream_usage:
|
||||
kwargs["stream_options"] = {"include_usage": stream_usage}
|
||||
|
||||
return super()._stream(*args, **kwargs)
|
||||
|
||||
@@ -1675,7 +1687,8 @@ class ChatOpenAI(BaseChatOpenAI):
|
||||
) -> AsyncIterator[ChatGenerationChunk]:
|
||||
"""Set default stream_options."""
|
||||
stream_usage = self._should_stream_usage(stream_usage, **kwargs)
|
||||
kwargs["stream_options"] = {"include_usage": stream_usage}
|
||||
if stream_usage:
|
||||
kwargs["stream_options"] = {"include_usage": stream_usage}
|
||||
|
||||
async for chunk in super()._astream(*args, **kwargs):
|
||||
yield chunk
|
||||
|
||||
@@ -137,6 +137,9 @@ class BaseOpenAI(BaseLLM):
|
||||
http_async_client: Union[Any, None] = None
|
||||
"""Optional httpx.AsyncClient. Only used for async invocations. Must specify
|
||||
http_client as well if you'd like a custom client for sync invocations."""
|
||||
extra_body: Optional[Mapping[str, Any]] = None
|
||||
"""Optional additional JSON properties to include in the request parameters when
|
||||
making requests to OpenAI compatible APIs, such as vLLM."""
|
||||
|
||||
class Config:
|
||||
"""Configuration for this pydantic object."""
|
||||
@@ -222,6 +225,9 @@ class BaseOpenAI(BaseLLM):
|
||||
if self.max_tokens is not None:
|
||||
normal_params["max_tokens"] = self.max_tokens
|
||||
|
||||
if self.extra_body is not None:
|
||||
normal_params["extra_body"] = self.extra_body
|
||||
|
||||
# Azure gpt-35-turbo doesn't support best_of
|
||||
# don't specify best_of if it is 1
|
||||
if self.best_of > 1:
|
||||
|
||||
12
libs/partners/openai/poetry.lock
generated
12
libs/partners/openai/poetry.lock
generated
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
@@ -385,7 +385,7 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "langchain-core"
|
||||
version = "0.2.9"
|
||||
version = "0.2.10"
|
||||
description = "Building applications with LLMs through composability"
|
||||
optional = false
|
||||
python-versions = ">=3.8.1,<4.0"
|
||||
@@ -586,13 +586,13 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "openai"
|
||||
version = "1.29.0"
|
||||
version = "1.35.6"
|
||||
description = "The official Python library for the openai API"
|
||||
optional = false
|
||||
python-versions = ">=3.7.1"
|
||||
files = [
|
||||
{file = "openai-1.29.0-py3-none-any.whl", hash = "sha256:c61cd12376c84362d406341f9e2f9a9d6b81c082b133b44484dc0f43954496b1"},
|
||||
{file = "openai-1.29.0.tar.gz", hash = "sha256:d5a769f485610cff8bae14343fa45a8b1d346be3d541fa5b28ccd040dbc8baf8"},
|
||||
{file = "openai-1.35.6-py3-none-any.whl", hash = "sha256:c2bfa599445a2d6010adc7954476c2dc64e1aa8dad02ef29e0f31b9a887c1d02"},
|
||||
{file = "openai-1.35.6.tar.gz", hash = "sha256:c5958617048a2d777d2b96050fd69ae6721bdffbf59967698694223cc092abd9"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
@@ -1400,4 +1400,4 @@ watchmedo = ["PyYAML (>=3.10)"]
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.8.1,<4.0"
|
||||
content-hash = "979fe68dc87d220765c4f31867d1b51aaddf147ed571d4eb30bc39fc51d774d2"
|
||||
content-hash = "abce67a9e29b0a4c6fb7c22efb8fb4b1248cb692ec85d74fdb650f50f714b241"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "langchain-openai"
|
||||
version = "0.1.10"
|
||||
version = "0.1.11"
|
||||
description = "An integration package connecting OpenAI and LangChain"
|
||||
authors = []
|
||||
readme = "README.md"
|
||||
@@ -13,7 +13,7 @@ license = "MIT"
|
||||
[tool.poetry.dependencies]
|
||||
python = ">=3.8.1,<4.0"
|
||||
langchain-core = ">=0.2.2,<0.3"
|
||||
openai = "^1.26.0"
|
||||
openai = "^1.32.0"
|
||||
tiktoken = ">=0.7,<1"
|
||||
|
||||
[tool.poetry.group.test]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user