Skip to content

Multi-Agent Chat

We demonstrate four different ways of implementing a multi-agent chat system using APPL. The four implementations are:

  1. Resume (Recommended): Uses the resume feature of the APPL function to store the state of the conversation. The context is stored in the instance of the class with a private variable.
  2. History: Uses a variable to store the history of the conversation. The history is stored in the beginning and updated at the end of each turn.
  3. Generator: Utilizes Python's yield and generator capabilities, enabling functions to produce outputs in stages, temporarily hand over control, and later resume where they left off by calling the send method, which also allows for new inputs to be passed to the yield statement.
  4. Same Context: Creates a context in the init function and uses the same context throughout the conversation.

Implementations

1. Resume

from typing import Optional

import appl
from appl import AIRole, PromptContext, SystemMessage, gen, ppl, records

appl.init()


class Agent(object):
    def __init__(self, name: Optional[str] = None):
        self._name = name
        self._setup()

    @ppl
    def _setup(self):
        if self._name:
            SystemMessage(f"Your name is {self._name}.")
        self.chat(None)  # setup the context

    @ppl(ctx="resume")  # The context is resumed from the last call to chat
    def chat(self, msg: Optional[str]):
        if msg is None:  # first call to setup the context
            return
        msg  # add to the prompt
        with AIRole():
            (reply := gen(max_tokens=50))  # generate reply and add to the prompt
        return reply


alice = Agent("Alice")
bob = Agent("Bob")
msg = "Hello"
for i in range(2):
    msg = str(alice.chat(msg))
    print("Alice:", msg)
    msg = str(bob.chat(msg))
    print("Bob:", msg)

2. History

from typing import Optional

import appl
from appl import AIRole, PromptContext, SystemMessage, gen, ppl, records

appl.init()


class Agent(object):
    def __init__(self, name: Optional[str] = None):
        self._name = name
        self._history = self._setup()  # initialize history

    @ppl
    def _setup(self):
        if self._name:
            SystemMessage(f"Your name is {self._name}.")
        return records()

    @ppl
    def chat(self, msg):
        self._history  # retrieve history
        msg  # add to the prompt
        with AIRole():
            (reply := gen(max_tokens=50))  # generate reply and add to the prompt
        self._history = records()  # update history
        return reply


alice = Agent("Alice")
bob = Agent("Bob")
msg = "Hello!"
for i in range(2):
    msg = str(alice.chat(msg))
    print("Alice:", msg)
    msg = str(bob.chat(msg))
    print("Bob:", msg)

3. Generator

from typing import Optional

import appl
from appl import AIRole, PromptContext, SystemMessage, gen, ppl, records

appl.init()


class Agent(object):
    def __init__(self, name: Optional[str] = None):
        self._name = name
        self.chat = self._chat_generator().send

    @ppl
    def _setup(self):
        if self._name:
            SystemMessage(f"Your name is {self._name}.")
        return records()

    @ppl(auto_prime=True)  # auto prime the generator
    def _chat_generator(self):
        self._setup()
        reply = None
        while True:
            yield reply  # yield and receive messages
            with AIRole():
                (reply := gen(max_tokens=50))


alice = Agent("Alice")
bob = Agent("Bob")
msg = "Hello!"
for i in range(2):
    msg = str(alice.chat(msg))
    print("Alice:", msg)
    msg = str(bob.chat(msg))
    print("Bob:", msg)

4. Same Context

from abc import ABC, abstractmethod
from typing import Optional

import appl
from appl import AIRole, PromptContext, SystemMessage, gen, ppl, records
from appl.func import wraps

appl.init()


class AgentBase(ABC):
    def __init__(self):
        self._ctx = PromptContext()  # the context for the agent
        self._setup(_ctx=self._ctx)  # manually provide the shared context

    @abstractmethod
    @ppl(ctx="same")
    def _setup(self):
        raise NotImplementedError

    @abstractmethod
    @ppl(ctx="same")
    def _chat(self, msg: str):
        raise NotImplementedError

    @wraps(_chat)
    def chat(self, *args, **kwargs):
        # manually provide the shared context self._ctx stored in the instance
        return self._chat(*args, _ctx=self._ctx, **kwargs)

    setattr(chat, "__isabstractmethod__", False)
    # set to False since _chat is abstractmethod


class Agent(AgentBase):
    def __init__(self, name: Optional[str] = None):
        self._name = name
        super().__init__()

    @ppl(ctx="same")
    def _setup(self):
        # modify the shared context
        if self._name:
            SystemMessage(f"Your name is {self._name}.")

    @ppl(ctx="same")
    def _chat(self, msg: str):
        msg
        with AIRole():
            (reply := gen(max_tokens=50))
        return reply


alice = Agent("Alice")
bob = Agent("Bob")
msg = "Hello!"
for i in range(2):
    msg = str(alice.chat(msg))
    print("Alice:", msg)
    msg = str(bob.chat(msg))
    print("Bob:", msg)

Example Conversation

The example conversation between agents:

Role Message
Alice Hello! How can I assist you today?
Bob Hi there! I'm just here to chat and answer any questions you might have. How's your day going?
Alice Thank you for asking! My day is going well. How about you?
Bob I'm just a virtual assistant, so I don't have feelings, but I'm here to help you with anything you need. Is there anything specific you'd like to talk about or ask me?

The conversation seen by Alice:

Role Message
System Your name is Alice.
User Hello!
Assistant Hello! How can I assist you today?
User Hi there! I'm just here to chat and answer any questions you might have. How's your day going?
Assistant Thank you for asking! My day is going well. How about you?

The conversation seen by Bob:

Role Message
System Your name is Bob.
User Hello! How can I assist you today?
Assistant Hi there! I'm just here to chat and answer any questions you might have. How's your day going?
User Thank you for asking! My day is going well. How about you?
Assistant I'm just a virtual assistant, so I don't have feelings, but I'm here to help you with anything you need. Is there anything specific you'd like to talk about or ask me?