Så du har lekt med stora språkmodeller och börjar integrera Generativ AI i dina appar? Det är häftigt! Men låt oss vara verkliga. LLMs beter sig inte alltid som vi vill att de ska. De är som onda småbarn med sina egna sinnen!
Du inser snart att enkla snabbkedjor inte räcker. Ibland behöver vi något mer. Ibland behöver vi arbetsflöden för flera agenter! Det är där AutoGen kommer in.
Låt oss ta ett exempel. Föreställ dig att du gör en anteckningsapp (Det är klart att världen inte har tillräckligt med dem. 😝). Men hallå, vi vill göra något speciellt. Vi vill ta den enkla, råa noteringen som en användare ger oss och förvandla den till ett helt omstrukturerat dokument, komplett med en sammanfattning, en valfri titel och en automatiserad att-göra-lista med uppgifter. Och vi vill göra allt detta utan att svettas - ja, åtminstone för dina AI-agenter.
Okej, nu vet jag vad du tänker - "Är det inte som nybörjarprogram?" Till det säger jag att du har rätt. Menar... men rätt! Men låt dig inte luras av enkelheten i arbetsflödet. De färdigheter du kommer att lära dig här - som att hantera AI-agenter, implementera arbetsflödeskontroll och hantera konversationshistorik - hjälper dig att ta ditt AI-spel till nästa nivå.
Så spänn fast dig, för vi ska lära oss hur man gör AI-arbetsflöden med AutoGen!
Innan vi börjar, notera att du kan hitta en länk till all källkod på GitHub .
Låt oss börja med det första användningsfallet - "Generera en sammanfattning för anteckningen följt av en villkorlig titel". För att vara rättvis behöver vi egentligen inte använda agenter här. Men hallå, vi måste väl börja någonstans?
Agentiska ramverk som AutoGen kräver alltid att vi konfigurerar modellparametrarna. Vi pratar om modellen och reservmodellen som ska användas, temperaturen och till och med inställningar som timeout och cachelagring. När det gäller AutoGen ser den inställningen ut ungefär så här:
# build the gpt_configuration object base_llm_config = { "config_list": [ { "model": "Llama-3-8B-Instruct", "api_key": os.getenv("OPENAI_API_KEY"), "base_url": os.getenv("OPENAI_API_URL"), } ], "temperature": 0.0, "cache_seed": None, "timeout": 600, }
Som du kan se är jag en stor AI-fantast med öppen källkod och svär vid Llama 3. Du kan få AutoGen att peka på vilken OpenAI-kompatibel slutledningsserver som helst genom att helt enkelt konfigurera api_key
och base_url
värdena. Så, använd gärna Groq, Together.ai eller till och med vLLM för att vara värd för din modell lokalt. Jag använder Inferix .
Det är verkligen så enkelt!
Jag är nyfiken! Skulle du vara intresserad av en liknande guide för AI-värd med öppen källkod? Låt mig veta i kommentarerna.
Att initiera samtalsagenter i AutoGen är ganska enkelt; ange helt enkelt LLM-baskonfigurationen tillsammans med ett systemmeddelande och du är klar.
import autogen def get_note_summarizer(base_llm_config: dict): # A system message to define the role and job of our agent system_message = """You are a helpful AI assistant. The user will provide you a note. Generate a summary describing what the note is about. The summary must follow the provided "RULES". "RULES": - The summary should be not more than 3 short sentences. - Don't use bullet points. - The summary should be short and concise. - Identify and retain any "catchy" or memorable phrases from the original text - Identify and correct all grammatical errors. - Output the summary and nothing else.""" # Create and return our assistant agent return autogen.AssistantAgent( name="Note_Summarizer", # Lets give our agent a nice name llm_config=base_llm_config, # This is where we pass the llm configuration system_message=system_message, ) def get_title_generator(base_llm_config: dict): # A system message to define the role and job of our agent system_message = """You are a helpful AI assistant. The user will provide you a note along with a summary. Generate a title based on the user's input. The title must be witty and easy to read. The title should accurate present what the note is about. The title must strictly be less than 10 words. Make sure you keep the title short. Make sure you print the title and nothing else. """ # Create and return our assistant agent return autogen.AssistantAgent( name="Title_Generator", llm_config=base_llm_config, system_message=system_message, )
Den viktigaste delen av att skapa agenter är system_message
. Ta en stund att titta på system_message
som jag har använt för att konfigurera mina agenter.
Det är viktigt att komma ihåg att hur AI-agenter i AutoGen arbetar är genom att delta i en konversation . Sättet de tolkar och för konversationen vidare helt beror på system_message
de är konfigurerade med. Detta är en av platserna där du kommer att spendera lite tid för att få saker rätt.
Vi behöver bara en agent till. En agent som ska agera ombud för oss människor. En agent som kan initiera konversationen med "anteckningen" som sin första uppmaning.
def get_user(): # A system message to define the role and job of our agent system_message = "A human admin. Supplies the initial prompt and nothing else." # Create and return our user agent return autogen.UserProxyAgent( name="Admin", system_message=system_message, human_input_mode="NEVER", # We don't want interrupts for human-in-loop scenarios code_execution_config=False, # We definitely don't want AI executing code. default_auto_reply=None, )
Det är inget fancy på gång här. Observera bara att jag har satt parametern default_auto_reply
till None
. Det är viktigt. Om du ställer in detta till ingen ser du till att konversationen avslutas när användaragenten skickas ett meddelande.
Hoppsan, jag glömde helt att skapa de agenterna. Låt oss göra det riktigt snabbt.
# Create our agents user = get_user() note_summarizer = get_note_summarizer(base_llm_config) title_generator = get_title_generator(base_llm_config)
GroupChat
Den sista pusselbiten är att få våra agenter att samordna sig. Vi måste bestämma sekvensen för deras deltagande och bestämma vilka agenter som ska.
Okej, det är mer än en bit. Men du förstår poängen! 🙈
En möjlig lösning skulle vara att låta AI räkna ut i vilken sekvens agenterna deltar. Det här är ingen dålig idé. Faktum är att detta är mitt val när jag hanterar komplexa problem där arbetsflödets natur är dynamisk.
Detta tillvägagångssätt har dock sina nackdelar. Verkligheten slår till igen! Agenten som är ansvarig för att fatta dessa beslut behöver ofta en stor modell, vilket resulterar i högre latenser och kostnader. Dessutom finns det en risk att det kan fatta felaktiga beslut.
För deterministiska arbetsflöden, där vi vet sekvensen av steg i förväg, gillar jag att ta tag i tyglarna och styra skeppet själv. Lyckligtvis stöder AutoGen detta användningsfall med en praktisk funktion som heter GroupChat
.
from autogen import GroupChatManager from autogen.agentchat.groupchat import GroupChat from autogen.agentchat.agent import Agent def get_group_chat(agents, generate_title: bool = False): # Define the function which decides the agent selection order def speaker_selection_method(last_speaker: Agent, group_chat: GroupChat): # The admin will always forward the note to the summarizer if last_speaker.name == "Admin": return group_chat.agent_by_name("Note_Summarizer") # Forward the note to the title generator if the user wants a title if last_speaker.name == "Note_Summarizer" and generate_title: return group_chat.agent_by_name("Title_Generator") # Handle the default case - exit return None return GroupChat( agents=agents, messages=[], max_round=3, # There will only be 3 turns in this group chat. The group chat will exit automatically post that. speaker_selection_method=speaker_selection_method, )
Föreställ dig en GroupChat
som en WhatsApp-grupp där alla agenter kan chatta och samarbeta. Denna inställning låter agenter bygga vidare på varandras arbete. GroupChat
klassen tillsammans med en medföljande klass som kallas GroupChatManager
fungerar som gruppadministratörerna och håller reda på alla meddelanden varje agent skickar för att säkerställa att alla håller sig uppdaterade med konversationshistoriken.
I kodavsnittet ovan har vi skapat en GroupChat
med en anpassad speaker_selection_method
. speaker_selection_method
tillåter oss att specificera vårt anpassade arbetsflöde. Här är en visuell representation av detsamma.
Eftersom speaker_selection_method
i huvudsak är en Python-funktion kan vi göra vad vi vill med den! Detta hjälper oss att skapa några riktigt kraftfulla arbetsflöden. Till exempel kan vi:
Föreställ dig möjligheterna! 😜
Det sista steget är att skapa en instans av GroupChat
, lägga den inuti en GroupChatManager
och initiera konversationen.
# Create our group chat groupchat = get_group_chat([user, note_summarizer, title_generator], generate_title=True) manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=base_llm_config) # Start the chat user.initiate_chat( manager, clear_history=True, message=note, )
Obs: Användaren chattar med
GroupChatManager
, inte de enskilda agenterna. Den har ingen aning om vilka agenter som kommer att gå med i konversationen för att ge det slutliga svaret. Sneaky, eller hur?
Utgången kommer att se ut ungefär så här:
Admin (to chat_manager): Note: Convo with editor: - discuss titles and thumbnails - discuss video editing tips tracker - Zeeshan presents the tracker - what trick helps with what - he decidedls if we can experiment with something new - make sure all all videos since how config management works in k8s are backed u - make list of YouTube thumbnail templates - make list of YouTube idea generation limits -------------------------------------------------------------------------------- Next speaker: Note_Summarizer Note_Summarizer (to chat_manager): The note is about a conversation with an editor regarding video production. They discussed titles and thumbnails, as well as a video editing tips tracker presented by Zeeshan, which highlights tricks for specific tasks. Additionally, they ensured that all videos on Kubernetes configuration management are backed up and created lists of YouTube thumbnail templates and idea generation limits. -------------------------------------------------------------------------------- Next speaker: Title_Generator Title_Generator (to chat_manager): "Video Production Chat: Titles, Thumbnails, and Editing Tips" --------------------------------------------------------------------------------
Nästa upp kommer vi att dyka in i det slutliga användningsfallet: ta en given "anteckning", omstrukturera den för bättre tydlighet och sedan skapa en uppgiftslista för användaren.
Så här ska vi gå tillväga:
Vi börjar med att identifiera en lista över ämnen som tas upp i anteckningen. Denna lista är drivkraften bakom hela processen. Den fastställer sektionerna för den omformaterade anteckningen och bestämmer detaljnivån för våra genererade uppgifter.
Det finns bara ett litet problem. Paraphrazer
och Task_Creator
-agenten bryr sig inte riktigt om varandras utdata. De bryr sig bara om resultatet från Topic_Analyzer
.
Så vi behöver ett sätt att hålla dessa agenters svar från att belamra konversationshistoriken, annars blir det totalt kaos. Vi har redan tagit kontroll över arbetsflödet; nu är det dags att bli chef för konversationshistoriken också! 😎
Först och främst måste vi sätta upp våra agenter. Jag ska inte tråka ut dig med detaljerna så här är koden:
def get_topic_analyzer(base_llm_config: dict): # A system message to define the role and job of our agent system_message = """You are a helpful AI assistant. The user will provide you a note. Generate a list of topics discussed in that note. The output must obey the following "RULES": "RULES": - Output should only contain the important topics from the note. - There must be atleast one topic in output. - Don't reuse the same text from user's note. - Don't have more than 10 topics in output.""" # Create and return our assistant agent return autogen.AssistantAgent( name="Topic_Analyzer", llm_config=base_llm_config, system_message=system_message, ) def get_paraphrazer(base_llm_config: dict): # A system message to define the role and job of our agent system_message = """You are a helpful AI content editor. The user will provide you a note along with a summary. Rewrite that note and make sure you cover everything in the note. Do not include the title. The output must obey the following "RULES": "RULES": - Output must be in markdown. - Make sure you use each points provided in summary as headers. - Each header must start with `##`. - Headers are not bullet points. - Each header can optionally have a list of bullet points. Don't put bullet points if the header has no content. - Strictly use "-" to start bullet points. - Optionally make an additional header named "Addional Info" to cover points not included in the summary. Use "Addional Info" header for unclassified points. - Identify and correct spelling & grammatical mistakes.""" # Create and return our assistant agent return autogen.AssistantAgent( name="Paraphrazer", llm_config=base_llm_config, system_message=system_message, ) def get_tasks_creator(base_llm_config: dict): # A system message to define the role and job of our agent system_message = """You are a helpful AI personal assistant. The user will provide you a note along with a summary. Identify each task the user has to do as next steps. Make sure to cover all the action items mentioned in the note. The output must obey the following "RULES": "RULES": - Output must be an YAML object with a field named tasks. - Make sure each task object contains fields title and description. - Extract the title based on the tasks the user has to do as next steps. - Description will be in markdown format. Feel free to include additional formatting and numbered lists. - Strictly use "-" or "dashes" to start bullet points in the description field. - Output empty tasks array if no tasks were found. - Identify and correct spelling & grammatical mistakes. - Identify and fix any errors in the YAML object. - Output should strictly be in YAML with no ``` or any additional text.""" # Create and return our assistant agent return autogen.AssistantAgent( name="Task_Creator", llm_config=base_llm_config, system_message=system_message, )
GroupChat
Tyvärr. AutoGen tillåter oss inte att styra konversationshistoriken direkt. Så vi måste gå vidare och utöka GroupChat
klassen med vår anpassade implementering.
class CustomGroupChat(GroupChat): def __init__(self, agents): super().__init__(agents, messages=[], max_round=4) # This function get's invoked whenever we want to append a message to the conversation history. def append(self, message: Dict, speaker: Agent): # We want to skip messages from the Paraphrazer and the Task_Creator if speaker.name != "Paraphrazer" and speaker.name != "Task_Creator": super().append(message, speaker) # The `speaker_selection_method` now becomes a function we will override from the base class def select_speaker(self, last_speaker: Agent, selector: AssistantAgent): if last_speaker.name == "Admin": return self.agent_by_name("Topic_Analyzer") if last_speaker.name == "Topic_Analyzer": return self.agent_by_name("Paraphrazer") if last_speaker.name == "Paraphrazer": return self.agent_by_name("Task_Creator") # Return the user agent by default return self.agent_by_name("Admin")
Vi åsidosätter två funktioner från basgruppen GroupChat
klassen:
append
- Detta styr vilka meddelanden som läggs till i konversationshistoriken.select_speaker
- Detta är ett annat sätt att specificera speaker_selection_method
.
Men vänta, när jag dykte djupare in i AutoGens kod insåg jag att GroupChatManager
får varje agent att underhålla konversationshistoriken också. Fråga mig inte varför. Jag vet verkligen inte!
Så låt oss utöka GroupChatManager
också för att fixa det:
class CustomGroupChatManager(GroupChatManager): def __init__(self, groupchat, llm_config): super().__init__(groupchat=groupchat, llm_config=llm_config) # Don't forget to register your reply functions self.register_reply(Agent, CustomGroupChatManager.run_chat, config=groupchat, reset_config=GroupChat.reset) def run_chat( self, messages: Optional[List[Dict]] = None, sender: Optional[Agent] = None, config: Optional[GroupChat] = None, ) -> Union[str, Dict, None]: """Run a group chat.""" if messages is None: messages = self._oai_messages[sender] message = messages[-1] speaker = sender groupchat = config for i in range(groupchat.max_round): # set the name to speaker's name if the role is not function if message["role"] != "function": message["name"] = speaker.name groupchat.append(message, speaker) if self._is_termination_msg(message): # The conversation is over break # We do not want each agent to maintain their own conversation history history # broadcast the message to all agents except the speaker # for agent in groupchat.agents: # if agent != speaker: # self.send(message, agent, request_reply=False, silent=True) # Pro Tip: Feel free to "send" messages to the user agent if you want to access the messages outside of autogen for agent in groupchat.agents: if agent.name == "Admin": self.send(message, agent, request_reply=False, silent=True) if i == groupchat.max_round - 1: # the last round break try: # select the next speaker speaker = groupchat.select_speaker(speaker, self) # let the speaker speak # We'll now have to pass their entire conversation of messages on generate_reply # Commented OG code: reply = speaker.generate_reply(sender=self) reply = speaker.generate_reply(sender=self, messages=groupchat.messages) except KeyboardInterrupt: # let the admin agent speak if interrupted if groupchat.admin_name in groupchat.agent_names: # admin agent is one of the participants speaker = groupchat.agent_by_name(groupchat.admin_name) # We'll now have to pass their entire conversation of messages on generate_reply # Commented OG code: reply = speaker.generate_reply(sender=self) reply = speaker.generate_reply(sender=self, messages=groupchat.messages) else: # admin agent is not found in the participants raise if reply is None: break # The speaker sends the message without requesting a reply speaker.send(reply, self, request_reply=False) message = self.last_message(speaker) return True, None
Jag har gjort några mindre ändringar i den ursprungliga implementeringen. Du bör kunna följa kommentarerna för att veta mer.
Men det finns en sak jag verkligen vill betona. Du kan åsidosätta GroupChatManagers "run_chat"-metod för att plugga in din egen arbetsflödesmotor som Apache Airflow eller Temporal. Utövare av distribuerade system vet exakt hur kraftfull denna förmåga är!
Vi ställer in det här som i det föregående exemplet och tittar på denna baby purrr! 🐱
# Create our agents user = get_user() topic_analyzer = get_topic_analyzer(base_llm_config) paraphrazer = get_paraphrazer(base_llm_config) task_creator = get_tasks_creator(base_llm_config) # Create our group chat groupchat = CustomGroupChat(agents=[user, topic_analyzer, paraphrazer, task_creator]) manager = CustomGroupChatManager(groupchat=groupchat, llm_config=base_llm_config) # Start the chat user.initiate_chat( manager, clear_history=True, message=note, ) # Lets print the count of tasks just for fun chat_messages = user.chat_messages.get(manager) if chat_messages is not None: for message in chat_messages: if message.get("name") == "Task_Creator": taskList = yaml.safe_load(message.get("content")) # type: ignore l = len(taskList.get("tasks")) print(f"Got {l} tasks from Task_Creator.")
Utgången kommer att se ut ungefär så här:
Admin (to chat_manager): Note: Convo with editor: - discuss titles and thumbnails - discuss video editing tips tracker - Zeeshan presents the tracker - what trick helps with what - he decidedls if we can experiment with something new - make sure all all videos since how config management works in k8s are backed u - make list of YouTube thumbnail templates - make list of YouTube idea generation limits -------------------------------------------------------------------------------- Topic_Analyzer (to chat_manager): Here is the list of topics discussed in the note: 1. Titles 2. Thumbnails 3. Video editing tips 4. Config management in Kubernetes (k8s) 5. YouTube thumbnail templates 6. YouTube idea generation limits -------------------------------------------------------------------------------- Paraphrazer (to chat_manager): Here is the rewritten note in markdown format: ## Titles - Discuss titles and thumbnails with the editor ## Video Editing Tips Tracker ### Zeeshan presents the tracker - What trick helps with what - He decides if we can experiment with something new ## Config Management in Kubernetes (k8s) - Make sure all videos since how config management works in k8s are backed up ## YouTube Thumbnail Templates - Make a list of YouTube thumbnail templates ## YouTube Idea Generation Limits - Make a list of YouTube idea generation limits ## Additional Info - Discuss video editing tips tracker with Zeeshan - Present the tracker and decide if we can experiment with something new -------------------------------------------------------------------------------- Task_Creator (to chat_manager): tasks: - title: Discuss Titles and Thumbnails description: >- - Discuss titles and thumbnails with the editor This task involves having a conversation with the editor to discuss the titles and thumbnails for the videos. - title: Discuss Video Editing Tips Tracker description: >- - Zeeshan presents the tracker - Discuss what trick helps with what - Decide if we can experiment with something new This task involves discussing the video editing tips tracker presented by Zeeshan, understanding what tricks help with what, and deciding if it's possible to experiment with something new. - title: Back up All Videos Since How Config Management Works in k8s description: >- - Make sure all videos since how config management works in k8s are backed up This task involves ensuring that all videos related to config management in Kubernetes (k8s) are backed up. - title: Create List of YouTube Thumbnail Templates description: >- - Make list of YouTube thumbnail templates This task involves creating a list of YouTube thumbnail templates. - title: Create List of YouTube Idea Generation Limits description: >- - Make list of YouTube idea generation limits This task involves creating a list of YouTube idea generation limits. -------------------------------------------------------------------------------- Got 5 tasks from Task_Creator.
Japp. Välkommen till en ålder av AI som ger oss hoomans arbete att göra! (Var gick det fel? 🤷♂️)
Att bygga generativa AI-drivna applikationer är svårt. Men det kan göras med rätt verktyg. För att sammanfatta:
Som nästa steg kan du kontrollera följande resurser för att dyka djupare in i AI-agenternas värld: