microsoft / autogen

A programming framework for agentic AI 🤖
https://microsoft.github.io/autogen/
Creative Commons Attribution 4.0 International
31.59k stars 4.59k forks source link

[Issue]: ConversableAgent parameter ---chat_messages #2928

Open somewhere1 opened 3 months ago

somewhere1 commented 3 months ago

Describe the issue

"chat_messages (dict or None): the previous chat messages that this agent had in the past with other agents. Can be used to give the agent a memory by providing the chat history. This will allow the agent to resume previous had conversations. Defaults to an empty chat history."I'm having trouble understanding the meaning of this parameter. Since it doesn't exist before we initialize the object, how can there be a chat history? This has confused me for a long time. I haven't found a correct example of how to use this parameter, and I'm hoping to find the right way to use it

Steps to reproduce

No response

Screenshots and logs

KeyError: <autogen.agentchat.conversable_agent.ConversableAgent object at 0x0000027035619CD0>

Additional Information

No response

yuanzheng319 commented 3 months ago

I also struggled to use a short chat history to initialize a ConversableAgent object, as in OpenAI's chat_completion API example, we initialize like:

from openai import OpenAI
client = OpenAI()

response = client.chat.completions.create(
  model="gpt-3.5-turbo",
  messages=[
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": "Who won the world series in 2020?"},
    {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
    {"role": "user", "content": "Where was it played?"}
  ]
)

Now the question is how to inject those short conversation history as a memory into ConversableAgent.chat_messages? Here is a hacky way to do it (although we should have official support for this type of initialization beyond just a plain string):

from typing import List, Dict

# Mocking the Agent class for this example
class Agent:
    def __init__(self, name: str):
        self.name = name

# Sample User Agent
agent_user = Agent("Agent A")

# Example message history without the last user query
chat_messages = {
    agent_user: [
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Who won the world series in 2020?"},
        {"role": "assistant", "content": "The Los Angeles Dodgers won the World Series in 2020."},
    ]
}

# Initializing ConversableAgent with chat_messages and LLM configuration
conversable_agent = ConversableAgent(
    name="AssistantAgent",
    system_message="You are a helpful assistant.",
    chat_messages=chat_messages,  # Preloaded chat history
    llm_config={"model": "gpt-3.5-turbo"}  
)

# New user query
new_message = {"role": "user", "content": "Where was it played?"}

# Generate a reply using the current conversation history plus the new message
updated_history = chat_messages[agent_user] + [new_message]

reply = conversable_agent.generate_reply(messages=updated_history)

print(reply)
skzhang1 commented 3 months ago

hi @WaelKarkoub Do you have any ideas here?

WaelKarkoub commented 3 months ago

chat_messages is optional and is mainly used to resume old chats or update the context history of the agent with older context. For example, let's say you have stored these agents' chats in a database, what you can do now is reconstruct the chat messages (key=agent, value=list of messages) and feed it to the agent. So even when you restart the process, we can still keep the same context (or message history as some call it) from an older session. This feature is part of the persistence roadmap https://github.com/microsoft/autogen/issues/2358.

Hopefully I understood you correctly, I'm failing to see where the issue is though. Are you trying to report a bug?

skzhang1 commented 3 months ago

Thanks @WaelKarkoub! I think I have the same question. "chat_messages is used to initialize a convesable_agent" and documentation said "This will allow the agent to resume previous had conversations.".

However, the conflict is if this is the first time to initialize the agent, how we get its previous chat history? Even we use the same agent class but they are essentially different objects in python (the agents used to generate the history and the agent which is initialized using the chat_messages.).

I am not sure whether I clarify it clear.

WaelKarkoub commented 3 months ago

The chat history is empty when you initialize an agent, so you can't really get it. What you can do is store the previous chat history from the "previously" initialized agent in a database and reconstruct it later when you want to use it again. Once you reconstruct it you can pass it to the newly initialized agent. Hope that helped @skzhang1 !

skzhang1 commented 3 months ago

@WaelKarkoub Thanks! After getting into the code details. I think I got it point. @somewhere1 The critical point is the chat_messages is from the sender but not the agent going to be initialized. So the chat history is possible to exist. Hope this help!

yuanzheng319 commented 3 months ago

Thanks for explaining. @WaelKarkoub I think it would be great to support including a short chat history when initializing an agent as part of the agent's identity/personality, like the idea of 'few-shot prompting'. Often times it is not easy to define a certain behavior/identity with only a string without giving examples. For example, If we can inject those 3 examples into an agent's identity,

{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already."}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "Who wrote 'Romeo and Juliet'?"}, {"role": "assistant", "content": "Oh, just some guy named William Shakespeare. Ever heard of him?"}]}
{"messages": [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "How far is the Moon from Earth?"}, {"role": "assistant", "content": "Around 384,400 kilometers. Give or take a few, like that really matters."}]}

It would behave more consistently than only specifying system_message="a factual chatbot that is also sarcastic."

WaelKarkoub commented 3 months ago

@yuanzheng319 who is sending those user messages? isn't it another agent as well (e.g. user proxy agent)? You can do what you just showed me using chat_messages. so the chat messages dictionary's key is the agent, which in your case might be the user proxy agent, and the value for the key is the list of messages:

{user_proxy_agent: [{"role": "system", "content": "Marv is a factual chatbot that is also sarcastic."}, {"role": "user", "content": "What's the capital of France?"}, {"role": "assistant", "content": "Paris, as if everyone doesn't know that already."}]}

you can feed this dictionary to the agent's constructor. Just be careful with system messages. From looking at the code, it assumes there's only one system message and it's the beginning of the message list.