This hands-on exercise guides you through implementing a multi-agent system designed for collaborative problem resolution. We will build a small team of LLM-powered agents tasked with planning a corporate team-building event. This scenario requires agents with different specializations to share information, identify potential conflicts in their proposals, and work towards a unified, coherent plan. Through this process, you will see a practical application of how distributed knowledge and specialized reasoning can be combined to solve a problem that would be more challenging for a single agent.The core of this exercise lies in demonstrating how agents can:Contribute specialized information (e.g., logistics, activity ideas).Have their contributions evaluated for compatibility by a coordinating agent.Potentially revise their contributions based on feedback, simulating a basic negotiation or refinement process.Ultimately, have their individual inputs synthesized into a collective output.This practical example builds upon the chapter's discussions on collective reasoning, distributed problem resolution, and touches upon elements of how agents might manage interactions, albeit in a simplified manner.System Architecture: The Event Planning TeamOur multi-agent system will consist of three distinct agents:Logistics Agent: This agent is responsible for researching and proposing suitable venues for the team-building event. It considers factors like team size, budget, location preferences, and date ranges.Activity Agent: This agent focuses on brainstorming and suggesting engaging team-building activities. It considers the event's goals, team demographics, and the nature of activities that might foster collaboration or morale.Coordinator Agent: This agent acts as the orchestrator. It collects proposals from the Logistics and Activity agents, uses an LLM to analyze them for compatibility and potential conflicts, requests revisions if necessary, and finally, synthesizes the inputs into a final event plan.The interaction flow is visualized below:digraph G { rankdir=TB; bgcolor="transparent"; node [shape=box, style="filled", color="#e9ecef", fontname="sans-serif", margin=0.15]; edge [fontname="sans-serif", fontsize=10]; coordinator [label="Coordinator Agent", fillcolor="#a5d8ff", shape=ellipse]; logistics [label="Logistics Agent", fillcolor="#b2f2bb"]; activity [label="Activity Agent", fillcolor="#ffd8a8"]; final_plan [label="Final Event Plan", shape=document, fillcolor="#da77f2"]; user_input [label="Event Requirements\n(Team Size, Budget, Goals)", shape=note, fillcolor="#e9ecef"]; user_input -> coordinator [style=dotted]; coordinator -> logistics [label=" Request Venue Proposal", fontcolor="#1c7ed6"]; logistics -> coordinator [label=" Venue Proposal", fontcolor="#37b24d"]; coordinator -> activity [label=" Request Activity Proposal", fontcolor="#1c7ed6"]; activity -> coordinator [label=" Activity Proposal", fontcolor="#f76707"]; subgraph cluster_conflict_resolution { label = "Refinement Loop"; labeljust = "l"; style="dashed,rounded"; bgcolor="#f8f9fa"; color="#adb5bd"; margin=20; node [fontsize=9]; edge [fontsize=9]; coordinator -> logistics [label=" Request Revision\n(if incompatible)", style=dashed, color="#f03e3e", constraint=false]; logistics -> coordinator [label=" Revised Venue\nProposal", style=dashed, color="#40c057", constraint=false]; coordinator -> activity [label=" Request Revision\n(if incompatible)", style=dashed, color="#f03e3e", constraint=false]; activity -> coordinator [label=" Revised Activity\nProposal", style=dashed, color="#40c057", constraint=false]; placeholder [style=invis, width=0, height=0, label=""]; # To help with layout coordinator -> placeholder [style=invis]; placeholder -> logistics [style=invis]; placeholder -> activity [style=invis]; } coordinator -> final_plan [label=" Synthesize Final Plan", fontcolor="#7048e8"]; }The diagram illustrates the Coordinator Agent initiating requests to the Logistics and Activity Agents. Proposals are returned, potentially undergoing a refinement loop if incompatibilities are detected, before the Coordinator synthesizes the final event plan.Prerequisites and SetupBefore we begin, ensure you have the following:Python 3.8 or higher.Access to an LLM, such as one from OpenAI. You'll need an API key. For this example, we'll use the openai Python library.Familiarity with defining functions or classes in Python and making API calls to an LLM.Install the necessary library:pip install openaiSet up your API key, typically as an environment variable:export OPENAI_API_KEY='your_api_key_here'We'll define a helper function to interact with the LLM. This example uses OpenAI's models, but the principles apply to other LLMs.import os import openai # Ensure your OpenAI API key is set as an environment variable # openai.api_key = os.getenv("OPENAI_API_KEY") # Deprecated # Use the new client: client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) def get_llm_response(prompt_text, model="gpt-3.5-turbo"): try: response = client.chat.completions.create( model=model, messages=[{"role": "user", "content": prompt_text}], temperature=0.5, # Adjust for creativity vs. determinism max_tokens=300 ) return response.choices[0].message.content.strip() except Exception as e: print(f"Error communicating with LLM: {e}") return None This helper function encapsulates the API call, making our agent logic cleaner. Remember to handle API keys securely and manage exceptions robustly in production systems.Implementation WalkthroughWe'll implement each agent's core logic and then the coordination process.Step 1: Defining Individual Agent CapabilitiesEach agent will be represented by a Python function that takes relevant inputs and uses an LLM to generate its specialized output.Logistics AgentThis agent suggests venues based on provided constraints.def logistics_agent(team_size, budget, desired_location, event_duration): prompt = f""" You are a Logistics Specialist for corporate event planning. Your task is to propose two distinct venue options for a team-building event. Event Details: - Team Size: {team_size} people - Budget for Venue: ${budget} - Desired General Location: {desired_location} - Event Duration: {event_duration} Please provide: 1. Venue Name 2. A brief description of why it's suitable. 3. Estimated cost for the duration. 4. Any notable features or constraints (e.g., capacity, specific amenities). Format your response clearly for each option. """ print("\n--- Logistics Agent working... ---") response = get_llm_response(prompt) print("Logistics Agent Proposal:\n", response) return responseActivity AgentThis agent suggests team-building activities aligned with event goals.def activity_agent(team_size, event_goals, team_profile): prompt = f""" You are an Activity Specialist for corporate team-building events. Your task is to propose two distinct activities suitable for the event. Event Context: - Team Size: {team_size} people - Primary Event Goals: {event_goals} - Team Profile: {team_profile} (e.g., "Software engineers, mixed seniority") Please provide for each activity: 1. Activity Name 2. A brief description of the activity. 3. How it aligns with the event goals. 4. Estimated duration and any specific requirements (e.g., outdoor space, specific materials). Format your response clearly for each option. """ print("\n--- Activity Agent working... ---") response = get_llm_response(prompt) print("Activity Agent Proposal:\n", response) return responseStep 2: Designing the Communication and Coordination Logic (Coordinator Agent)The CoordinatorAgent will manage the workflow, including conflict identification and requesting revisions.def coordinator_agent_analyze_proposals(venue_proposal, activity_proposal): prompt = f""" You are an Event Planning Coordinator. You have received proposals from a Logistics Agent and an Activity Agent. Your task is to analyze these proposals for compatibility and overall coherence. Venue Proposal: {venue_proposal} Activity Proposal: {activity_proposal} Analyze the following: 1. Compatibility: Are the activities suitable for the proposed venue types? (e.g., an outdoor activity at an indoor-only venue). 2. Budget: While detailed budget checks are separate, note any obvious mismatches if an activity implies significant extra costs not covered by a typical venue budget (e.g., specialized equipment rental not usually part of venue hire). 3. Overall Cohesion: Do the proposals seem to align for a successful event? If there are significant incompatibilities, clearly state them and suggest what needs to be revised (e.g., "Logistics Agent should find a venue with outdoor space," or "Activity Agent should propose an indoor activity"). If proposals are generally compatible, state "Proposals are compatible." """ print("\n--- Coordinator Agent analyzing proposals... ---") analysis = get_llm_response(prompt) print("Coordinator Analysis:\n", analysis) return analysis def request_revision_logistics(original_proposal, feedback): prompt = f""" You are a Logistics Specialist. Your previous venue proposal needs revision based on feedback. Your Original Proposal: {original_proposal} Feedback and Revision Request: {feedback} Please provide an updated venue proposal that addresses the feedback. If you cannot fully address it, explain why and offer the best alternative. """ print("\n--- Coordinator requesting revision from Logistics Agent... ---") revised_proposal = get_llm_response(prompt) print("Logistics Agent Revised Proposal:\n", revised_proposal) return revised_proposal def request_revision_activity(original_proposal, feedback): prompt = f""" You are an Activity Specialist. Your previous activity proposal needs revision based on feedback. Your Original Proposal: {original_proposal} Feedback and Revision Request: {feedback} Please provide an updated activity proposal that addresses the feedback. If you cannot fully address it, explain why and offer the best alternative. """ print("\n--- Coordinator requesting revision from Activity Agent... ---") revised_proposal = get_llm_response(prompt) print("Activity Agent Revised Proposal:\n", revised_proposal) return revised_proposalThe revision request functions simulate the Coordinator agent sending feedback back to the specialist agents. In a more complex system, this would involve message passing and state updates.Step 3: Synthesizing the Final PlanOnce compatible (or revised) proposals are available, the Coordinator synthesizes them.def coordinator_agent_synthesize_plan(final_venue_proposal, final_activity_proposal, event_details): prompt = f""" You are an Event Planning Coordinator. You have finalized venue and activity proposals. Synthesize these into a coherent event plan. Event Details: - Team Size: {event_details['team_size']} - Budget: ${event_details['budget']} - Location: {event_details['location']} - Duration: {event_details['duration']} - Goals: {event_details['goals']} - Team Profile: {event_details['profile']} Final Venue Proposal: {final_venue_proposal} Final Activity Proposal: {final_activity_proposal} Create a concise, actionable event plan. Include: - Event Title (be creative) - Date/Time (use placeholder if not specified, e.g., "To be confirmed for next month") - Venue Details (summarized) - Activity Details (summarized) - A brief suggested schedule or flow for the event. - Any important notes or next steps. """ print("\n--- Coordinator Agent synthesizing final plan... ---") final_plan = get_llm_response(prompt) print("\n================ FINAL EVENT PLAN ================\n") print(final_plan) return final_planRunning the Scenario and Observing CollaborationNow, let's orchestrate the entire process. We'll define some initial event parameters and run the agents.def run_event_planning_scenario(): # Initial Event Parameters event_details = { "team_size": 30, "budget": 2000, # Budget for venue "location": "City Center or easily accessible suburban area", "duration": "Full Day", "goals": "Improve team cohesion and problem-solving skills", "profile": "Cross-functional project team (engineers, designers, product managers)" } # 1. Get initial proposals venue_proposal = logistics_agent( event_details["team_size"], event_details["budget"], event_details["location"], event_details["duration"] ) activity_proposal = activity_agent( event_details["team_size"], event_details["goals"], event_details["profile"] ) if not venue_proposal or not activity_proposal: print("Failed to get initial proposals. Exiting.") return # 2. Coordinator analyzes proposals max_revisions = 1 # Keep it simple for this example revisions_done = 0 current_venue_proposal = venue_proposal current_activity_proposal = activity_proposal while revisions_done < max_revisions: analysis_result = coordinator_agent_analyze_proposals(current_venue_proposal, current_activity_proposal) if not analysis_result: print("Failed to get analysis. Exiting.") return if "Proposals are compatible." in analysis_result: print("\nProposals deemed compatible by Coordinator.") break else: print(f"\nIncompatibility found. Attempting revision {revisions_done + 1}/{max_revisions}") # Simplified: Assume feedback targets both if issues exist, or make it more targeted. # For a more system, parse analysis_result to target specific agent(s). # Here, we'll naively ask both to revise based on general feedback if not compatible. # A more advanced coordinator would parse the analysis to decide who to ask for revision. # This is a simplification; a real system would parse the analysis to generate targeted feedback. # For this example, let's assume the analysis contains actionable feedback. feedback_for_logistics = f"Coordinator analysis suggests potential issues with your venue proposal in light of the activity proposal. Analysis: {analysis_result}. Please revise." current_venue_proposal = request_revision_logistics(current_venue_proposal, feedback_for_logistics) if not current_venue_proposal: print("Logistics agent failed to revise. Using last known good proposal or exiting.") break # or handle error feedback_for_activity = f"Coordinator analysis suggests potential issues with your activity proposal in light of the venue proposal. Analysis: {analysis_result}. Please revise." current_activity_proposal = request_revision_activity(current_activity_proposal, feedback_for_activity) if not current_activity_proposal: print("Activity agent failed to revise. Using last known good proposal or exiting.") break # or handle error revisions_done += 1 if revisions_done >= max_revisions: print("\nMax revisions reached. Proceeding with current proposals.") # 3. Synthesize final plan coordinator_agent_synthesize_plan(current_venue_proposal, current_activity_proposal, event_details) if __name__ == "__main__": # Ensure OPENAI_API_KEY is set in your environment if not os.getenv("OPENAI_API_KEY"): print("Error: OPENAI_API_KEY environment variable not set.") else: run_event_planning_scenario()When you run run_event_planning_scenario(), observe the outputs:The initial proposals from the Logistics and Activity agents.The Coordinator Agent's analysis of these proposals.If incompatibilities are identified, observe the (simulated) revision requests and the subsequent revised proposals. Note that the LLM's ability to "revise" effectively depends heavily on the clarity of the feedback and the original context.The final, synthesized event plan.This flow demonstrates a basic form of collaborative problem resolution. The agents aren't just performing tasks in isolation; their outputs are integrated and checked for consistency, with a mechanism (albeit simplified) for iterative refinement.Reflections on Collaborative Problem ResolutionThis hands-on exercise, while using straightforward LLM calls for each agent's "reasoning," illustrates several important aspects of multi-agent collaborative problem resolution discussed in this chapter:Task Decomposition: The complex problem of event planning was broken down into specialized sub-tasks handled by the Logistics and Activity agents.Information Sharing and Aggregation: Proposals from individual agents were shared with the Coordinator, who aggregated this information for analysis and synthesis.Conflict Detection and Simple Refinement: The Coordinator agent played a role in identifying potential misalignments between proposals. The revision loop, though basic, mimics a negotiation or refinement process where agents adjust their contributions based on broader system needs or constraints identified by another agent.Distributed Problem Solving: The final plan is a product of the collective effort and information from multiple agents, orchestrated towards a common goal. No single agent possessed all the information or capabilities to produce the plan alone.Further Considerations and Extensions:Sophisticated Communication: In more complex systems, agents would use well-defined message formats and communication protocols (as discussed in Chapter 3) rather than direct function calls and shared memory within a single script.Advanced Negotiation: The conflict resolution here was rudimentary. Applications might involve more sophisticated negotiation strategies, where agents might propose counter-offers, explain their constraints, or use utility functions to evaluate trade-offs (referencing "Techniques for Negotiation and Consensus").Agent State and Memory: Each agent here is largely stateless between calls (except for the implicit context carried in prompts). Persistent memory (Chapter 2) would allow agents to learn from past interactions or maintain more complex internal states.Dynamic Task Allocation: The Coordinator's role was predefined. More adaptive systems might dynamically allocate tasks or even spawn new agents based on the evolving problem state (see Chapter 4 on orchestration).Belief-Desire-Intention (BDI) Link: While not a full BDI implementation, the agents exhibit behaviors aligned with BDI principles. They have "beliefs" (their specialized knowledge and the current proposals), "desires" (to fulfill their assigned task, like proposing a venue), and "intentions" (the actual proposal they generate or revise). The Coordinator helps align these individual intentions towards a collective goal.This exercise provides a foundational example. Building multi-agent systems for complex problem resolution often involves tackling challenges in ensuring reliable communication, managing states, designing coordination mechanisms, and evaluating system behavior. The techniques discussed throughout this course aim to equip you to address these challenges.