├── .github ├── timestamp └── workflows │ └── main.yml ├── .gitignore ├── ai-langchain-react-agent.py ├── readme.md └── requirements.txt /.github/timestamp: -------------------------------------------------------------------------------- 1 | 2025-06-08T04:56:18Z 2 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Timestamp 2 | on: 3 | push: 4 | branches: 5 | - master 6 | schedule: 7 | - cron: '45 4 * * *' 8 | jobs: 9 | auto_commit: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | with: 14 | persist-credentials: false 15 | fetch-depth: 0 16 | - name: Modify timestamp file 17 | run: | 18 | d=`date '+%Y-%m-%dT%H:%M:%SZ'` 19 | echo $d > .github/timestamp 20 | - name: Commit changes 21 | run: | 22 | git config --local user.email "${{ secrets.USEREMAIL }}" 23 | git config --local user.name "${{ secrets.USERNAME }}" 24 | git commit -a -m "Timestamp" 25 | - name: Push Back 26 | uses: ad-m/github-push-action@master 27 | with: 28 | force: true 29 | directory: '.' 30 | github_token: ${{ secrets.GITHUB_TOKEN }} 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | -------------------------------------------------------------------------------- /ai-langchain-react-agent.py: -------------------------------------------------------------------------------- 1 | from langchain import hub 2 | from langchain.agents import Tool, AgentExecutor, create_react_agent 3 | from langchain.prompts import PromptTemplate 4 | from langchain_community.tools import DuckDuckGoSearchRun 5 | from langchain_experimental.tools.python.tool import PythonAstREPLTool 6 | from langchain_openai import ChatOpenAI 7 | 8 | # Set up the LLM 9 | llm = ChatOpenAI( 10 | openai_api_key = 'REPLACE_THIS_WITH_YOUR_OPENAI_API_KEY', 11 | temperature = 0, 12 | model = 'gpt-3.5-turbo') 13 | 14 | # Content of the prompt template 15 | template = ''' 16 | Answer the following question as best you can. 17 | Do not use a tool if not required. 18 | Question: {question} 19 | ''' 20 | 21 | # Create the prompt template 22 | prompt_template = PromptTemplate.from_template(template) 23 | prompt = hub.pull('hwchase17/react') 24 | 25 | # Set up the Python REPL tool 26 | python_repl = PythonAstREPLTool() 27 | python_repl_tool = Tool( 28 | name = 'Python REPL', 29 | func = python_repl.run, 30 | description = ''' 31 | A Python shell. Use this to execute python commands. 32 | Input should be a valid python command. 33 | When using this tool, sometimes output is abbreviated - make sure 34 | it does not look abbreviated before using it in your answer. 35 | ''' 36 | ) 37 | 38 | # Set up the DuckDuckGo Search tool 39 | search = DuckDuckGoSearchRun() 40 | duckduckgo_tool = Tool( 41 | name = 'DuckDuckGo Search', 42 | func = search.run, 43 | description = ''' 44 | A wrapper around DuckDuckGo Search. 45 | Useful for when you need to answer questions about current events. 46 | Input should be a search query. 47 | ''' 48 | ) 49 | 50 | # Create an array that contains all the tools used by the agent 51 | tools = [python_repl_tool, duckduckgo_tool] 52 | 53 | # Create a ReAct agent 54 | agent = create_react_agent(llm, tools, prompt) 55 | agent_executor = AgentExecutor( 56 | agent=agent, 57 | tools = tools, 58 | verbose = True, # explain all reasoning steps 59 | handle_parsing_errors=True, # continue on error 60 | max_iterations = 10 # try up to 10 times to find the best answer 61 | ) 62 | 63 | # Ask your question (replace this with your question) 64 | question = "What is '(4876 * 1032 / 85) ^ 3'?" 65 | output = agent_executor.invoke({'input': prompt_template.format(question=question)}) 66 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # LangChain ReAct agent with multiple tools (Python REPL and DuckDuckGo Search) 2 | 3 | This project works with the [OpenAI GPT-3.5 Turbo](https://platform.openai.com/docs/models/gpt-3-5-turbo) Large Language Model (LLM). However, you can also use other OpenAI models that have been trained to handle function calls. 4 | 5 | You need an OpenAI API key for this project. [Get your OpenAI API key here](https://platform.openai.com/login). Insert your OpenAI API key in the "ai-langchain-react-agent.py" script. 6 | 7 | Agents give decision-making powers to Large Language Models (LLMs) and decide which action(s) to take to get the best answer. An Agent can use one or multiple specific "tools". Depending on what the user input (prompt) is, the agent may or may not call any of these tools, or even multiple tools in a row, until it can reason its way to the answer. 8 | 9 | This project uses a ReAct type of agent, which uses the ReAct framework or model for prompting. The basic idea is that the model does Reasoning, which is the Re part, and based on that reasoning it takes Action, which is the Act part. Then based on the result of the action, or its observation, it will go and reason again. 10 | 11 | Tools are the name LangChain uses for what are basically a type of function calls that can run a specific action and return the result. LangChain offers many pre-built tools, but also allows you to build your own tools. 12 | 13 | A Read-Eval-Print Loop (REPL), is a computer environment where user inputs are read and evaluated, and then the results are returned to the user. PythonAstREPLTool is one of the predefined tools that LangChain comes with. It is a tool that will run a Python REPL session and return the output. It is used for complex mathematical calculations, which are often a weakness of LLMs. Python REPL is probably the most powerful of all tools, because it can execute Python program code, such as Python functions. This allows you to use your own applications. 14 | 15 | The DuckDuckGo Search tool is used to search the internet. It does much of the same as "SERP" API's, but it does not require any kind of sign up or payment. This tool is most commonly used to find information that is newer than the cut-off date of the LLM training data. 16 | 17 | ## Some example questions 18 | 19 | You can copy and paste the example questions from this table to replace the question at the bottom of the "ai-langchain-react-agent.py" script. This allows you to verify, if the agent uses the best tool for the question. 20 | 21 | | Expected Tool | Question | 22 | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------ | 23 | | Python REPL | `"What is the result of this python code: '47a93.isalnum()'?"` | 24 | | DuckDuckGo Search | `"What is the Microsoft (MSFT) share price?"` | 25 | | LLM (no tool) | `"A boy runs down the stairs in the morning and sees a tree in his living room, and some boxes under the tree. What's is going on?"` | 26 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/botextractai/ai-langchain-react-agent/34b552efb619c8be05ca621d835cd96456745fc4/requirements.txt --------------------------------------------------------------------------------