Integrating Multiple Tools for Web-Based Question-Answering

Introduction

As developers and information enthusiasts, we often find ourselves needing to utilize various tools and libraries to fetch and process data. By leveraging multiple tools simultaneously, we can create powerful, efficient, and comprehensive solutions for the systems we build with LangChain. This lesson will demonstrate a practical example of combining the power of Google Search with the versatile Python-REPL tool for an effective result. You will learn how to harness the potential of multiple tools working together to streamline your own information retrieval projects.

Let’s be more specific about what exactly we want to accomplish:

  1. Find the answer to a query by searching the web: The agent should use its tools and language model to identify the most relevant sources for it.
  2. Save the answer to a file: After retrieving the answer, the agent is expected to save it to a text file.

Setting Up Libraries

First, we set the necessary API keys as environment variables.

import os

os.environ["OPENAI_API_KEY"] = "<YOUR-OPENAI-API-KEY>"
os.environ["GOOGLE_API_KEY"] = "<YOUR-GOOGLE-SEARCH-API-KEY>"
os.environ["GOOGLE_CSE_ID"] = "<YOUR-CUSTOM-SEARCH-ENGINE-ID>"

You can sign up for these keys by following these instructions:

Next thing, we want to import the libraries we aim to use for our project. Remember to install the required packages with the following command: pip install langchain==0.1.4 deeplake==3.9.27 openai==1.10.0 tiktoken.

from langchain.llms import OpenAI
from langchain.agents import Tool, initialize_agent, AgentType

from langchain.utilities import GoogleSearchAPIWrapper, PythonREPL

We’re going to declare some wrappers. The GoogleSearchAPIWrapper wrapper allows us to easily create a tool for using the Google Search APIs, whereas the PythonREPL wrapper allows the model to execute generated Python code.

search = GoogleSearchAPIWrapper()
python_repl = PythonREPL()

The next code block creates an instance of the OpenAI language model with a temperature parameter set to 0. This parameter influences the randomness of the model's output, and by setting it to 0, the generated responses will be more deterministic and focused.

llm = OpenAI(model="gpt-3.5-turbo-instruct", temperature=0)

Here we have our toolkit set assembled of:

  1. The google-search tool is a convenient way to perform Google searches when an agent needs information about current events. The tool makes use of Google's API to provide relevant search results.
  2. The python_repl tool: This tool wraps a Python shell, allowing the execution of Python commands directly.
toolkit = [
    Tool(
        name="google-search",
        func=search.run,
        description="useful for when you need to search Google to answer questions about current events"
    ),
    Tool(
        name="python_repl",
        description="A Python shell. Use this to execute Python commands. Input should be a valid Python command. Useful for saving strings to files.",
        func=python_repl.run
    )
]

These tools are then added to the toolkit list, which is used to initialize an agent with the specified tools. The agent can then perform various tasks using the tools in its toolkit. The agent can be easily extended by adding more tools to the toolkit, allowing it to handle a wide range of tasks and situations. Let’s instantiate the agent.

agent = initialize_agent(
	toolkit,
	llm,
	agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
	verbose=True
)

The parameter agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION specifies the agent's strategy, which means that the agent will attempt to perform tasks without any prior examples, relying solely on its understanding of the problem description and the available tools (and their descriptions).

Now let’s run the experiment! We should be able to ask the Agent directly by giving him instructions on what we want:

agent.run("Find the birth date of Napoleon Bonaparte and save it to a file 'answer.txt'.")

You should see an output like the following.

> Entering new AgentExecutor chain...
 I need to find the date of Napoleon's birth and save it to a file.
Action: google-search
Action Input: "Napoleon Bonaparte birth date"
Observation: Napoleon Bonaparte later known by his regnal name Napoleon I, was a Corsican-born French military commander and political leader who rose to prominence ... Nov 9, 2009 ... Napoleon Bonaparte was born on August 15, 1769, in Ajaccio, on the Mediterranean island of Corsica. He was the second of eight surviving ... Napoleone Buonaparte was born in Ajaccio, Corsica, on 15 August 1769. He was the second of eight children born to Carlo Buonaparte, a lawyer descended from ... May 1, 2023 ... Napoleon I, French in full Napoléon Bonaparte, original Italian Napoleone Buonaparte, byname the Corsican or the Little Corporal, ... Napoleon Bonaparte was born on August 15, 1769. He was most notably known as a French military and political leader, who became prominent during the French ... Furthermore, Charles Bonaparte's “journal” notes the birth on 15 August 1769. It is true that Napoleon very occasionally used the papers of his brother ... Jun 23, 2002 ... Napoleon Bonaparte was born at Ajaccio, Corsica, ... importance of Napoleon the individual argued about his origins and his date of birth. In 1764, Charles-Marie Bonaparte wed the young Letizia Ramolino and settled with her in the Bonaparte family residence. Napoleon was born there on August 15 ... Napoleon Bonaparte was born the 15th of August, 1769 on Corsica, just three months after the island had been defeated by the French. Napoleon was born on the 15th of August, 1769, in French occupied Corsica. His father was Carlo Maria di Buonaparte, and his mother, Maria Letizia Ramolino.
Thought: I have the date of Napoleon's birth.
Action: python_repl
Action Input:

with open('answer.txt', 'w') as f:
    f.write('Napoleon Bonaparte was born on August 15, 1769')

Observation: 
Thought: I have saved the answer to the file.
Final Answer: Napoleon Bonaparte was born on August 15, 1769.

> Finished chain. 

As you can see from the printed output, the agent first used the google-search tool with the query "Napoleon Bonaparte birth date". Upon seeing its result, the agent then wrote the following Python program to save the answer to the answer.txt local file:

with open('answer.txt', 'w') as f:
    f.write('Napoleon Bonaparte was born on August 15, 1769')

You should now have a local file answer.txt containing a text similar to Napoleon Bonaparte, born on August 15, 1769.

Let’s also find the death date of Napoleon and append it to the answer.txt file.

query = "Find when Napoleon Bonaparte died and append this information " \
    "to the content of the 'answer.txt' file in a new line."

agent.run(query)

You should see something similar to the following printed output.

> Entering new AgentExecutor chain...
 I need to find the date of Napoleon's death and then write it to a file.
Action: google-search
Action Input: "When did Napoleon Bonaparte die?"
Observation: Napoleon Bonaparte later known by his regnal name Napoleon I, was a Corsican-born French military commander and political leader who rose to prominence ... Aug 15, 2022 ... Napoleon was only 51 when he died on the island of St. Helena, where he was out of power and exiled from his beloved France. By May 5, 1821, ... Nov 9, 2009 ... In October 1815, Napoleon was exiled to the remote, British-held island of Saint Helena, in the South Atlantic Ocean. He died there on May 5, ... Apr 25, 2014 ... Napoleon Bonaparte died at 5.49pm on 5 May 1821, at Longwood on the island of Saint Helena. An autopsy was carried out on 6 May; ... Jan 21, 2014 ... Was Napoleon poisoned? ... weeks before his demise at age 51, “I die before my time, murdered by the English oligarchy and its assassin. Jan 17, 2007 ... 17, 2007&#151; -- Napoleon Bonaparte died in exile in 1821. But his story never does. His personal physician reported on his death ... May 22, 2023 ... He was the third son of Napoleon I's brother Louis Bonaparte, who was king of Holland from 1806 to 1810, ... How did Napoleon III die? Jan 20, 2003 ... Napoleon was not poisoned, they said. He died of stomach cancer. At a news conference in Paris, Jacques di Costanzo, ... May 1, 2023 ... Napoleon I, French in full Napoléon Bonaparte, original Italian ... It was during Napoleon's year in Paris that his father died of a stomach ... In 1785, when Napoleon was not yet sixteen, his father died of stomach cancer ... Napoleon Bonaparte has continued to inspire passion and interest Read more.
Thought: I now know the date of Napoleon's death.
Action: python_repl
Action Input:

with open('answer.txt', 'a') as f:
    f.write('\nNapoleon Bonaparte died on May 5, 1821.')

Observation: 
Thought: I now know the final answer.
Final Answer: Napoleon Bonaparte died on May 5, 1821.

> Finished chain.

Your final answer.txt should look like the following:

Napoleon Bonaparte was born on August 15, 1769
Napoleon Bonaparte died on May 5, 1821.

This process demonstrates the agent's ability to integrate multiple tools for a single task seamlessly.

Conclusion

In conclusion, we've illustrated how a LangChain agent can effectively employ multiple tools and techniques to accomplish a task, such as doing question-answering on the web and storing the answers in a file. This example highlights the potential of LangChain agents to provide valuable assistance across diverse scenarios.

In the upcoming lesson, we’ll see how to create an ad-hoc tool for retrieving relevant documents from a Deep Lake vector store.