Make Tools own model, add ToolKit Concept (#1095)

Follow-up of @hinthornw's PR:

- Migrate the Tool abstraction to a separate file (`BaseTool`).
- `Tool` implementation of `BaseTool` takes in function and coroutine to
more easily maintain backwards compatibility
- Add a Toolkit abstraction that can own the generation of tools around
a shared concept or state

---------

Co-authored-by: William FH <13333726+hinthornw@users.noreply.github.com>
Co-authored-by: Harrison Chase <hw.chase.17@gmail.com>
Co-authored-by: Francisco Ingham <fpingham@gmail.com>
Co-authored-by: Dhruv Anand <105786647+dhruv-anand-aintech@users.noreply.github.com>
Co-authored-by: cragwolfe <cragcw@gmail.com>
Co-authored-by: Anton Troynikov <atroyn@users.noreply.github.com>
Co-authored-by: Oliver Klingefjord <oliver@klingefjord.com>
Co-authored-by: William Fu-Hinthorn <whinthorn@Williams-MBP-3.attlocal.net>
Co-authored-by: Bruno Bornsztein <bruno.bornsztein@gmail.com>
searx-api
Ankush Gola 1 year ago committed by GitHub
parent 45b5640fe5
commit 7b5e160d28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,4 +1,4 @@
.PHONY: all clean format lint test test_watch integration_tests help .PHONY: all clean format lint test tests test_watch integration_tests help
all: help all: help

@ -25,6 +25,7 @@ from langchain.llms.openai import OpenAI
from langchain.agents import initialize_agent, Tool from langchain.agents import initialize_agent, Tool
import os import os
os.environ["SERPER_API_KEY"] = "" os.environ["SERPER_API_KEY"] = ""
os.environ['OPENAI_API_KEY'] = "" os.environ['OPENAI_API_KEY'] = ""

@ -96,12 +96,8 @@
"Thought:\u001b[32;1m\u001b[1;3m I need to find out Jason Sudeikis' age\n", "Thought:\u001b[32;1m\u001b[1;3m I need to find out Jason Sudeikis' age\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Jason Sudeikis age\"\u001b[0m\n", "Action Input: \"Jason Sudeikis age\"\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3mDaniel Jason Sudeikis is an American actor, comedian, writer, and producer. In the 1990s, he began his career in improv comedy and performed with ComedySportz, iO Chicago, and The Second City.\u001b[0m\n", "Observation: \u001b[33;1m\u001b[1;3m47 years\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find out Jason Sudeikis' exact age\n", "Thought:\u001b[32;1m\u001b[1;3m I need to calculate 47 raised to the 0.23 power\n",
"Action: Search\n",
"Action Input: \"Jason Sudeikis age exact\"\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3mDaniel Jason Sudeikis. (1975-09-18) September 18, 1975 (age 47). Fairfax, Virginia, U.S. · Fort Scott Community College · Actor; comedian; producer; writer · 1997 ...\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now have the information I need to calculate the age raised to the 0.23 power\n",
"Action: Calculator\n", "Action: Calculator\n",
"Action Input: 47^0.23\u001b[0m\n", "Action Input: 47^0.23\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.4242784855673896\n", "Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.4242784855673896\n",
@ -116,18 +112,17 @@
"\u001b[32;1m\u001b[1;3m I need to find out who won the grand prix and then calculate their age raised to the 0.23 power.\n", "\u001b[32;1m\u001b[1;3m I need to find out who won the grand prix and then calculate their age raised to the 0.23 power.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Formula 1 Grand Prix Winner\"\u001b[0m\n", "Action Input: \"Formula 1 Grand Prix Winner\"\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3mMax Emilian Verstappen is a Belgian-Dutch racing driver and the 2021 and 2022 Formula One World Champion. He competes under the Dutch flag in Formula One with Red Bull Racing. Verstappen is the son of racing drivers Jos Verstappen, who also competed in Formula One, and Sophie Kumpen.\u001b[0m\n", "Observation: \u001b[33;1m\u001b[1;3mMax Verstappen\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find out Max Emilian Verstappen's age.\n", "Thought:\u001b[32;1m\u001b[1;3m I need to find out Max Verstappen's age\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Max Emilian Verstappen age\"\u001b[0m\n", "Action Input: \"Max Verstappen Age\"\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3m25 years\u001b[0m\n", "Observation: \u001b[33;1m\u001b[1;3m25 years\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now need to calculate 25 raised to the 0.23 power.\n", "Thought:\u001b[32;1m\u001b[1;3m I need to calculate 25 raised to the 0.23 power\n",
"Action: Calculator\n", "Action: Calculator\n",
"Action Input: 25^0.23\u001b[0m\n", "Action Input: 25^0.23\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.096651272316035\n", "Observation: \u001b[36;1m\u001b[1;3mAnswer: 1.84599359907945\u001b[0m\n",
"\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer.\n", "Final Answer: Max Verstappen, 25 years old, raised to the 0.23 power is 1.84599359907945.\u001b[0m\n",
"Final Answer: Max Emilian Verstappen, who is 25 years old, won the most recent Formula 1 Grand Prix and his age raised to the 0.23 power is 2.096651272316035.\u001b[0m\n",
"\n", "\n",
"\u001b[1m> Finished chain.\u001b[0m\n", "\u001b[1m> Finished chain.\u001b[0m\n",
"\n", "\n",
@ -140,14 +135,14 @@
"Thought:\u001b[32;1m\u001b[1;3m I need to find out Bianca Andreescu's age.\n", "Thought:\u001b[32;1m\u001b[1;3m I need to find out Bianca Andreescu's age.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Bianca Andreescu age\"\u001b[0m\n", "Action Input: \"Bianca Andreescu age\"\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3mBianca Vanessa Andreescu is a Canadian-Romanian professional tennis player. She has a career-high ranking of No. 4 in the world, and is the highest-ranked Canadian in the history of the Women's Tennis Association.\u001b[0m\n", "Observation: \u001b[33;1m\u001b[1;3m22 years\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the age of Bianca Andreescu.\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the age of Bianca Andreescu and can calculate her age raised to the 0.34 power.\n",
"Action: Calculator\n", "Action: Calculator\n",
"Action Input: 19^0.34\u001b[0m\n", "Action Input: 22^0.34\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.7212987634680084\n", "Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.8603798598506933\n",
"\u001b[0m\n", "\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer.\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer.\n",
"Final Answer: Bianca Andreescu, aged 19, won the US Open women's final in 2019. Her age raised to the 0.34 power is 2.7212987634680084.\u001b[0m\n", "Final Answer: Bianca Andreescu won the US Open women's final in 2019 and her age raised to the 0.34 power is 2.8603798598506933.\u001b[0m\n",
"\n", "\n",
"\u001b[1m> Finished chain.\u001b[0m\n", "\u001b[1m> Finished chain.\u001b[0m\n",
"\n", "\n",
@ -170,7 +165,7 @@
"Final Answer: Jay-Z is Beyonce's husband and his age raised to the 0.19 power is 2.12624064206896.\u001b[0m\n", "Final Answer: Jay-Z is Beyonce's husband and his age raised to the 0.19 power is 2.12624064206896.\u001b[0m\n",
"\n", "\n",
"\u001b[1m> Finished chain.\u001b[0m\n", "\u001b[1m> Finished chain.\u001b[0m\n",
"Serial executed in 94.83 seconds.\n" "Serial executed in 65.11 seconds.\n"
] ]
} }
], ],
@ -217,96 +212,91 @@
"\n", "\n",
"\n", "\n",
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001b[33;1m\u001b[1;3m I need to find out who Beyonce's husband is and then calculate his age raised to the 0.19 power.\n", "\u001b[32;1m\u001b[1;3m I need to find out who Olivia Wilde's boyfriend is and then calculate his age raised to the 0.23 power.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Who is Beyonce's husband?\"\u001b[0m\u001b[31;1m\u001b[1;3m I need to find out who won the grand prix and then calculate their age raised to the 0.23 power.\n", "Action Input: \"Olivia Wilde boyfriend\"\u001b[0m\u001b[32;1m\u001b[1;3m I need to find out who Beyonce's husband is and then calculate his age raised to the 0.19 power.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Formula 1 Grand Prix Winner\"\u001b[0m\u001b[32;1m\u001b[1;3m I need to find out who Olivia Wilde's boyfriend is and then calculate his age raised to the 0.23 power.\n", "Action Input: \"Who is Beyonce's husband?\"\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3mJay-Z\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find out who won the grand prix and then calculate their age raised to the 0.23 power.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Olivia Wilde boyfriend\"\u001b[0m\u001b[38;5;200m\u001b[1;3m I need to find out who won the US Open women's final in 2019 and then calculate her age raised to the 0.34 power.\n", "Action Input: \"Formula 1 Grand Prix Winner\"\u001b[0m\u001b[32;1m\u001b[1;3m I need to find out who won the US Open women's final in 2019 and then calculate her age raised to the 0.34 power.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"US Open women's final 2019 winner\"\u001b[0m\n", "Action Input: \"US Open women's final 2019 winner\"\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3mJay-Z\u001b[0m\n",
"Thought:\n",
"Observation: \u001b[33;1m\u001b[1;3mMax Emilian Verstappen is a Belgian-Dutch racing driver and the 2021 and 2022 Formula One World Champion. He competes under the Dutch flag in Formula One with Red Bull Racing. Verstappen is the son of racing drivers Jos Verstappen, who also competed in Formula One, and Sophie Kumpen.\u001b[0m\n",
"Thought:\n",
"Observation: \u001b[33;1m\u001b[1;3mJason Sudeikis\u001b[0m\n", "Observation: \u001b[33;1m\u001b[1;3mJason Sudeikis\u001b[0m\n",
"Thought:\n", "Thought:\n",
"Observation: \u001b[33;1m\u001b[1;3mMax Verstappen\u001b[0m\n",
"Thought:\n",
"Observation: \u001b[33;1m\u001b[1;3mBianca Andreescu defeated Serena Williams in the final, 63, 75 to win the women's singles tennis title at the 2019 US Open. It was her first major title, and she became the first Canadian, as well as the first player born in the 2000s, to win a major singles title.\u001b[0m\n", "Observation: \u001b[33;1m\u001b[1;3mBianca Andreescu defeated Serena Williams in the final, 63, 75 to win the women's singles tennis title at the 2019 US Open. It was her first major title, and she became the first Canadian, as well as the first player born in the 2000s, to win a major singles title.\u001b[0m\n",
"Thought:\u001b[31;1m\u001b[1;3m I need to find out Max Emilian Verstappen's age.\n", "Thought:\u001b[32;1m\u001b[1;3m I need to find out Jason Sudeikis' age\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Max Emilian Verstappen age\"\u001b[0m\n", "Action Input: \"Jason Sudeikis age\"\u001b[0m\u001b[32;1m\u001b[1;3m I need to find out Jay-Z's age\n",
"Observation: \u001b[33;1m\u001b[1;3m25 years\u001b[0m\n",
"Thought:\u001b[38;5;200m\u001b[1;3m I need to find out Bianca Andreescu's age.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Bianca Andreescu age\"\u001b[0m\n", "Action Input: \"How old is Jay-Z?\"\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3mBianca Vanessa Andreescu is a Canadian-Romanian professional tennis player. She has a career-high ranking of No. 4 in the world, and is the highest-ranked Canadian in the history of the Women's Tennis Association.\u001b[0m\n", "Observation: \u001b[33;1m\u001b[1;3m53 years\u001b[0m\n",
"Thought:\u001b[36;1m\u001b[1;3m I need to find out who won the US Open men's final in 2019 and then calculate his age raised to the 0.334 power.\n", "Thought:\u001b[32;1m\u001b[1;3m I need to find out who won the US Open men's final in 2019 and then calculate his age raised to the 0.334 power.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"US Open men's final 2019 winner\"\u001b[0m\n", "Action Input: \"US Open men's final 2019 winner\"\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3mRafael Nadal\u001b[0m\n", "Observation: \u001b[33;1m\u001b[1;3mRafael Nadal defeated Daniil Medvedev in the final, 75, 63, 57, 46, 64 to win the men's singles tennis title at the 2019 US Open. It was his fourth US ...\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find out Jason Sudeikis' age\n", "Thought:\n",
"Action: Search\n", "Observation: \u001b[33;1m\u001b[1;3m47 years\u001b[0m\n",
"Action Input: \"Jason Sudeikis age\"\u001b[0m\n", "Thought:\u001b[32;1m\u001b[1;3m I need to find out Max Verstappen's age\n",
"Observation: \u001b[33;1m\u001b[1;3mDaniel Jason Sudeikis is an American actor, comedian, writer, and producer. In the 1990s, he began his career in improv comedy and performed with ComedySportz, iO Chicago, and The Second City.\u001b[0m\n",
"Thought:\u001b[33;1m\u001b[1;3m I need to find out Jay-Z's age\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"How old is Jay-Z?\"\u001b[0m\u001b[36;1m\u001b[1;3m I need to find out Rafael Nadal's age\n", "Action Input: \"Max Verstappen Age\"\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3m25 years\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find out Bianca Andreescu's age.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Rafael Nadal age\"\u001b[0m\n", "Action Input: \"Bianca Andreescu age\"\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3m36 years\u001b[0m\n", "Observation: \u001b[33;1m\u001b[1;3m22 years\u001b[0m\n",
"Thought:\n", "Thought:\u001b[32;1m\u001b[1;3m I need to calculate 53 raised to the 0.19 power\n",
"Observation: \u001b[33;1m\u001b[1;3m53 years\u001b[0m\n",
"Thought:\u001b[38;5;200m\u001b[1;3m I now know the age of Bianca Andreescu.\n",
"Action: Calculator\n",
"Action Input: 19^0.34\u001b[0m\u001b[31;1m\u001b[1;3m I now need to calculate 25 raised to the 0.23 power.\n",
"Action: Calculator\n", "Action: Calculator\n",
"Action Input: 25^0.23\u001b[0m\n", "Action Input: 53^0.19\u001b[0m\u001b[32;1m\u001b[1;3m I need to find out the age of the winner\n",
"Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.7212987634680084\n",
"\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find out Jason Sudeikis' exact age\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Jason Sudeikis age exact\"\u001b[0m\u001b[33;1m\u001b[1;3m I need to calculate 53 raised to the 0.19 power\n", "Action Input: \"Rafael Nadal age\"\u001b[0m\u001b[32;1m\u001b[1;3m I need to calculate 47 raised to the 0.23 power\n",
"Action: Calculator\n", "Action: Calculator\n",
"Action Input: 53^0.19\u001b[0m\u001b[36;1m\u001b[1;3m I need to calculate 36 raised to the 0.334 power\n", "Action Input: 47^0.23\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3m36 years\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to calculate 25 raised to the 0.23 power\n",
"Action: Calculator\n", "Action: Calculator\n",
"Action Input: 36^0.334\u001b[0m\n", "Action Input: 25^0.23\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3mDaniel Jason Sudeikis. (1975-09-18) September 18, 1975 (age 47). Fairfax, Virginia, U.S. · Fort Scott Community College · Actor; comedian; producer; writer · 1997 ...\u001b[0m\n",
"Thought:\n",
"Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.096651272316035\n",
"\u001b[0m\n",
"Thought:\n",
"Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.12624064206896\n", "Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.12624064206896\n",
"\u001b[0m\n", "\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the age of Bianca Andreescu and can calculate her age raised to the 0.34 power.\n",
"Action: Calculator\n",
"Action Input: 22^0.34\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mAnswer: 1.84599359907945\u001b[0m\n",
"Thought:\n", "Thought:\n",
"Observation: \u001b[36;1m\u001b[1;3mAnswer: 3.3098250249682484\n", "Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.4242784855673896\n",
"\u001b[0m\n", "\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now have the information I need to calculate the age raised to the 0.23 power\n", "Thought:\u001b[32;1m\u001b[1;3m I now need to calculate his age raised to the 0.334 power\n",
"Action: Calculator\n", "Action: Calculator\n",
"Action Input: 47^0.23\u001b[0m\n", "Action Input: 36^0.334\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.4242784855673896\n", "Observation: \u001b[36;1m\u001b[1;3mAnswer: 2.8603798598506933\n",
"\u001b[0m\n", "\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer.\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: Bianca Andreescu, aged 19, won the US Open women's final in 2019. Her age raised to the 0.34 power is 2.7212987634680084.\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: Jay-Z is Beyonce's husband and his age raised to the 0.19 power is 2.12624064206896.\u001b[0m\n", "Final Answer: Jay-Z is Beyonce's husband and his age raised to the 0.19 power is 2.12624064206896.\u001b[0m\n",
"\n", "\n",
"\u001b[1m> Finished chain.\u001b[0m\n", "\u001b[1m> Finished chain.\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m I now know the final answer\n", "\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: Rafael Nadal, aged 36, won the US Open men's final in 2019 and his age raised to the 0.334 power is 3.3098250249682484.\u001b[0m\n", "Final Answer: Max Verstappen, 25 years old, raised to the 0.23 power is 1.84599359907945.\u001b[0m\n",
"\n", "\n",
"\u001b[1m> Finished chain.\u001b[0m\n", "\u001b[1m> Finished chain.\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m I now know the final answer\n", "\n",
"Observation: \u001b[36;1m\u001b[1;3mAnswer: 3.3098250249682484\n",
"\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: Jason Sudeikis, Olivia Wilde's boyfriend, is 47 years old and his age raised to the 0.23 power is 2.4242784855673896.\u001b[0m\n", "Final Answer: Jason Sudeikis, Olivia Wilde's boyfriend, is 47 years old and his age raised to the 0.23 power is 2.4242784855673896.\u001b[0m\n",
"\n", "\n",
"\u001b[1m> Finished chain.\u001b[0m\n", "\u001b[1m> Finished chain.\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m I now know the final answer.\n", "\u001b[32;1m\u001b[1;3m I now know the final answer.\n",
"Final Answer: Max Emilian Verstappen, who is 25 years old, won the most recent Formula 1 Grand Prix and his age raised to the 0.23 power is 2.096651272316035.\u001b[0m\n", "Final Answer: Bianca Andreescu won the US Open women's final in 2019 and her age raised to the 0.34 power is 2.8603798598506933.\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: Rafael Nadal, aged 36, won the US Open men's final in 2019 and his age raised to the 0.334 power is 3.3098250249682484.\u001b[0m\n",
"\n", "\n",
"\u001b[1m> Finished chain.\u001b[0m\n", "\u001b[1m> Finished chain.\u001b[0m\n",
"Concurrent executed in 25.06 seconds.\n" "Concurrent executed in 12.38 seconds.\n"
] ]
} }
], ],
@ -316,12 +306,10 @@
" # To make async requests in Tools more efficient, you can pass in your own aiohttp.ClientSession, \n", " # To make async requests in Tools more efficient, you can pass in your own aiohttp.ClientSession, \n",
" # but you must manually close the client session at the end of your program/event loop\n", " # but you must manually close the client session at the end of your program/event loop\n",
" aiosession = ClientSession()\n", " aiosession = ClientSession()\n",
" colors = [\"blue\", \"green\", \"red\", \"pink\", \"yellow\"]\n", " for _ in questions:\n",
" for color in colors:\n", " manager = CallbackManager([StdOutCallbackHandler()])\n",
" # Use a custom CallbackManager to print in different colors.\n",
" manager = CallbackManager([StdOutCallbackHandler(color=color)])\n",
" llm = OpenAI(temperature=0, callback_manager=manager)\n", " llm = OpenAI(temperature=0, callback_manager=manager)\n",
" async_tools = load_tools([\"llm-math\", \"serpapi\"], llm=llm, aiosession=aiosession)\n", " async_tools = load_tools([\"llm-math\", \"serpapi\"], llm=llm, aiosession=aiosession, callback_manager=manager)\n",
" agents.append(\n", " agents.append(\n",
" initialize_agent(async_tools, llm, agent=\"zero-shot-react-description\", verbose=True, callback_manager=manager)\n", " initialize_agent(async_tools, llm, agent=\"zero-shot-react-description\", verbose=True, callback_manager=manager)\n",
" )\n", " )\n",
@ -415,7 +403,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.10.9" "version": "3.9.1"
} }
}, },
"nbformat": 4, "nbformat": 4,

@ -42,7 +42,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 23,
"id": "9af9734e", "id": "9af9734e",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -53,7 +53,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 24,
"id": "becda2a1", "id": "becda2a1",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -70,7 +70,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 25,
"id": "339b1bb8", "id": "339b1bb8",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -99,7 +99,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 26,
"id": "e21d2098", "id": "e21d2098",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -145,7 +145,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 27,
"id": "9b1cc2a2", "id": "9b1cc2a2",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -155,7 +155,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 28,
"id": "e4f5092f", "id": "e4f5092f",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -166,7 +166,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 8, "execution_count": 29,
"id": "490604e9", "id": "490604e9",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -176,7 +176,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 9, "execution_count": 31,
"id": "653b1617", "id": "653b1617",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -187,16 +187,12 @@
"\n", "\n",
"\n", "\n",
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001b[32;1m\u001b[1;3mThought: I need to find out how many people live in Canada\n", "\u001b[32;1m\u001b[1;3mThought: I need to find out the population of Canada\n",
"Action: Search\n", "Action: Search\n",
"Action Input: Population of Canada\u001b[0m\n", "Action Input: Population of Canada 2023\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mCanada is a country in North America. Its ten provinces and three territories extend from the Atlantic Ocean to the Pacific Ocean and northward into the Arctic Ocean, covering over 9.98 million square kilometres, making it the world's second-largest country by total area.\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3mThe current population of Canada is 38,610,447 as of Saturday, February 18, 2023, based on Worldometer elaboration of the latest United Nations data. Canada 2020 population is estimated at 37,742,154 people at mid year according to UN data.\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find out the population of Canada\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Action: Search\n", "Final Answer: Arrr, Canada be havin' 38,610,447 scallywags livin' there as of 2023!\u001b[0m\n",
"Action Input: Population of Canada\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mCanada is a country in North America. Its ten provinces and three territories extend from the Atlantic Ocean to the Pacific Ocean and northward into the Arctic Ocean, covering over 9.98 million square kilometres, making it the world's second-largest country by total area.\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the population of Canada\n",
"Final Answer: Arrr, Canada be home to over 37 million people!\u001b[0m\n",
"\n", "\n",
"\u001b[1m> Finished chain.\u001b[0m\n" "\u001b[1m> Finished chain.\u001b[0m\n"
] ]
@ -204,16 +200,16 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"'Arrr, Canada be home to over 37 million people!'" "\"Arrr, Canada be havin' 38,610,447 scallywags livin' there as of 2023!\""
] ]
}, },
"execution_count": 9, "execution_count": 31,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
], ],
"source": [ "source": [
"agent_executor.run(\"How many people live in canada?\")" "agent_executor.run(\"How many people live in canada as of 2023?\")"
] ]
}, },
{ {
@ -227,7 +223,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 20, "execution_count": 32,
"id": "43dbfa2f", "id": "43dbfa2f",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -248,7 +244,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 21, "execution_count": 33,
"id": "0f087313", "id": "0f087313",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -258,7 +254,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 22, "execution_count": 34,
"id": "92c75a10", "id": "92c75a10",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -268,7 +264,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 23, "execution_count": 35,
"id": "ac5b83bf", "id": "ac5b83bf",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -278,7 +274,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 24, "execution_count": 36,
"id": "c960e4ff", "id": "c960e4ff",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -289,56 +285,29 @@
"\n", "\n",
"\n", "\n",
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001b[32;1m\u001b[1;3mThought: I should look up the population of Canada.\n", "\u001b[32;1m\u001b[1;3mThought: I need to find out the population of Canada in 2023.\n",
"Action: Search\n",
"Action Input: Population of Canada\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mCanada is a country in North America. Its ten provinces and three territories extend from the Atlantic Ocean to the Pacific Ocean and northward into the Arctic Ocean, covering over 9.98 million square kilometres, making it the world's second-largest country by total area.\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I should look for the population of Canada.\n",
"Action: Search\n",
"Action Input: Population of Canada\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mCanada is a country in North America. Its ten provinces and three territories extend from the Atlantic Ocean to the Pacific Ocean and northward into the Arctic Ocean, covering over 9.98 million square kilometres, making it the world's second-largest country by total area.\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I should look for the population of Canada.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: Population of Canada\u001b[0m\n", "Action Input: Population of Canada in 2023\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mCanada is a country in North America. Its ten provinces and three territories extend from the Atlantic Ocean to the Pacific Ocean and northward into the Arctic Ocean, covering over 9.98 million square kilometres, making it the world's second-largest country by total area.\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3mThe current population of Canada is 38,610,447 as of Saturday, February 18, 2023, based on Worldometer elaboration of the latest United Nations data. Canada 2020 population is estimated at 37,742,154 people at mid year according to UN data.\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I should look for the population of Canada.\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer.\n",
"Action: Search\n", "Final Answer: La popolazione del Canada nel 2023 è stimata in 38.610.447 persone.\u001b[0m\n",
"Action Input: Population of Canada\u001b[0m\n", "\n",
"Observation: \u001b[36;1m\u001b[1;3mCanada is a country in North America. Its ten provinces and three territories extend from the Atlantic Ocean to the Pacific Ocean and northward into the Arctic Ocean, covering over 9.98 million square kilometres, making it the world's second-largest country by total area.\u001b[0m\n", "\u001b[1m> Finished chain.\u001b[0m\n"
"Thought:\u001b[32;1m\u001b[1;3m I should look for the population of Canada.\n",
"Action: Search\n",
"Action Input: Population of Canada\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mCanada is a country in North America. Its ten provinces and three territories extend from the Atlantic Ocean to the Pacific Ocean and northward into the Arctic Ocean, covering over 9.98 million square kilometres, making it the world's second-largest country by total area.\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I should look for the population of Canada.\n",
"Action: Search\n",
"Action Input: Population of Canada\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mCanada is a country in North America. Its ten provinces and three territories extend from the Atlantic Ocean to the Pacific Ocean and northward into the Arctic Ocean, covering over 9.98 million square kilometres, making it the world's second-largest country by total area.\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I should look for the population of Canada.\n",
"Action: Search\n",
"Action Input: Population of Canada\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mCanada is a country in North America. Its ten provinces and three territories extend from the Atlantic Ocean to the Pacific Ocean and northward into the Arctic Ocean, covering over 9.98 million square kilometres, making it the world's second-largest country by total area.\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I should look for the population of Canada.\n",
"Action: Search\n",
"Action Input: Population of Canada\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mCanada is a country in North America. Its ten provinces and three territories extend from the Atlantic Ocean to the Pacific Ocean and northward into the Arctic Ocean, covering over 9.98 million square kilometres, making it the world's second-largest country by total area.\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the population of Canada.\n",
"Final Answer: La popolazione del Canada è di circa 37 milioni di persone.\u001b[0m\n",
"\u001b[1m> Finished AgentExecutor chain.\u001b[0m\n"
] ]
}, },
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"'La popolazione del Canada è di circa 37 milioni di persone.'" "'La popolazione del Canada nel 2023 è stimata in 38.610.447 persone.'"
] ]
}, },
"execution_count": 24, "execution_count": 36,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
], ],
"source": [ "source": [
"agent_executor.run(input=\"How many people live in canada?\", language=\"italian\")" "agent_executor.run(input=\"How many people live in canada as of 2023?\", language=\"italian\")"
] ]
}, },
{ {
@ -376,7 +345,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.10.9" "version": "3.9.1"
}, },
"vscode": { "vscode": {
"interpreter": { "interpreter": {

@ -7,31 +7,27 @@
"source": [ "source": [
"# Defining Custom Tools\n", "# Defining Custom Tools\n",
"\n", "\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", "When constructing your own agent, you will need to provide it with a list of Tools that it can use. Besides the actual function that is called, the Tool consists of several components:\n",
"\n", "\n",
"```python\n", "- name (str), is required\n",
"@dataclass \n", "- description (str), is optional\n",
"class Tool:\n", "- return_direct (bool), defaults to False\n",
" \"\"\"Interface for tools.\"\"\"\n",
"\n", "\n",
" name: str\n", "The function that should be called when the tool is selected should take as input a single string and return a single string.\n",
" func: Callable[[str], str]\n",
" description: Optional[str] = None\n",
" return_direct: bool = True\n",
"```\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. You can create these tools directly, but we also provide a decorator to easily convert any function into a tool." "There are two ways to define a tool, we will cover both in the example below."
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 2,
"id": "1aaba18c", "id": "1aaba18c",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"# Import things that are needed generically\n", "# Import things that are needed generically\n",
"from langchain.agents import initialize_agent, Tool\n", "from langchain.agents import initialize_agent, Tool\n",
"from langchain.tools import BaseTool\n",
"from langchain.llms import OpenAI\n", "from langchain.llms import OpenAI\n",
"from langchain import LLMMathChain, SerpAPIWrapper" "from langchain import LLMMathChain, SerpAPIWrapper"
] ]
@ -46,7 +42,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 3,
"id": "36ed392e", "id": "36ed392e",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -59,8 +55,18 @@
"id": "f8bc72c2", "id": "f8bc72c2",
"metadata": {}, "metadata": {},
"source": [ "source": [
"## Completely New Tools\n", "## Completely New Tools \n",
"First, we show how to create completely new tools from scratch." "First, we show how to create completely new tools from scratch.\n",
"\n",
"There are two ways to do this: either by using the Tool dataclass, or by subclassing the BaseTool class."
]
},
{
"cell_type": "markdown",
"id": "b63fcc3b",
"metadata": {},
"source": [
"### Tool dataclass"
] ]
}, },
{ {
@ -89,7 +95,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 4,
"id": "5b93047d", "id": "5b93047d",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -101,7 +107,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 5,
"id": "6f96a891", "id": "6f96a891",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -112,45 +118,161 @@
"\n", "\n",
"\n", "\n",
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m I need to find out who Olivia Wilde's boyfriend is and then calculate his age raised to the 0.23 power.\n", "\u001b[32;1m\u001b[1;3m I need to find out who Leo DiCaprio's girlfriend is and then calculate her age raised to the 0.43 power.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: Olivia Wilde's boyfriend\u001b[0m\n", "Action Input: \"Leo DiCaprio girlfriend\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mHarry Styles\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3mCamila Morrone\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to calculate Harry Styles' age raised to the 0.23 power.\n", "Thought:\u001b[32;1m\u001b[1;3m I now need to calculate her age raised to the 0.43 power\n",
"Action: Calculator\n", "Action: Calculator\n",
"Action Input: 23^0.23\u001b[0m\n", "Action Input: 22^0.43\u001b[0m\n",
"\n", "\n",
"\u001b[1m> Entering new LLMMathChain chain...\u001b[0m\n", "\u001b[1m> Entering new LLMMathChain chain...\u001b[0m\n",
"23^0.23\u001b[32;1m\u001b[1;3m\n", "22^0.43\u001b[32;1m\u001b[1;3m\n",
"```python\n", "```python\n",
"import math\n", "import math\n",
"print(math.pow(23, 0.23))\n", "print(math.pow(22, 0.43))\n",
"```\n", "```\n",
"\u001b[0m\n", "\u001b[0m\n",
"Answer: \u001b[33;1m\u001b[1;3m2.0568252837687546\n", "Answer: \u001b[33;1m\u001b[1;3m3.777824273683966\n",
"\u001b[0m\n", "\u001b[0m\n",
"\u001b[1m> Finished LLMMathChain chain.\u001b[0m\n", "\u001b[1m> Finished chain.\u001b[0m\n",
"\n", "\n",
"Observation: \u001b[33;1m\u001b[1;3mAnswer: 2.0568252837687546\n", "Observation: \u001b[33;1m\u001b[1;3mAnswer: 3.777824273683966\n",
"\u001b[0m\n", "\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer.\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: Harry Styles' age raised to the 0.23 power is 2.0568252837687546.\u001b[0m\n", "Final Answer: Camila Morrone's age raised to the 0.43 power is 3.777824273683966.\u001b[0m\n",
"\u001b[1m> Finished AgentExecutor chain.\u001b[0m\n" "\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
] ]
}, },
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"\"Harry Styles' age raised to the 0.23 power is 2.0568252837687546.\"" "\"Camila Morrone's age raised to the 0.43 power is 3.777824273683966.\""
] ]
}, },
"execution_count": 7, "execution_count": 5,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
], ],
"source": [ "source": [
"agent.run(\"Who is Olivia Wilde's boyfriend? What is his current age raised to the 0.23 power?\")" "agent.run(\"Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?\")"
]
},
{
"cell_type": "markdown",
"id": "6f12eaf0",
"metadata": {},
"source": [
"### Subclassing the BaseTool class"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "c58a7c40",
"metadata": {},
"outputs": [],
"source": [
"class CustomSearchTool(BaseTool):\n",
" name = \"Search\"\n",
" description = \"useful for when you need to answer questions about current events\"\n",
"\n",
" def _run(self, query: str) -> str:\n",
" \"\"\"Use the tool.\"\"\"\n",
" return search.run(query)\n",
" \n",
" async def _arun(self, query: str) -> str:\n",
" \"\"\"Use the tool asynchronously.\"\"\"\n",
" raise NotImplementedError(\"BingSearchRun does not support async\")\n",
" \n",
"class CustomCalculatorTool(BaseTool):\n",
" name = \"Calculator\"\n",
" description = \"useful for when you need to answer questions about math\"\n",
"\n",
" def _run(self, query: str) -> str:\n",
" \"\"\"Use the tool.\"\"\"\n",
" return llm_math_chain.run(query)\n",
" \n",
" async def _arun(self, query: str) -> str:\n",
" \"\"\"Use the tool asynchronously.\"\"\"\n",
" raise NotImplementedError(\"BingSearchRun does not support async\")"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "3318a46f",
"metadata": {},
"outputs": [],
"source": [
"tools = [CustomSearchTool(), CustomCalculatorTool()]"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "ee2d0f3a",
"metadata": {},
"outputs": [],
"source": [
"agent = initialize_agent(tools, llm, agent=\"zero-shot-react-description\", verbose=True)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "6a2cebbf",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"\n",
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m I need to find out who Leo DiCaprio's girlfriend is and then calculate her age raised to the 0.43 power.\n",
"Action: Search\n",
"Action Input: \"Leo DiCaprio girlfriend\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mCamila Morrone\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now need to calculate her age raised to the 0.43 power\n",
"Action: Calculator\n",
"Action Input: 22^0.43\u001b[0m\n",
"\n",
"\u001b[1m> Entering new LLMMathChain chain...\u001b[0m\n",
"22^0.43\u001b[32;1m\u001b[1;3m\n",
"```python\n",
"import math\n",
"print(math.pow(22, 0.43))\n",
"```\n",
"\u001b[0m\n",
"Answer: \u001b[33;1m\u001b[1;3m3.777824273683966\n",
"\u001b[0m\n",
"\u001b[1m> Finished chain.\u001b[0m\n",
"\n",
"Observation: \u001b[33;1m\u001b[1;3mAnswer: 3.777824273683966\n",
"\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: Camila Morrone's age raised to the 0.43 power is 3.777824273683966.\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
]
},
{
"data": {
"text/plain": [
"\"Camila Morrone's age raised to the 0.43 power is 3.777824273683966.\""
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"agent.run(\"Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?\")"
] ]
}, },
{ {
@ -165,7 +287,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 4,
"id": "8f15307d", "id": "8f15307d",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -180,17 +302,17 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 5,
"id": "0a23b91b", "id": "0a23b91b",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Tool(name='search_api', func=<function search_api at 0x10dad7d90>, description='search_api(query: str) -> str - Searches the API for the query.', return_direct=False)" "Tool(name='search_api', description='search_api(query: str) -> str - Searches the API for the query.', return_direct=False, verbose=False, callback_manager=<langchain.callbacks.shared.SharedCallbackManager object at 0x1184e0cd0>, func=<function search_api at 0x1635f8700>, coroutine=None)"
] ]
}, },
"execution_count": 2, "execution_count": 5,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -209,7 +331,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 6,
"id": "28cdf04d", "id": "28cdf04d",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -222,17 +344,17 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 7,
"id": "1085a4bd", "id": "1085a4bd",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"Tool(name='search', func=<function search_api at 0x112301bd0>, description='search(query: str) -> str - Searches the API for the query.', return_direct=True)" "Tool(name='search', description='search(query: str) -> str - Searches the API for the query.', return_direct=True, verbose=False, callback_manager=<langchain.callbacks.shared.SharedCallbackManager object at 0x1184e0cd0>, func=<function search_api at 0x1635f8670>, coroutine=None)"
] ]
}, },
"execution_count": 4, "execution_count": 7,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -304,28 +426,29 @@
"\n", "\n",
"\n", "\n",
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m I need to find out who Olivia Wilde's boyfriend is and then calculate his age raised to the 0.23 power.\n", "\u001b[32;1m\u001b[1;3m I need to find out who Leo DiCaprio's girlfriend is and then calculate her age raised to the 0.43 power.\n",
"Action: Google Search\n", "Action: Google Search\n",
"Action Input: \"Olivia Wilde boyfriend\"\u001b[0m\n", "Action Input: \"Leo DiCaprio girlfriend\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mHarry Styles\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3mCamila Morrone\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find out Harry Styles' age\n", "Thought:\u001b[32;1m\u001b[1;3m I need to find out Camila Morrone's age\n",
"Action: Google Search\n", "Action: Google Search\n",
"Action Input: \"Harry Styles age\"\u001b[0m\n", "Action Input: \"Camila Morrone age\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3m28 years\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3m25 years\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to calculate 28 raised to the 0.23 power\n", "Thought:\u001b[32;1m\u001b[1;3m I need to calculate 25 raised to the 0.43 power\n",
"Action: Calculator\n", "Action: Calculator\n",
"Action Input: 28^0.23\u001b[0m\n", "Action Input: 25^0.43\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3mAnswer: 2.1520202182226886\n", "Observation: \u001b[33;1m\u001b[1;3mAnswer: 3.991298452658078\n",
"\u001b[0m\n", "\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: Harry Styles is Olivia Wilde's boyfriend and his current age raised to the 0.23 power is 2.1520202182226886.\u001b[0m\n", "Final Answer: Camila Morrone is Leo DiCaprio's girlfriend and her current age raised to the 0.43 power is 3.991298452658078.\u001b[0m\n",
"\u001b[1m> Finished AgentExecutor chain.\u001b[0m\n" "\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
] ]
}, },
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"\"Harry Styles is Olivia Wilde's boyfriend and his current age raised to the 0.23 power is 2.1520202182226886.\"" "\"Camila Morrone is Leo DiCaprio's girlfriend and her current age raised to the 0.43 power is 3.991298452658078.\""
] ]
}, },
"execution_count": 12, "execution_count": 12,
@ -334,7 +457,7 @@
} }
], ],
"source": [ "source": [
"agent.run(\"Who is Olivia Wilde's boyfriend? What is his current age raised to the 0.23 power?\")" "agent.run(\"Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?\")"
] ]
}, },
{ {
@ -354,7 +477,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 13,
"id": "3450512e", "id": "3450512e",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -382,7 +505,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 8, "execution_count": 14,
"id": "4b9a7849", "id": "4b9a7849",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -409,7 +532,7 @@
"\"'All I Want For Christmas Is You' by Mariah Carey.\"" "\"'All I Want For Christmas Is You' by Mariah Carey.\""
] ]
}, },
"execution_count": 8, "execution_count": 14,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -429,7 +552,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 15,
"id": "3bb6185f", "id": "3bb6185f",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -447,7 +570,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 16,
"id": "113ddb84", "id": "113ddb84",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -458,7 +581,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 17,
"id": "582439a6", "id": "582439a6",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -484,7 +607,7 @@
"'Answer: 1.2599210498948732'" "'Answer: 1.2599210498948732'"
] ]
}, },
"execution_count": 5, "execution_count": 17,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -518,7 +641,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.10.9" "version": "3.9.1"
}, },
"vscode": { "vscode": {
"interpreter": { "interpreter": {

@ -32,7 +32,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 2,
"id": "36ed392e", "id": "36ed392e",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -51,7 +51,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 3,
"id": "6abf3b08", "id": "6abf3b08",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -72,23 +72,28 @@
"\n", "\n",
"\n", "\n",
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m I should look up Olivia Wilde's boyfriend's age\n", "\u001b[32;1m\u001b[1;3m I should look up who Leo DiCaprio is dating\n",
"Action: Search\n",
"Action Input: \"Leo DiCaprio girlfriend\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mCamila Morrone\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I should look up how old Camila Morrone is\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Olivia Wilde's boyfriend's age\"\u001b[0m\n", "Action Input: \"Camila Morrone age\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3m28 years\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3m25 years\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I should use the calculator to raise that number to the 0.23 power\n", "Thought:\u001b[32;1m\u001b[1;3m I should calculate what 25 years raised to the 0.43 power is\n",
"Action: Calculator\n", "Action: Calculator\n",
"Action Input: 28^0.23\u001b[0m\n", "Action Input: 25^0.43\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3mAnswer: 2.1520202182226886\n", "Observation: \u001b[33;1m\u001b[1;3mAnswer: 3.991298452658078\n",
"\u001b[0m\n", "\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: 2.1520202182226886\u001b[0m\n", "Final Answer: Camila Morrone is Leo DiCaprio's girlfriend and she is 3.991298452658078 years old.\u001b[0m\n",
"\u001b[1m> Finished AgentExecutor chain.\u001b[0m\n" "\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
] ]
} }
], ],
"source": [ "source": [
"response = agent({\"input\":\"How old is Olivia Wilde's boyfriend? What is that number raised to the 0.23 power?\"})" "response = agent({\"input\":\"Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?\"})"
] ]
}, },
{ {
@ -101,7 +106,7 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"[(AgentAction(tool='Search', tool_input=\"Olivia Wilde's boyfriend's age\", log=' I should look up Olivia Wilde\\'s boyfriend\\'s age\\nAction: Search\\nAction Input: \"Olivia Wilde\\'s boyfriend\\'s age\"'), '28 years'), (AgentAction(tool='Calculator', tool_input='28^0.23', log=' I should use the calculator to raise that number to the 0.23 power\\nAction: Calculator\\nAction Input: 28^0.23'), 'Answer: 2.1520202182226886\\n')]\n" "[(AgentAction(tool='Search', tool_input='Leo DiCaprio girlfriend', log=' I should look up who Leo DiCaprio is dating\\nAction: Search\\nAction Input: \"Leo DiCaprio girlfriend\"'), 'Camila Morrone'), (AgentAction(tool='Search', tool_input='Camila Morrone age', log=' I should look up how old Camila Morrone is\\nAction: Search\\nAction Input: \"Camila Morrone age\"'), '25 years'), (AgentAction(tool='Calculator', tool_input='25^0.43', log=' I should calculate what 25 years raised to the 0.43 power is\\nAction: Calculator\\nAction Input: 25^0.43'), 'Answer: 3.991298452658078\\n')]\n"
] ]
} }
], ],
@ -124,18 +129,26 @@
" [\n", " [\n",
" [\n", " [\n",
" \"Search\",\n", " \"Search\",\n",
" \"Olivia Wilde's boyfriend's age\",\n", " \"Leo DiCaprio girlfriend\",\n",
" \" I should look up Olivia Wilde's boyfriend's age\\nAction: Search\\nAction Input: \\\"Olivia Wilde's boyfriend's age\\\"\"\n", " \" I should look up who Leo DiCaprio is dating\\nAction: Search\\nAction Input: \\\"Leo DiCaprio girlfriend\\\"\"\n",
" ],\n",
" \"Camila Morrone\"\n",
" ],\n",
" [\n",
" [\n",
" \"Search\",\n",
" \"Camila Morrone age\",\n",
" \" I should look up how old Camila Morrone is\\nAction: Search\\nAction Input: \\\"Camila Morrone age\\\"\"\n",
" ],\n", " ],\n",
" \"28 years\"\n", " \"25 years\"\n",
" ],\n", " ],\n",
" [\n", " [\n",
" [\n", " [\n",
" \"Calculator\",\n", " \"Calculator\",\n",
" \"28^0.23\",\n", " \"25^0.43\",\n",
" \" I should use the calculator to raise that number to the 0.23 power\\nAction: Calculator\\nAction Input: 28^0.23\"\n", " \" I should calculate what 25 years raised to the 0.43 power is\\nAction: Calculator\\nAction Input: 25^0.43\"\n",
" ],\n", " ],\n",
" \"Answer: 2.1520202182226886\\n\"\n", " \"Answer: 3.991298452658078\\n\"\n",
" ]\n", " ]\n",
"]\n" "]\n"
] ]
@ -165,7 +178,7 @@
], ],
"metadata": { "metadata": {
"kernelspec": { "kernelspec": {
"display_name": "Python 3.9.0 64-bit ('llm-env')", "display_name": "Python 3 (ipykernel)",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
@ -179,7 +192,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.9.0" "version": "3.9.1"
}, },
"vscode": { "vscode": {
"interpreter": { "interpreter": {

@ -12,10 +12,17 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 1,
"id": "bd4450a2", "id": "bd4450a2",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"No `_type` key found, defaulting to `prompt`.\n"
]
},
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
@ -40,7 +47,7 @@
"'Manacor, Mallorca, Spain.'" "'Manacor, Mallorca, Spain.'"
] ]
}, },
"execution_count": 2, "execution_count": 1,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -63,7 +70,6 @@
] ]
}, },
{ {
"attachments": {},
"cell_type": "markdown", "cell_type": "markdown",
"id": "3aede965", "id": "3aede965",
"metadata": {}, "metadata": {},
@ -75,13 +81,29 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 2,
"id": "e679f7b6", "id": "e679f7b6",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"No `_type` key found, defaulting to `prompt`.\n"
]
}
],
"source": [ "source": [
"self_ask_with_search = initialize_agent(tools, llm, agent_path=\"lc@2826ef9e8acdf88465e1e5fc8a7bf59e0f9d0a85://agents/self-ask-with-search/agent.json\", verbose=True)" "self_ask_with_search = initialize_agent(tools, llm, agent_path=\"lc@2826ef9e8acdf88465e1e5fc8a7bf59e0f9d0a85://agents/self-ask-with-search/agent.json\", verbose=True)"
] ]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9d3d6697",
"metadata": {},
"outputs": [],
"source": []
} }
], ],
"metadata": { "metadata": {
@ -100,7 +122,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.10.9" "version": "3.9.1"
} }
}, },
"nbformat": 4, "nbformat": 4,

@ -82,7 +82,7 @@
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": null,
"id": "ebde3ea6", "id": "47653ac6",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
@ -99,7 +99,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 7,
"id": "fca094af", "id": "fca094af",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -109,7 +109,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 8,
"id": "0fd3ef0a", "id": "0fd3ef0a",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -123,13 +123,14 @@
"\u001b[32;1m\u001b[1;3m I need to use the Jester tool\n", "\u001b[32;1m\u001b[1;3m I need to use the Jester tool\n",
"Action: Jester\n", "Action: Jester\n",
"Action Input: foo\u001b[0m\n", "Action Input: foo\u001b[0m\n",
"Observation: Jester is not a valid tool, try another one.\n", "Observation: foo is not a valid tool, try another one.\n",
"Thought:\u001b[32;1m\u001b[1;3m I should try again\n", "\u001b[32;1m\u001b[1;3m I should try Jester again\n",
"Action: Jester\n", "Action: Jester\n",
"Action Input: foo\u001b[0m\n", "Action Input: foo\u001b[0m\n",
"Observation: Jester is not a valid tool, try another one.\n", "Observation: foo is not a valid tool, try another one.\n",
"Thought:\n", "\u001b[32;1m\u001b[1;3m\u001b[0m\n",
"\u001b[1m> Finished AgentExecutor chain.\u001b[0m\n" "\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
] ]
}, },
{ {
@ -138,7 +139,7 @@
"'Agent stopped due to max iterations.'" "'Agent stopped due to max iterations.'"
] ]
}, },
"execution_count": 7, "execution_count": 8,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -157,7 +158,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 8, "execution_count": 9,
"id": "3cc521bb", "id": "3cc521bb",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -167,7 +168,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 9, "execution_count": 10,
"id": "1618d316", "id": "1618d316",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -181,22 +182,24 @@
"\u001b[32;1m\u001b[1;3m I need to use the Jester tool\n", "\u001b[32;1m\u001b[1;3m I need to use the Jester tool\n",
"Action: Jester\n", "Action: Jester\n",
"Action Input: foo\u001b[0m\n", "Action Input: foo\u001b[0m\n",
"Observation: Jester is not a valid tool, try another one.\n", "Observation: foo is not a valid tool, try another one.\n",
"Thought:\u001b[32;1m\u001b[1;3m I should try again\n", "\u001b[32;1m\u001b[1;3m I should try Jester again\n",
"Action: Jester\n", "Action: Jester\n",
"Action Input: foo\u001b[0m\n", "Action Input: foo\u001b[0m\n",
"Observation: Jester is not a valid tool, try another one.\n", "Observation: foo is not a valid tool, try another one.\n",
"Thought:\n", "\u001b[32;1m\u001b[1;3m\n",
"\u001b[1m> Finished AgentExecutor chain.\u001b[0m\n" "Final Answer: Jester is the tool to use for this question.\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
] ]
}, },
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"'Jester is not a valid tool, try another one.'" "'Jester is the tool to use for this question.'"
] ]
}, },
"execution_count": 9, "execution_count": 10,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -230,7 +233,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.10.9" "version": "3.9.1"
} }
}, },
"nbformat": 4, "nbformat": 4,

@ -50,7 +50,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 3,
"id": "6db1d43f", "id": "6db1d43f",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -68,7 +68,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 7, "execution_count": 4,
"id": "aa25d0ca", "id": "aa25d0ca",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -85,7 +85,8 @@
"Observation: \u001b[36;1m\u001b[1;3m12\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3m12\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: 3 times 4 is 12\u001b[0m\n", "Final Answer: 3 times 4 is 12\u001b[0m\n",
"\u001b[1m> Finished AgentExecutor chain.\u001b[0m\n" "\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
] ]
}, },
{ {
@ -94,7 +95,7 @@
"'3 times 4 is 12'" "'3 times 4 is 12'"
] ]
}, },
"execution_count": 7, "execution_count": 4,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -114,7 +115,7 @@
], ],
"metadata": { "metadata": {
"kernelspec": { "kernelspec": {
"display_name": "Python 3.9.0 64-bit ('llm-env')", "display_name": "Python 3 (ipykernel)",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
@ -128,7 +129,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.9.0" "version": "3.9.1"
}, },
"vscode": { "vscode": {
"interpreter": { "interpreter": {

@ -12,7 +12,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 1,
"id": "e6860c2d", "id": "e6860c2d",
"metadata": { "metadata": {
"pycharm": { "pycharm": {
@ -28,7 +28,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 2,
"id": "dadbcfcd", "id": "dadbcfcd",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -38,40 +38,39 @@
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "ee251155",
"metadata": {},
"source": [ "source": [
"## Google Serper API Wrapper\n", "## Google Serper API Wrapper\n",
"\n", "\n",
"First, let's try to use the Google Serper API tool." "First, let's try to use the Google Serper API tool."
], ]
"metadata": {
"collapsed": false
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 6,
"id": "0cdaa487",
"metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"tools = load_tools([\"google-serper\"], llm=llm)" "tools = load_tools([\"google-serper\"], llm=llm)"
], ]
"metadata": {
"collapsed": false
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 7,
"id": "01b1ab4a",
"metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"agent = initialize_agent(tools, llm, agent=\"zero-shot-react-description\", verbose=True)" "agent = initialize_agent(tools, llm, agent=\"zero-shot-react-description\", verbose=True)"
], ]
"metadata": {
"collapsed": false
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 8,
"id": "5cf44ec0",
"metadata": {},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
@ -79,70 +78,67 @@
"text": [ "text": [
"\n", "\n",
"\n", "\n",
"\u001B[1m> Entering new AgentExecutor chain...\u001B[0m\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001B[32;1m\u001B[1;3m I need to find out what the current weather is in Pomfret.\n", "\u001b[32;1m\u001b[1;3m I should look up the current weather conditions.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"weather in Pomfret\"\u001B[0m\n", "Action Input: \"weather in Pomfret\"\u001b[0m\n",
"Observation: \u001B[36;1m\u001B[1;3mShowers early becoming a steady light rain later in the day. Near record high temperatures. High around 60F. Winds SW at 10 to 15 mph. Chance of rain 60%.\u001B[0m\n", "Observation: \u001b[36;1m\u001b[1;3m37°F\u001b[0m\n",
"Thought:\u001B[32;1m\u001B[1;3m I now know the current weather in Pomfret.\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the current temperature in Pomfret.\n",
"Final Answer: Showers early becoming a steady light rain later in the day. Near record high temperatures. High around 60F. Winds SW at 10 to 15 mph. Chance of rain 60%.\u001B[0m\n", "Final Answer: The current temperature in Pomfret is 37°F.\u001b[0m\n",
"\u001B[1m> Finished AgentExecutor chain.\u001B[0m\n" "\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
] ]
}, },
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"'Showers early becoming a steady light rain later in the day. Near record high temperatures. High around 60F. Winds SW at 10 to 15 mph. Chance of rain 60%.'" "'The current temperature in Pomfret is 37°F.'"
] ]
}, },
"execution_count": 6, "execution_count": 8,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
], ],
"source": [ "source": [
"agent.run(\"What is the weather in Pomfret?\")" "agent.run(\"What is the weather in Pomfret?\")"
], ]
"metadata": {
"collapsed": false
}
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "0e39fc46",
"metadata": {},
"source": [ "source": [
"## SerpAPI\n", "## SerpAPI\n",
"\n", "\n",
"Now, let's use the SerpAPI tool." "Now, let's use the SerpAPI tool."
], ]
"metadata": {
"collapsed": false
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 9,
"id": "e1c39a0f",
"metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"tools = load_tools([\"serpapi\"], llm=llm)" "tools = load_tools([\"serpapi\"], llm=llm)"
], ]
"metadata": {
"collapsed": false
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 10,
"id": "900dd6cb",
"metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"agent = initialize_agent(tools, llm, agent=\"zero-shot-react-description\", verbose=True)" "agent = initialize_agent(tools, llm, agent=\"zero-shot-react-description\", verbose=True)"
], ]
"metadata": {
"collapsed": false
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 11,
"id": "342ee8ec",
"metadata": {},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
@ -150,70 +146,67 @@
"text": [ "text": [
"\n", "\n",
"\n", "\n",
"\u001B[1m> Entering new AgentExecutor chain...\u001B[0m\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001B[32;1m\u001B[1;3m I need to find out what the current weather is in Pomfret.\n", "\u001b[32;1m\u001b[1;3m I need to find out what the current weather is in Pomfret.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"weather in Pomfret\"\u001B[0m\n", "Action Input: \"weather in Pomfret\"\u001b[0m\n",
"Observation: \u001B[36;1m\u001B[1;3mShowers early becoming a steady light rain later in the day. Near record high temperatures. High around 60F. Winds SW at 10 to 15 mph. Chance of rain 60%.\u001B[0m\n", "Observation: \u001b[36;1m\u001b[1;3mPartly cloudy skies during the morning hours will give way to cloudy skies with light rain and snow developing in the afternoon. High 42F. Winds WNW at 10 to 15 ...\u001b[0m\n",
"Thought:\u001B[32;1m\u001B[1;3m I now know the current weather in Pomfret.\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the current weather in Pomfret.\n",
"Final Answer: Showers early becoming a steady light rain later in the day. Near record high temperatures. High around 60F. Winds SW at 10 to 15 mph. Chance of rain 60%.\u001B[0m\n", "Final Answer: Partly cloudy skies during the morning hours will give way to cloudy skies with light rain and snow developing in the afternoon. High 42F. Winds WNW at 10 to 15 mph.\u001b[0m\n",
"\u001B[1m> Finished AgentExecutor chain.\u001B[0m\n" "\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
] ]
}, },
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"'Showers early becoming a steady light rain later in the day. Near record high temperatures. High around 60F. Winds SW at 10 to 15 mph. Chance of rain 60%.'" "'Partly cloudy skies during the morning hours will give way to cloudy skies with light rain and snow developing in the afternoon. High 42F. Winds WNW at 10 to 15 mph.'"
] ]
}, },
"execution_count": 6, "execution_count": 11,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
], ],
"source": [ "source": [
"agent.run(\"What is the weather in Pomfret?\")" "agent.run(\"What is the weather in Pomfret?\")"
], ]
"metadata": {
"collapsed": false
}
}, },
{ {
"cell_type": "markdown", "cell_type": "markdown",
"id": "adc8bb68",
"metadata": {},
"source": [ "source": [
"## GoogleSearchAPIWrapper\n", "## GoogleSearchAPIWrapper\n",
"\n", "\n",
"Now, let's use the official Google Search API Wrapper." "Now, let's use the official Google Search API Wrapper."
], ]
"metadata": {
"collapsed": false
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 13, "execution_count": 13,
"id": "ef24f92d",
"metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"tools = load_tools([\"google-search\"], llm=llm)" "tools = load_tools([\"google-search\"], llm=llm)"
], ]
"metadata": {
"collapsed": false
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 14, "execution_count": 14,
"id": "909cd28b",
"metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"agent = initialize_agent(tools, llm, agent=\"zero-shot-react-description\", verbose=True)" "agent = initialize_agent(tools, llm, agent=\"zero-shot-react-description\", verbose=True)"
], ]
"metadata": {
"collapsed": false
}
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 17, "execution_count": 17,
"id": "46515d2a",
"metadata": {},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
@ -221,14 +214,14 @@
"text": [ "text": [
"\n", "\n",
"\n", "\n",
"\u001B[1m> Entering new AgentExecutor chain...\u001B[0m\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001B[32;1m\u001B[1;3m I should look up the current weather conditions.\n", "\u001b[32;1m\u001b[1;3m I should look up the current weather conditions.\n",
"Action: Google Search\n", "Action: Google Search\n",
"Action Input: \"weather in Pomfret\"\u001B[0m\n", "Action Input: \"weather in Pomfret\"\u001b[0m\n",
"Observation: \u001B[36;1m\u001B[1;3mShowers early becoming a steady light rain later in the day. Near record high temperatures. High around 60F. Winds SW at 10 to 15 mph. Chance of rain 60%. Pomfret, CT Weather Forecast, with current conditions, wind, air quality, and what to expect for the next 3 days. Hourly Weather-Pomfret, CT. As of 12:52 am EST. Special Weather Statement +2 ... Hazardous Weather Conditions. Special Weather Statement ... Pomfret CT. Tonight ... National Digital Forecast Database Maximum Temperature Forecast. Pomfret Center Weather Forecasts. Weather Underground provides local & long-range weather forecasts, weatherreports, maps & tropical weather conditions for ... Pomfret, CT 12 hour by hour weather forecast includes precipitation, temperatures, sky conditions, rain chance, dew-point, relative humidity, wind direction ... North Pomfret Weather Forecasts. Weather Underground provides local & long-range weather forecasts, weatherreports, maps & tropical weather conditions for ... Today's Weather - Pomfret, CT. Dec 31, 2022 4:00 PM. Putnam MS. --. Weather forecast icon. Feels like --. Hi --. Lo --. Pomfret, CT temperature trend for the next 14 Days. Find daytime highs and nighttime lows from TheWeatherNetwork.com. Pomfret, MD Weather Forecast Date: 332 PM EST Wed Dec 28 2022. The area/counties/county of: Charles, including the cites of: St. Charles and Waldorf.\u001B[0m\n", "Observation: \u001b[36;1m\u001b[1;3mShowers early becoming a steady light rain later in the day. Near record high temperatures. High around 60F. Winds SW at 10 to 15 mph. Chance of rain 60%. Pomfret, CT Weather Forecast, with current conditions, wind, air quality, and what to expect for the next 3 days. Hourly Weather-Pomfret, CT. As of 12:52 am EST. Special Weather Statement +2 ... Hazardous Weather Conditions. Special Weather Statement ... Pomfret CT. Tonight ... National Digital Forecast Database Maximum Temperature Forecast. Pomfret Center Weather Forecasts. Weather Underground provides local & long-range weather forecasts, weatherreports, maps & tropical weather conditions for ... Pomfret, CT 12 hour by hour weather forecast includes precipitation, temperatures, sky conditions, rain chance, dew-point, relative humidity, wind direction ... North Pomfret Weather Forecasts. Weather Underground provides local & long-range weather forecasts, weatherreports, maps & tropical weather conditions for ... Today's Weather - Pomfret, CT. Dec 31, 2022 4:00 PM. Putnam MS. --. Weather forecast icon. Feels like --. Hi --. Lo --. Pomfret, CT temperature trend for the next 14 Days. Find daytime highs and nighttime lows from TheWeatherNetwork.com. Pomfret, MD Weather Forecast Date: 332 PM EST Wed Dec 28 2022. The area/counties/county of: Charles, including the cites of: St. Charles and Waldorf.\u001b[0m\n",
"Thought:\u001B[32;1m\u001B[1;3m I now know the current weather conditions in Pomfret.\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the current weather conditions in Pomfret.\n",
"Final Answer: Showers early becoming a steady light rain later in the day. Near record high temperatures. High around 60F. Winds SW at 10 to 15 mph. Chance of rain 60%.\u001B[0m\n", "Final Answer: Showers early becoming a steady light rain later in the day. Near record high temperatures. High around 60F. Winds SW at 10 to 15 mph. Chance of rain 60%.\u001b[0m\n",
"\u001B[1m> Finished AgentExecutor chain.\u001B[0m\n" "\u001b[1m> Finished AgentExecutor chain.\u001b[0m\n"
] ]
}, },
{ {
@ -244,15 +237,12 @@
], ],
"source": [ "source": [
"agent.run(\"What is the weather in Pomfret?\")" "agent.run(\"What is the weather in Pomfret?\")"
], ]
"metadata": {
"collapsed": false
}
} }
], ],
"metadata": { "metadata": {
"kernelspec": { "kernelspec": {
"display_name": "Python 3.9.0 64-bit ('llm-env')", "display_name": "Python 3 (ipykernel)",
"language": "python", "language": "python",
"name": "python3" "name": "python3"
}, },
@ -266,7 +256,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.9.0" "version": "3.9.1"
}, },
"vscode": { "vscode": {
"interpreter": { "interpreter": {

@ -67,7 +67,9 @@
" ],\r\n", " ],\r\n",
" \"output_parser\": null,\r\n", " \"output_parser\": null,\r\n",
" \"template\": \"Answer the following questions as best you can. You have access to the following tools:\\n\\nSearch: A search engine. Useful for when you need to answer questions about current events. Input should be a search query.\\nCalculator: Useful for when you need to answer questions about math.\\n\\nUse the following format:\\n\\nQuestion: the input question you must answer\\nThought: you should always think about what to do\\nAction: the action to take, should be one of [Search, Calculator]\\nAction Input: the input to the action\\nObservation: the result of the action\\n... (this Thought/Action/Action Input/Observation can repeat N times)\\nThought: I now know the final answer\\nFinal Answer: the final answer to the original input question\\n\\nBegin!\\n\\nQuestion: {input}\\nThought:{agent_scratchpad}\",\r\n", " \"template\": \"Answer the following questions as best you can. You have access to the following tools:\\n\\nSearch: A search engine. Useful for when you need to answer questions about current events. Input should be a search query.\\nCalculator: Useful for when you need to answer questions about math.\\n\\nUse the following format:\\n\\nQuestion: the input question you must answer\\nThought: you should always think about what to do\\nAction: the action to take, should be one of [Search, Calculator]\\nAction Input: the input to the action\\nObservation: the result of the action\\n... (this Thought/Action/Action Input/Observation can repeat N times)\\nThought: I now know the final answer\\nFinal Answer: the final answer to the original input question\\n\\nBegin!\\n\\nQuestion: {input}\\nThought:{agent_scratchpad}\",\r\n",
" \"template_format\": \"f-string\"\r\n", " \"template_format\": \"f-string\",\r\n",
" \"validate_template\": true,\r\n",
" \"_type\": \"prompt\"\r\n",
" },\r\n", " },\r\n",
" \"llm\": {\r\n", " \"llm\": {\r\n",
" \"model_name\": \"text-davinci-003\",\r\n", " \"model_name\": \"text-davinci-003\",\r\n",
@ -85,6 +87,10 @@
" \"output_key\": \"text\",\r\n", " \"output_key\": \"text\",\r\n",
" \"_type\": \"llm_chain\"\r\n", " \"_type\": \"llm_chain\"\r\n",
" },\r\n", " },\r\n",
" \"allowed_tools\": [\r\n",
" \"Search\",\r\n",
" \"Calculator\"\r\n",
" ],\r\n",
" \"return_values\": [\r\n", " \"return_values\": [\r\n",
" \"output\"\r\n", " \"output\"\r\n",
" ],\r\n", " ],\r\n",
@ -107,7 +113,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 4,
"id": "eb660b76", "id": "eb660b76",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -140,7 +146,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.10.9" "version": "3.9.1"
} }
}, },
"nbformat": 4, "nbformat": 4,

@ -87,7 +87,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 6,
"id": "03208e2b", "id": "03208e2b",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -105,7 +105,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 13,
"id": "244ee75c", "id": "244ee75c",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -116,38 +116,47 @@
"\n", "\n",
"\n", "\n",
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m I need to find out who Olivia Wilde's boyfriend is and then calculate his age raised to the 0.23 power.\n", "\u001b[32;1m\u001b[1;3m I need to find out who Leo DiCaprio's girlfriend is and then calculate her age raised to the 0.43 power.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Olivia Wilde boyfriend\"\u001b[0m\n", "Action Input: \"Leo DiCaprio girlfriend\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mHarry Styles\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3mCamila Morrone\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find out Harry Styles' age\n", "Thought:\u001b[32;1m\u001b[1;3m I need to find out Camila Morrone's age\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Harry Styles age\"\u001b[0m\n", "Action Input: \"Camila Morrone age\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3m28 years\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3m25 years\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to calculate 28 raised to the 0.23 power\n", "Thought:\u001b[32;1m\u001b[1;3m I need to calculate 25 raised to the 0.43 power\n",
"Action: Calculator\n", "Action: Calculator\n",
"Action Input: 28^0.23\u001b[0m\n", "Action Input: 25^0.43\u001b[0m\n",
"Observation: \u001b[33;1m\u001b[1;3mAnswer: 2.1520202182226886\n", "Observation: \u001b[33;1m\u001b[1;3mAnswer: 3.991298452658078\n",
"\u001b[0m\n", "\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: Harry Styles is Olivia Wilde's boyfriend and his current age raised to the 0.23 power is 2.1520202182226886.\u001b[0m\n", "Final Answer: Camila Morrone is Leo DiCaprio's girlfriend and her current age raised to the 0.43 power is 3.991298452658078.\u001b[0m\n",
"\n",
"\u001b[1m> Finished chain.\u001b[0m\n" "\u001b[1m> Finished chain.\u001b[0m\n"
] ]
}, },
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"\"Harry Styles is Olivia Wilde's boyfriend and his current age raised to the 0.23 power is 2.1520202182226886.\"" "\"Camila Morrone is Leo DiCaprio's girlfriend and her current age raised to the 0.43 power is 3.991298452658078.\""
] ]
}, },
"execution_count": 5, "execution_count": 13,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
], ],
"source": [ "source": [
"agent.run(\"Who is Olivia Wilde's boyfriend? What is his current age raised to the 0.23 power?\")" "agent.run(\"Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?\")"
] ]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5901695b",
"metadata": {},
"outputs": [],
"source": []
} }
], ],
"metadata": { "metadata": {

@ -32,7 +32,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 2,
"id": "07e96d99", "id": "07e96d99",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -63,7 +63,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 3,
"id": "a069c4b6", "id": "a069c4b6",
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
@ -73,7 +73,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 4,
"id": "e603cd7d", "id": "e603cd7d",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -84,54 +84,55 @@
"\n", "\n",
"\n", "\n",
"\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n", "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
"\u001b[32;1m\u001b[1;3m I need to find out who Olivia Wilde's boyfriend is and then calculate his age raised to the 0.23 power.\n", "\u001b[32;1m\u001b[1;3m I need to find out who Leo DiCaprio's girlfriend is and then calculate her age raised to the 0.43 power.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"Who is Olivia Wilde's boyfriend?\"\u001b[0m\n", "Action Input: \"Who is Leo DiCaprio's girlfriend?\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mHarry Styles\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3mCamila Morrone\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to find out Harry Styles' age\n", "Thought:\u001b[32;1m\u001b[1;3m I need to find out Camila Morrone's age\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"How old is Harry Styles?\"\u001b[0m\n", "Action Input: \"How old is Camila Morrone?\"\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3m28 years\u001b[0m\n", "Observation: \u001b[36;1m\u001b[1;3m25 years\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I need to calculate 28 raised to the 0.23 power\n", "Thought:\u001b[32;1m\u001b[1;3m I need to calculate 25 raised to the 0.43 power\n",
"Action: Calculator\n", "Action: Calculator\n",
"Action Input: 28^0.23\u001b[0m\n", "Action Input: 25^0.43\u001b[0m\n",
"\n", "\n",
"\u001b[1m> Entering new LLMMathChain chain...\u001b[0m\n", "\u001b[1m> Entering new LLMMathChain chain...\u001b[0m\n",
"28^0.23\u001b[32;1m\u001b[1;3m\n", "25^0.43\u001b[32;1m\u001b[1;3m\n",
"```python\n", "```python\n",
"import math\n", "import math\n",
"print(math.pow(28, 0.23))\n", "print(math.pow(25, 0.43))\n",
"```\n", "```\n",
"\u001b[0m\n", "\u001b[0m\n",
"Answer: \u001b[33;1m\u001b[1;3m2.1520202182226886\n", "Answer: \u001b[33;1m\u001b[1;3m3.991298452658078\n",
"\u001b[0m\n", "\u001b[0m\n",
"\u001b[1m> Finished LLMMathChain chain.\u001b[0m\n", "\u001b[1m> Finished chain.\u001b[0m\n",
"\n", "\n",
"Observation: \u001b[33;1m\u001b[1;3mAnswer: 2.1520202182226886\n", "Observation: \u001b[33;1m\u001b[1;3mAnswer: 3.991298452658078\n",
"\u001b[0m\n", "\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: Harry Styles is 28 years old and his age raised to the 0.23 power is 2.1520202182226886.\u001b[0m\n", "Final Answer: Camila Morrone is 25 years old and her age raised to the 0.43 power is 3.991298452658078.\u001b[0m\n",
"\u001b[1m> Finished AgentExecutor chain.\u001b[0m\n" "\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
] ]
}, },
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"'Harry Styles is 28 years old and his age raised to the 0.23 power is 2.1520202182226886.'" "'Camila Morrone is 25 years old and her age raised to the 0.43 power is 3.991298452658078.'"
] ]
}, },
"execution_count": 5, "execution_count": 4,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
], ],
"source": [ "source": [
"mrkl.run(\"Who is Olivia Wilde's boyfriend? What is his current age raised to the 0.23 power?\")" "mrkl.run(\"Who is Leo DiCaprio's girlfriend? What is her current age raised to the 0.43 power?\")"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 6, "execution_count": 5,
"id": "a5c07010", "id": "a5c07010",
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
@ -145,31 +146,32 @@
"\u001b[32;1m\u001b[1;3m I need to find out the artist's full name and then search the FooBar database for their albums.\n", "\u001b[32;1m\u001b[1;3m I need to find out the artist's full name and then search the FooBar database for their albums.\n",
"Action: Search\n", "Action: Search\n",
"Action Input: \"The Storm Before the Calm\" artist\u001b[0m\n", "Action Input: \"The Storm Before the Calm\" artist\u001b[0m\n",
"Observation: \u001b[36;1m\u001b[1;3mAlanis Morissette - the storm before the calm - Amazon.com Music.\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 now need to search the FooBar database for Alanis Morissette's albums.\n", "Thought:\u001b[32;1m\u001b[1;3m I now need to search the FooBar database for Alanis Morissette's albums\n",
"Action: FooBar DB\n", "Action: FooBar DB\n",
"Action Input: What albums of Alanis Morissette are in the FooBar database?\u001b[0m\n", "Action Input: What albums by Alanis Morissette are in the FooBar database?\u001b[0m\n",
"\n", "\n",
"\u001b[1m> Entering new SQLDatabaseChain chain...\u001b[0m\n", "\u001b[1m> Entering new SQLDatabaseChain chain...\u001b[0m\n",
"What albums of Alanis Morissette are in the FooBar database? \n", "What albums by Alanis Morissette are in the FooBar database? \n",
"SQLQuery:\u001b[32;1m\u001b[1;3m SELECT Title FROM Album WHERE ArtistId IN (SELECT ArtistId FROM Artist WHERE Name = 'Alanis Morissette');\u001b[0m\n", "SQLQuery:\u001b[32;1m\u001b[1;3m SELECT Title FROM Album INNER JOIN Artist ON Album.ArtistId = Artist.ArtistId WHERE Artist.Name = 'Alanis Morissette' LIMIT 5;\u001b[0m\n",
"SQLResult: \u001b[33;1m\u001b[1;3m[('Jagged Little Pill',)]\u001b[0m\n", "SQLResult: \u001b[33;1m\u001b[1;3m[('Jagged Little Pill',)]\u001b[0m\n",
"Answer:\u001b[32;1m\u001b[1;3m The album 'Jagged Little Pill' by Alanis Morissette is in the FooBar database.\u001b[0m\n", "Answer:\u001b[32;1m\u001b[1;3m The albums by Alanis Morissette in the FooBar database are Jagged Little Pill.\u001b[0m\n",
"\u001b[1m> Finished SQLDatabaseChain chain.\u001b[0m\n", "\u001b[1m> Finished chain.\u001b[0m\n",
"\n", "\n",
"Observation: \u001b[38;5;200m\u001b[1;3m The album 'Jagged Little Pill' by Alanis Morissette is in the FooBar database.\u001b[0m\n", "Observation: \u001b[38;5;200m\u001b[1;3m The albums by Alanis Morissette in the FooBar database are Jagged Little Pill.\u001b[0m\n",
"Thought:\u001b[32;1m\u001b[1;3m I now know the final answer.\n", "Thought:\u001b[32;1m\u001b[1;3m I now know the final answer\n",
"Final Answer: Alanis Morissette is the artist who recently released an album called 'The Storm Before the Calm' and the album 'Jagged Little Pill' by Alanis Morissette is in the FooBar database.\u001b[0m\n", "Final Answer: The artist who released the album The Storm Before the Calm is Alanis Morissette and the albums of theirs in the FooBar database are Jagged Little Pill.\u001b[0m\n",
"\u001b[1m> Finished AgentExecutor chain.\u001b[0m\n" "\n",
"\u001b[1m> Finished chain.\u001b[0m\n"
] ]
}, },
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"\"Alanis Morissette is the artist who recently released an album called 'The Storm Before the Calm' and the album 'Jagged Little Pill' by Alanis Morissette is in the FooBar database.\"" "'The artist who released the album The Storm Before the Calm is Alanis Morissette and the albums of theirs in the FooBar database are Jagged Little Pill.'"
] ]
}, },
"execution_count": 6, "execution_count": 5,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
@ -203,7 +205,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.10.9" "version": "3.9.1"
} }
}, },
"nbformat": 4, "nbformat": 4,

@ -506,7 +506,7 @@
"name": "python", "name": "python",
"nbconvert_exporter": "python", "nbconvert_exporter": "python",
"pygments_lexer": "ipython3", "pygments_lexer": "ipython3",
"version": "3.9.1" "version": "3.10.9"
} }
}, },
"nbformat": 4, "nbformat": 4,

@ -12,7 +12,9 @@
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 1,
"id": "17c04cc6-c93d-4b6c-a033-e897577f4ed1", "id": "17c04cc6-c93d-4b6c-a033-e897577f4ed1",
"metadata": {}, "metadata": {
"tags": []
},
"outputs": [], "outputs": [],
"source": [ "source": [
"import os\n", "import os\n",
@ -40,7 +42,9 @@
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 2,
"id": "bfa16b79-aa4b-4d41-a067-70d1f593f667", "id": "bfa16b79-aa4b-4d41-a067-70d1f593f667",
"metadata": {}, "metadata": {
"tags": []
},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",

@ -1,17 +1,16 @@
"""Chain that takes in an input and produces an action and action input.""" """Chain that takes in an input and produces an action and action input."""
from __future__ import annotations from __future__ import annotations
import asyncio
import json import json
import logging import logging
from abc import abstractmethod from abc import abstractmethod
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, Optional, Tuple, Union from typing import Any, Dict, List, Optional, Sequence, Tuple, Union
import yaml import yaml
from pydantic import BaseModel, root_validator from pydantic import BaseModel, root_validator
from langchain.agents.tools import Tool from langchain.agents.tools import InvalidTool
from langchain.callbacks.base import BaseCallbackManager from langchain.callbacks.base import BaseCallbackManager
from langchain.chains.base import Chain from langchain.chains.base import Chain
from langchain.chains.llm import LLMChain from langchain.chains.llm import LLMChain
@ -21,6 +20,7 @@ from langchain.prompts.base import BasePromptTemplate
from langchain.prompts.few_shot import FewShotPromptTemplate from langchain.prompts.few_shot import FewShotPromptTemplate
from langchain.prompts.prompt import PromptTemplate from langchain.prompts.prompt import PromptTemplate
from langchain.schema import AgentAction, AgentFinish from langchain.schema import AgentAction, AgentFinish
from langchain.tools.base import BaseTool
logger = logging.getLogger() logger = logging.getLogger()
@ -179,11 +179,11 @@ class Agent(BaseModel):
@classmethod @classmethod
@abstractmethod @abstractmethod
def create_prompt(cls, tools: List[Tool]) -> BasePromptTemplate: def create_prompt(cls, tools: Sequence[BaseTool]) -> BasePromptTemplate:
"""Create a prompt for this class.""" """Create a prompt for this class."""
@classmethod @classmethod
def _validate_tools(cls, tools: List[Tool]) -> None: def _validate_tools(cls, tools: Sequence[BaseTool]) -> None:
"""Validate that appropriate tools are passed in.""" """Validate that appropriate tools are passed in."""
pass pass
@ -191,7 +191,7 @@ class Agent(BaseModel):
def from_llm_and_tools( def from_llm_and_tools(
cls, cls,
llm: BaseLLM, llm: BaseLLM,
tools: List[Tool], tools: Sequence[BaseTool],
callback_manager: Optional[BaseCallbackManager] = None, callback_manager: Optional[BaseCallbackManager] = None,
**kwargs: Any, **kwargs: Any,
) -> Agent: ) -> Agent:
@ -298,7 +298,7 @@ class AgentExecutor(Chain, BaseModel):
"""Consists of an agent using tools.""" """Consists of an agent using tools."""
agent: Agent agent: Agent
tools: List[Tool] tools: Sequence[BaseTool]
return_intermediate_steps: bool = False return_intermediate_steps: bool = False
max_iterations: Optional[int] = 15 max_iterations: Optional[int] = 15
early_stopping_method: str = "force" early_stopping_method: str = "force"
@ -307,7 +307,7 @@ class AgentExecutor(Chain, BaseModel):
def from_agent_and_tools( def from_agent_and_tools(
cls, cls,
agent: Agent, agent: Agent,
tools: List[Tool], tools: Sequence[BaseTool],
callback_manager: Optional[BaseCallbackManager] = None, callback_manager: Optional[BaseCallbackManager] = None,
**kwargs: Any, **kwargs: Any,
) -> AgentExecutor: ) -> AgentExecutor:
@ -393,7 +393,7 @@ class AgentExecutor(Chain, BaseModel):
def _take_next_step( def _take_next_step(
self, self,
name_to_tool_map: Dict[str, Tool], name_to_tool_map: Dict[str, BaseTool],
color_mapping: Dict[str, str], color_mapping: Dict[str, str],
inputs: Dict[str, str], inputs: Dict[str, str],
intermediate_steps: List[Tuple[AgentAction, str]], intermediate_steps: List[Tuple[AgentAction, str]],
@ -410,35 +410,26 @@ class AgentExecutor(Chain, BaseModel):
# Otherwise we lookup the tool # Otherwise we lookup the tool
if output.tool in name_to_tool_map: if output.tool in name_to_tool_map:
tool = name_to_tool_map[output.tool] tool = name_to_tool_map[output.tool]
self.callback_manager.on_tool_start( return_direct = tool.return_direct
{"name": str(tool.func)[:60] + "..."}, color = color_mapping[output.tool]
llm_prefix = "" if return_direct else self.agent.llm_prefix
# We then call the tool on the tool input to get an observation
observation = tool.run(
output, output,
color="green",
verbose=self.verbose, verbose=self.verbose,
color=color,
llm_prefix=llm_prefix,
observation_prefix=self.agent.observation_prefix,
) )
try:
# We then call the tool on the tool input to get an observation
observation = tool.func(output.tool_input)
color = color_mapping[output.tool]
return_direct = tool.return_direct
except (KeyboardInterrupt, Exception) as e:
self.callback_manager.on_tool_error(e, verbose=self.verbose)
raise e
else: else:
self.callback_manager.on_tool_start( observation = InvalidTool().run(
{"name": "N/A"}, output, color="green", verbose=self.verbose output,
verbose=self.verbose,
color=None,
llm_prefix="",
observation_prefix=self.agent.observation_prefix,
) )
observation = f"{output.tool} is not a valid tool, try another one."
color = None
return_direct = False return_direct = False
llm_prefix = "" if return_direct else self.agent.llm_prefix
self.callback_manager.on_tool_end(
observation,
color=color,
observation_prefix=self.agent.observation_prefix,
llm_prefix=llm_prefix,
verbose=self.verbose,
)
if return_direct: if return_direct:
# Set the log to "" because we do not want to log it. # Set the log to "" because we do not want to log it.
return AgentFinish({self.agent.return_values[0]: observation}, "") return AgentFinish({self.agent.return_values[0]: observation}, "")
@ -446,7 +437,7 @@ class AgentExecutor(Chain, BaseModel):
async def _atake_next_step( async def _atake_next_step(
self, self,
name_to_tool_map: Dict[str, Tool], name_to_tool_map: Dict[str, BaseTool],
color_mapping: Dict[str, str], color_mapping: Dict[str, str],
inputs: Dict[str, str], inputs: Dict[str, str],
intermediate_steps: List[Tuple[AgentAction, str]], intermediate_steps: List[Tuple[AgentAction, str]],
@ -463,66 +454,26 @@ class AgentExecutor(Chain, BaseModel):
# Otherwise we lookup the tool # Otherwise we lookup the tool
if output.tool in name_to_tool_map: if output.tool in name_to_tool_map:
tool = name_to_tool_map[output.tool] tool = name_to_tool_map[output.tool]
if self.callback_manager.is_async: return_direct = tool.return_direct
await self.callback_manager.on_tool_start( color = color_mapping[output.tool]
{"name": str(tool.func)[:60] + "..."}, llm_prefix = "" if return_direct else self.agent.llm_prefix
output, # We then call the tool on the tool input to get an observation
verbose=self.verbose, observation = await tool.arun(
) output,
else: verbose=self.verbose,
self.callback_manager.on_tool_start(
{"name": str(tool.func)[:60] + "..."},
output,
verbose=self.verbose,
)
try:
# We then call the tool on the tool input to get an observation
observation = (
await tool.coroutine(output.tool_input)
if tool.coroutine
# If the tool is not a coroutine, we run it in the executor
# to avoid blocking the event loop.
else await asyncio.get_event_loop().run_in_executor(
None, tool.func, output.tool_input
)
)
color = color_mapping[output.tool]
return_direct = tool.return_direct
except (KeyboardInterrupt, Exception) as e:
if self.callback_manager.is_async:
await self.callback_manager.on_tool_error(e, verbose=self.verbose)
else:
self.callback_manager.on_tool_error(e, verbose=self.verbose)
raise e
else:
if self.callback_manager.is_async:
await self.callback_manager.on_tool_start(
{"name": "N/A"}, output, verbose=self.verbose
)
else:
self.callback_manager.on_tool_start(
{"name": "N/A"}, output, verbose=self.verbose
)
observation = f"{output.tool} is not a valid tool, try another one."
color = None
return_direct = False
llm_prefix = "" if return_direct else self.agent.llm_prefix
if self.callback_manager.is_async:
await self.callback_manager.on_tool_end(
observation,
color=color, color=color,
observation_prefix=self.agent.observation_prefix,
llm_prefix=llm_prefix, llm_prefix=llm_prefix,
verbose=self.verbose, observation_prefix=self.agent.observation_prefix,
) )
else: else:
self.callback_manager.on_tool_end( observation = await InvalidTool().arun(
observation, output,
color=color,
observation_prefix=self.agent.observation_prefix,
llm_prefix=llm_prefix,
verbose=self.verbose, verbose=self.verbose,
color=None,
llm_prefix="",
observation_prefix=self.agent.observation_prefix,
) )
return_direct = False
if return_direct: if return_direct:
# Set the log to "" because we do not want to log it. # Set the log to "" because we do not want to log it.
return AgentFinish({self.agent.return_values[0]: observation}, "") return AgentFinish({self.agent.return_values[0]: observation}, "")
@ -530,14 +481,6 @@ class AgentExecutor(Chain, BaseModel):
def _call(self, inputs: Dict[str, str]) -> Dict[str, Any]: def _call(self, inputs: Dict[str, str]) -> Dict[str, Any]:
"""Run text through and get agent response.""" """Run text through and get agent response."""
# Make sure that every tool is synchronous (not a coroutine)
for tool in self.tools:
if asyncio.iscoroutinefunction(tool.func):
raise ValueError(
"Tools cannot be asynchronous for `run` method. "
"Please use `arun` instead."
)
# Do any preparation necessary when receiving a new input. # Do any preparation necessary when receiving a new input.
self.agent.prepare_for_new_call() self.agent.prepare_for_new_call()
# Construct a mapping of tool name to tool for easy lookup # Construct a mapping of tool name to tool for easy lookup
@ -566,13 +509,6 @@ class AgentExecutor(Chain, BaseModel):
async def _acall(self, inputs: Dict[str, str]) -> Dict[str, str]: async def _acall(self, inputs: Dict[str, str]) -> Dict[str, str]:
"""Run text through and get agent response.""" """Run text through and get agent response."""
# Make sure that every tool is asynchronous (a coroutine)
for tool in self.tools:
if tool.coroutine and not asyncio.iscoroutinefunction(tool.coroutine):
raise ValueError(
"The coroutine for the tool must be a coroutine function."
)
# Do any preparation necessary when receiving a new input. # Do any preparation necessary when receiving a new input.
self.agent.prepare_for_new_call() self.agent.prepare_for_new_call()
# Construct a mapping of tool name to tool for easy lookup # Construct a mapping of tool name to tool for easy lookup

@ -2,15 +2,15 @@
from __future__ import annotations from __future__ import annotations
import re import re
from typing import Any, List, Optional, Tuple from typing import Any, List, Optional, Sequence, Tuple
from langchain.agents.agent import Agent from langchain.agents.agent import Agent
from langchain.agents.conversational.prompt import FORMAT_INSTRUCTIONS, PREFIX, SUFFIX from langchain.agents.conversational.prompt import FORMAT_INSTRUCTIONS, PREFIX, SUFFIX
from langchain.agents.tools import Tool
from langchain.callbacks.base import BaseCallbackManager from langchain.callbacks.base import BaseCallbackManager
from langchain.chains import LLMChain from langchain.chains import LLMChain
from langchain.llms import BaseLLM from langchain.llms import BaseLLM
from langchain.prompts import PromptTemplate from langchain.prompts import PromptTemplate
from langchain.tools.base import BaseTool
class ConversationalAgent(Agent): class ConversationalAgent(Agent):
@ -36,7 +36,7 @@ class ConversationalAgent(Agent):
@classmethod @classmethod
def create_prompt( def create_prompt(
cls, cls,
tools: List[Tool], tools: Sequence[BaseTool],
prefix: str = PREFIX, prefix: str = PREFIX,
suffix: str = SUFFIX, suffix: str = SUFFIX,
format_instructions: str = FORMAT_INSTRUCTIONS, format_instructions: str = FORMAT_INSTRUCTIONS,
@ -90,7 +90,7 @@ class ConversationalAgent(Agent):
def from_llm_and_tools( def from_llm_and_tools(
cls, cls,
llm: BaseLLM, llm: BaseLLM,
tools: List[Tool], tools: Sequence[BaseTool],
callback_manager: Optional[BaseCallbackManager] = None, callback_manager: Optional[BaseCallbackManager] = None,
prefix: str = PREFIX, prefix: str = PREFIX,
suffix: str = SUFFIX, suffix: str = SUFFIX,

@ -1,15 +1,15 @@
"""Load agent.""" """Load agent."""
from typing import Any, List, Optional from typing import Any, Optional, Sequence
from langchain.agents.agent import AgentExecutor from langchain.agents.agent import AgentExecutor
from langchain.agents.loading import AGENT_TO_CLASS, load_agent from langchain.agents.loading import AGENT_TO_CLASS, load_agent
from langchain.agents.tools import Tool
from langchain.callbacks.base import BaseCallbackManager from langchain.callbacks.base import BaseCallbackManager
from langchain.llms.base import BaseLLM from langchain.llms.base import BaseLLM
from langchain.tools.base import BaseTool
def initialize_agent( def initialize_agent(
tools: List[Tool], tools: Sequence[BaseTool],
llm: BaseLLM, llm: BaseLLM,
agent: Optional[str] = None, agent: Optional[str] = None,
callback_manager: Optional[BaseCallbackManager] = None, callback_manager: Optional[BaseCallbackManager] = None,

@ -3,6 +3,7 @@
from typing import Any, List, Optional from typing import Any, List, Optional
from langchain.agents.tools import Tool from langchain.agents.tools import Tool
from langchain.callbacks.base import BaseCallbackManager
from langchain.chains.api import news_docs, open_meteo_docs, tmdb_docs from langchain.chains.api import news_docs, open_meteo_docs, tmdb_docs
from langchain.chains.api.base import APIChain from langchain.chains.api.base import APIChain
from langchain.chains.llm_math.base import LLMMathChain from langchain.chains.llm_math.base import LLMMathChain
@ -11,34 +12,39 @@ from langchain.llms.base import BaseLLM
from langchain.python import PythonREPL from langchain.python import PythonREPL
from langchain.requests import RequestsWrapper from langchain.requests import RequestsWrapper
from langchain.serpapi import SerpAPIWrapper from langchain.serpapi import SerpAPIWrapper
from langchain.tools.base import BaseTool
from langchain.tools.bing_search.tool import BingSearchRun
from langchain.tools.google_search.tool import GoogleSearchResults, GoogleSearchRun
from langchain.tools.wolfram_alpha.tool import WolframAlphaQueryRun
from langchain.utilities.bash import BashProcess from langchain.utilities.bash import BashProcess
from langchain.utilities.bing_search import BingSearchAPIWrapper
from langchain.utilities.google_search import GoogleSearchAPIWrapper from langchain.utilities.google_search import GoogleSearchAPIWrapper
from langchain.utilities.google_serper import GoogleSerperAPIWrapper from langchain.utilities.google_serper import GoogleSerperAPIWrapper
from langchain.utilities.searx_search import SearxSearchWrapper from langchain.utilities.searx_search import SearxSearchWrapper
from langchain.utilities.wolfram_alpha import WolframAlphaAPIWrapper from langchain.utilities.wolfram_alpha import WolframAlphaAPIWrapper
def _get_python_repl() -> Tool: def _get_python_repl() -> BaseTool:
return Tool( return Tool(
"Python REPL", name="Python REPL",
PythonREPL().run, description="A Python shell. Use this to execute python commands. Input should be a valid python command. If you expect output it should be printed out.",
"A Python shell. Use this to execute python commands. Input should be a valid python command. If you expect output it should be printed out.", func=PythonREPL().run,
) )
def _get_requests() -> Tool: def _get_requests() -> BaseTool:
return Tool( return Tool(
"Requests", name="Requests",
RequestsWrapper().run, description="A portal to the internet. Use this when you need to get specific content from a site. Input should be a specific url, and the output will be all the text on that page.",
"A portal to the internet. Use this when you need to get specific content from a site. Input should be a specific url, and the output will be all the text on that page.", func=RequestsWrapper().run,
) )
def _get_terminal() -> Tool: def _get_terminal() -> BaseTool:
return Tool( return Tool(
"Terminal", name="Terminal",
BashProcess().run, description="Executes commands in a terminal. Input should be valid commands, and the output will be any output from running that command.",
"Executes commands in a terminal. Input should be valid commands, and the output will be any output from running that command.", func=BashProcess().run,
) )
@ -49,23 +55,23 @@ _BASE_TOOLS = {
} }
def _get_pal_math(llm: BaseLLM) -> Tool: def _get_pal_math(llm: BaseLLM) -> BaseTool:
return Tool( return Tool(
"PAL-MATH", name="PAL-MATH",
PALChain.from_math_prompt(llm).run, description="A language model that is really good at solving complex word math problems. Input should be a fully worded hard word math problem.",
"A language model that is really good at solving complex word math problems. Input should be a fully worded hard word math problem.", func=PALChain.from_math_prompt(llm).run,
) )
def _get_pal_colored_objects(llm: BaseLLM) -> Tool: def _get_pal_colored_objects(llm: BaseLLM) -> BaseTool:
return Tool( return Tool(
"PAL-COLOR-OBJ", name="PAL-COLOR-OBJ",
PALChain.from_colored_object_prompt(llm).run, description="A language model that is really good at reasoning about position and the color attributes of objects. Input should be a fully worded hard reasoning problem. Make sure to include all information about the objects AND the final question you want to answer.",
"A language model that is really good at reasoning about position and the color attributes of objects. Input should be a fully worded hard reasoning problem. Make sure to include all information about the objects AND the final question you want to answer.", func=PALChain.from_colored_object_prompt(llm).run,
) )
def _get_llm_math(llm: BaseLLM) -> Tool: def _get_llm_math(llm: BaseLLM) -> BaseTool:
return Tool( return Tool(
name="Calculator", name="Calculator",
description="Useful for when you need to answer questions about math.", description="Useful for when you need to answer questions about math.",
@ -74,12 +80,12 @@ def _get_llm_math(llm: BaseLLM) -> Tool:
) )
def _get_open_meteo_api(llm: BaseLLM) -> Tool: def _get_open_meteo_api(llm: BaseLLM) -> BaseTool:
chain = APIChain.from_llm_and_api_docs(llm, open_meteo_docs.OPEN_METEO_DOCS) chain = APIChain.from_llm_and_api_docs(llm, open_meteo_docs.OPEN_METEO_DOCS)
return Tool( return Tool(
"Open Meteo API", name="Open Meteo API",
chain.run, description="Useful for when you want to get weather information from the OpenMeteo API. The input should be a question in natural language that this API can answer.",
"Useful for when you want to get weather information from the OpenMeteo API. The input should be a question in natural language that this API can answer.", func=chain.run,
) )
@ -91,19 +97,19 @@ _LLM_TOOLS = {
} }
def _get_news_api(llm: BaseLLM, **kwargs: Any) -> Tool: def _get_news_api(llm: BaseLLM, **kwargs: Any) -> BaseTool:
news_api_key = kwargs["news_api_key"] news_api_key = kwargs["news_api_key"]
chain = APIChain.from_llm_and_api_docs( chain = APIChain.from_llm_and_api_docs(
llm, news_docs.NEWS_DOCS, headers={"X-Api-Key": news_api_key} llm, news_docs.NEWS_DOCS, headers={"X-Api-Key": news_api_key}
) )
return Tool( return Tool(
"News API", name="News API",
chain.run, description="Use this when you want to get information about the top headlines of current news stories. The input should be a question in natural language that this API can answer.",
"Use this when you want to get information about the top headlines of current news stories. The input should be a question in natural language that this API can answer.", func=chain.run,
) )
def _get_tmdb_api(llm: BaseLLM, **kwargs: Any) -> Tool: def _get_tmdb_api(llm: BaseLLM, **kwargs: Any) -> BaseTool:
tmdb_bearer_token = kwargs["tmdb_bearer_token"] tmdb_bearer_token = kwargs["tmdb_bearer_token"]
chain = APIChain.from_llm_and_api_docs( chain = APIChain.from_llm_and_api_docs(
llm, llm,
@ -111,37 +117,33 @@ def _get_tmdb_api(llm: BaseLLM, **kwargs: Any) -> Tool:
headers={"Authorization": f"Bearer {tmdb_bearer_token}"}, headers={"Authorization": f"Bearer {tmdb_bearer_token}"},
) )
return Tool( return Tool(
"TMDB API", name="TMDB API",
chain.run, description="Useful for when you want to get information from The Movie Database. The input should be a question in natural language that this API can answer.",
"Useful for when you want to get information from The Movie Database. The input should be a question in natural language that this API can answer.", func=chain.run,
) )
def _get_wolfram_alpha(**kwargs: Any) -> Tool: def _get_wolfram_alpha(**kwargs: Any) -> BaseTool:
return Tool( return WolframAlphaQueryRun(api_wrapper=WolframAlphaAPIWrapper(**kwargs))
"Wolfram Alpha",
WolframAlphaAPIWrapper(**kwargs).run,
"A wrapper around Wolfram Alpha. Useful for when you need to answer questions about Math, Science, Technology, Culture, Society and Everyday Life. Input should be a search query.",
)
def _get_google_search(**kwargs: Any) -> Tool: def _get_google_search(**kwargs: Any) -> BaseTool:
return Tool( return GoogleSearchRun(api_wrapper=GoogleSearchAPIWrapper(**kwargs))
"Google Search",
GoogleSearchAPIWrapper(**kwargs).run,
"A wrapper around Google Search. Useful for when you need to answer questions about current events. Input should be a search query.",
)
def _get_google_serper(**kwargs: Any) -> Tool: def _get_google_serper(**kwargs: Any) -> BaseTool:
return Tool( return Tool(
"Search", name="Search",
GoogleSerperAPIWrapper(**kwargs).run, func=GoogleSerperAPIWrapper(**kwargs).run,
"A low-cost Google Search API. Useful for when you need to answer questions about current events. Input should be a search query.", description="A low-cost Google Search API. Useful for when you need to answer questions about current events. Input should be a search query.",
) )
def _get_serpapi(**kwargs: Any) -> Tool: def _get_google_search_results_json(**kwargs: Any) -> BaseTool:
return GoogleSearchResults(api_wrapper=GoogleSearchAPIWrapper(**kwargs))
def _get_serpapi(**kwargs: Any) -> BaseTool:
return Tool( return Tool(
name="Search", name="Search",
description="A search engine. Useful for when you need to answer questions about current events. Input should be a search query.", description="A search engine. Useful for when you need to answer questions about current events. Input should be a search query.",
@ -150,7 +152,7 @@ def _get_serpapi(**kwargs: Any) -> Tool:
) )
def _get_searx_search(**kwargs: Any) -> Tool: def _get_searx_search(**kwargs: Any) -> BaseTool:
return Tool( return Tool(
name="Search", name="Search",
description="A meta search engine. Useful for when you need to answer questions about current events. Input should be a search query.", description="A meta search engine. Useful for when you need to answer questions about current events. Input should be a search query.",
@ -158,6 +160,10 @@ def _get_searx_search(**kwargs: Any) -> Tool:
) )
def _get_bing_search(**kwargs: Any) -> BaseTool:
return BingSearchRun(api_wrapper=BingSearchAPIWrapper(**kwargs))
_EXTRA_LLM_TOOLS = { _EXTRA_LLM_TOOLS = {
"news-api": (_get_news_api, ["news_api_key"]), "news-api": (_get_news_api, ["news_api_key"]),
"tmdb-api": (_get_tmdb_api, ["tmdb_bearer_token"]), "tmdb-api": (_get_tmdb_api, ["tmdb_bearer_token"]),
@ -166,6 +172,11 @@ _EXTRA_LLM_TOOLS = {
_EXTRA_OPTIONAL_TOOLS = { _EXTRA_OPTIONAL_TOOLS = {
"wolfram-alpha": (_get_wolfram_alpha, ["wolfram_alpha_appid"]), "wolfram-alpha": (_get_wolfram_alpha, ["wolfram_alpha_appid"]),
"google-search": (_get_google_search, ["google_api_key", "google_cse_id"]), "google-search": (_get_google_search, ["google_api_key", "google_cse_id"]),
"google-search-results-json": (
_get_google_search_results_json,
["google_api_key", "google_cse_id", "num_results"],
),
"bing-search": (_get_bing_search, ["bing_subscription_key", "bing_search_url"]),
"google-serper": (_get_google_serper, ["serper_api_key"]), "google-serper": (_get_google_serper, ["serper_api_key"]),
"serpapi": (_get_serpapi, ["serpapi_api_key", "aiosession"]), "serpapi": (_get_serpapi, ["serpapi_api_key", "aiosession"]),
"searx-search": (_get_searx_search, ["searx_host", "searx_host"]), "searx-search": (_get_searx_search, ["searx_host", "searx_host"]),
@ -173,13 +184,17 @@ _EXTRA_OPTIONAL_TOOLS = {
def load_tools( def load_tools(
tool_names: List[str], llm: Optional[BaseLLM] = None, **kwargs: Any tool_names: List[str],
) -> List[Tool]: llm: Optional[BaseLLM] = None,
callback_manager: Optional[BaseCallbackManager] = None,
**kwargs: Any,
) -> List[BaseTool]:
"""Load tools based on their name. """Load tools based on their name.
Args: Args:
tool_names: name of tools to load. tool_names: name of tools to load.
llm: Optional language model, may be needed to initialize certain tools. llm: Optional language model, may be needed to initialize certain tools.
callback_manager: Optional callback manager. If not provided, default global callback manager will be used.
Returns: Returns:
List of tools. List of tools.
@ -191,7 +206,10 @@ def load_tools(
elif name in _LLM_TOOLS: elif name in _LLM_TOOLS:
if llm is None: if llm is None:
raise ValueError(f"Tool {name} requires an LLM to be provided") raise ValueError(f"Tool {name} requires an LLM to be provided")
tools.append(_LLM_TOOLS[name](llm)) tool = _LLM_TOOLS[name](llm)
if callback_manager is not None:
tool.callback_manager = callback_manager
tools.append(tool)
elif name in _EXTRA_LLM_TOOLS: elif name in _EXTRA_LLM_TOOLS:
if llm is None: if llm is None:
raise ValueError(f"Tool {name} requires an LLM to be provided") raise ValueError(f"Tool {name} requires an LLM to be provided")
@ -203,12 +221,17 @@ def load_tools(
f"provided: {missing_keys}" f"provided: {missing_keys}"
) )
sub_kwargs = {k: kwargs[k] for k in extra_keys} sub_kwargs = {k: kwargs[k] for k in extra_keys}
tools.append(_get_llm_tool_func(llm=llm, **sub_kwargs)) tool = _get_llm_tool_func(llm=llm, **sub_kwargs)
if callback_manager is not None:
tool.callback_manager = callback_manager
tools.append(tool)
elif name in _EXTRA_OPTIONAL_TOOLS: elif name in _EXTRA_OPTIONAL_TOOLS:
_get_tool_func, extra_keys = _EXTRA_OPTIONAL_TOOLS[name] _get_tool_func, extra_keys = _EXTRA_OPTIONAL_TOOLS[name]
sub_kwargs = {k: kwargs[k] for k in extra_keys if k in kwargs} sub_kwargs = {k: kwargs[k] for k in extra_keys if k in kwargs}
tools.append(_get_tool_func(**sub_kwargs)) tool = _get_tool_func(**sub_kwargs)
if callback_manager is not None:
tool.callback_manager = callback_manager
tools.append(tool)
else: else:
raise ValueError(f"Got unknown tool {name}") raise ValueError(f"Got unknown tool {name}")
return tools return tools

@ -2,7 +2,7 @@
from __future__ import annotations from __future__ import annotations
import re import re
from typing import Any, Callable, List, NamedTuple, Optional, Tuple from typing import Any, Callable, List, NamedTuple, Optional, Sequence, Tuple
from langchain.agents.agent import Agent, AgentExecutor from langchain.agents.agent import Agent, AgentExecutor
from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS, PREFIX, SUFFIX from langchain.agents.mrkl.prompt import FORMAT_INSTRUCTIONS, PREFIX, SUFFIX
@ -11,6 +11,7 @@ from langchain.callbacks.base import BaseCallbackManager
from langchain.chains import LLMChain from langchain.chains import LLMChain
from langchain.llms.base import BaseLLM from langchain.llms.base import BaseLLM
from langchain.prompts import PromptTemplate from langchain.prompts import PromptTemplate
from langchain.tools.base import BaseTool
FINAL_ANSWER_ACTION = "Final Answer:" FINAL_ANSWER_ACTION = "Final Answer:"
@ -69,7 +70,7 @@ class ZeroShotAgent(Agent):
@classmethod @classmethod
def create_prompt( def create_prompt(
cls, cls,
tools: List[Tool], tools: Sequence[BaseTool],
prefix: str = PREFIX, prefix: str = PREFIX,
suffix: str = SUFFIX, suffix: str = SUFFIX,
format_instructions: str = FORMAT_INSTRUCTIONS, format_instructions: str = FORMAT_INSTRUCTIONS,
@ -99,7 +100,7 @@ class ZeroShotAgent(Agent):
def from_llm_and_tools( def from_llm_and_tools(
cls, cls,
llm: BaseLLM, llm: BaseLLM,
tools: List[Tool], tools: Sequence[BaseTool],
callback_manager: Optional[BaseCallbackManager] = None, callback_manager: Optional[BaseCallbackManager] = None,
prefix: str = PREFIX, prefix: str = PREFIX,
suffix: str = SUFFIX, suffix: str = SUFFIX,
@ -125,7 +126,7 @@ class ZeroShotAgent(Agent):
return cls(llm_chain=llm_chain, allowed_tools=tool_names, **kwargs) return cls(llm_chain=llm_chain, allowed_tools=tool_names, **kwargs)
@classmethod @classmethod
def _validate_tools(cls, tools: List[Tool]) -> None: def _validate_tools(cls, tools: Sequence[BaseTool]) -> None:
for tool in tools: for tool in tools:
if tool.description is None: if tool.description is None:
raise ValueError( raise ValueError(
@ -191,7 +192,11 @@ class MRKLChain(AgentExecutor):
mrkl = MRKLChain.from_chains(llm, chains) mrkl = MRKLChain.from_chains(llm, chains)
""" """
tools = [ tools = [
Tool(name=c.action_name, func=c.action, description=c.action_description) Tool(
name=c.action_name,
func=c.action,
description=c.action_description,
)
for c in chains for c in chains
] ]
agent = ZeroShotAgent.from_llm_and_tools(llm, tools) agent = ZeroShotAgent.from_llm_and_tools(llm, tools)

@ -1,6 +1,6 @@
"""Chain that implements the ReAct paper from https://arxiv.org/pdf/2210.03629.pdf.""" """Chain that implements the ReAct paper from https://arxiv.org/pdf/2210.03629.pdf."""
import re import re
from typing import Any, List, Optional, Tuple from typing import Any, List, Optional, Sequence, Tuple
from pydantic import BaseModel from pydantic import BaseModel
@ -12,6 +12,7 @@ from langchain.docstore.base import Docstore
from langchain.docstore.document import Document from langchain.docstore.document import Document
from langchain.llms.base import BaseLLM from langchain.llms.base import BaseLLM
from langchain.prompts.base import BasePromptTemplate from langchain.prompts.base import BasePromptTemplate
from langchain.tools.base import BaseTool
class ReActDocstoreAgent(Agent, BaseModel): class ReActDocstoreAgent(Agent, BaseModel):
@ -23,14 +24,14 @@ class ReActDocstoreAgent(Agent, BaseModel):
return "react-docstore" return "react-docstore"
@classmethod @classmethod
def create_prompt(cls, tools: List[Tool]) -> BasePromptTemplate: def create_prompt(cls, tools: Sequence[BaseTool]) -> BasePromptTemplate:
"""Return default prompt.""" """Return default prompt."""
return WIKI_PROMPT return WIKI_PROMPT
i: int = 1 i: int = 1
@classmethod @classmethod
def _validate_tools(cls, tools: List[Tool]) -> None: def _validate_tools(cls, tools: Sequence[BaseTool]) -> None:
if len(tools) != 2: if len(tools) != 2:
raise ValueError(f"Exactly two tools must be specified, but got {tools}") raise ValueError(f"Exactly two tools must be specified, but got {tools}")
tool_names = {tool.name for tool in tools} tool_names = {tool.name for tool in tools}
@ -108,12 +109,12 @@ class ReActTextWorldAgent(ReActDocstoreAgent, BaseModel):
"""Agent for the ReAct TextWorld chain.""" """Agent for the ReAct TextWorld chain."""
@classmethod @classmethod
def create_prompt(cls, tools: List[Tool]) -> BasePromptTemplate: def create_prompt(cls, tools: Sequence[BaseTool]) -> BasePromptTemplate:
"""Return default prompt.""" """Return default prompt."""
return TEXTWORLD_PROMPT return TEXTWORLD_PROMPT
@classmethod @classmethod
def _validate_tools(cls, tools: List[Tool]) -> None: def _validate_tools(cls, tools: Sequence[BaseTool]) -> None:
if len(tools) != 1: if len(tools) != 1:
raise ValueError(f"Exactly one tool must be specified, but got {tools}") raise ValueError(f"Exactly one tool must be specified, but got {tools}")
tool_names = {tool.name for tool in tools} tool_names = {tool.name for tool in tools}
@ -135,8 +136,16 @@ class ReActChain(AgentExecutor):
"""Initialize with the LLM and a docstore.""" """Initialize with the LLM and a docstore."""
docstore_explorer = DocstoreExplorer(docstore) docstore_explorer = DocstoreExplorer(docstore)
tools = [ tools = [
Tool(name="Search", func=docstore_explorer.search), Tool(
Tool(name="Lookup", func=docstore_explorer.lookup), name="Search",
func=docstore_explorer.search,
description="Search for a term in the docstore.",
),
Tool(
name="Lookup",
func=docstore_explorer.lookup,
description="Lookup a term in the docstore.",
),
] ]
agent = ReActDocstoreAgent.from_llm_and_tools(llm, tools) agent = ReActDocstoreAgent.from_llm_and_tools(llm, tools)
super().__init__(agent=agent, tools=tools, **kwargs) super().__init__(agent=agent, tools=tools, **kwargs)

@ -1,5 +1,5 @@
"""Chain that does self ask with search.""" """Chain that does self ask with search."""
from typing import Any, List, Optional, Tuple, Union from typing import Any, Optional, Sequence, Tuple, Union
from langchain.agents.agent import Agent, AgentExecutor from langchain.agents.agent import Agent, AgentExecutor
from langchain.agents.self_ask_with_search.prompt import PROMPT from langchain.agents.self_ask_with_search.prompt import PROMPT
@ -7,6 +7,7 @@ from langchain.agents.tools import Tool
from langchain.llms.base import BaseLLM from langchain.llms.base import BaseLLM
from langchain.prompts.base import BasePromptTemplate from langchain.prompts.base import BasePromptTemplate
from langchain.serpapi import SerpAPIWrapper from langchain.serpapi import SerpAPIWrapper
from langchain.tools.base import BaseTool
from langchain.utilities.google_serper import GoogleSerperAPIWrapper from langchain.utilities.google_serper import GoogleSerperAPIWrapper
@ -19,12 +20,12 @@ class SelfAskWithSearchAgent(Agent):
return "self-ask-with-search" return "self-ask-with-search"
@classmethod @classmethod
def create_prompt(cls, tools: List[Tool]) -> BasePromptTemplate: def create_prompt(cls, tools: Sequence[BaseTool]) -> BasePromptTemplate:
"""Prompt does not depend on tools.""" """Prompt does not depend on tools."""
return PROMPT return PROMPT
@classmethod @classmethod
def _validate_tools(cls, tools: List[Tool]) -> None: def _validate_tools(cls, tools: Sequence[BaseTool]) -> None:
if len(tools) != 1: if len(tools) != 1:
raise ValueError(f"Exactly one tool must be specified, but got {tools}") raise ValueError(f"Exactly one tool must be specified, but got {tools}")
tool_names = {tool.name for tool in tools} tool_names = {tool.name for tool in tools}
@ -87,6 +88,8 @@ class SelfAskWithSearchChain(AgentExecutor):
**kwargs: Any, **kwargs: Any,
): ):
"""Initialize with just an LLM and a search chain.""" """Initialize with just an LLM and a search chain."""
search_tool = Tool(name="Intermediate Answer", func=search_chain.run) search_tool = Tool(
name="Intermediate Answer", func=search_chain.run, description="Search"
)
agent = SelfAskWithSearchAgent.from_llm_and_tools(llm, [search_tool]) agent = SelfAskWithSearchAgent.from_llm_and_tools(llm, [search_tool])
super().__init__(agent=agent, tools=[search_tool], **kwargs) super().__init__(agent=agent, tools=[search_tool], **kwargs)

@ -1,31 +1,53 @@
"""Interface for tools.""" """Interface for tools."""
import asyncio
from dataclasses import dataclass
from inspect import signature from inspect import signature
from typing import Any, Awaitable, Callable, Optional, Union from typing import Any, Awaitable, Callable, Optional, Union
from langchain.tools.base import BaseTool
@dataclass
class Tool:
"""Interface for tools."""
name: str class Tool(BaseTool):
"""Tool that takes in function or coroutine directly."""
description: str = ""
func: Callable[[str], str] func: Callable[[str], str]
description: Optional[str] = None
return_direct: bool = False
# If the tool has a coroutine, then we can use this to run it asynchronously
coroutine: Optional[Callable[[str], Awaitable[str]]] = None coroutine: Optional[Callable[[str], Awaitable[str]]] = None
def __call__(self, *args: Any, **kwargs: Any) -> str: def _run(self, tool_input: str) -> str:
"""Make tools callable by piping through to `func`.""" """Use the tool."""
if asyncio.iscoroutinefunction(self.func): return self.func(tool_input)
raise TypeError("Coroutine cannot be called directly")
return self.func(*args, **kwargs) async def _arun(self, tool_input: str) -> str:
"""Use the tool asynchronously."""
if self.coroutine:
return await self.coroutine(tool_input)
raise NotImplementedError("Tool does not support async")
# TODO: this is for backwards compatibility, remove in future
def __init__(
self, name: str, func: Callable[[str], str], description: str, **kwargs: Any
) -> None:
"""Initialize tool."""
super(Tool, self).__init__(
name=name, func=func, description=description, **kwargs
)
class InvalidTool(BaseTool):
"""Tool that is run when invalid tool name is encountered by agent."""
name = "invalid_tool"
description = "Called when tool name is invalid."
def _run(self, tool_name: str) -> str:
"""Use the tool."""
return f"{tool_name} is not a valid tool, try another one."
async def _arun(self, tool_name: str) -> str:
"""Use the tool asynchronously."""
return f"{tool_name} is not a valid tool, try another one."
def tool( def tool(*args: Union[str, Callable], return_direct: bool = False) -> Callable:
*args: Union[str, Callable], return_direct: bool = False
) -> Union[Callable, Tool]:
"""Make tools out of functions, can be used with or without arguments. """Make tools out of functions, can be used with or without arguments.
Requires: Requires:
@ -52,13 +74,13 @@ def tool(
# Description example: # Description example:
# search_api(query: str) - Searches the API for the query. # search_api(query: str) - Searches the API for the query.
description = f"{tool_name}{signature(func)} - {func.__doc__.strip()}" description = f"{tool_name}{signature(func)} - {func.__doc__.strip()}"
tool = Tool( tool_ = Tool(
name=tool_name, name=tool_name,
func=func, func=func,
description=description, description=description,
return_direct=return_direct, return_direct=return_direct,
) )
return tool return tool_
return _make_tool return _make_tool
@ -73,7 +95,7 @@ def tool(
elif len(args) == 0: elif len(args) == 0:
# if there are no arguments, then we use the function name as the tool name # if there are no arguments, then we use the function name as the tool name
# Example usage: @tool(return_direct=True) # Example usage: @tool(return_direct=True)
def _partial(func: Callable[[str], str]) -> Tool: def _partial(func: Callable[[str], str]) -> BaseTool:
return _make_with_name(func.__name__)(func) return _make_with_name(func.__name__)(func)
return _partial return _partial

@ -0,0 +1,5 @@
"""Core toolkit implementations."""
from langchain.tools.base import BaseTool
__all__ = ["BaseTool"]

@ -0,0 +1,131 @@
"""Base implementation for tools or skills."""
from abc import abstractmethod
from typing import Any, List, Optional
from pydantic import BaseModel, Extra, Field, validator
from langchain.callbacks import get_callback_manager
from langchain.callbacks.base import BaseCallbackManager
from langchain.schema import AgentAction
class BaseTool(BaseModel):
"""Class responsible for defining a tool or skill for an LLM."""
name: str
description: str
return_direct: bool = False
verbose: bool = False
callback_manager: BaseCallbackManager = Field(default_factory=get_callback_manager)
class Config:
"""Configuration for this pydantic object."""
extra = Extra.forbid
arbitrary_types_allowed = True
@validator("callback_manager", pre=True, always=True)
def set_callback_manager(
cls, callback_manager: Optional[BaseCallbackManager]
) -> BaseCallbackManager:
"""If callback manager is None, set it.
This allows users to pass in None as callback manager, which is a nice UX.
"""
return callback_manager or get_callback_manager()
@abstractmethod
def _run(self, tool_input: str) -> str:
"""Use the tool."""
@abstractmethod
async def _arun(self, tool_input: str) -> str:
"""Use the tool asynchronously."""
def __call__(self, tool_input: str) -> str:
"""Make tools callable with str input."""
agent_action = AgentAction(tool_input=tool_input, tool=self.name, log="")
return self.run(agent_action)
def run(
self,
action: AgentAction,
verbose: Optional[bool] = None,
start_color: Optional[str] = "green",
color: Optional[str] = "green",
**kwargs: Any
) -> str:
"""Run the tool."""
if verbose is None:
verbose = self.verbose
self.callback_manager.on_tool_start(
{"name": self.name, "description": self.description},
action,
verbose=verbose,
color=start_color,
**kwargs,
)
try:
observation = self._run(action.tool_input)
except (Exception, KeyboardInterrupt) as e:
self.callback_manager.on_tool_error(e, verbose=verbose)
raise e
self.callback_manager.on_tool_end(
observation, verbose=verbose, color=color, **kwargs
)
return observation
async def arun(
self,
action: AgentAction,
verbose: Optional[bool] = None,
start_color: Optional[str] = "green",
color: Optional[str] = "green",
**kwargs: Any
) -> str:
"""Run the tool asynchronously."""
if verbose is None:
verbose = self.verbose
if self.callback_manager.is_async:
await self.callback_manager.on_tool_start(
{"name": self.name, "description": self.description},
action,
verbose=verbose,
color=start_color,
**kwargs,
)
else:
self.callback_manager.on_tool_start(
{"name": self.name, "description": self.description},
action,
verbose=verbose,
color=start_color,
**kwargs,
)
try:
# We then call the tool on the tool input to get an observation
observation = await self._arun(action.tool_input)
except (Exception, KeyboardInterrupt) as e:
if self.callback_manager.is_async:
await self.callback_manager.on_tool_error(e, verbose=verbose)
else:
self.callback_manager.on_tool_error(e, verbose=verbose)
raise e
if self.callback_manager.is_async:
await self.callback_manager.on_tool_end(
observation, verbose=verbose, color=color, **kwargs
)
else:
self.callback_manager.on_tool_end(
observation, verbose=verbose, color=color, **kwargs
)
return observation
class BaseToolkit(BaseModel):
"""Class responsible for defining a collection of related tools."""
@abstractmethod
def get_tools(self) -> List[BaseTool]:
"""Get the tools in the toolkit."""

@ -0,0 +1 @@
"""Bing Search API toolkit."""

@ -0,0 +1,20 @@
"""Tool for the Bing search API."""
from langchain.tools.base import BaseTool
from langchain.utilities.bing_search import BingSearchAPIWrapper
class BingSearchRun(BaseTool):
"""Tool that adds the capability to query the Bing search API."""
name = "bing_search"
description = "Execute the Bing search API."
api_wrapper: BingSearchAPIWrapper
def _run(self, query: str) -> str:
"""Use the tool."""
return self.api_wrapper.run(query)
async def _arun(self, query: str) -> str:
"""Use the tool asynchronously."""
raise NotImplementedError("BingSearchRun does not support async")

@ -0,0 +1,26 @@
"""Tool for the Bing search API."""
from typing import List
from langchain.tools.base import BaseTool, BaseToolkit
from langchain.tools.bing_search.tool import BingSearchRun
from langchain.utilities.bing_search import BingSearchAPIWrapper
class BingSearchToolkit(BaseToolkit):
"""Tool that adds the capability to query the Bing search API."""
bing_subscription_key: str
bing_search_url: str
def get_tools(self) -> List[BaseTool]:
"""Get the tools in the toolkit."""
wrapper = BingSearchAPIWrapper(
bing_subscription_key=self.bing_subscription_key,
bing_search_url=self.bing_search_url,
)
return [
BingSearchRun(
api_wrapper=wrapper,
)
]

@ -0,0 +1 @@
"""Google Search API Toolkit."""

@ -0,0 +1,41 @@
"""Tool for the Google search API."""
from langchain.tools.base import BaseTool
from langchain.utilities.google_search import GoogleSearchAPIWrapper
class GoogleSearchRun(BaseTool):
"""Tool that adds the capability to query the Google search API."""
name = "google_search"
description = "Execute the Google search API."
api_wrapper: GoogleSearchAPIWrapper
def _run(self, query: str) -> str:
"""Use the tool."""
return self.api_wrapper.run(query)
async def _arun(self, query: str) -> str:
"""Use the tool asynchronously."""
raise NotImplementedError("GoogleSearchRun does not support async")
class GoogleSearchResults(BaseTool):
"""Tool that has capability to query the Google Search API and get back json."""
name = "Google Search Results JSON"
description = (
"A wrapper around Google Search. "
"Useful for when you need to answer questions about current events. "
"Input should be a search query. Output is a JSON array of the query results"
)
num_results: int = 4
api_wrapper: GoogleSearchAPIWrapper
def _run(self, query: str) -> str:
"""Use the tool."""
return str(self.api_wrapper.results(query, self.num_results))
async def _arun(self, query: str) -> str:
"""Use the tool asynchronously."""
raise NotImplementedError("GoogleSearchRun does not support async")

@ -0,0 +1,26 @@
"""Tool for the Google search API."""
from typing import List
from langchain.tools.base import BaseTool, BaseToolkit
from langchain.tools.google_search.tool import GoogleSearchRun
from langchain.utilities.google_search import GoogleSearchAPIWrapper
class GoogleSearchToolkit(BaseToolkit):
"""Tool that adds the capability to query the Google search API."""
google_subscription_key: str
google_search_url: str
def get_tools(self) -> List[BaseTool]:
"""Get the tools in the toolkit."""
wrapper = GoogleSearchAPIWrapper(
google_api_key=self.google_subscription_key,
google_search_url=self.google_search_url,
)
return [
GoogleSearchRun(
api_wrapper=wrapper,
)
]

@ -0,0 +1 @@
"""Wolfram Alpha API toolkit."""

@ -0,0 +1,20 @@
"""Tool for the Wolfram Alpha API."""
from langchain.tools.base import BaseTool
from langchain.utilities.wolfram_alpha import WolframAlphaAPIWrapper
class WolframAlphaQueryRun(BaseTool):
"""Tool that adds the capability to query using the Wolfram Alpha SDK."""
name = "query_wolfram_alpha"
description = "Query Wolfram Alpha with the given query."
api_wrapper: WolframAlphaAPIWrapper
def _run(self, query: str) -> str:
"""Use the WolframAlpha tool."""
return self.api_wrapper.run(query)
async def _arun(self, query: str) -> str:
"""Use the WolframAlpha tool asynchronously."""
raise NotImplementedError("WolframAlphaQueryRun does not support async")

@ -0,0 +1,22 @@
"""Toolkit for the Wolfram Alpha API."""
from typing import List
from langchain.tools.base import BaseTool, BaseToolkit
from langchain.tools.wolfram_alpha.tool import WolframAlphaQueryRun
from langchain.utilities.wolfram_alpha import WolframAlphaAPIWrapper
class WolframAlphaToolkit(BaseToolkit):
"""Tool that adds the capability to interact with Wolfram Alpha."""
wolfram_alpha_appid: str
def get_tools(self) -> List[BaseTool]:
"""Get the tools in the toolkit."""
wrapper = WolframAlphaAPIWrapper(wolfram_alpha_appid=self.wolfram_alpha_appid)
return [
WolframAlphaQueryRun(
api_wrapper=wrapper,
)
]

@ -4,7 +4,8 @@ from typing import Any, List, Mapping, Optional
from pydantic import BaseModel from pydantic import BaseModel
from langchain.agents import AgentExecutor, Tool, initialize_agent from langchain.agents import AgentExecutor, initialize_agent
from langchain.agents.tools import Tool
from langchain.callbacks.base import CallbackManager from langchain.callbacks.base import CallbackManager
from langchain.llms.base import LLM from langchain.llms.base import LLM
from tests.unit_tests.callbacks.fake_callback_handler import FakeCallbackHandler from tests.unit_tests.callbacks.fake_callback_handler import FakeCallbackHandler
@ -42,8 +43,16 @@ def _get_agent(**kwargs: Any) -> AgentExecutor:
] ]
fake_llm = FakeListLLM(responses=responses) fake_llm = FakeListLLM(responses=responses)
tools = [ tools = [
Tool("Search", lambda x: x, "Useful for searching"), Tool(
Tool("Lookup", lambda x: x, "Useful for looking up things in a table"), name="Search",
func=lambda x: x,
description="Useful for searching",
),
Tool(
name="Lookup",
func=lambda x: x,
description="Useful for looking up things in a table",
),
] ]
agent = initialize_agent( agent = initialize_agent(
tools, fake_llm, agent="zero-shot-react-description", verbose=True, **kwargs tools, fake_llm, agent="zero-shot-react-description", verbose=True, **kwargs
@ -79,7 +88,12 @@ def test_agent_with_callbacks_global() -> None:
] ]
fake_llm = FakeListLLM(responses=responses, callback_manager=manager, verbose=True) fake_llm = FakeListLLM(responses=responses, callback_manager=manager, verbose=True)
tools = [ tools = [
Tool("Search", lambda x: x, "Useful for searching"), Tool(
name="Search",
func=lambda x: x,
description="Useful for searching",
callback_manager=manager,
),
] ]
agent = initialize_agent( agent = initialize_agent(
tools, tools,
@ -118,7 +132,12 @@ def test_agent_with_callbacks_local() -> None:
] ]
fake_llm = FakeListLLM(responses=responses, callback_manager=manager, verbose=True) fake_llm = FakeListLLM(responses=responses, callback_manager=manager, verbose=True)
tools = [ tools = [
Tool("Search", lambda x: x, "Useful for searching"), Tool(
name="Search",
func=lambda x: x,
description="Useful for searching",
callback_manager=manager,
),
] ]
agent = initialize_agent( agent = initialize_agent(
tools, tools,
@ -159,7 +178,11 @@ def test_agent_with_callbacks_not_verbose() -> None:
] ]
fake_llm = FakeListLLM(responses=responses, callback_manager=manager) fake_llm = FakeListLLM(responses=responses, callback_manager=manager)
tools = [ tools = [
Tool("Search", lambda x: x, "Useful for searching"), Tool(
name="Search",
func=lambda x: x,
description="Useful for searching",
),
] ]
agent = initialize_agent( agent = initialize_agent(
tools, tools,
@ -186,7 +209,12 @@ def test_agent_tool_return_direct() -> None:
] ]
fake_llm = FakeListLLM(responses=responses) fake_llm = FakeListLLM(responses=responses)
tools = [ tools = [
Tool("Search", lambda x: x, "Useful for searching", return_direct=True), Tool(
name="Search",
func=lambda x: x,
description="Useful for searching",
return_direct=True,
),
] ]
agent = initialize_agent( agent = initialize_agent(
tools, tools,
@ -204,7 +232,12 @@ def test_agent_with_new_prefix_suffix() -> None:
responses=["FooBarBaz\nAction: Search\nAction Input: misalignment"] responses=["FooBarBaz\nAction: Search\nAction Input: misalignment"]
) )
tools = [ tools = [
Tool("Search", lambda x: x, "Useful for searching", return_direct=True), Tool(
name="Search",
func=lambda x: x,
description="Useful for searching",
return_direct=True,
),
] ]
prefix = "FooBarBaz" prefix = "FooBarBaz"

@ -58,8 +58,8 @@ def test_predict_until_observation_normal() -> None:
outputs = ["foo\nAction 1: Search[foo]"] outputs = ["foo\nAction 1: Search[foo]"]
fake_llm = FakeListLLM(responses=outputs) fake_llm = FakeListLLM(responses=outputs)
tools = [ tools = [
Tool("Search", lambda x: x), Tool(name="Search", func=lambda x: x, description="foo"),
Tool("Lookup", lambda x: x), Tool(name="Lookup", func=lambda x: x, description="bar"),
] ]
agent = ReActDocstoreAgent.from_llm_and_tools(fake_llm, tools) agent = ReActDocstoreAgent.from_llm_and_tools(fake_llm, tools)
output = agent.plan([], input="") output = agent.plan([], input="")
@ -72,8 +72,8 @@ def test_predict_until_observation_repeat() -> None:
outputs = ["foo", " Search[foo]"] outputs = ["foo", " Search[foo]"]
fake_llm = FakeListLLM(responses=outputs) fake_llm = FakeListLLM(responses=outputs)
tools = [ tools = [
Tool("Search", lambda x: x), Tool(name="Search", func=lambda x: x, description="foo"),
Tool("Lookup", lambda x: x), Tool(name="Lookup", func=lambda x: x, description="bar"),
] ]
agent = ReActDocstoreAgent.from_llm_and_tools(fake_llm, tools) agent = ReActDocstoreAgent.from_llm_and_tools(fake_llm, tools)
output = agent.plan([], input="") output = agent.plan([], input="")

@ -2,6 +2,7 @@
import pytest import pytest
from langchain.agents.tools import Tool, tool from langchain.agents.tools import Tool, tool
from langchain.schema import AgentAction
def test_unnamed_decorator() -> None: def test_unnamed_decorator() -> None:
@ -65,3 +66,42 @@ def test_missing_docstring() -> None:
@tool @tool
def search_api(query: str) -> str: def search_api(query: str) -> str:
return "API result" return "API result"
def test_create_tool_posistional_args() -> None:
"""Test that positional arguments are allowed."""
test_tool = Tool("test_name", lambda x: x, "test_description")
assert test_tool("foo") == "foo"
assert test_tool.name == "test_name"
assert test_tool.description == "test_description"
def test_create_tool_keyword_args() -> None:
"""Test that keyword arguments are allowed."""
test_tool = Tool(name="test_name", func=lambda x: x, description="test_description")
assert test_tool("foo") == "foo"
assert test_tool.name == "test_name"
assert test_tool.description == "test_description"
@pytest.mark.asyncio
async def test_create_async_tool() -> None:
"""Test that async tools are allowed."""
async def _test_func(x: str) -> str:
return x
test_tool = Tool(
name="test_name",
func=lambda x: x,
description="test_description",
coroutine=_test_func,
)
assert test_tool("foo") == "foo"
assert test_tool.name == "test_name"
assert test_tool.description == "test_description"
assert test_tool.coroutine is not None
assert (
await test_tool.arun(AgentAction(tool_input="foo", tool="test_name", log=""))
== "foo"
)

Loading…
Cancel
Save