Lesson 4 of 6~3 min read
Lesson 3 — Building the Agent Loop
Now you connect the tools to the AI and build the loop that lets it work autonomously.
Lesson 3 — Building the Agent Loop
Now you connect the tools to the AI and build the loop that lets it work autonomously.
# Tool definitions — this is how you tell Claude what tools exist
TOOLS = [
{
"name": "search_web",
"description": "Search the internet for information. Use this to find sources on a topic.",
"input_schema": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search query"
},
"max_results": {
"type": "integer",
"description": "Number of results to return (default 5)",
"default": 5
}
},
"required": ["query"]
}
},
{
"name": "read_page",
"description": "Read the content of a specific webpage URL. Use this after searching to get full details.",
"input_schema": {
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "The URL to read"
}
},
"required": ["url"]
}
}
]
def run_tool(name: str, inputs: dict) -> str:
"""Execute a tool by name and return the result as a string."""
if name == "search_web":
results = search_web(inputs["query"], inputs.get("max_results", 5))
return "\n\n".join([
f"Title: {r['title']}\nURL: {r['url']}\nSnippet: {r['content']}"
for r in results
])
elif name == "read_page":
return read_page(inputs["url"])
return f"Unknown tool: {name}"
def run_agent(goal: str) -> str:
"""Run the research agent on a goal and return the final report."""
system = """You are a research agent. Your job is to thoroughly research a topic and produce a well-structured report.
Process:
Be thorough. Don't stop after one search. Good research takes multiple steps."""
messages = [{"role": "user", "content": goal}]
print(f"\n🔍 Starting research: {goal}\n")
while True:
response = anthropic_client.messages.create(
model="claude-opus-4-6",
max_tokens=4096,
system=system,
tools=TOOLS,
messages=messages
)
# If the model is done (no more tool calls), return its final message
if response.stop_reason == "end_turn":
final_text = next(
(block.text for block in response.content if hasattr(block, "text")),
"No response generated."
)
return final_text
# Process tool calls
messages.append({"role": "assistant", "content": response.content})
tool_results = []
for block in response.content:
if block.type == "tool_use":
print(f" → Using tool: {block.name}({list(block.input.values())[0] if block.input else ''})")
result = run_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result
})
if tool_results:
messages.append({"role": "user", "content": tool_results})
# Run it
if __name__ == "__main__":
research_goal = input("What should I research? ")
report = run_agent(research_goal)
print("\n" + "="*60)
print("RESEARCH REPORT")
print("="*60)
print(report)
Save this as `agent.py`, run `python agent.py`, and type in a research question. Watch the terminal as the agent searches, reads, and reasons its way to an answer. That's the split-screen moment right there.