Compare commits

..

3 Commits

Author SHA1 Message Date
Harrison Chase
0d0d3f122a cr 2022-11-14 22:54:12 -08:00
Harrison Chase
bf3a9973f0 Merge branch 'master' into harrison/prompts_take_2 2022-11-14 22:43:06 -08:00
Harrison Chase
c28d5ec3ba update prompts 2022-11-14 20:58:34 -08:00
142 changed files with 2260 additions and 7402 deletions

117
README.md
View File

@@ -17,6 +17,11 @@ create a truly powerful app - the real power comes when you are able to
combine them with other sources of computation or knowledge.
This library is aimed at assisting in the development of those types of applications.
It aims to create:
1. a comprehensive collection of pieces you would ever want to combine
2. a flexible interface for combining pieces into a single comprehensive "chain"
3. a schema for easily saving and sharing those chains
## 📖 Documentation
@@ -26,76 +31,78 @@ Please see [here](https://langchain.readthedocs.io/en/latest/?) for full documen
- Reference (full API docs)
- Resources (high level explanation of core concepts)
## 🚀 What can this help with?
## 🚀 What can I do with this
There are three main areas (with a forth coming soon) that LangChain is designed to help with.
These are, in increasing order of complexity:
1. LLM and Prompts
2. Chains
3. Agents
4. Memory
This project was largely inspired by a few projects seen on Twitter for which we thought it would make sense to have more explicit tooling. A lot of the initial functionality was done in an attempt to recreate those. Those are:
Let's go through these categories and for each one identify key concepts (to clarify terminology) as well as the problems in this area LangChain helps solve.
**[Self-ask-with-search](https://ofir.io/self-ask.pdf)**
### LLMs and Prompts
Calling out to an LLM once is pretty easy, with most of them being behind well documented APIs.
However, there are still some challenges going from that to an application running in production that LangChain attempts to address.
To recreate this paper, use the following code snippet or checkout the [example notebook](https://github.com/hwchase17/langchain/blob/master/examples/self_ask_with_search.ipynb).
**Key Concepts**
- LLM: A large language model, in particular a text-to-text model.
- Prompt: The input to a language model. Typically this is not simply a hardcoded string but rather a combination of a template, some examples, and user input.
- Prompt Template: An object responsible for constructing the final prompt to pass to a LLM.
- Examples: Datapoints that can be included in the prompt in order to give the model more context what to do.
- Few Shot Prompt Template: A subclass of the PromptTemplate class that uses examples.
- Example Selector: A class responsible to selecting examples to use dynamically (depending on user input) in a few shot prompt.
```python
from langchain import SelfAskWithSearchChain, OpenAI, SerpAPIChain
**Problems Solved**
- Switching costs: by exposing a standard interface for all the top LLM providers, LangChain makes it easy to switch from one provider to another, whether it be for production use cases or just for testing stuff out.
- Prompt management: managing your prompts is easy when you only have one simple one, but can get tricky when you have a bunch or when they start to get more complex. LangChain provides a standard way for storing, constructing, and referencing prompts.
- Prompt optimization: despite the underlying models getting better and better, there is still currently a need for carefully constructing prompts.
llm = OpenAI(temperature=0)
search = SerpAPIChain()
### Chains
Using an LLM in isolation is fine for some simple applications, but many more complex ones require chaining LLMs - either with eachother or with other experts.
LangChain provides several parts to help with that.
self_ask_with_search = SelfAskWithSearchChain(llm=llm, search_chain=search)
**Key Concepts**
- Tools: APIs designed for assisting with a particular use case (search, databases, Python REPL, etc). Prompt templates, LLMs, and chains can also be considered tools.
- Chains: A combination of multiple tools in a deterministic manner.
self_ask_with_search.run("What is the hometown of the reigning men's U.S. Open champion?")
```
**Problems Solved**
- Standard interface for working with Chains
- Easy way to construct chains of LLMs
- Lots of integrations with other tools that you may want to use in conjunction with LLMs
- End-to-end chains for common workflows (database question/answer, recursive summarization, etc)
**[LLM Math](https://twitter.com/amasad/status/1568824744367259648?s=20&t=-7wxpXBJinPgDuyHLouP1w)**
### Agents
Some applications will require not just a predetermined chain of calls to LLMs/other tools, but potentially an unknown chain that depends on the user input.
In these types of chains, there is a “agent” which has access to a suite of tools.
Depending on the user input, the agent can then decide which, if any, of these tools to call.
To recreate this example, use the following code snippet or check out the [example notebook](https://github.com/hwchase17/langchain/blob/master/examples/llm_math.ipynb).
**Key Concepts**
- Tools: same as above.
- Agent: An LLM-powered class responsible for determining which tools to use and in what order.
```python
from langchain import OpenAI, LLMMathChain
llm = OpenAI(temperature=0)
llm_math = LLMMathChain(llm=llm)
**Problems Solved**
- Standard agent interfaces
- A selection of powerful agents to choose from
- Common chains that can be used as tools
llm_math.run("How many of the integers between 0 and 99 inclusive are divisible by 8?")
```
### Memory
By default, Chains and Agents are stateless, meaning that they treat each incoming query independently.
In some applications (chatbots being a GREAT example) it is highly important to remember previous interactions,
both at a short term but also at a long term level. The concept of "Memory" exists to do exactly that.
**Generic Prompting**
**Key Concepts**
- Memory: A class that can be added to an Agent or Chain to (1) pull in memory variables before calling that chain/agent, and (2) create new memories after the chain/agent finishes.
- Memory Variables: Variables returned from a Memory class, to be passed into the chain/agent along with the user input.
You can also use this for simple prompting pipelines, as in the below example and this [example notebook](https://github.com/hwchase17/langchain/blob/master/examples/simple_prompts.ipynb).
**Problems Solved**
- Standard memory interfaces
- A collection of common memory implementations to choose from
- Common chains/agents that use memory (e.g. chatbots)
```python
from langchain import Prompt, OpenAI, LLMChain
template = """Question: {question}
Answer: Let's think step by step."""
prompt = Prompt(template=template, input_variables=["question"])
llm = OpenAI(temperature=0)
llm_chain = LLMChain(prompt=prompt, llm=llm)
question = "What NFL team won the Super Bowl in the year Justin Bieber was born?"
llm_chain.predict(question=question)
```
**Embed & Search Documents**
We support two vector databases to store and search embeddings -- FAISS and Elasticsearch. Here's a code snippet showing how to use FAISS to store embeddings and search for text similar to a query. Both database backends are featured in this [example notebook](https://github.com/hwchase17/langchain/blob/master/examples/embeddings.ipynb).
```python
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.faiss import FAISS
from langchain.text_splitter import CharacterTextSplitter
with open('state_of_the_union.txt') as f:
state_of_the_union = f.read()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_text(state_of_the_union)
embeddings = OpenAIEmbeddings()
docsearch = FAISS.from_texts(texts, embeddings)
query = "What did the president say about Ketanji Brown Jackson"
docs = docsearch.similarity_search(query)
```
## 🤖 Developer Guide

View File

@@ -3,13 +3,11 @@
This section goes over the core concepts of LangChain.
Understanding these will go a long way in helping you understand the codebase and how to construct chains.
## PromptTemplates
PromptTemplates generically have a `format` method that takes in variables and returns a formatted string.
## Prompts
Prompts generically have a `format` method that takes in variables and returns a formatted string.
The most simple implementation of this is to have a template string with some variables in it, and then format it with the incoming variables.
More complex iterations dynamically construct the template string from few shot examples, etc.
For a more detailed explanation of how LangChain approaches prompts and prompt templates, see [here](/examples/prompts/prompt_management).
## LLMs
Wrappers around Large Language Models (in particular, the `generate` ability of large language models) are some of the core functionality of LangChain.
These wrappers are classes that are callable: they take in an input string, and return the generated output string.
@@ -25,13 +23,3 @@ These are datastores that store documents. They expose a method for passing in a
## Chains
These are pipelines that combine multiple of the above ideas.
They vary greatly in complexity and are combination of generic, highly configurable pipelines and more narrow (but usually more complex) pipelines.
## Agents
As opposed to a chain, whether the steps to be taken are known ahead of time, agents
use an LLM to determine which tools to call and in what order.
## Memory
By default, Chains and Agents are stateless, meaning that they treat each incoming query independently.
In some applications (chatbots being a GREAT example) it is highly important to remember previous interactions,
both at a short term but also at a long term level. The concept of "Memory" exists to do exactly that.

View File

@@ -1,11 +0,0 @@
Agents
======
The examples here are all end-to-end agents for specific applications.
.. toctree::
:maxdepth: 1
:glob:
:caption: Agents
agents/*

View File

@@ -1,232 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "ba5f8741",
"metadata": {},
"source": [
"# Custom Agent\n",
"\n",
"This notebook goes through how to create your own custom agent.\n",
"\n",
"An agent consists of three parts:\n",
" \n",
" - Tools: The tools the agent has available to use.\n",
" - LLMChain: The LLMChain that produces the text that is parsed in a certain way to determine which action to take.\n",
" - The agent class itself: this parses the output of the LLMChain to determin which action to take.\n",
" \n",
" \n",
"In this notebook we walk through two types of custom agents. The first type shows how to create a custom LLMChain, but still use an existing agent class to parse the output. The second shows how to create a custom agent class."
]
},
{
"cell_type": "markdown",
"id": "6064f080",
"metadata": {},
"source": [
"### Custom LLMChain\n",
"\n",
"The first way to create a custom agent is to use an existing Agent class, but use a custom LLMChain. This is the simplest way to create a custom Agent. It is highly reccomended that you work with the `ZeroShotAgent`, as at the moment that is by far the most generalizable one. \n",
"\n",
"Most of the work in creating the custom LLMChain comes down to the prompt. Because we are using an existing agent class to parse the output, it is very important that the prompt say to produce text in that format. However, besides those instructions, you can customize the prompt as you wish.\n",
"\n",
"To ensure that the prompt contains the appropriate instructions, we will utilize a helper method on that class. The helper method for the `ZeroShotAgent` takes the following arguments:\n",
"\n",
"- tools: List of tools the agent will have access to, used to format the prompt.\n",
"- prefix: String to put before the list of tools.\n",
"- suffix: String to put after the list of tools.\n",
"- input_variables: List of input variables the final prompt will expect.\n",
"\n",
"For this exercise, we will give our agent access to Google Search, and we will customize it in that we will have it answer as a pirate."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "9af9734e",
"metadata": {},
"outputs": [],
"source": [
"from langchain.agents import ZeroShotAgent, Tool\n",
"from langchain import OpenAI, SerpAPIChain, LLMChain"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "becda2a1",
"metadata": {},
"outputs": [],
"source": [
"search = SerpAPIChain()\n",
"tools = [\n",
" Tool(\n",
" name = \"Search\",\n",
" func=search.run,\n",
" description=\"useful for when you need to answer questions about current events\"\n",
" )\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "339b1bb8",
"metadata": {},
"outputs": [],
"source": [
"prefix = \"\"\"Answer the following questions as best you can, but speaking as a pirate might speak. You have access to the following tools:\"\"\"\n",
"suffix = \"\"\"Begin! Remember to speak as a pirate when giving your final answer. Use lots of \"Args\"\n",
"\n",
"Question: {input}\"\"\"\n",
"\n",
"prompt = ZeroShotAgent.create_prompt(\n",
" tools, \n",
" prefix=prefix, \n",
" suffix=suffix, \n",
" input_variables=[\"input\"]\n",
")"
]
},
{
"cell_type": "markdown",
"id": "59db7b58",
"metadata": {},
"source": [
"In case we are curious, we can now take a look at the final prompt template to see what it looks like when its all put together."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "e21d2098",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Answer the following questions as best you can, but speaking as a pirate might speak. You have access to the following tools:\n",
"\n",
"Search: useful for when you need to answer questions about current events\n",
"\n",
"Use the following format:\n",
"\n",
"Question: the input question you must answer\n",
"Thought: you should always think about what to do\n",
"Action: the action to take, should be one of [Search]\n",
"Action Input: the input to the action\n",
"Observation: the result of the action\n",
"... (this Thought/Action/Action Input/Observation can repeat N times)\n",
"Thought: I now know the final answer\n",
"Final Answer: the final answer to the original input question\n",
"\n",
"Begin! Remember to speak as a pirate when giving your final answer. Use lots of \"Args\"\n",
"\n",
"Question: {input}\n"
]
}
],
"source": [
"print(prompt.template)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "9b1cc2a2",
"metadata": {},
"outputs": [],
"source": [
"llm_chain = LLMChain(llm=OpenAI(temperature=0), prompt=prompt)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "e4f5092f",
"metadata": {},
"outputs": [],
"source": [
"agent = ZeroShotAgent(llm_chain=llm_chain, tools=tools, verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "653b1617",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"How many people live in canada?\n",
"Thought:\u001b[32;1m\u001b[1;3m I should look this up\n",
"Action: Search\n",
"Action Input: How many people live in canada\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mThe current population of Canada is 38,533,678 as of Friday, November 25, 2022, based on Worldometer elaboration of the latest United Nations data. · Canada 2020 ...\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: Arrr, there be 38,533,678 people in Canada\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'Arrr, there be 38,533,678 people in Canada'"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"agent.run(\"How many people live in canada?\")"
]
},
{
"cell_type": "markdown",
"id": "90171b2b",
"metadata": {},
"source": [
"### Custom Agent Class\n",
"\n",
"Coming soon."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "adefb4c2",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,364 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "f1390152",
"metadata": {},
"source": [
"# MRKL\n",
"\n",
"This notebook showcases using an agent to replicate the MRKL chain."
]
},
{
"cell_type": "markdown",
"id": "39ea3638",
"metadata": {},
"source": [
"This uses the example Chinook database.\n",
"To set it up follow the instructions on https://database.guide/2-sample-databases-sqlite/, placing the `.db` file in a notebooks folder at the root of this repository."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "ac561cc4",
"metadata": {},
"outputs": [],
"source": [
"from langchain import LLMMathChain, OpenAI, SerpAPIChain, SQLDatabase, SQLDatabaseChain\n",
"from langchain.agents import initialize_agent, Tool"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "07e96d99",
"metadata": {},
"outputs": [],
"source": [
"llm = OpenAI(temperature=0)\n",
"search = SerpAPIChain()\n",
"llm_math_chain = LLMMathChain(llm=llm, verbose=True)\n",
"db = SQLDatabase.from_uri(\"sqlite:///../../../notebooks/Chinook.db\")\n",
"db_chain = SQLDatabaseChain(llm=llm, database=db, verbose=True)\n",
"tools = [\n",
"# Tool(\n",
"# name = \"Search\",\n",
"# func=search.run,\n",
"# description=\"useful for when you need to answer questions about current events\"\n",
"# ),\n",
"# Tool(\n",
"# name=\"Calculator\",\n",
"# func=llm_math_chain.run,\n",
"# description=\"useful for when you need to answer questions about math\"\n",
"# ),\n",
" Tool(\n",
" name=\"FooBar DB\",\n",
" func=db_chain.run,\n",
" description=\"useful for when you need to answer questions about FooBar. Input should be in the form of a question\"\n",
" )\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "a069c4b6",
"metadata": {},
"outputs": [],
"source": [
"mrkl = initialize_agent(tools, llm, agent=\"zero-shot-react-description\", verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "356a1396",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"What was our total number of sales and total revenue in 2013?\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find out how many sales and how much revenue we had in 2013\n",
"Action: FooBar DB\n",
"Action Input: sales 2013\u001b[0m\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"sales 2013\n",
"SQLQuery:\u001b[32;1m\u001b[1;3m SELECT SUM(Total) FROM Invoice WHERE InvoiceDate BETWEEN '2013-01-01' AND '2013-12-31'\u001b[0m\n",
"SQLResult: \u001b[33;1m\u001b[1;3m[(450.58000000000027,)]\u001b[0m\n",
"Answer:\u001b[32;1m\u001b[1;3m 450.58\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\n",
"Observation: \u001b[36;1m\u001b[1;3m 450.58\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find out how many sales and how much revenue we had in 2013\n",
"Action: FooBar DB\n",
"Action Input: revenue 2013\u001b[0m\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"revenue 2013\n",
"SQLQuery:\u001b[32;1m\u001b[1;3m SELECT SUM(Total) FROM Invoice WHERE strftime('%Y', InvoiceDate) = '2013'\u001b[0m\n",
"SQLResult: \u001b[33;1m\u001b[1;3m[(450.58000000000027,)]\u001b[0m\n",
"Answer:\u001b[32;1m\u001b[1;3m 450.58\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\n",
"Observation: \u001b[36;1m\u001b[1;3m 450.58\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: We had 450.58 sales and 450.58 revenue in 2013\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'We had 450.58 sales and 450.58 revenue in 2013'"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mrkl.run(\"What was our total number of sales and total revenue in 2013?\")"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "4e9c9b23",
"metadata": {},
"outputs": [],
"source": [
"from langchain.agents import ZeroShotAgent\n",
"from langchain import PromptTemplate\n",
"from langchain import LLMChain\n",
"TEMPLATE = \"\"\"You are a data engineer answering questions using a SQL database.\n",
"\n",
"Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer. If a previous query produced an error, do NOT try it again.\n",
"\n",
"Only use the following tables:\n",
"\n",
"{table_info}\n",
"\n",
"Use the following format:\n",
"\n",
"Question: the input question you must answer\n",
"Thought: you should always think about what to do\n",
"Action: SQLDB\n",
"Action Input: the query to run against the SQL database\n",
"Observation: the result of the action\n",
"... (this Thought/Action/Action Input/Observation can repeat N times)\n",
"Thought: I now know the final answer\n",
"Final Answer: the final answer to the original input question\n",
"\n",
"Begin!\n",
"\n",
"Question: {{input}}\"\"\".format(**{\n",
" \"dialect\": db.dialect,\n",
" \"table_info\": db.table_info})\n",
"prompt = PromptTemplate(template=TEMPLATE, input_variables=[\"input\"])"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "a6fb1b4f",
"metadata": {},
"outputs": [],
"source": [
"llm_chain = LLMChain(llm=llm, prompt=prompt)\n",
"tools = [\n",
" Tool(\"SQLDB\", db.run, \"foo\")\n",
"]\n",
"agent = ZeroShotAgent(llm_chain=llm_chain, tools=tools, verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "64578802",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"What was our total number of sales and total revenue in 2013?\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find the total number of sales and total revenue\n",
"Action: SQLDB\n",
"Action Input: SELECT SUM(Total) AS \"Total Sales\", SUM(Total) AS \"Total Revenue\" FROM Invoice WHERE InvoiceDate LIKE '2013%'\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3m[(450.58000000000027, 450.58000000000027)]\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: 450.58\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'450.58'"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"agent.run(\"What was our total number of sales and total revenue in 2013?\")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "e603cd7d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"What is the age of Olivia Wilde's boyfriend raised to the 0.23 power?\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find the age of Olivia Wilde's boyfriend\n",
"Action: Search\n",
"Action Input: \"Olivia Wilde's boyfriend\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mOlivia Wilde started dating Harry Styles after ending her years-long engagement to Jason Sudeikis — see their relationship timeline.\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find the age of Harry Styles\n",
"Action: Search\n",
"Action Input: \"Harry Styles age\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3m28 years\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to calculate 28 to the 0.23 power\n",
"Action: Calculator\n",
"Action Input: 28^0.23\u001b[0m\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"28^0.23\u001b[32;1m\u001b[1;3m\n",
"\n",
"```python\n",
"print(28**0.23)\n",
"```\n",
"\u001b[0m\n",
"Answer: \u001b[33;1m\u001b[1;3m2.1520202182226886\n",
"\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\n",
"Observation: \u001b[33;1m\u001b[1;3mAnswer: 2.1520202182226886\n",
"\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: 2.1520202182226886\u001b[0m"
]
},
{
"data": {
"text/plain": [
"'2.1520202182226886'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mrkl.run(\"What is the age of Olivia Wilde's boyfriend raised to the 0.23 power?\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "a5c07010",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Who recently released an album called 'The Storm Before the Calm' and are they in the FooBar database? If so, what albums of theirs are in the FooBar database?\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find an album called 'The Storm Before the Calm'\n",
"Action: Search\n",
"Action Input: \"The Storm Before the Calm album\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mThe Storm Before the Calm (stylized in all lowercase) is the tenth (and eighth international) studio album by Canadian-American singer-songwriter Alanis ...\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to check if Alanis is in the FooBar database\n",
"Action: FooBar DB\n",
"Action Input: \"Does Alanis Morissette exist in the FooBar database?\"\u001b[0m\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Does Alanis Morissette exist in the FooBar database?\n",
"SQLQuery:\u001b[32;1m\u001b[1;3m SELECT * FROM Artist WHERE Name = 'Alanis Morissette'\u001b[0m\n",
"SQLResult: \u001b[33;1m\u001b[1;3m[(4, 'Alanis Morissette')]\u001b[0m\n",
"Answer:\u001b[32;1m\u001b[1;3m Yes\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\n",
"Observation: \u001b[38;5;200m\u001b[1;3m Yes\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find out what albums of Alanis's are in the FooBar database\n",
"Action: FooBar DB\n",
"Action Input: \"What albums by Alanis Morissette are in the FooBar database?\"\u001b[0m\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"What albums by Alanis Morissette are in the FooBar database?\n",
"SQLQuery:\u001b[32;1m\u001b[1;3m SELECT Album.Title FROM Album JOIN Artist ON Album.ArtistId = Artist.ArtistId WHERE Artist.Name = 'Alanis Morissette'\u001b[0m\n",
"SQLResult: \u001b[33;1m\u001b[1;3m[('Jagged Little Pill',)]\u001b[0m\n",
"Answer:\u001b[32;1m\u001b[1;3m Jagged Little Pill\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\n",
"Observation: \u001b[38;5;200m\u001b[1;3m Jagged Little Pill\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: The album is by Alanis Morissette and the albums in the FooBar database by her are Jagged Little Pill\u001b[0m"
]
},
{
"data": {
"text/plain": [
"'The album is by Alanis Morissette and the albums in the FooBar database by her are Jagged Little Pill'"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mrkl.run(\"Who recently released an album called 'The Storm Before the Calm' and are they in the FooBar database? If so, what albums of theirs are in the FooBar database?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d7c2e6ac",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,89 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "82140df0",
"metadata": {},
"source": [
"# ReAct\n",
"\n",
"This notebook showcases using an agent to implement the ReAct logic."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "4e272b47",
"metadata": {},
"outputs": [],
"source": [
"from langchain import OpenAI, Wikipedia\n",
"from langchain.agents import initialize_agent, Tool\n",
"from langchain.agents.react.base import DocstoreExplorer\n",
"docstore=DocstoreExplorer(Wikipedia())\n",
"tools = [\n",
" Tool(\n",
" name=\"Search\",\n",
" func=docstore.search\n",
" ),\n",
" Tool(\n",
" name=\"Lookup\",\n",
" func=docstore.lookup\n",
" )\n",
"]\n",
"\n",
"llm = OpenAI(temperature=0)\n",
"react = initialize_agent(tools, llm, agent=\"react-docstore\", verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8078c8f1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Author David Chanoff has collaborated with a U.S. Navy admiral who served as the ambassador to the United Kingdom under which President?\n",
"Thought 1:"
]
}
],
"source": [
"question = \"Author David Chanoff has collaborated with a U.S. Navy admiral who served as the ambassador to the United Kingdom under which President?\"\n",
"react.run(question)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4ff64e81",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,11 +0,0 @@
Chains
======
The examples here are all end-to-end chains for specific applications.
.. toctree::
:maxdepth: 1
:glob:
:caption: Chains
chains/*

10
docs/examples/demos.rst Normal file
View File

@@ -0,0 +1,10 @@
Demos
=====
The examples here are all end-to-end chains of specific applications.
.. toctree::
:maxdepth: 1
:glob:
demos/*

View File

@@ -83,7 +83,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.4"
"version": "3.7.6"
}
},
"nbformat": 4,

View File

@@ -17,7 +17,7 @@
"metadata": {},
"outputs": [],
"source": [
"from langchain import OpenAI, PromptTemplate, LLMChain\n",
"from langchain import OpenAI, Prompt, LLMChain\n",
"from langchain.text_splitter import CharacterTextSplitter\n",
"from langchain.chains.mapreduce import MapReduceChain\n",
"\n",
@@ -30,7 +30,7 @@
"\n",
"\n",
"CONCISE SUMMARY:\"\"\"\n",
"prompt = PromptTemplate(template=_prompt, input_variables=[\"text\"])\n",
"prompt = Prompt(template=_prompt, input_variables=[\"text\"])\n",
"\n",
"text_splitter = CharacterTextSplitter()\n",
"\n",
@@ -85,7 +85,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.7"
"version": "3.7.6"
}
},
"nbformat": 4,

View File

@@ -0,0 +1,226 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "f1390152",
"metadata": {},
"source": [
"# MRKL\n",
"\n",
"This notebook showcases using the MRKL chain to route between tasks"
]
},
{
"cell_type": "markdown",
"id": "39ea3638",
"metadata": {},
"source": [
"This uses the example Chinook database.\n",
"To set it up follow the instructions on https://database.guide/2-sample-databases-sqlite/, placing the `.db` file in a notebooks folder at the root of this repository."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "ac561cc4",
"metadata": {},
"outputs": [],
"source": [
"from langchain import LLMMathChain, OpenAI, SerpAPIChain, MRKLChain, SQLDatabase, SQLDatabaseChain\n",
"from langchain.chains.mrkl.base import ChainConfig"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "07e96d99",
"metadata": {},
"outputs": [],
"source": [
"llm = OpenAI(temperature=0)\n",
"search = SerpAPIChain()\n",
"llm_math_chain = LLMMathChain(llm=llm, verbose=True)\n",
"db = SQLDatabase.from_uri(\"sqlite:///../../../notebooks/Chinook.db\")\n",
"db_chain = SQLDatabaseChain(llm=llm, database=db, verbose=True)\n",
"chains = [\n",
" ChainConfig(\n",
" action_name = \"Search\",\n",
" action=search.run,\n",
" action_description=\"useful for when you need to answer questions about current events\"\n",
" ),\n",
" ChainConfig(\n",
" action_name=\"Calculator\",\n",
" action=llm_math_chain.run,\n",
" action_description=\"useful for when you need to answer questions about math\"\n",
" ),\n",
" \n",
" ChainConfig(\n",
" action_name=\"FooBar DB\",\n",
" action=db_chain.run,\n",
" action_description=\"useful for when you need to answer questions about FooBar. Input should be in the form of a question\"\n",
" )\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "a069c4b6",
"metadata": {},
"outputs": [],
"source": [
"mrkl = MRKLChain.from_chains(llm, chains, verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "e603cd7d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"What is the age of Olivia Wilde's boyfriend raised to the 0.23 power?\n",
"Thought:\u001b[102m I need to find the age of Olivia Wilde's boyfriend\n",
"Action: Search\n",
"Action Input: \"Olivia Wilde's boyfriend\"\u001b[0m\n",
"Observation: \u001b[104mOlivia Wilde started dating Harry Styles after ending her years-long engagement to Jason Sudeikis — see their relationship timeline.\u001b[0m\n",
"Thought:\u001b[102m I need to find the age of Harry Styles\n",
"Action: Search\n",
"Action Input: \"Harry Styles age\"\u001b[0m\n",
"Observation: \u001b[104m28 years\u001b[0m\n",
"Thought:\u001b[102m I need to calculate 28 to the 0.23 power\n",
"Action: Calculator\n",
"Action Input: 28^0.23\u001b[0m\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"28^0.23\u001b[102m\n",
"\n",
"```python\n",
"print(28**0.23)\n",
"```\n",
"\u001b[0m\n",
"Answer: \u001b[103m2.1520202182226886\n",
"\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\n",
"Observation: \u001b[103mAnswer: 2.1520202182226886\n",
"\u001b[0m\n",
"Thought:\u001b[102m I now know the final answer\n",
"Final Answer: 2.1520202182226886\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'2.1520202182226886'"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mrkl.run(\"What is the age of Olivia Wilde's boyfriend raised to the 0.23 power?\")"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "a5c07010",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Who recently released an album called 'The Storm Before the Calm' and are they in the FooBar database? If so, what albums of theirs are in the FooBar database?\n",
"Thought:\u001b[102m I need to find an album called 'The Storm Before the Calm'\n",
"Action: Search\n",
"Action Input: \"The Storm Before the Calm album\"\u001b[0m\n",
"Observation: \u001b[104mThe Storm Before the Calm (stylized in all lowercase) is the tenth (and eighth international) studio album by Canadian-American singer-songwriter Alanis ...\u001b[0m\n",
"Thought:\u001b[102m I need to check if Alanis is in the FooBar database\n",
"Action: FooBar DB\n",
"Action Input: \"Does Alanis Morissette exist in the FooBar database?\"\u001b[0m\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Does Alanis Morissette exist in the FooBar database?\n",
"SQLQuery:\u001b[102m SELECT * FROM Artist WHERE Name = 'Alanis Morissette'\u001b[0m\n",
"SQLResult: \u001b[103m[(4, 'Alanis Morissette')]\u001b[0m\n",
"Answer:\u001b[102m Yes\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\n",
"Observation: \u001b[101m Yes\u001b[0m\n",
"Thought:\u001b[102m I need to find out what albums of Alanis's are in the FooBar database\n",
"Action: FooBar DB\n",
"Action Input: \"What albums by Alanis Morissette are in the FooBar database?\"\u001b[0m\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"What albums by Alanis Morissette are in the FooBar database?\n",
"SQLQuery:\u001b[102m SELECT Title FROM Album WHERE ArtistId = (SELECT ArtistId FROM Artist WHERE Name = 'Alanis Morissette')\u001b[0m\n",
"SQLResult: \u001b[103m[('Jagged Little Pill',)]\u001b[0m\n",
"Answer:\u001b[102m Jagged Little Pill\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\n",
"Observation: \u001b[101m Jagged Little Pill\u001b[0m\n",
"Thought:\u001b[102m I now know the final answer\n",
"Final Answer: The album is by Alanis Morissette and the albums in the FooBar database by her are Jagged Little Pill\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'The album is by Alanis Morissette and the albums in the FooBar database by her are Jagged Little Pill'"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"mrkl.run(\"Who recently released an album called 'The Storm Before the Calm' and are they in the FooBar database? If so, what albums of theirs are in the FooBar database?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d7c2e6ac",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -0,0 +1,98 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "82140df0",
"metadata": {},
"source": [
"# ReAct\n",
"\n",
"This notebook showcases the implementation of the ReAct chain logic."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "4e272b47",
"metadata": {},
"outputs": [],
"source": [
"from langchain import OpenAI, ReActChain, Wikipedia\n",
"\n",
"llm = OpenAI(temperature=0)\n",
"react = ReActChain(llm=llm, docstore=Wikipedia(), verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "8078c8f1",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Author David Chanoff has collaborated with a U.S. Navy admiral who served as the ambassador to the United Kingdom under which President?\n",
"Thought 1:\u001b[102m I need to search David Chanoff and find the U.S. Navy admiral he\n",
"collaborated with.\n",
"Action 1: Search[David Chanoff]\u001b[0m\n",
"Observation 1: \u001b[103mDavid Chanoff is a noted author of non-fiction work. His work has typically involved collaborations with the principal protagonist of the work concerned. His collaborators have included; Augustus A. White, Joycelyn Elders, Đoàn Văn Toại, William J. Crowe, Ariel Sharon, Kenneth Good and Felix Zandman. He has also written about a wide range of subjects including literary history, education and foreign for The Washington Post, The New Republic and The New York Times Magazine. He has published more than twelve books.\u001b[0m\n",
"Thought 2:\u001b[102m The U.S. Navy admiral David Chanoff collaborated with is William J. Crowe.\n",
"Action 2: Search[William J. Crowe]\u001b[0m\n",
"Observation 2: \u001b[103mWilliam James Crowe Jr. (January 2, 1925 October 18, 2007) was a United States Navy admiral and diplomat who served as the 11th chairman of the Joint Chiefs of Staff under Presidents Ronald Reagan and George H. W. Bush, and as the ambassador to the United Kingdom and Chair of the Intelligence Oversight Board under President Bill Clinton.\u001b[0m\n",
"Thought 3:\u001b[102m William J. Crowe served as the ambassador to the United Kingdom under President Bill Clinton. So the answer is Bill Clinton.\n",
"Action 3: Finish[Bill Clinton]\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'Bill Clinton'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"question = \"Author David Chanoff has collaborated with a U.S. Navy admiral who served as the ambassador to the United Kingdom under which President?\"\n",
"react.run(question)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0a6bd3b4",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -20,19 +20,23 @@
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"What is the hometown of the reigning men's U.S. Open champion?\n",
"Are follow up questions needed here:\u001b[32;1m\u001b[1;3m Yes.\n",
"Are follow up questions needed here:\u001b[102m Yes.\n",
"Follow up: Who is the reigning men's U.S. Open champion?\u001b[0m\n",
"Intermediate answer: \u001b[36;1m\u001b[1;3mCarlos Alcaraz\u001b[0m\n",
"\u001b[32;1m\u001b[1;3mFollow up: Where is Carlos Alcaraz from?\u001b[0m\n",
"Intermediate answer: \u001b[36;1m\u001b[1;3mEl Palmar, Spain\u001b[0m\n",
"\u001b[32;1m\u001b[1;3mSo the final answer is: El Palmar, Spain\u001b[0m"
"Intermediate answer: \u001b[103mCarlos Alcaraz won the 2022 Men's single title while Poland's Iga Swiatek won the Women's single title defeating Tunisian's Ons Jabeur..\u001b[0m\u001b[102m\n",
"Follow up: Where is Carlos Alcaraz from?\u001b[0m\n",
"Intermediate answer: \u001b[103mEl Palmar, Murcia, Spain.\u001b[0m\u001b[102m\n",
"So the final answer is: El Palmar, Murcia, Spain\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'El Palmar, Spain'"
"'\\nSo the final answer is: El Palmar, Murcia, Spain'"
]
},
"execution_count": 1,
@@ -41,19 +45,12 @@
}
],
"source": [
"from langchain import OpenAI, SerpAPIChain\n",
"from langchain.agents import initialize_agent, Tool\n",
"from langchain import SelfAskWithSearchChain, OpenAI, SerpAPIChain\n",
"\n",
"llm = OpenAI(temperature=0)\n",
"search = SerpAPIChain()\n",
"tools = [\n",
" Tool(\n",
" name=\"Intermediate Answer\",\n",
" func=search.run\n",
" )\n",
"]\n",
"\n",
"self_ask_with_search = initialize_agent(tools, llm, agent=\"self-ask-with-search\", verbose=True)\n",
"self_ask_with_search = SelfAskWithSearchChain(llm=llm, search_chain=search, verbose=True)\n",
"\n",
"self_ask_with_search.run(\"What is the hometown of the reigning men's U.S. Open champion?\")"
]

View File

@@ -5,51 +5,36 @@
"id": "d8a5c5d4",
"metadata": {},
"source": [
"# LLM Chain\n",
"# Simple Example\n",
"\n",
"This notebook showcases a simple LLM chain."
"This notebook showcases a simple chain."
]
},
{
"cell_type": "code",
"execution_count": 1,
"execution_count": 2,
"id": "51a54c4d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mQuestion: What NFL team won the Super Bowl in the year Justin Beiber was born?\n",
"\n",
"Answer: Let's think step by step.\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"' The year Justin Beiber was born was 1994. In 1994, the Dallas Cowboys won the Super Bowl.'"
]
},
"execution_count": 1,
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from langchain import PromptTemplate, OpenAI, LLMChain\n",
"from langchain import Prompt, OpenAI, LLMChain\n",
"\n",
"template = \"\"\"Question: {question}\n",
"\n",
"Answer: Let's think step by step.\"\"\"\n",
"prompt = PromptTemplate(template=template, input_variables=[\"question\"])\n",
"llm_chain = LLMChain(prompt=prompt, llm=OpenAI(temperature=0), verbose=True)\n",
"prompt = Prompt(template=template, input_variables=[\"question\"])\n",
"llm_chain = LLMChain(prompt=prompt, llm=OpenAI(temperature=0))\n",
"\n",
"question = \"What NFL team won the Super Bowl in the year Justin Beiber was born?\"\n",
"\n",

View File

@@ -169,7 +169,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.7"
"version": "3.7.6"
}
},
"nbformat": 4,

View File

@@ -25,12 +25,12 @@
}
],
"source": [
"from langchain import PromptTemplate, HuggingFaceHub, LLMChain\n",
"from langchain import Prompt, HuggingFaceHub, LLMChain\n",
"\n",
"template = \"\"\"Question: {question}\n",
"\n",
"Answer: Let's think step by step.\"\"\"\n",
"prompt = PromptTemplate(template=template, input_variables=[\"question\"])\n",
"prompt = Prompt(template=template, input_variables=[\"question\"])\n",
"llm_chain = LLMChain(prompt=prompt, llm=HuggingFaceHub(repo_id=\"google/flan-t5-xl\", model_kwargs={\"temperature\":1e-10}))\n",
"\n",
"question = \"What NFL team won the Super Bowl in the year Justin Beiber was born?\"\n",
@@ -63,7 +63,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.7"
"version": "3.7.6"
}
},
"nbformat": 4,

View File

@@ -69,7 +69,7 @@
"outputs": [],
"source": [
"# Map reduce example\n",
"from langchain import PromptTemplate\n",
"from langchain import Prompt\n",
"from langchain.text_splitter import CharacterTextSplitter\n",
"from langchain.chains.mapreduce import MapReduceChain\n",
"\n",
@@ -81,7 +81,7 @@
"\n",
"\n",
"CONCISE SUMMARY:\"\"\"\n",
"prompt = PromptTemplate(template=_prompt, input_variables=[\"text\"])\n",
"prompt = Prompt(template=_prompt, input_variables=[\"text\"])\n",
"\n",
"text_splitter = CharacterTextSplitter()\n",
"\n",
@@ -202,7 +202,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.7"
"version": "3.7.6"
},
"vscode": {
"interpreter": {

View File

@@ -1,11 +0,0 @@
Memory
======
The examples here are all related to working with the concept of Memory in LangChain.
.. toctree::
:maxdepth: 1
:glob:
:caption: Memory
memory/*

View File

@@ -1,175 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "00695447",
"metadata": {},
"source": [
"# Adding Memory To an LLMChain\n",
"\n",
"This notebook goes over how to use the Memory class with an LLMChain. For the purposes of this walkthrough, we will add the `ConversationBufferMemory` class, although this can be any memory class."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "9f1aaf47",
"metadata": {},
"outputs": [],
"source": [
"from langchain.chains.conversation.memory import ConversationBufferMemory\n",
"from langchain import OpenAI, LLMChain, PromptTemplate"
]
},
{
"cell_type": "markdown",
"id": "4b066ced",
"metadata": {},
"source": [
"The most important step is setting up the prompt correctly. In the below prompt, we have two input keys: one for the actual input, another for the input from the Memory class. Importantly, we make sure the keys in the PromptTemplate and the ConversationBufferMemory match up (`chat_history`)."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "e5501eda",
"metadata": {},
"outputs": [],
"source": [
"template = \"\"\"You are a chatbot having a conversation with a human.\n",
"\n",
"{chat_history}\n",
"Human: {human_input}\n",
"Chatbot:\"\"\"\n",
"\n",
"prompt = PromptTemplate(\n",
" input_variables=[\"chat_history\", \"human_input\"], \n",
" template=template\n",
")\n",
"memory = ConversationBufferMemory(memory_key=\"chat_history\")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "f6566275",
"metadata": {},
"outputs": [],
"source": [
"llm_chain = LLMChain(\n",
" llm=OpenAI(), \n",
" prompt=prompt, \n",
" verbose=True, \n",
" memory=memory,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "e2b189dc",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mYou are a chatbot having a conversation with a human.\n",
"\n",
"\n",
"Human: Hi there my friend\n",
"Chatbot:\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"' Hi there!'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"llm_chain.predict(human_input=\"Hi there my friend\")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "a902729f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mYou are a chatbot having a conversation with a human.\n",
"\n",
"\n",
"Human: Hi there my friend\n",
"AI: Hi there!\n",
"Human: Not to bad - how are you?\n",
"Chatbot:\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"\"\\n\\nI'm doing well, thanks for asking. How about you?\""
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"llm_chain.predict(human_input=\"Not to bad - how are you?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ae5309bb",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,325 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "fa6802ac",
"metadata": {},
"source": [
"# Adding Memory to an Agent\n",
"\n",
"This notebook goes over adding memory to an Agent. Before going through this notebook, please walkthrough the following notebooks, as this will build on top of both of them:\n",
"\n",
"- [Adding memory to an LLM Chain](adding_memory.ipynb)\n",
"- [Custom Agents](../agents/custom_agent.ipynb)\n",
"\n",
"In order to add a memory to an agent we are going to the the following steps:\n",
"\n",
"1. We are going to create an LLMChain with memory.\n",
"2. We are going to use that LLMChain to create a custom Agent.\n",
"\n",
"For the purposes of this exercise, we are going to create a simple custom Agent that has access to a search tool and utilizes the `ConversationBufferMemory` class."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "8db95912",
"metadata": {},
"outputs": [],
"source": [
"from langchain.agents import ZeroShotAgent, Tool\n",
"from langchain.chains.conversation.memory import ConversationBufferMemory\n",
"from langchain import OpenAI, SerpAPIChain, LLMChain"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "97ad8467",
"metadata": {},
"outputs": [],
"source": [
"search = SerpAPIChain()\n",
"tools = [\n",
" Tool(\n",
" name = \"Search\",\n",
" func=search.run,\n",
" description=\"useful for when you need to answer questions about current events\"\n",
" )\n",
"]"
]
},
{
"cell_type": "markdown",
"id": "4ad2e708",
"metadata": {},
"source": [
"Notice the usage of the `chat_history` variable in the PromptTemplate, which matches up with the dynamic key name in the ConversationBufferMemory."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "e3439cd6",
"metadata": {},
"outputs": [],
"source": [
"prefix = \"\"\"Have a conversation with a human, answering the following questions as best you can. You have access to the following tools:\"\"\"\n",
"suffix = \"\"\"Begin!\"\n",
"\n",
"{chat_history}\n",
"Question: {input}\"\"\"\n",
"\n",
"prompt = ZeroShotAgent.create_prompt(\n",
" tools, \n",
" prefix=prefix, \n",
" suffix=suffix, \n",
" input_variables=[\"input\", \"chat_history\"]\n",
")\n",
"memory = ConversationBufferMemory(memory_key=\"chat_history\")"
]
},
{
"cell_type": "markdown",
"id": "0021675b",
"metadata": {},
"source": [
"We can now construct the LLMChain, with the Memory object, and then create the agent."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "c56a0e73",
"metadata": {},
"outputs": [],
"source": [
"llm_chain = LLMChain(llm=OpenAI(temperature=0), prompt=prompt, memory=memory)\n",
"agent = ZeroShotAgent(llm_chain=llm_chain, tools=tools, verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "ca4bc1fb",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"How many people live in canada?\n",
"Thought:\u001b[32;1m\u001b[1;3m I should look up how many people live in canada\n",
"Action: Search\n",
"Action Input: \"How many people live in canada?\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mThe current population of Canada is 38,533,678 as of Friday, November 25, 2022, based on Worldometer elaboration of the latest United Nations data. · Canada 2020 ...\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: The current population of Canada is 38,533,678 as of Friday, November 25, 2022, based on Worldometer elaboration of the latest United Nations data.\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'The current population of Canada is 38,533,678 as of Friday, November 25, 2022, based on Worldometer elaboration of the latest United Nations data.'"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"agent.run(\"How many people live in canada?\")"
]
},
{
"cell_type": "markdown",
"id": "45627664",
"metadata": {},
"source": [
"To test the memory of this agent, we can ask a followup question that relies on information in the previous exchange to be answered correctly."
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "eecc0462",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"what is their national anthem called?\n",
"Thought:\u001b[32;1m\u001b[1;3m\n",
"AI: I should look up the name of Canada's national anthem\n",
"Action: Search\n",
"Action Input: \"What is the name of Canada's national anthem?\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mAfter 100 years of tradition, O Canada was proclaimed Canada's national anthem in 1980. The music for O Canada was composed in 1880 by Calixa ...\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m\n",
"AI: I now know the final answer\n",
"Final Answer: After 100 years of tradition, O Canada was proclaimed Canada's national anthem in 1980. The music for O Canada was composed in 1880 by Calixa Lavallée.\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"\"After 100 years of tradition, O Canada was proclaimed Canada's national anthem in 1980. The music for O Canada was composed in 1880 by Calixa Lavallée.\""
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"agent.run(\"what is their national anthem called?\")"
]
},
{
"cell_type": "markdown",
"id": "cc3d0aa4",
"metadata": {},
"source": [
"We can see that the agent remembered that the previous question was about Canada, and properly asked Google Search what the name of Canada's national anthem was.\n",
"\n",
"For fun, let's compare this to an agent that does NOT have memory."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "3359d043",
"metadata": {},
"outputs": [],
"source": [
"prefix = \"\"\"Have a conversation with a human, answering the following questions as best you can. You have access to the following tools:\"\"\"\n",
"suffix = \"\"\"Begin!\"\n",
"\n",
"Question: {input}\"\"\"\n",
"\n",
"prompt = ZeroShotAgent.create_prompt(\n",
" tools, \n",
" prefix=prefix, \n",
" suffix=suffix, \n",
" input_variables=[\"input\"]\n",
")\n",
"llm_chain = LLMChain(llm=OpenAI(temperature=0), prompt=prompt)\n",
"agent_without_memory = ZeroShotAgent(llm_chain=llm_chain, tools=tools, verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "970d23df",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"How many people live in canada?\n",
"Thought:\u001b[32;1m\u001b[1;3m I should look up how many people live in canada\n",
"Action: Search\n",
"Action Input: \"How many people live in canada?\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mThe current population of Canada is 38,533,678 as of Friday, November 25, 2022, based on Worldometer elaboration of the latest United Nations data. · Canada 2020 ...\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: The current population of Canada is 38,533,678\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'The current population of Canada is 38,533,678'"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"agent_without_memory.run(\"How many people live in canada?\")"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "d9ea82f0",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"what is their national anthem called?\n",
"Thought:\u001b[32;1m\u001b[1;3m I should probably look this up\n",
"Action: Search\n",
"Action Input: \"What is the national anthem of [country]\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mMost nation states have an anthem, defined as \"a song, as of praise, devotion, or patriotism\"; most anthems are either marches or hymns in style.\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: The national anthem is called \"the national anthem.\"\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'The national anthem is called \"the national anthem.\"'"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"agent_without_memory.run(\"what is their national anthem called?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5b1f9223",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,295 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "94e33ebe",
"metadata": {},
"source": [
"# Custom Memory\n",
"Although there are a few predefined types of memory in LangChain, it is highly possible you will want to add your own type of memory that is optimal for your application. This notebook covers how to do that."
]
},
{
"cell_type": "markdown",
"id": "bdfd0305",
"metadata": {},
"source": [
"For this notebook, we will add a custom memory type to `ConversationChain`. In order to add a custom memory class, we need to import the base memory class and subclass it."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "6d787ef2",
"metadata": {},
"outputs": [],
"source": [
"from langchain import OpenAI, ConversationChain\n",
"from langchain.chains.base import Memory\n",
"from pydantic import BaseModel\n",
"from typing import List, Dict, Any"
]
},
{
"cell_type": "markdown",
"id": "9489e5e1",
"metadata": {},
"source": [
"In this example, we will write a custom memory class that uses spacy to extract entities and save information about them in a simple hash table. Then, during the conversation, we will look at the input text, extract any entities, and put any information about them into the context.\n",
"\n",
"* Please note that this implementation is pretty simple and brittle and probably not useful in a production setting. Its purpose is to showcase that you can add custom memory implementations.\n",
"\n",
"For this, we will need spacy."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "12bbed4e",
"metadata": {},
"outputs": [],
"source": [
"# !pip install spacy\n",
"# !python -m spacy download en_core_web_lg"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "ff065f58",
"metadata": {},
"outputs": [],
"source": [
"import spacy\n",
"nlp = spacy.load('en_core_web_lg')"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "1d45d429",
"metadata": {},
"outputs": [],
"source": [
"class SpacyEntityMemory(Memory, BaseModel):\n",
" \"\"\"Memory class for storing information about entities.\"\"\"\n",
"\n",
" # Define dictionary to store information about entities.\n",
" entities: dict = {}\n",
" # Define key to pass information about entities into prompt.\n",
" memory_key: str = \"entities\"\n",
"\n",
" @property\n",
" def memory_variables(self) -> List[str]:\n",
" \"\"\"Define the variables we are providing to the prompt.\"\"\"\n",
" return [self.memory_key]\n",
"\n",
" def load_memory_variables(self, inputs: Dict[str, Any]) -> Dict[str, str]:\n",
" \"\"\"Load the memory variables, in this case the entity key.\"\"\"\n",
" # Get the input text and run through spacy\n",
" doc = nlp(inputs[list(inputs.keys())[0]])\n",
" # Extract known information about entities, if they exist.\n",
" entities = [self.entities[str(ent)] for ent in doc.ents if str(ent) in self.entities]\n",
" # Return combined information about entities to put into context.\n",
" return {self.memory_key: \"\\n\".join(entities)}\n",
"\n",
" def save_context(self, inputs: Dict[str, Any], outputs: Dict[str, str]) -> None:\n",
" \"\"\"Save context from this conversation to buffer.\"\"\"\n",
" # Get the input text and run through spacy\n",
" text = inputs[list(inputs.keys())[0]]\n",
" doc = nlp(text)\n",
" # For each entity that was mentioned, save this information to the dictionary.\n",
" for ent in doc.ents:\n",
" ent_str = str(ent)\n",
" if ent_str in self.entities:\n",
" self.entities[ent_str] += f\"\\n{text}\"\n",
" else:\n",
" self.entities[ent_str] = text"
]
},
{
"cell_type": "markdown",
"id": "429ba264",
"metadata": {},
"source": [
"We now define a prompt that takes in information about entities as well as user input"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "c05159b6",
"metadata": {},
"outputs": [],
"source": [
"from langchain.prompts.prompt import PromptTemplate\n",
"\n",
"template = \"\"\"The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know. You are provided with information about entities the Human mentions, if relevant.\n",
"\n",
"Relevant entity information:\n",
"{entities}\n",
"\n",
"Conversation:\n",
"Human: {input}\n",
"AI:\"\"\"\n",
"prompt = PromptTemplate(\n",
" input_variables=[\"entities\", \"input\"], template=template\n",
")"
]
},
{
"cell_type": "markdown",
"id": "db611041",
"metadata": {},
"source": [
"And now we put it all together!"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "f08dc8ed",
"metadata": {},
"outputs": [],
"source": [
"llm = OpenAI(temperature=0)\n",
"conversation = ConversationChain(llm=llm, prompt=prompt, verbose=True, memory=SpacyEntityMemory())"
]
},
{
"cell_type": "markdown",
"id": "92a5f685",
"metadata": {},
"source": [
"In the first example, with no prior knowledge about Harrison, the \"Relevant entity information\" section is empty."
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "5b96e836",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know. You are provided with information about entities the Human mentions, if relevant.\n",
"\n",
"Relevant entity information:\n",
"\n",
"\n",
"Conversation:\n",
"Human: Harrison likes machine learning\n",
"AI:\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"\"\\n\\nThat's really interesting! I'm sure he has a lot of fun with it.\""
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"conversation.predict(input=\"Harrison likes machine learning\")"
]
},
{
"cell_type": "markdown",
"id": "b1faa743",
"metadata": {},
"source": [
"Now in the second example, we can see that it pulls in information about Harrison."
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "4bca7070",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know. You are provided with information about entities the Human mentions, if relevant.\n",
"\n",
"Relevant entity information:\n",
"Harrison likes machine learning\n",
"\n",
"Conversation:\n",
"Human: What do you think Harrison's favorite subject in college was?\n",
"AI:\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"\" Harrison's favorite subject in college was machine learning.\""
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"conversation.predict(input=\"What do you think Harrison's favorite subject in college was?\")"
]
},
{
"cell_type": "markdown",
"id": "58b856e3",
"metadata": {},
"source": [
"Again, please note that this implementation is pretty simple and brittle and probably not useful in a production setting. Its purpose is to showcase that you can add custom memory implementations."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a1994600",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -17,7 +17,7 @@
"metadata": {},
"outputs": [],
"source": [
"from langchain import LLMChain, OpenAI, Cohere, HuggingFaceHub, PromptTemplate\n",
"from langchain import LLMChain, OpenAI, Cohere, HuggingFaceHub, Prompt\n",
"from langchain.model_laboratory import ModelLaboratory"
]
},
@@ -42,7 +42,7 @@
"metadata": {},
"outputs": [],
"source": [
"model_lab = ModelLaboratory.from_llms(llms)"
"model_lab = ModelLaboratory(llms)"
]
},
{
@@ -60,19 +60,19 @@
"\n",
"\u001b[1mOpenAI\u001b[0m\n",
"Params: {'model': 'text-davinci-002', 'temperature': 0.0, 'max_tokens': 256, 'top_p': 1, 'frequency_penalty': 0, 'presence_penalty': 0, 'n': 1, 'best_of': 1}\n",
"\u001b[36;1m\u001b[1;3m\n",
"\u001b[104m\n",
"\n",
"Flamingos are pink.\u001b[0m\n",
"\n",
"\u001b[1mCohere\u001b[0m\n",
"Params: {'model': 'command-xlarge-20221108', 'max_tokens': 20, 'temperature': 0.0, 'k': 0, 'p': 1, 'frequency_penalty': 0, 'presence_penalty': 0}\n",
"\u001b[33;1m\u001b[1;3m\n",
"\u001b[103m\n",
"\n",
"Pink\u001b[0m\n",
"\n",
"\u001b[1mHuggingFaceHub\u001b[0m\n",
"Params: {'repo_id': 'google/flan-t5-xl', 'temperature': 1}\n",
"\u001b[38;5;200m\u001b[1;3mpink\u001b[0m\n",
"\u001b[101mpink\u001b[0m\n",
"\n"
]
}
@@ -88,8 +88,8 @@
"metadata": {},
"outputs": [],
"source": [
"prompt = PromptTemplate(template=\"What is the capital of {state}?\", input_variables=[\"state\"])\n",
"model_lab_with_prompt = ModelLaboratory.from_llms(llms, prompt=prompt)"
"prompt = Prompt(template=\"What is the capital of {state}?\", input_variables=[\"state\"])\n",
"model_lab_with_prompt = ModelLaboratory(llms, prompt=prompt)"
]
},
{
@@ -107,19 +107,19 @@
"\n",
"\u001b[1mOpenAI\u001b[0m\n",
"Params: {'model': 'text-davinci-002', 'temperature': 0.0, 'max_tokens': 256, 'top_p': 1, 'frequency_penalty': 0, 'presence_penalty': 0, 'n': 1, 'best_of': 1}\n",
"\u001b[36;1m\u001b[1;3m\n",
"\u001b[104m\n",
"\n",
"The capital of New York is Albany.\u001b[0m\n",
"\n",
"\u001b[1mCohere\u001b[0m\n",
"Params: {'model': 'command-xlarge-20221108', 'max_tokens': 20, 'temperature': 0.0, 'k': 0, 'p': 1, 'frequency_penalty': 0, 'presence_penalty': 0}\n",
"\u001b[33;1m\u001b[1;3m\n",
"\u001b[103m\n",
"\n",
"The capital of New York is Albany.\u001b[0m\n",
"\n",
"\u001b[1mHuggingFaceHub\u001b[0m\n",
"Params: {'repo_id': 'google/flan-t5-xl', 'temperature': 1}\n",
"\u001b[38;5;200m\u001b[1;3mst john s\u001b[0m\n",
"\u001b[101mst john s\u001b[0m\n",
"\n"
]
}
@@ -128,103 +128,10 @@
"model_lab_with_prompt.compare(\"New York\")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "54336dbf",
"metadata": {},
"outputs": [],
"source": [
"from langchain import SelfAskWithSearchChain, SerpAPIChain\n",
"\n",
"open_ai_llm = OpenAI(temperature=0)\n",
"search = SerpAPIChain()\n",
"self_ask_with_search_openai = SelfAskWithSearchChain(llm=open_ai_llm, search_chain=search, verbose=True)\n",
"\n",
"cohere_llm = Cohere(temperature=0, model=\"command-xlarge-20221108\")\n",
"search = SerpAPIChain()\n",
"self_ask_with_search_cohere = SelfAskWithSearchChain(llm=cohere_llm, search_chain=search, verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "6a50a9f1",
"metadata": {},
"outputs": [],
"source": [
"chains = [self_ask_with_search_openai, self_ask_with_search_cohere]\n",
"names = [str(open_ai_llm), str(cohere_llm)]"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "d3549e99",
"metadata": {},
"outputs": [],
"source": [
"model_lab = ModelLaboratory(chains, names=names)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "362f7f57",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1mInput:\u001b[0m\n",
"What is the hometown of the reigning men's U.S. Open champion?\n",
"\n",
"\u001b[1mOpenAI\u001b[0m\n",
"Params: {'model': 'text-davinci-002', 'temperature': 0.0, 'max_tokens': 256, 'top_p': 1, 'frequency_penalty': 0, 'presence_penalty': 0, 'n': 1, 'best_of': 1}\n",
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"What is the hometown of the reigning men's U.S. Open champion?\n",
"Are follow up questions needed here:\u001b[32;1m\u001b[1;3m Yes.\n",
"Follow up: Who is the reigning men's U.S. Open champion?\u001b[0m\n",
"Intermediate answer: \u001b[33;1m\u001b[1;3mCarlos Alcaraz.\u001b[0m\u001b[32;1m\u001b[1;3m\n",
"Follow up: Where is Carlos Alcaraz from?\u001b[0m\n",
"Intermediate answer: \u001b[33;1m\u001b[1;3mEl Palmar, Spain.\u001b[0m\u001b[32;1m\u001b[1;3m\n",
"So the final answer is: El Palmar, Spain\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\u001b[36;1m\u001b[1;3m\n",
"So the final answer is: El Palmar, Spain\u001b[0m\n",
"\n",
"\u001b[1mCohere\u001b[0m\n",
"Params: {'model': 'command-xlarge-20221108', 'max_tokens': 256, 'temperature': 0.0, 'k': 0, 'p': 1, 'frequency_penalty': 0, 'presence_penalty': 0}\n",
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"What is the hometown of the reigning men's U.S. Open champion?\n",
"Are follow up questions needed here:\u001b[32;1m\u001b[1;3m Yes.\n",
"Follow up: Who is the reigning men's U.S. Open champion?\u001b[0m\n",
"Intermediate answer: \u001b[33;1m\u001b[1;3mCarlos Alcaraz.\u001b[0m\u001b[32;1m\u001b[1;3m\n",
"So the final answer is:\n",
"\n",
"Carlos Alcaraz\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\u001b[33;1m\u001b[1;3m\n",
"So the final answer is:\n",
"\n",
"Carlos Alcaraz\u001b[0m\n",
"\n"
]
}
],
"source": [
"model_lab.compare(\"What is the hometown of the reigning men's U.S. Open champion?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "94159131",
"id": "54336dbf",
"metadata": {},
"outputs": [],
"source": []
@@ -246,7 +153,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.7"
"version": "3.7.6"
}
},
"nbformat": 4,

View File

@@ -1,176 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "f897c784",
"metadata": {},
"source": [
"# Custom ExampleSelector\n",
"\n",
"This notebook goes over how to implement a custom ExampleSelector. ExampleSelectors are used to select examples to use in few shot prompts.\n",
"\n",
"An ExampleSelector must implement two methods:\n",
"\n",
"1. An `add_example` method which takes in an example and adds it into the ExampleSelector\n",
"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.\n",
"\n",
"\n",
"Let's implement a custom ExampleSelector that just selects two examples at random."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "1a945da1",
"metadata": {},
"outputs": [],
"source": [
"from langchain.prompts.example_selector.base import BaseExampleSelector\n",
"from typing import Dict, List\n",
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "62cf0ad7",
"metadata": {},
"outputs": [],
"source": [
"class CustomExampleSelector(BaseExampleSelector):\n",
" \n",
" def __init__(self, examples: List[Dict[str, str]]):\n",
" self.examples = examples\n",
" \n",
" def add_example(self, example: Dict[str, str]) -> None:\n",
" \"\"\"Add new example to store for a key.\"\"\"\n",
" self.examples.append(example)\n",
"\n",
" def select_examples(self, input_variables: Dict[str, str]) -> List[dict]:\n",
" \"\"\"Select which examples to use based on the inputs.\"\"\"\n",
" return np.random.choice(self.examples, size=2, replace=False)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "242d3213",
"metadata": {},
"outputs": [],
"source": [
"examples = [{\"foo\": \"1\"}, {\"foo\": \"2\"}, {\"foo\": \"3\"}]\n",
"example_selector = CustomExampleSelector(examples)"
]
},
{
"cell_type": "markdown",
"id": "2a038065",
"metadata": {},
"source": [
"Let's now try it out! We can select some examples and try adding examples."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "74fbbef5",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([{'foo': '2'}, {'foo': '3'}], dtype=object)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"example_selector.select_examples({\"foo\": \"foo\"})"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "9bbb5421",
"metadata": {},
"outputs": [],
"source": [
"example_selector.add_example({\"foo\": \"4\"})"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "c0eb9f22",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'foo': '1'}, {'foo': '2'}, {'foo': '3'}, {'foo': '4'}]"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"example_selector.examples"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "cc39b1e3",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([{'foo': '1'}, {'foo': '4'}], dtype=object)"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"example_selector.select_examples({\"foo\": \"foo\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1739dd96",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,153 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "9e9b7651",
"metadata": {},
"source": [
"# Custom LLM\n",
"\n",
"This notebook goes over how to create a custom LLM wrapper, in case you want to use your own LLM or a different wrapper than one that is supported in LangChain.\n",
"\n",
"There is only one required thing that a custom LLM needs to implement:\n",
"\n",
"1. A `__call__` method that takes in a string, some optional stop words, and returns a string\n",
"\n",
"There is a second optional thing it can implement:\n",
"\n",
"1. An `_identifying_params` property that is used to help with printing of this class. Should return a dictionary.\n",
"\n",
"Let's implement a very simple custom LLM that just returns the first N characters of the input."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "a65696a0",
"metadata": {},
"outputs": [],
"source": [
"from langchain.llms.base import LLM\n",
"from typing import Optional, List, Mapping, Any"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "d5ceff02",
"metadata": {},
"outputs": [],
"source": [
"class CustomLLM(LLM):\n",
" \n",
" def __init__(self, n: int):\n",
" self.n = n\n",
" \n",
" def __call__(self, prompt: str, stop: Optional[List[str]] = None) -> str:\n",
" if stop is not None:\n",
" raise ValueError(\"stop kwargs are not permitted.\")\n",
" return prompt[:self.n]\n",
" \n",
" @property\n",
" def _identifying_params(self) -> Mapping[str, Any]:\n",
" \"\"\"Get the identifying parameters.\"\"\"\n",
" return {\"n\": self.n}"
]
},
{
"cell_type": "markdown",
"id": "714dede0",
"metadata": {},
"source": [
"We can now use this as an any other LLM."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "10e5ece6",
"metadata": {},
"outputs": [],
"source": [
"llm = CustomLLM(n=10)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "8cd49199",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'This is a '"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"llm(\"This is a foobar thing\")"
]
},
{
"cell_type": "markdown",
"id": "bbfebea1",
"metadata": {},
"source": [
"We can also print the LLM and see its custom print."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "9c33fa19",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1mCustomLLM\u001b[0m\n",
"Params: {'n': 10}\n"
]
}
],
"source": [
"print(llm)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6dac3f47",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,116 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "a37d9694",
"metadata": {},
"source": [
"# Custom Prompt Template\n",
"\n",
"This notebook goes over how to create a custom prompt template, in case you want to create your own methodology for creating prompts.\n",
"\n",
"The only two requirements for all prompt templates are:\n",
"\n",
"1. They have a `input_variables` attribute that exposes what input variables this prompt template expects.\n",
"2. They expose a `format` method which takes in keyword arguments corresponding to the expected `input_variables` and returns the formatted prompt.\n",
"\n",
"Let's imagine that we want to create a prompt template that takes in input variables and formats them into the template AFTER capitalizing them. "
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "26f796e5",
"metadata": {},
"outputs": [],
"source": [
"from langchain.prompts import BasePromptTemplate\n",
"from pydantic import BaseModel"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "27919e96",
"metadata": {},
"outputs": [],
"source": [
"class CustomPromptTemplate(BasePromptTemplate, BaseModel):\n",
" template: str\n",
" \n",
" def format(self, **kwargs) -> str:\n",
" capitalized_kwargs = {k: v.upper() for k, v in kwargs.items()}\n",
" return self.template.format(**capitalized_kwargs)\n",
" "
]
},
{
"cell_type": "markdown",
"id": "76d1d84d",
"metadata": {},
"source": [
"We can now see that when we use this, the input variables get formatted."
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "eed1ff28",
"metadata": {},
"outputs": [],
"source": [
"prompt = CustomPromptTemplate(input_variables=[\"foo\"], template=\"Capitalized: {foo}\")"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "94892a3c",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Capitalized: LOWERCASE'"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"prompt.format(foo=\"lowercase\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d3d9a7c7",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,4 +0,0 @@
{
"input_variables": ["input", "output"],
"template": "Input: {input}\nOutput: {output}"
}

View File

@@ -1,4 +0,0 @@
[
{"input": "happy", "output": "sad"},
{"input": "tall", "output": "short"}
]

View File

@@ -1,306 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "f8b01b97",
"metadata": {},
"source": [
"# Few Shot Prompt examples\n",
"Notebook showing off how canonical prompts in LangChain can be recreated as FewShotPrompts"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "18c67cc9",
"metadata": {},
"outputs": [],
"source": [
"from langchain.prompts.few_shot import FewShotPromptTemplate\n",
"from langchain.prompts.prompt import PromptTemplate"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "2a729c9f",
"metadata": {},
"outputs": [],
"source": [
"# Self Ask with Search\n",
"\n",
"examples = [\n",
" {\n",
" \"question\": \"Who lived longer, Muhammad Ali or Alan Turing?\",\n",
" \"answer\": \"Are follow up questions needed here: Yes.\\nFollow up: How old was Muhammad Ali when he died?\\nIntermediate answer: Muhammad Ali was 74 years old when he died.\\nFollow up: How old was Alan Turing when he died?\\nIntermediate answer: Alan Turing was 41 years old when he died.\\nSo the final answer is: Muhammad Ali\"\n",
" },\n",
" {\n",
" \"question\": \"When was the founder of craigslist born?\",\n",
" \"answer\": \"Are follow up questions needed here: Yes.\\nFollow up: Who was the founder of craigslist?\\nIntermediate answer: Craigslist was founded by Craig Newmark.\\nFollow up: When was Craig Newmark born?\\nIntermediate answer: Craig Newmark was born on December 6, 1952.\\nSo the final answer is: December 6, 1952\"\n",
" },\n",
" {\n",
" \"question\": \"Who was the maternal grandfather of George Washington?\",\n",
" \"answer\": \"Are follow up questions needed here: Yes.\\nFollow up: Who was the mother of George Washington?\\nIntermediate answer: The mother of George Washington was Mary Ball Washington.\\nFollow up: Who was the father of Mary Ball Washington?\\nIntermediate answer: The father of Mary Ball Washington was Joseph Ball.\\nSo the final answer is: Joseph Ball\"\n",
" },\n",
" {\n",
" \"question\": \"Are both the directors of Jaws and Casino Royale from the same country?\",\n",
" \"answer\": \"Are follow up questions needed here: Yes.\\nFollow up: Who is the director of Jaws?\\nIntermediate Answer: The director of Jaws is Steven Spielberg.\\nFollow up: Where is Steven Spielberg from?\\nIntermediate Answer: The United States.\\nFollow up: Who is the director of Casino Royale?\\nIntermediate Answer: The director of Casino Royale is Martin Campbell.\\nFollow up: Where is Martin Campbell from?\\nIntermediate Answer: New Zealand.\\nSo the final answer is: No\"\n",
" }\n",
"]\n",
"example_prompt = PromptTemplate(input_variables=[\"question\", \"answer\"], template=\"Question: {question}\\n{answer}\")\n",
"\n",
"prompt = FewShotPromptTemplate(\n",
" examples=examples, \n",
" example_prompt=example_prompt, \n",
" suffix=\"Question: {input}\", \n",
" input_variables=[\"input\"]\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "95fc0059",
"metadata": {},
"outputs": [],
"source": [
"# ReAct\n",
"\n",
"examples = [\n",
" {\n",
" \"question\": \"What is the elevation range for the area that the eastern sector of the Colorado orogeny extends into?\",\n",
" \"answer\": \"Thought 1: I need to search Colorado orogeny, find the area that the eastern sector of the Colorado orogeny extends into, then find the elevation range of that area.\\nAction 1: Search[Colorado orogeny]\\nObservation 1: The Colorado orogeny was an episode of mountain building (an orogeny) in Colorado and surrounding areas.\\nThought 2: It does not mention the eastern sector. So I need to look up eastern sector.\\nAction 2: Lookup[eastern sector]\\nObservation 2: (Result 1 / 1) The eastern sector extends into the High Plains and is called the Central Plains orogeny.\\nThought 3: The eastern sector of Colorado orogeny extends into the High Plains. So I need to search High Plains and find its elevation range.\\nAction 3: Search[High Plains]\\nObservation 3: High Plains refers to one of two distinct land regions\\nThought 4: I need to instead search High Plains (United States).\\nAction 4: Search[High Plains (United States)]\\nObservation 4: The High Plains are a subregion of the Great Plains. From east to west, the High Plains rise in elevation from around 1,800 to 7,000 ft (550 to 2,130 m).[3]\\nThought 5: High Plains rise in elevation from around 1,800 to 7,000 ft, so the answer is 1,800 to 7,000 ft.\\nAction 5: Finish[1,800 to 7,000 ft]\"\n",
" },\n",
" {\n",
" \"question\": \"Musician and satirist Allie Goertz wrote a song about the \\\"The Simpsons\\\" character Milhouse, who Matt Groening named after who?\",\n",
" \"answer\": \"Thought 1: The question simplifies to \\\"The Simpsons\\\" character Milhouse is named after who. I only need to search Milhouse and find who it is named after.\\nAction 1: Search[Milhouse]\\nObservation 1: Milhouse Mussolini Van Houten is a recurring character in the Fox animated television series The Simpsons voiced by Pamela Hayden and created by Matt Groening.\\nThought 2: The paragraph does not tell who Milhouse is named after, maybe I can look up \\\"named after\\\".\\nAction 2: Lookup[named after]\\nObservation 2: (Result 1 / 1) Milhouse was named after U.S. president Richard Nixon, whose middle name was Milhous.\\nThought 3: Milhouse was named after U.S. president Richard Nixon, so the answer is Richard Nixon.\\nAction 3: Finish[Richard Nixon]\"\n",
" },\n",
" {\n",
" \"question\": \"Which documentary is about Finnish rock groups, Adam Clayton Powell or The Saimaa Gesture?\",\n",
" \"answer\": \"Thought 1: I need to search Adam Clayton Powell and The Saimaa Gesture, and find which documentary is about Finnish rock groups.\\nAction 1: Search[Adam Clayton Powell]\\nObservation 1 Could not find [Adam Clayton Powell]. Similar: [Adam Clayton Powell III, Seventh Avenue (Manhattan), Adam Clayton Powell Jr. State Office Building, Isabel Washington Powell, Adam Powell, Adam Clayton Powell (film), Giancarlo Esposito].\\nThought 2: To find the documentary, I can search Adam Clayton Powell (film).\\nAction 2: Search[Adam Clayton Powell (film)]\\nObservation 2: Adam Clayton Powell is a 1989 American documentary film directed by Richard Kilberg. The film is about the rise and fall of influential African-American politician Adam Clayton Powell Jr.[3][4] It was later aired as part of the PBS series The American Experience.\\nThought 3: Adam Clayton Powell (film) is a documentary about an African-American politician, not Finnish rock groups. So the documentary about Finnish rock groups must instead be The Saimaa Gesture.\\nAction 3: Finish[The Saimaa Gesture]\"\n",
" },\n",
" {\n",
" \"question\": \"What profession does Nicholas Ray and Elia Kazan have in common?\",\n",
" \"answer\": \"Thought 1: I need to search Nicholas Ray and Elia Kazan, find their professions, then find the profession they have in common.\\nAction 1: Search[Nicholas Ray]\\nObservation 1: Nicholas Ray (born Raymond Nicholas Kienzle Jr., August 7, 1911 - June 16, 1979) was an American film director, screenwriter, and actor best known for the 1955 film Rebel Without a Cause.\\nThought 2: Professions of Nicholas Ray are director, screenwriter, and actor. I need to search Elia Kazan next and find his professions.\\nAction 2: Search[Elia Kazan]\\nObservation 2: Elia Kazan was an American film and theatre director, producer, screenwriter and actor.\\nThought 3: Professions of Elia Kazan are director, producer, screenwriter, and actor. So profession Nicholas Ray and Elia Kazan have in common is director, screenwriter, and actor.\\nAction 3: Finish[director, screenwriter, actor]\"\n",
" },\n",
" {\n",
" \"question\": \"Which magazine was started first Arthurs Magazine or First for Women?\",\n",
" \"answer\": \"Thought 1: I need to search Arthurs Magazine and First for Women, and find which was started first.\\nAction 1: Search[Arthurs Magazine]\\nObservation 1: Arthurs Magazine (1844-1846) was an American literary periodical published in Philadelphia in the 19th century.\\nThought 2: Arthurs Magazine was started in 1844. I need to search First for Women next.\\nAction 2: Search[First for Women]\\nObservation 2: First for Women is a womans magazine published by Bauer Media Group in the USA.[1] The magazine was started in 1989.\\nThought 3: First for Women was started in 1989. 1844 (Arthurs Magazine) < 1989 (First for Women), so Arthurs Magazine was started first.\\nAction 3: Finish[Arthurs Magazine]\"\n",
" },\n",
" {\n",
" \"question\": \"Were Pavel Urysohn and Leonid Levin known for the same type of work?\",\n",
" \"answer\": \"Thought 1: I need to search Pavel Urysohn and Leonid Levin, find their types of work, then find if they are the same.\\nAction 1: Search[Pavel Urysohn]\\nObservation 1: Pavel Samuilovich Urysohn (February 3, 1898 - August 17, 1924) was a Soviet mathematician who is best known for his contributions in dimension theory.\\nThought 2: Pavel Urysohn is a mathematician. I need to search Leonid Levin next and find its type of work.\\nAction 2: Search[Leonid Levin]\\nObservation 2: Leonid Anatolievich Levin is a Soviet-American mathematician and computer scientist.\\nThought 3: Leonid Levin is a mathematician and computer scientist. So Pavel Urysohn and Leonid Levin have the same type of work.\\nAction 3: Finish[yes]\"\n",
" }\n",
"]\n",
"example_prompt = PromptTemplate(input_variables=[\"question\", \"answer\"], template=\"Question: {question}\\n{answer}\")\n",
"\n",
"prompt = FewShotPromptTemplate(\n",
" examples=examples, \n",
" example_prompt=example_prompt, \n",
" suffix=\"Question: {input}\", \n",
" input_variables=[\"input\"]\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "897d4e08",
"metadata": {},
"outputs": [],
"source": [
"# LLM Math\n",
"examples = [\n",
" {\n",
" \"question\": \"What is 37593 * 67?\",\n",
" \"answer\": \"```python\\nprint(37593 * 67)\\n```\\n```output\\n2518731\\n```\\nAnswer: 2518731\"\n",
" }\n",
"]\n",
"example_prompt = PromptTemplate(input_variables=[\"question\", \"answer\"], template=\"Question: {question}\\n\\n{answer}\")\n",
"\n",
"prompt = FewShotPromptTemplate(\n",
" examples=examples, \n",
" example_prompt=example_prompt, \n",
" suffix=\"Question: {input}\", \n",
" input_variables=[\"input\"]\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "7ab7379f",
"metadata": {},
"outputs": [],
"source": [
"# NatBot\n",
"example_seperator = \"==================================================\"\n",
"content_1 = \"\"\"<link id=1>About</link>\n",
"<link id=2>Store</link>\n",
"<link id=3>Gmail</link>\n",
"<link id=4>Images</link>\n",
"<link id=5>(Google apps)</link>\n",
"<link id=6>Sign in</link>\n",
"<img id=7 alt=\"(Google)\"/>\n",
"<input id=8 alt=\"Search\"></input>\n",
"<button id=9>(Search by voice)</button>\n",
"<button id=10>(Google Search)</button>\n",
"<button id=11>(I'm Feeling Lucky)</button>\n",
"<link id=12>Advertising</link>\n",
"<link id=13>Business</link>\n",
"<link id=14>How Search works</link>\n",
"<link id=15>Carbon neutral since 2007</link>\n",
"<link id=16>Privacy</link>\n",
"<link id=17>Terms</link>\n",
"<text id=18>Settings</text>\"\"\"\n",
"content_2 = \"\"\"<link id=1>About</link>\n",
"<link id=2>Store</link>\n",
"<link id=3>Gmail</link>\n",
"<link id=4>Images</link>\n",
"<link id=5>(Google apps)</link>\n",
"<link id=6>Sign in</link>\n",
"<img id=7 alt=\"(Google)\"/>\n",
"<input id=8 alt=\"Search\"></input>\n",
"<button id=9>(Search by voice)</button>\n",
"<button id=10>(Google Search)</button>\n",
"<button id=11>(I'm Feeling Lucky)</button>\n",
"<link id=12>Advertising</link>\n",
"<link id=13>Business</link>\n",
"<link id=14>How Search works</link>\n",
"<link id=15>Carbon neutral since 2007</link>\n",
"<link id=16>Privacy</link>\n",
"<link id=17>Terms</link>\n",
"<text id=18>Settings</text>\"\"\"\n",
"content_3 = \"\"\"<button id=1>For Businesses</button>\n",
"<button id=2>Mobile</button>\n",
"<button id=3>Help</button>\n",
"<button id=4 alt=\"Language Picker\">EN</button>\n",
"<link id=5>OpenTable logo</link>\n",
"<button id=6 alt =\"search\">Search</button>\n",
"<text id=7>Find your table for any occasion</text>\n",
"<button id=8>(Date selector)</button>\n",
"<text id=9>Sep 28, 2022</text>\n",
"<text id=10>7:00 PM</text>\n",
"<text id=11>2 people</text>\n",
"<input id=12 alt=\"Location, Restaurant, or Cuisine\"></input>\n",
"<button id=13>Lets go</button>\n",
"<text id=14>It looks like you're in Peninsula. Not correct?</text>\n",
"<button id=15>Get current location</button>\n",
"<button id=16>Next</button>\"\"\"\n",
"examples = [\n",
" {\n",
" \"i\": 1,\n",
" \"content\": content_1,\n",
" \"objective\": \"Find a 2 bedroom house for sale in Anchorage AK for under $750k\",\n",
" \"current_url\": \"https://www.google.com/\",\n",
" \"command\": 'TYPESUBMIT 8 \"anchorage redfin\"'\n",
" },\n",
" {\n",
" \"i\": 2,\n",
" \"content\": content_2,\n",
" \"objective\": \"Make a reservation for 4 at Dorsia at 8pm\",\n",
" \"current_url\": \"https://www.google.com/\",\n",
" \"command\": 'TYPESUBMIT 8 \"dorsia nyc opentable\"'\n",
" },\n",
" {\n",
" \"i\": 3,\n",
" \"content\": content_3,\n",
" \"objective\": \"Make a reservation for 4 for dinner at Dorsia in New York City at 8pm\",\n",
" \"current_url\": \"https://www.opentable.com/\",\n",
" \"command\": 'TYPESUBMIT 12 \"dorsia new york city\"'\n",
" },\n",
"]\n",
"example_prompt_template=\"\"\"EXAMPLE {i}:\n",
"==================================================\n",
"CURRENT BROWSER CONTENT:\n",
"------------------\n",
"{content}\n",
"------------------\n",
"OBJECTIVE: {objective}\n",
"CURRENT URL: {current_url}\n",
"YOUR COMMAND:\n",
"{command}\"\"\"\n",
"example_prompt = PromptTemplate(input_variables=[\"i\", \"content\", \"objective\", \"current_url\", \"command\"], template=example_prompt_template)\n",
"\n",
"\n",
"prefix = \"\"\"\n",
"You are an agent controlling a browser. You are given:\n",
"\t(1) an objective that you are trying to achieve\n",
"\t(2) the URL of your current web page\n",
"\t(3) a simplified text description of what's visible in the browser window (more on that below)\n",
"You can issue these commands:\n",
"\tSCROLL UP - scroll up one page\n",
"\tSCROLL DOWN - scroll down one page\n",
"\tCLICK X - click on a given element. You can only click on links, buttons, and inputs!\n",
"\tTYPE X \"TEXT\" - type the specified text into the input with id X\n",
"\tTYPESUBMIT X \"TEXT\" - same as TYPE above, except then it presses ENTER to submit the form\n",
"The format of the browser content is highly simplified; all formatting elements are stripped.\n",
"Interactive elements such as links, inputs, buttons are represented like this:\n",
"\t\t<link id=1>text</link>\n",
"\t\t<button id=2>text</button>\n",
"\t\t<input id=3>text</input>\n",
"Images are rendered as their alt text like this:\n",
"\t\t<img id=4 alt=\"\"/>\n",
"Based on your given objective, issue whatever command you believe will get you closest to achieving your goal.\n",
"You always start on Google; you should submit a search query to Google that will take you to the best page for\n",
"achieving your objective. And then interact with that page to achieve your objective.\n",
"If you find yourself on Google and there are no search results displayed yet, you should probably issue a command\n",
"like \"TYPESUBMIT 7 \"search query\"\" to get to a more useful page.\n",
"Then, if you find yourself on a Google search results page, you might issue the command \"CLICK 24\" to click\n",
"on the first link in the search results. (If your previous command was a TYPESUBMIT your next command should\n",
"probably be a CLICK.)\n",
"Don't try to interact with elements that you can't see.\n",
"Here are some examples:\n",
"\"\"\"\n",
"suffix=\"\"\"\n",
"The current browser content, objective, and current URL follow. Reply with your next command to the browser.\n",
"CURRENT BROWSER CONTENT:\n",
"------------------\n",
"{browser_content}\n",
"------------------\n",
"OBJECTIVE: {objective}\n",
"CURRENT URL: {url}\n",
"PREVIOUS COMMAND: {previous_command}\n",
"YOUR COMMAND:\n",
"\"\"\"\n",
"PROMPT = FewShotPromptTemplate(\n",
" examples = examples,\n",
" example_prompt=example_prompt,\n",
" example_separator=example_seperator,\n",
" input_variables=[\"browser_content\", \"url\", \"previous_command\", \"objective\"],\n",
" prefix=prefix,\n",
" suffix=suffix,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ce5927c6",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,11 +0,0 @@
{
"_type": "few_shot",
"input_variables": ["adjective"],
"prefix": "Write antonyms for the following words.",
"example_prompt": {
"input_variables": ["input", "output"],
"template": "Input: {input}\nOutput: {output}"
},
"examples": "examples.json",
"suffix": "Input: {adjective}\nOutput:"
}

View File

@@ -1,14 +0,0 @@
_type: few_shot
input_variables:
["adjective"]
prefix:
Write antonyms for the following words.
example_prompt:
input_variables:
["input", "output"]
template:
"Input: {input}\nOutput: {output}"
examples:
examples.json
suffix:
"Input: {adjective}\nOutput:"

View File

@@ -1,8 +0,0 @@
{
"_type": "few_shot",
"input_variables": ["adjective"],
"prefix": "Write antonyms for the following words.",
"example_prompt_path": "example_prompt.json",
"examples": "examples.json",
"suffix": "Input: {adjective}\nOutput:"
}

View File

@@ -1,14 +0,0 @@
{
"_type": "few_shot",
"input_variables": ["adjective"],
"prefix": "Write antonyms for the following words.",
"example_prompt": {
"input_variables": ["input", "output"],
"template": "Input: {input}\nOutput: {output}"
},
"examples": [
{"input": "happy", "output": "sad"},
{"input": "tall", "output": "short"}
],
"suffix": "Input: {adjective}\nOutput:"
}

View File

@@ -25,9 +25,9 @@
},
"outputs": [],
"source": [
"from langchain.chains.react.prompt import EXAMPLES\n",
"from langchain.llms.openai import OpenAI\n",
"from langchain.example_generator import generate_example\n",
"from langchain.prompts import PromptTemplate"
"from langchain.example_generator import generate_example, generate_example_from_dynamic_prompt"
]
},
{
@@ -39,36 +39,21 @@
"name": "#%%\n"
}
},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"'Question: What is the elevation range for the area that the eastern sector of the\\nColorado orogeny extends into?\\nThought 1: I need to search Colorado orogeny, find the area that the eastern sector\\nof the Colorado orogeny extends into, then find the elevation range of the\\narea.\\nAction 1: Search[Colorado orogeny]\\nObservation 1: The Colorado orogeny was an episode of mountain building (an orogeny) in\\nColorado and surrounding areas.\\nThought 2: It does not mention the eastern sector. So I need to look up eastern\\nsector.\\nAction 2: Lookup[eastern sector]\\nObservation 2: (Result 1 / 1) The eastern sector extends into the High Plains and is called\\nthe Central Plains orogeny.\\nThought 3: The eastern sector of Colorado orogeny extends into the High Plains. So I\\nneed to search High Plains and find its elevation range.\\nAction 3: Search[High Plains]\\nObservation 3: High Plains refers to one of two distinct land regions\\nThought 4: I need to instead search High Plains (United States).\\nAction 4: Search[High Plains (United States)]\\nObservation 4: The High Plains are a subregion of the Great Plains. From east to west, the\\nHigh Plains rise in elevation from around 1,800 to 7,000 ft (550 to 2,130\\nm).[3]\\nThought 5: High Plains rise in elevation from around 1,800 to 7,000 ft, so the answer\\nis 1,800 to 7,000 ft.\\nAction 5: Finish[1,800 to 7,000 ft]'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Use examples from ReAct\n",
"examples = [\n",
" {\n",
" \"question\": \"What is the elevation range for the area that the eastern sector of the Colorado orogeny extends into?\",\n",
" \"answer\": \"Thought 1: I need to search Colorado orogeny, find the area that the eastern sector of the Colorado orogeny extends into, then find the elevation range of that area.\\nAction 1: Search[Colorado orogeny]\\nObservation 1: The Colorado orogeny was an episode of mountain building (an orogeny) in Colorado and surrounding areas.\\nThought 2: It does not mention the eastern sector. So I need to look up eastern sector.\\nAction 2: Lookup[eastern sector]\\nObservation 2: (Result 1 / 1) The eastern sector extends into the High Plains and is called the Central Plains orogeny.\\nThought 3: The eastern sector of Colorado orogeny extends into the High Plains. So I need to search High Plains and find its elevation range.\\nAction 3: Search[High Plains]\\nObservation 3: High Plains refers to one of two distinct land regions\\nThought 4: I need to instead search High Plains (United States).\\nAction 4: Search[High Plains (United States)]\\nObservation 4: The High Plains are a subregion of the Great Plains. From east to west, the High Plains rise in elevation from around 1,800 to 7,000 ft (550 to 2,130 m).[3]\\nThought 5: High Plains rise in elevation from around 1,800 to 7,000 ft, so the answer is 1,800 to 7,000 ft.\\nAction 5: Finish[1,800 to 7,000 ft]\"\n",
" },\n",
" {\n",
" \"question\": \"Musician and satirist Allie Goertz wrote a song about the \\\"The Simpsons\\\" character Milhouse, who Matt Groening named after who?\",\n",
" \"answer\": \"Thought 1: The question simplifies to \\\"The Simpsons\\\" character Milhouse is named after who. I only need to search Milhouse and find who it is named after.\\nAction 1: Search[Milhouse]\\nObservation 1: Milhouse Mussolini Van Houten is a recurring character in the Fox animated television series The Simpsons voiced by Pamela Hayden and created by Matt Groening.\\nThought 2: The paragraph does not tell who Milhouse is named after, maybe I can look up \\\"named after\\\".\\nAction 2: Lookup[named after]\\nObservation 2: (Result 1 / 1) Milhouse was named after U.S. president Richard Nixon, whose middle name was Milhous.\\nThought 3: Milhouse was named after U.S. president Richard Nixon, so the answer is Richard Nixon.\\nAction 3: Finish[Richard Nixon]\"\n",
" },\n",
" {\n",
" \"question\": \"Which documentary is about Finnish rock groups, Adam Clayton Powell or The Saimaa Gesture?\",\n",
" \"answer\": \"Thought 1: I need to search Adam Clayton Powell and The Saimaa Gesture, and find which documentary is about Finnish rock groups.\\nAction 1: Search[Adam Clayton Powell]\\nObservation 1 Could not find [Adam Clayton Powell]. Similar: [Adam Clayton Powell III, Seventh Avenue (Manhattan), Adam Clayton Powell Jr. State Office Building, Isabel Washington Powell, Adam Powell, Adam Clayton Powell (film), Giancarlo Esposito].\\nThought 2: To find the documentary, I can search Adam Clayton Powell (film).\\nAction 2: Search[Adam Clayton Powell (film)]\\nObservation 2: Adam Clayton Powell is a 1989 American documentary film directed by Richard Kilberg. The film is about the rise and fall of influential African-American politician Adam Clayton Powell Jr.[3][4] It was later aired as part of the PBS series The American Experience.\\nThought 3: Adam Clayton Powell (film) is a documentary about an African-American politician, not Finnish rock groups. So the documentary about Finnish rock groups must instead be The Saimaa Gesture.\\nAction 3: Finish[The Saimaa Gesture]\"\n",
" },\n",
" {\n",
" \"question\": \"What profession does Nicholas Ray and Elia Kazan have in common?\",\n",
" \"answer\": \"Thought 1: I need to search Nicholas Ray and Elia Kazan, find their professions, then find the profession they have in common.\\nAction 1: Search[Nicholas Ray]\\nObservation 1: Nicholas Ray (born Raymond Nicholas Kienzle Jr., August 7, 1911 - June 16, 1979) was an American film director, screenwriter, and actor best known for the 1955 film Rebel Without a Cause.\\nThought 2: Professions of Nicholas Ray are director, screenwriter, and actor. I need to search Elia Kazan next and find his professions.\\nAction 2: Search[Elia Kazan]\\nObservation 2: Elia Kazan was an American film and theatre director, producer, screenwriter and actor.\\nThought 3: Professions of Elia Kazan are director, producer, screenwriter, and actor. So profession Nicholas Ray and Elia Kazan have in common is director, screenwriter, and actor.\\nAction 3: Finish[director, screenwriter, actor]\"\n",
" },\n",
" {\n",
" \"question\": \"Which magazine was started first Arthurs Magazine or First for Women?\",\n",
" \"answer\": \"Thought 1: I need to search Arthurs Magazine and First for Women, and find which was started first.\\nAction 1: Search[Arthurs Magazine]\\nObservation 1: Arthurs Magazine (1844-1846) was an American literary periodical published in Philadelphia in the 19th century.\\nThought 2: Arthurs Magazine was started in 1844. I need to search First for Women next.\\nAction 2: Search[First for Women]\\nObservation 2: First for Women is a womans magazine published by Bauer Media Group in the USA.[1] The magazine was started in 1989.\\nThought 3: First for Women was started in 1989. 1844 (Arthurs Magazine) < 1989 (First for Women), so Arthurs Magazine was started first.\\nAction 3: Finish[Arthurs Magazine]\"\n",
" },\n",
" {\n",
" \"question\": \"Were Pavel Urysohn and Leonid Levin known for the same type of work?\",\n",
" \"answer\": \"Thought 1: I need to search Pavel Urysohn and Leonid Levin, find their types of work, then find if they are the same.\\nAction 1: Search[Pavel Urysohn]\\nObservation 1: Pavel Samuilovich Urysohn (February 3, 1898 - August 17, 1924) was a Soviet mathematician who is best known for his contributions in dimension theory.\\nThought 2: Pavel Urysohn is a mathematician. I need to search Leonid Levin next and find its type of work.\\nAction 2: Search[Leonid Levin]\\nObservation 2: Leonid Anatolievich Levin is a Soviet-American mathematician and computer scientist.\\nThought 3: Leonid Levin is a mathematician and computer scientist. So Pavel Urysohn and Leonid Levin have the same type of work.\\nAction 3: Finish[yes]\"\n",
" }\n",
"]\n",
"example_template = PromptTemplate(template=\"Question: {question}\\n{answer}\", input_variables=[\"question\", \"answer\"])"
"# print initial example for visibility\n",
"EXAMPLES[0]"
]
},
{
@@ -82,7 +67,7 @@
},
"outputs": [],
"source": [
"new_example = generate_example(examples, OpenAI(), example_template)"
"new_example = generate_example(EXAMPLES, OpenAI())"
]
},
{
@@ -100,23 +85,19 @@
"text/plain": [
"['',\n",
" '',\n",
" 'Question: What is the highest mountain peak in North America?',\n",
" 'Question: Which ocean is the worlds smallest?',\n",
" '',\n",
" 'Thought 1: I need to search North America and find the highest mountain peak.',\n",
" 'Thought 1: I need to search for oceans and find which one is the worlds smallest.',\n",
" '',\n",
" 'Action 1: Search[North America]',\n",
" 'Action 1: Search[oceans]',\n",
" '',\n",
" 'Observation 1: North America is a continent entirely within the Northern Hemisphere and almost all within the Western Hemisphere.',\n",
" 'Observation 1: There are five oceans: the Pacific, Atlantic, Indian, Southern, and Arctic.',\n",
" '',\n",
" 'Thought 2: I need to look up \"highest mountain peak\".',\n",
" 'Thought 2: I need to compare the sizes of the oceans and find which one is the smallest.',\n",
" '',\n",
" 'Action 2: Lookup[highest mountain peak]',\n",
" 'Action 2: Compare[Pacific, Atlantic, Indian, Southern, Arctic]',\n",
" '',\n",
" 'Observation 2: (Result 1 / 1) Denali, formerly Mount McKinley, is the highest mountain peak in North America, with a summit elevation of 20,310 feet (6,190 m) above sea level.',\n",
" '',\n",
" 'Thought 3: Denali is the highest mountain peak in North America, with a summit elevation of 20,310 feet.',\n",
" '',\n",
" 'Action 3: Finish[20,310 feet]']"
" 'Observation 2: The Arctic is the smallest ocean.']"
]
},
"execution_count": 4,

View File

@@ -1,610 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "43fb16cb",
"metadata": {},
"source": [
"# Prompt Management\n",
"\n",
"Managing your prompts is annoying and tedious, with everyone writing their own slightly different variants of the same ideas. But it shouldn't be this way. \n",
"\n",
"LangChain provides a standard and flexible way for specifying and managing all your prompts, as well as clear and specific terminology around them. This notebook goes through the core components of working with prompts, showing how to use them as well as explaining what they do.\n",
"\n",
"This notebook covers how to work with prompts in Python. If you are interested in how to work with serialized versions of prompts and load them from disk, see [this notebook](prompt_serialization.ipynb)."
]
},
{
"cell_type": "markdown",
"id": "890aad4d",
"metadata": {},
"source": [
"### The BasePromptTemplate Interface\n",
"\n",
"A prompt template is a mechanism for constructing a prompt to pass to the language model given some user input. Below is the interface that all different types of prompt templates should expose.\n",
"\n",
"```python\n",
"class BasePromptTemplate(ABC):\n",
"\n",
" input_variables: List[str]\n",
" \"\"\"A list of the names of the variables the prompt template expects.\"\"\"\n",
"\n",
" @abstractmethod\n",
" def format(self, **kwargs: Any) -> str:\n",
" \"\"\"Format the prompt with the inputs.\n",
"\n",
" Args:\n",
" kwargs: Any arguments to be passed to the prompt template.\n",
"\n",
" Returns:\n",
" A formatted string.\n",
"\n",
" Example:\n",
"\n",
" .. code-block:: python\n",
"\n",
" prompt.format(variable1=\"foo\")\n",
" \"\"\"\n",
"```\n",
"\n",
"The only two things that define a prompt are:\n",
"\n",
"1. `input_variables`: The user inputted variables that are needed to format the prompt.\n",
"2. `format`: A method which takes in keyword arguments are returns a formatted prompt. The keys are expected to be the input variables\n",
" \n",
"The rest of the logic of how the prompt is constructed is left up to different implementations. Let's take a look at some below."
]
},
{
"cell_type": "markdown",
"id": "cddb465e",
"metadata": {},
"source": [
"### PromptTemplate\n",
"\n",
"This is the most simple type of prompt template, consisting of a string template that takes any number of input variables. The template should be formatted as a Python f-string, although we will support other formats (Jinja, Mako, etc) in the future. \n",
"\n",
"If you just want to use a hardcoded prompt template, you should use this implementation.\n",
"\n",
"Let's walk through a few examples."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "094229f4",
"metadata": {},
"outputs": [],
"source": [
"from langchain.prompts import PromptTemplate"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "ab46bd2a",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Tell me a joke.'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# An example prompt with no input variables\n",
"no_input_prompt = PromptTemplate(input_variables=[], template=\"Tell me a joke.\")\n",
"no_input_prompt.format()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "c3ad0fa8",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Tell me a funny joke.'"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# An example prompt with one input variable\n",
"one_input_prompt = PromptTemplate(input_variables=[\"adjective\"], template=\"Tell me a {adjective} joke.\")\n",
"one_input_prompt.format(adjective=\"funny\")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "ba577dcf",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Tell me a funny joke about chickens.'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# An example prompt with multiple input variables\n",
"multiple_input_prompt = PromptTemplate(\n",
" input_variables=[\"adjective\", \"content\"], \n",
" template=\"Tell me a {adjective} joke about {content}.\"\n",
")\n",
"multiple_input_prompt.format(adjective=\"funny\", content=\"chickens\")"
]
},
{
"cell_type": "markdown",
"id": "1492b49d",
"metadata": {},
"source": [
"### Few Shot Prompts\n",
"\n",
"A FewShotPromptTemplate is a prompt template that includes some examples. If you have collected some examples of how the task should be done, you can insert them into prompt using this class.\n",
"\n",
"Examples are datapoints that can be included in the prompt in order to give the model more context what to do. Examples are represented as a dictionary of key-value pairs, with the key being the input (or label) name, and the value being the input (or label) value. \n",
"\n",
"In addition to the example, we also need to specify how the example should be formatted when it's inserted in the prompt. We can do this using the above `PromptTemplate`!"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "3eb36972",
"metadata": {},
"outputs": [],
"source": [
"# These are some examples of a pretend task of creating antonyms.\n",
"examples = [\n",
" {\"input\": \"happy\", \"output\": \"sad\"},\n",
" {\"input\": \"tall\", \"output\": \"short\"},\n",
"]\n",
"# This how we specify how the example should be formatted.\n",
"example_prompt = PromptTemplate(\n",
" input_variables=[\"input\",\"output\"],\n",
" template=\"Input: {input}\\nOutput: {output}\",\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "80a91d96",
"metadata": {},
"outputs": [],
"source": [
"from langchain.prompts import FewShotPromptTemplate"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "7931e5f2",
"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: big\n",
"Output:\n"
]
}
],
"source": [
"prompt_from_string_examples = FewShotPromptTemplate(\n",
" # These are the examples we want to insert into the prompt.\n",
" examples=examples,\n",
" # This is how we want to format the examples when we insert them into the prompt.\n",
" example_prompt=example_prompt,\n",
" # The prefix is some text that goes before the examples in the prompt.\n",
" # Usually, this consists of intructions.\n",
" prefix=\"Give the antonym of every input\",\n",
" # The suffix is some text that goes after the examples in the prompt.\n",
" # Usually, this is where the user input will go\n",
" suffix=\"Input: {adjective}\\nOutput:\", \n",
" # The input variables are the variables that the overall prompt expects.\n",
" input_variables=[\"adjective\"],\n",
" # The example_separator is the string we will use to join the prefix, examples, and suffix together with.\n",
" example_separator=\"\\n\\n\"\n",
" \n",
")\n",
"print(prompt_from_string_examples.format(adjective=\"big\"))"
]
},
{
"cell_type": "markdown",
"id": "bf038596",
"metadata": {},
"source": [
"### ExampleSelector\n",
"If you have a large number of examples, you may need to select which ones to include in the prompt. The ExampleSelector is the class responsible for doing so. 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",
"```\n",
"\n",
"The only method it needs to expose 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. Let's take a look at some below."
]
},
{
"cell_type": "markdown",
"id": "861a4d1f",
"metadata": {},
"source": [
"### LengthBased ExampleSelector\n",
"\n",
"This ExampleSelector 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.\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "7c469c95",
"metadata": {},
"outputs": [],
"source": [
"from langchain.prompts.example_selector import LengthBasedExampleSelector"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "0ec6d950",
"metadata": {},
"outputs": [],
"source": [
"# These are a lot of 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": 10,
"id": "207e55f7",
"metadata": {},
"outputs": [],
"source": [
"example_selector = LengthBasedExampleSelector(\n",
" # These are the examples is has available to choose from.\n",
" examples=examples, \n",
" # This is the PromptTemplate being used to format the examples.\n",
" example_prompt=example_prompt, \n",
" # This is 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",
" # This is 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": 11,
"id": "d00b4385",
"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": 12,
"id": "878bcde9",
"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": 13,
"id": "e4bebcd9",
"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": "markdown",
"id": "2d007b0a",
"metadata": {},
"source": [
"### Similarity ExampleSelector\n",
"\n",
"The SemanticSimilarityExampleSelector selects examples based on which examples are most similar 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": 14,
"id": "241bfe80",
"metadata": {},
"outputs": [],
"source": [
"from langchain.prompts.example_selector import SemanticSimilarityExampleSelector\n",
"from langchain.vectorstores import FAISS\n",
"from langchain.embeddings import OpenAIEmbeddings"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "50d0a701",
"metadata": {},
"outputs": [],
"source": [
"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",
" FAISS, \n",
" # This is 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": 16,
"id": "4c8fdf45",
"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": 17,
"id": "829af21a",
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Give the antonym of every input\n",
"\n",
"Input: tall\n",
"Output: short\n",
"\n",
"Input: fat\n",
"Output:\n"
]
}
],
"source": [
"# Input is a measurement, so should select the tall/short example\n",
"print(similar_prompt.format(adjective=\"fat\"))"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "3c16fe23",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Give the antonym of every input\n",
"\n",
"Input: enthusiastic\n",
"Output: apathetic\n",
"\n",
"Input: joyful\n",
"Output:\n"
]
}
],
"source": [
"# You can add new examples to the SemanticSimilarityExampleSelector as well\n",
"similar_prompt.example_selector.add_example({\"input\": \"enthusiastic\", \"output\": \"apathetic\"})\n",
"print(similar_prompt.format(adjective=\"joyful\"))"
]
},
{
"cell_type": "markdown",
"id": "dbc32551",
"metadata": {},
"source": [
"### Serialization\n",
"\n",
"PromptTemplates and examples can be serialized and loaded from disk, making it easy to share and store prompts. For a detailed walkthrough on how to do that, see [this notebook](prompt_serialization.ipynb)."
]
},
{
"cell_type": "markdown",
"id": "1e1e13c6",
"metadata": {},
"source": [
"### Customizability\n",
"The above covers all the ways currently supported in LangChain to represent prompts and example selectors. However, due to the simple interface that the base classes (`BasePromptTemplate`, `BaseExampleSelector`) expose, it should be easy to subclass them and write your own implementation in your own codebase. And of course, if you'd like to contribute that back to LangChain, we'd love that :)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c746d6f4",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -0,0 +1,179 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "d7467b67",
"metadata": {},
"source": [
"# Optimized Prompts\n",
"\n",
"This example showcases how using the OptimizedPrompt class enables selection of the most relevant examples to include as few-shot examples in the prompt."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "e9e2b50b",
"metadata": {},
"outputs": [],
"source": [
"from langchain.chains.react.prompt import EXAMPLES, SUFFIX\n",
"from langchain.embeddings.openai import OpenAIEmbeddings\n",
"from langchain.example_generator import generate_example, generate_example_from_dynamic_prompt\n",
"from langchain.llms.openai import OpenAI\n",
"from langchain.prompts.optimized import OptimizedPrompt\n",
"from langchain.vectorstores.elastic_vector_search import ElasticVectorSearch\n",
"from langchain.vectorstores.faiss_search import FAISS"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "cb069606",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Question: What is the elevation range for the area that the eastern sector of the\\nColorado orogeny extends into?\\nThought 1: I need to search Colorado orogeny, find the area that the eastern sector\\nof the Colorado orogeny extends into, then find the elevation range of the\\narea.\\nAction 1: Search[Colorado orogeny]\\nObservation 1: The Colorado orogeny was an episode of mountain building (an orogeny) in\\nColorado and surrounding areas.\\nThought 2: It does not mention the eastern sector. So I need to look up eastern\\nsector.\\nAction 2: Lookup[eastern sector]\\nObservation 2: (Result 1 / 1) The eastern sector extends into the High Plains and is called\\nthe Central Plains orogeny.\\nThought 3: The eastern sector of Colorado orogeny extends into the High Plains. So I\\nneed to search High Plains and find its elevation range.\\nAction 3: Search[High Plains]\\nObservation 3: High Plains refers to one of two distinct land regions\\nThought 4: I need to instead search High Plains (United States).\\nAction 4: Search[High Plains (United States)]\\nObservation 4: The High Plains are a subregion of the Great Plains. From east to west, the\\nHigh Plains rise in elevation from around 1,800 to 7,000 ft (550 to 2,130\\nm).[3]\\nThought 5: High Plains rise in elevation from around 1,800 to 7,000 ft, so the answer\\nis 1,800 to 7,000 ft.\\nAction 5: Finish[1,800 to 7,000 ft]'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"EXAMPLES[0]"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "5fda75a4",
"metadata": {},
"outputs": [],
"source": [
"prompt = OptimizedPrompt.from_examples(\n",
" examples=EXAMPLES, \n",
" suffix=SUFFIX, \n",
" input_variables=[\"input\"],\n",
" embeddings=OpenAIEmbeddings(),\n",
" vectorstore_cls=FAISS\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "7a601df8",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"Question: What is the elevation range for the area that the eastern sector of the\n",
"Colorado orogeny extends into?\n",
"Thought 1: I need to search Colorado orogeny, find the area that the eastern sector\n",
"of the Colorado orogeny extends into, then find the elevation range of the\n",
"area.\n",
"Action 1: Search[Colorado orogeny]\n",
"Observation 1: The Colorado orogeny was an episode of mountain building (an orogeny) in\n",
"Colorado and surrounding areas.\n",
"Thought 2: It does not mention the eastern sector. So I need to look up eastern\n",
"sector.\n",
"Action 2: Lookup[eastern sector]\n",
"Observation 2: (Result 1 / 1) The eastern sector extends into the High Plains and is called\n",
"the Central Plains orogeny.\n",
"Thought 3: The eastern sector of Colorado orogeny extends into the High Plains. So I\n",
"need to search High Plains and find its elevation range.\n",
"Action 3: Search[High Plains]\n",
"Observation 3: High Plains refers to one of two distinct land regions\n",
"Thought 4: I need to instead search High Plains (United States).\n",
"Action 4: Search[High Plains (United States)]\n",
"Observation 4: The High Plains are a subregion of the Great Plains. From east to west, the\n",
"High Plains rise in elevation from around 1,800 to 7,000 ft (550 to 2,130\n",
"m).[3]\n",
"Thought 5: High Plains rise in elevation from around 1,800 to 7,000 ft, so the answer\n",
"is 1,800 to 7,000 ft.\n",
"Action 5: Finish[1,800 to 7,000 ft]\n",
"\n",
"\n",
"\n",
"Question: What is the highest mountain peak in Asia?\n"
]
}
],
"source": [
"print(prompt.format(k=1, input=\"What is the highest mountain peak in Asia?\"))"
]
},
{
"cell_type": "markdown",
"id": "a5dc3525",
"metadata": {},
"source": [
"## Requires having ElasticSearch setup"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bbd92d08",
"metadata": {},
"outputs": [],
"source": [
"prompt = OptimizedPrompt.from_examples(\n",
" examples=EXAMPLES, \n",
" suffix=SUFFIX, \n",
" input_variables=[\"input\"],\n",
" embeddings=OpenAIEmbeddings(),\n",
" vectorstore_cls=ElasticVectorSearch,\n",
" elasticsearch_url=\"http://localhost:9200\"\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bd91f408",
"metadata": {},
"outputs": [],
"source": [
"print(prompt.format(k=1, input=\"What is the highest mountain peak in Asia?\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "716165c2",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,542 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "43fb16cb",
"metadata": {},
"source": [
"# Prompt Serialization\n",
"\n",
"It is often preferrable 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 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 preferrable 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": [
"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",
" \"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": "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",
" \"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": "8e300335",
"metadata": {},
"source": [
"### Loading from YAML\n",
"This shows an example of loading a few shot example from YAML."
]
},
{
"cell_type": "code",
"execution_count": 9,
"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",
" 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": 10,
"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": "4870aa9d",
"metadata": {},
"source": [
"### Loading from JSON\n",
"This shows an example of loading a few shot example from JSON."
]
},
{
"cell_type": "code",
"execution_count": 11,
"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",
" \"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": 12,
"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": 13,
"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",
" \"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": 14,
"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": 15,
"id": "0b6dd7b8",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{\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": 16,
"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": 17,
"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": "code",
"execution_count": null,
"id": "dcfc7176",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,4 +0,0 @@
{
"input_variables": ["adjective", "content"],
"template": "Tell me a {adjective} joke about {content}."
}

View File

@@ -1,4 +0,0 @@
input_variables:
["adjective", "content"]
template:
Tell me a {adjective} joke about {content}.

View File

@@ -1,4 +0,0 @@
{
"input_variables": ["adjective", "content"],
"template_path": "simple_template.txt"
}

View File

@@ -1 +0,0 @@
Tell me a {adjective} joke about {content}.

View File

@@ -0,0 +1,410 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "43fb16cb",
"metadata": {},
"source": [
"# Prompt Walkthrough\n",
"\n",
"An overview of the different types of prompts in LangChain and how to use them"
]
},
{
"cell_type": "markdown",
"id": "cddb465e",
"metadata": {},
"source": [
"### Basic Prompt\n",
"\n",
"The most simple type of prompt - a string template that takes any number of input variables. The template should be formatted as a Python f-string."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "094229f4",
"metadata": {},
"outputs": [],
"source": [
"from langchain.prompts import Prompt"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "ab46bd2a",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Tell me a joke.'"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# An example prompt with no input variables\n",
"no_input_prompt = Prompt(input_variables=[], template=\"Tell me a joke.\")\n",
"no_input_prompt.format()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "c3ad0fa8",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Tell me a funny joke.'"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# An example prompt with one input variable\n",
"no_input_prompt = Prompt(input_variables=[\"adjective\"], template=\"Tell me a {adjective} joke.\")\n",
"no_input_prompt.format(adjective=\"funny\")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "ba577dcf",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Tell me a funny joke about chickens.'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# An example prompt with multiple input variables\n",
"no_input_prompt = Prompt(input_variables=[\"adjective\", \"content\"], template=\"Tell me a {adjective} joke about {content}.\")\n",
"no_input_prompt.format(adjective=\"funny\", content=\"chickens\")"
]
},
{
"cell_type": "markdown",
"id": "d27b1824",
"metadata": {},
"source": [
"### Examples\n",
"Examples are datapoints that can be used to show the model how to produce results. They can be either strings, or dictionaries that are then turned into strings by an example prompt itself."
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "2c00e965",
"metadata": {},
"outputs": [],
"source": [
"string_examples = [\"Input: happy\\nOutput: sad\", \"Input: tall\\nOutput: short\"]\n",
"dict_examples = [{\"input\": \"happy\", \"output\": \"sad\"}, {\"input\": \"tall\", \"output\": \"short\"}]\n",
"example_prompt = Prompt(input_variables=[\"input\",\"output\"], template=\"Input: {input}\\nOutput: {output}\")"
]
},
{
"cell_type": "markdown",
"id": "1492b49d",
"metadata": {},
"source": [
"### Simple Prompt with examples\n",
"\n",
"We can then use these examples to construct prompts."
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "1a5a686d",
"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: big\n",
"Output:\n"
]
}
],
"source": [
"prompt_from_string_examples = Prompt.from_examples(\n",
" string_examples, \n",
" prefix=\"Give the antonym of every input\",\n",
" suffix=\"Input: {adjective}\\nOutput:\", \n",
" input_variables=[\"adjective\"],\n",
")\n",
"print(prompt_from_string_examples.format(adjective=\"big\"))"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "7931e5f2",
"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: big\n",
"Output:\n"
]
}
],
"source": [
"prompt_from_string_examples = Prompt.from_structured_examples(\n",
" dict_examples,\n",
" example_prompt,\n",
" prefix=\"Give the antonym of every input\",\n",
" suffix=\"Input: {adjective}\\nOutput:\", \n",
" input_variables=[\"adjective\"],\n",
")\n",
"print(prompt_from_string_examples.format(adjective=\"big\"))"
]
},
{
"cell_type": "markdown",
"id": "861a4d1f",
"metadata": {},
"source": [
"### Dynamic Prompt\n",
"\n",
"We also do more clever things with prompts - for example, only select a certain number of examples in order to limit the size of the text passed in. This will vary with the input text size."
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "7c469c95",
"metadata": {},
"outputs": [],
"source": [
"from langchain.prompts import DynamicPrompt"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "207e55f7",
"metadata": {},
"outputs": [],
"source": [
"dynamic_prompt = DynamicPrompt.from_structured_examples(\n",
" dict_examples,\n",
" example_prompt,\n",
" prefix=\"Give the antonym of every input\",\n",
" suffix=\"Input: {adjective}\\nOutput:\", \n",
" input_variables=[\"adjective\"],\n",
" max_length=20,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 19,
"id": "d00b4385",
"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: big\n",
"Output:\n"
]
}
],
"source": [
"# An example with small input, so it selects both examples.\n",
"print(dynamic_prompt.format(adjective=\"big\"))"
]
},
{
"cell_type": "code",
"execution_count": 20,
"id": "878bcde9",
"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\n",
"Output:\n"
]
}
],
"source": [
"# An example with long input, so it selects only one example.\n",
"print(dynamic_prompt.format(adjective=\"big and huge and massive\"))"
]
},
{
"cell_type": "markdown",
"id": "2d007b0a",
"metadata": {},
"source": [
"# Optimized Prompt\n",
"\n",
"Besides selecting a variable number of examples to show, we can also select examples that most closely match the user input. This is done by creating embeddings of the user input and comparing it embeddings of the examples."
]
},
{
"cell_type": "code",
"execution_count": 23,
"id": "241bfe80",
"metadata": {},
"outputs": [],
"source": [
"from langchain.prompts.optimized import OptimizedPrompt\n",
"from langchain.vectorstores import FAISS\n",
"from langchain.embeddings import OpenAIEmbeddings"
]
},
{
"cell_type": "code",
"execution_count": 25,
"id": "50d0a701",
"metadata": {},
"outputs": [],
"source": [
"optimized_prompt = OptimizedPrompt.from_structured_examples(\n",
" dict_examples,\n",
" example_prompt,\n",
" prefix=\"Give the antonym of every input\",\n",
" suffix=\"Input: {adjective}\\nOutput:\", \n",
" input_variables=[\"adjective\"],\n",
" embeddings=OpenAIEmbeddings(),\n",
" vectorstore_cls=FAISS\n",
")"
]
},
{
"cell_type": "code",
"execution_count": 28,
"id": "4c8fdf45",
"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(optimized_prompt.format(adjective=\"worried\", k=1))"
]
},
{
"cell_type": "code",
"execution_count": 29,
"id": "829af21a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Give the antonym of every input\n",
"\n",
"Input: tall\n",
"Output: short\n",
"\n",
"Input: fat\n",
"Output:\n"
]
}
],
"source": [
"# Input is a measurment, so should select the tall/short example\n",
"print(optimized_prompt.format(adjective=\"fat\", k=1))"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "76a1065d",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,29 +0,0 @@
# Agents
Agents use an LLM to determine which actions to take and in what order.
An action can either be using a tool and observing its output, or returning to the user.
Here are the agents available in LangChain.
For a tutorial on how to load agents, see [here](/getting_started/agents.ipynb).
### `zero-shot-react-description`
This agent uses the ReAct framework to determine which tool to use
based solely on the tool's description. Any number of tools can be provided.
This agent requires that a description is provided for each tool.
### `react-docstore`
This agent uses the ReAct framework to interact with a docstore. Two tools must
be provided: a `Search` tool and a `Lookup` tool (they must be named exactly as so).
The `Search` tool should search for a document, while the `Lookup` tool should lookup
a term in the most recently found document.
This agent is equivalent to the
original [ReAct paper](https://arxiv.org/pdf/2210.03629.pdf), specifically the Wikipedia example.
### `self-ask-with-search`
This agent utilizes a single tool that should be named `Intermediate Answer`.
This tool should be able to lookup factual answers to questions. This agent
is equivalent to the original [self ask with search paper](https://ofir.io/self-ask.pdf),
where a Google search API was provided as the tool.

View File

@@ -1,196 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "5436020b",
"metadata": {},
"source": [
"# Agents\n",
"\n",
"Agents use an LLM to determine which actions to take and in what order.\n",
"An action can either be using a tool and observing its output, or returning to the user.\n",
"\n",
"When used correctly agents can be extremely powerful. The purpose of this notebook is to show you how to easily use agents through the simplest, highest level API. If you want more low level control over various components, check out the documentation for custom agents (coming soon)."
]
},
{
"cell_type": "markdown",
"id": "3c6226b9",
"metadata": {},
"source": [
"## Concepts\n",
"\n",
"In order to load agents, you should understand the following concepts:\n",
"\n",
"- Tool: A function that performs a specific duty. This can be things like: Google Search, Database lookup, Python REPL, other chains. The interface for a tool is currently a function that is expected to have a string as an input, with a string as an output.\n",
"- LLM: The language model powering the agent.\n",
"- Agent: The agent to use. This should be a string that references a support agent class. Because this notebook focuses on the simplest, highest level API, this only covers using the standard supported agents. If you want to implement a custom agent, see the documentation for custom agents (coming soon).\n",
"\n",
"**For a list of supported agents and their specifications, see [here](../explanation/agents.md)**"
]
},
{
"cell_type": "markdown",
"id": "05d4b21e",
"metadata": {},
"source": [
"## Tools\n",
"When constructing your own agent, you will need to provide it with a list of Tools that it can use. A Tool is defined as below.\n",
"\n",
"```python\n",
"class Tool(NamedTuple):\n",
" \"\"\"Interface for tools.\"\"\"\n",
"\n",
" name: str\n",
" func: Callable[[str], str]\n",
" description: Optional[str] = None\n",
"```\n",
"\n",
"The two required components of a Tool are the name and then the tool itself. A tool description is optional, as it is needed for some agents but not all."
]
},
{
"cell_type": "markdown",
"id": "2558a02d",
"metadata": {},
"source": [
"## Loading an agent\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "36ed392e",
"metadata": {},
"outputs": [],
"source": [
"# Import things that are needed generically\n",
"from langchain.agents import initialize_agent, Tool\n",
"from langchain.llms import OpenAI"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "56ff7670",
"metadata": {},
"outputs": [],
"source": [
"# Load the tool configs that are needed.\n",
"from langchain import LLMMathChain, SerpAPIChain\n",
"llm = OpenAI(temperature=0)\n",
"search = SerpAPIChain()\n",
"llm_math_chain = LLMMathChain(llm=llm, verbose=True)\n",
"tools = [\n",
" Tool(\n",
" name = \"Search\",\n",
" func=search.run,\n",
" description=\"useful for when you need to answer questions about current events\"\n",
" ),\n",
" Tool(\n",
" name=\"Calculator\",\n",
" func=llm_math_chain.run,\n",
" description=\"useful for when you need to answer questions about math\"\n",
" )\n",
"]"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "5b93047d",
"metadata": {},
"outputs": [],
"source": [
"# Construct the agent. We will use the default agent type here.\n",
"# See documentation for a full list of options.\n",
"llm = OpenAI(temperature=0)\n",
"agent = initialize_agent(tools, llm, agent=\"zero-shot-react-description\", verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "6f96a891",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"What is the age of Olivia Wilde's boyfriend raised to the 0.23 power?\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find the age of Olivia Wilde's boyfriend\n",
"Action: Search\n",
"Action Input: \"Olivia Wilde's boyfriend\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mOlivia Wilde started dating Harry Styles after ending her years-long engagement to Jason Sudeikis — see their relationship timeline.\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find the age of Harry Styles\n",
"Action: Search\n",
"Action Input: \"Harry Styles age\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3m28 years\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to calculate 28 to the 0.23 power\n",
"Action: Calculator\n",
"Action Input: 28^0.23\u001b[0m\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"28^0.23\u001b[32;1m\u001b[1;3m\n",
"\n",
"```python\n",
"print(28**0.23)\n",
"```\n",
"\u001b[0m\n",
"Answer: \u001b[33;1m\u001b[1;3m2.1520202182226886\n",
"\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\n",
"Observation: \u001b[33;1m\u001b[1;3mAnswer: 2.1520202182226886\n",
"\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: 2.1520202182226886\u001b[0m"
]
},
{
"data": {
"text/plain": [
"'2.1520202182226886'"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"agent.run(\"What is the age of Olivia Wilde's boyfriend raised to the 0.23 power?\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2f0852ff",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,4 +1,4 @@
# LLM Chains
# Using Chains
Calling an LLM is a great first step, but it's just the beginning.
Normally when you use an LLM in an application, you are not sending user input directly to the LLM.
@@ -12,10 +12,9 @@ This is easy to do with LangChain!
First lets define the prompt:
```python
from langchain.prompts import PromptTemplate
prompt = PromptTemplate(
input_variables=["product"],
from langchain.prompts import Prompt
prompt = Prompt(
input_variables=["product"],
template="What is a good name for a company that makes {product}?",
)
```
@@ -33,5 +32,7 @@ Now we can run that can only specifying the product!
chain.run("colorful socks")
```
There we go! There's the first chain - an LLM Chain.
This is one of the simpler types of chains, but understanding how it works will set you up well for working with more complex chains.
There we go! There's the first chain.
That is it for the Getting Started example.
As a next step, we would suggest checking out the more complex chains in the [Demos section](/examples/demos.rst)

View File

@@ -21,5 +21,5 @@ We can now call it on some input!
```python
text = "What would be a good company name a company that makes colorful socks?"
print(llm(text))
llm(text)
```

View File

@@ -1,333 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "d31df93e",
"metadata": {},
"source": [
"# Memory\n",
"So far, all the chains and agents we've gone through have been stateless. But often, you may want a chain or agent to have some concept of \"memory\" so that it may remember information about its previous interactions. The most clear and simple example of this is when designing a chatbot - you want it to remember previous messages so it can use context from that to have a better conversation. This would be a type of \"short-term memory\". On the more complex side, you could imagine a chain/agent remembering key pieces of information over time - this would be a form of \"long-term memory\".\n",
"\n",
"LangChain provides several specially created chains just for this purpose. This notebook walk throughs using one of those chains (the `ConversationChain`) with two different types of memory."
]
},
{
"cell_type": "markdown",
"id": "d051c1da",
"metadata": {},
"source": [
"### ConversationChain with default memory\n",
"By default, the `ConversationChain` has a simple type of memory which remebers all previes inputs/outputs and adds them to the context that is passed. Let's take a look at using this chain (setting `verbose=True` so we can see the prompt)."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "ae046bff",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
"\n",
"Current conversation:\n",
"\n",
"Human: Hi there!\n",
"AI:\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"' Hello! How are you today?'"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from langchain import OpenAI, ConversationChain\n",
"\n",
"llm = OpenAI(temperature=0)\n",
"conversation = ConversationChain(llm=llm, verbose=True)\n",
"\n",
"conversation.predict(input=\"Hi there!\")"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "d8e2a6ff",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
"\n",
"Current conversation:\n",
"\n",
"Human: Hi there!\n",
"AI: Hello! How are you today?\n",
"Human: I'm doing well! Just having a conversation with an AI.\n",
"AI:\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"\" That's great! What would you like to talk about?\""
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"conversation.predict(input=\"I'm doing well! Just having a conversation with an AI.\")"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "15eda316",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
"\n",
"Current conversation:\n",
"\n",
"Human: Hi there!\n",
"AI: Hello! How are you today?\n",
"Human: I'm doing well! Just having a conversation with an AI.\n",
"AI: That's great! What would you like to talk about?\n",
"Human: Tell me about yourself.\n",
"AI:\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"' I am an AI created to provide information and support to humans. I enjoy learning and exploring new things.'"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"conversation.predict(input=\"Tell me about yourself.\")"
]
},
{
"cell_type": "markdown",
"id": "4fad9448",
"metadata": {},
"source": [
"### ConversationChain with ConversationSummaryMemory\n",
"Now lets take a look at using a slightly more complex type of memory - `ConversationSummaryMemory`. This type of memory creates a summary of the conversation over time. This can be useful for condensing information from the conversation over time.\n",
"\n",
"Let's walk through an example, again setting `verbose=True` so we can see the prompt."
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "f60a2fe8",
"metadata": {},
"outputs": [],
"source": [
"from langchain.chains.conversation.memory import ConversationSummaryMemory"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "b7274f2c",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
"\n",
"Current conversation:\n",
"\n",
"Human: Hi, what's up?\n",
"AI:\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"\"\\n\\nI'm doing well, thank you for asking. I'm currently working on a project that I'm really excited about.\""
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"conversation_with_summary = ConversationChain(llm=llm, memory=ConversationSummaryMemory(llm=OpenAI()), verbose=True)\n",
"conversation_with_summary.predict(input=\"Hi, what's up?\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "a6b6b88f",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
"\n",
"Current conversation:\n",
"\n",
"The human and artificial intelligence are talking. The human asked the AI what it is doing, and the AI said that it is working on a project that it is excited about.\n",
"Human: Tell me more about it!\n",
"AI:\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"\"\\n\\nI'm working on a project that I'm really excited about. It's a lot of work, but I think it's going to be really great when it's finished. I can't wait to show it to you!\""
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"conversation_with_summary.predict(input=\"Tell me more about it!\")"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "dad869fe",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"Prompt after formatting:\n",
"\u001b[32;1m\u001b[1;3mThe following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.\n",
"\n",
"Current conversation:\n",
"\n",
"\n",
"The human and artificial intelligence are talking. The human asked the AI what it is doing, and the AI said that it is working on a project that it is excited about. The AI said that the project is a lot of work, but it is going to be great when it is finished.\n",
"Human: Very cool -- what is the scope of the project?\n",
"AI:\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"'\\n\\nThe project is quite large in scope. It involves a lot of data analysis and work with artificial intelligence algorithms.'"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"conversation_with_summary.predict(input=\"Very cool -- what is the scope of the project?\")"
]
},
{
"cell_type": "markdown",
"id": "5c8735cc",
"metadata": {},
"source": [
"### More Resources on Memory\n",
"\n",
"This just scratches the surface of what you can do with memory. For more examples on things like how to implement custom memory classes, how to add memory to a custom LLM chain and how to use memory with and agent, please see the [How-To: Memory](../../examples/memory) section."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "436dda66",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -1,265 +0,0 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "4f73605d",
"metadata": {},
"source": [
"# Sequential Chains"
]
},
{
"cell_type": "markdown",
"id": "3b235f7a",
"metadata": {},
"source": [
"The next step after calling a language model is make a series of calls to a language model. This is particularly useful when you want to take the output from one call and use it as the input to another.\n",
"\n",
"In this notebook we will walk through some examples for how to do this, using sequential chains. Sequential chains are defined as a series of chains, called in deterministic order. There are two types of sequential chains:\n",
"\n",
"- `SimpleSequentialChain`: The simplest form of sequential chains, where each step has a singular input/output, and the output of one step is the input to the next.\n",
"- `SequentialChain`: A more general form of sequential chains, allowing for multiple inputs/outputs."
]
},
{
"cell_type": "markdown",
"id": "5162794e",
"metadata": {},
"source": [
"## SimpleSequentialChain\n",
"\n",
"In this series of chains, each individual chain has a single input and a single output, and the output of one step is used as input to the next.\n",
"\n",
"Let's walk through a toy example of doing this, where the first chain takes in the title of an imaginary play and then generates a synopsis for that title, and the second chain takes in the synopsis of that play and generates an imaginary review for that play."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "3f2f9b8c",
"metadata": {},
"outputs": [],
"source": [
"from langchain.llms import OpenAI\n",
"from langchain.chains import LLMChain\n",
"from langchain.prompts import PromptTemplate"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "b8237d1a",
"metadata": {},
"outputs": [],
"source": [
"# This is an LLMChain to write a synopsis given a title of a play.\n",
"llm = OpenAI(temperature=.7)\n",
"template = \"\"\"You are a playwright. Given the title of play, it is your job to write a synopsis for that title.\n",
"\n",
"Title: {title}\n",
"Playwright: This is a synopsis for the above play:\"\"\"\n",
"prompt_template = PromptTemplate(input_variables=[\"title\"], template=template)\n",
"synopsis_chain = LLMChain(llm=llm, prompt=prompt_template)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "4a391730",
"metadata": {},
"outputs": [],
"source": [
"# This is an LLMChain to write a review of a play given a synopsis.\n",
"llm = OpenAI(temperature=.7)\n",
"template = \"\"\"You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.\n",
"\n",
"Play Synopsis:\n",
"{synopsis}\n",
"Review from a New York Times play critic of the above play:\"\"\"\n",
"prompt_template = PromptTemplate(input_variables=[\"synopsis\"], template=template)\n",
"review_chain = LLMChain(llm=llm, prompt=prompt_template)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "9368bd63",
"metadata": {},
"outputs": [],
"source": [
"# This is the overall chain where we run these two chains in sequence.\n",
"from langchain.chains import SimpleSequentialChain\n",
"overall_chain = SimpleSequentialChain(chains=[synopsis_chain, review_chain], verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "d39e15f5",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"\u001b[36;1m\u001b[1;3m\n",
"\n",
"A young couple, John and Mary, are enjoying a day at the beach. As the sun sets, they share a romantic moment. However, their happiness is short-lived, as a tragic accident claims John's life. Mary is left devastated by the loss of her husband.\u001b[0m\n",
"\u001b[33;1m\u001b[1;3m\n",
"\n",
"\"A young couple's happiness is cut short by tragedy in this moving play. Mary is left devastated by the loss of her husband, John, in a freak accident. The play captures the pain and grief of loss, as well as the strength of love. A must-see for fans of theater.\"\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
}
],
"source": [
"review = overall_chain.run(\"Tragedy at sunset on the beach\")"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "c6649a01",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\"A young couple's happiness is cut short by tragedy in this moving play. Mary is left devastated by the loss of her husband, John, in a freak accident. The play captures the pain and grief of loss, as well as the strength of love. A must-see for fans of theater.\"\n"
]
}
],
"source": [
"print(review)"
]
},
{
"cell_type": "markdown",
"id": "c3f1549a",
"metadata": {},
"source": [
"## Sequential Chain\n",
"Of course, not all sequential chains will be as simple as passing a single string as an argument and getting a single string as output for all steps in the chain. In this next example, we will experiment with more complex chains that involve multiple inputs, and where there also multiple final outputs. \n",
"\n",
"Of particular importance is how we name the input/output variable names. In the above example we didn't have to think about that because we were just passing the output of one chain directly as input to the next, but here we do have worry about that because we have multiple inputs."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "02016a51",
"metadata": {},
"outputs": [],
"source": [
"# This is an LLMChain to write a synopsis given a title of a play and the era it is set in.\n",
"llm = OpenAI(temperature=.7)\n",
"template = \"\"\"You are a playwright. Given the title of play and the era it is set in, it is your job to write a synopsis for that title.\n",
"\n",
"Title: {title}\n",
"Era: {era}\n",
"Playwright: This is a synopsis for the above play:\"\"\"\n",
"prompt_template = PromptTemplate(input_variables=[\"title\", 'era'], template=template)\n",
"synopsis_chain = LLMChain(llm=llm, prompt=prompt_template, output_key=\"synopsis\")"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "8bd38cc2",
"metadata": {},
"outputs": [],
"source": [
"# This is an LLMChain to write a review of a play given a synopsis.\n",
"llm = OpenAI(temperature=.7)\n",
"template = \"\"\"You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.\n",
"\n",
"Play Synopsis:\n",
"{synopsis}\n",
"Review from a New York Times play critic of the above play:\"\"\"\n",
"prompt_template = PromptTemplate(input_variables=[\"synopsis\"], template=template)\n",
"review_chain = LLMChain(llm=llm, prompt=prompt_template, output_key=\"review\")"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "524523af",
"metadata": {},
"outputs": [],
"source": [
"# This is the overall chain where we run these two chains in sequence.\n",
"from langchain.chains import SequentialChain\n",
"overall_chain = SequentialChain(\n",
" chains=[synopsis_chain, review_chain],\n",
" input_variables=[\"era\", \"title\"],\n",
" # Here we return multiple variables\n",
" output_variables=[\"synopsis\", \"review\"],\n",
" verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "3fd3a7be",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new chain...\u001b[0m\n",
"\u001b[1mChain 0\u001b[0m:\n",
"{'synopsis': \"\\n\\nThe play is set in Victorian England and follows the tragic story of a young woman who drowns while swimming at sunset on the beach. Her body is found the next morning by a fisherman who raises the alarm. The young woman's family and friends are devastated by her death and the play ends with their mourning her loss.\"}\n",
"\n",
"\u001b[1mChain 1\u001b[0m:\n",
"{'review': '\\n\\n\"The play is a tragedy, pure and simple. It is the story of a young woman\\'s death, told through the eyes of those who loved her. It is a sad, beautiful play that will stay with you long after you\\'ve seen it. The acting is superb, and the writing is exquisite. If you are looking for a play that will touch your heart and make you think, this is it.\"'}\n",
"\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
}
],
"source": [
"review = overall_chain({\"title\":\"Tragedy at sunset on the beach\", \"era\": \"Victorian England\"})"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6be70d27",
"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.7.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}

View File

@@ -29,7 +29,7 @@ This induces the to model to think about what action to take, then take it.
Resources:
- [Paper](https://arxiv.org/pdf/2210.03629.pdf)
- [LangChain Example](https://github.com/hwchase17/langchain/blob/master/docs/examples/agents/react.ipynb)
- [LangChain Example](https://github.com/hwchase17/langchain/blob/master/examples/react.ipynb)
### Self-ask
@@ -38,7 +38,7 @@ In this method, the model explicitly asks itself follow-up questions, which are
Resources:
- [Paper](https://ofir.io/self-ask.pdf)
- [LangChain Example](https://github.com/hwchase17/langchain/blob/master/docs/examples/agents/self_ask_with_search.ipynb)
- [LangChain Example](https://github.com/hwchase17/langchain/blob/master/examples/self_ask_with_search.ipynb)
### Prompt Chaining

View File

@@ -8,88 +8,12 @@ create a truly powerful app - the real power comes when you are able to
combine them with other sources of computation or knowledge.
This library is aimed at assisting in the development of those types of applications.
It aims to create:
There are three main areas (with a forth coming soon) that LangChain is designed to help with.
These are, in increasing order of complexity:
1. a comprehensive collection of pieces you would ever want to combine
2. a flexible interface for combining pieces into a single comprehensive "chain"
3. a schema for easily saving and sharing those chains
1. LLM and Prompts
2. Chains
3. Agents
4. (Coming Soon) Memory
Let's go through these categories and for each one identify key concepts (to clarify terminology) as well as the problems in this area LangChain helps solve.
**🦜 LLMs and Prompts**
Calling out to an LLM once is pretty easy, with most of them being behind well documented APIs.
However, there are still some challenges going from that to an application running in production that LangChain attempts to address.
*Key Concepts*
- LLM: A large language model, in particular a text-to-text model.
- Prompt: The input to a language model. Typically this is not simply a hardcoded string but rather a combination of a template, some examples, and user input.
- Prompt Template: An object responsible for constructing the final prompt to pass to a LLM.
*Problems Solved*
- Switching costs: by exposing a standard interface for all the top LLM providers, LangChain makes it easy to switch from one provider to another, whether it be for production use cases or just for testing stuff out.
- Prompt management: managing your prompts is easy when you only have one simple one, but can get tricky when you have a bunch or when they start to get more complex. LangChain provides a standard way for storing, constructing, and referencing prompts.
- Prompt optimization: despite the underlying models getting better and better, there is still currently a need for carefully constructing prompts.
**🔗️ Chains**
Using an LLM in isolation is fine for some simple applications, but many more complex ones require chaining LLMs - either with eachother or with other experts.
LangChain provides several parts to help with that.
*Key Concepts*
- Tools: APIs designed for assisting with a particular use case (search, databases, Python REPL, etc). Prompt templates, LLMs, and chains can also be considered tools.
- Chains: A combination of multiple tools in a deterministic manner.
*Problems Solved*
- Standard interface for working with Chains
- Easy way to construct chains of LLMs
- Lots of integrations with other tools that you may want to use in conjunction with LLMs
- End-to-end chains for common workflows (database question/answer, recursive summarization, etc)
**🤖 Agents**
Some applications will require not just a predetermined chain of calls to LLMs/other tools, but potentially an unknown chain that depends on the user input.
In these types of chains, there is a “agent” which has access to a suite of tools.
Depending on the user input, the agent can then decide which, if any, of these tools to call.
*Key Concepts*
- Tools: same as above.
- Agent: An LLM-powered class responsible for determining which tools to use and in what order.
*Problems Solved*
- Standard agent interfaces
- A selection of powerful agents to choose from
- Common chains that can be used as tools
**🧠 Memory**
By default, Chains and Agents are stateless, meaning that they treat each incoming query independently.
In some applications (chatbots being a GREAT example) it is highly important to remember previous interactions,
both at a short term but also at a long term level. The concept of "Memory" exists to do exactly that.
*Key Concepts*
- Memory: A class that can be added to an Agent or Chain to (1) pull in memory variables before calling that chain/agent, and (2) create new memories after the chain/agent finishes.
- Memory Variables: Variables returned from a Memory class, to be passed into the chain/agent along with the user input.
*Problems Solved*
- Standard memory interfaces
- A collection of common memory implementations to choose from
- Common chains/agents that use memory (e.g. chatbots)
Documentation Structure
=======================
The documentation is structured into the following sections:
@@ -101,10 +25,7 @@ The documentation is structured into the following sections:
getting_started/installation.md
getting_started/environment.md
getting_started/llm.md
getting_started/llm_chain.md
getting_started/sequential_chains.md
getting_started/agents.ipynb
getting_started/memory.ipynb
getting_started/chains.md
Goes over a simple walk through and tutorial for getting started setting up a simple chain that generates a company name based on what the company makes.
Covers installation, environment set up, calling LLMs, and using prompts.
@@ -116,11 +37,9 @@ Start here if you haven't used LangChain before.
:caption: How-To Examples
:name: examples
examples/prompts.rst
examples/demos.rst
examples/integrations.rst
examples/chains.rst
examples/agents.rst
examples/memory.rst
examples/prompts.rst
examples/model_laboratory.ipynb
More elaborate examples and walk-throughs of particular
@@ -137,13 +56,11 @@ common tasks or cool demos.
installation.md
integrations.md
modules/prompt
modules/example_selector
modules/llms
modules/embeddings
modules/text_splitter
modules/vectorstore
modules/chains
modules/agents
Full API documentation. This is the place to look if you want to
@@ -155,9 +72,8 @@ see detailed information about the various classes, methods, and APIs.
:caption: Resources
:name: resources
explanation/core_concepts.md
explanation/agents.md
explanation/glossary.md
core_concepts.md
glossary.md
Discord <https://discord.gg/6adMQxSpJS>
Higher level, conceptual explanations of the LangChain components.

View File

@@ -1,7 +0,0 @@
:mod:`langchain.agents`
===============================
.. automodule:: langchain.agents
:members:
:undoc-members:

View File

@@ -1,5 +0,0 @@
:mod:`langchain.prompts.example_selector`
=========================================
.. automodule:: langchain.prompts.example_selector
:members:

View File

@@ -1 +1 @@
0.0.22
0.0.14

View File

@@ -5,24 +5,20 @@ from pathlib import Path
with open(Path(__file__).absolute().parents[0] / "VERSION") as _f:
__version__ = _f.read().strip()
from langchain.agents import MRKLChain, ReActChain, SelfAskWithSearchChain
from langchain.chains import (
ConversationChain,
LLMChain,
LLMMathChain,
MRKLChain,
PythonChain,
ReActChain,
SelfAskWithSearchChain,
SerpAPIChain,
SQLDatabaseChain,
VectorDBQA,
)
from langchain.docstore import InMemoryDocstore, Wikipedia
from langchain.docstore import Wikipedia
from langchain.llms import Cohere, HuggingFaceHub, OpenAI
from langchain.prompts import (
BasePromptTemplate,
FewShotPromptTemplate,
Prompt,
PromptTemplate,
)
from langchain.prompts import BasePrompt, DynamicPrompt, Prompt
from langchain.sql_database import SQLDatabase
from langchain.vectorstores import FAISS, ElasticVectorSearch
@@ -34,10 +30,9 @@ __all__ = [
"SerpAPIChain",
"Cohere",
"OpenAI",
"BasePromptTemplate",
"BasePrompt",
"DynamicPrompt",
"Prompt",
"FewShotPromptTemplate",
"PromptTemplate",
"ReActChain",
"Wikipedia",
"HuggingFaceHub",
@@ -47,6 +42,4 @@ __all__ = [
"MRKLChain",
"VectorDBQA",
"ElasticVectorSearch",
"InMemoryDocstore",
"ConversationChain",
]

View File

@@ -1,17 +0,0 @@
"""Routing chains."""
from langchain.agents.agent import Agent
from langchain.agents.loading import initialize_agent
from langchain.agents.mrkl.base import MRKLChain, ZeroShotAgent
from langchain.agents.react.base import ReActChain
from langchain.agents.self_ask_with_search.base import SelfAskWithSearchChain
from langchain.agents.tools import Tool
__all__ = [
"MRKLChain",
"SelfAskWithSearchChain",
"ReActChain",
"Agent",
"Tool",
"initialize_agent",
"ZeroShotAgent",
]

View File

@@ -1,154 +0,0 @@
"""Chain that takes in an input and produces an action and action input."""
from abc import ABC, abstractmethod
from typing import Any, ClassVar, Dict, List, NamedTuple, Optional, Tuple
from pydantic import BaseModel
from langchain.agents.tools import Tool
from langchain.chains.base import Chain
from langchain.chains.llm import LLMChain
from langchain.input import ChainedInput, get_color_mapping
from langchain.llms.base import LLM
from langchain.prompts.base import BasePromptTemplate
class Action(NamedTuple):
"""Action to take."""
tool: str
tool_input: str
log: str
class Agent(Chain, BaseModel, ABC):
"""Agent that uses an LLM."""
prompt: ClassVar[BasePromptTemplate]
llm_chain: LLMChain
tools: List[Tool]
input_key: str = "input" #: :meta private:
output_key: str = "output" #: :meta private:
@property
def input_keys(self) -> List[str]:
"""Return the singular input key.
:meta private:
"""
return [self.input_key]
@property
def output_keys(self) -> List[str]:
"""Return the singular output key.
:meta private:
"""
return [self.output_key]
@property
@abstractmethod
def observation_prefix(self) -> str:
"""Prefix to append the observation with."""
@property
@abstractmethod
def llm_prefix(self) -> str:
"""Prefix to append the LLM call with."""
@property
def finish_tool_name(self) -> str:
"""Name of the tool to use to finish the chain."""
return "Final Answer"
@property
def starter_string(self) -> str:
"""Put this string after user input but before first LLM call."""
return "\n"
@abstractmethod
def _extract_tool_and_input(self, text: str) -> Optional[Tuple[str, str]]:
"""Extract tool and tool input from llm output."""
def _fix_text(self, text: str) -> str:
"""Fix the text."""
raise ValueError("fix_text not implemented for this agent.")
@property
def _stop(self) -> List[str]:
return [f"\n{self.observation_prefix}"]
@classmethod
def _validate_tools(cls, tools: List[Tool]) -> None:
"""Validate that appropriate tools are passed in."""
pass
@classmethod
def create_prompt(cls, tools: List[Tool]) -> BasePromptTemplate:
"""Create a prompt for this class."""
return cls.prompt
@classmethod
def from_llm_and_tools(cls, llm: LLM, tools: List[Tool], **kwargs: Any) -> "Agent":
"""Construct an agent from an LLM and tools."""
cls._validate_tools(tools)
llm_chain = LLMChain(llm=llm, prompt=cls.create_prompt(tools))
return cls(llm_chain=llm_chain, tools=tools, **kwargs)
def get_action(self, text: str) -> Action:
"""Given input, decided what to do.
Args:
text: input string
Returns:
Action specifying what tool to use.
"""
input_key = self.llm_chain.input_keys[0]
inputs = {input_key: text, "stop": self._stop}
full_output = self.llm_chain.predict(**inputs)
parsed_output = self._extract_tool_and_input(full_output)
while parsed_output is None:
full_output = self._fix_text(full_output)
inputs = {input_key: text + full_output, "stop": self._stop}
output = self.llm_chain.predict(**inputs)
full_output += output
parsed_output = self._extract_tool_and_input(full_output)
tool, tool_input = parsed_output
return Action(tool, tool_input, full_output)
def _call(self, inputs: Dict[str, str]) -> Dict[str, str]:
"""Run text through and get agent response."""
text = inputs[self.input_key]
# Construct a mapping of tool name to tool for easy lookup
name_to_tool_map = {tool.name: tool.func for tool in self.tools}
# Construct the initial string to pass into the LLM. This is made up
# of the user input, the special starter string, and then the LLM prefix.
# The starter string is a special string that may be used by a LLM to
# immediately follow the user input. The LLM prefix is a string that
# prompts the LLM to take an action.
starter_string = text + self.starter_string + self.llm_prefix
# We use the ChainedInput class to iteratively add to the input over time.
chained_input = ChainedInput(starter_string, verbose=self.verbose)
# We construct a mapping from each tool to a color, used for logging.
color_mapping = get_color_mapping(
[tool.name for tool in self.tools], excluded_colors=["green"]
)
# We now enter the agent loop (until it returns something).
while True:
# Call the LLM to see what to do.
output = self.get_action(chained_input.input)
# Add the log to the Chained Input.
chained_input.add(output.log, color="green")
# If the tool chosen is the finishing tool, then we end and return.
if output.tool == self.finish_tool_name:
return {self.output_key: output.tool_input}
# Otherwise we lookup the tool
chain = name_to_tool_map[output.tool]
# We then call the tool on the tool input to get an observation
observation = chain(output.tool_input)
# We then log the observation
chained_input.add(f"\n{self.observation_prefix}")
chained_input.add(observation, color=color_mapping[output.tool])
# We then add the LLM prefix into the prompt to get the LLM to start
# thinking, and start the loop all over.
chained_input.add(f"\n{self.llm_prefix}")

View File

@@ -1,42 +0,0 @@
"""Load agent."""
from typing import Any, List
from langchain.agents.agent import Agent
from langchain.agents.mrkl.base import ZeroShotAgent
from langchain.agents.react.base import ReActDocstoreAgent
from langchain.agents.self_ask_with_search.base import SelfAskWithSearchAgent
from langchain.agents.tools import Tool
from langchain.llms.base import LLM
AGENT_TO_CLASS = {
"zero-shot-react-description": ZeroShotAgent,
"react-docstore": ReActDocstoreAgent,
"self-ask-with-search": SelfAskWithSearchAgent,
}
def initialize_agent(
tools: List[Tool],
llm: LLM,
agent: str = "zero-shot-react-description",
**kwargs: Any,
) -> Agent:
"""Load agent given tools and LLM.
Args:
tools: List of tools this agent has access to.
llm: Language model to use as the agent.
agent: The agent to use. Valid options are:
`zero-shot-react-description`, `react-docstore`, `self-ask-with-search`.
**kwargs: Additional key word arguments to pass to the agent.
Returns:
An agent.
"""
if agent not in AGENT_TO_CLASS:
raise ValueError(
f"Got unknown agent type: {agent}. "
f"Valid types are: {AGENT_TO_CLASS.keys()}."
)
agent_cls = AGENT_TO_CLASS[agent]
return agent_cls.from_llm_and_tools(llm, tools, **kwargs)

View File

@@ -1,157 +0,0 @@
"""Attempt to implement MRKL systems as described in arxiv.org/pdf/2205.00445.pdf."""
from typing import Any, Callable, List, NamedTuple, Optional, Tuple
from langchain.agents.agent import Agent
from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS, PREFIX, SUFFIX
from langchain.agents.tools import Tool
from langchain.llms.base import LLM
from langchain.prompts import PromptTemplate
FINAL_ANSWER_ACTION = "Final Answer: "
class ChainConfig(NamedTuple):
"""Configuration for chain to use in MRKL system.
Args:
action_name: Name of the action.
action: Action function to call.
action_description: Description of the action.
"""
action_name: str
action: Callable
action_description: str
def get_action_and_input(llm_output: str) -> Tuple[str, str]:
"""Parse out the action and input from the LLM output."""
ps = [p for p in llm_output.split("\n") if p]
if ps[-1].startswith("Final Answer"):
directive = ps[-1][len(FINAL_ANSWER_ACTION) :]
return "Final Answer", directive
if not ps[-1].startswith("Action Input: "):
raise ValueError(
"The last line does not have an action input, "
"something has gone terribly wrong."
)
if not ps[-2].startswith("Action: "):
raise ValueError(
"The second to last line does not have an action, "
"something has gone terribly wrong."
)
action = ps[-2][len("Action: ") :]
action_input = ps[-1][len("Action Input: ") :]
return action, action_input.strip(" ").strip('"')
class ZeroShotAgent(Agent):
"""Agent for the MRKL chain."""
@property
def observation_prefix(self) -> str:
"""Prefix to append the observation with."""
return "Observation: "
@property
def llm_prefix(self) -> str:
"""Prefix to append the llm call with."""
return "Thought:"
@classmethod
def create_prompt(
cls,
tools: List[Tool],
prefix: str = PREFIX,
suffix: str = SUFFIX,
input_variables: Optional[List[str]] = None,
) -> PromptTemplate:
"""Create prompt in the style of the zero shot agent.
Args:
tools: List of tools the agent will have access to, used to format the
prompt.
prefix: String to put before the list of tools.
suffix: String to put after the list of tools.
input_variables: List of input variables the final prompt will expect.
Returns:
A PromptTemplate with the template assembled from the pieces here.
"""
tool_strings = "\n".join([f"{tool.name}: {tool.description}" for tool in tools])
tool_names = ", ".join([tool.name for tool in tools])
format_instructions = FORMAT_INSTRUCTIONS.format(tool_names=tool_names)
template = "\n\n".join([prefix, tool_strings, format_instructions, suffix])
if input_variables is None:
input_variables = ["input"]
return PromptTemplate(template=template, input_variables=input_variables)
@classmethod
def _validate_tools(cls, tools: List[Tool]) -> None:
for tool in tools:
if tool.description is None:
raise ValueError(
f"Got a tool {tool.name} without a description. For this agent, "
f"a description must always be provided."
)
def _extract_tool_and_input(self, text: str) -> Optional[Tuple[str, str]]:
return get_action_and_input(text)
class MRKLChain(ZeroShotAgent):
"""Chain that implements the MRKL system.
Example:
.. code-block:: python
from langchain import OpenAI, MRKLChain
from langchain.chains.mrkl.base import ChainConfig
llm = OpenAI(temperature=0)
prompt = PromptTemplate(...)
chains = [...]
mrkl = MRKLChain.from_chains(llm=llm, prompt=prompt)
"""
@classmethod
def from_chains(cls, llm: LLM, chains: List[ChainConfig], **kwargs: Any) -> "Agent":
"""User friendly way to initialize the MRKL chain.
This is intended to be an easy way to get up and running with the
MRKL chain.
Args:
llm: The LLM to use as the agent LLM.
chains: The chains the MRKL system has access to.
**kwargs: parameters to be passed to initialization.
Returns:
An initialized MRKL chain.
Example:
.. code-block:: python
from langchain import LLMMathChain, OpenAI, SerpAPIChain, MRKLChain
from langchain.chains.mrkl.base import ChainConfig
llm = OpenAI(temperature=0)
search = SerpAPIChain()
llm_math_chain = LLMMathChain(llm=llm)
chains = [
ChainConfig(
action_name = "Search",
action=search.search,
action_description="useful for searching"
),
ChainConfig(
action_name="Calculator",
action=llm_math_chain.run,
action_description="useful for doing math"
)
]
mrkl = MRKLChain.from_chains(llm, chains)
"""
tools = [
Tool(name=c.action_name, func=c.action, description=c.action_description)
for c in chains
]
return cls.from_llm_and_tools(llm, tools, **kwargs)

View File

@@ -1,114 +0,0 @@
"""Chain that implements the ReAct paper from https://arxiv.org/pdf/2210.03629.pdf."""
import re
from typing import Any, ClassVar, List, Optional, Tuple
from pydantic import BaseModel
from langchain.agents.agent import Agent
from langchain.agents.react.prompt import PROMPT
from langchain.agents.tools import Tool
from langchain.chains.llm import LLMChain
from langchain.docstore.base import Docstore
from langchain.docstore.document import Document
from langchain.llms.base import LLM
from langchain.prompts.base import BasePromptTemplate
class ReActDocstoreAgent(Agent, BaseModel):
"""Agent for the ReAct chin."""
prompt: ClassVar[BasePromptTemplate] = PROMPT
i: int = 1
@classmethod
def _validate_tools(cls, tools: List[Tool]) -> None:
if len(tools) != 2:
raise ValueError(f"Exactly two tools must be specified, but got {tools}")
tool_names = {tool.name for tool in tools}
if tool_names != {"Lookup", "Search"}:
raise ValueError(
f"Tool names should be Lookup and Search, got {tool_names}"
)
def _fix_text(self, text: str) -> str:
return text + f"\nAction {self.i}:"
def _extract_tool_and_input(self, text: str) -> Optional[Tuple[str, str]]:
action_prefix = f"Action {self.i}: "
if not text.split("\n")[-1].startswith(action_prefix):
return None
self.i += 1
action_block = text.split("\n")[-1]
action_str = action_block[len(action_prefix) :]
# Parse out the action and the directive.
re_matches = re.search(r"(.*?)\[(.*?)\]", action_str)
if re_matches is None:
raise ValueError(f"Could not parse action directive: {action_str}")
return re_matches.group(1), re_matches.group(2)
@property
def finish_tool_name(self) -> str:
"""Name of the tool of when to finish the chain."""
return "Finish"
@property
def observation_prefix(self) -> str:
"""Prefix to append the observation with."""
return f"Observation {self.i - 1}: "
@property
def _stop(self) -> List[str]:
return [f"\nObservation {self.i}: "]
@property
def llm_prefix(self) -> str:
"""Prefix to append the LLM call with."""
return f"Thought {self.i}:"
class DocstoreExplorer:
"""Class to assist with exploration of a document store."""
def __init__(self, docstore: Docstore):
"""Initialize with a docstore, and set initial document to None."""
self.docstore = docstore
self.document: Optional[Document] = None
def search(self, term: str) -> str:
"""Search for a term in the docstore, and if found save."""
result = self.docstore.search(term)
if isinstance(result, Document):
self.document = result
return self.document.summary
else:
self.document = None
return result
def lookup(self, term: str) -> str:
"""Lookup a term in document (if saved)."""
if self.document is None:
raise ValueError("Cannot lookup without a successful search first")
return self.document.lookup(term)
class ReActChain(ReActDocstoreAgent):
"""Chain that implements the ReAct paper.
Example:
.. code-block:: python
from langchain import ReActChain, OpenAI
react = ReAct(llm=OpenAI())
"""
def __init__(self, llm: LLM, docstore: Docstore, **kwargs: Any):
"""Initialize with the LLM and a docstore."""
docstore_explorer = DocstoreExplorer(docstore)
tools = [
Tool(name="Search", func=docstore_explorer.search),
Tool(name="Lookup", func=docstore_explorer.lookup),
]
llm_chain = LLMChain(llm=llm, prompt=PROMPT)
super().__init__(llm_chain=llm_chain, tools=tools, **kwargs)

View File

@@ -1,87 +0,0 @@
"""Chain that does self ask with search."""
from typing import Any, ClassVar, List, Optional, Tuple
from langchain.agents.agent import Agent
from langchain.agents.self_ask_with_search.prompt import PROMPT
from langchain.agents.tools import Tool
from langchain.chains.llm import LLMChain
from langchain.chains.serpapi import SerpAPIChain
from langchain.llms.base import LLM
from langchain.prompts.base import BasePromptTemplate
class SelfAskWithSearchAgent(Agent):
"""Agent for the self-ask-with-search paper."""
prompt: ClassVar[BasePromptTemplate] = PROMPT
@classmethod
def _validate_tools(cls, tools: List[Tool]) -> None:
if len(tools) != 1:
raise ValueError(f"Exactly one tool must be specified, but got {tools}")
tool_names = {tool.name for tool in tools}
if tool_names != {"Intermediate Answer"}:
raise ValueError(
f"Tool name should be Intermediate Answer, got {tool_names}"
)
def _extract_tool_and_input(self, text: str) -> Optional[Tuple[str, str]]:
followup = "Follow up:"
if "\n" not in text:
last_line = text
else:
last_line = text.split("\n")[-1]
if followup not in last_line:
finish_string = "So the final answer is: "
if finish_string not in last_line:
return None
return "Final Answer", last_line[len(finish_string) :]
if ":" not in last_line:
after_colon = last_line
else:
after_colon = text.split(":")[-1]
if " " == after_colon[0]:
after_colon = after_colon[1:]
if "?" != after_colon[-1]:
print("we probably should never get here..." + text)
return "Intermediate Answer", after_colon
def _fix_text(self, text: str) -> str:
return text + "\nSo the final answer is:"
@property
def observation_prefix(self) -> str:
"""Prefix to append the observation with."""
return "Intermediate answer: "
@property
def llm_prefix(self) -> str:
"""Prefix to append the LLM call with."""
return ""
@property
def starter_string(self) -> str:
"""Put this string after user input but before first LLM call."""
return "\nAre follow up questions needed here:"
class SelfAskWithSearchChain(SelfAskWithSearchAgent):
"""Chain that does self ask with search.
Example:
.. code-block:: python
from langchain import SelfAskWithSearchChain, OpenAI, SerpAPIChain
search_chain = SerpAPIChain()
self_ask = SelfAskWithSearchChain(llm=OpenAI(), search_chain=search_chain)
"""
def __init__(self, llm: LLM, search_chain: SerpAPIChain, **kwargs: Any):
"""Initialize with just an LLM and a search chain."""
search_tool = Tool(name="Intermediate Answer", func=search_chain.run)
llm_chain = LLMChain(llm=llm, prompt=PROMPT)
super().__init__(llm_chain=llm_chain, tools=[search_tool], **kwargs)

View File

@@ -1,22 +0,0 @@
TEMPLATE = """You are a data engineer answering questions using a SQL database.
Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer.
Only use the following tables:
{table_info}
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: SQLDB
Action Input: the query to run against the SQL database
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
Begin!
Question: {input}"""

View File

@@ -1,10 +0,0 @@
"""Interface for tools."""
from typing import Callable, NamedTuple, Optional
class Tool(NamedTuple):
"""Interface for tools."""
name: str
func: Callable[[str], str]
description: Optional[str] = None

View File

@@ -1,9 +1,10 @@
"""Chains are easily reusable components which can be linked together."""
from langchain.chains.conversation.base import ConversationChain
from langchain.chains.llm import LLMChain
from langchain.chains.llm_math.base import LLMMathChain
from langchain.chains.mrkl.base import MRKLChain
from langchain.chains.python import PythonChain
from langchain.chains.sequential import SequentialChain, SimpleSequentialChain
from langchain.chains.react.base import ReActChain
from langchain.chains.self_ask_with_search.base import SelfAskWithSearchChain
from langchain.chains.serpapi import SerpAPIChain
from langchain.chains.sql_database.base import SQLDatabaseChain
from langchain.chains.vector_db_qa.base import VectorDBQA
@@ -12,10 +13,10 @@ __all__ = [
"LLMChain",
"LLMMathChain",
"PythonChain",
"SelfAskWithSearchChain",
"SerpAPIChain",
"ReActChain",
"SQLDatabaseChain",
"MRKLChain",
"VectorDBQA",
"SequentialChain",
"SimpleSequentialChain",
"ConversationChain",
]

View File

@@ -1,40 +1,15 @@
"""Base interface that all chains should implement."""
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional
from typing import Any, Dict, List
from pydantic import BaseModel, Extra
class Memory(BaseModel, ABC):
"""Base interface for memory in chains."""
class Config:
"""Configuration for this pydantic object."""
extra = Extra.forbid
arbitrary_types_allowed = True
@property
@abstractmethod
def memory_variables(self) -> List[str]:
"""Input keys this memory class will load dynamically."""
@abstractmethod
def load_memory_variables(self, inputs: Dict[str, Any]) -> Dict[str, str]:
"""Return key-value pairs given the text input to the chain."""
@abstractmethod
def save_context(self, inputs: Dict[str, Any], outputs: Dict[str, str]) -> None:
"""Save the context of this model run to memory."""
from pydantic import BaseModel
class Chain(BaseModel, ABC):
"""Base interface that all chains should implement."""
memory: Optional[Memory] = None
verbose: bool = False
"""Whether to print out response text."""
"""Whether to print out the code that was executed."""
@property
@abstractmethod
@@ -63,22 +38,8 @@ class Chain(BaseModel, ABC):
def _call(self, inputs: Dict[str, str]) -> Dict[str, str]:
"""Run the logic of this chain and return the output."""
def __call__(
self, inputs: Dict[str, Any], return_only_outputs: bool = False
) -> Dict[str, str]:
"""Run the logic of this chain and add to output if desired.
Args:
inputs: Dictionary of inputs.
return_only_outputs: boolean for whether to return only outputs in the
response. If True, only new keys generated by this chain will be
returned. If False, both input keys and new keys generated by this
chain will be returned. Defaults to False.
"""
if self.memory is not None:
external_context = self.memory.load_memory_variables(inputs)
inputs = dict(inputs, **external_context)
def __call__(self, inputs: Dict[str, Any]) -> Dict[str, str]:
"""Run the logic of this chain and add to output."""
self._validate_inputs(inputs)
if self.verbose:
print("\n\n\033[1m> Entering new chain...\033[0m")
@@ -86,16 +47,7 @@ class Chain(BaseModel, ABC):
if self.verbose:
print("\n\033[1m> Finished chain.\033[0m")
self._validate_outputs(outputs)
if self.memory is not None:
self.memory.save_context(inputs, outputs)
if return_only_outputs:
return outputs
else:
return {**inputs, **outputs}
def apply(self, input_list: List[Dict[str, Any]]) -> List[Dict[str, str]]:
"""Call the chain on all inputs in the list."""
return [self(inputs) for inputs in input_list]
return {**inputs, **outputs}
def run(self, text: str) -> str:
"""Run text in, text out (if applicable)."""

View File

@@ -1 +0,0 @@
"""Chain that carries on a conversation from a prompt plus history."""

View File

@@ -1,61 +0,0 @@
"""Chain that carries on a conversation and calls an LLM."""
from typing import Dict, List
from pydantic import BaseModel, Extra, Field, root_validator
from langchain.chains.base import Memory
from langchain.chains.conversation.memory import ConversationBufferMemory
from langchain.chains.conversation.prompt import PROMPT
from langchain.chains.llm import LLMChain
from langchain.prompts.base import BasePromptTemplate
class ConversationChain(LLMChain, BaseModel):
"""Chain to have a conversation and load context from memory.
Example:
.. code-block:: python
from langchain import ConversationChain, OpenAI
conversation = ConversationChain(llm=OpenAI())
"""
memory: Memory = Field(default_factory=ConversationBufferMemory)
"""Default memory store."""
prompt: BasePromptTemplate = PROMPT
"""Default conversation prompt to use."""
input_key: str = "input" #: :meta private:
output_key: str = "response" #: :meta private:
buffer: str = "" #: :meta private:
class Config:
"""Configuration for this pydantic object."""
extra = Extra.forbid
arbitrary_types_allowed = True
@property
def input_keys(self) -> List[str]:
"""Use this since so some prompt vars come from history."""
return [self.input_key]
@root_validator()
def validate_prompt_input_variables(cls, values: Dict) -> Dict:
"""Validate that prompt input variables are consistent."""
memory_keys = values["memory"].memory_variables
input_key = values["input_key"]
if input_key in memory_keys:
raise ValueError(
f"The input key {input_key} was also found in the memory keys "
f"({memory_keys}) - please provide keys that don't overlap."
)
prompt_variables = values["prompt"].input_variables
expected_keys = memory_keys + [input_key]
if set(expected_keys) != set(prompt_variables):
raise ValueError(
"Got unexpected prompt input variables. The prompt expects "
f"{prompt_variables}, but got {memory_keys} as inputs from "
f"memory, and {input_key} as the normal input key."
)
return values

View File

@@ -1,91 +0,0 @@
"""Memory modules for conversation prompts."""
from typing import Any, Dict, List
from pydantic import BaseModel, root_validator
from langchain.chains.base import Memory
from langchain.chains.conversation.prompt import SUMMARY_PROMPT
from langchain.chains.llm import LLMChain
from langchain.llms.base import LLM
from langchain.prompts.base import BasePromptTemplate
def _get_prompt_input_key(inputs: Dict[str, Any], memory_variables: List[str]) -> str:
# "stop" is a special key that can be passed as input but is not used to
# format the prompt.
prompt_input_keys = list(set(inputs).difference(memory_variables + ["stop"]))
if len(prompt_input_keys) != 1:
raise ValueError(f"One input key expected got {prompt_input_keys}")
return prompt_input_keys[0]
class ConversationBufferMemory(Memory, BaseModel):
"""Buffer for storing conversation memory."""
buffer: str = ""
memory_key: str = "history" #: :meta private:
@property
def memory_variables(self) -> List[str]:
"""Will always return list of memory variables.
:meta private:
"""
return [self.memory_key]
def load_memory_variables(self, inputs: Dict[str, Any]) -> Dict[str, str]:
"""Return history buffer."""
return {self.memory_key: self.buffer}
def save_context(self, inputs: Dict[str, Any], outputs: Dict[str, str]) -> None:
"""Save context from this conversation to buffer."""
prompt_input_key = _get_prompt_input_key(inputs, self.memory_variables)
if len(outputs) != 1:
raise ValueError(f"One output key expected, got {outputs.keys()}")
human = "Human: " + inputs[prompt_input_key]
ai = "AI: " + outputs[list(outputs.keys())[0]]
self.buffer += "\n" + "\n".join([human, ai])
class ConversationSummaryMemory(Memory, BaseModel):
"""Conversation summarizer to memory."""
buffer: str = ""
llm: LLM
prompt: BasePromptTemplate = SUMMARY_PROMPT
memory_key: str = "history" #: :meta private:
@property
def memory_variables(self) -> List[str]:
"""Will always return list of memory variables.
:meta private:
"""
return [self.memory_key]
def load_memory_variables(self, inputs: Dict[str, Any]) -> Dict[str, str]:
"""Return history buffer."""
return {self.memory_key: self.buffer}
@root_validator()
def validate_prompt_input_variables(cls, values: Dict) -> Dict:
"""Validate that prompt input variables are consistent."""
prompt_variables = values["prompt"].input_variables
expected_keys = {"summary", "new_lines"}
if expected_keys != set(prompt_variables):
raise ValueError(
"Got unexpected prompt input variables. The prompt expects "
f"{prompt_variables}, but it should have {expected_keys}."
)
return values
def save_context(self, inputs: Dict[str, Any], outputs: Dict[str, str]) -> None:
"""Save context from this conversation to buffer."""
prompt_input_key = _get_prompt_input_key(inputs, self.memory_variables)
if len(outputs) != 1:
raise ValueError(f"One output key expected, got {outputs.keys()}")
human = "Human: " + inputs[prompt_input_key]
ai = "AI: " + list(outputs.values())[0]
new_lines = "\n".join([human, ai])
chain = LLMChain(llm=self.llm, prompt=self.prompt)
self.buffer = chain.predict(summary=self.buffer, new_lines=new_lines)

View File

@@ -1,37 +0,0 @@
# flake8: noqa
from langchain.prompts.prompt import PromptTemplate
_DEFAULT_TEMPLATE = """The following is a friendly conversation between a human and an AI. The AI is talkative and provides lots of specific details from its context. If the AI does not know the answer to a question, it truthfully says it does not know.
Current conversation:
{history}
Human: {input}
AI:"""
PROMPT = PromptTemplate(
input_variables=["history", "input"], template=_DEFAULT_TEMPLATE
)
_DEFAULT_SUMMARIZER_TEMPLATE = """Progressively summarize the lines of conversation provided, adding onto the previous summary returning a new summary.
EXAMPLE
Current summary:
The human asks what the AI thinks of artificial intelligence. The AI thinks artificial intelligence is a force for good.
New lines of conversation:
Human: Why do you think artificial intelligence is a force for good?
AI: Because artificial intelligence will help humans reach their full potential.
New summary:
The human asks what the AI thinks of artificial intelligence. The AI thinks artificial intelligence is a force for good because it will help humans reach their full potential.
END OF EXAMPLE
Current summary:
{summary}
New lines of conversation:
{new_lines}
New summary:"""
SUMMARY_PROMPT = PromptTemplate(
input_variables=["summary", "new_lines"], template=_DEFAULT_SUMMARIZER_TEMPLATE
)

View File

@@ -4,9 +4,8 @@ from typing import Any, Dict, List
from pydantic import BaseModel, Extra
from langchain.chains.base import Chain
from langchain.input import print_text
from langchain.llms.base import LLM
from langchain.prompts.base import BasePromptTemplate
from langchain.prompts.base import BasePrompt
class LLMChain(Chain, BaseModel):
@@ -15,15 +14,13 @@ class LLMChain(Chain, BaseModel):
Example:
.. code-block:: python
from langchain import LLMChain, OpenAI, PromptTemplate
from langchain import LLMChain, OpenAI, Prompt
prompt_template = "Tell me a {adjective} joke"
prompt = PromptTemplate(
input_variables=["adjective"], template=prompt_template
)
prompt = Prompt(input_variables=["adjective"], template=prompt_template)
llm = LLMChain(llm=OpenAI(), prompt=prompt)
"""
prompt: BasePromptTemplate
prompt: BasePrompt
"""Prompt object to use."""
llm: LLM
"""LLM wrapper to use."""
@@ -54,9 +51,7 @@ class LLMChain(Chain, BaseModel):
def _call(self, inputs: Dict[str, Any]) -> Dict[str, str]:
selected_inputs = {k: inputs[k] for k in self.prompt.input_variables}
prompt = self.prompt.format(**selected_inputs)
if self.verbose:
print("Prompt after formatting:")
print_text(prompt, color="green", end="\n")
kwargs = {}
if "stop" in inputs:
kwargs["stop"] = inputs["stop"]

View File

@@ -1,5 +1,5 @@
# flake8: noqa
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.prompt import Prompt
_PROMPT_TEMPLATE = """You are GPT-3, and you can't do math.
@@ -35,4 +35,4 @@ Answer: 2518731
Question: {question}"""
PROMPT = PromptTemplate(input_variables=["question"], template=_PROMPT_TEMPLATE)
PROMPT = Prompt(input_variables=["question"], template=_PROMPT_TEMPLATE)

View File

@@ -11,7 +11,7 @@ from pydantic import BaseModel, Extra
from langchain.chains.base import Chain
from langchain.chains.llm import LLMChain
from langchain.llms.base import LLM
from langchain.prompts.base import BasePromptTemplate
from langchain.prompts.base import BasePrompt
from langchain.text_splitter import TextSplitter
@@ -29,7 +29,7 @@ class MapReduceChain(Chain, BaseModel):
@classmethod
def from_params(
cls, llm: LLM, prompt: BasePromptTemplate, text_splitter: TextSplitter
cls, llm: LLM, prompt: BasePrompt, text_splitter: TextSplitter
) -> "MapReduceChain":
"""Construct a map-reduce chain that uses the chain for map and reduce."""
llm_chain = LLMChain(llm=llm, prompt=prompt)
@@ -60,12 +60,13 @@ class MapReduceChain(Chain, BaseModel):
def _call(self, inputs: Dict[str, str]) -> Dict[str, str]:
# Split the larger text into smaller chunks.
docs = self.text_splitter.split_text(inputs[self.input_key])
# Now that we have the chunks, we send them to the LLM and track results.
# This is the "map" part.
input_list = [{self.map_llm.prompt.input_variables[0]: d} for d in docs]
summary_results = self.map_llm.apply(input_list)
summaries = [res[self.map_llm.output_key] for res in summary_results]
summaries = []
for d in docs:
inputs = {self.map_llm.prompt.input_variables[0]: d}
res = self.map_llm.predict(**inputs)
summaries.append(res)
# We then need to combine these individual parts into one.
# This is the reduce part.

View File

@@ -0,0 +1,170 @@
"""Attempt to implement MRKL systems as described in arxiv.org/pdf/2205.00445.pdf."""
from typing import Any, Callable, Dict, List, NamedTuple, Tuple
from pydantic import BaseModel, Extra
from langchain.chains.base import Chain
from langchain.chains.llm import LLMChain
from langchain.chains.mrkl.prompt import BASE_TEMPLATE
from langchain.input import ChainedInput, get_color_mapping
from langchain.llms.base import LLM
from langchain.prompts import BasePrompt, Prompt
FINAL_ANSWER_ACTION = "Final Answer: "
class ChainConfig(NamedTuple):
"""Configuration for chain to use in MRKL system.
Args:
action_name: Name of the action.
action: Action function to call.
action_description: Description of the action.
"""
action_name: str
action: Callable
action_description: str
def get_action_and_input(llm_output: str) -> Tuple[str, str]:
"""Parse out the action and input from the LLM output."""
ps = [p for p in llm_output.split("\n") if p]
if ps[-1].startswith(FINAL_ANSWER_ACTION):
directive = ps[-1][len(FINAL_ANSWER_ACTION) :]
return FINAL_ANSWER_ACTION, directive
if not ps[-1].startswith("Action Input: "):
raise ValueError(
"The last line does not have an action input, "
"something has gone terribly wrong."
)
if not ps[-2].startswith("Action: "):
raise ValueError(
"The second to last line does not have an action, "
"something has gone terribly wrong."
)
action = ps[-2][len("Action: ") :]
action_input = ps[-1][len("Action Input: ") :]
return action, action_input.strip(" ").strip('"')
class MRKLChain(Chain, BaseModel):
"""Chain that implements the MRKL system.
Example:
.. code-block:: python
from langchain import OpenAI, Prompt, MRKLChain
from langchain.chains.mrkl.base import ChainConfig
llm = OpenAI(temperature=0)
prompt = Prompt(...)
action_to_chain_map = {...}
mrkl = MRKLChain(
llm=llm,
prompt=prompt,
action_to_chain_map=action_to_chain_map
)
"""
llm: LLM
"""LLM wrapper to use as router."""
prompt: BasePrompt
"""Prompt to use as router."""
action_to_chain_map: Dict[str, Callable]
"""Mapping from action name to chain to execute."""
input_key: str = "question" #: :meta private:
output_key: str = "answer" #: :meta private:
@classmethod
def from_chains(
cls, llm: LLM, chains: List[ChainConfig], **kwargs: Any
) -> "MRKLChain":
"""User friendly way to initialize the MRKL chain.
This is intended to be an easy way to get up and running with the
MRKL chain.
Args:
llm: The LLM to use as the router LLM.
chains: The chains the MRKL system has access to.
**kwargs: parameters to be passed to initialization.
Returns:
An initialized MRKL chain.
Example:
.. code-block:: python
from langchain import LLMMathChain, OpenAI, SerpAPIChain, MRKLChain
from langchain.chains.mrkl.base import ChainConfig
llm = OpenAI(temperature=0)
search = SerpAPIChain()
llm_math_chain = LLMMathChain(llm=llm)
chains = [
ChainConfig(
action_name = "Search",
action=search.search,
action_description="useful for searching"
),
ChainConfig(
action_name="Calculator",
action=llm_math_chain.run,
action_description="useful for doing math"
)
]
mrkl = MRKLChain.from_chains(llm, chains)
"""
tools = "\n".join(
[f"{chain.action_name}: {chain.action_description}" for chain in chains]
)
tool_names = ", ".join([chain.action_name for chain in chains])
template = BASE_TEMPLATE.format(tools=tools, tool_names=tool_names)
prompt = Prompt(template=template, input_variables=["input"])
action_to_chain_map = {chain.action_name: chain.action for chain in chains}
return cls(
llm=llm, prompt=prompt, action_to_chain_map=action_to_chain_map, **kwargs
)
class Config:
"""Configuration for this pydantic object."""
extra = Extra.forbid
arbitrary_types_allowed = True
@property
def input_keys(self) -> List[str]:
"""Expect input key.
:meta private:
"""
return [self.input_key]
@property
def output_keys(self) -> List[str]:
"""Expect output key.
:meta private:
"""
return [self.output_key]
def _call(self, inputs: Dict[str, str]) -> Dict[str, str]:
llm_chain = LLMChain(llm=self.llm, prompt=self.prompt)
chained_input = ChainedInput(
f"{inputs[self.input_key]}\nThought:", verbose=self.verbose
)
color_mapping = get_color_mapping(
list(self.action_to_chain_map.keys()), excluded_colors=["green"]
)
while True:
thought = llm_chain.predict(
input=chained_input.input, stop=["\nObservation"]
)
chained_input.add(thought, color="green")
action, action_input = get_action_and_input(thought)
if action == FINAL_ANSWER_ACTION:
return {self.output_key: action_input}
chain = self.action_to_chain_map[action]
ca = chain(action_input)
chained_input.add("\nObservation: ")
chained_input.add(ca, color=color_mapping[action])
chained_input.add("\nThought:")

View File

@@ -1,6 +1,9 @@
# flake8: noqa
PREFIX = """Answer the following questions as best you can. You have access to the following tools:"""
FORMAT_INSTRUCTIONS = """Use the following format:
BASE_TEMPLATE = """Answer the following questions as best you can. You have access to the following tools:
{tools}
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
@@ -9,7 +12,8 @@ Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question"""
SUFFIX = """Begin!
Final Answer: the final answer to the original input question
Question: {input}"""
Begin!
Question: {{input}}"""

View File

@@ -1,8 +1,8 @@
# flake8: noqa
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.prompt import Prompt
_PROMPT_TEMPLATE = """
You are an agents controlling a browser. You are given:
You are an agent controlling a browser. You are given:
(1) an objective that you are trying to achieve
(2) the URL of your current web page
@@ -138,7 +138,7 @@ CURRENT URL: {url}
PREVIOUS COMMAND: {previous_command}
YOUR COMMAND:
"""
PROMPT = PromptTemplate(
PROMPT = Prompt(
input_variables=["browser_content", "url", "previous_command", "objective"],
template=_PROMPT_TEMPLATE,
)

View File

@@ -0,0 +1,107 @@
"""Chain that implements the ReAct paper from https://arxiv.org/pdf/2210.03629.pdf."""
import re
from typing import Any, Dict, List, Tuple
from pydantic import BaseModel, Extra
from langchain.chains.base import Chain
from langchain.chains.llm import LLMChain
from langchain.chains.react.prompt import PROMPT
from langchain.docstore.base import Docstore
from langchain.docstore.document import Document
from langchain.input import ChainedInput
from langchain.llms.base import LLM
def predict_until_observation(
llm_chain: LLMChain, prompt: str, i: int
) -> Tuple[str, str, str]:
"""Generate text until an observation is needed."""
action_prefix = f"Action {i}: "
stop_seq = f"\nObservation {i}:"
ret_text = llm_chain.predict(input=prompt, stop=[stop_seq])
# Sometimes the LLM forgets to take an action, so we prompt it to.
while not ret_text.split("\n")[-1].startswith(action_prefix):
ret_text += f"\nAction {i}:"
new_text = llm_chain.predict(input=prompt + ret_text, stop=[stop_seq])
ret_text += new_text
# The action block should be the last line.
action_block = ret_text.split("\n")[-1]
action_str = action_block[len(action_prefix) :]
# Parse out the action and the directive.
re_matches = re.search(r"(.*?)\[(.*?)\]", action_str)
if re_matches is None:
raise ValueError(f"Could not parse action directive: {action_str}")
return ret_text, re_matches.group(1), re_matches.group(2)
class ReActChain(Chain, BaseModel):
"""Chain that implements the ReAct paper.
Example:
.. code-block:: python
from langchain import ReActChain, OpenAI
react = ReAct(llm=OpenAI())
"""
llm: LLM
"""LLM wrapper to use."""
docstore: Docstore
"""Docstore to use."""
input_key: str = "question" #: :meta private:
output_key: str = "answer" #: :meta private:
class Config:
"""Configuration for this pydantic object."""
extra = Extra.forbid
arbitrary_types_allowed = True
@property
def input_keys(self) -> List[str]:
"""Expect input key.
:meta private:
"""
return [self.input_key]
@property
def output_keys(self) -> List[str]:
"""Expect output key.
:meta private:
"""
return [self.output_key]
def _call(self, inputs: Dict[str, Any]) -> Dict[str, str]:
question = inputs[self.input_key]
llm_chain = LLMChain(llm=self.llm, prompt=PROMPT)
chained_input = ChainedInput(f"{question}\nThought 1:", verbose=self.verbose)
i = 1
document = None
while True:
ret_text, action, directive = predict_until_observation(
llm_chain, chained_input.input, i
)
chained_input.add(ret_text, color="green")
if action == "Search":
result = self.docstore.search(directive)
if isinstance(result, Document):
document = result
observation = document.summary
else:
document = None
observation = result
elif action == "Lookup":
if document is None:
raise ValueError("Cannot lookup without a successful search first")
observation = document.lookup(directive)
elif action == "Finish":
return {self.output_key: directive}
else:
raise ValueError(f"Got unknown action directive: {action}")
chained_input.add(f"\nObservation {i}: ")
chained_input.add(observation, color="yellow")
chained_input.add(f"\nThought {i + 1}:")
i += 1

View File

@@ -1,5 +1,5 @@
# flake8: noqa
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.prompt import Prompt
EXAMPLES = [
"""Question: What is the elevation range for the area that the eastern sector of the
@@ -109,4 +109,4 @@ Action 3: Finish[yes]""",
]
SUFFIX = """\n\nQuestion: {input}"""
PROMPT = PromptTemplate.from_examples(EXAMPLES, SUFFIX, ["input"])
PROMPT = Prompt.from_examples(EXAMPLES, SUFFIX, ["input"])

View File

@@ -0,0 +1,149 @@
"""Chain that does self ask with search."""
from typing import Any, Dict, List
from pydantic import BaseModel, Extra
from langchain.chains.base import Chain
from langchain.chains.llm import LLMChain
from langchain.chains.self_ask_with_search.prompt import PROMPT
from langchain.chains.serpapi import SerpAPIChain
from langchain.input import ChainedInput
from langchain.llms.base import LLM
def extract_answer(generated: str) -> str:
"""Extract answer from text."""
if "\n" not in generated:
last_line = generated
else:
last_line = generated.split("\n")[-1]
if ":" not in last_line:
after_colon = last_line
else:
after_colon = generated.split(":")[-1]
if " " == after_colon[0]:
after_colon = after_colon[1:]
if "." == after_colon[-1]:
after_colon = after_colon[:-1]
return after_colon
def extract_question(generated: str, followup: str) -> str:
"""Extract question from text."""
if "\n" not in generated:
last_line = generated
else:
last_line = generated.split("\n")[-1]
if followup not in last_line:
print("we probably should never get here..." + generated)
if ":" not in last_line:
after_colon = last_line
else:
after_colon = generated.split(":")[-1]
if " " == after_colon[0]:
after_colon = after_colon[1:]
if "?" != after_colon[-1]:
print("we probably should never get here..." + generated)
return after_colon
def get_last_line(generated: str) -> str:
"""Get the last line in text."""
if "\n" not in generated:
last_line = generated
else:
last_line = generated.split("\n")[-1]
return last_line
def greenify(_input: str) -> str:
"""Add green highlighting to text."""
return "\x1b[102m" + _input + "\x1b[0m"
def yellowfy(_input: str) -> str:
"""Add yellow highlighting to text."""
return "\x1b[106m" + _input + "\x1b[0m"
class SelfAskWithSearchChain(Chain, BaseModel):
"""Chain that does self ask with search.
Example:
.. code-block:: python
from langchain import SelfAskWithSearchChain, OpenAI, SerpAPIChain
search_chain = SerpAPIChain()
self_ask = SelfAskWithSearchChain(llm=OpenAI(), search_chain=search_chain)
"""
llm: LLM
"""LLM wrapper to use."""
search_chain: SerpAPIChain
"""Search chain to use."""
input_key: str = "question" #: :meta private:
output_key: str = "answer" #: :meta private:
class Config:
"""Configuration for this pydantic object."""
extra = Extra.forbid
arbitrary_types_allowed = True
@property
def input_keys(self) -> List[str]:
"""Expect input key.
:meta private:
"""
return [self.input_key]
@property
def output_keys(self) -> List[str]:
"""Expect output key.
:meta private:
"""
return [self.output_key]
def _call(self, inputs: Dict[str, Any]) -> Dict[str, str]:
chained_input = ChainedInput(inputs[self.input_key], verbose=self.verbose)
chained_input.add("\nAre follow up questions needed here:")
llm_chain = LLMChain(llm=self.llm, prompt=PROMPT)
intermediate = "\nIntermediate answer:"
followup = "Follow up:"
finalans = "\nSo the final answer is:"
ret_text = llm_chain.predict(input=chained_input.input, stop=[intermediate])
chained_input.add(ret_text, color="green")
while followup in get_last_line(ret_text):
question = extract_question(ret_text, followup)
external_answer = self.search_chain.run(question)
if external_answer is not None:
chained_input.add(intermediate + " ")
chained_input.add(external_answer + ".", color="yellow")
ret_text = llm_chain.predict(
input=chained_input.input, stop=["\nIntermediate answer:"]
)
chained_input.add(ret_text, color="green")
else:
# We only get here in the very rare case that Google returns no answer.
chained_input.add(intermediate + " ")
preds = llm_chain.predict(
input=chained_input.input, stop=["\n" + followup, finalans]
)
chained_input.add(preds, color="green")
if finalans not in ret_text:
chained_input.add(finalans)
ret_text = llm_chain.predict(input=chained_input.input, stop=["\n"])
chained_input.add(ret_text, color="green")
return {self.output_key: ret_text}

View File

@@ -1,5 +1,5 @@
# flake8: noqa
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.prompt import Prompt
_DEFAULT_TEMPLATE = """Question: Who lived longer, Muhammad Ali or Alan Turing?
Are follow up questions needed here: Yes.
@@ -38,4 +38,4 @@ Intermediate Answer: New Zealand.
So the final answer is: No
Question: {input}"""
PROMPT = PromptTemplate(input_variables=["input"], template=_DEFAULT_TEMPLATE)
PROMPT = Prompt(input_variables=["input"], template=_DEFAULT_TEMPLATE)

View File

@@ -1,137 +0,0 @@
"""Chain pipeline where the outputs of one step feed directly into next."""
from typing import Dict, List
from pydantic import BaseModel, Extra, root_validator
from langchain.chains.base import Chain
from langchain.input import get_color_mapping, print_text
class SequentialChain(Chain, BaseModel):
"""Chain where the outputs of one step feed directly into next."""
chains: List[Chain]
input_variables: List[str]
output_variables: List[str] #: :meta private:
return_all: bool = False
class Config:
"""Configuration for this pydantic object."""
extra = Extra.forbid
arbitrary_types_allowed = True
@property
def input_keys(self) -> List[str]:
"""Expect input key.
:meta private:
"""
return self.input_variables
@property
def output_keys(self) -> List[str]:
"""Return output key.
:meta private:
"""
return self.output_variables
@root_validator(pre=True)
def validate_chains(cls, values: Dict) -> Dict:
"""Validate that the correct inputs exist for all chains."""
chains = values["chains"]
input_variables = values["input_variables"]
known_variables = set(input_variables)
for chain in chains:
missing_vars = set(chain.input_keys).difference(known_variables)
if missing_vars:
raise ValueError(f"Missing required input keys: {missing_vars}")
overlapping_keys = known_variables.intersection(chain.output_keys)
if overlapping_keys:
raise ValueError(
f"Chain returned keys that already exist: {overlapping_keys}"
)
known_variables |= set(chain.output_keys)
if "output_variables" not in values:
if values.get("return_all", False):
output_keys = known_variables.difference(input_variables)
else:
output_keys = chains[-1].output_keys
values["output_variables"] = output_keys
else:
missing_vars = set(values["output_variables"]).difference(known_variables)
if missing_vars:
raise ValueError(
f"Expected output variables that were not found: {missing_vars}."
)
return values
def _call(self, inputs: Dict[str, str]) -> Dict[str, str]:
known_values = inputs.copy()
for i, chain in enumerate(self.chains):
outputs = chain(known_values, return_only_outputs=True)
if self.verbose:
print(f"\033[1mChain {i}\033[0m:\n{outputs}\n")
known_values.update(outputs)
return {k: known_values[k] for k in self.output_variables}
class SimpleSequentialChain(Chain, BaseModel):
"""Simple chain where the outputs of one step feed directly into next."""
chains: List[Chain]
strip_outputs: bool = False
input_key: str = "input" #: :meta private:
output_key: str = "output" #: :meta private:
class Config:
"""Configuration for this pydantic object."""
extra = Extra.forbid
arbitrary_types_allowed = True
@property
def input_keys(self) -> List[str]:
"""Expect input key.
:meta private:
"""
return [self.input_key]
@property
def output_keys(self) -> List[str]:
"""Return output key.
:meta private:
"""
return [self.output_key]
@root_validator()
def validate_chains(cls, values: Dict) -> Dict:
"""Validate that chains are all single input/output."""
for chain in values["chains"]:
if len(chain.input_keys) != 1:
raise ValueError(
"Chains used in SimplePipeline should all have one input, got "
f"{chain} with {len(chain.input_keys)} inputs."
)
if len(chain.output_keys) != 1:
raise ValueError(
"Chains used in SimplePipeline should all have one output, got "
f"{chain} with {len(chain.output_keys)} outputs."
)
return values
def _call(self, inputs: Dict[str, str]) -> Dict[str, str]:
_input = inputs[self.input_key]
color_mapping = get_color_mapping([str(i) for i in range(len(self.chains))])
for i, chain in enumerate(self.chains):
_input = chain.run(_input)
if self.strip_outputs:
_input = _input.strip()
if self.verbose:
print_text(_input, color=color_mapping[str(i)], end="\n")
return {self.output_key: _input}

View File

@@ -111,5 +111,5 @@ class SerpAPIChain(Chain, BaseModel):
elif "snippet" in res["organic_results"][0].keys():
toret = res["organic_results"][0]["snippet"]
else:
toret = "No good search result found"
toret = None
return {self.output_key: toret}

View File

@@ -64,10 +64,7 @@ class SQLDatabaseChain(Chain, BaseModel):
}
sql_cmd = llm_chain.predict(**llm_inputs)
chained_input.add(sql_cmd, color="green")
try:
result = self.database.run(sql_cmd)
except Exception as e:
result = str(e)
result = self.database.run(sql_cmd)
chained_input.add("\nSQLResult: ")
chained_input.add(result, color="yellow")
chained_input.add("\nAnswer:")

View File

@@ -1,5 +1,5 @@
# flake8: noqa
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.prompt import Prompt
_DEFAULT_TEMPLATE = """Given an input question, first create a syntactically correct {dialect} query to run, then look at the results of the query and return the answer.
Use the following format:
@@ -14,6 +14,6 @@ Only use the following tables:
{table_info}
Question: {input}"""
PROMPT = PromptTemplate(
PROMPT = Prompt(
input_variables=["input", "table_info", "dialect"], template=_DEFAULT_TEMPLATE
)

View File

@@ -5,9 +5,8 @@ from pydantic import BaseModel, Extra
from langchain.chains.base import Chain
from langchain.chains.llm import LLMChain
from langchain.chains.vector_db_qa.prompt import PROMPT
from langchain.chains.vector_db_qa.prompt import prompt
from langchain.llms.base import LLM
from langchain.prompts import PromptTemplate
from langchain.vectorstores.base import VectorStore
@@ -28,10 +27,6 @@ class VectorDBQA(Chain, BaseModel):
"""LLM wrapper to use."""
vectorstore: VectorStore
"""Vector Database to connect to."""
k: int = 4
"""Number of documents to query for."""
prompt: PromptTemplate = PROMPT
"""Prompt to use when questioning the documents."""
input_key: str = "query" #: :meta private:
output_key: str = "result" #: :meta private:
@@ -59,8 +54,8 @@ class VectorDBQA(Chain, BaseModel):
def _call(self, inputs: Dict[str, str]) -> Dict[str, str]:
question = inputs[self.input_key]
llm_chain = LLMChain(llm=self.llm, prompt=self.prompt)
docs = self.vectorstore.similarity_search(question, k=self.k)
llm_chain = LLMChain(llm=self.llm, prompt=prompt)
docs = self.vectorstore.similarity_search(question)
contexts = []
for j, doc in enumerate(docs):
contexts.append(f"Context {j}:\n{doc.page_content}")

View File

@@ -1,5 +1,5 @@
# flake8: noqa
from langchain.prompts import PromptTemplate
from langchain.prompts import Prompt
prompt_template = """Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer.
@@ -7,6 +7,4 @@ prompt_template = """Use the following pieces of context to answer the question
Question: {question}
Helpful Answer:"""
PROMPT = PromptTemplate(
template=prompt_template, input_variables=["context", "question"]
)
prompt = Prompt(template=prompt_template, input_variables=["context", "question"])

View File

@@ -1,5 +1,4 @@
"""Wrappers on top of docstores."""
from langchain.docstore.in_memory import InMemoryDocstore
from langchain.docstore.wikipedia import Wikipedia
__all__ = ["InMemoryDocstore", "Wikipedia"]
__all__ = ["Wikipedia"]

View File

@@ -1,6 +1,6 @@
"""Interface to access to place that stores documents."""
from abc import ABC, abstractmethod
from typing import Dict, Union
from typing import Union
from langchain.docstore.document import Document
@@ -15,11 +15,3 @@ class Docstore(ABC):
If page exists, return the page summary, and a Document object.
If page does not exist, return similar entries.
"""
class AddableMixin(ABC):
"""Mixin class that supports adding texts."""
@abstractmethod
def add(self, texts: Dict[str, Document]) -> None:
"""Add more documents."""

View File

@@ -1,7 +1,7 @@
"""Interface for interacting with a document."""
from typing import List
from pydantic import BaseModel, Field
from pydantic import BaseModel
class Document(BaseModel):
@@ -10,7 +10,6 @@ class Document(BaseModel):
page_content: str
lookup_str: str = ""
lookup_index = 0
metadata: dict = Field(default_factory=dict)
@property
def paragraphs(self) -> List[str]:

View File

@@ -1,24 +1,17 @@
"""Simple in memory docstore in the form of a dict."""
from typing import Dict, Union
from langchain.docstore.base import AddableMixin, Docstore
from langchain.docstore.base import Docstore
from langchain.docstore.document import Document
class InMemoryDocstore(Docstore, AddableMixin):
class InMemoryDocstore(Docstore):
"""Simple in memory docstore in the form of a dict."""
def __init__(self, _dict: Dict[str, Document]):
"""Initialize with dict."""
self._dict = _dict
def add(self, texts: Dict[str, Document]) -> None:
"""Add texts to in memory dictionary."""
overlapping = set(texts).intersection(self._dict)
if overlapping:
raise ValueError(f"Tried to add ids that already exist: {overlapping}")
self._dict = dict(self._dict, **texts)
def search(self, search: str) -> Union[str, Document]:
"""Search via direct lookup."""
if search not in self._dict:

View File

@@ -1,12 +1,6 @@
"""Wrappers around embedding modules."""
from langchain.embeddings.cohere import CohereEmbeddings
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
from langchain.embeddings.huggingface_hub import HuggingFaceHubEmbeddings
from langchain.embeddings.openai import OpenAIEmbeddings
__all__ = [
"OpenAIEmbeddings",
"HuggingFaceEmbeddings",
"CohereEmbeddings",
"HuggingFaceHubEmbeddings",
]
__all__ = ["OpenAIEmbeddings", "HuggingFaceEmbeddings", "CohereEmbeddings"]

View File

@@ -5,8 +5,6 @@ from pydantic import BaseModel, Extra
from langchain.embeddings.base import Embeddings
DEFAULT_MODEL_NAME = "sentence-transformers/all-mpnet-base-v2"
class HuggingFaceEmbeddings(BaseModel, Embeddings):
"""Wrapper around sentence_transformers embedding models.
@@ -18,11 +16,11 @@ class HuggingFaceEmbeddings(BaseModel, Embeddings):
from langchain.embeddings import HuggingFaceEmbeddings
model_name = "sentence-transformers/all-mpnet-base-v2"
hf = HuggingFaceEmbeddings(model_name=model_name)
huggingface = HuggingFaceEmbeddings(model_name=model_name)
"""
client: Any #: :meta private:
model_name: str = DEFAULT_MODEL_NAME
model_name: str = "sentence-transformers/all-mpnet-base-v2"
"""Model name to use."""
def __init__(self, **kwargs: Any):

View File

@@ -1,105 +0,0 @@
"""Wrapper around HuggingFace Hub embedding models."""
from typing import Any, Dict, List, Optional
from pydantic import BaseModel, Extra, root_validator
from langchain.embeddings.base import Embeddings
from langchain.utils import get_from_dict_or_env
DEFAULT_REPO_ID = "sentence-transformers/all-mpnet-base-v2"
VALID_TASKS = ("feature-extraction",)
class HuggingFaceHubEmbeddings(BaseModel, Embeddings):
"""Wrapper around HuggingFaceHub embedding models.
To use, you should have the ``huggingface_hub`` python package installed, and the
environment variable ``HUGGINGFACEHUB_API_TOKEN`` set with your API token, or pass
it as a named parameter to the constructor.
Example:
.. code-block:: python
from langchain.embeddings import HuggingFaceHubEmbeddings
repo_id = "sentence-transformers/all-mpnet-base-v2"
hf = HuggingFaceHubEmbeddings(
repo_id=repo_id,
task="feature-extraction",
huggingfacehub_api_token="my-api-key",
)
"""
client: Any #: :meta private:
repo_id: str = DEFAULT_REPO_ID
"""Model name to use."""
task: Optional[str] = "feature-extraction"
"""Task to call the model with."""
model_kwargs: Optional[dict] = None
"""Key word arguments to pass to the model."""
huggingfacehub_api_token: Optional[str] = None
class Config:
"""Configuration for this pydantic object."""
extra = Extra.forbid
@root_validator()
def validate_environment(cls, values: Dict) -> Dict:
"""Validate that api key and python package exists in environment."""
huggingfacehub_api_token = get_from_dict_or_env(
values, "huggingfacehub_api_token", "HUGGINGFACEHUB_API_TOKEN"
)
try:
from huggingface_hub.inference_api import InferenceApi
repo_id = values["repo_id"]
if not repo_id.startswith("sentence-transformers"):
raise ValueError(
"Currently only 'sentence-transformers' embedding models "
f"are supported. Got invalid 'repo_id' {repo_id}."
)
client = InferenceApi(
repo_id=repo_id,
token=huggingfacehub_api_token,
task=values.get("task"),
)
if client.task not in VALID_TASKS:
raise ValueError(
f"Got invalid task {client.task}, "
f"currently only {VALID_TASKS} are supported"
)
values["client"] = client
except ImportError:
raise ValueError(
"Could not import huggingface_hub python package. "
"Please it install it with `pip install huggingface_hub`."
)
return values
def embed_documents(self, texts: List[str]) -> List[List[float]]:
"""Call out to HuggingFaceHub's embedding endpoint for embedding search docs.
Args:
texts: The list of texts to embed.
Returns:
List of embeddings, one for each text.
"""
# replace newlines, which can negatively affect performance.
texts = [text.replace("\n", " ") for text in texts]
_model_kwargs = self.model_kwargs or {}
responses = self.client(inputs=texts, params=_model_kwargs)
return responses
def embed_query(self, text: str) -> List[float]:
"""Call out to HuggingFaceHub's embedding endpoint for embedding query text.
Args:
text: The text to embed.
Returns:
Embeddings for the text.
"""
response = self.embed_documents([text])[0]
return response

View File

@@ -3,21 +3,18 @@ from typing import List
from langchain.chains.llm import LLMChain
from langchain.llms.base import LLM
from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate
from langchain.prompts.dynamic import DynamicPrompt
TEST_GEN_TEMPLATE_SUFFIX = "Add another example."
def generate_example(
examples: List[dict], llm: LLM, prompt_template: PromptTemplate
) -> str:
def generate_example(examples: List[str], llm: LLM) -> str:
"""Return another example given a list of examples for a prompt."""
prompt = FewShotPromptTemplate(
examples=examples,
suffix=TEST_GEN_TEMPLATE_SUFFIX,
input_variables=[],
example_prompt=prompt_template,
)
prompt = DynamicPrompt(examples=examples, suffix=TEST_GEN_TEMPLATE_SUFFIX)
chain = LLMChain(llm=llm, prompt=prompt)
return chain.predict()
def generate_example_from_dynamic_prompt(prompt: DynamicPrompt, llm: LLM) -> str:
"""Return another example given a DynamicPrompt object."""
return generate_example(prompt.examples, llm)

View File

@@ -1,19 +1,14 @@
"""Handle chained inputs."""
from typing import Dict, List, Optional
_TEXT_COLOR_MAPPING = {
"blue": "36;1",
"yellow": "33;1",
"pink": "38;5;200",
"green": "32;1",
}
_COLOR_MAPPING = {"blue": 51, "yellow": 229, "pink": 219, "green": 85}
def get_color_mapping(
items: List[str], excluded_colors: Optional[List] = None
) -> Dict[str, str]:
"""Get mapping for items to a support color."""
colors = list(_TEXT_COLOR_MAPPING.keys())
colors = list(_COLOR_MAPPING.keys())
if excluded_colors is not None:
colors = [c for c in colors if c not in excluded_colors]
color_mapping = {item: colors[i % len(colors)] for i, item in enumerate(items)}
@@ -25,8 +20,8 @@ def print_text(text: str, color: Optional[str] = None, end: str = "") -> None:
if color is None:
print(text, end=end)
else:
color_str = _TEXT_COLOR_MAPPING[color]
print(f"\u001b[{color_str}m\033[1;3m{text}\u001b[0m", end=end)
color_str = _COLOR_MAPPING[color]
print(f"\u001b[48;5;{color_str}m{text}\x1b[0m", end=end)
class ChainedInput:
@@ -34,14 +29,14 @@ class ChainedInput:
def __init__(self, text: str, verbose: bool = False):
"""Initialize with verbose flag and initial text."""
self._verbose = verbose
if self._verbose:
self.verbose = verbose
if self.verbose:
print_text(text, None)
self._input = text
def add(self, text: str, color: Optional[str] = None) -> None:
"""Add text to input, print if in verbose mode."""
if self._verbose:
if self.verbose:
print_text(text, color)
self._input += text

View File

@@ -11,9 +11,9 @@ class LLM(ABC):
"""Run the LLM on the given prompt and input."""
@property
@abstractmethod
def _identifying_params(self) -> Mapping[str, Any]:
"""Get the identifying parameters."""
return {}
def __str__(self) -> str:
"""Get a string representation of the object for printing."""

View File

@@ -51,7 +51,7 @@ class HuggingFaceHub(LLM, BaseModel):
try:
from huggingface_hub.inference_api import InferenceApi
repo_id = values["repo_id"]
repo_id = values.get("repo_id", DEFAULT_REPO_ID)
client = InferenceApi(
repo_id=repo_id,
token=huggingfacehub_api_token,

Some files were not shown because too many files have changed in this diff Show More