Skip to content

Latest commit

 

History

History
511 lines (318 loc) · 13.5 KB

AgentMethods.md

File metadata and controls

511 lines (318 loc) · 13.5 KB

Agent Methods Guide

Welcome to the Agent Methods guide! This section provides an in-depth look at the key methods within the Agent base class of AgentForge. Understanding these methods is crucial for creating custom agents by subclassing the Agent class, allowing you to extend and customize agent behaviors effectively.


Introduction

The Agent base class provides a robust template for building agents in AgentForge. By subclassing Agent, you inherit default functionalities and can override methods to tailor agent behaviors to your specific needs.

Why Override Methods?

  • Customization: Adapt agent behaviors to perform specific tasks.
  • Specialization: Implement unique processing logic or data handling.
  • Extensibility: Add new functionalities without altering the base class.

Method Categories

For better understanding, we've grouped the methods into the following categories:

  1. Core Workflow Method
  2. Data Loading Methods
  3. Data Processing Method
  4. Prompt Generation Method
  5. LLM Interaction Method
  6. Result Handling Methods
  7. Storage Methods
  8. Customization Hooks

1. Core Workflow Method

run(self, **kwargs)

Purpose: The central method that orchestrates the agent's workflow, executing a sequence of steps to generate the final output.

Workflow Steps:

  1. Load Data: self.load_data(**kwargs)
  2. Process Data: self.process_data()
  3. Generate Prompt: self.generate_prompt()
  4. Run LLM: self.run_llm()
  5. Parse Result: self.parse_result()
  6. Save to Storage: self.save_to_storage()
  7. Build Output: self.build_output()
  8. Cleanup: Clears self.data to free up memory.

Usage:

  • Call run() with any necessary keyword arguments.
  • The method handles error logging and returns the final output or None if an error occurs.

Example:

from agentforge.agent import Agent

class CustomAgent(Agent):
    pass

agent = CustomAgent()
output = agent.run(user_input="Hello, AgentForge!")
print(output)

2. Data Loading Methods

These methods handle loading various types of data into the agent.

load_data(self, **kwargs)

Purpose: Centralizes the data loading process, orchestrating the loading of agent configurations, persona data, storage initialization, and any additional data.

What It Does:

  • Loads Agent Configuration Data: self.load_agent_data()
  • Loads Persona Data: self.load_persona_data()
  • Resolves Storage: self.resolve_storage()
  • Loads Data from Storage: self.load_from_storage()
  • Loads Additional Data: self.load_additional_data()
  • Loads Keyword Arguments: self.load_kwargs(**kwargs)

When to Override:

  • Typically, you don't need to override this method. Instead, override the specific data loading methods as needed.

load_agent_data(self)

Purpose: Loads the agent's configuration data, including parameters and prompts, and updates self.data accordingly.

What It Does:

  • Retrieves agent data using the Config class.
  • Updates self.data with parameters (params) and prompt templates (prompts).

Usage:

  • Automatically called by load_data().

load_persona_data(self)

Purpose: Loads persona-specific data, enriching the agent's context.

What It Does:

  • Checks if personas are enabled in the system settings.
  • If enabled, loads persona data and updates self.data with persona attributes.

Usage:

  • Automatically called by load_data().

resolve_storage(self)

Purpose: Initializes the storage system for the agent if storage is enabled in the system settings.

What It Does:

  • Checks if storage is enabled.
  • If enabled, initializes the storage instance and stores it in self.agent_data['storage'].

Usage:

  • Automatically called by load_data().

load_from_storage(self)

Purpose: Placeholder for loading data from storage systems.

Usage:

  • Override this method if your agent needs to load data from a database or file system.

Example Override:

def load_from_storage(self):
    collection_name = 'Memories'  # Name of the collection in the vector database
    query = 'User is thinking about planning a trip'  # A text query to search the specified collection
    self.data['stored_values'] = self.agent_data['storage'].query_memory(collection_name, query)

load_additional_data(self)

Purpose: Placeholder for loading any additional data required by the agent.

Usage:

  • Override this method to load custom data necessary for your agent's operation.

Example Override:

def load_additional_data(self):
    self.data['timestamp'] = datetime.now().isoformat()

load_kwargs(self, **kwargs)

Purpose: Loads variables passed as keyword arguments into self.data.

What It Does:

  • Iterates over **kwargs and updates self.data with the provided key-value pairs.

Usage:

  • Automatically called by load_data().

Example:

def load_kwargs(self, **kwargs):
    self.data.update(kwargs)

3. Data Processing Method

process_data(self)

Purpose: Processes the loaded data before it's used in prompt generation.

Default Behavior: Does nothing by default.

Usage:

  • Override this method to implement custom data processing logic.

Example Override:

def process_data(self):
    # Convert user input to uppercase
    self.data['user_input'] = self.data['user_input'].upper()

4. Prompt Generation Method

generate_prompt(self)

Purpose: Renders the prompt templates using the variables loaded in self.data.

What It Does:

  • Retrieves prompt templates from self.data['prompts'].
  • Uses PromptHandling to:
    • Check the format of the prompts.
    • Render the prompts with current data.
    • Validate the rendered prompts.
  • Stores the rendered prompts in self.prompt.

Usage:

  • Automatically called by run().

When to Override:

  • Typically, you don't need to override this method. Only override it if you need custom prompt rendering logic.

5. LLM Interaction Method

run_llm(self)

Purpose: Executes the language model using the generated prompts.

What It Does:

  • Retrieves the LLM instance from self.agent_data['llm'].
  • Retrieves parameters from self.agent_data.get('params', {}).
  • Adds agent_name to the parameters.
  • Calls generate_text on the LLM with the prompts and parameters.
  • Stores the result in self.result.

Usage:

  • Automatically called by run().

When to Override:

  • Typically, you don't need to override this method. Only override it if you need simulate an LLM response.

Example Override:

def run_llm(self):
    # Custom LLM execution
    self.result = "Simulated LLM output"

6. Result Handling Methods

parse_result(self)

Purpose: Parses the raw result from the LLM.

Default Behavior: Does nothing by default.

Usage:

  • Override this method to implement custom parsing logic.

Example Override:

def parse_result(self):
    self.result = json.loads(self.result)

build_output(self)

Purpose: Constructs the final output from the processed data.

Default Behavior:

  • Sets self.output = self.result

Usage:

  • Automatically called by run().

When to Override:

  • To customize the final output format.

Example Override:

def build_output(self):
    self.output = f"Processed Output: {self.result}"

7. Storage Methods

save_to_storage(self)

Purpose: Placeholder for saving data to storage.

Default Behavior: Does nothing by default.

Usage:

  • Override this method if your agent needs to save data persistently.

Notes:

  • The storage instance is available at self.agent_data['storage'].
  • Ensure that storage is enabled in the system settings (StorageEnabled: true).

Example Override:

def save_to_storage(self):
    data = self.result
    metadata = {'timestamp': datetime.now().isoformat()}
    self.agent_data['storage'].save_memory(collection_name='Results', data=data, metadata=metadata)

8. Customization Hooks

These methods are designed to be overridden to customize agent behavior:

  • load_from_storage()
  • load_additional_data()
  • process_data()
  • parse_result()
  • save_to_storage()
  • build_output()

By overriding these methods, you can inject custom logic at various points in the agent's workflow.


Putting It All Together: Custom Agent Example

Let's create a custom agent that performs sentiment analysis on user input using an LLM. This example shows how to override methods to customize agent behavior.

Step 1: Define the Custom Agent

# sentiment_agent.py
from agentforge.agent import Agent

class SentimentAgent(Agent):
    def process_data(self):
        # Clean the user input by stripping leading/trailing whitespace
        self.data['cleaned_input'] = self.data['user_input'].strip()
    
    def parse_result(self):
        # Simplify the LLM's response to extract the sentiment
        response = self.result.lower()
        if 'positive' in response:
            sentiment = 'Positive'
        elif 'negative' in response:
            sentiment = 'Negative'
        elif 'neutral' in response:
            sentiment = 'Neutral'
        else:
            sentiment = 'Undetermined'
        self.result = sentiment
    
    def build_output(self):
        # Build the final output message
        self.output = f"Sentiment Analysis Result: {self.result}"

Step 2: Create the Prompt Template (SentimentAgent.yaml)

Place this YAML file in the .agentforge/prompts/ directory.

Prompts:
  System: You are a sentiment analysis assistant.
  User: |+
    Determine if the sentiment of the following text is Positive, Negative, or Neutral.

    Text: "{cleaned_input}"

Step 3: Run the Agent

# run_sentiment_agent.py
from sentiment_agent import SentimentAgent

# Initialize the agent
agent = SentimentAgent()

# User input
user_input = "  I absolutely love using AgentForge!  "

# Run the agent with the user input
response = agent.run(user_input=user_input)

# Print the output
print(response)

Expected Output

Sentiment Analysis Result: Positive

Explanation

Overridden Methods:

  1. process_data(self)

    • Purpose: Cleans the user input before it's used in the prompt.
    • What It Does: Strips any leading or trailing whitespace from self.data['user_input'] and stores it in self.data['cleaned_input'].
  2. parse_result(self)

    • Purpose: Parses the LLM's response to extract the sentiment.
    • What It Does: Checks the LLM's response for keywords 'positive', 'negative', or 'neutral' and assigns the corresponding sentiment to self.result.
  3. build_output(self)

    • Purpose: Constructs the final output to present to the user.
    • What It Does: Formats the output message using the parsed sentiment.

Key Points:

  • Custom Data Processing: By cleaning the user input in process_data, we ensure the prompt receives properly formatted text.
  • Prompt Template: Uses {cleaned_input} to insert the processed input into the prompt.
  • Output Construction: Presents a clear and concise result to the user.

Tips and Best Practices

  • Start Simple: Begin by subclassing Agent without overriding any methods. Ensure your basic agent works before adding complexity.
  • Override as Needed: Only override methods that require custom logic for your agent's purpose.
  • Test Each Step: After overriding a method, test your agent to ensure it behaves as expected.
  • Use Descriptive Names: Name your agents and variables clearly to enhance readability.
  • Leverage Inheritance: Remember that your custom agent inherits all methods from Agent. You can call super() to utilize base class functionality.

Additional Functions and Utilities

The Agent class utilizes additional utilities that assist with tasks such as:

  • Prompt Handling: Managed by self.prompt_handling.
  • Logging: Managed by self.logger.
  • Configuration Management: Managed by self.config.
  • Data Storage: Available via self.agent_data['storage'] if storage is enabled.

For more details, refer to the respective documentation:


Conclusion

By understanding and utilizing these methods, you can create powerful custom agents tailored to your specific needs. The Agent base class provides a flexible foundation, and by selectively overriding methods, you can extend and customize agent behaviors efficiently.


Next Steps

  • Explore More: Check out the Custom Agents Guide for further insights into creating specialized agents.
  • Dive into Utilities: Learn about the utility classes and functions in the Utilities Overview.
  • Understand Prompts: Review the Agent Prompts Guide to master crafting effective prompts.

Need Help?

If you have questions or need assistance, feel free to reach out: