josh-ashkinaze / plurals

Plurals: A System for Guiding LLMs Via Simulated Social Ensembles
https://josh-ashkinaze.github.io/plurals/
12 stars 2 forks source link

Implement a strategy pattern for Agent initialization #47

Closed josh-ashkinaze closed 3 weeks ago

josh-ashkinaze commented 2 months ago

What is the problem? Setting the system instructions for Agent involves a lot of logic (e.g: ANES, personas, templates) that should be factored out out from the main class. Agent should ideally be limited to only the logic for processing tasks. Also, this refactor will make things more future-proof when adding other initialization methods.

What is the high-level solution? Implement a Strategy pattern.

Here is a good link on this design pattern (https://refactoring.guru/design-patterns/strategy)

Low-level details

How this looks in Agent

class Agent:
    def __init__(self,
                 task: Optional[str] = None,
                 combination_instructions: Optional[str] = None,
                 ideology: Optional[str] = None,
                 query_str: Optional[str] = None,
                 model: str = "gpt-4o",
                 system_instructions: Optional[str] = None,
                 persona_template: Optional[str] = None,
                 persona: Optional[str] = None,
                 kwargs: Optional[Dict[str, Any]] = None):
        # ... blah blah blah

        # get strategy
        self.system_instruction_strategy = self._get_system_instruction_strategy()

        # use strategy
        self._set_system_instructions()

    def _get_system_instruction_strategy(self):
        if self.system_instructions is not None:
            return DirectSystemInstructionStrategy()
        elif not self.system_instructions and not self.persona and not self.ideology and not self.query_str:
            return DefaultSystemInstructionStrategy()
        else:
            return PersonaBasedSystemInstructionStrategy()

    def _set_system_instructions(self):
        self.system_instruction_strategy.set_system_instructions(self)

How the strategy class is set up

from abc import ABC, abstractmethod

class SystemInstructionStrategy(ABC):
    @abstractmethod
    def set_system_instructions(self, agent):
        pass
        # write over w/ concrete strategies 

class DefaultSystemInstructionStrategy(SystemInstructionStrategy):
    def set_system_instructions(self, agent):
        # implement

class DirectSystemInstructionStrategy(SystemInstructionStrategy):
    def set_system_instructions(self, agent):
        # implement

class PersonaBasedSystemInstructionStrategy(SystemInstructionStrategy):
    def set_system_instructions(self, agent):
       # this will implement all the persona logic

The most involved will definitely be PersonaBasedSystemInstructionStrategy.

One judgment call is whether PersonaBasedSystemInstructionStrategy(SystemInstructionStrategy) should have child classes of its own, since I am just imagining ANES is one dataset but when we add another dataset later on.

Test implications

We have a bunch of Aget initialization tests and these can stay, but we also want tests where we test whether Agent chose the correct strategy based on initialization.

Summing up

cogitoergo-sum commented 3 weeks ago

Completed Agent refractoring