geekan / MetaGPT

🌟 The Multi-Agent Framework: First AI Software Company, Towards Natural Language Programming
https://deepwisdom.ai/
MIT License
43.99k stars 5.23k forks source link

Possible bug with the Role Memory #1304

Open nkrj01 opened 4 months ago

nkrj01 commented 4 months ago

Bug description When I put two agents (AgentA and AgentB) in an environment, AgentB is automatically picks up the published message of AgentA even though _watch function is not set to AgentAAction.

AgentAAction: take a string and publish one letter at a time AgentBAction: given any string simple add the word "Add"

There is no LLM functionality here.

Code is shown below:

Defining AgentA

from metagpt.actions import Action, UserRequirement from metagpt.roles import Role from metagpt.logs import logger from metagpt.schema import Message

class AgentAAction(Action): name: str = "AgentAAction"

async def run(self, task: str):
    sub_task = [letter for letter in task]
    return sub_task

class AgentA(Role): name: str = "AgentA" profile: str = "AgentA"

def __init__(self, **kwargs):
    super().__init__(**kwargs)
    self.set_actions([AgentAAction])
    self._watch({UserRequirement})

async def _act(self) -> None:
    logger.info(f"{self._setting}: to do {self.rc.todo}({self.rc.todo.name}) {type(self.rc)}")
    todo = self.rc.todo  # todo will be SimpleWriteCode()

    task = self.get_memories(k=1)[0]  # find the most recent messages
    sub_tasks = await todo.run(task.content)

    for i in sub_tasks:
       msg = Message(content=i, role=self.profile, cause_by=type(todo))
       self.rc.env.publish_message(msg)

Defining AgentB

class AgentBAction(Action): name: str = "AgentBAction"

async def run(self, sub_task: str):
    final_output = sub_task + "Add"
    return final_output

class AgentB(Role): name: str = "AgentB" profile: str = "AgentB"

def __init__(self, **kwargs):
    super().__init__(**kwargs)
    self.set_actions([AgentBAction])
    self._watch({UserRequirement}) ## Note!! Not watching AgentAAction

async def _act(self) -> Message:
    logger.info(f"{self._setting}: to do {self.rc.todo}({self.rc.todo.name}) {type(self.rc)}")
    todo = self.rc.todo  # todo will be AgentBAction

    sub_tasks = self.rc.history  # find all the messages
    print(sub_tasks)

    for i in sub_tasks:
        final_output = await todo.run(i.content)
        final_output = Message(content=final_output, role=self.profile, cause_by=type(todo))
        self.rc.env.publish_message(final_output)
        self.rc.memory.add(final_output)

from metagpt.context import Context import asyncio from metagpt.environment import Environment

agentA = AgentA() agentB = AgentB() context = Context() # Load config2.yaml env = Environment(context=context) env.add_roles([agentA, agentB]) env.publish_message(Message(content='APPLE', send_to=AgentA)) env.publish_message(Message(content='CAT', send_to=AgentB)) # Send the user's message to Agent A to start the process. await env.run()

print all the messages in the memory of agentB

for index, memory in enumerate(agentB.get_memories(k=0)): print(f'{index}: {memory}')

Output: 0: user: CAT 1: AgentA: A 2: AgentA: P 3: AgentA: P 4: AgentA: L 5: AgentA: E 6: AgentB: CATAdd 7: AgentB: AAdd 8: AgentB: PAdd 9: AgentB: PAdd 10: AgentB: LAdd 11: AgentB: EAdd

Ideally the output should just be: 0: user: CAT 1: user: CATadd

Bug solved method

Environment information

Windows 12

Screenshots or logs

garylin2099 commented 4 months ago

looks like message is still observed even if cause_by is set to type(todo). Can @iorisa check this?

Kaushal-26 commented 4 months ago

I think in current implementation of publish_message does not take care of role watch actions.

As in metagpt/environment/base_env.py#L187

for role, addrs in self.member_addrs.items():
    if is_send_to(message, addrs):
        role.put_message(message)
        found = True

It should be

for role, addrs in self.member_addrs.items():
    if is_send_to(message, addrs) and role.is_watch(message.cause_by):
        role.put_message(message)
        found = True

Create this pull request: https://github.com/geekan/MetaGPT/pull/1314

PS: I am a bit new, I don't know if it will break other examples or not.