What an Agent Actually Is
At its core, an agent is a loop:
- Receive a task
- Think about what to do
- Take an action (run code, read a file, search)
- Observe the result
- Decide what to do next
- Repeat until done
The LLM handles steps 2, 3, and 5. Your code handles the rest.
Setup
pip3 install ollama --break-system-packages
ollama pull llama3.1:8bA Minimal Agent
# agent.py
import ollama
import subprocess
import json
import re
MODEL = "llama3.1:8b"
SYSTEM_PROMPT = """You are an AI agent that completes tasks by writing and running Python code.
When you want to run code, output it in this format:
<code>
your python code here
</code>
After seeing the output, continue thinking and either run more code or give your final answer.
When you're done, output: DONE: [your final answer]"""
def run_code(code: str) -> str:
try:
result = subprocess.run(
["python3", "-c", code],
capture_output=True,
text=True,
timeout=30
)
output = result.stdout + result.stderr
return output[:2000] if output else "(no output)"
except subprocess.TimeoutExpired:
return "Error: code timed out after 30 seconds"
except Exception as e:
return f"Error: {e}"
def extract_code(text: str):
match = re.search(r'<code>(.*?)</code>', text, re.DOTALL)
return match.group(1).strip() if match else None
def run_agent(task: str, max_steps: int = 10):
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": task}
]
for step in range(max_steps):
print(f"\n--- Step {step + 1} ---")
response = ollama.chat(model=MODEL, messages=messages)
assistant_message = response['message']['content']
print(f"Agent: {assistant_message[:500]}")
messages.append({
"role": "assistant",
"content": assistant_message
})
if "DONE:" in assistant_message:
final = assistant_message.split("DONE:")[-1].strip()
print(f"\nFinal answer: {final}")
return final
code = extract_code(assistant_message)
if code:
print(f"\nRunning code...")
output = run_code(code)
print(f"Output: {output}")
messages.append({
"role": "user",
"content": f"Code output:\n{output}\n\nContinue with the task."
})
return "Max steps reached"
# Example
result = run_agent(
"Calculate the first 20 Fibonacci numbers and find which ones are prime."
)Running It
python3 agent.pyThe agent will write code, run it, see the output, and keep going until it has an answer.
Safe Execution
The example above runs code directly on your server. For production use, sandbox the execution:
# Run code inside a Docker container with no network access
docker run --rm --network none python:3.11-slim python3 -c "your code here"Replace the subprocess.run call with a Docker-based sandbox for untrusted code.
Extending the Agent
Add more tools by giving the agent new action formats:
# Read a file
def read_file(path: str) -> str:
try:
return open(path).read()[:3000]
except Exception as e:
return f"Error: {e}"
# Web search (requires requests)
def search_web(query: str) -> str:
import requests
response = requests.get(
f"https://api.duckduckgo.com/?q={query}&format=json"
)
data = response.json()
return data.get('AbstractText', 'No result found')Document the tools in your system prompt and parse the agent's output for the corresponding action tags.
Running this on NoctHost
An agent loop is only as fast as its model, so budget by model size: a 7B model on the Pro plan (4 vCPU, 8 GB) gives responsive tool-use, while lighter agents run on the Standard plan (2 vCPU, 4 GB). NoctHost bills hourly from a prepaid balance you top up with crypto, no card and no KYC, and the sandbox from earlier keeps an autonomous agent safely boxed in.