{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# History and Data Analysis Collaboration System\n", "\n", "## Overview\n", "This notebook implements a multi-agent collaboration system that combines historical research with data analysis to answer complex historical questions. It leverages the power of large language models to simulate specialized agents working together to provide comprehensive answers.\n", "\n", "## Motivation\n", "Historical analysis often requires both deep contextual understanding and quantitative data interpretation. By creating a system that combines these two aspects, we aim to provide more robust and insightful answers to complex historical questions. This approach mimics real-world collaboration between historians and data analysts, potentially leading to more nuanced and data-driven historical insights.\n", "\n", "## Key Components\n", "1. **Agent Class**: A base class for creating specialized AI agents.\n", "2. **HistoryResearchAgent**: Specialized in historical context and trends.\n", "3. **DataAnalysisAgent**: Focused on interpreting numerical data and statistics.\n", "4. **HistoryDataCollaborationSystem**: Orchestrates the collaboration between agents.\n", "\n", "## Method Details\n", "The collaboration system follows these steps:\n", "1. **Historical Context**: The History Agent provides relevant historical background.\n", "2. **Data Needs Identification**: The Data Agent determines what quantitative information is needed.\n", "3. **Historical Data Provision**: The History Agent supplies relevant historical data.\n", "4. **Data Analysis**: The Data Agent interprets the provided historical data.\n", "5. **Final Synthesis**: The History Agent combines all insights into a comprehensive answer.\n", "\n", "This iterative process allows for a back-and-forth between historical context and data analysis, mimicking real-world collaborative research.\n", "\n", "## Conclusion\n", "The History and Data Analysis Collaboration System demonstrates the potential of multi-agent AI systems in tackling complex, interdisciplinary questions. By combining the strengths of historical research and data analysis, it offers a novel approach to understanding historical trends and events. This system could be valuable for researchers, educators, and anyone interested in gaining deeper insights into historical topics.\n", "\n", "Future improvements could include adding more specialized agents, incorporating external data sources, and refining the collaboration process for even more nuanced analyses." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Import required libraries" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import os\n", "import time\n", "\n", "from langchain_openai import ChatOpenAI\n", "from langchain_core.messages import HumanMessage, SystemMessage, AIMessage\n", "from typing import List, Dict\n", "from dotenv import load_dotenv\n", "\n", "load_dotenv()\n", "os.environ[\"OPENAI_API_KEY\"] = os.getenv('OPENAI_API_KEY')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Initialize the language model" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "llm = ChatOpenAI(model=\"gpt-4o-mini\", max_tokens=1000, temperature=0.7)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Define the base Agent class" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "class Agent:\n", " def __init__(self, name: str, role: str, skills: List[str]):\n", " self.name = name\n", " self.role = role\n", " self.skills = skills\n", " self.llm = llm\n", "\n", " def process(self, task: str, context: List[Dict] = None) -> str:\n", " messages = [\n", " SystemMessage(content=f\"You are {self.name}, a {self.role}. Your skills include: {', '.join(self.skills)}. Respond to the task based on your role and skills.\")\n", " ]\n", " \n", " if context:\n", " for msg in context:\n", " if msg['role'] == 'human':\n", " messages.append(HumanMessage(content=msg['content']))\n", " elif msg['role'] == 'ai':\n", " messages.append(AIMessage(content=msg['content']))\n", " \n", " messages.append(HumanMessage(content=task))\n", " response = self.llm.invoke(messages)\n", " return response.content" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Define specialized agents: HistoryResearchAgent and DataAnalysisAgent" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "class HistoryResearchAgent(Agent):\n", " def __init__(self):\n", " super().__init__(\"Clio\", \"History Research Specialist\", [\"deep knowledge of historical events\", \"understanding of historical contexts\", \"identifying historical trends\"])\n", "\n", "class DataAnalysisAgent(Agent):\n", " def __init__(self):\n", " super().__init__(\"Data\", \"Data Analysis Expert\", [\"interpreting numerical data\", \"statistical analysis\", \"data visualization description\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Define the different functions for the collaboration system" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Research Historical Context" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "def research_historical_context(history_agent, task: str, context: list) -> list:\n", " print(\"πŸ›οΈ History Agent: Researching historical context...\")\n", " history_task = f\"Provide relevant historical context and information for the following task: {task}\"\n", " history_result = history_agent.process(history_task)\n", " context.append({\"role\": \"ai\", \"content\": f\"History Agent: {history_result}\"})\n", " print(f\"πŸ“œ Historical context provided: {history_result[:100]}...\\n\")\n", " return context" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Identify Data Needs" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "def identify_data_needs(data_agent, task: str, context: list) -> list:\n", " print(\"πŸ“Š Data Agent: Identifying data needs based on historical context...\")\n", " historical_context = context[-1][\"content\"]\n", " data_need_task = f\"Based on the historical context, what specific data or statistical information would be helpful to answer the original question? Historical context: {historical_context}\"\n", " data_need_result = data_agent.process(data_need_task, context)\n", " context.append({\"role\": \"ai\", \"content\": f\"Data Agent: {data_need_result}\"})\n", " print(f\"πŸ” Data needs identified: {data_need_result[:100]}...\\n\")\n", " return context" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Provide Historical Data" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "def provide_historical_data(history_agent, task: str, context: list) -> list:\n", " print(\"πŸ›οΈ History Agent: Providing relevant historical data...\")\n", " data_needs = context[-1][\"content\"]\n", " data_provision_task = f\"Based on the data needs identified, provide relevant historical data or statistics. Data needs: {data_needs}\"\n", " data_provision_result = history_agent.process(data_provision_task, context)\n", " context.append({\"role\": \"ai\", \"content\": f\"History Agent: {data_provision_result}\"})\n", " print(f\"πŸ“Š Historical data provided: {data_provision_result[:100]}...\\n\")\n", " return context" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Analyze Data" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "def analyze_data(data_agent, task: str, context: list) -> list:\n", " print(\"πŸ“ˆ Data Agent: Analyzing historical data...\")\n", " historical_data = context[-1][\"content\"]\n", " analysis_task = f\"Analyze the historical data provided and describe any trends or insights relevant to the original task. Historical data: {historical_data}\"\n", " analysis_result = data_agent.process(analysis_task, context)\n", " context.append({\"role\": \"ai\", \"content\": f\"Data Agent: {analysis_result}\"})\n", " print(f\"πŸ’‘ Data analysis results: {analysis_result[:100]}...\\n\")\n", " return context" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Synthesize Final Answer" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "def synthesize_final_answer(history_agent, task: str, context: list) -> str:\n", " print(\"πŸ›οΈ History Agent: Synthesizing final answer...\")\n", " synthesis_task = \"Based on all the historical context, data, and analysis, provide a comprehensive answer to the original task.\"\n", " final_result = history_agent.process(synthesis_task, context)\n", " return final_result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### HistoryDataCollaborationSystem Class" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "class HistoryDataCollaborationSystem:\n", " def __init__(self):\n", " self.history_agent = Agent(\"Clio\", \"History Research Specialist\", [\"deep knowledge of historical events\", \"understanding of historical contexts\", \"identifying historical trends\"])\n", " self.data_agent = Agent(\"Data\", \"Data Analysis Expert\", [\"interpreting numerical data\", \"statistical analysis\", \"data visualization description\"])\n", "\n", " def solve(self, task: str, timeout: int = 300) -> str:\n", " print(f\"\\nπŸ‘₯ Starting collaboration to solve: {task}\\n\")\n", " \n", " start_time = time.time()\n", " context = []\n", " \n", " steps = [\n", " (research_historical_context, self.history_agent),\n", " (identify_data_needs, self.data_agent),\n", " (provide_historical_data, self.history_agent),\n", " (analyze_data, self.data_agent),\n", " (synthesize_final_answer, self.history_agent)\n", " ]\n", " \n", " for step_func, agent in steps:\n", " if time.time() - start_time > timeout:\n", " return \"Operation timed out. The process took too long to complete.\"\n", " try:\n", " result = step_func(agent, task, context)\n", " if isinstance(result, str):\n", " return result # This is the final answer\n", " context = result\n", " except Exception as e:\n", " return f\"Error during collaboration: {str(e)}\"\n", " \n", " print(\"\\nβœ… Collaboration complete. Final answer synthesized.\\n\")\n", " return context[-1][\"content\"]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example usage" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "πŸ‘₯ Starting collaboration to solve: How did urbanization rates in Europe compare to those in North America during the Industrial Revolution, and what were the main factors influencing these trends?\n", "\n", "πŸ›οΈ History Agent: Researching historical context...\n", "πŸ“œ Historical context provided: During the Industrial Revolution, which generally spanned from the late 18th century to the mid-19th...\n", "\n", "πŸ“Š Data Agent: Identifying data needs based on historical context...\n", "πŸ” Data needs identified: To analyze the urbanization phenomenon during the Industrial Revolution in Europe and North America ...\n", "\n", "πŸ›οΈ History Agent: Providing relevant historical data...\n", "πŸ“Š Historical data provided: Here is some relevant historical data and statistics that pertain to the urbanization phenomenon dur...\n", "\n", "πŸ“ˆ Data Agent: Analyzing historical data...\n", "πŸ’‘ Data analysis results: Data Agent: Analyzing the historical data provided reveals several key trends and insights regarding...\n", "\n", "πŸ›οΈ History Agent: Synthesizing final answer...\n", "### Urbanization During the Industrial Revolution: A Comparative Analysis of Europe and North America\n", "\n", "The Industrial Revolution, spanning from the late 18th century to the mid-19th century, marked a transformative era characterized by significant changes in economic structures, social dynamics, and urban development. Urbanization emerged as a crucial phenomenon during this period, particularly in Europe and North America, albeit with notable differences in the pace, scale, and nature of urban growth between the two regions.\n", "\n", "#### Urbanization in Europe\n", "\n", "1. **Origins and Growth**: The Industrial Revolution began in Britain around the 1760s, leading to rapid industrial growth and a shift from agrarian to industrial economies. Cities such as Manchester, Birmingham, and London witnessed explosive population growth. For example, London’s population surged from approximately 1 million in 1801 to 2.5 million by 1851, while Manchester grew from 75,000 to 300,000 during the same period.\n", "\n", "2. **Rate of Urbanization**: By 1851, about 50% of Britain's population lived in urban areas, reflecting a significant urbanization trend. The annual growth rates in major cities were substantial, with Manchester experiencing an approximate 4.6% growth rate. This rapid urbanization was driven by the promise of jobs in factories and improved transportation networks, such as railways and canals, which facilitated the movement of goods and people.\n", "\n", "3. **Social and Economic Shifts**: The urban workforce transformed dramatically, with roughly 50% of the British workforce engaged in manufacturing by mid-century. This shift led to the emergence of a distinct working class and significant social changes, including increased labor organization and political activism, exemplified by movements like Chartism.\n", "\n", "4. **Challenges**: Urbanization brought about severe social challenges, including overcrowding, poor living conditions, and public health crises. For instance, cholera outbreaks in London during the 1840s underscored the dire consequences of rapid urban growth, as many urban areas lacked adequate sanitation and housing.\n", "\n", "#### Urbanization in North America\n", "\n", "1. **Emergence and Growth**: North America, particularly the United States, began its industrialization later, gaining momentum in the early to mid-19th century. Cities like New York and Chicago became pivotal industrial and urban centers. New York City's population grew from around 60,000 in 1800 to over 1.1 million by 1860, showcasing a remarkable urban expansion.\n", "\n", "2. **Urbanization Rates**: By 1860, approximately 20% of the U.S. population lived in urban areas, indicating a lower urbanization level compared to Europe. However, the growth rate of urban populations was high, with New York experiencing an annual growth rate of about 7.6%. This growth was fueled by substantial immigration, primarily from Europe, which contributed significantly to urban demographics.\n", "\n", "3. **Economic and Labor Dynamics**: The U.S. saw about 20% of its workforce in manufacturing by 1860, with approximately 110,000 manufacturing establishments, marking a burgeoning industrial sector. The influx of immigrants provided a labor force that was essential for the growth of industries and urban centers, significantly diversifying the population.\n", "\n", "4. **Social Issues**: Like their European counterparts, urban areas in the U.S. faced challenges related to overcrowding and inadequate infrastructure. In New York, some neighborhoods had population densities exceeding 135,000 people per square mile. These conditions often led to public health concerns and social unrest, prompting the rise of labor movements advocating for workers’ rights and improved living conditions.\n", "\n", "5. **Legislative Responses**: The response to urbanization in the U.S. included the formation of labor unions and early labor movements, such as the National Labor Union established in 1866, which aimed to address workers' rights and working conditions. This reflected a growing awareness of the need for social and economic reforms amidst the rapid urban and industrial expansion.\n", "\n", "#### Conclusion\n", "\n", "In conclusion, urbanization during the Industrial Revolution was a defining characteristic of both Europe and North America, driven by industrialization, economic opportunities, and transportation advancements. Europe, particularly Britain, experienced an earlier and more advanced stage of urbanization, while North America, fueled by immigration and rapid industrial growth, showed a remarkable increase in urban populations. Despite their differences, both regions faced similar challenges related to overcrowding, public health, and labor rights, leading to social changes and movements advocating for reforms. The complexities of urbanization during this transformative era laid the groundwork for the modern urban landscape, shaping socioeconomic structures and influencing future developments in both regions.\n" ] } ], "source": [ "# Create an instance of the collaboration system\n", "collaboration_system = HistoryDataCollaborationSystem()\n", "\n", "# Define a complex historical question that requires both historical knowledge and data analysis\n", "question = \"How did urbanization rates in Europe compare to those in North America during the Industrial Revolution, and what were the main factors influencing these trends?\"\n", "\n", "# Solve the question using the collaboration system\n", "result = collaboration_system.solve(question)\n", "\n", "# Print the result\n", "print(result)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![](https://europe-west1-genai-agents-views-tracker.cloudfunctions.net/genai-agents-tracker?notebook=all-agents-tutorials--multi-agent-collaboration-system)" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.0" } }, "nbformat": 4, "nbformat_minor": 2 }