LLM-Powered AI Agents
Module: AI Agents | Difficulty: Advanced
The Agent Paradigm
An AI agent is an autonomous system that perceives its environment, takes actions, and learns to achieve goals. LLM-powered agents use language models as the reasoning backbone, combining language understanding with tool use and planning.
The ReAct Framework
ReAct interleaves reasoning traces with actions:
Thought: I need to research competitors in the AI space. Action: web_search("AI competitors 2024 market analysis") Observation: Found 15 major competitors including...
The mathematical formulation:
Chain-of-Thought Reasoning
The agent generates intermediate reasoning steps:
Tool Use Mathematics
Function Calling as Conditional Generation
Given a set of tools with schemas :
The agent selects which tool to call and generates appropriate arguments.
Tool-Augmented Generation
where is the tool output and is the space of possible tool results.
Planning Algorithms
Task Decomposition
Complex tasks are decomposed into subtasks:
A*-Style Planning for Agents
where:
- = cost of path from start to node
- = heuristic estimate of cost from to goal
Memory Systems
Code Example: Simple ReAct Agent
from typing import List, Dict, Callable
import json
class ReActAgent:
"""Simple ReAct agent with tool use."""
def __init__(self, llm: Callable, tools: Dict[str, Callable],
max_steps: int = 10):
self.llm = llm
self.tools = tools
self.max_steps = max_steps
self.memory = []
def think(self, observation: str) -> str:
"""Generate thought from observation."""
prompt = f"""Based on the following observation, what should I do next?
Observation: {observation}
Thought:"""
return self.llm(prompt)
def act(self, thought: str) -> tuple:
"""Decide action based on thought."""
prompt = f"""Given this thought, choose a tool and arguments.
Thought: {thought}
Available tools: {list(self.tools.keys())}
Action (JSON):"""
response = self.llm(prompt)
action = json.loads(response)
return action['tool'], action.get('args', {})
def observe(self, tool: str, args: dict) -> str:
"""Execute tool and get observation."""
if tool in self.tools:
result = self.tools[tool](**args)
return str(result)
return f"Error: Unknown tool '{tool}'"
def run(self, goal: str) -> str:
"""Execute the ReAct loop."""
observation = f"Goal: {goal}"
for step in range(self.max_steps):
# Think
thought = self.think(observation)
print(f"Step {step+1} - Thought: {thought}")
# Act
tool, args = self.act(thought)
print(f"Step {step+1} - Action: {tool}({args})")
# Observe
observation = self.observe(tool, args)
print(f"Step {step+1} - Observation: {observation[:100]}...")
self.memory.append({
'thought': thought,
'action': {'tool': tool, 'args': args},
'observation': observation
})
# Check if goal achieved
if "COMPLETE" in observation.upper():
return observation
return "Max steps reached"
# Example tools
def web_search(query: str) -> str:
return f"Search results for: {query}"
def calculate(expression: str) -> str:
return str(eval(expression))
tools = {"web_search": web_search, "calculate": calculate}
agent = ReActAgent(llm=lambda x: "search", tools=tools)
Multi-Agent Coordination
Coordination Protocols
Message Passing: Agent sends message to agent :
Consensus: Agents converge on shared decision:
Summary
- ReAct framework interleaves reasoning traces with actions for interpretable agents
- Tool use extends LLM capabilities beyond language to code execution and API calls
- Planning decomposes complex goals into manageable subtasks
- Memory systems (working, episodic, semantic) enable persistent agent knowledge
- Multi-agent coordination enables division of labor for complex tasks