mirror of
https://github.com/hwchase17/langchain.git
synced 2026-07-16 17:26:50 +00:00
ModelIO revamp (#15230)
This commit is contained in:
BIN
docs/docs/modules/model_io/chat/.langchain.db
Normal file
BIN
docs/docs/modules/model_io/chat/.langchain.db
Normal file
Binary file not shown.
224
docs/docs/modules/model_io/chat/chat_model_caching.ipynb
Normal file
224
docs/docs/modules/model_io/chat/chat_model_caching.ipynb
Normal file
@@ -0,0 +1,224 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "dcf87b32",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Caching\n",
|
||||
"LangChain provides an optional caching layer for chat models. This is useful for two reasons:\n",
|
||||
"\n",
|
||||
"It can save you money by reducing the number of API calls you make to the LLM provider, if you're often requesting the same completion multiple times.\n",
|
||||
"It can speed up your application by reducing the number of API calls you make to the LLM provider.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "5472a032",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.chat_models import ChatOpenAI\n",
|
||||
"from langchain.globals import set_llm_cache\n",
|
||||
"\n",
|
||||
"llm = ChatOpenAI()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "357b89a8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## In Memory Cache"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "113e719a",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"CPU times: user 17.7 ms, sys: 9.35 ms, total: 27.1 ms\n",
|
||||
"Wall time: 801 ms\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\"Sure, here's a classic one for you:\\n\\nWhy don't scientists trust atoms?\\n\\nBecause they make up everything!\""
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"from langchain.cache import InMemoryCache\n",
|
||||
"set_llm_cache(InMemoryCache())\n",
|
||||
"\n",
|
||||
"# The first time, it is not yet in cache, so it should take longer\n",
|
||||
"llm.predict(\"Tell me a joke\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "a2121434",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"CPU times: user 1.42 ms, sys: 419 µs, total: 1.83 ms\n",
|
||||
"Wall time: 1.83 ms\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\"Sure, here's a classic one for you:\\n\\nWhy don't scientists trust atoms?\\n\\nBecause they make up everything!\""
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# The second time it is, so it goes faster\n",
|
||||
"llm.predict(\"Tell me a joke\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b88ff8af",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## SQLite Cache\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "99290ab4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!rm .langchain.db"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "fe826c5c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# We can do the same thing with a SQLite cache\n",
|
||||
"from langchain.cache import SQLiteCache\n",
|
||||
"\n",
|
||||
"set_llm_cache(SQLiteCache(database_path=\".langchain.db\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "eb558734",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"CPU times: user 23.2 ms, sys: 17.8 ms, total: 40.9 ms\n",
|
||||
"Wall time: 592 ms\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\"Sure, here's a classic one for you:\\n\\nWhy don't scientists trust atoms?\\n\\nBecause they make up everything!\""
|
||||
]
|
||||
},
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# The first time, it is not yet in cache, so it should take longer\n",
|
||||
"llm.predict(\"Tell me a joke\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "497c7000",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"CPU times: user 5.61 ms, sys: 22.5 ms, total: 28.1 ms\n",
|
||||
"Wall time: 47.5 ms\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\"Sure, here's a classic one for you:\\n\\nWhy don't scientists trust atoms?\\n\\nBecause they make up everything!\""
|
||||
]
|
||||
},
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# The second time it is, so it goes faster\n",
|
||||
"llm.predict(\"Tell me a joke\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "33815d3f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
# Caching
|
||||
LangChain provides an optional caching layer for chat models. This is useful for two reasons:
|
||||
|
||||
It can save you money by reducing the number of API calls you make to the LLM provider, if you're often requesting the same completion multiple times.
|
||||
It can speed up your application by reducing the number of API calls you make to the LLM provider.
|
||||
|
||||
```python
|
||||
from langchain.globals import set_llm_cache
|
||||
from langchain.chat_models import ChatOpenAI
|
||||
|
||||
llm = ChatOpenAI()
|
||||
```
|
||||
|
||||
## In Memory Cache
|
||||
|
||||
|
||||
```python
|
||||
from langchain.cache import InMemoryCache
|
||||
set_llm_cache(InMemoryCache())
|
||||
|
||||
# The first time, it is not yet in cache, so it should take longer
|
||||
llm.predict("Tell me a joke")
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
CPU times: user 35.9 ms, sys: 28.6 ms, total: 64.6 ms
|
||||
Wall time: 4.83 s
|
||||
|
||||
|
||||
"\n\nWhy couldn't the bicycle stand up by itself? It was...two tired!"
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
|
||||
```python
|
||||
# The second time it is, so it goes faster
|
||||
llm.predict("Tell me a joke")
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
CPU times: user 238 µs, sys: 143 µs, total: 381 µs
|
||||
Wall time: 1.76 ms
|
||||
|
||||
|
||||
'\n\nWhy did the chicken cross the road?\n\nTo get to the other side.'
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
## SQLite Cache
|
||||
|
||||
|
||||
```bash
|
||||
rm .langchain.db
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
# We can do the same thing with a SQLite cache
|
||||
from langchain.cache import SQLiteCache
|
||||
set_llm_cache(SQLiteCache(database_path=".langchain.db"))
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
# The first time, it is not yet in cache, so it should take longer
|
||||
llm.predict("Tell me a joke")
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
CPU times: user 17 ms, sys: 9.76 ms, total: 26.7 ms
|
||||
Wall time: 825 ms
|
||||
|
||||
|
||||
'\n\nWhy did the chicken cross the road?\n\nTo get to the other side.'
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
|
||||
```python
|
||||
# The second time it is, so it goes faster
|
||||
llm.predict("Tell me a joke")
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
CPU times: user 2.46 ms, sys: 1.23 ms, total: 3.7 ms
|
||||
Wall time: 2.67 ms
|
||||
|
||||
|
||||
'\n\nWhy did the chicken cross the road?\n\nTo get to the other side.'
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
28
docs/docs/modules/model_io/chat/index.mdx
Normal file
28
docs/docs/modules/model_io/chat/index.mdx
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Chat Models
|
||||
|
||||
ChatModels are a core component of LangChain.
|
||||
LangChain does not serve its own ChatModels, but rather provides a standard interface for interacting with many different models. To be specific, this interface is one that takes as input a list of messages and returns a message.
|
||||
|
||||
|
||||
There are lots of model providers (OpenAI, Cohere, Hugging Face, etc) - the `ChatModel` class is designed to provide a standard interface for all of them.
|
||||
|
||||
## [Quick Start](./quick_start)
|
||||
|
||||
Check out [this quick start](./quick_start) to get an overview of working with ChatModels, including all the different methods they expose
|
||||
|
||||
## [Integrations](/docs/integrations/chat/)
|
||||
|
||||
For a full list of all LLM integrations that LangChain provides, please go to the [Integrations page](/docs/integrations/chat/)
|
||||
|
||||
## How-To Guides
|
||||
|
||||
We have several how-to guides for more advanced usage of LLMs.
|
||||
This includes:
|
||||
|
||||
- [How to cache ChatModel responses](./chat_model_caching)
|
||||
- [How to stream responses from a ChatModel](./streaming)
|
||||
- [How to track token usage in a ChatModel call)(./token_usage_tracking)
|
||||
@@ -1,52 +0,0 @@
|
||||
# Prompts
|
||||
|
||||
Prompts for chat models are built around messages, instead of just plain text.
|
||||
|
||||
You can make use of templating by using a `MessagePromptTemplate`. You can build a `ChatPromptTemplate` from one or more `MessagePromptTemplates`. You can use `ChatPromptTemplate`'s `format_prompt` -- this returns a `PromptValue`, which you can convert to a string or Message object, depending on whether you want to use the formatted value as input to an llm or chat model.
|
||||
|
||||
For convenience, there is a `from_template` method defined on the template. If you were to use this template, this is what it would look like:
|
||||
|
||||
|
||||
```python
|
||||
from langchain.prompts import PromptTemplate
|
||||
from langchain.prompts.chat import (
|
||||
ChatPromptTemplate,
|
||||
SystemMessagePromptTemplate,
|
||||
AIMessagePromptTemplate,
|
||||
HumanMessagePromptTemplate,
|
||||
)
|
||||
|
||||
template="You are a helpful assistant that translates {input_language} to {output_language}."
|
||||
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
|
||||
human_template="{text}"
|
||||
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
|
||||
|
||||
# get a chat completion from the formatted messages
|
||||
chat(chat_prompt.format_prompt(input_language="English", output_language="French", text="I love programming.").to_messages())
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
AIMessage(content="J'adore la programmation.", additional_kwargs={})
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
If you wanted to construct the MessagePromptTemplate more directly, you could create a PromptTemplate outside and then pass it in, e.g.:
|
||||
|
||||
|
||||
```python
|
||||
prompt=PromptTemplate(
|
||||
template="You are a helpful assistant that translates {input_language} to {output_language}.",
|
||||
input_variables=["input_language", "output_language"],
|
||||
)
|
||||
system_message_prompt = SystemMessagePromptTemplate(prompt=prompt)
|
||||
```
|
||||
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"sidebar_position: 1\n",
|
||||
"title: Chat models\n",
|
||||
"sidebar_position: 0\n",
|
||||
"title: Quick Start\n",
|
||||
"---"
|
||||
]
|
||||
},
|
||||
@@ -16,11 +16,7 @@
|
||||
"id": "a1a454a9-f963-417b-8be0-e60317cd328c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
":::info\n",
|
||||
"\n",
|
||||
"Head to [Integrations](/docs/integrations/chat/) for documentation on built-in integrations with chat model providers.\n",
|
||||
"\n",
|
||||
":::\n",
|
||||
"# Quick Start\n",
|
||||
"\n",
|
||||
"Chat models are a variation on language models.\n",
|
||||
"While chat models use language models under the hood, the interface they use is a bit different.\n",
|
||||
@@ -765,9 +761,9 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "poetry-venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "poetry-venv"
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
@@ -779,7 +775,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.1"
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
115
docs/docs/modules/model_io/concepts.mdx
Normal file
115
docs/docs/modules/model_io/concepts.mdx
Normal file
@@ -0,0 +1,115 @@
|
||||
---
|
||||
sidebar_position: 0
|
||||
---
|
||||
|
||||
# Concepts
|
||||
|
||||
The core element of any language model application is...the model. LangChain gives you the building blocks to interface with any language model. Everything in this section is about making it easier to work with models. This largely involves a clear interface for what a model is, helper utils for constructing inputs to models, and helper utils for working with the outputs of models.
|
||||
|
||||
## Models
|
||||
|
||||
There are two main types of models that LangChain integrates with: LLMs and Chat Models. These are defined by their input and output types.
|
||||
|
||||
### LLMs
|
||||
|
||||
LLMs in LangChain refer to pure text completion models.
|
||||
The APIs they wrap take a string prompt as input and output a string completion. OpenAI's GPT-3 is implemented as an LLM.
|
||||
|
||||
### Chat Models
|
||||
Chat models are often backed by LLMs but tuned specifically for having conversations.
|
||||
Crucially, their provider APIs use a different interface than pure text completion models. Instead of a single string,
|
||||
they take a list of chat messages as input and they return an AI message as output. See the section below for more details on what exactly a message consists of. GPT-4 and Anthropic's Claude-2 are both implemented as chat models.
|
||||
|
||||
### Considerations
|
||||
|
||||
These two API types have pretty different input and output schemas. This means that best way to interact with them may be quite different. Although LangChain makes it possible to treat them interchangeably, that doesn't mean you **should**. In particular, the prompting strategies for LLMs vs ChatModels may be quite different. This means that you will want to make sure the prompt you are using is designed for the model type you are working with.
|
||||
|
||||
Additionally, not all models are the same. Different models have different prompting strategies that work best for them. For example, Anthropic's models work best with XML while OpenAI's work best with JSON. This means that the prompt you use for one model may not transfer to other ones. LangChain provides a lot of default prompts, however these are not garunteed to work well with the model are you using. Historically speaking, most prompts work well with OpenAI but are not heavily tested on other models. This is something we are working to address, but it is something you should keep in mind.
|
||||
|
||||
|
||||
## Messages
|
||||
|
||||
ChatModels take a list of messages as input and return a message. There are a few different types of messages. All messages have a `role` and a `content` property. The `role` describes WHO is saying the message. LangChain has different message classes for different roles. The `content` property described the content of the message. This can be a few different things:
|
||||
|
||||
- A string (most models are this way)
|
||||
- A List of dictionaries (this is used for multi-modal input, where the dictionary contains information about that input type and that input location)
|
||||
|
||||
In addition, messages have an `additional_kwargs` property. This is where additional information about messages can be passed. This is largely used for input parameters that are *provider specific* and not general. The best known example of this is `function_call` from OpenAI.
|
||||
|
||||
### HumanMessage
|
||||
|
||||
This represents a message from the user. Generally consists only of content.
|
||||
|
||||
|
||||
### AIMessage
|
||||
|
||||
This represents a message from the model. This may have `additional_kwargs` in it - for example `functional_call` if using OpenAI Function calling.
|
||||
|
||||
|
||||
### SystemMessage
|
||||
|
||||
This represents a system message. Only some models support this. This tells the model how to behave. This generally only consists of content.
|
||||
|
||||
### FunctionMessage
|
||||
|
||||
This represents the result of a function call. In addition to `role` and `content`, this message has a `name` parameter which conveys the name of the function that was called to produce this result.
|
||||
|
||||
### ToolMessage
|
||||
|
||||
This represents the result of a tool call. This is distinct from a FunctionMessage in order to match OpenAI's `function` and `tool` message types. In addition to `role` and `content`, this message has a `tool_call_id` parameter which conveys the id of the call to the tool that was called to produce this result.
|
||||
|
||||
## Prompts
|
||||
|
||||
The inputs to language models are often called prompts. Oftentimes, the user input from your app is not the direct input to the model. Rather, their input is transformed in some way to product the string or list of messages that does go into the model. The objects that take user input and transform it into the final string or messages are known as "Prompt Templates". LangChain provides several abstractions to make working with prompts easier.
|
||||
|
||||
### PromptValue
|
||||
|
||||
ChatModels and LLMs take different input types. PromptValue is class designed to be interoptable between the two. It exposes a method to be cast to a string (to work with LLMs) and another to be cast to a list of messages (to work with ChatModels).
|
||||
|
||||
### PromptTemplate
|
||||
|
||||
This is an example of a prompt template. This consists of a template string. This string is then formatted with user inputs to produce a final string.
|
||||
|
||||
### MessagePromptTemplate
|
||||
|
||||
This is an example of a prompt template. This consists of a template **message** - meaning a specific role and a PromptTemplate. This PromptTemplate is then formatted with user inputs to produce a final string that becomes the `content` of this message.
|
||||
|
||||
#### HumanMessagePromptTemplate
|
||||
|
||||
This is MessagePromptTemplate that produces a HumanMessage.
|
||||
|
||||
#### AIMessagePromptTemplate
|
||||
|
||||
This is MessagePromptTemplate that produces an AIMessage.
|
||||
|
||||
#### SystemMessagePromptTemplate
|
||||
|
||||
This is MessagePromptTemplate that produces a SystemMessage.
|
||||
|
||||
### MessagesPlaceholder
|
||||
|
||||
Oftentimes inputs to prompts can be a list of messages. This is when you would use a MessagesPlaceholder. These objects are parameterized by a `variable_name` argument. The input with the same value as this `variable_name` value should be a list of messages.
|
||||
|
||||
### ChatPromptTemplate
|
||||
|
||||
This is an example of a prompt template. This consists of a list of MessagePromptTemplates or MessagePlaceholders. These are then formatted with user inputs to produce a final list of messages.
|
||||
|
||||
## Output Parsers
|
||||
|
||||
The output of models are either strings or a message. Oftentimes, the string or messages contains information formatted in a specific format to be used downstream (e.g. a comma separated list, or JSON blob). Output parsers are responsible for taking in the output of a model and transforming it into a more usable form. These generally work on the `content` of the output message, but occasionally work on values in the `additional_kwargs` field.
|
||||
|
||||
### StrOutputParser
|
||||
|
||||
This is a simple output parser that just converts the output of a language model (LLM or ChatModel) into a string. If the model is an LLM (and therefore outputs a string) it just passes that string through. If the output is a ChatModel (and therefore outputs a message) it passes through the `.content` attribute of the message.
|
||||
|
||||
### OpenAI Functions Parsers
|
||||
|
||||
There are a few parsers dedicated to working with OpenAI function calling. They take the output of the `function_call` and `arguments` parameters (which are inside `additional_kwargs`) and work with those, largely ignoring content.
|
||||
|
||||
### Agent Output Parsers
|
||||
|
||||
[Agents](../agents) are systems that use language models to determine what steps to take. The output of a language model therefore needs to be parsed into some schema that can represent what actions (if any) are to be taken. AgentOutputParsers are responsible for taking raw LLM or ChatModel output and converting it to that schema. The logic inside these output parsers can differ depending on the model and prompting strategy being used.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,19 +9,29 @@ sidebar_class_name: hidden
|
||||
|
||||
The core element of any language model application is...the model. LangChain gives you the building blocks to interface with any language model.
|
||||
|
||||
- [Prompts](/docs/modules/model_io/prompts/): Templatize, dynamically select, and manage model inputs
|
||||
- [Chat models](/docs/modules/model_io/chat/): Models that are backed by a language model but take a list of Chat Messages as input and return a Chat Message
|
||||
- [LLMs](/docs/modules/model_io/llms/): Models that take a text string as input and return a text string
|
||||
- [Output parsers](/docs/modules/model_io/output_parsers/): Extract information from model outputs
|
||||
|
||||

|
||||
|
||||
## [Conceptual Guide](./concepts)
|
||||
|
||||
## LLMs vs Chat models
|
||||
A conceptual explanation of messages, prompts, LLMs vs ChatModels, and output parsers. You should read this before getting started.
|
||||
|
||||
## [Quick Start](./quick_start)
|
||||
|
||||
Covers the basics of getting started working with different types of models. You should walk through [this section] if you want to get an overview of the functionality.
|
||||
|
||||
## [Prompts](./prompts)
|
||||
|
||||
[This section](./prompts) deep dives into the different types of prompt templates and how to use them.
|
||||
|
||||
## [LLMs](./llms)
|
||||
|
||||
[This section](./llms) covers functionality related to the LLM class. This is a type of model that takes a text string as input and returns a text string.
|
||||
|
||||
## [ChatModels](./chat)
|
||||
|
||||
[This section](./chat) covers functionality related to the ChatModel class. This is a type of model that takes a list of messages as input and returns a message.
|
||||
|
||||
## [Output Parsers](./output_parsers)
|
||||
|
||||
Output parsers are responsible for transforming the output of LLMs and ChatModels into more structured data. [This section](./output_parsers) covers the different types of output parsers.
|
||||
|
||||
LLMs and chat models are subtly but importantly different. LLMs in LangChain refer to pure text completion models.
|
||||
The APIs they wrap take a string prompt as input and output a string completion. OpenAI's GPT-3 is implemented as an LLM.
|
||||
Chat models are often backed by LLMs but tuned specifically for having conversations.
|
||||
And, crucially, their provider APIs use a different interface than pure text completion models. Instead of a single string,
|
||||
they take a list of chat messages as input. Usually these messages are labeled with the speaker (usually one of "System",
|
||||
"AI", and "Human"). And they return an AI chat message as output. GPT-4 and Anthropic's Claude-2 are both implemented as chat models.
|
||||
|
||||
BIN
docs/docs/modules/model_io/llms/.langchain.db
Normal file
BIN
docs/docs/modules/model_io/llms/.langchain.db
Normal file
Binary file not shown.
@@ -1,121 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f6574496-b360-4ffa-9523-7fd34a590164",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Async API\n",
|
||||
"\n",
|
||||
"All `LLM`s implement the `Runnable` interface, which comes with default implementations of all methods, ie. ainvoke, batch, abatch, stream, astream. This gives all `LLM`s basic support for asynchronous calls.\n",
|
||||
"\n",
|
||||
"Async support defaults to calling the `LLM`'s respective sync method in asyncio's default thread pool executor. This lets other async functions in your application make progress while the `LLM` is being executed, by moving this call to a background thread. Where `LLM`s providers have native implementations for async, that is used instead of the default `LLM` implementation.\n",
|
||||
"\n",
|
||||
"See which [integrations provide native async support here](/docs/integrations/llms/).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "5e49e96c-0f88-466d-b3d3-ea0966bdf19e",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\u001b[1mConcurrent executed in 1.03 seconds.\u001b[0m\n",
|
||||
"\u001b[1mSerial executed in 6.80 seconds.\u001b[0m\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import asyncio\n",
|
||||
"import time\n",
|
||||
"\n",
|
||||
"from langchain.llms import OpenAI\n",
|
||||
"\n",
|
||||
"llm = OpenAI(model=\"gpt-3.5-turbo-instruct\", temperature=0.9)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def invoke_serially():\n",
|
||||
" for _ in range(10):\n",
|
||||
" resp = llm.invoke(\"Hello, how are you?\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"async def async_invoke(llm):\n",
|
||||
" resp = await llm.ainvoke(\"Hello, how are you?\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"async def invoke_concurrently():\n",
|
||||
" tasks = [async_invoke(llm) for _ in range(10)]\n",
|
||||
" await asyncio.gather(*tasks)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"s = time.perf_counter()\n",
|
||||
"# If running this outside of Jupyter, use asyncio.run(generate_concurrently())\n",
|
||||
"await invoke_concurrently()\n",
|
||||
"elapsed = time.perf_counter() - s\n",
|
||||
"print(\"\\033[1m\" + f\"Concurrent executed in {elapsed:0.2f} seconds.\" + \"\\033[0m\")\n",
|
||||
"\n",
|
||||
"s = time.perf_counter()\n",
|
||||
"invoke_serially()\n",
|
||||
"elapsed = time.perf_counter() - s\n",
|
||||
"print(\"\\033[1m\" + f\"Serial executed in {elapsed:0.2f} seconds.\" + \"\\033[0m\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e0b60caf-f99e-46a6-bdad-46b2cfea29ac",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"To simplify things we could also just use `abatch` to run a batch concurrently:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "bd11000f-2232-491a-9f70-abcbb4611fbf",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\u001b[1mBatch executed in 1.31 seconds.\u001b[0m\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"s = time.perf_counter()\n",
|
||||
"# If running this outside of Jupyter, use asyncio.run(generate_concurrently())\n",
|
||||
"await llm.abatch([\"Hello, how are you?\"] * 10)\n",
|
||||
"elapsed = time.perf_counter() - s\n",
|
||||
"print(\"\\033[1m\" + f\"Batch executed in {elapsed:0.2f} seconds.\" + \"\\033[0m\")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
29
docs/docs/modules/model_io/llms/index.mdx
Normal file
29
docs/docs/modules/model_io/llms/index.mdx
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# LLMs
|
||||
|
||||
Large Language Models (LLMs) are a core component of LangChain.
|
||||
LangChain does not serve its own LLMs, but rather provides a standard interface for interacting with many different LLMs. To be specific, this interface is one that takes as input a string and returns a string.
|
||||
|
||||
|
||||
There are lots of LLM providers (OpenAI, Cohere, Hugging Face, etc) - the `LLM` class is designed to provide a standard interface for all of them.
|
||||
|
||||
## [Quick Start](./quick_start)
|
||||
|
||||
Check out [this quick start](./quick_start) to get an overview of working with LLMs, including all the different methods they expose
|
||||
|
||||
## [Integrations](/docs/integrations/llms/)
|
||||
|
||||
For a full list of all LLM integrations that LangChain provides, please go to the [Integrations page](/docs/integrations/llms/)
|
||||
|
||||
## How-To Guides
|
||||
|
||||
We have several how-to guides for more advanced usage of LLMs.
|
||||
This includes:
|
||||
|
||||
- [How to write a custom LLM class](./custom_llm)
|
||||
- [How to cache LLM responses](./llm_caching)
|
||||
- [How to stream responses from an LLM](./streaming_llm)
|
||||
- [How to track token usage in an LLM call)(./token_usage_tracking)
|
||||
217
docs/docs/modules/model_io/llms/llm_caching.ipynb
Normal file
217
docs/docs/modules/model_io/llms/llm_caching.ipynb
Normal file
@@ -0,0 +1,217 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b843b5c4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Caching\n",
|
||||
"LangChain provides an optional caching layer for LLMs. This is useful for two reasons:\n",
|
||||
"\n",
|
||||
"It can save you money by reducing the number of API calls you make to the LLM provider, if you're often requesting the same completion multiple times.\n",
|
||||
"It can speed up your application by reducing the number of API calls you make to the LLM provider.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "0aa6d335",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.globals import set_llm_cache\n",
|
||||
"from langchain.llms import OpenAI\n",
|
||||
"\n",
|
||||
"# To make the caching really obvious, lets use a slower model.\n",
|
||||
"llm = OpenAI(model_name=\"gpt-3.5-turbo-instruct\", n=2, best_of=2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "f168ff0d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"CPU times: user 13.7 ms, sys: 6.54 ms, total: 20.2 ms\n",
|
||||
"Wall time: 330 ms\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\"\\n\\nWhy couldn't the bicycle stand up by itself? Because it was two-tired!\""
|
||||
]
|
||||
},
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"from langchain.cache import InMemoryCache\n",
|
||||
"set_llm_cache(InMemoryCache())\n",
|
||||
"\n",
|
||||
"# The first time, it is not yet in cache, so it should take longer\n",
|
||||
"llm.predict(\"Tell me a joke\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "ce7620fb",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"CPU times: user 436 µs, sys: 921 µs, total: 1.36 ms\n",
|
||||
"Wall time: 1.36 ms\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\"\\n\\nWhy couldn't the bicycle stand up by itself? Because it was two-tired!\""
|
||||
]
|
||||
},
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# The second time it is, so it goes faster\n",
|
||||
"llm.predict(\"Tell me a joke\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4ab452f4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## SQLite Cache"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "2e65de83",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"!rm .langchain.db"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "0be83715",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# We can do the same thing with a SQLite cache\n",
|
||||
"from langchain.cache import SQLiteCache\n",
|
||||
"\n",
|
||||
"set_llm_cache(SQLiteCache(database_path=\".langchain.db\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "9b427ce7",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"CPU times: user 29.3 ms, sys: 17.3 ms, total: 46.7 ms\n",
|
||||
"Wall time: 364 ms\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'\\n\\nWhy did the tomato turn red?\\n\\nBecause it saw the salad dressing!'"
|
||||
]
|
||||
},
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# The first time, it is not yet in cache, so it should take longer\n",
|
||||
"llm.predict(\"Tell me a joke\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "87f52611",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"CPU times: user 4.58 ms, sys: 2.23 ms, total: 6.8 ms\n",
|
||||
"Wall time: 4.68 ms\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'\\n\\nWhy did the tomato turn red?\\n\\nBecause it saw the salad dressing!'"
|
||||
]
|
||||
},
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%time\n",
|
||||
"# The second time it is, so it goes faster\n",
|
||||
"llm.predict(\"Tell me a joke\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6a9bb158",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
# Caching
|
||||
LangChain provides an optional caching layer for LLMs. This is useful for two reasons:
|
||||
|
||||
It can save you money by reducing the number of API calls you make to the LLM provider, if you're often requesting the same completion multiple times.
|
||||
It can speed up your application by reducing the number of API calls you make to the LLM provider.
|
||||
|
||||
```python
|
||||
from langchain.globals import set_llm_cache
|
||||
from langchain.llms import OpenAI
|
||||
|
||||
# To make the caching really obvious, lets use a slower model.
|
||||
llm = OpenAI(model_name="gpt-3.5-turbo-instruct", n=2, best_of=2)
|
||||
```
|
||||
|
||||
## In Memory Cache
|
||||
|
||||
|
||||
```python
|
||||
from langchain.cache import InMemoryCache
|
||||
set_llm_cache(InMemoryCache())
|
||||
|
||||
# The first time, it is not yet in cache, so it should take longer
|
||||
llm.predict("Tell me a joke")
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
CPU times: user 35.9 ms, sys: 28.6 ms, total: 64.6 ms
|
||||
Wall time: 4.83 s
|
||||
|
||||
|
||||
"\n\nWhy couldn't the bicycle stand up by itself? It was...two tired!"
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
|
||||
```python
|
||||
# The second time it is, so it goes faster
|
||||
llm.predict("Tell me a joke")
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
CPU times: user 238 µs, sys: 143 µs, total: 381 µs
|
||||
Wall time: 1.76 ms
|
||||
|
||||
|
||||
'\n\nWhy did the chicken cross the road?\n\nTo get to the other side.'
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
## SQLite Cache
|
||||
|
||||
|
||||
```bash
|
||||
rm .langchain.db
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
# We can do the same thing with a SQLite cache
|
||||
from langchain.cache import SQLiteCache
|
||||
set_llm_cache(SQLiteCache(database_path=".langchain.db"))
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
# The first time, it is not yet in cache, so it should take longer
|
||||
llm.predict("Tell me a joke")
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
CPU times: user 17 ms, sys: 9.76 ms, total: 26.7 ms
|
||||
Wall time: 825 ms
|
||||
|
||||
|
||||
'\n\nWhy did the chicken cross the road?\n\nTo get to the other side.'
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
|
||||
```python
|
||||
# The second time it is, so it goes faster
|
||||
llm.predict("Tell me a joke")
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
CPU times: user 2.46 ms, sys: 1.23 ms, total: 3.7 ms
|
||||
Wall time: 2.67 ms
|
||||
|
||||
|
||||
'\n\nWhy did the chicken cross the road?\n\nTo get to the other side.'
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
## Optional caching in chains
|
||||
You can also turn off caching for particular nodes in chains. Note that because of certain interfaces, it's often easier to construct the chain first, and then edit the LLM afterwards.
|
||||
|
||||
As an example, we will load a summarizer map-reduce chain. We will cache results for the map-step, but then not freeze it for the combine step.
|
||||
|
||||
|
||||
```python
|
||||
llm = OpenAI(model_name="gpt-3.5-turbo-instruct")
|
||||
no_cache_llm = OpenAI(model_name="gpt-3.5-turbo-instruct", cache=False)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
from langchain.text_splitter import CharacterTextSplitter
|
||||
from langchain.chains.mapreduce import MapReduceChain
|
||||
|
||||
text_splitter = CharacterTextSplitter()
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
with open('../../../state_of_the_union.txt') as f:
|
||||
state_of_the_union = f.read()
|
||||
texts = text_splitter.split_text(state_of_the_union)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
from langchain.docstore.document import Document
|
||||
docs = [Document(page_content=t) for t in texts[:3]]
|
||||
from langchain.chains.summarize import load_summarize_chain
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
chain = load_summarize_chain(llm, chain_type="map_reduce", reduce_llm=no_cache_llm)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
chain.run(docs)
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
CPU times: user 452 ms, sys: 60.3 ms, total: 512 ms
|
||||
Wall time: 5.09 s
|
||||
|
||||
|
||||
'\n\nPresident Biden is discussing the American Rescue Plan and the Bipartisan Infrastructure Law, which will create jobs and help Americans. He also talks about his vision for America, which includes investing in education and infrastructure. In response to Russian aggression in Ukraine, the United States is joining with European allies to impose sanctions and isolate Russia. American forces are being mobilized to protect NATO countries in the event that Putin decides to keep moving west. The Ukrainians are bravely fighting back, but the next few weeks will be hard for them. Putin will pay a high price for his actions in the long run. Americans should not be alarmed, as the United States is taking action to protect its interests and allies.'
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
When we run it again, we see that it runs substantially faster but the final answer is different. This is due to caching at the map steps, but not at the reduce step.
|
||||
|
||||
|
||||
```python
|
||||
chain.run(docs)
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
CPU times: user 11.5 ms, sys: 4.33 ms, total: 15.8 ms
|
||||
Wall time: 1.04 s
|
||||
|
||||
|
||||
'\n\nPresident Biden is discussing the American Rescue Plan and the Bipartisan Infrastructure Law, which will create jobs and help Americans. He also talks about his vision for America, which includes investing in education and infrastructure.'
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
|
||||
```bash
|
||||
rm .langchain.db sqlite.db
|
||||
```
|
||||
@@ -1,179 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "73f9bf40",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Serialization\n",
|
||||
"\n",
|
||||
"LangChain Python and LangChain JS share a serialization scheme. You can check if a LangChain class is serializable by running with the `is_lc_serializable` class method."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "9c9fb6ff",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.llms import OpenAI\n",
|
||||
"from langchain.llms.loading import load_llm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "441d28cb-e898-47fd-8f27-f620a9cd6c34",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"OpenAI.is_lc_serializable()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "87b8a7c6-35b7-4fab-938b-4d05e9cc06f1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"llm = OpenAI(model=\"gpt-3.5-turbo-instruct\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "88ce018b",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Dump\n",
|
||||
"\n",
|
||||
"Any serializable object can be serialized to a dict or json string."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "f12b28f3",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'lc': 1,\n",
|
||||
" 'type': 'constructor',\n",
|
||||
" 'id': ['langchain', 'llms', 'openai', 'OpenAI'],\n",
|
||||
" 'kwargs': {'model': 'gpt-3.5-turbo-instruct',\n",
|
||||
" 'openai_api_key': {'lc': 1, 'type': 'secret', 'id': ['OPENAI_API_KEY']}}}"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain.load import dumpd, dumps\n",
|
||||
"\n",
|
||||
"dumpd(llm)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "095b1d56",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'{\"lc\": 1, \"type\": \"constructor\", \"id\": [\"langchain\", \"llms\", \"openai\", \"OpenAI\"], \"kwargs\": {\"model\": \"gpt-3.5-turbo-instruct\", \"openai_api_key\": {\"lc\": 1, \"type\": \"secret\", \"id\": [\"OPENAI_API_KEY\"]}}}'"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"dumps(llm)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ab3e4223",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Load\n",
|
||||
"\n",
|
||||
"Any serialized object can be loaded."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "68e45b1c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.load import loads\n",
|
||||
"from langchain.load.load import load\n",
|
||||
"\n",
|
||||
"loaded_1 = load(dumpd(llm))\n",
|
||||
"loaded_2 = loads(dumps(llm))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"id": "c9272667-7fe3-4e5f-a1cc-69e8829b9e8f",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"\n",
|
||||
"I am an AI and do not have the capability to experience emotions. But thank you for asking. Is there anything I can assist you with?\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(loaded_1.invoke(\"How are you doing?\"))"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -6,8 +6,8 @@
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"---\n",
|
||||
"sidebar_position: 2\n",
|
||||
"title: LLMs\n",
|
||||
"sidebar_position: 0\n",
|
||||
"title: Quick Start\n",
|
||||
"---"
|
||||
]
|
||||
},
|
||||
@@ -16,11 +16,7 @@
|
||||
"id": "bc68673f-2227-4ff3-8b7f-f672c0d662ed",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
":::info\n",
|
||||
"\n",
|
||||
"Head to [Integrations](/docs/integrations/llms/) for documentation on built-in integrations with LLM providers.\n",
|
||||
"\n",
|
||||
":::\n",
|
||||
"# Quick Start\n",
|
||||
"\n",
|
||||
"Large Language Models (LLMs) are a core component of LangChain.\n",
|
||||
"LangChain does not serve its own LLMs, but rather provides a standard interface for interacting with many different LLMs.\n",
|
||||
@@ -473,142 +469,6 @@
|
||||
"\n",
|
||||
"In LangSmith you can then provide feedback for any trace, compile annotated datasets for evals, debug performance in the playground, and more."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "20ef52be-6e51-43a3-be2a-b1a862d5fc80",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### [Legacy] `__call__`: string in -> string out\n",
|
||||
"The simplest way to use an LLM is a callable: pass in a string, get a string completion."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "1ce7ca36-35f6-4584-acd1-a082e1c01983",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'\\n\\nQ: What did the fish say when it hit the wall?\\nA: Dam!'"
|
||||
]
|
||||
},
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"llm(\"Tell me a joke\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7b4ad9e5-50ec-4031-bfaa-23a0130da3c6",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### [Legacy] `generate`: batch calls, richer outputs\n",
|
||||
"`generate` lets you call the model with a list of strings, getting back a more complete response than just the text. This complete response can include things like multiple top responses and other LLM provider-specific information:\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "af7b2d3d-ab7a-4b2a-a67a-9dd8129ca026",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"30"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"llm_result = llm.generate([\"Tell me a joke\", \"Tell me a poem\"] * 15)\n",
|
||||
"len(llm_result.generations)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "351c2604-e995-4395-8b0e-640332e0b290",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[Generation(text=\"\\n\\nQ: Why don't scientists trust atoms?\\nA: Because they make up everything!\", generation_info={'finish_reason': 'stop', 'logprobs': None})]"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"llm_result.generations[0]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "8324d177-badc-494c-ab41-afe4d0682d8e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[Generation(text='\\n\\nRoses are red,\\nViolets are blue,\\nSugar is sweet,\\nAnd so are you!', generation_info={'finish_reason': 'stop', 'logprobs': None})]"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"llm_result.generations[-1]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8ec12f03-749c-4487-b1f3-7dde5db9f82a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can also access provider specific information that is returned. This information is **not** standardized across providers."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "cad9e4c5-bdae-4641-b78f-42eedffccaff",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'token_usage': {'completion_tokens': 900,\n",
|
||||
" 'total_tokens': 1020,\n",
|
||||
" 'prompt_tokens': 120},\n",
|
||||
" 'model_name': 'text-davinci-003'}"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"llm_result.llm_output"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
@@ -627,7 +487,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.1"
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
@@ -1,39 +0,0 @@
|
||||
# List parser
|
||||
|
||||
This output parser can be used when you want to return a list of comma-separated items.
|
||||
|
||||
```python
|
||||
from langchain.output_parsers import CommaSeparatedListOutputParser
|
||||
from langchain.prompts import PromptTemplate
|
||||
from langchain.llms import OpenAI
|
||||
|
||||
output_parser = CommaSeparatedListOutputParser()
|
||||
|
||||
format_instructions = output_parser.get_format_instructions()
|
||||
prompt = PromptTemplate(
|
||||
template="List five {subject}.\n{format_instructions}",
|
||||
input_variables=["subject"],
|
||||
partial_variables={"format_instructions": format_instructions}
|
||||
)
|
||||
|
||||
model = OpenAI(temperature=0)
|
||||
|
||||
_input = prompt.format(subject="ice cream flavors")
|
||||
output = model(_input)
|
||||
|
||||
output_parser.parse(output)
|
||||
```
|
||||
|
||||
The resulting output will be:
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
['Vanilla',
|
||||
'Chocolate',
|
||||
'Strawberry',
|
||||
'Mint Chocolate Chip',
|
||||
'Cookies and Cream']
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
@@ -1,174 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0360be02",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Enum parser\n",
|
||||
"\n",
|
||||
"This notebook shows how to use an Enum output parser."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "2f039b4b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.output_parsers.enum import EnumOutputParser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "9a35d1a7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from enum import Enum\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class Colors(Enum):\n",
|
||||
" RED = \"red\"\n",
|
||||
" GREEN = \"green\"\n",
|
||||
" BLUE = \"blue\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "a90a66f5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"parser = EnumOutputParser(enum=Colors)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "c48b88cb",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"<Colors.RED: 'red'>"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"parser.parse(\"red\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "7d313e41",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"<Colors.GREEN: 'green'>"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Can handle spaces\n",
|
||||
"parser.parse(\" green\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "976ae42d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"<Colors.BLUE: 'blue'>"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# And new lines\n",
|
||||
"parser.parse(\"blue\\n\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "636a48ab",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "OutputParserException",
|
||||
"evalue": "Response 'yellow' is not one of the expected values: ['red', 'green', 'blue']",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)",
|
||||
"File \u001b[0;32m~/workplace/langchain/langchain/output_parsers/enum.py:25\u001b[0m, in \u001b[0;36mEnumOutputParser.parse\u001b[0;34m(self, response)\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 25\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43menum\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresponse\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstrip\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m:\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.9.1/lib/python3.9/enum.py:315\u001b[0m, in \u001b[0;36mEnumMeta.__call__\u001b[0;34m(cls, value, names, module, qualname, type, start)\u001b[0m\n\u001b[1;32m 314\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m names \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m: \u001b[38;5;66;03m# simple value lookup\u001b[39;00m\n\u001b[0;32m--> 315\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mcls\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__new__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mcls\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 316\u001b[0m \u001b[38;5;66;03m# otherwise, functional API: we're creating a new Enum type\u001b[39;00m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.9.1/lib/python3.9/enum.py:611\u001b[0m, in \u001b[0;36mEnum.__new__\u001b[0;34m(cls, value)\u001b[0m\n\u001b[1;32m 610\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m result \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m exc \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m--> 611\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m ve_exc\n\u001b[1;32m 612\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m exc \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
|
||||
"\u001b[0;31mValueError\u001b[0m: 'yellow' is not a valid Colors",
|
||||
"\nDuring handling of the above exception, another exception occurred:\n",
|
||||
"\u001b[0;31mOutputParserException\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[8], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;66;03m# And raises errors when appropriate\u001b[39;00m\n\u001b[0;32m----> 2\u001b[0m \u001b[43mparser\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43myellow\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/workplace/langchain/langchain/output_parsers/enum.py:27\u001b[0m, in \u001b[0;36mEnumOutputParser.parse\u001b[0;34m(self, response)\u001b[0m\n\u001b[1;32m 25\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39menum(response\u001b[38;5;241m.\u001b[39mstrip())\n\u001b[1;32m 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m:\n\u001b[0;32m---> 27\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m OutputParserException(\n\u001b[1;32m 28\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mResponse \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mresponse\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m is not one of the \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 29\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mexpected values: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_valid_values\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 30\u001b[0m )\n",
|
||||
"\u001b[0;31mOutputParserException\u001b[0m: Response 'yellow' is not one of the expected values: ['red', 'green', 'blue']"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# And raises errors when appropriate\n",
|
||||
"parser.parse(\"yellow\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c517f447",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
16
docs/docs/modules/model_io/output_parsers/index.mdx
Normal file
16
docs/docs/modules/model_io/output_parsers/index.mdx
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
---
|
||||
# Output Parsers
|
||||
|
||||
Output parsers are responsible for taking the output of an LLM and transforming it to a more suitable format. This is very useful when you are asing LLMs to generate any form of structured data.
|
||||
|
||||
Besides having a large collection of different types of output parsers, one distinguishing benefit of LangChain OutputParsers is that many of them support streaming.
|
||||
|
||||
## [Quick Start](./quick_start)
|
||||
|
||||
See [this quick-start guide](./quick_start) for an introduction to output parsers and how to work with them.
|
||||
|
||||
## [Output Parser Types](./types)
|
||||
|
||||
LangChain has lots of different types of output parsers. See [this table](./types) for a breakdown of what types exist and when to use them.
|
||||
@@ -1,116 +0,0 @@
|
||||
# Auto-fixing parser
|
||||
|
||||
This output parser wraps another output parser, and in the event that the first one fails it calls out to another LLM to fix any errors.
|
||||
|
||||
But we can do other things besides throw errors. Specifically, we can pass the misformatted output, along with the formatted instructions, to the model and ask it to fix it.
|
||||
|
||||
For this example, we'll use the above Pydantic output parser. Here's what happens if we pass it a result that does not comply with the schema:
|
||||
|
||||
```python
|
||||
from langchain.chat_models import ChatOpenAI
|
||||
from langchain.output_parsers import PydanticOutputParser
|
||||
from langchain_core.pydantic_v1 import BaseModel, Field
|
||||
from typing import List
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
class Actor(BaseModel):
|
||||
name: str = Field(description="name of an actor")
|
||||
film_names: List[str] = Field(description="list of names of films they starred in")
|
||||
|
||||
actor_query = "Generate the filmography for a random actor."
|
||||
|
||||
parser = PydanticOutputParser(pydantic_object=Actor)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
misformatted = "{'name': 'Tom Hanks', 'film_names': ['Forrest Gump']}"
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
parser.parse(misformatted)
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
JSONDecodeError Traceback (most recent call last)
|
||||
|
||||
File ~/workplace/langchain/langchain/output_parsers/pydantic.py:23, in PydanticOutputParser.parse(self, text)
|
||||
22 json_str = match.group()
|
||||
---> 23 json_object = json.loads(json_str)
|
||||
24 return self.pydantic_object.parse_obj(json_object)
|
||||
|
||||
|
||||
File ~/.pyenv/versions/3.9.1/lib/python3.9/json/__init__.py:346, in loads(s, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)
|
||||
343 if (cls is None and object_hook is None and
|
||||
344 parse_int is None and parse_float is None and
|
||||
345 parse_constant is None and object_pairs_hook is None and not kw):
|
||||
--> 346 return _default_decoder.decode(s)
|
||||
347 if cls is None:
|
||||
|
||||
|
||||
File ~/.pyenv/versions/3.9.1/lib/python3.9/json/decoder.py:337, in JSONDecoder.decode(self, s, _w)
|
||||
333 """Return the Python representation of ``s`` (a ``str`` instance
|
||||
334 containing a JSON document).
|
||||
335
|
||||
336 """
|
||||
--> 337 obj, end = self.raw_decode(s, idx=_w(s, 0).end())
|
||||
338 end = _w(s, end).end()
|
||||
|
||||
|
||||
File ~/.pyenv/versions/3.9.1/lib/python3.9/json/decoder.py:353, in JSONDecoder.raw_decode(self, s, idx)
|
||||
352 try:
|
||||
--> 353 obj, end = self.scan_once(s, idx)
|
||||
354 except StopIteration as err:
|
||||
|
||||
|
||||
JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
|
||||
|
||||
|
||||
During handling of the above exception, another exception occurred:
|
||||
|
||||
|
||||
OutputParserException Traceback (most recent call last)
|
||||
|
||||
Cell In[6], line 1
|
||||
----> 1 parser.parse(misformatted)
|
||||
|
||||
|
||||
File ~/workplace/langchain/langchain/output_parsers/pydantic.py:29, in PydanticOutputParser.parse(self, text)
|
||||
27 name = self.pydantic_object.__name__
|
||||
28 msg = f"Failed to parse {name} from completion {text}. Got: {e}"
|
||||
---> 29 raise OutputParserException(msg)
|
||||
|
||||
|
||||
OutputParserException: Failed to parse Actor from completion {'name': 'Tom Hanks', 'film_names': ['Forrest Gump']}. Got: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
Now we can construct and use a `OutputFixingParser`. This output parser takes as an argument another output parser but also an LLM with which to try to correct any formatting mistakes.
|
||||
|
||||
|
||||
```python
|
||||
from langchain.output_parsers import OutputFixingParser
|
||||
|
||||
new_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
new_parser.parse(misformatted)
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Actor(name='Tom Hanks', film_names=['Forrest Gump'])
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
@@ -1,229 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Pandas DataFrame Parser\n",
|
||||
"\n",
|
||||
"A Pandas DataFrame is a popular data structure in the Python programming language, commonly used for data manipulation and analysis. It provides a comprehensive set of tools for working with structured data, making it a versatile option for tasks such as data cleaning, transformation, and analysis.\n",
|
||||
"\n",
|
||||
"This output parser allows users to specify an arbitrary Pandas DataFrame and query LLMs for data in the form of a formatted dictionary that extracts data from the corresponding DataFrame. Keep in mind that large language models are leaky abstractions! You'll have to use an LLM with sufficient capacity to generate a well-formed query as per the defined format instructions.\n",
|
||||
"\n",
|
||||
"Use Pandas' DataFrame object to declare the DataFrame you wish to perform queries on."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pprint\n",
|
||||
"from typing import Any, Dict\n",
|
||||
"\n",
|
||||
"import pandas as pd\n",
|
||||
"from langchain.llms import OpenAI\n",
|
||||
"from langchain.output_parsers import PandasDataFrameOutputParser\n",
|
||||
"from langchain.prompts import PromptTemplate"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model_name = \"gpt-3.5-turbo-instruct\"\n",
|
||||
"temperature = 0.5\n",
|
||||
"model = OpenAI(model_name=model_name, temperature=temperature)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Solely for documentation purposes.\n",
|
||||
"def format_parser_output(parser_output: Dict[str, Any]) -> None:\n",
|
||||
" for key in parser_output.keys():\n",
|
||||
" parser_output[key] = parser_output[key].to_dict()\n",
|
||||
" return pprint.PrettyPrinter(width=4, compact=True).pprint(parser_output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Define your desired Pandas DataFrame.\n",
|
||||
"df = pd.DataFrame(\n",
|
||||
" {\n",
|
||||
" \"num_legs\": [2, 4, 8, 0],\n",
|
||||
" \"num_wings\": [2, 0, 0, 0],\n",
|
||||
" \"num_specimen_seen\": [10, 2, 1, 8],\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Set up a parser + inject instructions into the prompt template.\n",
|
||||
"parser = PandasDataFrameOutputParser(dataframe=df)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"LLM Output: column:num_wings\n",
|
||||
"{'num_wings': {0: 2,\n",
|
||||
" 1: 0,\n",
|
||||
" 2: 0,\n",
|
||||
" 3: 0}}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Here's an example of a column operation being performed.\n",
|
||||
"df_query = \"Retrieve the num_wings column.\"\n",
|
||||
"\n",
|
||||
"# Set up the prompt.\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"Answer the user query.\\n{format_instructions}\\n{query}\\n\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"_input = prompt.format_prompt(query=df_query)\n",
|
||||
"output = model(_input.to_string())\n",
|
||||
"print(\"LLM Output:\", output)\n",
|
||||
"parser_output = parser.parse(output)\n",
|
||||
"\n",
|
||||
"format_parser_output(parser_output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"LLM Output: row:1\n",
|
||||
"{'1': {'num_legs': 4,\n",
|
||||
" 'num_specimen_seen': 2,\n",
|
||||
" 'num_wings': 0}}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Here's an example of a row operation being performed.\n",
|
||||
"df_query = \"Retrieve the first row.\"\n",
|
||||
"\n",
|
||||
"# Set up the prompt.\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"Answer the user query.\\n{format_instructions}\\n{query}\\n\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"_input = prompt.format_prompt(query=df_query)\n",
|
||||
"output = model(_input.to_string())\n",
|
||||
"print(\"LLM Output:\", output)\n",
|
||||
"parser_output = parser.parse(output)\n",
|
||||
"\n",
|
||||
"format_parser_output(parser_output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"LLM Output: mean:num_legs[1..3]\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'mean': 4.0}"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Here's an example of a random Pandas DataFrame operation limiting the number of rows\n",
|
||||
"df_query = \"Retrieve the average of the num_legs column from rows 1 to 3.\"\n",
|
||||
"\n",
|
||||
"# Set up the prompt.\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"Answer the user query.\\n{format_instructions}\\n{query}\\n\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"_input = prompt.format_prompt(query=df_query)\n",
|
||||
"output = model(_input.to_string())\n",
|
||||
"print(\"LLM Output:\", output)\n",
|
||||
"parser.parse(output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Here's an example of a poorly formatted query\n",
|
||||
"df_query = \"Retrieve the mean of the num_fingers column.\"\n",
|
||||
"\n",
|
||||
"# Set up the prompt.\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"Answer the user query.\\n{format_instructions}\\n{query}\\n\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"_input = prompt.format_prompt(query=df_query)\n",
|
||||
"output = model(_input.to_string()) # Expected Output: \"Invalid column: num_fingers\".\n",
|
||||
"print(\"LLM Output:\", output)\n",
|
||||
"parser.parse(output) # Expected Output: Will raise an OutputParserException."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "venv",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.2"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -238,9 +238,9 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "poetry-venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "poetry-venv"
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
@@ -252,7 +252,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.1"
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
@@ -1,97 +0,0 @@
|
||||
# Structured output parser
|
||||
|
||||
This output parser can be used when you want to return multiple fields. While the Pydantic/JSON parser is more powerful, we initially experimented with data structures having text fields only.
|
||||
|
||||
```python
|
||||
from langchain.output_parsers import StructuredOutputParser, ResponseSchema
|
||||
from langchain.prompts import PromptTemplate, ChatPromptTemplate, HumanMessagePromptTemplate
|
||||
from langchain.llms import OpenAI
|
||||
from langchain.chat_models import ChatOpenAI
|
||||
```
|
||||
|
||||
Here we define the response schema we want to receive.
|
||||
|
||||
|
||||
```python
|
||||
response_schemas = [
|
||||
ResponseSchema(name="answer", description="answer to the user's question"),
|
||||
ResponseSchema(name="source", description="source used to answer the user's question, should be a website.")
|
||||
]
|
||||
output_parser = StructuredOutputParser.from_response_schemas(response_schemas)
|
||||
```
|
||||
|
||||
We now get a string that contains instructions for how the response should be formatted, and we then insert that into our prompt.
|
||||
|
||||
|
||||
```python
|
||||
format_instructions = output_parser.get_format_instructions()
|
||||
prompt = PromptTemplate(
|
||||
template="answer the users question as best as possible.\n{format_instructions}\n{question}",
|
||||
input_variables=["question"],
|
||||
partial_variables={"format_instructions": format_instructions}
|
||||
)
|
||||
```
|
||||
|
||||
We can now use this to format a prompt to send to the language model, and then parse the returned result.
|
||||
|
||||
|
||||
```python
|
||||
model = OpenAI(temperature=0)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
_input = prompt.format_prompt(question="what's the capital of france?")
|
||||
output = model(_input.to_string())
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
output_parser.parse(output)
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
{'answer': 'Paris',
|
||||
'source': 'https://www.worldatlas.com/articles/what-is-the-capital-of-france.html'}
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
And here's an example of using this in a chat model
|
||||
|
||||
|
||||
```python
|
||||
chat_model = ChatOpenAI(temperature=0)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
prompt = ChatPromptTemplate(
|
||||
messages=[
|
||||
HumanMessagePromptTemplate.from_template("answer the users question as best as possible.\n{format_instructions}\n{question}")
|
||||
],
|
||||
input_variables=["question"],
|
||||
partial_variables={"format_instructions": format_instructions}
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
_input = prompt.format_prompt(question="what's the capital of france?")
|
||||
output = chat_model(_input.to_messages())
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
output_parser.parse(output.content)
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
{'answer': 'Paris', 'source': 'https://en.wikipedia.org/wiki/Paris'}
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
116
docs/docs/modules/model_io/output_parsers/types/csv.ipynb
Normal file
116
docs/docs/modules/model_io/output_parsers/types/csv.ipynb
Normal file
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "e3fbf5c7",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# CSV parser\n",
|
||||
"\n",
|
||||
"This output parser can be used when you want to return a list of comma-separated items."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "7e7f40d8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.chat_models import ChatOpenAI\n",
|
||||
"from langchain.output_parsers import CommaSeparatedListOutputParser\n",
|
||||
"from langchain.prompts import PromptTemplate\n",
|
||||
"\n",
|
||||
"output_parser = CommaSeparatedListOutputParser()\n",
|
||||
"\n",
|
||||
"format_instructions = output_parser.get_format_instructions()\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"List five {subject}.\\n{format_instructions}\",\n",
|
||||
" input_variables=[\"subject\"],\n",
|
||||
" partial_variables={\"format_instructions\": format_instructions},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"model = ChatOpenAI(temperature=0)\n",
|
||||
"\n",
|
||||
"chain = prompt | model | output_parser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "fca9f502",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"['Vanilla',\n",
|
||||
" 'Chocolate',\n",
|
||||
" 'Strawberry',\n",
|
||||
" 'Mint Chocolate Chip',\n",
|
||||
" 'Cookies and Cream']"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"chain.invoke({\"subject\": \"ice cream flavors\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "39381846",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"['Vanilla']\n",
|
||||
"['Chocolate']\n",
|
||||
"['Strawberry']\n",
|
||||
"['Mint Chocolate Chip']\n",
|
||||
"['Cookies and Cream']\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for s in chain.stream({\"subject\": \"ice cream flavors\"}):\n",
|
||||
" print(s)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "13cc7be2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.chains import LLMChain\n",
|
||||
"from langchain.llms import OpenAI\n",
|
||||
"from langchain.output_parsers import DatetimeOutputParser\n",
|
||||
"from langchain.prompts import PromptTemplate"
|
||||
@@ -45,69 +44,66 @@
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "9240a3ae",
|
||||
"id": "dc5727d3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"PromptTemplate(input_variables=['question'], partial_variables={'format_instructions': \"Write a datetime string that matches the following pattern: '%Y-%m-%dT%H:%M:%S.%fZ'.\\n\\nExamples: 0668-08-09T12:56:32.732651Z, 1213-06-23T21:01:36.868629Z, 0713-07-06T18:19:02.257488Z\\n\\nReturn ONLY this string, no other words!\"}, template='Answer the users question:\\n\\n{question}\\n\\n{format_instructions}')"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"chain = LLMChain(prompt=prompt, llm=OpenAI())"
|
||||
"prompt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "ad62eacc",
|
||||
"id": "9240a3ae",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"output = chain.run(\"around when was bitcoin founded?\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "96657765",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'\\n\\n2008-01-03T18:15:05.000000Z'"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"output"
|
||||
"chain = prompt | OpenAI() | output_parser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "bf714e52",
|
||||
"id": "ad62eacc",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"output = chain.invoke({\"question\": \"when was bitcoin founded?\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "a56112b1",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"datetime.datetime(2008, 1, 3, 18, 15, 5)"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"2009-01-03 18:15:05\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"output_parser.parse(output)"
|
||||
"print(output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a56112b1",
|
||||
"id": "ad1f7e8d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
@@ -129,7 +125,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
120
docs/docs/modules/model_io/output_parsers/types/enum.ipynb
Normal file
120
docs/docs/modules/model_io/output_parsers/types/enum.ipynb
Normal file
@@ -0,0 +1,120 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0360be02",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Enum parser\n",
|
||||
"\n",
|
||||
"This notebook shows how to use an Enum output parser."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "2f039b4b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.output_parsers.enum import EnumOutputParser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "9a35d1a7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from enum import Enum\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class Colors(Enum):\n",
|
||||
" RED = \"red\"\n",
|
||||
" GREEN = \"green\"\n",
|
||||
" BLUE = \"blue\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "a90a66f5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"parser = EnumOutputParser(enum=Colors)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "c517f447",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain_community.chat_models import ChatOpenAI\n",
|
||||
"from langchain_core.prompts import PromptTemplate\n",
|
||||
"\n",
|
||||
"prompt = PromptTemplate.from_template(\n",
|
||||
" \"\"\"What color eyes does this person have?\n",
|
||||
"\n",
|
||||
"> Person: {person}\n",
|
||||
"\n",
|
||||
"Instructions: {instructions}\"\"\"\n",
|
||||
").partial(instructions=parser.get_format_instructions())\n",
|
||||
"chain = prompt | ChatOpenAI() | parser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "088f634c",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"<Colors.BLUE: 'blue'>"
|
||||
]
|
||||
},
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"chain.invoke({\"person\": \"Frank Sinatra\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8f0a5f80",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
31
docs/docs/modules/model_io/output_parsers/types/index.mdx
Normal file
31
docs/docs/modules/model_io/output_parsers/types/index.mdx
Normal file
@@ -0,0 +1,31 @@
|
||||
# Output Parser Types
|
||||
|
||||
This is a list of output parsers LangChain supports. The table below has various pieces of information:
|
||||
|
||||
**Name**: The name of the output parser
|
||||
|
||||
**Supports Streaming**: Whether the output parser supports streaming.
|
||||
|
||||
**Has Format Instructions**: Whether the output parser has format instructions. This is generally available except when (a) the desired schema is not specified in the prompt but rather in other parameters (like OpenAI function calling), or (b) when the OutputParser wraps another OutputParser.
|
||||
|
||||
**Calls LLM**: Whether this output parser itself calls an LLM. This is usually only done by output parsers that attempt to correct misformatted output.
|
||||
|
||||
**Input Type**: Expected input type. Most output parsers work on both strings and messages, but some (like OpenAI Functions) need a message with specific kwargs.
|
||||
|
||||
**Output Type**: The output type of the object returned by the parser.
|
||||
|
||||
**Description**: Our commentary on this output parser and when to use it.
|
||||
|
||||
| Name | Supports Streaming | Has Format Instructions | Calls LLM | Input Type | Output Type | Description | | |
|
||||
|-----------------|--------------------|-------------------------------|-----------|----------------------------------|----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---|---|
|
||||
| [OpenAIFunctions](./openai_functions) | ✅ | (Passes `functions` to model) | | `Message` (with `function_call`) | JSON object | Uses OpenAI function calling to structure the return output. If you are using a model that supports function calling, this is generally the most reliable method. | | |
|
||||
| [JSON](./json) | ✅ | ✅ | | `str \| Message` | JSON object | Returns a JSON object as specified. You can specify a Pydantic model and it will return JSON for that model. Probably the most reliable output parser for getting structured data that does NOT use function calling. | | |
|
||||
| [XML](./xml) | ✅ | ✅ | | `str \| Message` | `dict` | Returns a dictionary of tags. Use when XML output is needed. Use with models that are good at writing XML (like Anthropic's). | | |
|
||||
| [CSV](./csv) | ✅ | ✅ | | `str \| Message` | `List[str]` | Returns a list of comma separated values. | | |
|
||||
| [OutputFixing](./output_fixing) | | | ✅ | `str \| Message` | | Wraps another output parser. If that output parser errors, then this will pass the error message and the bad output to an LLM and ask it to fix the output. | | |
|
||||
| [RetryWithError](./retry) | | | ✅ | `str \| Message` | | Wraps another output parser. If that output parser errors, then this will pass the original inputs, the bad output, and the error message to an LLM and ask it to fix it. Compared to OutputFixingParser, this one also sends the original instructions. | | |
|
||||
| [Pydantic](./pydantic) | | ✅ | | `str \| Message` | `pydantic.BaseModel` | Takes a user defined Pydantic model and returns data in that format. | | |
|
||||
| [PandasDataFrame](./pandas_dataframe) | | ✅ | | `str \| Message` | `dict` | Useful for doing operations with pandas DataFrames. | | |
|
||||
| [Enum](./enum) | | ✅ | | `str \| Message` | `Enum` | Parses response into one of the provided enum values. | | |
|
||||
| [Datetime](./datetime) | | ✅ | | `str \| Message` | `datetime.datetime` | Parses response into a datetime string. | | |
|
||||
| [Structured](./structured) | | ✅ | | `str \| Message` | `Dict[str, str]` | An output parser that returns structured information. It is less powerful than other output parsers since it only allows for fields to be strings. This can be useful when you are working with smaller LLMs. | | |
|
||||
205
docs/docs/modules/model_io/output_parsers/types/json.ipynb
Normal file
205
docs/docs/modules/model_io/output_parsers/types/json.ipynb
Normal file
@@ -0,0 +1,205 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "72b1b316",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# JSON parser\n",
|
||||
"This output parser allows users to specify an arbitrary JSON schema and query LLMs for outputs that conform to that schema.\n",
|
||||
"\n",
|
||||
"Keep in mind that large language models are leaky abstractions! You'll have to use an LLM with sufficient capacity to generate well-formed JSON. In the OpenAI family, DaVinci can do reliably but Curie's ability already drops off dramatically. \n",
|
||||
"\n",
|
||||
"You can optionally use Pydantic to declare your data model."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "cd33369f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import List\n",
|
||||
"\n",
|
||||
"from langchain.chat_models import ChatOpenAI\n",
|
||||
"from langchain.prompts import PromptTemplate\n",
|
||||
"from langchain_core.output_parsers import JsonOutputParser\n",
|
||||
"from langchain_core.pydantic_v1 import BaseModel, Field"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "9b4d242f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model = ChatOpenAI(temperature=0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "a1090014",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Define your desired data structure.\n",
|
||||
"class Joke(BaseModel):\n",
|
||||
" setup: str = Field(description=\"question to set up a joke\")\n",
|
||||
" punchline: str = Field(description=\"answer to resolve the joke\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "4ccf45a3",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'setup': \"Why don't scientists trust atoms?\",\n",
|
||||
" 'punchline': 'Because they make up everything!'}"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# And a query intented to prompt a language model to populate the data structure.\n",
|
||||
"joke_query = \"Tell me a joke.\"\n",
|
||||
"\n",
|
||||
"# Set up a parser + inject instructions into the prompt template.\n",
|
||||
"parser = JsonOutputParser(pydantic_object=Joke)\n",
|
||||
"\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"Answer the user query.\\n{format_instructions}\\n{query}\\n\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"chain = prompt | model | parser\n",
|
||||
"\n",
|
||||
"chain.invoke({\"query\": joke_query})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "37d801be",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Streaming\n",
|
||||
"\n",
|
||||
"This output parser supports streaming."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "0309256d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'setup': ''}\n",
|
||||
"{'setup': 'Why'}\n",
|
||||
"{'setup': 'Why don'}\n",
|
||||
"{'setup': \"Why don't\"}\n",
|
||||
"{'setup': \"Why don't scientists\"}\n",
|
||||
"{'setup': \"Why don't scientists trust\"}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms\"}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': ''}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because'}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they'}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make'}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up'}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything'}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for s in chain.stream({\"query\": joke_query}):\n",
|
||||
" print(s)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "344bd968",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Without Pydantic\n",
|
||||
"\n",
|
||||
"You can also use this without Pydantic. This will prompt it return JSON, but doesn't provide specific about what the schema should be."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "dd3806d1",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'joke': \"Why don't scientists trust atoms? Because they make up everything!\"}"
|
||||
]
|
||||
},
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"joke_query = \"Tell me a joke.\"\n",
|
||||
"\n",
|
||||
"parser = JsonOutputParser()\n",
|
||||
"\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"Answer the user query.\\n{format_instructions}\\n{query}\\n\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"chain = prompt | model | parser\n",
|
||||
"\n",
|
||||
"chain.invoke({\"query\": joke_query})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a4d12261",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,405 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "bcbe5c87",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# OpenAI Functions\n",
|
||||
"\n",
|
||||
"These output parsers use OpenAI function calling to structure its outputs. This means they are only usable with models that support function calling. There are a few different variants:\n",
|
||||
"\n",
|
||||
"- JsonOutputFunctionsParser: Returns the arguments of the function call as JSON\n",
|
||||
"- PydanticOutputFunctionsParser: Returns the arguments of the function call as a Pydantic Model\n",
|
||||
"- JsonKeyOutputFunctionsParser: Returns the value of specific key in the function call as JSON\n",
|
||||
"- PydanticAttrOutputFunctionsParser: Returns the value of specific key in the function call as a Pydantic Model\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 38,
|
||||
"id": "aac4262b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain_community.chat_models import ChatOpenAI\n",
|
||||
"from langchain_community.utils.openai_functions import (\n",
|
||||
" convert_pydantic_to_openai_function,\n",
|
||||
")\n",
|
||||
"from langchain_core.prompts import ChatPromptTemplate\n",
|
||||
"from langchain_core.pydantic_v1 import BaseModel, Field, validator"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "52cb351d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Joke(BaseModel):\n",
|
||||
" \"\"\"Joke to tell user.\"\"\"\n",
|
||||
"\n",
|
||||
" setup: str = Field(description=\"question to set up a joke\")\n",
|
||||
" punchline: str = Field(description=\"answer to resolve the joke\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"openai_functions = [convert_pydantic_to_openai_function(Joke)]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "2c3259c4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model = ChatOpenAI(temperature=0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "d3e9007c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"prompt = ChatPromptTemplate.from_messages(\n",
|
||||
" [(\"system\", \"You are helpful assistant\"), (\"user\", \"{input}\")]\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "87680951",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## JsonOutputFunctionsParser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "cb065bdd",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"id": "6ff758c8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"parser = JsonOutputFunctionsParser()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "27a3acd1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"chain = prompt | model.bind(functions=openai_functions) | parser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"id": "59b59179",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'setup': \"Why don't scientists trust atoms?\",\n",
|
||||
" 'punchline': 'Because they make up everything!'}"
|
||||
]
|
||||
},
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"chain.invoke({\"input\": \"tell me a joke\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"id": "cdbd0a99",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{}\n",
|
||||
"{'setup': ''}\n",
|
||||
"{'setup': 'Why'}\n",
|
||||
"{'setup': 'Why don'}\n",
|
||||
"{'setup': \"Why don't\"}\n",
|
||||
"{'setup': \"Why don't scientists\"}\n",
|
||||
"{'setup': \"Why don't scientists trust\"}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms\"}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': ''}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because'}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they'}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make'}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up'}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything'}\n",
|
||||
"{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for s in chain.stream({\"input\": \"tell me a joke\"}):\n",
|
||||
" print(s)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7ca55ac9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## JsonKeyOutputFunctionsParser\n",
|
||||
"\n",
|
||||
"This merely extracts a single key from the returned response. This is useful for when you want to return a list of things."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"id": "f8bc404e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import List\n",
|
||||
"\n",
|
||||
"from langchain.output_parsers.openai_functions import JsonKeyOutputFunctionsParser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 31,
|
||||
"id": "9b91ff36",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Jokes(BaseModel):\n",
|
||||
" \"\"\"Jokes to tell user.\"\"\"\n",
|
||||
"\n",
|
||||
" joke: List[Joke]\n",
|
||||
" funniness_level: int"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 32,
|
||||
"id": "c91c5949",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"parser = JsonKeyOutputFunctionsParser(key_name=\"joke\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 33,
|
||||
"id": "b4583baf",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"openai_functions = [convert_pydantic_to_openai_function(Jokes)]\n",
|
||||
"chain = prompt | model.bind(functions=openai_functions) | parser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 34,
|
||||
"id": "e8b766ff",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[{'setup': \"Why don't scientists trust atoms?\",\n",
|
||||
" 'punchline': 'Because they make up everything!'},\n",
|
||||
" {'setup': 'Why did the scarecrow win an award?',\n",
|
||||
" 'punchline': 'Because he was outstanding in his field!'}]"
|
||||
]
|
||||
},
|
||||
"execution_count": 34,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"chain.invoke({\"input\": \"tell me two jokes\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 35,
|
||||
"id": "f74ef675",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[]\n",
|
||||
"[{}]\n",
|
||||
"[{'setup': ''}]\n",
|
||||
"[{'setup': 'Why'}]\n",
|
||||
"[{'setup': 'Why don'}]\n",
|
||||
"[{'setup': \"Why don't\"}]\n",
|
||||
"[{'setup': \"Why don't scientists\"}]\n",
|
||||
"[{'setup': \"Why don't scientists trust\"}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms\"}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': ''}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': ''}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scare'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scarecrow'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scarecrow win'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scarecrow win an'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scarecrow win an award'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scarecrow win an award?', 'punchline': ''}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scarecrow win an award?', 'punchline': 'Because'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scarecrow win an award?', 'punchline': 'Because he'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scarecrow win an award?', 'punchline': 'Because he was'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scarecrow win an award?', 'punchline': 'Because he was outstanding'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scarecrow win an award?', 'punchline': 'Because he was outstanding in'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scarecrow win an award?', 'punchline': 'Because he was outstanding in his'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scarecrow win an award?', 'punchline': 'Because he was outstanding in his field'}]\n",
|
||||
"[{'setup': \"Why don't scientists trust atoms?\", 'punchline': 'Because they make up everything!'}, {'setup': 'Why did the scarecrow win an award?', 'punchline': 'Because he was outstanding in his field!'}]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for s in chain.stream({\"input\": \"tell me two jokes\"}):\n",
|
||||
" print(s)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "941a3d4e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## PydanticOutputFunctionsParser\n",
|
||||
"\n",
|
||||
"This builds on top of `JsonOutputFunctionsParser` but passes the results to a Pydantic Model. This allows for further validation should you choose."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 41,
|
||||
"id": "f51823fe",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.output_parsers.openai_functions import PydanticOutputFunctionsParser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 42,
|
||||
"id": "3c6a5e4d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Joke(BaseModel):\n",
|
||||
" \"\"\"Joke to tell user.\"\"\"\n",
|
||||
"\n",
|
||||
" setup: str = Field(description=\"question to set up a joke\")\n",
|
||||
" punchline: str = Field(description=\"answer to resolve the joke\")\n",
|
||||
"\n",
|
||||
" # You can add custom validation logic easily with Pydantic.\n",
|
||||
" @validator(\"setup\")\n",
|
||||
" def question_ends_with_question_mark(cls, field):\n",
|
||||
" if field[-1] != \"?\":\n",
|
||||
" raise ValueError(\"Badly formed question!\")\n",
|
||||
" return field\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"parser = PydanticOutputFunctionsParser(pydantic_schema=Joke)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 44,
|
||||
"id": "d2bbd54f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"openai_functions = [convert_pydantic_to_openai_function(Joke)]\n",
|
||||
"chain = prompt | model.bind(functions=openai_functions) | parser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 45,
|
||||
"id": "db1a06e8",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Joke(setup=\"Why don't scientists trust atoms?\", punchline='Because they make up everything!')"
|
||||
]
|
||||
},
|
||||
"execution_count": 45,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"chain.invoke({\"input\": \"tell me a joke\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "d96211e7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "0fee7096",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Output-fixing parser\n",
|
||||
"\n",
|
||||
"This output parser wraps another output parser, and in the event that the first one fails it calls out to another LLM to fix any errors.\n",
|
||||
"\n",
|
||||
"But we can do other things besides throw errors. Specifically, we can pass the misformatted output, along with the formatted instructions, to the model and ask it to fix it.\n",
|
||||
"\n",
|
||||
"For this example, we'll use the above Pydantic output parser. Here's what happens if we pass it a result that does not comply with the schema:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "9bad594d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import List\n",
|
||||
"\n",
|
||||
"from langchain.chat_models import ChatOpenAI\n",
|
||||
"from langchain.output_parsers import PydanticOutputParser\n",
|
||||
"from langchain_core.pydantic_v1 import BaseModel, Field"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "15283e0b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class Actor(BaseModel):\n",
|
||||
" name: str = Field(description=\"name of an actor\")\n",
|
||||
" film_names: List[str] = Field(description=\"list of names of films they starred in\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"actor_query = \"Generate the filmography for a random actor.\"\n",
|
||||
"\n",
|
||||
"parser = PydanticOutputParser(pydantic_object=Actor)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "072d2d4c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"misformatted = \"{'name': 'Tom Hanks', 'film_names': ['Forrest Gump']}\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "4cbb35b3",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "OutputParserException",
|
||||
"evalue": "Failed to parse Actor from completion {'name': 'Tom Hanks', 'film_names': ['Forrest Gump']}. Got: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mJSONDecodeError\u001b[0m Traceback (most recent call last)",
|
||||
"File \u001b[0;32m~/workplace/langchain/libs/langchain/langchain/output_parsers/pydantic.py:29\u001b[0m, in \u001b[0;36mPydanticOutputParser.parse\u001b[0;34m(self, text)\u001b[0m\n\u001b[1;32m 28\u001b[0m json_str \u001b[38;5;241m=\u001b[39m match\u001b[38;5;241m.\u001b[39mgroup()\n\u001b[0;32m---> 29\u001b[0m json_object \u001b[38;5;241m=\u001b[39m \u001b[43mjson\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mloads\u001b[49m\u001b[43m(\u001b[49m\u001b[43mjson_str\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstrict\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[1;32m 30\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpydantic_object\u001b[38;5;241m.\u001b[39mparse_obj(json_object)\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.10.1/lib/python3.10/json/__init__.py:359\u001b[0m, in \u001b[0;36mloads\u001b[0;34m(s, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, **kw)\u001b[0m\n\u001b[1;32m 358\u001b[0m kw[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mparse_constant\u001b[39m\u001b[38;5;124m'\u001b[39m] \u001b[38;5;241m=\u001b[39m parse_constant\n\u001b[0;32m--> 359\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mcls\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkw\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdecode\u001b[49m\u001b[43m(\u001b[49m\u001b[43ms\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.10.1/lib/python3.10/json/decoder.py:337\u001b[0m, in \u001b[0;36mJSONDecoder.decode\u001b[0;34m(self, s, _w)\u001b[0m\n\u001b[1;32m 333\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"Return the Python representation of ``s`` (a ``str`` instance\u001b[39;00m\n\u001b[1;32m 334\u001b[0m \u001b[38;5;124;03mcontaining a JSON document).\u001b[39;00m\n\u001b[1;32m 335\u001b[0m \n\u001b[1;32m 336\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m--> 337\u001b[0m obj, end \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mraw_decode\u001b[49m\u001b[43m(\u001b[49m\u001b[43ms\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43midx\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m_w\u001b[49m\u001b[43m(\u001b[49m\u001b[43ms\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mend\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 338\u001b[0m end \u001b[38;5;241m=\u001b[39m _w(s, end)\u001b[38;5;241m.\u001b[39mend()\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.10.1/lib/python3.10/json/decoder.py:353\u001b[0m, in \u001b[0;36mJSONDecoder.raw_decode\u001b[0;34m(self, s, idx)\u001b[0m\n\u001b[1;32m 352\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 353\u001b[0m obj, end \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mscan_once\u001b[49m\u001b[43m(\u001b[49m\u001b[43ms\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43midx\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 354\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mStopIteration\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n",
|
||||
"\u001b[0;31mJSONDecodeError\u001b[0m: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)",
|
||||
"\nDuring handling of the above exception, another exception occurred:\n",
|
||||
"\u001b[0;31mOutputParserException\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[4], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mparser\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmisformatted\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/workplace/langchain/libs/langchain/langchain/output_parsers/pydantic.py:35\u001b[0m, in \u001b[0;36mPydanticOutputParser.parse\u001b[0;34m(self, text)\u001b[0m\n\u001b[1;32m 33\u001b[0m name \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpydantic_object\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__name__\u001b[39m\n\u001b[1;32m 34\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFailed to parse \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m from completion \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m. Got: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00me\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m---> 35\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m OutputParserException(msg, llm_output\u001b[38;5;241m=\u001b[39mtext)\n",
|
||||
"\u001b[0;31mOutputParserException\u001b[0m: Failed to parse Actor from completion {'name': 'Tom Hanks', 'film_names': ['Forrest Gump']}. Got: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"parser.parse(misformatted)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "723c559d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now we can construct and use a `OutputFixingParser`. This output parser takes as an argument another output parser but also an LLM with which to try to correct any formatting mistakes."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "4aaccbf1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.output_parsers import OutputFixingParser\n",
|
||||
"\n",
|
||||
"new_parser = OutputFixingParser.from_llm(parser=parser, llm=ChatOpenAI())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "8031c22d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Actor(name='Tom Hanks', film_names=['Forrest Gump'])"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"new_parser.parse(misformatted)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bc7af2a0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Pandas DataFrame Parser\n",
|
||||
"\n",
|
||||
"A Pandas DataFrame is a popular data structure in the Python programming language, commonly used for data manipulation and analysis. It provides a comprehensive set of tools for working with structured data, making it a versatile option for tasks such as data cleaning, transformation, and analysis.\n",
|
||||
"\n",
|
||||
"This output parser allows users to specify an arbitrary Pandas DataFrame and query LLMs for data in the form of a formatted dictionary that extracts data from the corresponding DataFrame. Keep in mind that large language models are leaky abstractions! You'll have to use an LLM with sufficient capacity to generate a well-formed query as per the defined format instructions.\n",
|
||||
"\n",
|
||||
"Use Pandas' DataFrame object to declare the DataFrame you wish to perform queries on."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pprint\n",
|
||||
"from typing import Any, Dict\n",
|
||||
"\n",
|
||||
"import pandas as pd\n",
|
||||
"from langchain.chat_models import ChatOpenAI\n",
|
||||
"from langchain.output_parsers import PandasDataFrameOutputParser\n",
|
||||
"from langchain.prompts import PromptTemplate"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model = ChatOpenAI(temperature=0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Solely for documentation purposes.\n",
|
||||
"def format_parser_output(parser_output: Dict[str, Any]) -> None:\n",
|
||||
" for key in parser_output.keys():\n",
|
||||
" parser_output[key] = parser_output[key].to_dict()\n",
|
||||
" return pprint.PrettyPrinter(width=4, compact=True).pprint(parser_output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Define your desired Pandas DataFrame.\n",
|
||||
"df = pd.DataFrame(\n",
|
||||
" {\n",
|
||||
" \"num_legs\": [2, 4, 8, 0],\n",
|
||||
" \"num_wings\": [2, 0, 0, 0],\n",
|
||||
" \"num_specimen_seen\": [10, 2, 1, 8],\n",
|
||||
" }\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Set up a parser + inject instructions into the prompt template.\n",
|
||||
"parser = PandasDataFrameOutputParser(dataframe=df)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 24,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'num_wings': {0: 2,\n",
|
||||
" 1: 0,\n",
|
||||
" 2: 0,\n",
|
||||
" 3: 0}}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Here's an example of a column operation being performed.\n",
|
||||
"df_query = \"Retrieve the num_wings column.\"\n",
|
||||
"\n",
|
||||
"# Set up the prompt.\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"Answer the user query.\\n{format_instructions}\\n{query}\\n\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"chain = prompt | model | parser\n",
|
||||
"parser_output = chain.invoke({\"query\": df_query})\n",
|
||||
"\n",
|
||||
"format_parser_output(parser_output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'0': {'num_legs': 2,\n",
|
||||
" 'num_specimen_seen': 10,\n",
|
||||
" 'num_wings': 2}}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Here's an example of a row operation being performed.\n",
|
||||
"df_query = \"Retrieve the first row.\"\n",
|
||||
"\n",
|
||||
"# Set up the prompt.\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"Answer the user query.\\n{format_instructions}\\n{query}\\n\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"chain = prompt | model | parser\n",
|
||||
"parser_output = chain.invoke({\"query\": df_query})\n",
|
||||
"\n",
|
||||
"format_parser_output(parser_output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'mean': 4.0}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Here's an example of a random Pandas DataFrame operation limiting the number of rows\n",
|
||||
"df_query = \"Retrieve the average of the num_legs column from rows 1 to 3.\"\n",
|
||||
"\n",
|
||||
"# Set up the prompt.\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"Answer the user query.\\n{format_instructions}\\n{query}\\n\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"chain = prompt | model | parser\n",
|
||||
"parser_output = chain.invoke({\"query\": df_query})\n",
|
||||
"\n",
|
||||
"print(parser_output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "OutputParserException",
|
||||
"evalue": "Invalid column: num_fingers. Please check the format instructions.",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mOutputParserException\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[23], line 12\u001b[0m\n\u001b[1;32m 5\u001b[0m prompt \u001b[38;5;241m=\u001b[39m PromptTemplate(\n\u001b[1;32m 6\u001b[0m template\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mAnswer the user query.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;132;01m{format_instructions}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;132;01m{query}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 7\u001b[0m input_variables\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mquery\u001b[39m\u001b[38;5;124m\"\u001b[39m],\n\u001b[1;32m 8\u001b[0m partial_variables\u001b[38;5;241m=\u001b[39m{\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mformat_instructions\u001b[39m\u001b[38;5;124m\"\u001b[39m: parser\u001b[38;5;241m.\u001b[39mget_format_instructions()},\n\u001b[1;32m 9\u001b[0m )\n\u001b[1;32m 11\u001b[0m chain \u001b[38;5;241m=\u001b[39m prompt \u001b[38;5;241m|\u001b[39m model \u001b[38;5;241m|\u001b[39m parser\n\u001b[0;32m---> 12\u001b[0m parser_output \u001b[38;5;241m=\u001b[39m \u001b[43mchain\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mquery\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mdf_query\u001b[49m\u001b[43m}\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/workplace/langchain/libs/core/langchain_core/runnables/base.py:1616\u001b[0m, in \u001b[0;36mRunnableSequence.invoke\u001b[0;34m(self, input, config)\u001b[0m\n\u001b[1;32m 1614\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1615\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i, step \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msteps):\n\u001b[0;32m-> 1616\u001b[0m \u001b[38;5;28minput\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[43mstep\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minvoke\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1617\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1618\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# mark each step as a child run\u001b[39;49;00m\n\u001b[1;32m 1619\u001b[0m \u001b[43m \u001b[49m\u001b[43mpatch_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 1620\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallbacks\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mrun_manager\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_child\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43mf\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mseq:step:\u001b[39;49m\u001b[38;5;132;43;01m{\u001b[39;49;00m\u001b[43mi\u001b[49m\u001b[38;5;241;43m+\u001b[39;49m\u001b[38;5;241;43m1\u001b[39;49m\u001b[38;5;132;43;01m}\u001b[39;49;00m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1621\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 1622\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 1623\u001b[0m \u001b[38;5;66;03m# finish the root run\u001b[39;00m\n\u001b[1;32m 1624\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n",
|
||||
"File \u001b[0;32m~/workplace/langchain/libs/core/langchain_core/output_parsers/base.py:170\u001b[0m, in \u001b[0;36mBaseOutputParser.invoke\u001b[0;34m(self, input, config)\u001b[0m\n\u001b[1;32m 166\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[1;32m 167\u001b[0m \u001b[38;5;28mself\u001b[39m, \u001b[38;5;28minput\u001b[39m: Union[\u001b[38;5;28mstr\u001b[39m, BaseMessage], config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 168\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m T:\n\u001b[1;32m 169\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28minput\u001b[39m, BaseMessage):\n\u001b[0;32m--> 170\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_call_with_config\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 171\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mlambda\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43minner_input\u001b[49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse_result\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 172\u001b[0m \u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[43mChatGeneration\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmessage\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minner_input\u001b[49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\n\u001b[1;32m 173\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 174\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 175\u001b[0m \u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 176\u001b[0m \u001b[43m \u001b[49m\u001b[43mrun_type\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mparser\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[1;32m 177\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 178\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 179\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_call_with_config(\n\u001b[1;32m 180\u001b[0m \u001b[38;5;28;01mlambda\u001b[39;00m inner_input: \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparse_result([Generation(text\u001b[38;5;241m=\u001b[39minner_input)]),\n\u001b[1;32m 181\u001b[0m \u001b[38;5;28minput\u001b[39m,\n\u001b[1;32m 182\u001b[0m config,\n\u001b[1;32m 183\u001b[0m run_type\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mparser\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 184\u001b[0m )\n",
|
||||
"File \u001b[0;32m~/workplace/langchain/libs/core/langchain_core/runnables/base.py:906\u001b[0m, in \u001b[0;36mRunnable._call_with_config\u001b[0;34m(self, func, input, config, run_type, **kwargs)\u001b[0m\n\u001b[1;32m 899\u001b[0m run_manager \u001b[38;5;241m=\u001b[39m callback_manager\u001b[38;5;241m.\u001b[39mon_chain_start(\n\u001b[1;32m 900\u001b[0m dumpd(\u001b[38;5;28mself\u001b[39m),\n\u001b[1;32m 901\u001b[0m \u001b[38;5;28minput\u001b[39m,\n\u001b[1;32m 902\u001b[0m run_type\u001b[38;5;241m=\u001b[39mrun_type,\n\u001b[1;32m 903\u001b[0m name\u001b[38;5;241m=\u001b[39mconfig\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_name\u001b[39m\u001b[38;5;124m\"\u001b[39m),\n\u001b[1;32m 904\u001b[0m )\n\u001b[1;32m 905\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 906\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[43mcall_func_with_variable_args\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 907\u001b[0m \u001b[43m \u001b[49m\u001b[43mfunc\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mconfig\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mrun_manager\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\n\u001b[1;32m 908\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 909\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 910\u001b[0m run_manager\u001b[38;5;241m.\u001b[39mon_chain_error(e)\n",
|
||||
"File \u001b[0;32m~/workplace/langchain/libs/core/langchain_core/runnables/config.py:308\u001b[0m, in \u001b[0;36mcall_func_with_variable_args\u001b[0;34m(func, input, config, run_manager, **kwargs)\u001b[0m\n\u001b[1;32m 306\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m run_manager \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;129;01mand\u001b[39;00m accepts_run_manager(func):\n\u001b[1;32m 307\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrun_manager\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m run_manager\n\u001b[0;32m--> 308\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43minput\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/workplace/langchain/libs/core/langchain_core/output_parsers/base.py:171\u001b[0m, in \u001b[0;36mBaseOutputParser.invoke.<locals>.<lambda>\u001b[0;34m(inner_input)\u001b[0m\n\u001b[1;32m 166\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21minvoke\u001b[39m(\n\u001b[1;32m 167\u001b[0m \u001b[38;5;28mself\u001b[39m, \u001b[38;5;28minput\u001b[39m: Union[\u001b[38;5;28mstr\u001b[39m, BaseMessage], config: Optional[RunnableConfig] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m 168\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m T:\n\u001b[1;32m 169\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(\u001b[38;5;28minput\u001b[39m, BaseMessage):\n\u001b[1;32m 170\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_call_with_config(\n\u001b[0;32m--> 171\u001b[0m \u001b[38;5;28;01mlambda\u001b[39;00m inner_input: \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse_result\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 172\u001b[0m \u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[43mChatGeneration\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmessage\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43minner_input\u001b[49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\n\u001b[1;32m 173\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m,\n\u001b[1;32m 174\u001b[0m \u001b[38;5;28minput\u001b[39m,\n\u001b[1;32m 175\u001b[0m config,\n\u001b[1;32m 176\u001b[0m run_type\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mparser\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 177\u001b[0m )\n\u001b[1;32m 178\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 179\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_call_with_config(\n\u001b[1;32m 180\u001b[0m \u001b[38;5;28;01mlambda\u001b[39;00m inner_input: \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mparse_result([Generation(text\u001b[38;5;241m=\u001b[39minner_input)]),\n\u001b[1;32m 181\u001b[0m \u001b[38;5;28minput\u001b[39m,\n\u001b[1;32m 182\u001b[0m config,\n\u001b[1;32m 183\u001b[0m run_type\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mparser\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[1;32m 184\u001b[0m )\n",
|
||||
"File \u001b[0;32m~/workplace/langchain/libs/core/langchain_core/output_parsers/base.py:222\u001b[0m, in \u001b[0;36mBaseOutputParser.parse_result\u001b[0;34m(self, result, partial)\u001b[0m\n\u001b[1;32m 209\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mparse_result\u001b[39m(\u001b[38;5;28mself\u001b[39m, result: List[Generation], \u001b[38;5;241m*\u001b[39m, partial: \u001b[38;5;28mbool\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mFalse\u001b[39;00m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m T:\n\u001b[1;32m 210\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Parse a list of candidate model Generations into a specific format.\u001b[39;00m\n\u001b[1;32m 211\u001b[0m \n\u001b[1;32m 212\u001b[0m \u001b[38;5;124;03m The return value is parsed from only the first Generation in the result, which\u001b[39;00m\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 220\u001b[0m \u001b[38;5;124;03m Structured output.\u001b[39;00m\n\u001b[1;32m 221\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 222\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse\u001b[49m\u001b[43m(\u001b[49m\u001b[43mresult\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;241;43m0\u001b[39;49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mtext\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/workplace/langchain/libs/langchain/langchain/output_parsers/pandas_dataframe.py:90\u001b[0m, in \u001b[0;36mPandasDataFrameOutputParser.parse\u001b[0;34m(self, request)\u001b[0m\n\u001b[1;32m 88\u001b[0m request_type, request_params \u001b[38;5;241m=\u001b[39m splitted_request\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m request_type \u001b[38;5;129;01min\u001b[39;00m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid column\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid operation\u001b[39m\u001b[38;5;124m\"\u001b[39m}:\n\u001b[0;32m---> 90\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m OutputParserException(\n\u001b[1;32m 91\u001b[0m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mrequest\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m. Please check the format instructions.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 92\u001b[0m )\n\u001b[1;32m 93\u001b[0m array_exists \u001b[38;5;241m=\u001b[39m re\u001b[38;5;241m.\u001b[39msearch(\u001b[38;5;124mr\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m(\u001b[39m\u001b[38;5;124m\\\u001b[39m\u001b[38;5;124m[.*?\u001b[39m\u001b[38;5;124m\\\u001b[39m\u001b[38;5;124m])\u001b[39m\u001b[38;5;124m\"\u001b[39m, request_params)\n\u001b[1;32m 94\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m array_exists:\n",
|
||||
"\u001b[0;31mOutputParserException\u001b[0m: Invalid column: num_fingers. Please check the format instructions."
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Here's an example of a poorly formatted query\n",
|
||||
"df_query = \"Retrieve the mean of the num_fingers column.\"\n",
|
||||
"\n",
|
||||
"# Set up the prompt.\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"Answer the user query.\\n{format_instructions}\\n{query}\\n\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"chain = prompt | model | parser\n",
|
||||
"parser_output = chain.invoke({\"query\": df_query})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
"id": "a1ae632a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Pydantic (JSON) parser\n",
|
||||
"This output parser allows users to specify an arbitrary JSON schema and query LLMs for JSON outputs that conform to that schema.\n",
|
||||
"# Pydantic parser\n",
|
||||
"This output parser allows users to specify an arbitrary Pydantic Model and query LLMs for outputs that conform to that schema.\n",
|
||||
"\n",
|
||||
"Keep in mind that large language models are leaky abstractions! You'll have to use an LLM with sufficient capacity to generate well-formed JSON. In the OpenAI family, DaVinci can do reliably but Curie's ability already drops off dramatically. \n",
|
||||
"\n",
|
||||
@@ -15,14 +15,14 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"execution_count": 1,
|
||||
"id": "cba6d8e3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from typing import List\n",
|
||||
"\n",
|
||||
"from langchain.llms import OpenAI\n",
|
||||
"from langchain.chat_models import ChatOpenAI\n",
|
||||
"from langchain.output_parsers import PydanticOutputParser\n",
|
||||
"from langchain.prompts import PromptTemplate\n",
|
||||
"from langchain_core.pydantic_v1 import BaseModel, Field, validator"
|
||||
@@ -30,14 +30,12 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"execution_count": 2,
|
||||
"id": "0a203100",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model_name = \"gpt-3.5-turbo-instruct\"\n",
|
||||
"temperature = 0.0\n",
|
||||
"model = OpenAI(model_name=model_name, temperature=temperature)"
|
||||
"model = ChatOpenAI(temperature=0)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -49,7 +47,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Joke(setup='Why did the chicken cross the road?', punchline='To get to the other side!')"
|
||||
"Joke(setup=\"Why don't scientists trust atoms?\", punchline='Because they make up everything!')"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
@@ -83,26 +81,24 @@
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"_input = prompt.format_prompt(query=joke_query)\n",
|
||||
"chain = prompt | model | parser\n",
|
||||
"\n",
|
||||
"output = model(_input.to_string())\n",
|
||||
"\n",
|
||||
"parser.parse(output)"
|
||||
"chain.invoke({\"query\": joke_query})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"execution_count": 6,
|
||||
"id": "03049f88",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Actor(name='Tom Hanks', film_names=['Forrest Gump', 'Saving Private Ryan', 'The Green Mile', 'Cast Away', 'Toy Story'])"
|
||||
"Actor(name='Tom Hanks', film_names=['Forrest Gump', 'Cast Away', 'Saving Private Ryan', 'Toy Story', 'The Green Mile'])"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -124,12 +120,18 @@
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"_input = prompt.format_prompt(query=actor_query)\n",
|
||||
"chain = prompt | model | parser\n",
|
||||
"\n",
|
||||
"output = model(_input.to_string())\n",
|
||||
"\n",
|
||||
"parser.parse(output)"
|
||||
"chain.invoke({\"query\": actor_query})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2b11e014",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
@@ -148,7 +150,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
@@ -105,14 +105,14 @@
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)",
|
||||
"File \u001b[0;32m~/workplace/langchain/langchain/output_parsers/pydantic.py:24\u001b[0m, in \u001b[0;36mPydanticOutputParser.parse\u001b[0;34m(self, text)\u001b[0m\n\u001b[1;32m 23\u001b[0m json_object \u001b[38;5;241m=\u001b[39m json\u001b[38;5;241m.\u001b[39mloads(json_str)\n\u001b[0;32m---> 24\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpydantic_object\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse_obj\u001b[49m\u001b[43m(\u001b[49m\u001b[43mjson_object\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 26\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m (json\u001b[38;5;241m.\u001b[39mJSONDecodeError, ValidationError) \u001b[38;5;28;01mas\u001b[39;00m e:\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.9.1/envs/langchain/lib/python3.9/site-packages/pydantic/main.py:527\u001b[0m, in \u001b[0;36mpydantic.main.BaseModel.parse_obj\u001b[0;34m()\u001b[0m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.9.1/envs/langchain/lib/python3.9/site-packages/pydantic/main.py:342\u001b[0m, in \u001b[0;36mpydantic.main.BaseModel.__init__\u001b[0;34m()\u001b[0m\n",
|
||||
"File \u001b[0;32m~/workplace/langchain/libs/langchain/langchain/output_parsers/pydantic.py:30\u001b[0m, in \u001b[0;36mPydanticOutputParser.parse\u001b[0;34m(self, text)\u001b[0m\n\u001b[1;32m 29\u001b[0m json_object \u001b[38;5;241m=\u001b[39m json\u001b[38;5;241m.\u001b[39mloads(json_str, strict\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n\u001b[0;32m---> 30\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpydantic_object\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse_obj\u001b[49m\u001b[43m(\u001b[49m\u001b[43mjson_object\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 32\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m (json\u001b[38;5;241m.\u001b[39mJSONDecodeError, ValidationError) \u001b[38;5;28;01mas\u001b[39;00m e:\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.10.1/envs/langchain/lib/python3.10/site-packages/pydantic/main.py:526\u001b[0m, in \u001b[0;36mpydantic.main.BaseModel.parse_obj\u001b[0;34m()\u001b[0m\n",
|
||||
"File \u001b[0;32m~/.pyenv/versions/3.10.1/envs/langchain/lib/python3.10/site-packages/pydantic/main.py:341\u001b[0m, in \u001b[0;36mpydantic.main.BaseModel.__init__\u001b[0;34m()\u001b[0m\n",
|
||||
"\u001b[0;31mValidationError\u001b[0m: 1 validation error for Action\naction_input\n field required (type=value_error.missing)",
|
||||
"\nDuring handling of the above exception, another exception occurred:\n",
|
||||
"\u001b[0;31mOutputParserException\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[6], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mparser\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparse\u001b[49m\u001b[43m(\u001b[49m\u001b[43mbad_response\u001b[49m\u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/workplace/langchain/langchain/output_parsers/pydantic.py:29\u001b[0m, in \u001b[0;36mPydanticOutputParser.parse\u001b[0;34m(self, text)\u001b[0m\n\u001b[1;32m 27\u001b[0m name \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpydantic_object\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__name__\u001b[39m\n\u001b[1;32m 28\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFailed to parse \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m from completion \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m. Got: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00me\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m---> 29\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m OutputParserException(msg)\n",
|
||||
"File \u001b[0;32m~/workplace/langchain/libs/langchain/langchain/output_parsers/pydantic.py:35\u001b[0m, in \u001b[0;36mPydanticOutputParser.parse\u001b[0;34m(self, text)\u001b[0m\n\u001b[1;32m 33\u001b[0m name \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mpydantic_object\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__name__\u001b[39m\n\u001b[1;32m 34\u001b[0m msg \u001b[38;5;241m=\u001b[39m \u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mFailed to parse \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m from completion \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtext\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m. Got: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00me\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m---> 35\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m OutputParserException(msg, llm_output\u001b[38;5;241m=\u001b[39mtext)\n",
|
||||
"\u001b[0;31mOutputParserException\u001b[0m: Failed to parse Action from completion {\"action\": \"search\"}. Got: 1 validation error for Action\naction_input\n field required (type=value_error.missing)"
|
||||
]
|
||||
}
|
||||
@@ -148,7 +148,7 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Action(action='search', action_input='')"
|
||||
"Action(action='search', action_input='input')"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
@@ -180,7 +180,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"execution_count": 10,
|
||||
"id": "5c86e141",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -192,17 +192,17 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"execution_count": 11,
|
||||
"id": "9c04f731",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"Action(action='search', action_input='who is leo di caprios gf?')"
|
||||
"Action(action='search', action_input='leo di caprio girlfriend')"
|
||||
]
|
||||
},
|
||||
"execution_count": 16,
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -210,6 +210,14 @@
|
||||
"source": [
|
||||
"retry_parser.parse_with_prompt(bad_response, prompt_value)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a2f94fd8",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
@@ -228,7 +236,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
148
docs/docs/modules/model_io/output_parsers/types/structured.ipynb
Normal file
148
docs/docs/modules/model_io/output_parsers/types/structured.ipynb
Normal file
@@ -0,0 +1,148 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7460ca08",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Structured output parser\n",
|
||||
"\n",
|
||||
"This output parser can be used when you want to return multiple fields. While the Pydantic/JSON parser is more powerful, this is useful for less powerful models."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "c656b190",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.chat_models import ChatOpenAI\n",
|
||||
"from langchain.output_parsers import ResponseSchema, StructuredOutputParser\n",
|
||||
"from langchain.prompts import PromptTemplate"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "23d9e019",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"response_schemas = [\n",
|
||||
" ResponseSchema(name=\"answer\", description=\"answer to the user's question\"),\n",
|
||||
" ResponseSchema(\n",
|
||||
" name=\"source\",\n",
|
||||
" description=\"source used to answer the user's question, should be a website.\",\n",
|
||||
" ),\n",
|
||||
"]\n",
|
||||
"output_parser = StructuredOutputParser.from_response_schemas(response_schemas)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "98aa73ca",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n",
|
||||
"We now get a string that contains instructions for how the response should be formatted, and we then insert that into our prompt.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "27ced542",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"format_instructions = output_parser.get_format_instructions()\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"answer the users question as best as possible.\\n{format_instructions}\\n{question}\",\n",
|
||||
" input_variables=[\"question\"],\n",
|
||||
" partial_variables={\"format_instructions\": format_instructions},\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "8de8fa78",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model = ChatOpenAI(temperature=0)\n",
|
||||
"chain = prompt | model | output_parser"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "6aae4eaa",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'answer': 'The capital of France is Paris.',\n",
|
||||
" 'source': 'https://en.wikipedia.org/wiki/Paris'}"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"chain.invoke({\"question\": \"what's the capital of france?\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "4ebfef62",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'answer': 'The capital of France is Paris.', 'source': 'https://en.wikipedia.org/wiki/Paris'}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for s in chain.stream({\"question\": \"what's the capital of france?\"}):\n",
|
||||
" print(s)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c18e5dc7",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
218
docs/docs/modules/model_io/output_parsers/types/xml.ipynb
Normal file
218
docs/docs/modules/model_io/output_parsers/types/xml.ipynb
Normal file
@@ -0,0 +1,218 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "181b5b6d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# XML parser\n",
|
||||
"This output parser allows users to obtain results from LLM in the popular XML format. \n",
|
||||
"\n",
|
||||
"Keep in mind that large language models are leaky abstractions! You'll have to use an LLM with sufficient capacity to generate well-formed XML. \n",
|
||||
"\n",
|
||||
"In the following example we use Claude model (https://docs.anthropic.com/claude/docs) which works really well with XML tags."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "3b10fc55",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.output_parsers import XMLOutputParser\n",
|
||||
"from langchain.prompts import PromptTemplate\n",
|
||||
"from langchain_community.chat_models import ChatAnthropic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "909161d1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"model = ChatAnthropic(model=\"claude-2\", max_tokens_to_sample=512, temperature=0.1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "da312f86-0d2a-4aef-a09d-1e72bd0ea9b1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's start with the simple request to the model."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "b03785af-69fc-40a1-a1be-c04ed6fade70",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" Here is the shortened filmography for Tom Hanks, enclosed in XML tags:\n",
|
||||
"\n",
|
||||
"<movie>Splash</movie>\n",
|
||||
"<movie>Big</movie>\n",
|
||||
"<movie>A League of Their Own</movie>\n",
|
||||
"<movie>Sleepless in Seattle</movie>\n",
|
||||
"<movie>Forrest Gump</movie>\n",
|
||||
"<movie>Toy Story</movie>\n",
|
||||
"<movie>Apollo 13</movie>\n",
|
||||
"<movie>Saving Private Ryan</movie>\n",
|
||||
"<movie>Cast Away</movie>\n",
|
||||
"<movie>The Da Vinci Code</movie>\n",
|
||||
"<movie>Captain Phillips</movie>\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"actor_query = \"Generate the shortened filmography for Tom Hanks.\"\n",
|
||||
"output = model.invoke(\n",
|
||||
" f\"\"\"{actor_query}\n",
|
||||
"Please enclose the movies in <movie></movie> tags\"\"\"\n",
|
||||
")\n",
|
||||
"print(output.content)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4db65781-3d54-4ba6-ae26-5b4ead47a4c8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now we will use the XMLOutputParser in order to get the structured output."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "87ba8d11",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'filmography': [{'movie': [{'title': 'Big'}, {'year': '1988'}]}, {'movie': [{'title': 'Forrest Gump'}, {'year': '1994'}]}, {'movie': [{'title': 'Toy Story'}, {'year': '1995'}]}, {'movie': [{'title': 'Saving Private Ryan'}, {'year': '1998'}]}, {'movie': [{'title': 'Cast Away'}, {'year': '2000'}]}]}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"parser = XMLOutputParser()\n",
|
||||
"\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"\"\"{query}\\n{format_instructions}\"\"\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"chain = prompt | model | parser\n",
|
||||
"\n",
|
||||
"output = chain.invoke({\"query\": actor_query})\n",
|
||||
"print(output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "327f5479-77e0-4549-8393-2cd7a286d491",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Finally, let's add some tags to tailor the output to our needs."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "b722a235",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'movies': [{'actor': [{'name': 'Tom Hanks'}, {'film': [{'name': 'Forrest Gump'}, {'genre': 'Drama'}]}, {'film': [{'name': 'Cast Away'}, {'genre': 'Adventure'}]}, {'film': [{'name': 'Saving Private Ryan'}, {'genre': 'War'}]}]}]}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"parser = XMLOutputParser(tags=[\"movies\", \"actor\", \"film\", \"name\", \"genre\"])\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"\"\"{query}\\n{format_instructions}\"\"\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"chain = prompt | model | parser\n",
|
||||
"\n",
|
||||
"output = chain.invoke({\"query\": actor_query})\n",
|
||||
"\n",
|
||||
"print(output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "808a5df5-b11e-42a0-bd7a-6b95ca0c3eba",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "ParseError",
|
||||
"evalue": "syntax error: line 1, column 1 (<string>)",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"Traceback \u001b[0;36m(most recent call last)\u001b[0m:\n",
|
||||
"\u001b[0m File \u001b[1;32m~/.pyenv/versions/3.10.1/envs/langchain/lib/python3.10/site-packages/IPython/core/interactiveshell.py:3508\u001b[0m in \u001b[1;35mrun_code\u001b[0m\n exec(code_obj, self.user_global_ns, self.user_ns)\u001b[0m\n",
|
||||
"\u001b[0m Cell \u001b[1;32mIn[7], line 1\u001b[0m\n for s in chain.stream({\"query\": actor_query}):\u001b[0m\n",
|
||||
"\u001b[0m File \u001b[1;32m~/workplace/langchain/libs/core/langchain_core/runnables/base.py:1984\u001b[0m in \u001b[1;35mstream\u001b[0m\n yield from self.transform(iter([input]), config, **kwargs)\u001b[0m\n",
|
||||
"\u001b[0m File \u001b[1;32m~/workplace/langchain/libs/core/langchain_core/runnables/base.py:1974\u001b[0m in \u001b[1;35mtransform\u001b[0m\n yield from self._transform_stream_with_config(\u001b[0m\n",
|
||||
"\u001b[0m File \u001b[1;32m~/workplace/langchain/libs/core/langchain_core/runnables/base.py:1141\u001b[0m in \u001b[1;35m_transform_stream_with_config\u001b[0m\n for chunk in iterator:\u001b[0m\n",
|
||||
"\u001b[0m File \u001b[1;32m~/workplace/langchain/libs/core/langchain_core/runnables/base.py:1938\u001b[0m in \u001b[1;35m_transform\u001b[0m\n for output in final_pipeline:\u001b[0m\n",
|
||||
"\u001b[0m File \u001b[1;32m~/workplace/langchain/libs/core/langchain_core/output_parsers/transform.py:50\u001b[0m in \u001b[1;35mtransform\u001b[0m\n yield from self._transform_stream_with_config(\u001b[0m\n",
|
||||
"\u001b[0m File \u001b[1;32m~/workplace/langchain/libs/core/langchain_core/runnables/base.py:1141\u001b[0m in \u001b[1;35m_transform_stream_with_config\u001b[0m\n for chunk in iterator:\u001b[0m\n",
|
||||
"\u001b[0m File \u001b[1;32m~/workplace/langchain/libs/core/langchain_core/output_parsers/xml.py:71\u001b[0m in \u001b[1;35m_transform\u001b[0m\n for event, elem in parser.read_events():\u001b[0m\n",
|
||||
"\u001b[0m File \u001b[1;32m~/.pyenv/versions/3.10.1/lib/python3.10/xml/etree/ElementTree.py:1329\u001b[0m in \u001b[1;35mread_events\u001b[0m\n raise event\u001b[0m\n",
|
||||
"\u001b[0;36m File \u001b[0;32m~/.pyenv/versions/3.10.1/lib/python3.10/xml/etree/ElementTree.py:1301\u001b[0;36m in \u001b[0;35mfeed\u001b[0;36m\n\u001b[0;31m self._parser.feed(data)\u001b[0;36m\n",
|
||||
"\u001b[0;36m File \u001b[0;32m<string>\u001b[0;36m\u001b[0m\n\u001b[0;31mParseError\u001b[0m\u001b[0;31m:\u001b[0m syntax error: line 1, column 1\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"for s in chain.stream({\"query\": actor_query}):\n",
|
||||
" print(s)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "efc073c6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "181b5b6d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# XML parser\n",
|
||||
"This output parser allows users to obtain results from LLM in the popular XML format. \n",
|
||||
"\n",
|
||||
"Keep in mind that large language models are leaky abstractions! You'll have to use an LLM with sufficient capacity to generate well-formed XML. \n",
|
||||
"\n",
|
||||
"In the following example we use Claude model (https://docs.anthropic.com/claude/docs) which works really well with XML tags."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "3b10fc55",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.llms import Anthropic\n",
|
||||
"from langchain.output_parsers import XMLOutputParser\n",
|
||||
"from langchain.prompts import PromptTemplate"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "909161d1",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/Users/harrisonchase/workplace/langchain/libs/langchain/langchain/llms/anthropic.py:171: UserWarning: This Anthropic LLM is deprecated. Please use `from langchain.chat_models import ChatAnthropic` instead\n",
|
||||
" warnings.warn(\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"model = Anthropic(model=\"claude-2\", max_tokens_to_sample=512, temperature=0.1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "da312f86-0d2a-4aef-a09d-1e72bd0ea9b1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Let's start with the simple request to the model."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "b03785af-69fc-40a1-a1be-c04ed6fade70",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
" Here is the shortened filmography for Tom Hanks enclosed in <movie> tags:\n",
|
||||
"\n",
|
||||
"<movie>Splash (1984)</movie>\n",
|
||||
"<movie>Big (1988)</movie> \n",
|
||||
"<movie>A League of Their Own (1992)</movie>\n",
|
||||
"<movie>Sleepless in Seattle (1993)</movie> \n",
|
||||
"<movie>Forrest Gump (1994)</movie>\n",
|
||||
"<movie>Apollo 13 (1995)</movie>\n",
|
||||
"<movie>Toy Story (1995)</movie>\n",
|
||||
"<movie>Saving Private Ryan (1998)</movie>\n",
|
||||
"<movie>Cast Away (2000)</movie>\n",
|
||||
"<movie>The Da Vinci Code (2006)</movie>\n",
|
||||
"<movie>Toy Story 3 (2010)</movie>\n",
|
||||
"<movie>Captain Phillips (2013)</movie>\n",
|
||||
"<movie>Bridge of Spies (2015)</movie>\n",
|
||||
"<movie>Toy Story 4 (2019)</movie>\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"actor_query = \"Generate the shortened filmography for Tom Hanks.\"\n",
|
||||
"output = model(\n",
|
||||
" f\"\"\"\n",
|
||||
"\n",
|
||||
"Human:\n",
|
||||
"{actor_query}\n",
|
||||
"Please enclose the movies in <movie></movie> tags\n",
|
||||
"Assistant:\n",
|
||||
"\"\"\"\n",
|
||||
")\n",
|
||||
"print(output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4db65781-3d54-4ba6-ae26-5b4ead47a4c8",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now we will use the XMLOutputParser in order to get the structured output."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "87ba8d11",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'filmography': [{'movie': [{'title': 'Splash'}, {'year': '1984'}]}, {'movie': [{'title': 'Big'}, {'year': '1988'}]}, {'movie': [{'title': 'A League of Their Own'}, {'year': '1992'}]}, {'movie': [{'title': 'Sleepless in Seattle'}, {'year': '1993'}]}, {'movie': [{'title': 'Forrest Gump'}, {'year': '1994'}]}, {'movie': [{'title': 'Toy Story'}, {'year': '1995'}]}, {'movie': [{'title': 'Apollo 13'}, {'year': '1995'}]}, {'movie': [{'title': 'Saving Private Ryan'}, {'year': '1998'}]}, {'movie': [{'title': 'Cast Away'}, {'year': '2000'}]}, {'movie': [{'title': 'Catch Me If You Can'}, {'year': '2002'}]}, {'movie': [{'title': 'The Polar Express'}, {'year': '2004'}]}, {'movie': [{'title': 'Bridge of Spies'}, {'year': '2015'}]}]}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"parser = XMLOutputParser()\n",
|
||||
"\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"\"\"\n",
|
||||
" \n",
|
||||
" Human:\n",
|
||||
" {query}\n",
|
||||
" {format_instructions}\n",
|
||||
" Assistant:\"\"\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"chain = prompt | model | parser\n",
|
||||
"\n",
|
||||
"output = chain.invoke({\"query\": actor_query})\n",
|
||||
"print(output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "327f5479-77e0-4549-8393-2cd7a286d491",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Finally, let's add some tags to tailor the output to our needs."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "b722a235",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{'movies': [{'actor': [{'name': 'Tom Hanks'}, {'film': [{'name': 'Splash'}, {'genre': 'Comedy'}]}, {'film': [{'name': 'Big'}, {'genre': 'Comedy'}]}, {'film': [{'name': 'A League of Their Own'}, {'genre': 'Comedy'}]}, {'film': [{'name': 'Sleepless in Seattle'}, {'genre': 'Romance'}]}, {'film': [{'name': 'Forrest Gump'}, {'genre': 'Drama'}]}, {'film': [{'name': 'Toy Story'}, {'genre': 'Animation'}]}, {'film': [{'name': 'Apollo 13'}, {'genre': 'Drama'}]}, {'film': [{'name': 'Saving Private Ryan'}, {'genre': 'War'}]}, {'film': [{'name': 'Cast Away'}, {'genre': 'Adventure'}]}, {'film': [{'name': 'The Green Mile'}, {'genre': 'Drama'}]}]}]}\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"parser = XMLOutputParser(tags=[\"movies\", \"actor\", \"film\", \"name\", \"genre\"])\n",
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"\"\"\n",
|
||||
" \n",
|
||||
" Human:\n",
|
||||
" {query}\n",
|
||||
" {format_instructions}\n",
|
||||
" Assistant:\"\"\",\n",
|
||||
" input_variables=[\"query\"],\n",
|
||||
" partial_variables={\"format_instructions\": parser.get_format_instructions()},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"chain = prompt | model | parser\n",
|
||||
"\n",
|
||||
"output = chain.invoke({\"query\": actor_query})\n",
|
||||
"\n",
|
||||
"print(output)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "808a5df5-b11e-42a0-bd7a-6b95ca0c3eba",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -5,9 +5,9 @@
|
||||
"id": "4de4e022",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Prompt pipelining\n",
|
||||
"# Composition\n",
|
||||
"\n",
|
||||
"The idea behind prompt pipelining is to provide a user friendly interface for composing different parts of prompts together. You can do this with either string prompts or chat prompts. Constructing prompts this way allows for easy reuse of components."
|
||||
"LangChain provides a user friendly interface for composing different parts of prompts together. You can do this with either string prompts or chat prompts. Constructing prompts this way allows for easy reuse of components."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -15,7 +15,7 @@
|
||||
"id": "c3190650",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## String prompt pipelining\n",
|
||||
"## String prompt composition\n",
|
||||
"\n",
|
||||
"When working with string prompts, each template is joined together. You can work with either prompts directly or strings (the first element in the list needs to be a prompt)."
|
||||
]
|
||||
@@ -151,7 +151,7 @@
|
||||
"id": "4e4f6a8a",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Chat prompt pipelining"
|
||||
"## Chat prompt composition"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -328,7 +328,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.1"
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
@@ -0,0 +1,8 @@
|
||||
# Example Selector Types
|
||||
|
||||
| Name | Description |
|
||||
|------------|---------------------------------------------------------------------------------------------|
|
||||
| Similarity | Uses semantic similarity between inputs and examples to decide which examples to choose. |
|
||||
| MMR | Uses Max Marginal Relevance between inputs and examples to decide which examples to choose. |
|
||||
| Length | Selects examples based on how many can fit within a certain length |
|
||||
| Ngram | Uses ngram overlap between inputs and examples to decide which examples to choose. |
|
||||
@@ -0,0 +1,194 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1036fdb2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Select by length\n",
|
||||
"\n",
|
||||
"This example selector selects which examples to use based on length. This is useful when you are worried about constructing a prompt that will go over the length of the context window. For longer inputs, it will select fewer examples to include, while for shorter inputs it will select more."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "1bd45644",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.prompts import FewShotPromptTemplate, PromptTemplate\n",
|
||||
"from langchain.prompts.example_selector import LengthBasedExampleSelector\n",
|
||||
"\n",
|
||||
"# Examples of a pretend task of creating antonyms.\n",
|
||||
"examples = [\n",
|
||||
" {\"input\": \"happy\", \"output\": \"sad\"},\n",
|
||||
" {\"input\": \"tall\", \"output\": \"short\"},\n",
|
||||
" {\"input\": \"energetic\", \"output\": \"lethargic\"},\n",
|
||||
" {\"input\": \"sunny\", \"output\": \"gloomy\"},\n",
|
||||
" {\"input\": \"windy\", \"output\": \"calm\"},\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"example_prompt = PromptTemplate(\n",
|
||||
" input_variables=[\"input\", \"output\"],\n",
|
||||
" template=\"Input: {input}\\nOutput: {output}\",\n",
|
||||
")\n",
|
||||
"example_selector = LengthBasedExampleSelector(\n",
|
||||
" # The examples it has available to choose from.\n",
|
||||
" examples=examples,\n",
|
||||
" # The PromptTemplate being used to format the examples.\n",
|
||||
" example_prompt=example_prompt,\n",
|
||||
" # The maximum length that the formatted examples should be.\n",
|
||||
" # Length is measured by the get_text_length function below.\n",
|
||||
" max_length=25,\n",
|
||||
" # The function used to get the length of a string, which is used\n",
|
||||
" # to determine which examples to include. It is commented out because\n",
|
||||
" # it is provided as a default value if none is specified.\n",
|
||||
" # get_text_length: Callable[[str], int] = lambda x: len(re.split(\"\\n| \", x))\n",
|
||||
")\n",
|
||||
"dynamic_prompt = FewShotPromptTemplate(\n",
|
||||
" # We provide an ExampleSelector instead of examples.\n",
|
||||
" example_selector=example_selector,\n",
|
||||
" example_prompt=example_prompt,\n",
|
||||
" prefix=\"Give the antonym of every input\",\n",
|
||||
" suffix=\"Input: {adjective}\\nOutput:\",\n",
|
||||
" input_variables=[\"adjective\"],\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "f62c140b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Give the antonym of every input\n",
|
||||
"\n",
|
||||
"Input: happy\n",
|
||||
"Output: sad\n",
|
||||
"\n",
|
||||
"Input: tall\n",
|
||||
"Output: short\n",
|
||||
"\n",
|
||||
"Input: energetic\n",
|
||||
"Output: lethargic\n",
|
||||
"\n",
|
||||
"Input: sunny\n",
|
||||
"Output: gloomy\n",
|
||||
"\n",
|
||||
"Input: windy\n",
|
||||
"Output: calm\n",
|
||||
"\n",
|
||||
"Input: big\n",
|
||||
"Output:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# An example with small input, so it selects all examples.\n",
|
||||
"print(dynamic_prompt.format(adjective=\"big\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "3ca959eb",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Give the antonym of every input\n",
|
||||
"\n",
|
||||
"Input: happy\n",
|
||||
"Output: sad\n",
|
||||
"\n",
|
||||
"Input: big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else\n",
|
||||
"Output:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# An example with long input, so it selects only one example.\n",
|
||||
"long_string = \"big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else\"\n",
|
||||
"print(dynamic_prompt.format(adjective=long_string))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "da43f9a7",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Give the antonym of every input\n",
|
||||
"\n",
|
||||
"Input: happy\n",
|
||||
"Output: sad\n",
|
||||
"\n",
|
||||
"Input: tall\n",
|
||||
"Output: short\n",
|
||||
"\n",
|
||||
"Input: energetic\n",
|
||||
"Output: lethargic\n",
|
||||
"\n",
|
||||
"Input: sunny\n",
|
||||
"Output: gloomy\n",
|
||||
"\n",
|
||||
"Input: windy\n",
|
||||
"Output: calm\n",
|
||||
"\n",
|
||||
"Input: big\n",
|
||||
"Output: small\n",
|
||||
"\n",
|
||||
"Input: enthusiastic\n",
|
||||
"Output:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# You can add an example to an example selector as well.\n",
|
||||
"new_example = {\"input\": \"big\", \"output\": \"small\"}\n",
|
||||
"dynamic_prompt.example_selector.add_example(new_example)\n",
|
||||
"print(dynamic_prompt.format(adjective=\"enthusiastic\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "be3cf8aa",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8c1e7149",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Select by similarity\n",
|
||||
"\n",
|
||||
"This object selects examples based on similarity to the inputs. It does this by finding the examples with the embeddings that have the greatest cosine similarity with the inputs.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "abc30764",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.embeddings import OpenAIEmbeddings\n",
|
||||
"from langchain.prompts import FewShotPromptTemplate, PromptTemplate\n",
|
||||
"from langchain.prompts.example_selector import SemanticSimilarityExampleSelector\n",
|
||||
"from langchain.vectorstores import Chroma\n",
|
||||
"\n",
|
||||
"example_prompt = PromptTemplate(\n",
|
||||
" input_variables=[\"input\", \"output\"],\n",
|
||||
" template=\"Input: {input}\\nOutput: {output}\",\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Examples of a pretend task of creating antonyms.\n",
|
||||
"examples = [\n",
|
||||
" {\"input\": \"happy\", \"output\": \"sad\"},\n",
|
||||
" {\"input\": \"tall\", \"output\": \"short\"},\n",
|
||||
" {\"input\": \"energetic\", \"output\": \"lethargic\"},\n",
|
||||
" {\"input\": \"sunny\", \"output\": \"gloomy\"},\n",
|
||||
" {\"input\": \"windy\", \"output\": \"calm\"},\n",
|
||||
"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "8a37fc84",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"example_selector = SemanticSimilarityExampleSelector.from_examples(\n",
|
||||
" # The list of examples available to select from.\n",
|
||||
" examples,\n",
|
||||
" # The embedding class used to produce embeddings which are used to measure semantic similarity.\n",
|
||||
" OpenAIEmbeddings(),\n",
|
||||
" # The VectorStore class that is used to store the embeddings and do a similarity search over.\n",
|
||||
" Chroma,\n",
|
||||
" # The number of examples to produce.\n",
|
||||
" k=1,\n",
|
||||
")\n",
|
||||
"similar_prompt = FewShotPromptTemplate(\n",
|
||||
" # We provide an ExampleSelector instead of examples.\n",
|
||||
" example_selector=example_selector,\n",
|
||||
" example_prompt=example_prompt,\n",
|
||||
" prefix=\"Give the antonym of every input\",\n",
|
||||
" suffix=\"Input: {adjective}\\nOutput:\",\n",
|
||||
" input_variables=[\"adjective\"],\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "eabd2020",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Give the antonym of every input\n",
|
||||
"\n",
|
||||
"Input: happy\n",
|
||||
"Output: sad\n",
|
||||
"\n",
|
||||
"Input: worried\n",
|
||||
"Output:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Input is a feeling, so should select the happy/sad example\n",
|
||||
"print(similar_prompt.format(adjective=\"worried\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "c02225a8",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Give the antonym of every input\n",
|
||||
"\n",
|
||||
"Input: tall\n",
|
||||
"Output: short\n",
|
||||
"\n",
|
||||
"Input: large\n",
|
||||
"Output:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Input is a measurement, so should select the tall/short example\n",
|
||||
"print(similar_prompt.format(adjective=\"large\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "09836c64",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Give the antonym of every input\n",
|
||||
"\n",
|
||||
"Input: enthusiastic\n",
|
||||
"Output: apathetic\n",
|
||||
"\n",
|
||||
"Input: passionate\n",
|
||||
"Output:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# You can add new examples to the SemanticSimilarityExampleSelector as well\n",
|
||||
"similar_prompt.example_selector.add_example(\n",
|
||||
" {\"input\": \"enthusiastic\", \"output\": \"apathetic\"}\n",
|
||||
")\n",
|
||||
"print(similar_prompt.format(adjective=\"passionate\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "92e2c85f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
252
docs/docs/modules/model_io/prompts/example_selectors.ipynb
Normal file
252
docs/docs/modules/model_io/prompts/example_selectors.ipynb
Normal file
@@ -0,0 +1,252 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1a65e4c9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Example selectors\n",
|
||||
"\n",
|
||||
"If you have a large number of examples, you may need to select which ones to include in the prompt. The Example Selector is the class responsible for doing so.\n",
|
||||
"\n",
|
||||
"The base interface is defined as below:\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"class BaseExampleSelector(ABC):\n",
|
||||
" \"\"\"Interface for selecting examples to include in prompts.\"\"\"\n",
|
||||
"\n",
|
||||
" @abstractmethod\n",
|
||||
" def select_examples(self, input_variables: Dict[str, str]) -> List[dict]:\n",
|
||||
" \"\"\"Select which examples to use based on the inputs.\"\"\"\n",
|
||||
" \n",
|
||||
" @abstractmethod\n",
|
||||
" def add_example(self, example: Dict[str, str]) -> Any:\n",
|
||||
" \"\"\"Add new example to store.\"\"\"\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"The only method it needs to define is a ``select_examples`` method. This takes in the input variables and then returns a list of examples. It is up to each specific implementation as to how those examples are selected.\n",
|
||||
"\n",
|
||||
"LangChain has a few different types of example selectors. For an overview of all these types, see [this documentation](./example_selector_types).\n",
|
||||
"\n",
|
||||
"In this guide, we will walk through creating a custom example selector."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "638e9039",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Examples\n",
|
||||
"\n",
|
||||
"In order to use an example selector, we need to create a list of examples. These should generally be example inputs and outputs. For this demo purpose, let's imagine we are selecting examples of how to translate English to Italian."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 36,
|
||||
"id": "48658d53",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"examples = [\n",
|
||||
" {\"input\": \"hi\", \"output\": \"ciao\"},\n",
|
||||
" {\"input\": \"bye\", \"output\": \"arrivaderci\"},\n",
|
||||
" {\"input\": \"soccer\", \"output\": \"calcio\"},\n",
|
||||
"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c2830b49",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Custom Example Selector\n",
|
||||
"\n",
|
||||
"Let's write an example selector that chooses what example to pick based on the length of the word."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 37,
|
||||
"id": "56b740a1",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain_core.example_selectors.base import BaseExampleSelector\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class CustomExampleSelector(BaseExampleSelector):\n",
|
||||
" def __init__(self, examples):\n",
|
||||
" self.examples = examples\n",
|
||||
"\n",
|
||||
" def add_example(self, example):\n",
|
||||
" self.examples.append(example)\n",
|
||||
"\n",
|
||||
" def select_examples(self, input_variables):\n",
|
||||
" # This assumes knowledge that part of the input will be a 'text' key\n",
|
||||
" new_word = input_variables[\"input\"]\n",
|
||||
" new_word_length = len(new_word)\n",
|
||||
"\n",
|
||||
" # Initialize variables to store the best match and its length difference\n",
|
||||
" best_match = None\n",
|
||||
" smallest_diff = float(\"inf\")\n",
|
||||
"\n",
|
||||
" # Iterate through each example\n",
|
||||
" for example in self.examples:\n",
|
||||
" # Calculate the length difference with the first word of the example\n",
|
||||
" current_diff = abs(len(example[\"input\"]) - new_word_length)\n",
|
||||
"\n",
|
||||
" # Update the best match if the current one is closer in length\n",
|
||||
" if current_diff < smallest_diff:\n",
|
||||
" smallest_diff = current_diff\n",
|
||||
" best_match = example\n",
|
||||
"\n",
|
||||
" return [best_match]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 38,
|
||||
"id": "ce928187",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"example_selector = CustomExampleSelector(examples)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 39,
|
||||
"id": "37ef3149",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[{'input': 'bye', 'output': 'arrivaderci'}]"
|
||||
]
|
||||
},
|
||||
"execution_count": 39,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"example_selector.select_examples({\"input\": \"okay\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 40,
|
||||
"id": "c5ad9f35",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"example_selector.add_example({\"input\": \"hand\", \"output\": \"mano\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 41,
|
||||
"id": "e4127fe0",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[{'input': 'hand', 'output': 'mano'}]"
|
||||
]
|
||||
},
|
||||
"execution_count": 41,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"example_selector.select_examples({\"input\": \"okay\"})"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "786c920c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Use in a Prompt\n",
|
||||
"\n",
|
||||
"We can now use this example selector in a prompt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 42,
|
||||
"id": "619090e2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain_core.prompts.few_shot import FewShotPromptTemplate\n",
|
||||
"from langchain_core.prompts.prompt import PromptTemplate\n",
|
||||
"\n",
|
||||
"example_prompt = PromptTemplate.from_template(\"Input: {input} -> Output: {output}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 43,
|
||||
"id": "5934c415",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Translate the following words from English to Italain:\n",
|
||||
"\n",
|
||||
"Input: hand -> Output: mano\n",
|
||||
"\n",
|
||||
"Input: word -> Output:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt = FewShotPromptTemplate(\n",
|
||||
" example_selector=example_selector,\n",
|
||||
" example_prompt=example_prompt,\n",
|
||||
" suffix=\"Input: {input} -> Output:\",\n",
|
||||
" prefix=\"Translate the following words from English to Italain:\",\n",
|
||||
" input_variables=[\"input\"],\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(prompt.format(input=\"word\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "8a6e0abe",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
# Custom example selector
|
||||
|
||||
In this tutorial, we'll create a custom example selector that selects examples randomly from a given list of examples.
|
||||
|
||||
An `ExampleSelector` must implement two methods:
|
||||
|
||||
1. An `add_example` method which takes in an example and adds it into the ExampleSelector
|
||||
2. A `select_examples` method which takes in input variables (which are meant to be user input) and returns a list of examples to use in the few-shot prompt.
|
||||
|
||||
Let's implement a custom `ExampleSelector` that just selects two examples at random.
|
||||
|
||||
**Note:**
|
||||
Take a look at the current set of example selector implementations supported in LangChain [here](/docs/modules/model_io/prompts/example_selectors/).
|
||||
|
||||
<!-- TODO(shreya): Add the correct link. -->
|
||||
|
||||
## Implement custom example selector
|
||||
|
||||
```python
|
||||
from langchain.prompts.example_selector.base import BaseExampleSelector
|
||||
from typing import Dict, List
|
||||
import numpy as np
|
||||
|
||||
|
||||
class CustomExampleSelector(BaseExampleSelector):
|
||||
|
||||
def __init__(self, examples: List[Dict[str, str]]):
|
||||
self.examples = examples
|
||||
|
||||
def add_example(self, example: Dict[str, str]) -> None:
|
||||
"""Add new example to store for a key."""
|
||||
self.examples.append(example)
|
||||
|
||||
def select_examples(self, input_variables: Dict[str, str]) -> List[dict]:
|
||||
"""Select which examples to use based on the inputs."""
|
||||
return np.random.choice(self.examples, size=2, replace=False)
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Use custom example selector
|
||||
|
||||
```python
|
||||
|
||||
examples = [
|
||||
{"foo": "1"},
|
||||
{"foo": "2"},
|
||||
{"foo": "3"}
|
||||
]
|
||||
|
||||
# Initialize example selector.
|
||||
example_selector = CustomExampleSelector(examples)
|
||||
|
||||
# Select examples
|
||||
example_selector.select_examples({"foo": "foo"})
|
||||
# -> array([{'foo': '2'}, {'foo': '3'}], dtype=object)
|
||||
|
||||
# Add new example to the set of examples
|
||||
example_selector.add_example({"foo": "4"})
|
||||
example_selector.examples
|
||||
# -> [{'foo': '1'}, {'foo': '2'}, {'foo': '3'}, {'foo': '4'}]
|
||||
|
||||
# Select examples
|
||||
example_selector.select_examples({"foo": "foo"})
|
||||
# -> array([{'foo': '1'}, {'foo': '4'}], dtype=object)
|
||||
```
|
||||
@@ -1,16 +0,0 @@
|
||||
# Example selectors
|
||||
|
||||
If you have a large number of examples, you may need to select which ones to include in the prompt. The Example Selector is the class responsible for doing so.
|
||||
|
||||
The base interface is defined as below:
|
||||
|
||||
```python
|
||||
class BaseExampleSelector(ABC):
|
||||
"""Interface for selecting examples to include in prompts."""
|
||||
|
||||
@abstractmethod
|
||||
def select_examples(self, input_variables: Dict[str, str]) -> List[dict]:
|
||||
"""Select which examples to use based on the inputs."""
|
||||
```
|
||||
|
||||
The only method it needs to define is a ``select_examples`` method. This takes in the input variables and then returns a list of examples. It is up to each specific implementation as to how those examples are selected.
|
||||
@@ -1,135 +0,0 @@
|
||||
# Select by length
|
||||
|
||||
This example selector selects which examples to use based on length. This is useful when you are worried about constructing a prompt that will go over the length of the context window. For longer inputs, it will select fewer examples to include, while for shorter inputs it will select more.
|
||||
|
||||
```python
|
||||
from langchain.prompts import PromptTemplate
|
||||
from langchain.prompts import FewShotPromptTemplate
|
||||
from langchain.prompts.example_selector import LengthBasedExampleSelector
|
||||
|
||||
|
||||
# Examples of a pretend task of creating antonyms.
|
||||
examples = [
|
||||
{"input": "happy", "output": "sad"},
|
||||
{"input": "tall", "output": "short"},
|
||||
{"input": "energetic", "output": "lethargic"},
|
||||
{"input": "sunny", "output": "gloomy"},
|
||||
{"input": "windy", "output": "calm"},
|
||||
]
|
||||
|
||||
example_prompt = PromptTemplate(
|
||||
input_variables=["input", "output"],
|
||||
template="Input: {input}\nOutput: {output}",
|
||||
)
|
||||
example_selector = LengthBasedExampleSelector(
|
||||
# The examples it has available to choose from.
|
||||
examples=examples,
|
||||
# The PromptTemplate being used to format the examples.
|
||||
example_prompt=example_prompt,
|
||||
# The maximum length that the formatted examples should be.
|
||||
# Length is measured by the get_text_length function below.
|
||||
max_length=25,
|
||||
# The function used to get the length of a string, which is used
|
||||
# to determine which examples to include. It is commented out because
|
||||
# it is provided as a default value if none is specified.
|
||||
# get_text_length: Callable[[str], int] = lambda x: len(re.split("\n| ", x))
|
||||
)
|
||||
dynamic_prompt = FewShotPromptTemplate(
|
||||
# We provide an ExampleSelector instead of examples.
|
||||
example_selector=example_selector,
|
||||
example_prompt=example_prompt,
|
||||
prefix="Give the antonym of every input",
|
||||
suffix="Input: {adjective}\nOutput:",
|
||||
input_variables=["adjective"],
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
# An example with small input, so it selects all examples.
|
||||
print(dynamic_prompt.format(adjective="big"))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Give the antonym of every input
|
||||
|
||||
Input: happy
|
||||
Output: sad
|
||||
|
||||
Input: tall
|
||||
Output: short
|
||||
|
||||
Input: energetic
|
||||
Output: lethargic
|
||||
|
||||
Input: sunny
|
||||
Output: gloomy
|
||||
|
||||
Input: windy
|
||||
Output: calm
|
||||
|
||||
Input: big
|
||||
Output:
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
|
||||
```python
|
||||
# An example with long input, so it selects only one example.
|
||||
long_string = "big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else"
|
||||
print(dynamic_prompt.format(adjective=long_string))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Give the antonym of every input
|
||||
|
||||
Input: happy
|
||||
Output: sad
|
||||
|
||||
Input: big and huge and massive and large and gigantic and tall and much much much much much bigger than everything else
|
||||
Output:
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
|
||||
```python
|
||||
# You can add an example to an example selector as well.
|
||||
new_example = {"input": "big", "output": "small"}
|
||||
dynamic_prompt.example_selector.add_example(new_example)
|
||||
print(dynamic_prompt.format(adjective="enthusiastic"))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Give the antonym of every input
|
||||
|
||||
Input: happy
|
||||
Output: sad
|
||||
|
||||
Input: tall
|
||||
Output: short
|
||||
|
||||
Input: energetic
|
||||
Output: lethargic
|
||||
|
||||
Input: sunny
|
||||
Output: gloomy
|
||||
|
||||
Input: windy
|
||||
Output: calm
|
||||
|
||||
Input: big
|
||||
Output: small
|
||||
|
||||
Input: enthusiastic
|
||||
Output:
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
@@ -1,116 +0,0 @@
|
||||
# Select by similarity
|
||||
|
||||
This object selects examples based on similarity to the inputs. It does this by finding the examples with the embeddings that have the greatest cosine similarity with the inputs.
|
||||
|
||||
```python
|
||||
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
|
||||
from langchain.vectorstores import Chroma
|
||||
from langchain.embeddings import OpenAIEmbeddings
|
||||
from langchain.prompts import FewShotPromptTemplate, PromptTemplate
|
||||
|
||||
example_prompt = PromptTemplate(
|
||||
input_variables=["input", "output"],
|
||||
template="Input: {input}\nOutput: {output}",
|
||||
)
|
||||
|
||||
# Examples of a pretend task of creating antonyms.
|
||||
examples = [
|
||||
{"input": "happy", "output": "sad"},
|
||||
{"input": "tall", "output": "short"},
|
||||
{"input": "energetic", "output": "lethargic"},
|
||||
{"input": "sunny", "output": "gloomy"},
|
||||
{"input": "windy", "output": "calm"},
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
example_selector = SemanticSimilarityExampleSelector.from_examples(
|
||||
# The list of examples available to select from.
|
||||
examples,
|
||||
# The embedding class used to produce embeddings which are used to measure semantic similarity.
|
||||
OpenAIEmbeddings(),
|
||||
# The VectorStore class that is used to store the embeddings and do a similarity search over.
|
||||
Chroma,
|
||||
# The number of examples to produce.
|
||||
k=1
|
||||
)
|
||||
similar_prompt = FewShotPromptTemplate(
|
||||
# We provide an ExampleSelector instead of examples.
|
||||
example_selector=example_selector,
|
||||
example_prompt=example_prompt,
|
||||
prefix="Give the antonym of every input",
|
||||
suffix="Input: {adjective}\nOutput:",
|
||||
input_variables=["adjective"],
|
||||
)
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Running Chroma using direct local API.
|
||||
Using DuckDB in-memory for database. Data will be transient.
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
|
||||
```python
|
||||
# Input is a feeling, so should select the happy/sad example
|
||||
print(similar_prompt.format(adjective="worried"))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Give the antonym of every input
|
||||
|
||||
Input: happy
|
||||
Output: sad
|
||||
|
||||
Input: worried
|
||||
Output:
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
|
||||
```python
|
||||
# Input is a measurement, so should select the tall/short example
|
||||
print(similar_prompt.format(adjective="large"))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Give the antonym of every input
|
||||
|
||||
Input: tall
|
||||
Output: short
|
||||
|
||||
Input: large
|
||||
Output:
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
|
||||
```python
|
||||
# You can add new examples to the SemanticSimilarityExampleSelector as well
|
||||
similar_prompt.example_selector.add_example({"input": "enthusiastic", "output": "apathetic"})
|
||||
print(similar_prompt.format(adjective="passionate"))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Give the antonym of every input
|
||||
|
||||
Input: enthusiastic
|
||||
Output: apathetic
|
||||
|
||||
Input: passionate
|
||||
Output:
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
346
docs/docs/modules/model_io/prompts/few_shot_examples.ipynb
Normal file
346
docs/docs/modules/model_io/prompts/few_shot_examples.ipynb
Normal file
@@ -0,0 +1,346 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b91e03f1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Few-shot prompt templates\n",
|
||||
"\n",
|
||||
"In this tutorial, we'll learn how to create a prompt template that uses few-shot examples. A few-shot prompt template can be constructed from either a set of examples, or from an Example Selector object.\n",
|
||||
"\n",
|
||||
"### Use Case\n",
|
||||
"\n",
|
||||
"In this tutorial, we'll configure few-shot examples for self-ask with search.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## Using an example set\n",
|
||||
"\n",
|
||||
"### Create the example set\n",
|
||||
"\n",
|
||||
"To get started, create a list of few-shot examples. Each example should be a dictionary with the keys being the input variables and the values being the values for those input variables."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "a44be840",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.prompts.few_shot import FewShotPromptTemplate\n",
|
||||
"from langchain.prompts.prompt import PromptTemplate\n",
|
||||
"\n",
|
||||
"examples = [\n",
|
||||
" {\n",
|
||||
" \"question\": \"Who lived longer, Muhammad Ali or Alan Turing?\",\n",
|
||||
" \"answer\": \"\"\"\n",
|
||||
"Are follow up questions needed here: Yes.\n",
|
||||
"Follow up: How old was Muhammad Ali when he died?\n",
|
||||
"Intermediate answer: Muhammad Ali was 74 years old when he died.\n",
|
||||
"Follow up: How old was Alan Turing when he died?\n",
|
||||
"Intermediate answer: Alan Turing was 41 years old when he died.\n",
|
||||
"So the final answer is: Muhammad Ali\n",
|
||||
"\"\"\",\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"question\": \"When was the founder of craigslist born?\",\n",
|
||||
" \"answer\": \"\"\"\n",
|
||||
"Are follow up questions needed here: Yes.\n",
|
||||
"Follow up: Who was the founder of craigslist?\n",
|
||||
"Intermediate answer: Craigslist was founded by Craig Newmark.\n",
|
||||
"Follow up: When was Craig Newmark born?\n",
|
||||
"Intermediate answer: Craig Newmark was born on December 6, 1952.\n",
|
||||
"So the final answer is: December 6, 1952\n",
|
||||
"\"\"\",\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"question\": \"Who was the maternal grandfather of George Washington?\",\n",
|
||||
" \"answer\": \"\"\"\n",
|
||||
"Are follow up questions needed here: Yes.\n",
|
||||
"Follow up: Who was the mother of George Washington?\n",
|
||||
"Intermediate answer: The mother of George Washington was Mary Ball Washington.\n",
|
||||
"Follow up: Who was the father of Mary Ball Washington?\n",
|
||||
"Intermediate answer: The father of Mary Ball Washington was Joseph Ball.\n",
|
||||
"So the final answer is: Joseph Ball\n",
|
||||
"\"\"\",\n",
|
||||
" },\n",
|
||||
" {\n",
|
||||
" \"question\": \"Are both the directors of Jaws and Casino Royale from the same country?\",\n",
|
||||
" \"answer\": \"\"\"\n",
|
||||
"Are follow up questions needed here: Yes.\n",
|
||||
"Follow up: Who is the director of Jaws?\n",
|
||||
"Intermediate Answer: The director of Jaws is Steven Spielberg.\n",
|
||||
"Follow up: Where is Steven Spielberg from?\n",
|
||||
"Intermediate Answer: The United States.\n",
|
||||
"Follow up: Who is the director of Casino Royale?\n",
|
||||
"Intermediate Answer: The director of Casino Royale is Martin Campbell.\n",
|
||||
"Follow up: Where is Martin Campbell from?\n",
|
||||
"Intermediate Answer: New Zealand.\n",
|
||||
"So the final answer is: No\n",
|
||||
"\"\"\",\n",
|
||||
" },\n",
|
||||
"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "55ff3100",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Create a formatter for the few-shot examples\n",
|
||||
"\n",
|
||||
"Configure a formatter that will format the few-shot examples into a string. This formatter should be a `PromptTemplate` object.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "8c6e48ad",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Question: Who lived longer, Muhammad Ali or Alan Turing?\n",
|
||||
"\n",
|
||||
"Are follow up questions needed here: Yes.\n",
|
||||
"Follow up: How old was Muhammad Ali when he died?\n",
|
||||
"Intermediate answer: Muhammad Ali was 74 years old when he died.\n",
|
||||
"Follow up: How old was Alan Turing when he died?\n",
|
||||
"Intermediate answer: Alan Turing was 41 years old when he died.\n",
|
||||
"So the final answer is: Muhammad Ali\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"example_prompt = PromptTemplate(\n",
|
||||
" input_variables=[\"question\", \"answer\"], template=\"Question: {question}\\n{answer}\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(example_prompt.format(**examples[0]))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "dad66af1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Feed examples and formatter to `FewShotPromptTemplate`\n",
|
||||
"\n",
|
||||
"Finally, create a `FewShotPromptTemplate` object. This object takes in the few-shot examples and the formatter for the few-shot examples.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "e76fa1ba",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Question: Who lived longer, Muhammad Ali or Alan Turing?\n",
|
||||
"\n",
|
||||
"Are follow up questions needed here: Yes.\n",
|
||||
"Follow up: How old was Muhammad Ali when he died?\n",
|
||||
"Intermediate answer: Muhammad Ali was 74 years old when he died.\n",
|
||||
"Follow up: How old was Alan Turing when he died?\n",
|
||||
"Intermediate answer: Alan Turing was 41 years old when he died.\n",
|
||||
"So the final answer is: Muhammad Ali\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Question: When was the founder of craigslist born?\n",
|
||||
"\n",
|
||||
"Are follow up questions needed here: Yes.\n",
|
||||
"Follow up: Who was the founder of craigslist?\n",
|
||||
"Intermediate answer: Craigslist was founded by Craig Newmark.\n",
|
||||
"Follow up: When was Craig Newmark born?\n",
|
||||
"Intermediate answer: Craig Newmark was born on December 6, 1952.\n",
|
||||
"So the final answer is: December 6, 1952\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Question: Who was the maternal grandfather of George Washington?\n",
|
||||
"\n",
|
||||
"Are follow up questions needed here: Yes.\n",
|
||||
"Follow up: Who was the mother of George Washington?\n",
|
||||
"Intermediate answer: The mother of George Washington was Mary Ball Washington.\n",
|
||||
"Follow up: Who was the father of Mary Ball Washington?\n",
|
||||
"Intermediate answer: The father of Mary Ball Washington was Joseph Ball.\n",
|
||||
"So the final answer is: Joseph Ball\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Question: Are both the directors of Jaws and Casino Royale from the same country?\n",
|
||||
"\n",
|
||||
"Are follow up questions needed here: Yes.\n",
|
||||
"Follow up: Who is the director of Jaws?\n",
|
||||
"Intermediate Answer: The director of Jaws is Steven Spielberg.\n",
|
||||
"Follow up: Where is Steven Spielberg from?\n",
|
||||
"Intermediate Answer: The United States.\n",
|
||||
"Follow up: Who is the director of Casino Royale?\n",
|
||||
"Intermediate Answer: The director of Casino Royale is Martin Campbell.\n",
|
||||
"Follow up: Where is Martin Campbell from?\n",
|
||||
"Intermediate Answer: New Zealand.\n",
|
||||
"So the final answer is: No\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Question: Who was the father of Mary Ball Washington?\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt = FewShotPromptTemplate(\n",
|
||||
" examples=examples,\n",
|
||||
" example_prompt=example_prompt,\n",
|
||||
" suffix=\"Question: {input}\",\n",
|
||||
" input_variables=[\"input\"],\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(prompt.format(input=\"Who was the father of Mary Ball Washington?\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "bbe1f843",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Using an example selector\n",
|
||||
"\n",
|
||||
"### Feed examples into `ExampleSelector`\n",
|
||||
"\n",
|
||||
"We will reuse the example set and the formatter from the previous section. However, instead of feeding the examples directly into the `FewShotPromptTemplate` object, we will feed them into an `ExampleSelector` object.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"In this tutorial, we will use the `SemanticSimilarityExampleSelector` class. This class selects few-shot examples based on their similarity to the input. It uses an embedding model to compute the similarity between the input and the few-shot examples, as well as a vector store to perform the nearest neighbor search.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "80c5ac5c",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Examples most similar to the input: Who was the father of Mary Ball Washington?\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"answer: \n",
|
||||
"Are follow up questions needed here: Yes.\n",
|
||||
"Follow up: Who was the mother of George Washington?\n",
|
||||
"Intermediate answer: The mother of George Washington was Mary Ball Washington.\n",
|
||||
"Follow up: Who was the father of Mary Ball Washington?\n",
|
||||
"Intermediate answer: The father of Mary Ball Washington was Joseph Ball.\n",
|
||||
"So the final answer is: Joseph Ball\n",
|
||||
"\n",
|
||||
"question: Who was the maternal grandfather of George Washington?\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain.embeddings import OpenAIEmbeddings\n",
|
||||
"from langchain.prompts.example_selector import SemanticSimilarityExampleSelector\n",
|
||||
"from langchain.vectorstores import Chroma\n",
|
||||
"\n",
|
||||
"example_selector = SemanticSimilarityExampleSelector.from_examples(\n",
|
||||
" # This is the list of examples available to select from.\n",
|
||||
" examples,\n",
|
||||
" # This is the embedding class used to produce embeddings which are used to measure semantic similarity.\n",
|
||||
" OpenAIEmbeddings(),\n",
|
||||
" # This is the VectorStore class that is used to store the embeddings and do a similarity search over.\n",
|
||||
" Chroma,\n",
|
||||
" # This is the number of examples to produce.\n",
|
||||
" k=1,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Select the most similar example to the input.\n",
|
||||
"question = \"Who was the father of Mary Ball Washington?\"\n",
|
||||
"selected_examples = example_selector.select_examples({\"question\": question})\n",
|
||||
"print(f\"Examples most similar to the input: {question}\")\n",
|
||||
"for example in selected_examples:\n",
|
||||
" print(\"\\n\")\n",
|
||||
" for k, v in example.items():\n",
|
||||
" print(f\"{k}: {v}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "89ac47fe",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Feed example selector into `FewShotPromptTemplate`\n",
|
||||
"\n",
|
||||
"Finally, create a `FewShotPromptTemplate` object. This object takes in the example selector and the formatter for the few-shot examples.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "de69a214",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Question: Who was the maternal grandfather of George Washington?\n",
|
||||
"\n",
|
||||
"Are follow up questions needed here: Yes.\n",
|
||||
"Follow up: Who was the mother of George Washington?\n",
|
||||
"Intermediate answer: The mother of George Washington was Mary Ball Washington.\n",
|
||||
"Follow up: Who was the father of Mary Ball Washington?\n",
|
||||
"Intermediate answer: The father of Mary Ball Washington was Joseph Ball.\n",
|
||||
"So the final answer is: Joseph Ball\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Question: Who was the father of Mary Ball Washington?\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt = FewShotPromptTemplate(\n",
|
||||
" example_selector=example_selector,\n",
|
||||
" example_prompt=example_prompt,\n",
|
||||
" suffix=\"Question: {input}\",\n",
|
||||
" input_variables=[\"input\"],\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"print(prompt.format(input=\"Who was the father of Mary Ball Washington?\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bf06d2a6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -441,7 +441,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.2"
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
@@ -8,7 +8,22 @@ guide the model's response, helping it understand the context and generate relev
|
||||
and coherent language-based output, such as answering questions, completing sentences,
|
||||
or engaging in a conversation.
|
||||
|
||||
LangChain provides several classes and functions to help construct and work with prompts.
|
||||
## [Quick Start](./quick_start)
|
||||
|
||||
- [Prompt templates](/docs/modules/model_io/prompts/prompt_templates/): Parametrized model inputs
|
||||
- [Example selectors](/docs/modules/model_io/prompts/example_selectors/): Dynamically select examples to include in prompts
|
||||
This [quick start](./quick_start) provides a basic overview of how to work with prompts.
|
||||
|
||||
## How-To Guides
|
||||
|
||||
We have many how-to guides for working with prompts. These include:
|
||||
|
||||
- [How to use few-shot examples with LLMs](./few_shot_examples)
|
||||
- [How to use few-shot examples with chat models](./few_shot_examples_chat)
|
||||
- [How to use example selectors](./example_selectors)
|
||||
- [How to partial prompts](./partial)
|
||||
- [How to work with message prompts](./message_prompts)
|
||||
- [How to compose prompts together](./composition)
|
||||
- [How to create a pipeline prompt](./pipeline)
|
||||
|
||||
## [Example Selector Types](./example_selector_types)
|
||||
|
||||
LangChain has a few different types of example selectors you can use off the shelf. You can explore those types [here](./example_selector_types)
|
||||
|
||||
140
docs/docs/modules/model_io/prompts/message_prompts.ipynb
Normal file
140
docs/docs/modules/model_io/prompts/message_prompts.ipynb
Normal file
@@ -0,0 +1,140 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "592be667",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Types of `MessagePromptTemplate`\n",
|
||||
"\n",
|
||||
"LangChain provides different types of `MessagePromptTemplate`. The most commonly used are `AIMessagePromptTemplate`, `SystemMessagePromptTemplate` and `HumanMessagePromptTemplate`, which create an AI message, system message and human message respectively.\n",
|
||||
"\n",
|
||||
"However, in cases where the chat model supports taking chat message with arbitrary role, you can use `ChatMessagePromptTemplate`, which allows user to specify the role name."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "3993c10e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"ChatMessage(content='May the force be with you', role='Jedi')"
|
||||
]
|
||||
},
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain.prompts import ChatMessagePromptTemplate\n",
|
||||
"\n",
|
||||
"prompt = \"May the {subject} be with you\"\n",
|
||||
"\n",
|
||||
"chat_message_prompt = ChatMessagePromptTemplate.from_template(\n",
|
||||
" role=\"Jedi\", template=prompt\n",
|
||||
")\n",
|
||||
"chat_message_prompt.format(subject=\"force\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4fc61017",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"LangChain also provides `MessagesPlaceholder`, which gives you full control of what messages to be rendered during formatting. This can be useful when you are uncertain of what role you should be using for your message prompt templates or when you wish to insert a list of messages during formatting.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "0469ee30",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.prompts import (\n",
|
||||
" ChatPromptTemplate,\n",
|
||||
" HumanMessagePromptTemplate,\n",
|
||||
" MessagesPlaceholder,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"human_prompt = \"Summarize our conversation so far in {word_count} words.\"\n",
|
||||
"human_message_template = HumanMessagePromptTemplate.from_template(human_prompt)\n",
|
||||
"\n",
|
||||
"chat_prompt = ChatPromptTemplate.from_messages(\n",
|
||||
" [MessagesPlaceholder(variable_name=\"conversation\"), human_message_template]\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "b57a5e29",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[HumanMessage(content='What is the best way to learn programming?'),\n",
|
||||
" AIMessage(content='1. Choose a programming language: Decide on a programming language that you want to learn.\\n\\n2. Start with the basics: Familiarize yourself with the basic programming concepts such as variables, data types and control structures.\\n\\n3. Practice, practice, practice: The best way to learn programming is through hands-on experience'),\n",
|
||||
" HumanMessage(content='Summarize our conversation so far in 10 words.')]"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain_core.messages import AIMessage, HumanMessage\n",
|
||||
"\n",
|
||||
"human_message = HumanMessage(content=\"What is the best way to learn programming?\")\n",
|
||||
"ai_message = AIMessage(\n",
|
||||
" content=\"\"\"\\\n",
|
||||
"1. Choose a programming language: Decide on a programming language that you want to learn.\n",
|
||||
"\n",
|
||||
"2. Start with the basics: Familiarize yourself with the basic programming concepts such as variables, data types and control structures.\n",
|
||||
"\n",
|
||||
"3. Practice, practice, practice: The best way to learn programming is through hands-on experience\\\n",
|
||||
"\"\"\"\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"chat_prompt.format_prompt(\n",
|
||||
" conversation=[human_message, ai_message], word_count=\"10\"\n",
|
||||
").to_messages()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "7158dce4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
183
docs/docs/modules/model_io/prompts/partial.ipynb
Normal file
183
docs/docs/modules/model_io/prompts/partial.ipynb
Normal file
@@ -0,0 +1,183 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d8ca736e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Partial prompt templates\n",
|
||||
"\n",
|
||||
"Like other methods, it can make sense to \"partial\" a prompt template - e.g. pass in a subset of the required values, as to create a new prompt template which expects only the remaining subset of values.\n",
|
||||
"\n",
|
||||
"LangChain supports this in two ways:\n",
|
||||
"1. Partial formatting with string values.\n",
|
||||
"2. Partial formatting with functions that return string values.\n",
|
||||
"\n",
|
||||
"These two different ways support different use cases. In the examples below, we go over the motivations for both use cases as well as how to do it in LangChain.\n",
|
||||
"\n",
|
||||
"## Partial with strings\n",
|
||||
"\n",
|
||||
"One common use case for wanting to partial a prompt template is if you get some of the variables before others. For example, suppose you have a prompt template that requires two variables, `foo` and `baz`. If you get the `foo` value early on in the chain, but the `baz` value later, it can be annoying to wait until you have both variables in the same place to pass them to the prompt template. Instead, you can partial the prompt template with the `foo` value, and then pass the partialed prompt template along and just use that. Below is an example of doing this:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "5f1942bd",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"foobaz\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain.prompts import PromptTemplate\n",
|
||||
"\n",
|
||||
"prompt = PromptTemplate(template=\"{foo}{bar}\", input_variables=[\"foo\", \"bar\"])\n",
|
||||
"partial_prompt = prompt.partial(foo=\"foo\")\n",
|
||||
"print(partial_prompt.format(bar=\"baz\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "79af4cea",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can also just initialize the prompt with the partialed variables.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "572fa26f",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"foobaz\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"{foo}{bar}\", input_variables=[\"bar\"], partial_variables={\"foo\": \"foo\"}\n",
|
||||
")\n",
|
||||
"print(prompt.format(bar=\"baz\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ab12d50d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Partial with functions\n",
|
||||
"\n",
|
||||
"The other common use is to partial with a function. The use case for this is when you have a variable you know that you always want to fetch in a common way. A prime example of this is with date or time. Imagine you have a prompt which you always want to have the current date. You can't hard code it in the prompt, and passing it along with the other input variables is a bit annoying. In this case, it's very handy to be able to partial the prompt with a function that always returns the current date.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "130224c4",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def _get_datetime():\n",
|
||||
" now = datetime.now()\n",
|
||||
" return now.strftime(\"%m/%d/%Y, %H:%M:%S\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "c538703a",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Tell me a funny joke about the day 12/27/2023, 10:45:22\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"Tell me a {adjective} joke about the day {date}\",\n",
|
||||
" input_variables=[\"adjective\", \"date\"],\n",
|
||||
")\n",
|
||||
"partial_prompt = prompt.partial(date=_get_datetime)\n",
|
||||
"print(partial_prompt.format(adjective=\"funny\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "da80290e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You can also just initialize the prompt with the partialed variables, which often makes more sense in this workflow.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "f86fce6d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Tell me a funny joke about the day 12/27/2023, 10:45:36\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt = PromptTemplate(\n",
|
||||
" template=\"Tell me a {adjective} joke about the day {date}\",\n",
|
||||
" input_variables=[\"adjective\"],\n",
|
||||
" partial_variables={\"date\": _get_datetime},\n",
|
||||
")\n",
|
||||
"print(prompt.format(adjective=\"funny\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "80e52940",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
184
docs/docs/modules/model_io/prompts/pipeline.ipynb
Normal file
184
docs/docs/modules/model_io/prompts/pipeline.ipynb
Normal file
@@ -0,0 +1,184 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "aeb01f8f",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Pipeline\n",
|
||||
"\n",
|
||||
"This notebook goes over how to compose multiple prompts together. This can be useful when you want to reuse parts of prompts. This can be done with a PipelinePrompt. A PipelinePrompt consists of two main parts:\n",
|
||||
"\n",
|
||||
"- Final prompt: The final prompt that is returned\n",
|
||||
"- Pipeline prompts: A list of tuples, consisting of a string name and a prompt template. Each prompt template will be formatted and then passed to future prompt templates as a variable with the same name."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "4044608f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.prompts.pipeline import PipelinePromptTemplate\n",
|
||||
"from langchain.prompts.prompt import PromptTemplate"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "e315c5bf",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"full_template = \"\"\"{introduction}\n",
|
||||
"\n",
|
||||
"{example}\n",
|
||||
"\n",
|
||||
"{start}\"\"\"\n",
|
||||
"full_prompt = PromptTemplate.from_template(full_template)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "33a2ce2b",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"introduction_template = \"\"\"You are impersonating {person}.\"\"\"\n",
|
||||
"introduction_prompt = PromptTemplate.from_template(introduction_template)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "180b7432",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"example_template = \"\"\"Here's an example of an interaction:\n",
|
||||
"\n",
|
||||
"Q: {example_q}\n",
|
||||
"A: {example_a}\"\"\"\n",
|
||||
"example_prompt = PromptTemplate.from_template(example_template)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "583f7188",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"start_template = \"\"\"Now, do this for real!\n",
|
||||
"\n",
|
||||
"Q: {input}\n",
|
||||
"A:\"\"\"\n",
|
||||
"start_prompt = PromptTemplate.from_template(start_template)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "e40edd5c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"input_prompts = [\n",
|
||||
" (\"introduction\", introduction_prompt),\n",
|
||||
" (\"example\", example_prompt),\n",
|
||||
" (\"start\", start_prompt),\n",
|
||||
"]\n",
|
||||
"pipeline_prompt = PipelinePromptTemplate(\n",
|
||||
" final_prompt=full_prompt, pipeline_prompts=input_prompts\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "7957de13",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"['example_q', 'example_a', 'input', 'person']"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"pipeline_prompt.input_variables"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "a0d87803",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"You are impersonating Elon Musk.\n",
|
||||
"\n",
|
||||
"Here's an example of an interaction:\n",
|
||||
"\n",
|
||||
"Q: What's your favorite car?\n",
|
||||
"A: Tesla\n",
|
||||
"\n",
|
||||
"Now, do this for real!\n",
|
||||
"\n",
|
||||
"Q: What's your favorite social media site?\n",
|
||||
"A:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(\n",
|
||||
" pipeline_prompt.format(\n",
|
||||
" person=\"Elon Musk\",\n",
|
||||
" example_q=\"What's your favorite car?\",\n",
|
||||
" example_a=\"Tesla\",\n",
|
||||
" input=\"What's your favorite social media site?\",\n",
|
||||
" )\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "399a1687",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,848 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a792b119",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Connecting to a Feature Store\n",
|
||||
"\n",
|
||||
"Feature stores are a concept from traditional machine learning that make sure data fed into models is up-to-date and relevant. For more on this, see [here](https://www.tecton.ai/blog/what-is-a-feature-store/).\n",
|
||||
"\n",
|
||||
"This concept is extremely relevant when considering putting LLM applications in production. In order to personalize LLM applications, you may want to combine LLMs with up-to-date information about particular users. Feature stores can be a great way to keep that data fresh, and LangChain provides an easy way to combine that data with LLMs.\n",
|
||||
"\n",
|
||||
"In this notebook we will show how to connect prompt templates to feature stores. The basic idea is to call a feature store from inside a prompt template to retrieve values that are then formatted into the prompt."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ad0b5edf",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"source": [
|
||||
"## Feast\n",
|
||||
"\n",
|
||||
"To start, we will use the popular open-source feature store framework [Feast](https://github.com/feast-dev/feast).\n",
|
||||
"\n",
|
||||
"This assumes you have already run the steps in the README around getting started. We will build off of that example in getting started, and create and LLMChain to write a note to a specific driver regarding their up-to-date statistics."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7f02f6f3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Load Feast Store\n",
|
||||
"\n",
|
||||
"Again, this should be set up according to the instructions in the Feast README."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "fd1a452a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from feast import FeatureStore\n",
|
||||
"\n",
|
||||
"# You may need to update the path depending on where you stored it\n",
|
||||
"feast_repo_path = \"../../../../../my_feature_repo/feature_repo/\"\n",
|
||||
"store = FeatureStore(repo_path=feast_repo_path)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cfe8aae5",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Prompts\n",
|
||||
"\n",
|
||||
"Here we will set up a custom FeastPromptTemplate. This prompt template will take in a driver id, look up their stats, and format those stats into a prompt.\n",
|
||||
"\n",
|
||||
"Note that the input to this prompt template is just `driver_id`, since that is the only user defined piece (all other variables are looked up inside the prompt template)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "5e9cee04",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.prompts import PromptTemplate, StringPromptTemplate"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"id": "594a3cf3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"template = \"\"\"Given the driver's up to date stats, write them note relaying those stats to them.\n",
|
||||
"If they have a conversation rate above .5, give them a compliment. Otherwise, make a silly joke about chickens at the end to make them feel better\n",
|
||||
"\n",
|
||||
"Here are the drivers stats:\n",
|
||||
"Conversation rate: {conv_rate}\n",
|
||||
"Acceptance rate: {acc_rate}\n",
|
||||
"Average Daily Trips: {avg_daily_trips}\n",
|
||||
"\n",
|
||||
"Your response:\"\"\"\n",
|
||||
"prompt = PromptTemplate.from_template(template)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"id": "8464c731",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class FeastPromptTemplate(StringPromptTemplate):\n",
|
||||
" def format(self, **kwargs) -> str:\n",
|
||||
" driver_id = kwargs.pop(\"driver_id\")\n",
|
||||
" feature_vector = store.get_online_features(\n",
|
||||
" features=[\n",
|
||||
" \"driver_hourly_stats:conv_rate\",\n",
|
||||
" \"driver_hourly_stats:acc_rate\",\n",
|
||||
" \"driver_hourly_stats:avg_daily_trips\",\n",
|
||||
" ],\n",
|
||||
" entity_rows=[{\"driver_id\": driver_id}],\n",
|
||||
" ).to_dict()\n",
|
||||
" kwargs[\"conv_rate\"] = feature_vector[\"conv_rate\"][0]\n",
|
||||
" kwargs[\"acc_rate\"] = feature_vector[\"acc_rate\"][0]\n",
|
||||
" kwargs[\"avg_daily_trips\"] = feature_vector[\"avg_daily_trips\"][0]\n",
|
||||
" return prompt.format(**kwargs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"id": "c0c7bae2",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"prompt_template = FeastPromptTemplate(input_variables=[\"driver_id\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"id": "d8d70bb7",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Given the driver's up to date stats, write them note relaying those stats to them.\n",
|
||||
"If they have a conversation rate above .5, give them a compliment. Otherwise, make a silly joke about chickens at the end to make them feel better\n",
|
||||
"\n",
|
||||
"Here are the drivers stats:\n",
|
||||
"Conversation rate: 0.4745151400566101\n",
|
||||
"Acceptance rate: 0.055561766028404236\n",
|
||||
"Average Daily Trips: 936\n",
|
||||
"\n",
|
||||
"Your response:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(prompt_template.format(driver_id=1001))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2870d070",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Use in a chain\n",
|
||||
"\n",
|
||||
"We can now use this in a chain, successfully creating a chain that achieves personalization backed by a feature store."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"id": "7106255c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.chains import LLMChain\n",
|
||||
"from langchain.chat_models import ChatOpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 24,
|
||||
"id": "79543326",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"chain = LLMChain(llm=ChatOpenAI(), prompt=prompt_template)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"id": "97a741a0",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"\"Hi there! I wanted to update you on your current stats. Your acceptance rate is 0.055561766028404236 and your average daily trips are 936. While your conversation rate is currently 0.4745151400566101, I have no doubt that with a little extra effort, you'll be able to exceed that .5 mark! Keep up the great work! And remember, even chickens can't always cross the road, but they still give it their best shot.\""
|
||||
]
|
||||
},
|
||||
"execution_count": 25,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"chain.run(1001)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "12e59aaf",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c4049990-651d-44d3-82b1-0cd122da55c1",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Tecton\n",
|
||||
"\n",
|
||||
"Above, we showed how you could use Feast, a popular open-source and self-managed feature store, with LangChain. Our examples below will show a similar integration using Tecton. Tecton is a fully managed feature platform built to orchestrate the complete ML feature lifecycle, from transformation to online serving, with enterprise-grade SLAs."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7bb4dba1-0678-4ea4-be0a-d353c0b13fc2",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"source": [
|
||||
"### Prerequisites\n",
|
||||
"\n",
|
||||
"* Tecton Deployment (sign up at [https://tecton.ai](https://tecton.ai))\n",
|
||||
"* `TECTON_API_KEY` environment variable set to a valid Service Account key"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "ac9eb618-8c52-4cd6-bb8e-9c99a150dfa6",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"source": [
|
||||
"### Define and load features\n",
|
||||
"\n",
|
||||
"We will use the user_transaction_counts Feature View from the [Tecton tutorial](https://docs.tecton.ai/docs/tutorials/tecton-fundamentals) as part of a Feature Service. For simplicity, we are only using a single Feature View; however, more sophisticated applications may require more feature views to retrieve the features needed for its prompt.\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"user_transaction_metrics = FeatureService(\n",
|
||||
" name = \"user_transaction_metrics\",\n",
|
||||
" features = [user_transaction_counts]\n",
|
||||
")\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"The above Feature Service is expected to be [applied to a live workspace](https://docs.tecton.ai/docs/applying-feature-repository-changes-to-a-workspace). For this example, we will be using the \"prod\" workspace."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 60,
|
||||
"id": "32e9675d-a7e5-429f-906f-2260294d3e46",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import tecton\n",
|
||||
"\n",
|
||||
"workspace = tecton.get_workspace(\"prod\")\n",
|
||||
"feature_service = workspace.get_feature_service(\"user_transaction_metrics\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "29b7550c-0eb4-4bd1-a501-1c63fb77aa56",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Prompts\n",
|
||||
"\n",
|
||||
"Here we will set up a custom TectonPromptTemplate. This prompt template will take in a user_id , look up their stats, and format those stats into a prompt.\n",
|
||||
"\n",
|
||||
"Note that the input to this prompt template is just `user_id`, since that is the only user defined piece (all other variables are looked up inside the prompt template)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 61,
|
||||
"id": "6fb77ea4-64c6-4e48-a783-bd1ece021b82",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.prompts import PromptTemplate, StringPromptTemplate"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 77,
|
||||
"id": "02a98fbc-8135-4b11-bf60-85d28e426667",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"template = \"\"\"Given the vendor's up to date transaction stats, write them a note based on the following rules:\n",
|
||||
"\n",
|
||||
"1. If they had a transaction in the last day, write a short congratulations message on their recent sales\n",
|
||||
"2. If no transaction in the last day, but they had a transaction in the last 30 days, playfully encourage them to sell more.\n",
|
||||
"3. Always add a silly joke about chickens at the end\n",
|
||||
"\n",
|
||||
"Here are the vendor's stats:\n",
|
||||
"Number of Transactions Last Day: {transaction_count_1d}\n",
|
||||
"Number of Transactions Last 30 Days: {transaction_count_30d}\n",
|
||||
"\n",
|
||||
"Your response:\"\"\"\n",
|
||||
"prompt = PromptTemplate.from_template(template)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 78,
|
||||
"id": "a35cdfd5-6ccc-4394-acfe-60d53804be51",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class TectonPromptTemplate(StringPromptTemplate):\n",
|
||||
" def format(self, **kwargs) -> str:\n",
|
||||
" user_id = kwargs.pop(\"user_id\")\n",
|
||||
" feature_vector = feature_service.get_online_features(\n",
|
||||
" join_keys={\"user_id\": user_id}\n",
|
||||
" ).to_dict()\n",
|
||||
" kwargs[\"transaction_count_1d\"] = feature_vector[\n",
|
||||
" \"user_transaction_counts.transaction_count_1d_1d\"\n",
|
||||
" ]\n",
|
||||
" kwargs[\"transaction_count_30d\"] = feature_vector[\n",
|
||||
" \"user_transaction_counts.transaction_count_30d_1d\"\n",
|
||||
" ]\n",
|
||||
" return prompt.format(**kwargs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 79,
|
||||
"id": "d5915df0-fb16-4770-8a82-22f885b74d1a",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"prompt_template = TectonPromptTemplate(input_variables=[\"user_id\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 80,
|
||||
"id": "a36abfc8-ea60-4ae0-a36d-d7b639c7307c",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Given the vendor's up to date transaction stats, write them a note based on the following rules:\n",
|
||||
"\n",
|
||||
"1. If they had a transaction in the last day, write a short congratulations message on their recent sales\n",
|
||||
"2. If no transaction in the last day, but they had a transaction in the last 30 days, playfully encourage them to sell more.\n",
|
||||
"3. Always add a silly joke about chickens at the end\n",
|
||||
"\n",
|
||||
"Here are the vendor's stats:\n",
|
||||
"Number of Transactions Last Day: 657\n",
|
||||
"Number of Transactions Last 30 Days: 20326\n",
|
||||
"\n",
|
||||
"Your response:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(prompt_template.format(user_id=\"user_469998441571\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f8d4b905-1051-4303-9c33-8eddb65c1274",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"source": [
|
||||
"### Use in a chain\n",
|
||||
"\n",
|
||||
"We can now use this in a chain, successfully creating a chain that achieves personalization backed by the Tecton Feature Platform."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 81,
|
||||
"id": "ffb60cd0-8e3c-4c9d-b639-43d766e12c4c",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.chains import LLMChain\n",
|
||||
"from langchain.chat_models import ChatOpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 82,
|
||||
"id": "3918abc7-00b5-466f-bdfc-ab046cd282da",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"chain = LLMChain(llm=ChatOpenAI(), prompt=prompt_template)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 83,
|
||||
"id": "e7d91c4b-3e99-40cc-b3e9-a004c8c9193e",
|
||||
"metadata": {
|
||||
"tags": []
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'Wow, congratulations on your recent sales! Your business is really soaring like a chicken on a hot air balloon! Keep up the great work!'"
|
||||
]
|
||||
},
|
||||
"execution_count": 83,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"chain.run(\"user_469998441571\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "f752b924-caf9-4f7a-b78b-cb8c8ada8c2e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "a0691cd9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Featureform\n",
|
||||
"\n",
|
||||
"Finally, we will use [Featureform](https://github.com/featureform/featureform), an open-source and enterprise-grade feature store, to run the same example. Featureform allows you to work with your infrastructure like Spark or locally to define your feature transformations."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "44320d68",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Initialize Featureform\n",
|
||||
"\n",
|
||||
"You can follow in the instructions in the README to initialize your transformations and features in Featureform."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e64ada9d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import featureform as ff\n",
|
||||
"\n",
|
||||
"client = ff.Client(host=\"demo.featureform.com\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "b28914a2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Prompts\n",
|
||||
"\n",
|
||||
"Here we will set up a custom FeatureformPromptTemplate. This prompt template will take in the average amount a user pays per transactions.\n",
|
||||
"\n",
|
||||
"Note that the input to this prompt template is just avg_transaction, since that is the only user defined piece (all other variables are looked up inside the prompt template)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "75d4a34a",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.prompts import PromptTemplate, StringPromptTemplate"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "88253bcb",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"template = \"\"\"Given the amount a user spends on average per transaction, let them know if they are a high roller. Otherwise, make a silly joke about chickens at the end to make them feel better\n",
|
||||
"\n",
|
||||
"Here are the user's stats:\n",
|
||||
"Average Amount per Transaction: ${avg_transcation}\n",
|
||||
"\n",
|
||||
"Your response:\"\"\"\n",
|
||||
"prompt = PromptTemplate.from_template(template)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "61f72476",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class FeatureformPromptTemplate(StringPromptTemplate):\n",
|
||||
" def format(self, **kwargs) -> str:\n",
|
||||
" user_id = kwargs.pop(\"user_id\")\n",
|
||||
" fpf = client.features([(\"avg_transactions\", \"quickstart\")], {\"user\": user_id})\n",
|
||||
" return prompt.format(**kwargs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "994a644c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"prompt_template = FeatureformPromptTemplate(input_variables=[\"user_id\"])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "79b2b0cb",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(prompt_template.format(user_id=\"C1410926\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "f09ddfdd",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Use in a chain\n",
|
||||
"\n",
|
||||
"We can now use this in a chain, successfully creating a chain that achieves personalization backed by the Featureform Feature Platform."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "5e89216f",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.chains import LLMChain\n",
|
||||
"from langchain.chat_models import ChatOpenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "9d3d558c",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"chain = LLMChain(llm=ChatOpenAI(), prompt=prompt_template)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b5412626",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"chain.run(\"C1410926\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4b99ac57",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## AzureML Managed Feature Store\n",
|
||||
"\n",
|
||||
"We will use [AzureML Managed Feature Store](https://learn.microsoft.com/en-us/azure/machine-learning/concept-what-is-managed-feature-store) to run the example below. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "1ebf16d2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Prerequisites\n",
|
||||
"\n",
|
||||
"* Create feature store with online materialization using instructions here [Enable online materialization and run online inference](https://github.com/Azure/azureml-examples/blob/featurestore/online/sdk/python/featurestore_sample/notebooks/sdk_only/5.%20Enable%20online%20store%20and%20run%20online%20inference.ipynb).\n",
|
||||
"\n",
|
||||
"* A successfully created feature store by following the instructions should have an `account` featureset with version as `1`. It will have `accountID` as index column with features `accountAge`, `accountCountry`, `numPaymentRejects1dPerUser`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8b1ad8ee",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Prompts\n",
|
||||
"\n",
|
||||
"* Here we will set up a custom AzureMLFeatureStorePromptTemplate. This prompt template will take in an `account_id` and optional `query`. It then fetches feature values from feature store and format those features into the output prompt. Note that the required input to this prompt template is just `account_id`, since that is the only user defined piece (all other variables are looked up inside the prompt template).\n",
|
||||
"\n",
|
||||
"* Also note that this is a bootstrap example to showcase how LLM applications can leverage AzureML managed feature store. Developers are welcome to improve the prompt template further to suit their needs."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "bd54e256",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"os.environ[\"AZURE_ML_CLI_PRIVATE_FEATURES_ENABLED\"] = \"True\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "5f935e7d",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pandas\n",
|
||||
"from azure.identity import AzureCliCredential\n",
|
||||
"from azureml.featurestore import (\n",
|
||||
" FeatureStoreClient,\n",
|
||||
" get_online_features,\n",
|
||||
" init_online_lookup,\n",
|
||||
")\n",
|
||||
"from langchain.prompts import PromptTemplate, StringPromptTemplate\n",
|
||||
"from pydantic import Extra\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class AzureMLFeatureStorePromptTemplate(StringPromptTemplate, extra=Extra.allow):\n",
|
||||
" def __init__(\n",
|
||||
" self,\n",
|
||||
" subscription_id: str,\n",
|
||||
" resource_group: str,\n",
|
||||
" feature_store_name: str,\n",
|
||||
" **kwargs,\n",
|
||||
" ):\n",
|
||||
" # this is an example template for proof of concept and can be changed to suit the developer needs\n",
|
||||
" template = \"\"\"\n",
|
||||
" {query}\n",
|
||||
" ###\n",
|
||||
" account id = {account_id}\n",
|
||||
" account age = {account_age}\n",
|
||||
" account country = {account_country}\n",
|
||||
" payment rejects 1d per user = {payment_rejects_1d_per_user}\n",
|
||||
" ###\n",
|
||||
" \"\"\"\n",
|
||||
" prompt_template = PromptTemplate.from_template(template)\n",
|
||||
" super().__init__(\n",
|
||||
" prompt=prompt_template, input_variables=[\"account_id\", \"query\"]\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" # use AzureMLOnBehalfOfCredential() in spark context\n",
|
||||
" credential = AzureCliCredential()\n",
|
||||
"\n",
|
||||
" self._fs_client = FeatureStoreClient(\n",
|
||||
" credential=credential,\n",
|
||||
" subscription_id=subscription_id,\n",
|
||||
" resource_group_name=resource_group,\n",
|
||||
" name=feature_store_name,\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" self._feature_set = self._fs_client.feature_sets.get(name=\"accounts\", version=1)\n",
|
||||
"\n",
|
||||
" init_online_lookup(self._feature_set.features, credential, force=True)\n",
|
||||
"\n",
|
||||
" def format(self, **kwargs) -> str:\n",
|
||||
" if \"account_id\" not in kwargs:\n",
|
||||
" raise \"account_id needed to fetch details from feature store\"\n",
|
||||
" account_id = kwargs.pop(\"account_id\")\n",
|
||||
"\n",
|
||||
" query = \"\"\n",
|
||||
" if \"query\" in kwargs:\n",
|
||||
" query = kwargs.pop(\"query\")\n",
|
||||
"\n",
|
||||
" # feature set is registered with accountID as entity index column.\n",
|
||||
" obs = pandas.DataFrame({\"accountID\": [account_id]})\n",
|
||||
"\n",
|
||||
" # get the feature details for the input entity from feature store.\n",
|
||||
" df = get_online_features(self._feature_set.features, obs)\n",
|
||||
"\n",
|
||||
" # populate prompt template output using the fetched feature values.\n",
|
||||
" kwargs[\"query\"] = query\n",
|
||||
" kwargs[\"account_id\"] = account_id\n",
|
||||
" kwargs[\"account_age\"] = df[\"accountAge\"][0]\n",
|
||||
" kwargs[\"account_country\"] = df[\"accountCountry\"][0]\n",
|
||||
" kwargs[\"payment_rejects_1d_per_user\"] = df[\"numPaymentRejects1dPerUser\"][0]\n",
|
||||
"\n",
|
||||
" return self.prompt.format(**kwargs)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "28f148b0",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Test"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "84571856",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Replace the place holders below with actual details of feature store that was created in previous steps\n",
|
||||
"\n",
|
||||
"prompt_template = AzureMLFeatureStorePromptTemplate(\n",
|
||||
" subscription_id=\"\", resource_group=\"\", feature_store_name=\"\"\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "99703f42",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
" \n",
|
||||
" ###\n",
|
||||
" account id = A1829581630230790\n",
|
||||
" account age = 563.0\n",
|
||||
" account country = GB\n",
|
||||
" payment rejects 1d per user = 15.0\n",
|
||||
" ###\n",
|
||||
" \n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(prompt_template.format(account_id=\"A1829581630230790\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c8830d12",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Use in a chain\n",
|
||||
"\n",
|
||||
"We can now use this in a chain, successfully creating a chain that achieves personalization backed by the AzureML Managed Feature Store."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "33266cb5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"os.environ[\"OPENAI_API_KEY\"] = \"\" # Fill the open ai key here\n",
|
||||
"\n",
|
||||
"from langchain.chains import LLMChain\n",
|
||||
"from langchain.chat_models import ChatOpenAI\n",
|
||||
"\n",
|
||||
"chain = LLMChain(llm=ChatOpenAI(), prompt=prompt_template)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "67ae8934",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'Thank you for being a valued member for over 10 years! We appreciate your continued support.'"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# NOTE: developer's can further fine tune AzureMLFeatureStorePromptTemplate\n",
|
||||
"# for getting even more accurate results for the input query\n",
|
||||
"chain.predict(\n",
|
||||
" account_id=\"A1829581630230790\",\n",
|
||||
" query=\"write a small thank you note within 20 words if account age > 10 using the account stats\",\n",
|
||||
")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.13"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,163 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c75efab3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Custom prompt template\n",
|
||||
"\n",
|
||||
"Let's suppose we want the LLM to generate English language explanations of a function given its name. To achieve this task, we will create a custom prompt template that takes in the function name as input, and formats the prompt template to provide the source code of the function.\n",
|
||||
"\n",
|
||||
"## Why are custom prompt templates needed?\n",
|
||||
"\n",
|
||||
"LangChain provides a set of [default prompt templates](/docs/modules/model_io/prompts/prompt_templates/) that can be used to generate prompts for a variety of tasks. However, there may be cases where the default prompt templates do not meet your needs. For example, you may want to create a prompt template with specific dynamic instructions for your language model. In such cases, you can create a custom prompt template."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "5d56ce86",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Creating a custom prompt template\n",
|
||||
"\n",
|
||||
"There are essentially two distinct prompt templates available - string prompt templates and chat prompt templates. String prompt templates provides a simple prompt in string format, while chat prompt templates produces a more structured prompt to be used with a chat API.\n",
|
||||
"\n",
|
||||
"In this guide, we will create a custom prompt using a string prompt template. \n",
|
||||
"\n",
|
||||
"To create a custom string prompt template, there are two requirements:\n",
|
||||
"1. It has an input_variables attribute that exposes what input variables the prompt template expects.\n",
|
||||
"2. It defines a format method that takes in keyword arguments corresponding to the expected input_variables and returns the formatted prompt.\n",
|
||||
"\n",
|
||||
"We will create a custom prompt template that takes in the function name as input and formats the prompt to provide the source code of the function. To achieve this, let's first create a function that will return the source code of a function given its name."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "c831e1ce",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import inspect\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def get_source_code(function_name):\n",
|
||||
" # Get the source code of the function\n",
|
||||
" return inspect.getsource(function_name)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c2c8f4ea",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Next, we'll create a custom prompt template that takes in the function name as input, and formats the prompt template to provide the source code of the function.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "3ad1efdc",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from langchain.prompts import StringPromptTemplate\n",
|
||||
"from pydantic import BaseModel, validator\n",
|
||||
"\n",
|
||||
"PROMPT = \"\"\"\\\n",
|
||||
"Given the function name and source code, generate an English language explanation of the function.\n",
|
||||
"Function Name: {function_name}\n",
|
||||
"Source Code:\n",
|
||||
"{source_code}\n",
|
||||
"Explanation:\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class FunctionExplainerPromptTemplate(StringPromptTemplate, BaseModel):\n",
|
||||
" \"\"\"A custom prompt template that takes in the function name as input, and formats the prompt template to provide the source code of the function.\"\"\"\n",
|
||||
"\n",
|
||||
" @validator(\"input_variables\")\n",
|
||||
" def validate_input_variables(cls, v):\n",
|
||||
" \"\"\"Validate that the input variables are correct.\"\"\"\n",
|
||||
" if len(v) != 1 or \"function_name\" not in v:\n",
|
||||
" raise ValueError(\"function_name must be the only input_variable.\")\n",
|
||||
" return v\n",
|
||||
"\n",
|
||||
" def format(self, **kwargs) -> str:\n",
|
||||
" # Get the source code of the function\n",
|
||||
" source_code = get_source_code(kwargs[\"function_name\"])\n",
|
||||
"\n",
|
||||
" # Generate the prompt to be sent to the language model\n",
|
||||
" prompt = PROMPT.format(\n",
|
||||
" function_name=kwargs[\"function_name\"].__name__, source_code=source_code\n",
|
||||
" )\n",
|
||||
" return prompt\n",
|
||||
"\n",
|
||||
" def _prompt_type(self):\n",
|
||||
" return \"function-explainer\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "7fcbf6ef",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Use the custom prompt template\n",
|
||||
"\n",
|
||||
"Now that we have created a custom prompt template, we can use it to generate prompts for our task."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "bd836cda",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Given the function name and source code, generate an English language explanation of the function.\n",
|
||||
"Function Name: get_source_code\n",
|
||||
"Source Code:\n",
|
||||
"def get_source_code(function_name):\n",
|
||||
" # Get the source code of the function\n",
|
||||
" return inspect.getsource(function_name)\n",
|
||||
"\n",
|
||||
"Explanation:\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fn_explainer = FunctionExplainerPromptTemplate(input_variables=[\"function_name\"])\n",
|
||||
"\n",
|
||||
"# Generate a prompt for the function \"get_source_code\"\n",
|
||||
"prompt = fn_explainer.format(function_name=get_source_code)\n",
|
||||
"print(prompt)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.10.12"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,261 +0,0 @@
|
||||
# Few-shot prompt templates
|
||||
|
||||
In this tutorial, we'll learn how to create a prompt template that uses few-shot examples. A few-shot prompt template can be constructed from either a set of examples, or from an Example Selector object.
|
||||
|
||||
### Use Case
|
||||
|
||||
In this tutorial, we'll configure few-shot examples for self-ask with search.
|
||||
|
||||
|
||||
## Using an example set
|
||||
|
||||
### Create the example set
|
||||
|
||||
To get started, create a list of few-shot examples. Each example should be a dictionary with the keys being the input variables and the values being the values for those input variables.
|
||||
|
||||
```python
|
||||
from langchain.prompts.few_shot import FewShotPromptTemplate
|
||||
from langchain.prompts.prompt import PromptTemplate
|
||||
|
||||
examples = [
|
||||
{
|
||||
"question": "Who lived longer, Muhammad Ali or Alan Turing?",
|
||||
"answer":
|
||||
"""
|
||||
Are follow up questions needed here: Yes.
|
||||
Follow up: How old was Muhammad Ali when he died?
|
||||
Intermediate answer: Muhammad Ali was 74 years old when he died.
|
||||
Follow up: How old was Alan Turing when he died?
|
||||
Intermediate answer: Alan Turing was 41 years old when he died.
|
||||
So the final answer is: Muhammad Ali
|
||||
"""
|
||||
},
|
||||
{
|
||||
"question": "When was the founder of craigslist born?",
|
||||
"answer":
|
||||
"""
|
||||
Are follow up questions needed here: Yes.
|
||||
Follow up: Who was the founder of craigslist?
|
||||
Intermediate answer: Craigslist was founded by Craig Newmark.
|
||||
Follow up: When was Craig Newmark born?
|
||||
Intermediate answer: Craig Newmark was born on December 6, 1952.
|
||||
So the final answer is: December 6, 1952
|
||||
"""
|
||||
},
|
||||
{
|
||||
"question": "Who was the maternal grandfather of George Washington?",
|
||||
"answer":
|
||||
"""
|
||||
Are follow up questions needed here: Yes.
|
||||
Follow up: Who was the mother of George Washington?
|
||||
Intermediate answer: The mother of George Washington was Mary Ball Washington.
|
||||
Follow up: Who was the father of Mary Ball Washington?
|
||||
Intermediate answer: The father of Mary Ball Washington was Joseph Ball.
|
||||
So the final answer is: Joseph Ball
|
||||
"""
|
||||
},
|
||||
{
|
||||
"question": "Are both the directors of Jaws and Casino Royale from the same country?",
|
||||
"answer":
|
||||
"""
|
||||
Are follow up questions needed here: Yes.
|
||||
Follow up: Who is the director of Jaws?
|
||||
Intermediate Answer: The director of Jaws is Steven Spielberg.
|
||||
Follow up: Where is Steven Spielberg from?
|
||||
Intermediate Answer: The United States.
|
||||
Follow up: Who is the director of Casino Royale?
|
||||
Intermediate Answer: The director of Casino Royale is Martin Campbell.
|
||||
Follow up: Where is Martin Campbell from?
|
||||
Intermediate Answer: New Zealand.
|
||||
So the final answer is: No
|
||||
"""
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Create a formatter for the few-shot examples
|
||||
|
||||
Configure a formatter that will format the few-shot examples into a string. This formatter should be a `PromptTemplate` object.
|
||||
|
||||
|
||||
```python
|
||||
example_prompt = PromptTemplate(input_variables=["question", "answer"], template="Question: {question}\n{answer}")
|
||||
|
||||
print(example_prompt.format(**examples[0]))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Question: Who lived longer, Muhammad Ali or Alan Turing?
|
||||
|
||||
Are follow up questions needed here: Yes.
|
||||
Follow up: How old was Muhammad Ali when he died?
|
||||
Intermediate answer: Muhammad Ali was 74 years old when he died.
|
||||
Follow up: How old was Alan Turing when he died?
|
||||
Intermediate answer: Alan Turing was 41 years old when he died.
|
||||
So the final answer is: Muhammad Ali
|
||||
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
### Feed examples and formatter to `FewShotPromptTemplate`
|
||||
|
||||
Finally, create a `FewShotPromptTemplate` object. This object takes in the few-shot examples and the formatter for the few-shot examples.
|
||||
|
||||
|
||||
```python
|
||||
prompt = FewShotPromptTemplate(
|
||||
examples=examples,
|
||||
example_prompt=example_prompt,
|
||||
suffix="Question: {input}",
|
||||
input_variables=["input"]
|
||||
)
|
||||
|
||||
print(prompt.format(input="Who was the father of Mary Ball Washington?"))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Question: Who lived longer, Muhammad Ali or Alan Turing?
|
||||
|
||||
Are follow up questions needed here: Yes.
|
||||
Follow up: How old was Muhammad Ali when he died?
|
||||
Intermediate answer: Muhammad Ali was 74 years old when he died.
|
||||
Follow up: How old was Alan Turing when he died?
|
||||
Intermediate answer: Alan Turing was 41 years old when he died.
|
||||
So the final answer is: Muhammad Ali
|
||||
|
||||
|
||||
Question: When was the founder of craigslist born?
|
||||
|
||||
Are follow up questions needed here: Yes.
|
||||
Follow up: Who was the founder of craigslist?
|
||||
Intermediate answer: Craigslist was founded by Craig Newmark.
|
||||
Follow up: When was Craig Newmark born?
|
||||
Intermediate answer: Craig Newmark was born on December 6, 1952.
|
||||
So the final answer is: December 6, 1952
|
||||
|
||||
|
||||
Question: Who was the maternal grandfather of George Washington?
|
||||
|
||||
Are follow up questions needed here: Yes.
|
||||
Follow up: Who was the mother of George Washington?
|
||||
Intermediate answer: The mother of George Washington was Mary Ball Washington.
|
||||
Follow up: Who was the father of Mary Ball Washington?
|
||||
Intermediate answer: The father of Mary Ball Washington was Joseph Ball.
|
||||
So the final answer is: Joseph Ball
|
||||
|
||||
|
||||
Question: Are both the directors of Jaws and Casino Royale from the same country?
|
||||
|
||||
Are follow up questions needed here: Yes.
|
||||
Follow up: Who is the director of Jaws?
|
||||
Intermediate Answer: The director of Jaws is Steven Spielberg.
|
||||
Follow up: Where is Steven Spielberg from?
|
||||
Intermediate Answer: The United States.
|
||||
Follow up: Who is the director of Casino Royale?
|
||||
Intermediate Answer: The director of Casino Royale is Martin Campbell.
|
||||
Follow up: Where is Martin Campbell from?
|
||||
Intermediate Answer: New Zealand.
|
||||
So the final answer is: No
|
||||
|
||||
|
||||
Question: Who was the father of Mary Ball Washington?
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
## Using an example selector
|
||||
|
||||
### Feed examples into `ExampleSelector`
|
||||
|
||||
We will reuse the example set and the formatter from the previous section. However, instead of feeding the examples directly into the `FewShotPromptTemplate` object, we will feed them into an `ExampleSelector` object.
|
||||
|
||||
|
||||
In this tutorial, we will use the `SemanticSimilarityExampleSelector` class. This class selects few-shot examples based on their similarity to the input. It uses an embedding model to compute the similarity between the input and the few-shot examples, as well as a vector store to perform the nearest neighbor search.
|
||||
|
||||
|
||||
```python
|
||||
from langchain.prompts.example_selector import SemanticSimilarityExampleSelector
|
||||
from langchain.vectorstores import Chroma
|
||||
from langchain.embeddings import OpenAIEmbeddings
|
||||
|
||||
|
||||
example_selector = SemanticSimilarityExampleSelector.from_examples(
|
||||
# This is the list of examples available to select from.
|
||||
examples,
|
||||
# This is the embedding class used to produce embeddings which are used to measure semantic similarity.
|
||||
OpenAIEmbeddings(),
|
||||
# This is the VectorStore class that is used to store the embeddings and do a similarity search over.
|
||||
Chroma,
|
||||
# This is the number of examples to produce.
|
||||
k=1
|
||||
)
|
||||
|
||||
# Select the most similar example to the input.
|
||||
question = "Who was the father of Mary Ball Washington?"
|
||||
selected_examples = example_selector.select_examples({"question": question})
|
||||
print(f"Examples most similar to the input: {question}")
|
||||
for example in selected_examples:
|
||||
print("\n")
|
||||
for k, v in example.items():
|
||||
print(f"{k}: {v}")
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Running Chroma using direct local API.
|
||||
Using DuckDB in-memory for database. Data will be transient.
|
||||
Examples most similar to the input: Who was the father of Mary Ball Washington?
|
||||
|
||||
|
||||
question: Who was the maternal grandfather of George Washington?
|
||||
answer:
|
||||
Are follow up questions needed here: Yes.
|
||||
Follow up: Who was the mother of George Washington?
|
||||
Intermediate answer: The mother of George Washington was Mary Ball Washington.
|
||||
Follow up: Who was the father of Mary Ball Washington?
|
||||
Intermediate answer: The father of Mary Ball Washington was Joseph Ball.
|
||||
So the final answer is: Joseph Ball
|
||||
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
### Feed example selector into `FewShotPromptTemplate`
|
||||
|
||||
Finally, create a `FewShotPromptTemplate` object. This object takes in the example selector and the formatter for the few-shot examples.
|
||||
|
||||
|
||||
```python
|
||||
prompt = FewShotPromptTemplate(
|
||||
example_selector=example_selector,
|
||||
example_prompt=example_prompt,
|
||||
suffix="Question: {input}",
|
||||
input_variables=["input"]
|
||||
)
|
||||
|
||||
print(prompt.format(input="Who was the father of Mary Ball Washington?"))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Question: Who was the maternal grandfather of George Washington?
|
||||
|
||||
Are follow up questions needed here: Yes.
|
||||
Follow up: Who was the mother of George Washington?
|
||||
Intermediate answer: The mother of George Washington was Mary Ball Washington.
|
||||
Follow up: Who was the father of Mary Ball Washington?
|
||||
Intermediate answer: The father of Mary Ball Washington was Joseph Ball.
|
||||
So the final answer is: Joseph Ball
|
||||
|
||||
|
||||
Question: Who was the father of Mary Ball Washington?
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
@@ -1,58 +0,0 @@
|
||||
# Format template output
|
||||
|
||||
The output of the format method is available as a string, list of messages and `ChatPromptValue`
|
||||
|
||||
As string:
|
||||
|
||||
|
||||
```python
|
||||
output = chat_prompt.format(input_language="English", output_language="French", text="I love programming.")
|
||||
output
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
'System: You are a helpful assistant that translates English to French.\nHuman: I love programming.'
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
|
||||
```python
|
||||
# or alternatively
|
||||
output_2 = chat_prompt.format_prompt(input_language="English", output_language="French", text="I love programming.").to_string()
|
||||
|
||||
assert output == output_2
|
||||
```
|
||||
|
||||
As list of Message objects:
|
||||
|
||||
|
||||
```python
|
||||
chat_prompt.format_prompt(input_language="English", output_language="French", text="I love programming.").to_messages()
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
[SystemMessage(content='You are a helpful assistant that translates English to French.', additional_kwargs={}),
|
||||
HumanMessage(content='I love programming.', additional_kwargs={})]
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
As `ChatPromptValue`:
|
||||
|
||||
|
||||
```python
|
||||
chat_prompt.format_prompt(input_language="English", output_language="French", text="I love programming.")
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
ChatPromptValue(messages=[SystemMessage(content='You are a helpful assistant that translates English to French.', additional_kwargs={}), HumanMessage(content='I love programming.', additional_kwargs={})])
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
@@ -1,29 +0,0 @@
|
||||
# Template formats
|
||||
|
||||
`PromptTemplate` by default uses Python f-string as its template format. However, it can also use other formats like `jinja2`, specified through the `template_format` argument.
|
||||
|
||||
To use the `jinja2` template:
|
||||
|
||||
```python
|
||||
from langchain.prompts import PromptTemplate
|
||||
|
||||
jinja2_template = "Tell me a {{ adjective }} joke about {{ content }}"
|
||||
prompt = PromptTemplate.from_template(jinja2_template, template_format="jinja2")
|
||||
|
||||
prompt.format(adjective="funny", content="chickens")
|
||||
# Output: Tell me a funny joke about chickens.
|
||||
```
|
||||
|
||||
To use the Python f-string template:
|
||||
|
||||
```python
|
||||
from langchain.prompts import PromptTemplate
|
||||
|
||||
fstring_template = """Tell me a {adjective} joke about {content}"""
|
||||
prompt = PromptTemplate.from_template(fstring_template)
|
||||
|
||||
prompt.format(adjective="funny", content="chickens")
|
||||
# Output: Tell me a funny joke about chickens.
|
||||
```
|
||||
|
||||
Currently, only `jinja2` and `f-string` are supported. For other formats, kindly raise an issue on the [Github page](https://github.com/langchain-ai/langchain/issues).
|
||||
@@ -1,63 +0,0 @@
|
||||
# Types of `MessagePromptTemplate`
|
||||
|
||||
LangChain provides different types of `MessagePromptTemplate`. The most commonly used are `AIMessagePromptTemplate`, `SystemMessagePromptTemplate` and `HumanMessagePromptTemplate`, which create an AI message, system message and human message respectively.
|
||||
|
||||
However, in cases where the chat model supports taking chat message with arbitrary role, you can use `ChatMessagePromptTemplate`, which allows user to specify the role name.
|
||||
|
||||
|
||||
```python
|
||||
from langchain.prompts import ChatMessagePromptTemplate
|
||||
|
||||
prompt = "May the {subject} be with you"
|
||||
|
||||
chat_message_prompt = ChatMessagePromptTemplate.from_template(role="Jedi", template=prompt)
|
||||
chat_message_prompt.format(subject="force")
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
ChatMessage(content='May the force be with you', additional_kwargs={}, role='Jedi')
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
LangChain also provides `MessagesPlaceholder`, which gives you full control of what messages to be rendered during formatting. This can be useful when you are uncertain of what role you should be using for your message prompt templates or when you wish to insert a list of messages during formatting.
|
||||
|
||||
|
||||
```python
|
||||
from langchain.prompts import MessagesPlaceholder
|
||||
from langchain.prompts import HumanMessagePromptTemplate
|
||||
from langchain.prompts import ChatPromptTemplate
|
||||
|
||||
human_prompt = "Summarize our conversation so far in {word_count} words."
|
||||
human_message_template = HumanMessagePromptTemplate.from_template(human_prompt)
|
||||
|
||||
chat_prompt = ChatPromptTemplate.from_messages([MessagesPlaceholder(variable_name="conversation"), human_message_template])
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
from langchain_core.messages import HumanMessage, AIMessage
|
||||
|
||||
human_message = HumanMessage(content="What is the best way to learn programming?")
|
||||
ai_message = AIMessage(content="""\
|
||||
1. Choose a programming language: Decide on a programming language that you want to learn.
|
||||
|
||||
2. Start with the basics: Familiarize yourself with the basic programming concepts such as variables, data types and control structures.
|
||||
|
||||
3. Practice, practice, practice: The best way to learn programming is through hands-on experience\
|
||||
""")
|
||||
|
||||
chat_prompt.format_prompt(conversation=[human_message, ai_message], word_count="10").to_messages()
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
[HumanMessage(content='What is the best way to learn programming?', additional_kwargs={}),
|
||||
AIMessage(content='1. Choose a programming language: Decide on a programming language that you want to learn. \n\n2. Start with the basics: Familiarize yourself with the basic programming concepts such as variables, data types and control structures.\n\n3. Practice, practice, practice: The best way to learn programming is through hands-on experience', additional_kwargs={}),
|
||||
HumanMessage(content='Summarize our conversation so far in 10 words.', additional_kwargs={})]
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
@@ -1,102 +0,0 @@
|
||||
# Partial prompt templates
|
||||
|
||||
Like other methods, it can make sense to "partial" a prompt template - e.g. pass in a subset of the required values, as to create a new prompt template which expects only the remaining subset of values.
|
||||
|
||||
LangChain supports this in two ways:
|
||||
1. Partial formatting with string values.
|
||||
2. Partial formatting with functions that return string values.
|
||||
|
||||
These two different ways support different use cases. In the examples below, we go over the motivations for both use cases as well as how to do it in LangChain.
|
||||
|
||||
## Partial with strings
|
||||
|
||||
One common use case for wanting to partial a prompt template is if you get some of the variables before others. For example, suppose you have a prompt template that requires two variables, `foo` and `baz`. If you get the `foo` value early on in the chain, but the `baz` value later, it can be annoying to wait until you have both variables in the same place to pass them to the prompt template. Instead, you can partial the prompt template with the `foo` value, and then pass the partialed prompt template along and just use that. Below is an example of doing this:
|
||||
|
||||
|
||||
|
||||
|
||||
```python
|
||||
from langchain.prompts import PromptTemplate
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
prompt = PromptTemplate(template="{foo}{bar}", input_variables=["foo", "bar"])
|
||||
partial_prompt = prompt.partial(foo="foo");
|
||||
print(partial_prompt.format(bar="baz"))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
foobaz
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
You can also just initialize the prompt with the partialed variables.
|
||||
|
||||
|
||||
```python
|
||||
prompt = PromptTemplate(template="{foo}{bar}", input_variables=["bar"], partial_variables={"foo": "foo"})
|
||||
print(prompt.format(bar="baz"))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
foobaz
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
## Partial with functions
|
||||
|
||||
The other common use is to partial with a function. The use case for this is when you have a variable you know that you always want to fetch in a common way. A prime example of this is with date or time. Imagine you have a prompt which you always want to have the current date. You can't hard code it in the prompt, and passing it along with the other input variables is a bit annoying. In this case, it's very handy to be able to partial the prompt with a function that always returns the current date.
|
||||
|
||||
|
||||
```python
|
||||
from datetime import datetime
|
||||
|
||||
def _get_datetime():
|
||||
now = datetime.now()
|
||||
return now.strftime("%m/%d/%Y, %H:%M:%S")
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
prompt = PromptTemplate(
|
||||
template="Tell me a {adjective} joke about the day {date}",
|
||||
input_variables=["adjective", "date"]
|
||||
);
|
||||
partial_prompt = prompt.partial(date=_get_datetime)
|
||||
print(partial_prompt.format(adjective="funny"))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Tell me a funny joke about the day 02/27/2023, 22:15:16
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
You can also just initialize the prompt with the partialed variables, which often makes more sense in this workflow.
|
||||
|
||||
|
||||
```python
|
||||
prompt = PromptTemplate(
|
||||
template="Tell me a {adjective} joke about the day {date}",
|
||||
input_variables=["adjective"],
|
||||
partial_variables={"date": _get_datetime}
|
||||
);
|
||||
print(prompt.format(adjective="funny"))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
Tell me a funny joke about the day 02/27/2023, 22:15:16
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
@@ -1,95 +0,0 @@
|
||||
# Composition
|
||||
|
||||
This notebook goes over how to compose multiple prompts together. This can be useful when you want to reuse parts of prompts. This can be done with a PipelinePrompt. A PipelinePrompt consists of two main parts:
|
||||
|
||||
- Final prompt: The final prompt that is returned
|
||||
- Pipeline prompts: A list of tuples, consisting of a string name and a prompt template. Each prompt template will be formatted and then passed to future prompt templates as a variable with the same name.
|
||||
|
||||
```python
|
||||
from langchain.prompts.pipeline import PipelinePromptTemplate
|
||||
from langchain.prompts.prompt import PromptTemplate
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
full_template = """{introduction}
|
||||
|
||||
{example}
|
||||
|
||||
{start}"""
|
||||
full_prompt = PromptTemplate.from_template(full_template)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
introduction_template = """You are impersonating {person}."""
|
||||
introduction_prompt = PromptTemplate.from_template(introduction_template)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
example_template = """Here's an example of an interaction:
|
||||
|
||||
Q: {example_q}
|
||||
A: {example_a}"""
|
||||
example_prompt = PromptTemplate.from_template(example_template)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
start_template = """Now, do this for real!
|
||||
|
||||
Q: {input}
|
||||
A:"""
|
||||
start_prompt = PromptTemplate.from_template(start_template)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
input_prompts = [
|
||||
("introduction", introduction_prompt),
|
||||
("example", example_prompt),
|
||||
("start", start_prompt)
|
||||
]
|
||||
pipeline_prompt = PipelinePromptTemplate(final_prompt=full_prompt, pipeline_prompts=input_prompts)
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
pipeline_prompt.input_variables
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
['example_a', 'person', 'example_q', 'input']
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
|
||||
|
||||
```python
|
||||
print(pipeline_prompt.format(
|
||||
person="Elon Musk",
|
||||
example_q="What's your favorite car?",
|
||||
example_a="Tesla",
|
||||
input="What's your favorite social media site?"
|
||||
))
|
||||
```
|
||||
|
||||
<CodeOutputBlock lang="python">
|
||||
|
||||
```
|
||||
You are impersonating Elon Musk.
|
||||
Here's an example of an interaction:
|
||||
|
||||
Q: What's your favorite car?
|
||||
A: Tesla
|
||||
Now, do this for real!
|
||||
|
||||
Q: What's your favorite social media site?
|
||||
A:
|
||||
|
||||
```
|
||||
|
||||
</CodeOutputBlock>
|
||||
@@ -1,742 +0,0 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "43fb16cb",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Serialization\n",
|
||||
"\n",
|
||||
"It is often preferable to store prompts not as python code but as files. This can make it easy to share, store, and version prompts. This notebook covers how to do that in LangChain, walking through all the different types of prompts and the different serialization options.\n",
|
||||
"\n",
|
||||
"At a high level, the following design principles are applied to serialization:\n",
|
||||
"\n",
|
||||
"1. Both JSON and YAML are supported. We want to support serialization methods that are human readable on disk, and YAML and JSON are two of the most popular methods for that. Note that this rule applies to prompts. For other assets, like examples, different serialization methods may be supported.\n",
|
||||
"\n",
|
||||
"2. We support specifying everything in one file, or storing different components (templates, examples, etc) in different files and referencing them. For some cases, storing everything in file makes the most sense, but for others it is preferable to split up some of the assets (long templates, large examples, reusable components). LangChain supports both.\n",
|
||||
"\n",
|
||||
"There is also a single entry point to load prompts from disk, making it easy to load any type of prompt."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "2c8d7587",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# All prompts are loaded through the `load_prompt` function.\n",
|
||||
"from langchain.prompts import load_prompt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "cddb465e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## PromptTemplate\n",
|
||||
"\n",
|
||||
"This section covers examples for loading a PromptTemplate."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4d4b40f2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Loading from YAML\n",
|
||||
"This shows an example of loading a PromptTemplate from YAML."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"id": "2d6e5117",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"_type: prompt\r\n",
|
||||
"input_variables:\r\n",
|
||||
" [\"adjective\", \"content\"]\r\n",
|
||||
"template: \r\n",
|
||||
" Tell me a {adjective} joke about {content}.\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!cat simple_prompt.yaml"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "4f4ca686",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Tell me a funny joke about chickens.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt = load_prompt(\"simple_prompt.yaml\")\n",
|
||||
"print(prompt.format(adjective=\"funny\", content=\"chickens\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "362eadb2",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Loading from JSON\n",
|
||||
"This shows an example of loading a PromptTemplate from JSON."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "510def23",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{\r\n",
|
||||
" \"_type\": \"prompt\",\r\n",
|
||||
" \"input_variables\": [\"adjective\", \"content\"],\r\n",
|
||||
" \"template\": \"Tell me a {adjective} joke about {content}.\"\r\n",
|
||||
"}\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!cat simple_prompt.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "de75e959",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"prompt = load_prompt(\"simple_prompt.json\")\n",
|
||||
"print(prompt.format(adjective=\"funny\", content=\"chickens\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d1d788f9",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Tell me a funny joke about chickens."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d788a83c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Loading template from a file\n",
|
||||
"This shows an example of storing the template in a separate file and then referencing it in the config. Notice that the key changes from `template` to `template_path`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "5547760d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Tell me a {adjective} joke about {content}."
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!cat simple_template.txt"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "9cb13ac5",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{\r\n",
|
||||
" \"_type\": \"prompt\",\r\n",
|
||||
" \"input_variables\": [\"adjective\", \"content\"],\r\n",
|
||||
" \"template_path\": \"simple_template.txt\"\r\n",
|
||||
"}\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!cat simple_prompt_with_template_file.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "762cb4bf",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Tell me a funny joke about chickens.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt = load_prompt(\"simple_prompt_with_template_file.json\")\n",
|
||||
"print(prompt.format(adjective=\"funny\", content=\"chickens\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2ae191cc",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## FewShotPromptTemplate\n",
|
||||
"\n",
|
||||
"This section covers examples for loading few-shot prompt templates."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9828f94c",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Examples\n",
|
||||
"This shows an example of what examples stored as json might look like."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "b21f5b95",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[\r\n",
|
||||
" {\"input\": \"happy\", \"output\": \"sad\"},\r\n",
|
||||
" {\"input\": \"tall\", \"output\": \"short\"}\r\n",
|
||||
"]\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!cat examples.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "d3052850",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"And here is what the same examples stored as yaml might look like."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "901385d1",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"- input: happy\r\n",
|
||||
" output: sad\r\n",
|
||||
"- input: tall\r\n",
|
||||
" output: short\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!cat examples.yaml"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "8e300335",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Loading from YAML\n",
|
||||
"This shows an example of loading a few-shot example from YAML."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "e2bec0fc",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"_type: few_shot\r\n",
|
||||
"input_variables:\r\n",
|
||||
" [\"adjective\"]\r\n",
|
||||
"prefix: \r\n",
|
||||
" Write antonyms for the following words.\r\n",
|
||||
"example_prompt:\r\n",
|
||||
" _type: prompt\r\n",
|
||||
" input_variables:\r\n",
|
||||
" [\"input\", \"output\"]\r\n",
|
||||
" template:\r\n",
|
||||
" \"Input: {input}\\nOutput: {output}\"\r\n",
|
||||
"examples:\r\n",
|
||||
" examples.json\r\n",
|
||||
"suffix:\r\n",
|
||||
" \"Input: {adjective}\\nOutput:\"\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!cat few_shot_prompt.yaml"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "98c8f356",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Write antonyms for the following words.\n",
|
||||
"\n",
|
||||
"Input: happy\n",
|
||||
"Output: sad\n",
|
||||
"\n",
|
||||
"Input: tall\n",
|
||||
"Output: short\n",
|
||||
"\n",
|
||||
"Input: funny\n",
|
||||
"Output:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt = load_prompt(\"few_shot_prompt.yaml\")\n",
|
||||
"print(prompt.format(adjective=\"funny\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "13620324",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The same would work if you loaded examples from the yaml file."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "831e5e4a",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"_type: few_shot\r\n",
|
||||
"input_variables:\r\n",
|
||||
" [\"adjective\"]\r\n",
|
||||
"prefix: \r\n",
|
||||
" Write antonyms for the following words.\r\n",
|
||||
"example_prompt:\r\n",
|
||||
" _type: prompt\r\n",
|
||||
" input_variables:\r\n",
|
||||
" [\"input\", \"output\"]\r\n",
|
||||
" template:\r\n",
|
||||
" \"Input: {input}\\nOutput: {output}\"\r\n",
|
||||
"examples:\r\n",
|
||||
" examples.yaml\r\n",
|
||||
"suffix:\r\n",
|
||||
" \"Input: {adjective}\\nOutput:\"\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!cat few_shot_prompt_yaml_examples.yaml"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "6f0a7eaa",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Write antonyms for the following words.\n",
|
||||
"\n",
|
||||
"Input: happy\n",
|
||||
"Output: sad\n",
|
||||
"\n",
|
||||
"Input: tall\n",
|
||||
"Output: short\n",
|
||||
"\n",
|
||||
"Input: funny\n",
|
||||
"Output:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt = load_prompt(\"few_shot_prompt_yaml_examples.yaml\")\n",
|
||||
"print(prompt.format(adjective=\"funny\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "4870aa9d",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Loading from JSON\n",
|
||||
"This shows an example of loading a few-shot example from JSON."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"id": "9d996a86",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{\r\n",
|
||||
" \"_type\": \"few_shot\",\r\n",
|
||||
" \"input_variables\": [\"adjective\"],\r\n",
|
||||
" \"prefix\": \"Write antonyms for the following words.\",\r\n",
|
||||
" \"example_prompt\": {\r\n",
|
||||
" \"_type\": \"prompt\",\r\n",
|
||||
" \"input_variables\": [\"input\", \"output\"],\r\n",
|
||||
" \"template\": \"Input: {input}\\nOutput: {output}\"\r\n",
|
||||
" },\r\n",
|
||||
" \"examples\": \"examples.json\",\r\n",
|
||||
" \"suffix\": \"Input: {adjective}\\nOutput:\"\r\n",
|
||||
"} \r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!cat few_shot_prompt.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "dd2c10bb",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Write antonyms for the following words.\n",
|
||||
"\n",
|
||||
"Input: happy\n",
|
||||
"Output: sad\n",
|
||||
"\n",
|
||||
"Input: tall\n",
|
||||
"Output: short\n",
|
||||
"\n",
|
||||
"Input: funny\n",
|
||||
"Output:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt = load_prompt(\"few_shot_prompt.json\")\n",
|
||||
"print(prompt.format(adjective=\"funny\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "9d23faf4",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Examples in the config\n",
|
||||
"This shows an example of referencing the examples directly in the config."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"id": "6cd781ef",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{\r\n",
|
||||
" \"_type\": \"few_shot\",\r\n",
|
||||
" \"input_variables\": [\"adjective\"],\r\n",
|
||||
" \"prefix\": \"Write antonyms for the following words.\",\r\n",
|
||||
" \"example_prompt\": {\r\n",
|
||||
" \"_type\": \"prompt\",\r\n",
|
||||
" \"input_variables\": [\"input\", \"output\"],\r\n",
|
||||
" \"template\": \"Input: {input}\\nOutput: {output}\"\r\n",
|
||||
" },\r\n",
|
||||
" \"examples\": [\r\n",
|
||||
" {\"input\": \"happy\", \"output\": \"sad\"},\r\n",
|
||||
" {\"input\": \"tall\", \"output\": \"short\"}\r\n",
|
||||
" ],\r\n",
|
||||
" \"suffix\": \"Input: {adjective}\\nOutput:\"\r\n",
|
||||
"} \r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!cat few_shot_prompt_examples_in.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"id": "533ab8a7",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Write antonyms for the following words.\n",
|
||||
"\n",
|
||||
"Input: happy\n",
|
||||
"Output: sad\n",
|
||||
"\n",
|
||||
"Input: tall\n",
|
||||
"Output: short\n",
|
||||
"\n",
|
||||
"Input: funny\n",
|
||||
"Output:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt = load_prompt(\"few_shot_prompt_examples_in.json\")\n",
|
||||
"print(prompt.format(adjective=\"funny\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2e86139e",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Example prompt from a file\n",
|
||||
"This shows an example of loading the PromptTemplate that is used to format the examples from a separate file. Note that the key changes from `example_prompt` to `example_prompt_path`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "0b6dd7b8",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{\r\n",
|
||||
" \"_type\": \"prompt\",\r\n",
|
||||
" \"input_variables\": [\"input\", \"output\"],\r\n",
|
||||
" \"template\": \"Input: {input}\\nOutput: {output}\" \r\n",
|
||||
"}\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!cat example_prompt.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"id": "76a1065d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{\r\n",
|
||||
" \"_type\": \"few_shot\",\r\n",
|
||||
" \"input_variables\": [\"adjective\"],\r\n",
|
||||
" \"prefix\": \"Write antonyms for the following words.\",\r\n",
|
||||
" \"example_prompt_path\": \"example_prompt.json\",\r\n",
|
||||
" \"examples\": \"examples.json\",\r\n",
|
||||
" \"suffix\": \"Input: {adjective}\\nOutput:\"\r\n",
|
||||
"} \r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!cat few_shot_prompt_example_prompt.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"id": "744d275d",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Write antonyms for the following words.\n",
|
||||
"\n",
|
||||
"Input: happy\n",
|
||||
"Output: sad\n",
|
||||
"\n",
|
||||
"Input: tall\n",
|
||||
"Output: short\n",
|
||||
"\n",
|
||||
"Input: funny\n",
|
||||
"Output:\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt = load_prompt(\"few_shot_prompt_example_prompt.json\")\n",
|
||||
"print(prompt.format(adjective=\"funny\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "c6e3f9fe",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## PromptTemplate with OutputParser\n",
|
||||
"This shows an example of loading a prompt along with an OutputParser from a file."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "500dab26",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"{\r\n",
|
||||
" \"input_variables\": [\r\n",
|
||||
" \"question\",\r\n",
|
||||
" \"student_answer\"\r\n",
|
||||
" ],\r\n",
|
||||
" \"output_parser\": {\r\n",
|
||||
" \"regex\": \"(.*?)\\\\nScore: (.*)\",\r\n",
|
||||
" \"output_keys\": [\r\n",
|
||||
" \"answer\",\r\n",
|
||||
" \"score\"\r\n",
|
||||
" ],\r\n",
|
||||
" \"default_output_key\": null,\r\n",
|
||||
" \"_type\": \"regex_parser\"\r\n",
|
||||
" },\r\n",
|
||||
" \"partial_variables\": {},\r\n",
|
||||
" \"template\": \"Given the following question and student answer, provide a correct answer and score the student answer.\\nQuestion: {question}\\nStudent Answer: {student_answer}\\nCorrect Answer:\",\r\n",
|
||||
" \"template_format\": \"f-string\",\r\n",
|
||||
" \"validate_template\": true,\r\n",
|
||||
" \"_type\": \"prompt\"\r\n",
|
||||
"}"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"! cat prompt_with_output_parser.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"id": "d267a736",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"prompt = load_prompt(\"prompt_with_output_parser.json\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"id": "cb770399",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{'answer': 'George Washington was born in 1732 and died in 1799.',\n",
|
||||
" 'score': '1/2'}"
|
||||
]
|
||||
},
|
||||
"execution_count": 21,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"prompt.output_parser.parse(\n",
|
||||
" \"George Washington was born in 1732 and died in 1799.\\nScore: 1/2\"\n",
|
||||
")"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.11.3"
|
||||
},
|
||||
"vscode": {
|
||||
"interpreter": {
|
||||
"hash": "8eb71adebe840dca1185e9603533462bc47eb1b1a73bf7dab2d0a8a4c932882e"
|
||||
}
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"input_variables": [
|
||||
"question",
|
||||
"student_answer"
|
||||
],
|
||||
"output_parser": {
|
||||
"regex": "(.*?)\nScore: (.*)",
|
||||
"output_keys": [
|
||||
"answer",
|
||||
"score"
|
||||
],
|
||||
"default_output_key": null,
|
||||
"_type": "regex_parser"
|
||||
},
|
||||
"partial_variables": {},
|
||||
"template": "Given the following question and student answer, provide a correct answer and score the student answer.\nQuestion: {question}\nStudent Answer: {student_answer}\nCorrect Answer:",
|
||||
"template_format": "f-string",
|
||||
"validate_template": true,
|
||||
"_type": "prompt"
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
# Validate template
|
||||
|
||||
By default, `PromptTemplate` will validate the `template` string by checking whether the `input_variables` match the variables defined in `template`. You can disable this behavior by setting `validate_template` to `False`.
|
||||
|
||||
```python
|
||||
template = "I am learning langchain because {reason}."
|
||||
|
||||
prompt_template = PromptTemplate(template=template,
|
||||
input_variables=["reason", "foo"]) # ValueError due to extra variables
|
||||
prompt_template = PromptTemplate(template=template,
|
||||
input_variables=["reason", "foo"],
|
||||
validate_template=False) # No error
|
||||
```
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"source": [
|
||||
"---\n",
|
||||
"sidebar_position: 0\n",
|
||||
"title: Prompt templates\n",
|
||||
"title: Quick Start\n",
|
||||
"---"
|
||||
]
|
||||
},
|
||||
@@ -16,6 +16,7 @@
|
||||
"id": "2d98412d-fc53-42c1-aed8-f1f8eb9ada58",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Quick Start\n",
|
||||
"Prompt templates are predefined recipes for generating prompts for language models.\n",
|
||||
"\n",
|
||||
"A template may include instructions, few-shot examples, and specific context and\n",
|
||||
@@ -38,7 +39,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"execution_count": 1,
|
||||
"id": "a5bc258b-87d2-486b-9785-edf5b23fd179",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -48,7 +49,7 @@
|
||||
"'Tell me a funny joke about chickens.'"
|
||||
]
|
||||
},
|
||||
"execution_count": 17,
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -72,7 +73,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"execution_count": 2,
|
||||
"id": "63bd7ac3-5cf6-4eb2-8205-d1a01029b56a",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
@@ -82,7 +83,7 @@
|
||||
"'Tell me a joke'"
|
||||
]
|
||||
},
|
||||
"execution_count": 18,
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
@@ -94,45 +95,6 @@
|
||||
"prompt_template.format()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "69f7c948-9f78-431a-a466-8038e6b6f856",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"For additional validation, specify `input_variables` explicitly. These variables\n",
|
||||
"will be compared against the variables present in the template string during instantiation, **raising an exception if\n",
|
||||
"there is a mismatch**. For example:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"id": "617d7b2c-7308-4e74-9cc9-96ee0b7a13ac",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"ename": "ValidationError",
|
||||
"evalue": "1 validation error for PromptTemplate\n__root__\n Invalid prompt schema; check for mismatched or missing input parameters. 'content' (type=value_error)",
|
||||
"output_type": "error",
|
||||
"traceback": [
|
||||
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
|
||||
"\u001b[0;31mValidationError\u001b[0m Traceback (most recent call last)",
|
||||
"Cell \u001b[0;32mIn[19], line 3\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01mlangchain\u001b[39;00m\u001b[38;5;21;01m.\u001b[39;00m\u001b[38;5;21;01mprompts\u001b[39;00m \u001b[38;5;28;01mimport\u001b[39;00m PromptTemplate\n\u001b[0;32m----> 3\u001b[0m invalid_prompt \u001b[38;5;241m=\u001b[39m \u001b[43mPromptTemplate\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 4\u001b[0m \u001b[43m \u001b[49m\u001b[43minput_variables\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43madjective\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 5\u001b[0m \u001b[43m \u001b[49m\u001b[43mtemplate\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mTell me a \u001b[39;49m\u001b[38;5;132;43;01m{adjective}\u001b[39;49;00m\u001b[38;5;124;43m joke about \u001b[39;49m\u001b[38;5;132;43;01m{content}\u001b[39;49;00m\u001b[38;5;124;43m.\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\n\u001b[1;32m 6\u001b[0m \u001b[43m)\u001b[49m\n",
|
||||
"File \u001b[0;32m~/langchain/libs/langchain/langchain/load/serializable.py:97\u001b[0m, in \u001b[0;36mSerializable.__init__\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 96\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m---> 97\u001b[0m \u001b[38;5;28;43msuper\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[38;5;21;43m__init__\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 98\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_lc_kwargs \u001b[38;5;241m=\u001b[39m kwargs\n",
|
||||
"File \u001b[0;32m~/langchain/.venv/lib/python3.9/site-packages/pydantic/main.py:341\u001b[0m, in \u001b[0;36mpydantic.main.BaseModel.__init__\u001b[0;34m()\u001b[0m\n",
|
||||
"\u001b[0;31mValidationError\u001b[0m: 1 validation error for PromptTemplate\n__root__\n Invalid prompt schema; check for mismatched or missing input parameters. 'content' (type=value_error)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from langchain.prompts import PromptTemplate\n",
|
||||
"\n",
|
||||
"invalid_prompt = PromptTemplate(\n",
|
||||
" input_variables=[\"adjective\"],\n",
|
||||
" template=\"Tell me a {adjective} joke about {content}.\",\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "2715fd80-e294-49ca-9fc2-5a012949ed8a",
|
||||
@@ -153,7 +115,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 22,
|
||||
"execution_count": 4,
|
||||
"id": "d088d53c-0e20-4fb9-9d54-b0e989b998b0",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
@@ -185,19 +147,16 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"execution_count": 6,
|
||||
"id": "f6632eda-582f-4f29-882f-108587f0397c",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"AIMessage(content='I absolutely love indulging in delicious treats!')"
|
||||
]
|
||||
},
|
||||
"execution_count": 23,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[SystemMessage(content=\"You are a helpful assistant that re-writes the user's text to sound more upbeat.\"), HumanMessage(content=\"I don't like eating tasty things\")]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
@@ -216,9 +175,8 @@
|
||||
" HumanMessagePromptTemplate.from_template(\"{text}\"),\n",
|
||||
" ]\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"llm = ChatOpenAI()\n",
|
||||
"llm(chat_template.format_messages(text=\"i dont like eating tasty things.\"))"
|
||||
"messages = chat_template.format_messages(text=\"I don't like eating tasty things\")\n",
|
||||
"print(messages)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -361,9 +319,9 @@
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "poetry-venv",
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "poetry-venv"
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
@@ -375,7 +333,7 @@
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.1"
|
||||
"version": "3.10.1"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
196
docs/docs/modules/model_io/quick_start.mdx
Normal file
196
docs/docs/modules/model_io/quick_start.mdx
Normal file
@@ -0,0 +1,196 @@
|
||||
# Quickstart
|
||||
|
||||
The quick start will cover the basics of working with language models. It will introduce the two different types of models - LLMs and ChatModels. It will then cover how to use PromptTemplates to format the inputs to these models, and how to use Output Parsers to work with the outputs. For a deeper conceptual guide into these topics - please see [this documentation](./concepts)
|
||||
|
||||
## Models
|
||||
For this getting started guide, we will provide two options: using OpenAI (a popular model available via API) or using a local open source model.
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import CodeBlock from "@theme/CodeBlock";
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="openai" label="OpenAI" default>
|
||||
|
||||
First we'll need to install their Python package:
|
||||
|
||||
```shell
|
||||
pip install openai
|
||||
```
|
||||
|
||||
Accessing the API requires an API key, which you can get by creating an account and heading [here](https://platform.openai.com/account/api-keys). Once we have a key we'll want to set it as an environment variable by running:
|
||||
|
||||
```shell
|
||||
export OPENAI_API_KEY="..."
|
||||
```
|
||||
|
||||
We can then initialize the model:
|
||||
|
||||
```python
|
||||
from langchain.chat_models import ChatOpenAI
|
||||
from langchain.llms import OpenAI
|
||||
|
||||
llm = OpenAI()
|
||||
chat_model = ChatOpenAI()
|
||||
```
|
||||
|
||||
If you'd prefer not to set an environment variable you can pass the key in directly via the `openai_api_key` named parameter when initiating the OpenAI LLM class:
|
||||
|
||||
```python
|
||||
from langchain.chat_models import ChatOpenAI
|
||||
llm = ChatOpenAI(openai_api_key="...")
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="local" label="Local">
|
||||
|
||||
[Ollama](https://ollama.ai/) allows you to run open-source large language models, such as Llama 2, locally.
|
||||
|
||||
First, follow [these instructions](https://github.com/jmorganca/ollama) to set up and run a local Ollama instance:
|
||||
|
||||
* [Download](https://ollama.ai/download)
|
||||
* Fetch a model via `ollama pull llama2`
|
||||
|
||||
Then, make sure the Ollama server is running. After that, you can do:
|
||||
```python
|
||||
from langchain.llms import Ollama
|
||||
from langchain.chat_models import ChatOllama
|
||||
|
||||
llm = Ollama(model="llama2")
|
||||
chat_model = ChatOllama()
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
Both `llm` and `chat_model` are objects that represent configuration for a particular model.
|
||||
You can initialize them with parameters like `temperature` and others, and pass them around.
|
||||
The main difference between them is their input and output schemas.
|
||||
The LLM objects take string as input and output string.
|
||||
The ChatModel objects take a list of messages as input and output a message.
|
||||
For a deeper conceptual explanation of this difference please see [this documentation](./concepts)
|
||||
|
||||
We can see the difference between an LLM and a ChatModel when we invoke it.
|
||||
|
||||
```python
|
||||
from langchain.schema import HumanMessage
|
||||
|
||||
text = "What would be a good company name for a company that makes colorful socks?"
|
||||
messages = [HumanMessage(content=text)]
|
||||
|
||||
llm.invoke(text)
|
||||
# >> Feetful of Fun
|
||||
|
||||
chat_model.invoke(messages)
|
||||
# >> AIMessage(content="Socks O'Color")
|
||||
```
|
||||
|
||||
The LLM returns a string, while the ChatModel returns a message.
|
||||
|
||||
## Prompt Templates
|
||||
|
||||
Most LLM applications do not pass user input directly into an LLM. Usually they will add the user input to a larger piece of text, called a prompt template, that provides additional context on the specific task at hand.
|
||||
|
||||
In the previous example, the text we passed to the model contained instructions to generate a company name. For our application, it would be great if the user only had to provide the description of a company/product without worrying about giving the model instructions.
|
||||
|
||||
PromptTemplates help with exactly this!
|
||||
They bundle up all the logic for going from user input into a fully formatted prompt.
|
||||
This can start off very simple - for example, a prompt to produce the above string would just be:
|
||||
|
||||
```python
|
||||
from langchain.prompts import PromptTemplate
|
||||
|
||||
prompt = PromptTemplate.from_template("What is a good name for a company that makes {product}?")
|
||||
prompt.format(product="colorful socks")
|
||||
```
|
||||
|
||||
```python
|
||||
What is a good name for a company that makes colorful socks?
|
||||
```
|
||||
|
||||
However, the advantages of using these over raw string formatting are several.
|
||||
You can "partial" out variables - e.g. you can format only some of the variables at a time.
|
||||
You can compose them together, easily combining different templates into a single prompt.
|
||||
For explanations of these functionalities, see the [section on prompts](/docs/modules/model_io/prompts) for more detail.
|
||||
|
||||
`PromptTemplate`s can also be used to produce a list of messages.
|
||||
In this case, the prompt not only contains information about the content, but also each message (its role, its position in the list, etc.).
|
||||
Here, what happens most often is a `ChatPromptTemplate` is a list of `ChatMessageTemplates`.
|
||||
Each `ChatMessageTemplate` contains instructions for how to format that `ChatMessage` - its role, and then also its content.
|
||||
Let's take a look at this below:
|
||||
|
||||
```python
|
||||
from langchain.prompts.chat import ChatPromptTemplate
|
||||
|
||||
template = "You are a helpful assistant that translates {input_language} to {output_language}."
|
||||
human_template = "{text}"
|
||||
|
||||
chat_prompt = ChatPromptTemplate.from_messages([
|
||||
("system", template),
|
||||
("human", human_template),
|
||||
])
|
||||
|
||||
chat_prompt.format_messages(input_language="English", output_language="French", text="I love programming.")
|
||||
```
|
||||
|
||||
```pycon
|
||||
[
|
||||
SystemMessage(content="You are a helpful assistant that translates English to French.", additional_kwargs={}),
|
||||
HumanMessage(content="I love programming.")
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
ChatPromptTemplates can also be constructed in other ways - see the [section on prompts](/docs/modules/model_io/prompts) for more detail.
|
||||
|
||||
## Output parsers
|
||||
|
||||
`OutputParser`s convert the raw output of a language model into a format that can be used downstream.
|
||||
There are a few main types of `OutputParser`s, including:
|
||||
|
||||
- Convert text from `LLM` into structured information (e.g. JSON)
|
||||
- Convert a `ChatMessage` into just a string
|
||||
- Convert the extra information returned from a call besides the message (like OpenAI function invocation) into a string.
|
||||
|
||||
For full information on this, see the [section on output parsers](/docs/modules/model_io/output_parsers).
|
||||
|
||||
In this getting started guide, we use a simple one that parses a list of comma separated values.
|
||||
|
||||
```python
|
||||
from langchain.output_parsers import CommaSeparatedListOutputParser
|
||||
|
||||
output_parser = CommaSeparatedListOutputParser()
|
||||
output_parser.parse("hi, bye")
|
||||
# >> ['hi', 'bye']
|
||||
```
|
||||
|
||||
## Composing with LCEL
|
||||
|
||||
We can now combine all these into one chain.
|
||||
This chain will take input variables, pass those to a prompt template to create a prompt, pass the prompt to a language model, and then pass the output through an (optional) output parser.
|
||||
This is a convenient way to bundle up a modular piece of logic.
|
||||
Let's see it in action!
|
||||
|
||||
```python
|
||||
template = "Generate a list of 5 {text}.\n\n{format_instructions}"
|
||||
|
||||
chat_prompt = ChatPromptTemplate.from_template(template)
|
||||
chat_prompt = chat_prompt.partial(format_instructions=output_parser.get_format_instructions())
|
||||
chain = chat_prompt | chat_model | output_parser
|
||||
chain.invoke({"text": "colors"})
|
||||
# >> ['red', 'blue', 'green', 'yellow', 'orange']
|
||||
```
|
||||
|
||||
Note that we are using the `|` syntax to join these components together.
|
||||
This `|` syntax is powered by the LangChain Expression Language (LCEL) and relies on the universal `Runnable` interface that all of these objects implement.
|
||||
To learn more about LCEL, read the documentation [here](/docs/expression_language).
|
||||
|
||||
## Conclusion
|
||||
|
||||
That's it for getting started with prompts, models, and output parsers! This just covered the surface of what there is to learn. For more information, check out:
|
||||
|
||||
- The [conceptual guide](./concepts) for information about the concepts presented here
|
||||
- The [prompt section](./prompts) for information on how to work with prompt templates
|
||||
- The [LLM section](./llms) for more information on the LLM interface
|
||||
- The [ChatModel section](./chat) for more information on the ChatModel interface
|
||||
- The [output parser section](./output_parsers) for information about the different types of output parsers.
|
||||
Reference in New Issue
Block a user