RUNLOCALAIv38
->Will it run?Best GPUCompareTroubleshootStartLearnPulseModelsHardwareToolsBench
Run check
RUNLOCALAI

Independently operated catalog for local-AI hardware and software. Hand-written verdicts. Source-cited claims. Reproducible commands when we have them.

OP·Eruo Fredoline
DIR
  • Models
  • Hardware
  • Tools
  • Benchmarks
TOOLS
  • Will it run?
  • Compare hardware
  • Cost vs cloud
  • Choose my GPU
  • Prompting kits
  • Quick answers
REF
  • All buyer guides
  • Learn local AI
  • Methodology
  • Glossary
  • Errors KB
  • Trust
EDITOR
  • About
  • Author
  • How we make money
  • Editorial policy
  • Contact
LEGAL
  • Privacy
  • Terms
  • Sitemap
MAIL · MONTHLY DIGEST
Get monthly local AI changes
Monthly recap. No spam.
DISCLOSURE

Some links on this site are affiliate links (Amazon Associates and other first-class retailers). When you buy through them, we earn a small commission at no extra cost to you. Affiliate links do not influence our verdicts — there are cards we rate highly that we don't have affiliate relationships with, and cards that sell well that we refuse to recommend. Read more →

© 2026 runlocalai.coIndependently operated
RUNLOCALAI · v38
  1. >
  2. Home
  3. /Learn
  4. /Courses
  5. /Introduction to AI Agents
  6. /Ch. 16
Introduction to AI Agents

16. Agent Project: Research Assistant

Chapter 16 of 16 · 20 min
KEY INSIGHT

The research assistant demonstrates the full agent lifecycle: planning, multi-tool orchestration, memory management, and evaluation. Each chapter feeds into this project, and each extension connects back to a specific concept.

This final chapter combines every concept into a working research assistant that can accept a research query, search the web for information, process results, and produce a structured written report.

Project structure

# research_assistant/
# ├── agent.py          # Main agent class
# ├── tools.py          # Tool definitions
# ├── memory.py         # Memory management
# ├── planner.py        # Task planning and decomposition
# ├── evaluator.py      # Test suite
# └── main.py           # Entry point

The agent implementation

# agent.py
import ollama
from tools import WebSearchTool, CalculatorTool
from memory import HierarchicalMemory
from planner import plan_task

class ResearchAssistant:
    def __init__(self, model: str = "llama3.2"):
        self.model = model
        self.tools = [WebSearchTool(), CalculatorTool()]
        self.tool_map = {t.name: t for t in self.tools}
        self.memory = HierarchicalMemory(window_size=15)
        self.max_turns = 20
    
    def research(self, query: str) -> str:
        """Run a complete research task from query to report"""
        steps = plan_task(query, self)
        
        messages = [
            {"role": "system", "content": (
                "You are a research assistant. Use web search to find facts, "
                "use calculator for any needed computations, and provide a "
                "well-structured summary in your final response."
            )},
            {"role": "user", "content": f"Research task: {query}\n\nPlanned steps: {'; '.join(steps)}"}
        ]
        
        for turn in range(self.max_turns):
            tool_schemas = [t.to_openai_schema() for t in self.tools]
            response = ollama.chat(model=self.model, messages=messages, tools=tool_schemas)
            
            if not response.message.tool_calls:
                # Check if this is a final answer
                messages.append({"role": "assistant", "content": response.message.content})
                self.memory.add(query, response.message.content)
                return response.message.content
            
            for call in response.message.tool_calls:
                tool_name = call.function.name
                if tool_name not in self.tool_map:
                    continue
                
                result = self.tool_map[tool_name].invoke(**call.function.arguments)
                messages.append({"role": "assistant", "content": "", "tool_calls": [call]})
                messages.append({"role": "tool", "tool_call_id": call.id, "content": result})
        
        return "Research incomplete due to max turns limit"

Running the project

# Install dependencies
pip install ollama duckduckgo-search requests jsonschema

# Pull a tool-capable model
ollama pull llama3.2

# Run a research query
python main.py "Compare AI regulation in the EU and US"

Example output

For the query "Compare AI regulation in the EU and US," the agent:

  1. Plans three steps: research EU AI Act, research US Executive Order, draft comparison
  2. Calls web_search for "EU AI Act key provisions 2024"
  3. Calls web_search for "US AI Executive Order 2023 key provisions"
  4. Calls calculator for any quantitative comparisons (e.g., fine amounts)
  5. Generates a structured report with sections on scope, enforcement, and impact

Extending the project

  • Add a file writer tool to save reports to disk
  • Add a citation tool that returns structured references
  • Integrate structured memory to track multi-session research threads
  • Add an evaluation harness that runs multiple research queries and scores the outputs
EXERCISE

Extend the research assistant with a file writing tool. Add the tool, test it by writing a research report to disk, and verify the file contents match the agent's final output. Then run the evaluation suite from Chapter 15 against the extended agent. ```

← Chapter 15
Agent Evaluation
Course complete →
Browse all courses