Perception and Action › Bringing It Together: A Complete Example

Michael BrenndoerferJuly 15, 20252 min read
AI Agent HandbookAll chapters
Part 8 of 15Environment and Interaction - The Agent's World
Chapter 22Perception and Action › Bringing It Together: A Complete Example
Reading section 7 of 10 · Bringing It Together: A Complete Example · 2 minSection 7 of 10 · 2 min

Book contents

Section 7 of 10 · 2 min read

Perception and Action › Bringing It Together: A Complete ExampleOne section · Sections in this chapter7 / 10 ↓

Let's build a complete example that shows perception and action working together in our personal assistant:

In[8]:
Code
## Using Claude Sonnet 4.5 for comprehensive agent capabilities
import os
from anthropic import Anthropic
import json

class PersonalAssistant:
    def __init__(self):
        self.client = Anthropic(api_key=os.getenv("ANTHROPIC_API_KEY"))
        self.conversation_history = []
        self.tools = {
            "calculator": self.calculator_tool,
            "memory": self.memory_tool
        }
        self.memory_store = {}
    
    def calculator_tool(self, expression):
        """Simple calculator tool"""
        try:
            return {"result": eval(expression)}
        except:
            return {"error": "Invalid expression"}
    
    def memory_tool(self, action, key=None, value=None):
        """Memory storage tool"""
        if action == "save":
            self.memory_store[key] = value
            return {"status": "saved"}
        elif action == "retrieve":
            return {"value": self.memory_store.get(key, "Not found")}
    
    def perceive_and_act(self, user_message):
        """Complete perception-action cycle"""
        
        # Perception 1: User input
        print(f"\n[PERCEPTION] User says: {user_message}")
        self.conversation_history.append({
            "role": "user",
            "content": user_message
        })
        
        # Perception 2: Check relevant memory
        # (In a real system, this would be more sophisticated)
        print(f"[PERCEPTION] Current memory: {self.memory_store}")
        
        # Decision & Action: Use LLM to decide what to do
        response = self.client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=1024,
            messages=self.conversation_history
        )
        
        agent_message = response.content[0].text
        
        # Action: Generate response
        print(f"[ACTION] Agent responds: {agent_message}")
        self.conversation_history.append({
            "role": "assistant",
            "content": agent_message
        })
        
        return agent_message

## Example usage
assistant = PersonalAssistant()

## Cycle 1
assistant.perceive_and_act("Hi! My name is Alex.")

## Cycle 2
assistant.perceive_and_act("What's 15 times 23?")

## Cycle 3
assistant.perceive_and_act("What's my name?")
Out[8]:
Console

[PERCEPTION] User says: Hi! My name is Alex.
[PERCEPTION] Current memory: {}
[ACTION] Agent responds: Hello Alex! It's nice to meet you. How can I help you today?

[PERCEPTION] User says: What's 15 times 23?
[PERCEPTION] Current memory: {}
[ACTION] Agent responds: 15 times 23 is 345.

[PERCEPTION] User says: What's my name?
[PERCEPTION] Current memory: {}
[ACTION] Agent responds: Your name is Alex. You mentioned that at the beginning of our conversation.
'Your name is Alex. You mentioned that at the beginning of our conversation.'

This example demonstrates:

  1. Multiple perceptions: The agent perceives user input and checks its memory
  2. State maintenance: Conversation history persists across cycles
  3. Action variety: The agent can respond, call tools, or update memory
  4. Continuity: Each cycle builds on previous ones