Build an AI Research Agent0% done
← PrevNext →
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:

  • Start with broad searches to understand the topic landscape
  • Identify the most relevant sources
  • Read the key pages to extract specific details
  • Synthesize your findings into a clear, structured report
  • Always cite your sources with URLs
  • 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.

    ← PREVIOUSLesson 2 — Setting Up Your ToolsNEXT →Lesson 4 — Watching It Think