AI agents are programs that use language models to plan and execute multi-step tasks autonomously. Instead of answering one question at a time, an agent decides what to do, does it, checks the result, and continues until the task is complete.
This guide builds a working agent from scratch using Python and a free local model via Ollama.
What youβll build
A research agent that:
- Takes a topic from you
- Searches the web for information
- Reads and summarizes the results
- Writes a structured report
- Saves it to a file
No API costs. Everything runs locally.
Prerequisites
- Python 3.10+
- Ollama installed with a model pulled
- Basic Python knowledge
# Install Ollama and pull a model
curl -fsSL https://ollama.com/install.sh | sh
ollama pull gemma4:26b
Gemma 4 26B is recommended β it handles agent tasks well at only 8 GB RAM. For lighter hardware, Gemma 4 E4B works too.
Step 1: The basic agent loop
Every agent follows the same pattern: think β act β observe β repeat.
import json
import requests
OLLAMA_URL = "http://localhost:11434/v1/chat/completions"
MODEL = "gemma4:26b"
def chat(messages):
"""Send messages to the local model and get a response."""
response = requests.post(OLLAMA_URL, json={
"model": MODEL,
"messages": messages,
"temperature": 0.3
})
return response.json()["choices"][0]["message"]["content"]
def agent_loop(task, max_steps=5):
"""Run the agent loop: think, act, observe, repeat."""
messages = [
{"role": "system", "content": """You are an AI agent that completes tasks step by step.
For each step, respond with JSON:
{"thought": "what you're thinking", "action": "action_name", "input": "action input"}
Available actions:
- search: Search the web for information
- write_file: Write content to a file
- done: Task is complete
When the task is complete, use action "done"."""},
{"role": "user", "content": task}
]
for step in range(max_steps):
response = chat(messages)
print(f"\n--- Step {step + 1} ---")
print(response)
try:
parsed = json.loads(response)
except json.JSONDecodeError:
messages.append({"role": "assistant", "content": response})
messages.append({"role": "user", "content": "Please respond with valid JSON."})
continue
action = parsed.get("action", "")
action_input = parsed.get("input", "")
if action == "done":
print("\nβ
Agent completed the task!")
return parsed.get("input", "Task complete")
# Execute the action
result = execute_action(action, action_input)
# Feed the result back to the agent
messages.append({"role": "assistant", "content": response})
messages.append({"role": "user", "content": f"Action result: {result}"})
print("\nβ οΈ Max steps reached")
return "Incomplete"
Step 2: Add tools
Tools are functions the agent can call. Start with two: web search and file writing.
import subprocess
import os
def execute_action(action, action_input):
"""Execute an agent action and return the result."""
if action == "search":
return web_search(action_input)
elif action == "write_file":
return write_file(action_input)
else:
return f"Unknown action: {action}"
def web_search(query):
"""Simple web search using DuckDuckGo."""
try:
import duckduckgo_search
results = duckduckgo_search.DDGS().text(query, max_results=3)
return "\n".join([f"- {r['title']}: {r['body'][:200]}" for r in results])
except ImportError:
return "Install duckduckgo-search: pip install duckduckgo-search"
def write_file(content):
"""Write content to a report file."""
# Parse "filename: content" format
if ":" in content:
filename, text = content.split(":", 1)
filename = filename.strip()
else:
filename = "report.md"
text = content
with open(filename, "w") as f:
f.write(text.strip())
return f"Written to {filename} ({len(text)} chars)"
Step 3: Run it
if __name__ == "__main__":
task = input("What should I research? ")
result = agent_loop(f"Research this topic and write a report: {task}")
print(f"\nResult: {result}")
pip install duckduckgo-search
python agent.py
# > What should I research? The current state of open-source AI models
The agent will search the web, read results, and write a structured report β all using your local Gemma 4 model.
Step 4: Add memory
Agents become more useful when they remember previous tasks. Add a simple file-based memory:
import datetime
MEMORY_FILE = "agent_memory.json"
def save_memory(task, result):
"""Save task results to persistent memory."""
memories = load_memory()
memories.append({
"timestamp": datetime.datetime.now().isoformat(),
"task": task,
"result": result[:500]
})
with open(MEMORY_FILE, "w") as f:
json.dump(memories[-50:], f, indent=2) # Keep last 50
def load_memory():
"""Load previous task results."""
try:
with open(MEMORY_FILE) as f:
return json.load(f)
except (FileNotFoundError, json.JSONDecodeError):
return []
def get_memory_context():
"""Format memories for the agent's context."""
memories = load_memory()
if not memories:
return "No previous tasks."
recent = memories[-5:]
return "\n".join([f"- {m['task']}: {m['result'][:100]}" for m in recent])
Add memory to the system prompt:
{"role": "system", "content": f"""You are an AI agent...
Previous tasks you've completed:
{get_memory_context()}
"""}
Step 5: Add more tools
The more tools your agent has, the more useful it becomes:
def read_file(filename):
"""Read a local file."""
try:
with open(filename) as f:
return f.read()[:2000]
except FileNotFoundError:
return f"File not found: {filename}"
def run_code(code):
"""Execute Python code (careful with this one)."""
try:
result = subprocess.run(
["python3", "-c", code],
capture_output=True, text=True, timeout=10
)
return result.stdout or result.stderr
except subprocess.TimeoutExpired:
return "Code execution timed out"
def list_files(directory="."):
"""List files in a directory."""
return "\n".join(os.listdir(directory))
Going further
Use a framework
For production agents, use an established framework instead of building from scratch:
- OpenClaw β persistent agents with scheduling and multi-model support
- LangGraph β graph-based agent workflows
- CrewAI β multi-agent collaboration
Use better models
Agent quality depends heavily on the model. For complex multi-step tasks:
- Gemma 4 26B β best free option for agents
- Qwen 3.5 Plus β stronger reasoning, needs more RAM
- Claude or GPT via API β best quality if youβre willing to pay
See our best local AI models by task for model recommendations.
Add safety
The agent above can write files and run code β be careful:
- Sandbox code execution (use Docker or a VM)
- Limit file access to specific directories
- Add confirmation prompts for destructive actions
- See our guide on sandboxing local AI models
The complete code
The full agent (~100 lines) is on GitHub. Clone it, install Ollama, and you have a working AI agent in 5 minutes.
AI agents are the next step beyond chatbots. They donβt just answer questions β they get things done. And with local models good enough for agent tasks, you can build and run them for free.
Related: Python Cheat Sheet