This repository contains the code developed as I worked through the "Build an AI Agent in Python" course on Boot.dev. The project focuses on creating a toy agentic code editor, leveraging Large Language Models (LLMs) and function calling to find and fix bugs in Python code.
├── calculator/ # A toy program for the Agent to work on. The agent will only access files under this working directory.
├── functions/ # Function tools for the agent to call. These enable the agent to take actual action.
│ ├── get_file_content.py
│ ├── get_files_info.py
│ ├── run_python.py
│ └── write_file.py
├── main.py # Main script to accept the user's prompt and let the agent run.
└── requirements.txt
Running the code could actually modify your files. This code limits the agent's hand within a working directory (which is hardcoded to calculator/
in ./main.py
). It is probably better to understand the code before running it. Use with CAUTION should you choose to play with it blindly.
Steps:
- Clone the repository, install requirements.
- Create an
.env
file with Gemini API keyGEMINI_API_KEY=...
python main.py "YOUR PROMPT"
The course prompt the agent to debug and fix the code, which is quite amazing to see for the first time. Here is a simpler example that ask it to read and explain the code.
python main.py "read and explain the code under calculator/"
The terminal output:
- Calling function: get_files_info
- Calling function: get_files_info
- Calling function: get_file_content
Okay, I have read the content of `main.py`. Here's an explanation:
1. **Imports:**
* `sys`: This module provides access to system-specific parameters and functions, including command-line arguments.
* `Calculator` from `pkg.calculator`: This imports a `Calculator` class from a module named `calculator` within a package named `pkg`. It's assumed that this class handles the evaluation of mathematical expressions.
* `render` from `pkg.render`: This imports a `render` function from a module named `render` within the `pkg` package. It's likely that this function formats the expression and result into a user-friendly string.
2. **`main` Function:**
* It creates an instance of the `Calculator` class.
* It checks if any command-line arguments are provided (other than the script name itself). If not, it prints usage instructions and exits.
* It joins the command-line arguments into a single string, which is treated as the mathematical expression to evaluate.
* It uses a `try...except` block to handle potential errors during evaluation:
* Inside the `try` block:
* It calls the `evaluate` method of the `Calculator` object to calculate the result of the expression.
* It calls the `render` function to format the expression and the result into a string.
* It prints the formatted string to the console.
* Inside the `except` block:
* If any exception occurs during the evaluation or rendering, it catches the exception, prints an error message to the console, and exits.
3. **`if __name__ == "__main__":` block:**
* This ensures that the `main` function is called only when the script is executed directly (not when it's imported as a module).
In summary, `main.py` is the entry point of a calculator application. It takes a mathematical expression as a command-line argument, evaluates it using a `Calculator` class (presumably defined elsewhere), formats the output using a `render` function (also defined elsewhere), and prints the result to the console. It also includes basic error handling and usage instructions.
- It did use the function tool to read the python code
calculator/main.py
- I am not completely satisfied, as I expect it to read the files in
calculator/pkg/
and explain everything.
- An agent needs a feedback loop.
- When it can take actions and see the outcome, it can continue to make follow-up plans and decisions.
- The LLM is the brain. It can read, speak, and plan the next step, but it cannot act.
- We (main.py) make real-world actions available and describe them to the LLM.
- When the LLM decides to use a tool, we perform the actual action in its place.
- The outcome of the action is gathered and passed back to the LLM like an observation.
- We need to keep track of the changes an agent made.
- Without historical records (like git), it would be difficult, if not impossible, to see what has been done.
- The agent could amazingly do what you want, but it could also mess things up.
- Limiting the scope and power of the agent is important to avoid unwanted side effects.
- An agent is as powerful and as dangerous as the tools it can access.
- To design and build a safe and helpful agent system is no simple task.
- You don't want your agent to do real world harms just becase the LLM strays away.