AI coding agents are moving beyond simple code completion. A useful AI coding agent can understand a codebase, inspect files, write or modify code, run it, read the resulting errors, and try again. The interesting part is that you can build a practical version of this yourself using Python and a local LLM, without paying for an API.
In this tutorial, I’ll show you how I would build a simple AI coding agent with Python, Ollama, and a small set of tools. The goal isn’t to recreate a production IDE agent. It is to understand the architecture behind one.
What an AI Coding Agent Actually Does
When I explain coding agents to learners, I usually emphasize one thing: the LLM itself is not the agent.
The model provides reasoning and generates tool calls. The agent is the system around it that gives the model access to the codebase and executes those decisions.
A basic coding agent needs to:
- Understand the user’s task.
- Inspect the project structure.
- Read relevant files.
- Decide what needs to change.
- Modify files.
- Execute the code or tests.
- Inspect errors.
- Make another change if necessary.
- Stop when the task is complete.
This creates an iterative loop:

That loop is the core of an AI coding agent.
Building an AI Coding Agent with Python
To avoid paid APIs, I’ll use Ollama, which lets you run supported language models locally. Ollama also supports tool calling, allowing a model to request functions and receive their results before continuing.
First, install Ollama and pull a local model that supports tool calling.
ollama pull qwen3
The important idea is that the model can now become the reasoning component of our agent.
Step 1: Give the Agent Tools
Instead of giving the model unrestricted access to your computer, expose a small number of explicit tools. For our first version, we need:
- list_files() — inspect the project
- read_file() — read source code
- write_file() — modify a file
- run_python() — execute Python code
For example:
from pathlib import Path
ROOT = Path("./workspace").resolve()
def list_files():
return [
str(p.relative_to(ROOT))
for p in ROOT.rglob("*")
if p.is_file()
]
def read_file(path):
target = (ROOT / path).resolve()
if not target.is_relative_to(ROOT):
raise ValueError("Access outside workspace is not allowed")
return target.read_text()
def write_file(path, content):
target = (ROOT / path).resolve()
if not target.is_relative_to(ROOT):
raise ValueError("Access outside workspace is not allowed")
target.write_text(content)
return f"Updated {path}"Path validation is important. An agent should not be able to escape its workspace by requesting something like ../../important_file.
Step 2: Let the Agent Execute Code
The execution tool is what makes the system much more interesting.
Python’s subprocess.run() can execute a command while capturing its output, return code, and errors. It also supports timeouts, which are important when an agent accidentally creates an infinite loop:
import subprocess
def run_python(path):
target = (ROOT / path).resolve()
if not target.is_relative_to(ROOT):
raise ValueError("Access outside workspace is not allowed")
try:
result = subprocess.run(
["python", str(target)],
cwd=ROOT,
capture_output=True,
text=True,
timeout=10
)
return {
"return_code": result.returncode,
"stdout": result.stdout[-4000:],
"stderr": result.stderr[-4000:]
}
except subprocess.TimeoutExpired:
return {
"return_code": -1,
"stdout": "",
"stderr": "Execution timed out."
}This gives the model something extremely valuable: feedback from the real program.
Step 3: Build the Agent Loop
Now we connect the tools to the LLM. Ollama’s tool-calling interface allows the model to request a tool, after which your application executes that tool and sends the result back into the conversation. Its documentation also demonstrates this multi-turn pattern as an agent loop.
The basic structure looks like this:
from ollama import chat
tools = [
list_files,
read_file,
write_file,
run_python
]
messages = [
{
"role": "system",
"content": """
You are a coding agent.
Work only inside the provided workspace.
Inspect files before modifying them.
After making changes, run relevant code or tests.
If execution fails, inspect the error and fix the problem.
Do not claim success until you have verified the result.
"""
},
{
"role": "user",
"content": "Fix the bug in this Python project."
}
]
while True:
response = chat(
model="qwen3",
messages=messages,
tools=tools
)
messages.append(response.message)
if not response.message.tool_calls:
print(response.message.content)
break
for call in response.message.tool_calls:
function = call.function.name
arguments = call.function.arguments
available = {
"list_files": list_files,
"read_file": read_file,
"write_file": write_file,
"run_python": run_python
}
if function in available:
result = available[function](**arguments)
else:
result = "Unknown tool"
messages.append({
"role": "tool",
"tool_name": function,
"content": str(result)
})This is the part I find most valuable to understand. The agent isn’t simply generating code. It is observing the environment and taking actions based on what it observes.
Preparing for AI/ML Interviews?
If you’re building AI projects like this for your portfolio, you’ll also need to explain how they work in interviews. Cracking Your First AI/ML Interview is a resource I’d recommend if you’re preparing for your first AI/ML interview.
Test Your AI Coding Agent
Now that the basic agent is ready, I recommend testing it on a small Python project rather than immediately pointing it at a large codebase.
Create a simple calculator.py file inside your workspace folder:
def calculate_average(numbers):
return sum(numbers) / len(number)
numbers = [10, 20, 30, 40]
print("Average:", calculate_average(numbers))There is an intentional bug in the function:
return sum(numbers) / len(number)
The variable should be numbers, not number.
Now start your agent. After the agent finishes, the corrected code should look like this:
def calculate_average(numbers):
return sum(numbers) / len(numbers)
numbers = [10, 20, 30, 40]
print("Average:", calculate_average(numbers))The Takeaway
When I first started working with AI agents, one of the biggest lessons for me was that the model is only one part of the system.
The real capability comes from connecting the model to tools, feedback, memory, execution, and constraints. If you’re learning AI agents, don’t begin by trying to build a massive autonomous coding system. Build this smaller loop first. Give a local model four or five tools, let it inspect a project, make a change, execute it, read the error, and try again.
Once you understand that loop, concepts like tool calling, agent orchestration, sandboxing, code execution, and multi-agent systems become much easier to understand.
I hope you liked this article on how to build an AI Coding Agent with Python. For more tips on AI and machine learning, you can follow me on Instagram.





