From 1fb07b2729af3393623afe45cbab22f5b345c438 Mon Sep 17 00:00:00 2001 From: Harish Mohan Raj Date: Tue, 28 Jan 2025 21:11:10 +0530 Subject: [PATCH] WIP: update user guide navigation --- .../assets/code-execution-in-conversation.png | 0 .../assets/code-executor-docker.png | 0 .../assets/code-executor-no-docker.png | 0 .../assets/code-executor-stock-chart.png | 0 .../assets/group-chat-fsm.png | 0 .../assets/swarm-enhanced-01.png | 0 .../assets/swarm-enhanced-02.png | 0 .../assets/swarm-enhanced-03.png | 0 .../assets/swarm-enhanced-04.png | 0 .../advanced-concepts/code-execution.mdx} | 4 +- .../code-execution/.gitignore | 1 - .../code-execution/_category_.json | 5 - .../code-execution/cli-code-executor.ipynb | 413 ---------- .../code-execution/custom-executor.ipynb | 503 ------------ .../jupyter-code-executor.ipynb | 459 ----------- .../user-defined-functions.ipynb | 352 -------- .../advanced-concepts/custom-group-chat.mdx} | 9 +- .../advanced-concepts/enhanced-swarm.mdx} | 12 +- .../groupchat/_category_.json | 5 - .../customized_speaker_selection.ipynb | 543 ------------ .../groupchat/resuming_groupchat.ipynb | 761 ----------------- ...transform_messages_speaker_selection.ipynb | 247 ------ .../using_custom_model_client_classes.ipynb | 451 ---------- .../user-guide/advanced-concepts/rag.mdx} | 13 +- .../retrieval_augmentation.mdx | 136 ---- .../user-guide/advanced-concepts/swarm.ipynb | 770 ------------------ .../advanced-concepts/tools-with-secrets.mdx} | 4 +- website/mint-json-template.json.jinja | 25 +- website/use-cases/walk-throughs/index.md | 3 - 29 files changed, 32 insertions(+), 4684 deletions(-) rename website/{use-cases/walk-throughs => docs/user-guide/advanced-concepts}/assets/code-execution-in-conversation.png (100%) rename website/{use-cases/walk-throughs => docs/user-guide/advanced-concepts}/assets/code-executor-docker.png (100%) rename website/{use-cases/walk-throughs => docs/user-guide/advanced-concepts}/assets/code-executor-no-docker.png (100%) rename website/{use-cases/walk-throughs => docs/user-guide/advanced-concepts}/assets/code-executor-stock-chart.png (100%) rename website/{use-cases/walk-throughs => docs/user-guide/advanced-concepts}/assets/group-chat-fsm.png (100%) rename website/{use-cases/walk-throughs => docs/user-guide/advanced-concepts}/assets/swarm-enhanced-01.png (100%) rename website/{use-cases/walk-throughs => docs/user-guide/advanced-concepts}/assets/swarm-enhanced-02.png (100%) rename website/{use-cases/walk-throughs => docs/user-guide/advanced-concepts}/assets/swarm-enhanced-03.png (100%) rename website/{use-cases/walk-throughs => docs/user-guide/advanced-concepts}/assets/swarm-enhanced-04.png (100%) rename website/{use-cases/walk-throughs/code-execution.md => docs/user-guide/advanced-concepts/code-execution.mdx} (99%) delete mode 100644 website/docs/user-guide/advanced-concepts/code-execution/.gitignore delete mode 100644 website/docs/user-guide/advanced-concepts/code-execution/_category_.json delete mode 100644 website/docs/user-guide/advanced-concepts/code-execution/cli-code-executor.ipynb delete mode 100644 website/docs/user-guide/advanced-concepts/code-execution/custom-executor.ipynb delete mode 100644 website/docs/user-guide/advanced-concepts/code-execution/jupyter-code-executor.ipynb delete mode 100644 website/docs/user-guide/advanced-concepts/code-execution/user-defined-functions.ipynb rename website/{use-cases/walk-throughs/custom-group-chat.md => docs/user-guide/advanced-concepts/custom-group-chat.mdx} (99%) rename website/{use-cases/walk-throughs/enhanced-swarm.md => docs/user-guide/advanced-concepts/enhanced-swarm.mdx} (99%) delete mode 100644 website/docs/user-guide/advanced-concepts/groupchat/_category_.json delete mode 100644 website/docs/user-guide/advanced-concepts/groupchat/customized_speaker_selection.ipynb delete mode 100644 website/docs/user-guide/advanced-concepts/groupchat/resuming_groupchat.ipynb delete mode 100644 website/docs/user-guide/advanced-concepts/groupchat/transform_messages_speaker_selection.ipynb delete mode 100644 website/docs/user-guide/advanced-concepts/groupchat/using_custom_model_client_classes.ipynb rename website/{use-cases/walk-throughs/rag.md => docs/user-guide/advanced-concepts/rag.mdx} (97%) delete mode 100644 website/docs/user-guide/advanced-concepts/retrieval_augmentation.mdx delete mode 100644 website/docs/user-guide/advanced-concepts/swarm.ipynb rename website/{use-cases/walk-throughs/tools-with-secrets.md => docs/user-guide/advanced-concepts/tools-with-secrets.mdx} (99%) delete mode 100644 website/use-cases/walk-throughs/index.md diff --git a/website/use-cases/walk-throughs/assets/code-execution-in-conversation.png b/website/docs/user-guide/advanced-concepts/assets/code-execution-in-conversation.png similarity index 100% rename from website/use-cases/walk-throughs/assets/code-execution-in-conversation.png rename to website/docs/user-guide/advanced-concepts/assets/code-execution-in-conversation.png diff --git a/website/use-cases/walk-throughs/assets/code-executor-docker.png b/website/docs/user-guide/advanced-concepts/assets/code-executor-docker.png similarity index 100% rename from website/use-cases/walk-throughs/assets/code-executor-docker.png rename to website/docs/user-guide/advanced-concepts/assets/code-executor-docker.png diff --git a/website/use-cases/walk-throughs/assets/code-executor-no-docker.png b/website/docs/user-guide/advanced-concepts/assets/code-executor-no-docker.png similarity index 100% rename from website/use-cases/walk-throughs/assets/code-executor-no-docker.png rename to website/docs/user-guide/advanced-concepts/assets/code-executor-no-docker.png diff --git a/website/use-cases/walk-throughs/assets/code-executor-stock-chart.png b/website/docs/user-guide/advanced-concepts/assets/code-executor-stock-chart.png similarity index 100% rename from website/use-cases/walk-throughs/assets/code-executor-stock-chart.png rename to website/docs/user-guide/advanced-concepts/assets/code-executor-stock-chart.png diff --git a/website/use-cases/walk-throughs/assets/group-chat-fsm.png b/website/docs/user-guide/advanced-concepts/assets/group-chat-fsm.png similarity index 100% rename from website/use-cases/walk-throughs/assets/group-chat-fsm.png rename to website/docs/user-guide/advanced-concepts/assets/group-chat-fsm.png diff --git a/website/use-cases/walk-throughs/assets/swarm-enhanced-01.png b/website/docs/user-guide/advanced-concepts/assets/swarm-enhanced-01.png similarity index 100% rename from website/use-cases/walk-throughs/assets/swarm-enhanced-01.png rename to website/docs/user-guide/advanced-concepts/assets/swarm-enhanced-01.png diff --git a/website/use-cases/walk-throughs/assets/swarm-enhanced-02.png b/website/docs/user-guide/advanced-concepts/assets/swarm-enhanced-02.png similarity index 100% rename from website/use-cases/walk-throughs/assets/swarm-enhanced-02.png rename to website/docs/user-guide/advanced-concepts/assets/swarm-enhanced-02.png diff --git a/website/use-cases/walk-throughs/assets/swarm-enhanced-03.png b/website/docs/user-guide/advanced-concepts/assets/swarm-enhanced-03.png similarity index 100% rename from website/use-cases/walk-throughs/assets/swarm-enhanced-03.png rename to website/docs/user-guide/advanced-concepts/assets/swarm-enhanced-03.png diff --git a/website/use-cases/walk-throughs/assets/swarm-enhanced-04.png b/website/docs/user-guide/advanced-concepts/assets/swarm-enhanced-04.png similarity index 100% rename from website/use-cases/walk-throughs/assets/swarm-enhanced-04.png rename to website/docs/user-guide/advanced-concepts/assets/swarm-enhanced-04.png diff --git a/website/use-cases/walk-throughs/code-execution.md b/website/docs/user-guide/advanced-concepts/code-execution.mdx similarity index 99% rename from website/use-cases/walk-throughs/code-execution.md rename to website/docs/user-guide/advanced-concepts/code-execution.mdx index a6e75f0c50..9236d35184 100644 --- a/website/use-cases/walk-throughs/code-execution.md +++ b/website/docs/user-guide/advanced-concepts/code-execution.mdx @@ -1,4 +1,6 @@ -# Code Execution +--- +title: Code Execution +--- AG2 agents can execute in a message passed to them (e.g., those containing code blocks) and output a message with the results of the execution for the following agent to interpret. diff --git a/website/docs/user-guide/advanced-concepts/code-execution/.gitignore b/website/docs/user-guide/advanced-concepts/code-execution/.gitignore deleted file mode 100644 index e0230e42a3..0000000000 --- a/website/docs/user-guide/advanced-concepts/code-execution/.gitignore +++ /dev/null @@ -1 +0,0 @@ -coding diff --git a/website/docs/user-guide/advanced-concepts/code-execution/_category_.json b/website/docs/user-guide/advanced-concepts/code-execution/_category_.json deleted file mode 100644 index 57f54268af..0000000000 --- a/website/docs/user-guide/advanced-concepts/code-execution/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "position": 2, - "label": "Code Execution", - "collapsible": true -} diff --git a/website/docs/user-guide/advanced-concepts/code-execution/cli-code-executor.ipynb b/website/docs/user-guide/advanced-concepts/code-execution/cli-code-executor.ipynb deleted file mode 100644 index c0b1981929..0000000000 --- a/website/docs/user-guide/advanced-concepts/code-execution/cli-code-executor.ipynb +++ /dev/null @@ -1,413 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Command Line Code Executor\n", - "\n", - "Command line code execution is the simplest form of code execution. Generally speaking, it will save each code block to a file and the execute that file. This means that each code block is executed in a new process. There are two forms of this executor:\n", - "\n", - "- Docker ([`DockerCommandLineCodeExecutor`](/reference/autogen/coding/DockerCommandLineCodeExecutor#dockercommandlinecodeexecutor)) - this is where all commands are executed in a Docker container\n", - "- Local ([`LocalCommandLineCodeExecutor`](/reference/autogen/coding/LocalCommandLineCodeExecutor#localcommandlinecodeexecutor)) - this is where all commands are executed on the host machine\n", - "\n", - "This executor type is similar to the legacy code execution in AutoGen.\n", - "\n", - "## Docker\n", - "\n", - "The [`DockerCommandLineCodeExecutor`](/reference/autogen/coding/DockerCommandLineCodeExecutor#dockercommandlinecodeexecutor) will create a Docker container and run all commands within that container. The default image that is used is `python:3-slim`, this can be customized by passing the `image` parameter to the constructor. If the image is not found locally then the class will try to pull it. Therefore, having built the image locally is enough. The only thing required for this image to be compatible with the executor is to have `sh` and `python` installed. Therefore, creating a custom image is a simple and effective way to ensure required system dependencies are available.\n", - "\n", - "You can use the executor as a context manager to ensure the container is cleaned up after use. Otherwise, the `atexit` module will be used to stop the container when the program exits.\n", - "\n", - "### Inspecting the container\n", - "\n", - "If you wish to keep the container around after AutoGen is finished using it for whatever reason (e.g. to inspect the container), then you can set the `auto_remove` parameter to `False` when creating the executor. `stop_container` can also be set to `False` to prevent the container from being stopped at the end of the execution.\n", - "\n", - "### Example" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "exit_code=0 output='Hello, World!\\n' code_file='coding/tmp_code_07da107bb575cc4e02b0e1d6d99cc204.py'\n" - ] - } - ], - "source": [ - "from pathlib import Path\n", - "\n", - "from autogen.coding import CodeBlock, DockerCommandLineCodeExecutor\n", - "\n", - "work_dir = Path(\"coding\")\n", - "work_dir.mkdir(exist_ok=True)\n", - "\n", - "with DockerCommandLineCodeExecutor(work_dir=work_dir) as executor:\n", - " print(\n", - " executor.execute_code_blocks(\n", - " code_blocks=[\n", - " CodeBlock(language=\"python\", code=\"print('Hello, World!')\"),\n", - " ]\n", - " )\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Combining AutoGen in Docker with a Docker based executor\n", - "\n", - "It is desirable to bundle your AutoGen application into a Docker image. But then, how do you allow your containerised application to execute code in a different container?\n", - "\n", - "The recommended approach to this is called \"Docker out of Docker\", where the Docker socket is mounted to the main AutoGen container, so that it can spawn and control \"sibling\" containers on the host. This is better than what is called \"Docker in Docker\", where the main container runs a Docker daemon and spawns containers within itself. You can read more about this [here](https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/).\n", - "\n", - "To do this you would need to mount the Docker socket into the AutoGen container. This can be done by adding the following to the `docker run` command:\n", - "\n", - "```bash\n", - "-v /var/run/docker.sock:/var/run/docker.sock\n", - "```\n", - "\n", - "This will allow the AutoGen container to spawn and control sibling containers on the host.\n", - "\n", - "If you need to bind a working directory to the AutoGen container but the directory belongs to your host machine, use the `bind_dir` parameter. This will allow the main AutoGen container to bind the *host* directory to the new spawned containers and allow it to access the files within the said directory. If the `bind_dir` is not specified, it will fallback to `work_dir`." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Local\n", - "\n", - "````{=mdx}\n", - ":::danger\n", - "The local version will run code on your local system. Use it with caution.\n", - ":::\n", - "````\n", - "\n", - "To execute code on the host machine, as in the machine running AutoGen, the [`LocalCommandLineCodeExecutor`](/reference/autogen/coding/LocalCommandLineCodeExecutor#localcommandlinecodeexecutor) can be used.\n", - "\n", - "### Example" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "exit_code=0 output='\\nHello, World!\\n' code_file='coding/065b51a16ee54f3298847518f9e999d7.py'\n" - ] - } - ], - "source": [ - "from pathlib import Path\n", - "\n", - "from autogen.coding import CodeBlock, LocalCommandLineCodeExecutor\n", - "\n", - "work_dir = Path(\"coding\")\n", - "work_dir.mkdir(exist_ok=True)\n", - "\n", - "executor = LocalCommandLineCodeExecutor(work_dir=work_dir)\n", - "print(\n", - " executor.execute_code_blocks(\n", - " code_blocks=[\n", - " CodeBlock(language=\"python\", code=\"print('Hello, World!')\"),\n", - " ]\n", - " )\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Using a Python virtual environment\n", - "\n", - "By default, the LocalCommandLineCodeExecutor executes code and installs dependencies within the same Python environment as the AutoGen code. You have the option to specify a Python virtual environment to prevent polluting the base Python environment.\n", - "\n", - "### Example" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from autogen.code_utils import create_virtual_env\n", - "from autogen.coding import CodeBlock, LocalCommandLineCodeExecutor\n", - "\n", - "venv_dir = \".venv\"\n", - "venv_context = create_virtual_env(venv_dir)\n", - "\n", - "executor = LocalCommandLineCodeExecutor(virtual_env_context=venv_context)\n", - "print(\n", - " executor.execute_code_blocks(code_blocks=[CodeBlock(language=\"python\", code=\"import sys; print(sys.executable)\")])\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Assigning to an agent\n", - "\n", - "These executors can be used to facilitate the execution of agent written code. " - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from pathlib import Path\n", - "\n", - "from autogen import ConversableAgent\n", - "from autogen.coding import DockerCommandLineCodeExecutor\n", - "\n", - "work_dir = Path(\"coding\")\n", - "work_dir.mkdir(exist_ok=True)\n", - "\n", - "executor = DockerCommandLineCodeExecutor(work_dir=work_dir)\n", - "\n", - "code_executor_agent = ConversableAgent(\n", - " name=\"code_executor_agent\",\n", - " llm_config=False,\n", - " code_execution_config={\n", - " \"executor\": executor,\n", - " },\n", - " human_input_mode=\"NEVER\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "When using code execution it is critical that you update the system prompt of agents you expect to write code to be able to make use of the executor. For example, for the [`DockerCommandLineCodeExecutor`](/reference/autogen/coding/DockerCommandLineCodeExecutor#dockercommandlinecodeexecutor) you might setup a code writing agent like so:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "# The code writer agent's system message is to instruct the LLM on how to\n", - "# use the Jupyter code executor with IPython kernel.\n", - "code_writer_system_message = \"\"\"\n", - "You have been given coding capability to solve tasks using Python code.\n", - "In the following cases, suggest python code (in a python coding block) or shell script (in a sh coding block) for the user to execute.\n", - " 1. When you need to collect info, use the code to output the info you need, for example, browse or search the web, download/read a file, print the content of a webpage or a file, get the current date/time, check the operating system. After sufficient info is printed and the task is ready to be solved based on your language skill, you can solve the task by yourself.\n", - " 2. When you need to perform some task with code, use the code to perform the task and output the result. Finish the task smartly.\n", - "Solve the task step by step if you need to. If a plan is not provided, explain your plan first. Be clear which step uses code, and which step uses your language skill.\n", - "When using code, you must indicate the script type in the code block. The user cannot provide any other feedback or perform any other action beyond executing the code you suggest. The user can't modify your code. So do not suggest incomplete code which requires users to modify. Don't use a code block if it's not intended to be executed by the user.\n", - "If you want the user to save the code in a file before executing it, put # filename: inside the code block as the first line. Don't include multiple code blocks in one response. Do not ask users to copy and paste the result. Instead, use 'print' function for the output when relevant. Check the execution result returned by the user.\n", - "\"\"\"\n", - "\n", - "import os\n", - "\n", - "code_writer_agent = ConversableAgent(\n", - " \"code_writer\",\n", - " system_message=code_writer_system_message,\n", - " llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n", - " code_execution_config=False, # Turn off code execution for this agent.\n", - " max_consecutive_auto_reply=2,\n", - " human_input_mode=\"NEVER\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Then we can use these two agents to solve a problem:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mcode_executor_agent\u001b[0m (to code_writer):\n", - "\n", - "Write Python code to calculate the 14th Fibonacci number.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mcode_writer\u001b[0m (to code_executor_agent):\n", - "\n", - "Sure, we can calculate the Fibonacci series using a few different methods such as recursion, iterative, by using Binet's formula, or by using matrix exponentiation.\n", - "\n", - "But, since we only need to calculate the 14th number, we will simply use the iterative method as it's the most efficient for this case.\n", - "\n", - "Here is the Python code that solves the task:\n", - "\n", - "```python\n", - "def fibonacci(n):\n", - " a, b = 0, 1\n", - " for _ in range(n):\n", - " a, b = b, a + b\n", - " return a\n", - "\n", - "print(fibonacci(14))\n", - "```\n", - "\n", - "In this script, `fibonacci(n)` is a function that calculates the nth Fibonacci number. Inside the function, two variables `a` and `b` are initialised to `0` and `1` which are the first two numbers in the Fibonacci series. Then, a loop runs `n` times (14 times in your case), and in each iteration `a` is replaced with `b` and `b` is replaced with `a + b`, which generates the next number in the series. \n", - "\n", - "The function returns `a`, which is the nth Fibonacci number. The result is then printed to the console.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> EXECUTING 1 CODE BLOCKS (inferred languages are [python])...\u001b[0m\n", - "\u001b[33mcode_executor_agent\u001b[0m (to code_writer):\n", - "\n", - "exitcode: 0 (execution succeeded)\n", - "Code output: 377\n", - "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mcode_writer\u001b[0m (to code_executor_agent):\n", - "\n", - "Great! The script has successfully computed the 14th Fibonacci number as 377. If you need to compute other Fibonacci numbers, you can simply change the argument in the `fibonacci()` function call. Please let me know if you need help with anything else.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mcode_executor_agent\u001b[0m (to code_writer):\n", - "\n", - "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "ChatResult(chat_id=None,\n", - " chat_history=[{'content': 'Write Python code to calculate the 14th '\n", - " 'Fibonacci number.',\n", - " 'role': 'assistant'},\n", - " {'content': 'Sure, we can calculate the Fibonacci '\n", - " 'series using a few different methods '\n", - " 'such as recursion, iterative, by using '\n", - " \"Binet's formula, or by using matrix \"\n", - " 'exponentiation.\\n'\n", - " '\\n'\n", - " 'But, since we only need to calculate the '\n", - " '14th number, we will simply use the '\n", - " \"iterative method as it's the most \"\n", - " 'efficient for this case.\\n'\n", - " '\\n'\n", - " 'Here is the Python code that solves the '\n", - " 'task:\\n'\n", - " '\\n'\n", - " '```python\\n'\n", - " 'def fibonacci(n):\\n'\n", - " ' a, b = 0, 1\\n'\n", - " ' for _ in range(n):\\n'\n", - " ' a, b = b, a + b\\n'\n", - " ' return a\\n'\n", - " '\\n'\n", - " 'print(fibonacci(14))\\n'\n", - " '```\\n'\n", - " '\\n'\n", - " 'In this script, `fibonacci(n)` is a '\n", - " 'function that calculates the nth '\n", - " 'Fibonacci number. Inside the function, '\n", - " 'two variables `a` and `b` are '\n", - " 'initialised to `0` and `1` which are the '\n", - " 'first two numbers in the Fibonacci '\n", - " 'series. Then, a loop runs `n` times (14 '\n", - " 'times in your case), and in each '\n", - " 'iteration `a` is replaced with `b` and '\n", - " '`b` is replaced with `a + b`, which '\n", - " 'generates the next number in the '\n", - " 'series. \\n'\n", - " '\\n'\n", - " 'The function returns `a`, which is the '\n", - " 'nth Fibonacci number. The result is then '\n", - " 'printed to the console.',\n", - " 'role': 'user'},\n", - " {'content': 'exitcode: 0 (execution succeeded)\\n'\n", - " 'Code output: 377\\n',\n", - " 'role': 'assistant'},\n", - " {'content': 'Great! The script has successfully '\n", - " 'computed the 14th Fibonacci number as '\n", - " '377. If you need to compute other '\n", - " 'Fibonacci numbers, you can simply change '\n", - " 'the argument in the `fibonacci()` '\n", - " 'function call. Please let me know if you '\n", - " 'need help with anything else.',\n", - " 'role': 'user'},\n", - " {'content': '', 'role': 'assistant'}],\n", - " summary='',\n", - " cost=({'gpt-4-0613': {'completion_tokens': 302,\n", - " 'cost': 0.04842,\n", - " 'prompt_tokens': 1010,\n", - " 'total_tokens': 1312},\n", - " 'total_cost': 0.04842},\n", - " {'gpt-4-0613': {'completion_tokens': 302,\n", - " 'cost': 0.04842,\n", - " 'prompt_tokens': 1010,\n", - " 'total_tokens': 1312},\n", - " 'total_cost': 0.04842}),\n", - " human_input=[])\n" - ] - } - ], - "source": [ - "import pprint\n", - "\n", - "chat_result = code_executor_agent.initiate_chat(\n", - " code_writer_agent, message=\"Write Python code to calculate the 14th Fibonacci number.\"\n", - ")\n", - "\n", - "pprint.pprint(chat_result)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, stop the container. Or better yet use a context manager for it to be stopped automatically." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "executor.stop()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "autogen", - "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.11.8" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/website/docs/user-guide/advanced-concepts/code-execution/custom-executor.ipynb b/website/docs/user-guide/advanced-concepts/code-execution/custom-executor.ipynb deleted file mode 100644 index de835a2ec2..0000000000 --- a/website/docs/user-guide/advanced-concepts/code-execution/custom-executor.ipynb +++ /dev/null @@ -1,503 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Custom Code Executor\n", - "\n", - "In this guide we will show you how to create a custom code executor that runs\n", - "code inside the same Jupyter notebook as this one.\n", - "\n", - "First, let's install the required dependencies:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "! pip -qqq install pyautogen matplotlib yfinance" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "from typing import List\n", - "\n", - "from IPython import get_ipython\n", - "\n", - "from autogen import ConversableAgent\n", - "from autogen.coding import CodeBlock, CodeExecutor, CodeExtractor, CodeResult, MarkdownCodeExtractor" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can create the custom code executor class by subclassing the\n", - "`CodeExecutor` protocol and implementing the `execute_code_blocks` method." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "class NotebookExecutor(CodeExecutor):\n", - " @property\n", - " def code_extractor(self) -> CodeExtractor:\n", - " # Extract code from markdown blocks.\n", - " return MarkdownCodeExtractor()\n", - "\n", - " def __init__(self) -> None:\n", - " # Get the current IPython instance running in this notebook.\n", - " self._ipython = get_ipython()\n", - "\n", - " def execute_code_blocks(self, code_blocks: List[CodeBlock]) -> CodeResult:\n", - " log = \"\"\n", - " for code_block in code_blocks:\n", - " result = self._ipython.run_cell(\"%%capture --no-display cap\\n\" + code_block.code)\n", - " log += self._ipython.ev(\"cap.stdout\")\n", - " log += self._ipython.ev(\"cap.stderr\")\n", - " if result.result is not None:\n", - " log += str(result.result)\n", - " exitcode = 0 if result.success else 1\n", - " if result.error_before_exec is not None:\n", - " log += f\"\\n{result.error_before_exec}\"\n", - " exitcode = 1\n", - " if result.error_in_exec is not None:\n", - " log += f\"\\n{result.error_in_exec}\"\n", - " exitcode = 1\n", - " if exitcode != 0:\n", - " break\n", - " return CodeResult(exit_code=exitcode, output=log)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now we can use the new custom code executor in our agents." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], - "source": [ - "code_writer_agent = ConversableAgent(\n", - " name=\"CodeWriter\",\n", - " system_message=\"You are a helpful AI assistant.\\n\"\n", - " \"You use your coding skill to solve problems.\\n\"\n", - " \"You have access to a IPython kernel to execute Python code.\\n\"\n", - " \"You can suggest Python code in Markdown blocks, each block is a cell.\\n\"\n", - " \"The code blocks will be executed in the IPython kernel in the order you suggest them.\\n\"\n", - " \"All necessary libraries have already been installed.\\n\"\n", - " \"Once the task is done, returns 'TERMINATE'.\",\n", - " llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.getenv(\"OPENAI_API_KEY\")}]},\n", - ")\n", - "\n", - "code_executor_agent = ConversableAgent(\n", - " name=\"CodeExecutor\",\n", - " llm_config=False,\n", - " code_execution_config={\"executor\": NotebookExecutor()},\n", - " is_termination_msg=lambda msg: \"TERMINATE\" in msg.get(\"content\", \"\").strip().upper(),\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's use the agents to complete a simple task of drawing a plot showing\n", - "the market caps of the top 7 publicly listed companies." - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mCodeExecutor\u001b[0m (to CodeWriter):\n", - "\n", - "Create a plot showing the market caps of the top 7 publicly listed companies using data from Yahoo Finance.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mCodeWriter\u001b[0m (to CodeExecutor):\n", - "\n", - "To accomplish this task, we would use the `yfinance` library to fetch data from Yahoo Finance, `pandas` library for data manipulation, and `matplotlib` for data visualization.\n", - "\n", - "Steps:\n", - "1. Identify the tickers for the top 7 largest publicly listed companies. Currently, these companies are: Apple (AAPL), Microsoft (MSFT), Google (GOOGL), Amazon (AMZN), Facebook (FB), Tesla (TSLA), and Berkshire Hathaway (BRK-A).\n", - "2. Fetch market cap information for these companies using yfinance.\n", - "3. Clean and process the fetched data into a usable format (a pandas DataFrame).\n", - "4. Plot the market caps for these companies.\n", - "\n", - "Let's start by fetching data for these companies.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mCodeExecutor\u001b[0m (to CodeWriter):\n", - "\n", - "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mCodeWriter\u001b[0m (to CodeExecutor):\n", - "\n", - "Great! Before I continue, I need to know if the necessary libraries are installed.\n", - "\n", - "The libraries needed for this task are:\n", - "1. `yfinance`\n", - "2. `pandas`\n", - "3. `matplotlib`\n", - "\n", - "If these libraries are not installed, you can install them using pip:\n", - "\n", - "```python\n", - "!pip install yfinance pandas matplotlib\n", - "```\n", - "\n", - "Assuming these libraries are installed, we would import them and proceed with fetching the market cap data:\n", - "\n", - "```python\n", - "import yfinance as yf\n", - "import pandas as pd\n", - "import matplotlib.pyplot as plt\n", - "\n", - "# Define tickers \n", - "tickers = [\"AAPL\", \"MSFT\", \"GOOGL\", \"AMZN\", \"FB\", \"TSLA\", \"BRK-A\"]\n", - "\n", - "# Fetch data\n", - "data = yf.download(tickers, start=\"2022-02-01\", end=\"2022-02-28\")\n", - "\n", - "# Extract only 'Close' values for each ticker\n", - "data = data['Close']\n", - "\n", - "# Create empty dictionary to hold market cap data\n", - "market_caps = {}\n", - "\n", - "# Calculate market caps\n", - "for ticker in tickers:\n", - " info = yf.Ticker(ticker).info\n", - " market_caps[ticker] = info[\"marketCap\"]\n", - "\n", - "# Convert market_caps dictionary to pandas DataFrame\n", - "df = pd.DataFrame(list(market_caps.items()), columns=['Company', 'Market_Cap'])\n", - "\n", - "# Sort DataFrame by Market_Cap in descending order\n", - "df = df.sort_values('Market_Cap', ascending=False)\n", - "\n", - "# Plot data\n", - "plt.figure(figsize=(10,6))\n", - "plt.barh(df['Company'], df['Market_Cap'], color='skyblue')\n", - "plt.xlabel('Market Cap (in trillions)')\n", - "plt.title('Market Caps of Top 7 Publicly Listed Companies')\n", - "plt.gca().invert_yaxis()\n", - "plt.show()\n", - "```\n", - "\n", - "Please note that the start and end dates used while fetching data specifies the time period we are interested in. Feel free to modify these as needed. The 'marketCap' obtained from the 'info' property of the Ticker object represents the market cap as of the end date.\n", - "\n", - "Also note that the final plot shows the companies in descending order of market cap, with the company with the highest market cap at the top of the chart.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[31m\n", - ">>>>>>>> EXECUTING 2 CODE BLOCKS (inferred languages are [python, python])...\u001b[0m\n" - ] - }, - { - "ename": "KeyError", - "evalue": "'marketCap'", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[24], line 20\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m ticker \u001b[38;5;129;01min\u001b[39;00m tickers:\n\u001b[1;32m 19\u001b[0m info \u001b[38;5;241m=\u001b[39m yf\u001b[38;5;241m.\u001b[39mTicker(ticker)\u001b[38;5;241m.\u001b[39minfo\n\u001b[0;32m---> 20\u001b[0m market_caps[ticker] \u001b[38;5;241m=\u001b[39m \u001b[43minfo\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mmarketCap\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\n\u001b[1;32m 22\u001b[0m \u001b[38;5;66;03m# Convert market_caps dictionary to pandas DataFrame\u001b[39;00m\n\u001b[1;32m 23\u001b[0m df \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mDataFrame(\u001b[38;5;28mlist\u001b[39m(market_caps\u001b[38;5;241m.\u001b[39mitems()), columns\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCompany\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mMarket_Cap\u001b[39m\u001b[38;5;124m'\u001b[39m])\n", - "\u001b[0;31mKeyError\u001b[0m: 'marketCap'" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mCodeExecutor\u001b[0m (to CodeWriter):\n", - "\n", - "exitcode: 0 (execution succeeded)\n", - "Code output: Requirement already satisfied: yfinance in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (0.2.36)\n", - "Requirement already satisfied: pandas in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (2.2.1)\n", - "Requirement already satisfied: matplotlib in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (3.9.3)\n", - "Requirement already satisfied: numpy>=1.16.5 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from yfinance) (1.26.4)\n", - "Requirement already satisfied: requests>=2.31 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from yfinance) (2.31.0)\n", - "Requirement already satisfied: multitasking>=0.0.7 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from yfinance) (0.0.11)\n", - "Requirement already satisfied: lxml>=4.9.1 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from yfinance) (5.0.1)\n", - "Requirement already satisfied: appdirs>=1.4.4 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from yfinance) (1.4.4)\n", - "Requirement already satisfied: pytz>=2022.5 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from yfinance) (2023.3.post1)\n", - "Requirement already satisfied: frozendict>=2.3.4 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from yfinance) (2.4.0)\n", - "Requirement already satisfied: peewee>=3.16.2 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from yfinance) (3.17.0)\n", - "Requirement already satisfied: beautifulsoup4>=4.11.1 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from yfinance) (4.12.2)\n", - "Requirement already satisfied: html5lib>=1.1 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from yfinance) (1.1)\n", - "Requirement already satisfied: python-dateutil>=2.8.2 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from pandas) (2.8.2)\n", - "Requirement already satisfied: tzdata>=2022.7 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from pandas) (2023.4)\n", - "Requirement already satisfied: contourpy>=1.0.1 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from matplotlib) (1.2.0)\n", - "Requirement already satisfied: cycler>=0.10 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from matplotlib) (0.12.1)\n", - "Requirement already satisfied: fonttools>=4.22.0 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from matplotlib) (4.47.2)\n", - "Requirement already satisfied: kiwisolver>=1.3.1 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from matplotlib) (1.4.5)\n", - "Requirement already satisfied: packaging>=20.0 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from matplotlib) (23.2)\n", - "Requirement already satisfied: pillow>=8 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from matplotlib) (10.2.0)\n", - "Requirement already satisfied: pyparsing>=2.3.1 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from matplotlib) (3.1.1)\n", - "Requirement already satisfied: soupsieve>1.2 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from beautifulsoup4>=4.11.1->yfinance) (2.5)\n", - "Requirement already satisfied: six>=1.9 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from html5lib>=1.1->yfinance) (1.16.0)\n", - "Requirement already satisfied: webencodings in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from html5lib>=1.1->yfinance) (0.5.1)\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from requests>=2.31->yfinance) (3.3.2)\n", - "Requirement already satisfied: idna<4,>=2.5 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from requests>=2.31->yfinance) (3.6)\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from requests>=2.31->yfinance) (1.26.18)\n", - "Requirement already satisfied: certifi>=2017.4.17 in /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages (from requests>=2.31->yfinance) (2024.2.2)\n", - "/Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.\n", - " df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')\n", - "/Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.\n", - " df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')\n", - "[************** 29%% ] 2 of 7 completed/Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.\n", - " df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')\n", - "[********************* 43%% ] 3 of 7 completed/Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.\n", - " df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')\n", - "[**********************57%%* ] 4 of 7 completed/Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.\n", - " df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')\n", - "[**********************71%%******** ] 5 of 7 completed/Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.\n", - " df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')\n", - "[*********************100%%**********************] 7 of 7 completed\n", - "\n", - "1 Failed download:\n", - "['FB']: Exception('%ticker%: No timezone found, symbol may be delisted')\n", - "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mCodeWriter\u001b[0m (to CodeExecutor):\n", - "\n", - "From the error message, it seems that the 'FB' ticker (Facebook) failed to download because it might have been delisted. This is likely due to Facebook's corporate rebranding to Meta Platforms Inc. in late 2021, which resulted in a ticker change from 'FB' to 'META'.\n", - "\n", - "To resolve this, we'll replace 'FB' in our tickers list with 'META' and then retrieve the data again. Here is the modified code:\n", - "\n", - "```python\n", - "# Define tickers \n", - "tickers = [\"AAPL\", \"MSFT\", \"GOOGL\", \"AMZN\", \"META\", \"TSLA\", \"BRK-A\"]\n", - "\n", - "# Fetch data\n", - "data = yf.download(tickers, start=\"2022-02-01\", end=\"2022-02-28\")\n", - "\n", - "# Extract only 'Close' values for each ticker\n", - "data = data['Close']\n", - "\n", - "# Create empty dictionary to hold market cap data\n", - "market_caps = {}\n", - "\n", - "# Calculate market caps\n", - "for ticker in tickers:\n", - " info = yf.Ticker(ticker).info\n", - " market_caps[ticker] = info[\"marketCap\"]\n", - "\n", - "# Convert market_caps dictionary to pandas DataFrame\n", - "df = pd.DataFrame(list(market_caps.items()), columns=['Company', 'Market_Cap'])\n", - "\n", - "# Sort DataFrame by Market_Cap in descending order\n", - "df = df.sort_values('Market_Cap', ascending=False)\n", - "\n", - "# Plot data\n", - "plt.figure(figsize=(10,6))\n", - "plt.barh(df['Company'], df['Market_Cap'], color='skyblue')\n", - "plt.xlabel('Market Cap (in trillions)')\n", - "plt.title('Market Caps of Top 7 Publicly Listed Companies')\n", - "plt.gca().invert_yaxis()\n", - "plt.show()\n", - "```\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[31m\n", - ">>>>>>>> EXECUTING CODE BLOCK (inferred language is python)...\u001b[0m\n" - ] - }, - { - "data": { - "image/png": "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r7Zt23L/FnAH9FwBSFOZMmVUr149LVy4UE8++aSkmx/IsbGxCg0N1fvvv59qnalTp+qpp55St27dlJiYqKioKHXs2FGrVq1SSEiIQ9v169dr8eLFGjRokHx8fNIMPklJSerTp48WLVqkFStW2Lfxzjvv6PXXX1enTp3Ut29f/f3335o2bZoaNWqkXbt2ydvbW//v//0/xcbGOlzO5unpme7xfv3117px44a6d++eqefn559/1g8//KDQ0FCVLFlSx44d04wZM9SkSRPt27dPBQsWdGg/aNAgeXt7a+zYsTpw4IBmzJihmJgY+x+yZ8+eVYsWLeTr66uRI0fK29tbx44dcwiU6Rk7dqzGjRunZs2aacCAAfbt//zzz9q6datcXFw0ZcoUffrpp1qxYoX9Mrnbe4Uy6+rVq2rSpIkOHTqkQYMGqWzZslqyZIl69eqlixcvOvwBK0mffvqpLl26pIEDB+ratWuaOnWqHn/8ce3evVvFixfP0r7nz5+vgIAANWrUKFu1SzfvyZGkokWLZmv9d955RxaLRa+++qrOnj2rKVOmqFmzZoqOjpa7u3umt/PXX3+pdu3aunjxovr376/KlSvrzz//1NKlSxUfH59mz1z37t315ptvatGiRRo0aJB9fsoXHx06dDC91ykxMVEtW7ZUQkKCBg8eLD8/P/35559atWqVLl68KC8vL82bN099+/ZV7dq11b9/f0lS+fLlJUlnzpxR3bp17YHA19dXX3/9tZ599lnFxcXZv8y4evWqnnjiCR0/flxDhgxRiRIlNG/ePK1fvz5TdX755ZcqV66cHnvssUy179u3r+bOnatnnnlGI0aM0E8//aTw8HDt379fK1ascGh76NAhde3aVc8995zCwsI0YcIEtWnTRh999JFGjx6tF154QZIUHh6uTp066cCBAypQ4H/fXyclJSk4OFh169bVe++9pzVr1mjMmDG6ceOG3nzzTXu7rLyHbtmyRcuXL9cLL7ygQoUK6f3331eHDh10/PjxDH+3582bp549e6ply5Z69913FR8frxkzZqhBgwbatWuX/b24Q4cO2rt3rwYPHqwyZcro7Nmz+uabb3T8+PEMv6gC7nsGANwiMjLSkGT8/PPPxgcffGAUKlTIiI+PNwzDMDp27Gg0bdrUMAzDKF26tBESEuKwbkq7FImJiUb16tWNxx9/3GG+JKNAgQLG3r17HeYfPXrUkGT897//Na5fv2507tzZcHd3N9auXWtvc+zYMcPJycl45513HNbdvXu34ezs7DA/JCTEKF26dKaO+8UXXzQkGbt27cpU+9uP1TAM48cffzQkGZ9++ql9XsrzWbNmTSMxMdE+/7333jMkGZ9//rlhGIaxYsUK+/OeFWfPnjVcXV2NFi1aGElJSfb5H3zwgSHJmD17tn3emDFjDEnG33//naV93P48TpkyxZBkfPbZZ/Z5iYmJRr169QxPT08jLi7OMIz/nU93d3fj5MmT9rY//fSTIcl48cUXs1THnj17DEnGK6+8kqn2Kcd74MAB4++//zaOHj1qzJw507BarUbx4sWNK1euGIZx83e5Z8+eqdZv3Lix0bhxY/vjDRs2GJKMBx54wH6MhmEYixcvNiQZU6dOtc/r2bNnqt89ScaYMWPsj3v06GEUKFAgzXOenJzssM8NGzbYl9WrV8+oU6eOQ/vly5enapfRc5LR78Dt+9y1a5chyViyZEmG2/bw8EjzeXz22WcNf39/49y5cw7zQ0NDDS8vL/trKeX3avHixfY2V65cMQIDA+94bLGxsYYko23bthnWmCI6OtqQZPTt29dh/ksvvWRIMtavX2+fV7p0aUOS8cMPP9jnrV271v67HRMTY58/c+bMVLX27NnTkGQMHjzYPi85OdkICQkxXF1dHc5FVt5DXV1djUOHDtnn/frrr4YkY9q0afZ5Ke8/R48eNQzDMC5dumR4e3sb/fr1c9je6dOnDS8vL/v8Cxcu2N+LAWQNlwUCSFenTp109epVrVq1SpcuXdKqVavSvSRQksO39hcuXFBsbKwaNmyonTt3pmrbuHFjVa1aNc3tJCYm2r+t/eqrr9SiRQv7suXLlys5OVmdOnXSuXPn7JOfn58qVKigDRs2ZOtYU0aPK1SoUKba33qs169f1/nz5xUYGChvb+80j7d///5ycXGxPx4wYICcnZ311VdfSfrffVCrVq3S9evXM133t99+q8TERA0bNszhm/J+/frJZrPlyD0mX331lfz8/NSlSxf7PBcXFw0ZMkSXL1/Wpk2bHNq3a9dODzzwgP1x7dq1VadOHfuxZ9b8+fMlKcuXBFaqVEm+vr4qW7asnnvuOQUGBmr16tWpehczq0ePHg6/J88884z8/f2zdDzJyclauXKl2rRpo0cffTTV8owG2ujRo4d++uknew+c9L8evcaNG2e6hszy8vKSJK1du1bx8fFZWtcwDC1btkxt2rSRYRgOr9mWLVsqNjbW/nr56quv5O/vr2eeeca+fsGCBe09YRnJ6us35VwNHz7cYf6IESMkKdXrpmrVqg7359WpU0fSzUtMS5UqlWr+kSNHUu3z1p7GlF68xMREffvtt/b5WXkPbdasmb13ULp5j6LNZktz3ym++eYbXbx4UV26dHE4F05OTqpTp479/dPd3V2urq7auHFjqsuXAWSMywIBpMvX11fNmjXTggULFB8fr6SkJIc/fG63atUqvf3224qOjna4byGtPxTLli2b7nbCw8N1+fJlff3116nueTl48KAMw1CFChXSXPfWAJMVNptNknTp0qVMtb969arCw8MVGRmpP//80+HeiZT7UG51e72enp7y9/e337/QuHFjdejQQePGjdPkyZPVpEkTtWvXTl27ds1wpK+YmBhJNwPErVxdXVWuXDn7cjPFxMSoQoUKDmFOkqpUqeJQU4q0zlXFihW1ePHiTO/TMAwtWLBA1atXz/LljMuWLZPNZpOLi4tKlizp8Adpdtx+PBaLRYGBgVm6F+Xvv/9WXFycqlevnuX9d+7cWcOGDdP8+fP1xhtvKDY2VqtWrdKLL76YI6Mfli1bVsOHD9ekSZM0f/58NWzYUE899ZTCwsLswSs9f//9ty5evKhZs2alO0pfykArMTExCgwMTHUMt/9upyWrr9+YmBgVKFAg1WiUfn5+8vb2TvU7fGuAkv4XOAMCAtKcf3sgKVCggMqVK+cwr2LFipLk8HuTlffQ22uSpMKFC2cYhg4ePCjpf/cd3i7lebRarXr33Xc1YsQIFS9eXHXr1lXr1q3Vo0cP+fn5pbt9AIQrAHfQtWtX9evXT6dPn9aTTz6Z7khz33//vZ566ik1atRI06dPl7+/v1xcXBQZGakFCxakap/RvSktW7bUmjVr9N5776lJkyYO95AkJyfLYrHo66+/TnMUrIzuq8pI5cqVJUm7d+/Www8/fMf2gwcPVmRkpIYNG6Z69erJy8tLFotFoaGhSk5OzvL+U/457bZt2/Tll19q7dq16tOnjyZOnKht27Zl+7juFVu3blVMTIzCw8OzvG6jRo3sowWmJb1AkpSUlC9HWitcuLBat25tD1dLly5VQkJCjo7mOHHiRPXq1Uuff/651q1bpyFDhig8PFzbtm3L8F8TpLwWwsLC1LNnzzTbZPfev1vZbDaVKFEiywOlZDaMpvd7kN5847aBKjIjq++h2dl3yvmYN29emiHp1pFhhw0bpjZt2mjlypVau3atXn/9dYWHh2v9+vUKCgrK6uEB9w3CFYAMtW/fXs8995y2bdumRYsWpdtu2bJlcnNz09q1ax16WiIjI7O8z7p16+r5559X69at1bFjR61YscL+oV++fHkZhqGyZcvav/lNT1a+xX/yySfl5OSkzz77LFODWixdulQ9e/bUxIkT7fOuXbvmMELfrQ4ePKimTZvaH1++fFmnTp1Sq1atHNrVrVtXdevW1TvvvKMFCxaoW7duioqKUt++fdPcbunSpSVJBw4ccPhmPDExUUePHlWzZs3ueCxZVbp0af32229KTk526L36/fffHWpKkfJt+a3++OOPLN0UP3/+fFkslgwvS82uwoULp3neYmJiUvU2SKmPxzAMHTp0KEshwdfXVzabLdujJvbo0UNt27bVzz//rPnz5ysoKEjVqlXL1rYyq0aNGqpRo4Zee+01/fDDD6pfv74++ugjvf3225LSfr35+vqqUKFCSkpKuuPvYunSpbVnzx4ZhuGwrQMHDmSqvtatW2vWrFn68ccf7zjEfunSpZWcnKyDBw/ae1ylm4NvXLx4MdXv8N1KTk7WkSNHHN6z/vjjD0myvw7MfA9NT0qvbbFixTL13lC+fHmNGDFCI0aM0MGDB/Xwww9r4sSJ+uyzz0yrCbjXcM8VgAx5enpqxowZGjt2rNq0aZNuOycnJ1ksFiUlJdnnHTt2TCtXrszWfps1a6aoqCitWbNG3bt3t3/j+vTTT8vJyUnjxo1L9Q2tYRg6f/68/bGHh0eal+ilJSAgQP369dO6des0bdq0VMuTk5Pt/0xXunm8t+9/2rRpDsd/q1mzZjncSzVjxgzduHHDPhLjhQsXUm0vpQcto6GomzVrJldXV73//vsO60dERCg2NjbVCGNmaNWqlU6fPu0Qtm/cuKFp06bJ09Mz1X0/K1eu1J9//ml/vH37dv3000/2Y7+T69eva8mSJWrQoEGal0LdrfLly2vbtm0Ow5+vWrUq3eHVU0Y/TLF06VKdOnUq08cj3bxMrF27dvryyy+1Y8eOVMvv1PPx5JNPysfHR++++642bdqUo71WcXFxunHjhsO8GjVqqECBAg6/mx4eHqlCqpOTkzp06KBly5alGSRvHVK+VatW+uuvvxyGHo+Pj8/0P/195ZVX5OHhob59++rMmTOplh8+fFhTp06170uSpkyZ4tBm0qRJkpQjr5sPPvjA/rNhGPrggw/k4uKiJ554QpL576FpadmypWw2m8aPH5/mvZ0p5yM+Pj7VkP7ly5dXoUKFMj00PnC/oucKwB2ldznPrUJCQjRp0iQFBwera9euOnv2rD788EMFBgbqt99+y9Z+27Vrp8jISPXo0UM2m00zZ85U+fLl9fbbb2vUqFE6duyY2rVrp0KFCuno0aNasWKF+vfvr5deekmSVLNmTS1atEjDhw9XrVq15OnpmWFAnDhxog4fPqwhQ4Zo+fLlat26tQoXLqzjx49ryZIl+v333xUaGirp5rfk8+bNk5eXl6pWraoff/xR3377bbpDICcmJuqJJ56wD9M8ffp0NWjQQE899ZQkae7cuZo+fbrat2+v8uXL69KlS/r4449ls9lS9W7dytfXV6NGjdK4ceMUHBysp556yr79WrVq5cgf3f3799fMmTPVq1cv/fLLLypTpoyWLl2qrVu3asqUKakGFQgMDFSDBg00YMAAJSQkaMqUKSpatKheeeWVTO1v7dq1On/+/F39b6uM9O3bV0uXLlVwcLA6deqkw4cP67PPPkv33qwiRYqoQYMG6t27t86cOaMpU6YoMDBQ/fr1y9J+x48fr3Xr1qlx48bq37+/qlSpolOnTmnJkiXasmVLhv/s2cXFRaGhofrggw/k5OTkMLhIZkyaNCnVgB4FChTQ6NGjU7Vdv369Bg0apI4dO6pixYq6ceOG5s2bZw9OKWrWrKlvv/1WkyZNUokSJVS2bFnVqVNH//nPf7RhwwbVqVNH/fr1U9WqVfXPP/9o586d+vbbb/XPP/9IujkIywcffKAePXrol19+kb+/v+bNm5fpgUfKly+vBQsWqHPnzqpSpYp69Oih6tWrKzExUT/88IP93wVI0kMPPaSePXtq1qxZunjxoho3bqzt27dr7ty5ateunUMvsxnc3Ny0Zs0a9ezZU3Xq1NHXX3+t1atXa/To0fL19ZWUM++ht7PZbJoxY4a6d++uRx55RKGhofL19dXx48e1evVq1a9fXx988IH++OMP+/tV1apV5ezsrBUrVujMmTP290AA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tWrVVKJECa1YsSJTNQJAdhw/flyRkZFasmSJGjZsqPLly+ull15SgwYNHN6TsmrChAm6fPmyOnXqlKX1CFcAcJ/o06ePwwfN7Nmz1bt371Ttrly5ouHDh2vHjh367rvvVKBAAbVv317JyckO7UaOHKmhQ4dq//799j/4U5w4cUINGzZU9erVtXTpUlmtVoWHh+vTTz/VRx99pL179+rFF19UWFiYNm3apICAAC1btkySdODAAZ06dUpTp05N8zjmz5+vSpUqqW3btqmWWSwW+6V5ly5dUs+ePbVlyxZt27ZNFSpUUKtWrXTp0iWHdV5//XV16NBBv/76q7p166bQ0FDt378/3efx+++/V82aNdNdniI+Pl4TJkzQvHnztHnzZh0/flwvvfRSmm3vdPxz586Vq6urtm7dqo8++uiO+76TFStWaOjQoRoxYoT27Nmj5557Tr1799aGDRsc2o0bN06dOnXSb7/9platWqlbt272nqjXX39d+/bt09dff639+/drxowZ8vHxcVi/du3a+v777++6XgBIz+7du5WUlKSKFSvK09PTPm3atMnhi8GsWLBggcaNG6fFixdnudffOVt7BAD864SFhWnUqFGKiYmRJG3dulVRUVEO16VLUocOHRwez549W76+vtq3b5+qV69unz9s2DA9/fTTqfZz4MABNW/eXO3bt9eUKVNksViUkJCg8ePH69tvv1W9evUkSeXKldOWLVs0c+ZMNW7c2H7pRbFixTIcfOHgwYOqVKnSHY/38ccfd3g8a9YseXt7a9OmTWrdurV9fseOHdW3b19J0ltvvaVvvvlG06ZN0/Tp09PcbkxMjEqUKHHH/V+/fl0fffSRypcvL+nmZStvvvlmmm2dnJwyPP4KFSrovffeu+M+M2vChAnq1auXXnjhBUnS8OHDtW3bNk2YMMHegybdvF+vS5cukqTx48fr/fff1/bt2xUcHKzjx48rKChIjz76qCTZ7z+7VYkSJbJ8MzgAZMXly5fl5OSkX375RU5OTg7LPD09s7y9qKgo9e3bV0uWLEl38IuMEK4A4D7h6+urkJAQzZkzR4ZhKCQkJFVPg3QzvLzxxhv66aefdO7cOXuP1fHjxx3CVcof1be6evWqGjZsqK5du2rKlCn2+YcOHVJ8fLyaN2/u0D4xMTHVZYl3YhhGptqdOXNGr732mjZu3Kiz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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mCodeExecutor\u001b[0m (to CodeWriter):\n", - "\n", - "exitcode: 0 (execution succeeded)\n", - "Code output: /Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.\n", - " df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')\n", - "/Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.\n", - " df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')\n", - "[ 0%% ]/Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.\n", - " df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')\n", - "/Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.\n", - " df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')\n", - "[********************* 43%% ] 3 of 7 completed/Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.\n", - " df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')\n", - "[**********************57%%* ] 4 of 7 completed/Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.\n", - " df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')\n", - "[**********************71%%******** ] 5 of 7 completed/Users/ekzhu/miniconda3/envs/autogen/lib/python3.11/site-packages/yfinance/utils.py:775: FutureWarning: The 'unit' keyword in TimedeltaIndex construction is deprecated and will be removed in a future version. Use pd.to_timedelta instead.\n", - " df.index += _pd.TimedeltaIndex(dst_error_hours, 'h')\n", - "[*********************100%%**********************] 7 of 7 completed\n", - "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mCodeWriter\u001b[0m (to CodeExecutor):\n", - "\n", - "I see that the fetched data was successfully retrieved and processed. However, it looks like the result of the plot isn't visible, so we don't know whether the plot was generated successfully. Please run the code again and provide the output of the plot.\n", - "\n", - "If there are any issues or any other points you would like me to help with, let me know!\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mCodeExecutor\u001b[0m (to CodeWriter):\n", - "\n", - "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mCodeWriter\u001b[0m (to CodeExecutor):\n", - "\n", - "I'm glad we were able to retrieve and process the data successfully. Please try running the last part of the code again to generate and display the plot:\n", - "\n", - "```python\n", - "# Plot data\n", - "plt.figure(figsize=(10,6))\n", - "plt.barh(df['Company'], df['Market_Cap'], color='skyblue')\n", - "plt.xlabel('Market Cap (in trillions)')\n", - "plt.title('Market Caps of Top 7 Publicly Listed Companies')\n", - "plt.gca().invert_yaxis()\n", - "plt.show()\n", - "```\n", - "\n", - "This section of the code creates a horizontal bar plot of the market capitalizations of the companies. The `plt.gca().invert_yaxis()` line is included to invert the y-axis, so the company with the highest market cap is at the top of the chart.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[31m\n", - ">>>>>>>> EXECUTING CODE BLOCK (inferred language is python)...\u001b[0m\n" - ] - }, - { - "data": { - "image/png": "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r7Zt23L/FnAH9FwBSFOZMmVUr149LVy4UE8++aSkmx/IsbGxCg0N1fvvv59qnalTp+qpp55St27dlJiYqKioKHXs2FGrVq1SSEiIQ9v169dr8eLFGjRokHx8fNIMPklJSerTp48WLVqkFStW2Lfxzjvv6PXXX1enTp3Ut29f/f3335o2bZoaNWqkXbt2ydvbW//v//0/xcbGOlzO5unpme7xfv3117px44a6d++eqefn559/1g8//KDQ0FCVLFlSx44d04wZM9SkSRPt27dPBQsWdGg/aNAgeXt7a+zYsTpw4IBmzJihmJgY+x+yZ8+eVYsWLeTr66uRI0fK29tbx44dcwiU6Rk7dqzGjRunZs2aacCAAfbt//zzz9q6datcXFw0ZcoUffrpp1qxYoX9Mrnbe4Uy6+rVq2rSpIkOHTqkQYMGqWzZslqyZIl69eqlixcvOvwBK0mffvqpLl26pIEDB+ratWuaOnWqHn/8ce3evVvFixfP0r7nz5+vgIAANWrUKFu1SzfvyZGkokWLZmv9d955RxaLRa+++qrOnj2rKVOmqFmzZoqOjpa7u3umt/PXX3+pdu3aunjxovr376/KlSvrzz//1NKlSxUfH59mz1z37t315ptvatGiRRo0aJB9fsoXHx06dDC91ykxMVEtW7ZUQkKCBg8eLD8/P/35559atWqVLl68KC8vL82bN099+/ZV7dq11b9/f0lS+fLlJUlnzpxR3bp17YHA19dXX3/9tZ599lnFxcXZv8y4evWqnnjiCR0/flxDhgxRiRIlNG/ePK1fvz5TdX755ZcqV66cHnvssUy179u3r+bOnatnnnlGI0aM0E8//aTw8HDt379fK1ascGh76NAhde3aVc8995zCwsI0YcIEtWnTRh999JFGjx6tF154QZIUHh6uTp066cCBAypQ4H/fXyclJSk4OFh169bVe++9pzVr1mjMmDG6ceOG3nzzTXu7rLyHbtmyRcuXL9cLL7ygQoUK6f3331eHDh10/PjxDH+3582bp549e6ply5Z69913FR8frxkzZqhBgwbatWuX/b24Q4cO2rt3rwYPHqwyZcro7Nmz+uabb3T8+PEMv6gC7nsGANwiMjLSkGT8/PPPxgcffGAUKlTIiI+PNwzDMDp27Gg0bdrUMAzDKF26tBESEuKwbkq7FImJiUb16tWNxx9/3GG+JKNAgQLG3r17HeYfPXrUkGT897//Na5fv2507tzZcHd3N9auXWtvc+zYMcPJycl45513HNbdvXu34ezs7DA/JCTEKF26dKaO+8UXXzQkGbt27cpU+9uP1TAM48cffzQkGZ9++ql9XsrzWbNmTSMxMdE+/7333jMkGZ9//rlhGIaxYsUK+/OeFWfPnjVcXV2NFi1aGElJSfb5H3zwgSHJmD17tn3emDFjDEnG33//naV93P48TpkyxZBkfPbZZ/Z5iYmJRr169QxPT08jLi7OMIz/nU93d3fj5MmT9rY//fSTIcl48cUXs1THnj17DEnGK6+8kqn2Kcd74MAB4++//zaOHj1qzJw507BarUbx4sWNK1euGIZx83e5Z8+eqdZv3Lix0bhxY/vjDRs2GJKMBx54wH6MhmEYixcvNiQZU6dOtc/r2bNnqt89ScaYMWPsj3v06GEUKFAgzXOenJzssM8NGzbYl9WrV8+oU6eOQ/vly5enapfRc5LR78Dt+9y1a5chyViyZEmG2/bw8EjzeXz22WcNf39/49y5cw7zQ0NDDS8vL/trKeX3avHixfY2V65cMQIDA+94bLGxsYYko23bthnWmCI6OtqQZPTt29dh/ksvvWRIMtavX2+fV7p0aUOS8cMPP9jnrV271v67HRMTY58/c+bMVLX27NnTkGQMHjzYPi85OdkICQkxXF1dHc5FVt5DXV1djUOHDtnn/frrr4YkY9q0afZ5Ke8/R48eNQzDMC5dumR4e3sb/fr1c9je6dOnDS8vL/v8Cxcu2N+LAWQNlwUCSFenTp109epVrVq1SpcuXdKqVavSvSRQksO39hcuXFBsbKwaNmyonTt3pmrbuHFjVa1aNc3tJCYm2r+t/eqrr9SiRQv7suXLlys5OVmdOnXSuXPn7JOfn58qVKigDRs2ZOtYU0aPK1SoUKba33qs169f1/nz5xUYGChvb+80j7d///5ycXGxPx4wYICcnZ311VdfSfrffVCrVq3S9evXM133t99+q8TERA0bNszhm/J+/frJZrPlyD0mX331lfz8/NSlSxf7PBcXFw0ZMkSXL1/Wpk2bHNq3a9dODzzwgP1x7dq1VadOHfuxZ9b8+fMlKcuXBFaqVEm+vr4qW7asnnvuOQUGBmr16tWpehczq0ePHg6/J88884z8/f2zdDzJyclauXKl2rRpo0cffTTV8owG2ujRo4d++uknew+c9L8evcaNG2e6hszy8vKSJK1du1bx8fFZWtcwDC1btkxt2rSRYRgOr9mWLVsqNjbW/nr56quv5O/vr2eeeca+fsGCBe09YRnJ6us35VwNHz7cYf6IESMkKdXrpmrVqg7359WpU0fSzUtMS5UqlWr+kSNHUu3z1p7GlF68xMREffvtt/b5WXkPbdasmb13ULp5j6LNZktz3ym++eYbXbx4UV26dHE4F05OTqpTp479/dPd3V2urq7auHFjqsuXAWSMywIBpMvX11fNmjXTggULFB8fr6SkJIc/fG63atUqvf3224qOjna4byGtPxTLli2b7nbCw8N1+fJlff3116nueTl48KAMw1CFChXSXPfWAJMVNptNknTp0qVMtb969arCw8MVGRmpP//80+HeiZT7UG51e72enp7y9/e337/QuHFjdejQQePGjdPkyZPVpEkTtWvXTl27ds1wpK+YmBhJNwPErVxdXVWuXDn7cjPFxMSoQoUKDmFOkqpUqeJQU4q0zlXFihW1ePHiTO/TMAwtWLBA1atXz/LljMuWLZPNZpOLi4tKlizp8Adpdtx+PBaLRYGBgVm6F+Xvv/9WXFycqlevnuX9d+7cWcOGDdP8+fP1xhtvKDY2VqtWrdKLL76YI6Mfli1bVsOHD9ekSZM0f/58NWzYUE899ZTCwsLswSs9f//9ty5evKhZs2alO0pfykArMTExCgwMTHUMt/9upyWrr9+YmBgVKFAg1WiUfn5+8vb2TvU7fGuAkv4XOAMCAtKcf3sgKVCggMqVK+cwr2LFipLk8HuTlffQ22uSpMKFC2cYhg4ePCjpf/cd3i7lebRarXr33Xc1YsQIFS9eXHXr1lXr1q3Vo0cP+fn5pbt9AIQrAHfQtWtX9evXT6dPn9aTTz6Z7khz33//vZ566ik1atRI06dPl7+/v1xcXBQZGakFCxakap/RvSktW7bUmjVr9N5776lJkyYO95AkJyfLYrHo66+/TnMUrIzuq8pI5cqVJUm7d+/Www8/fMf2gwcPVmRkpIYNG6Z69erJy8tLFotFoaGhSk5OzvL+U/457bZt2/Tll19q7dq16tOnjyZOnKht27Zl+7juFVu3blVMTIzCw8OzvG6jRo3sowWmJb1AkpSUlC9HWitcuLBat25tD1dLly5VQkJCjo7mOHHiRPXq1Uuff/651q1bpyFDhig8PFzbtm3L8F8TpLwWwsLC1LNnzzTbZPfev1vZbDaVKFEiywOlZDaMpvd7kN5847aBKjIjq++h2dl3yvmYN29emiHp1pFhhw0bpjZt2mjlypVau3atXn/9dYWHh2v9+vUKCgrK6uEB9w3CFYAMtW/fXs8995y2bdumRYsWpdtu2bJlcnNz09q1ax16WiIjI7O8z7p16+r5559X69at1bFjR61YscL+oV++fHkZhqGyZcvav/lNT1a+xX/yySfl5OSkzz77LFODWixdulQ9e/bUxIkT7fOuXbvmMELfrQ4ePKimTZvaH1++fFmnTp1Sq1atHNrVrVtXdevW1TvvvKMFCxaoW7duioqKUt++fdPcbunSpSVJBw4ccPhmPDExUUePHlWzZs3ueCxZVbp0af32229KTk526L36/fffHWpKkfJt+a3++OOPLN0UP3/+fFkslgwvS82uwoULp3neYmJiUvU2SKmPxzAMHTp0KEshwdfXVzabLdujJvbo0UNt27bVzz//rPnz5ysoKEjVqlXL1rYyq0aNGqpRo4Zee+01/fDDD6pfv74++ugjvf3225LSfr35+vqqUKFCSkpKuuPvYunSpbVnzx4ZhuGwrQMHDmSqvtatW2vWrFn68ccf7zjEfunSpZWcnKyDBw/ae1ylm4NvXLx4MdXv8N1KTk7WkSNHHN6z/vjjD0myvw7MfA9NT0qvbbFixTL13lC+fHmNGDFCI0aM0MGDB/Xwww9r4sSJ+uyzz0yrCbjXcM8VgAx5enpqxowZGjt2rNq0aZNuOycnJ1ksFiUlJdnnHTt2TCtXrszWfps1a6aoqCitWbNG3bt3t3/j+vTTT8vJyUnjxo1L9Q2tYRg6f/68/bGHh0eal+ilJSAgQP369dO6des0bdq0VMuTk5Pt/0xXunm8t+9/2rRpDsd/q1mzZjncSzVjxgzduHHDPhLjhQsXUm0vpQcto6GomzVrJldXV73//vsO60dERCg2NjbVCGNmaNWqlU6fPu0Qtm/cuKFp06bJ09Mz1X0/K1eu1J9//ml/vH37dv3000/2Y7+T69eva8mSJWrQoEGal0LdrfLly2vbtm0Ow5+vWrUq3eHVU0Y/TLF06VKdOnUq08cj3bxMrF27dvryyy+1Y8eOVMvv1PPx5JNPysfHR++++642bdqUo71WcXFxunHjhsO8GjVqqECBAg6/mx4eHqlCqpOTkzp06KBly5alGSRvHVK+VatW+uuvvxyGHo+Pj8/0P/195ZVX5OHhob59++rMmTOplh8+fFhTp06170uSpkyZ4tBm0qRJkpQjr5sPPvjA/rNhGPrggw/k4uKiJ554QpL576FpadmypWw2m8aPH5/mvZ0p5yM+Pj7VkP7ly5dXoUKFMj00PnC/oucKwB2ldznPrUJCQjRp0iQFBwera9euOnv2rD788EMFBgbqt99+y9Z+27Vrp8jISPXo0UM2m00zZ85U+fLl9fbbb2vUqFE6duyY2rVrp0KFCuno0aNasWKF+vfvr5deekmSVLNmTS1atEjDhw9XrVq15OnpmWFAnDhxog4fPqwhQ4Zo+fLlat26tQoXLqzjx49ryZIl+v333xUaGirp5rfk8+bNk5eXl6pWraoff/xR3377bbpDICcmJuqJJ56wD9M8ffp0NWjQQE899ZQkae7cuZo+fbrat2+v8uXL69KlS/r4449ls9lS9W7dytfXV6NGjdK4ceMUHBysp556yr79WrVq5cgf3f3799fMmTPVq1cv/fLLLypTpoyWLl2qrVu3asqUKakGFQgMDFSDBg00YMAAJSQkaMqUKSpatKheeeWVTO1v7dq1On/+/F39b6uM9O3bV0uXLlVwcLA6deqkw4cP67PPPkv33qwiRYqoQYMG6t27t86cOaMpU6YoMDBQ/fr1y9J+x48fr3Xr1qlx48bq37+/qlSpolOnTmnJkiXasmVLhv/s2cXFRaGhofrggw/k5OTkMLhIZkyaNCnVgB4FChTQ6NGjU7Vdv369Bg0apI4dO6pixYq6ceOG5s2bZw9OKWrWrKlvv/1WkyZNUokSJVS2bFnVqVNH//nPf7RhwwbVqVNH/fr1U9WqVfXPP/9o586d+vbbb/XPP/9IujkIywcffKAePXrol19+kb+/v+bNm5fpgUfKly+vBQsWqHPnzqpSpYp69Oih6tWrKzExUT/88IP93wVI0kMPPaSePXtq1qxZunjxoho3bqzt27dr7ty5ateunUMvsxnc3Ny0Zs0a9ezZU3Xq1NHXX3+t1atXa/To0fL19ZWUM++ht7PZbJoxY4a6d++uRx55RKGhofL19dXx48e1evVq1a9fXx988IH++OMP+/tV1apV5ezsrBUrVujMmTP290AA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tWrVVKJECa1YsSJTNQJAdhw/flyRkZFasmSJGjZsqPLly+ull15SgwYNHN6TsmrChAm6fPmyOnXqlKX1CFcAcJ/o06ePwwfN7Nmz1bt371Ttrly5ouHDh2vHjh367rvvVKBAAbVv317JyckO7UaOHKmhQ4dq//799j/4U5w4cUINGzZU9erVtXTpUlmtVoWHh+vTTz/VRx99pL179+rFF19UWFiYNm3apICAAC1btkySdODAAZ06dUpTp05N8zjmz5+vSpUqqW3btqmWWSwW+6V5ly5dUs+ePbVlyxZt27ZNFSpUUKtWrXTp0iWHdV5//XV16NBBv/76q7p166bQ0FDt378/3efx+++/V82aNdNdniI+Pl4TJkzQvHnztHnzZh0/flwvvfRSmm3vdPxz586Vq6urtm7dqo8++uiO+76TFStWaOjQoRoxYoT27Nmj5557Tr1799aGDRsc2o0bN06dOnXSb7/9platWqlbt272nqjXX39d+/bt09dff639+/drxowZ8vHxcVi/du3a+v777++6XgBIz+7du5WUlKSKFSvK09PTPm3atMnhi8GsWLBggcaNG6fFixdnudffOVt7BAD864SFhWnUqFGKiYmRJG3dulVRUVEO16VLUocOHRwez549W76+vtq3b5+qV69unz9s2DA9/fTTqfZz4MABNW/eXO3bt9eUKVNksViUkJCg8ePH69tvv1W9evUkSeXKldOWLVs0c+ZMNW7c2H7pRbFixTIcfOHgwYOqVKnSHY/38ccfd3g8a9YseXt7a9OmTWrdurV9fseOHdW3b19J0ltvvaVvvvlG06ZN0/Tp09PcbkxMjEqUKHHH/V+/fl0fffSRypcvL+nmZStvvvlmmm2dnJwyPP4KFSrovffeu+M+M2vChAnq1auXXnjhBUnS8OHDtW3bNk2YMMHegybdvF+vS5cukqTx48fr/fff1/bt2xUcHKzjx48rKChIjz76qCTZ7z+7VYkSJbJ8MzgAZMXly5fl5OSkX375RU5OTg7LPD09s7y9qKgo9e3bV0uWLEl38IuMEK4A4D7h6+urkJAQzZkzR4ZhKCQkJFVPg3QzvLzxxhv66aefdO7cOXuP1fHjxx3CVcof1be6evWqGjZsqK5du2rKlCn2+YcOHVJ8fLyaN2/u0D4xMTHVZYl3YhhGptqdOXNGr732mjZu3KizZ88qKSlJ8fHxOn78uEO7lLB36+OUUffScvXqVbm5ud1x/wULFrQHK0ny9/fX2bNnM1X77TLTU5YV+/fvV//+/R3m1a9fP1Vv4YMPPmj/2cPDQzabzX4MAwYMUIcOHbRz5061aNFC7dq102OPPeawvru7e64MMALg/hUUFKSkpCSdPXtWDRs2vKttLVy4UH369FFUVJRCQkKytQ3CFQDcR/r06aNBgwZJUrpD2rZp00alS5fWxx9/rBIlSig5OVnVq1e3D6SQwsPDI9W6VqtVzZo106pVq/Tyyy/rgQcekHTzm0VJWr16tX3eretkRcWKFfX777/fsV3Pnj11/vx5TZ06VaVLl5bValW9evVSHUdW+fj46MKFC3ds5+Li4vDYYrFkOhjeLq3nOjekdQwpYfvJJ59UTEyMvvrqK33zzTd64oknNHDgQE2YMMHe/p9//pGvr2+u1gzg3nP58mUdOnTI/vjo0aOKjo5WkSJFVLFiRXXr1k09evTQxIkTFRQUpL///lvfffedHnzwQXtI2rdvnxITE/XPP//o0qVL9i/RHn74YUk3LwXs2bOnpk6dqjp16uj06dOSbn5JlJWRYLnnCgDuI8HBwUpMTNT169dT3Scl3fz/TQcOHNBrr72mJ554QlWqVMlUkEhRoEABzZs3TzVr1lTTpk31119/SZKqVq0qq9Wq48ePKzAw0GEKCAiQdHPEPenm/yPJSNeuXfXHH3/o888/T7XMMAzFxsZKunnZ45AhQ9SqVStVq1ZNVqtV586dS7XOtm3bUj2uUqVKuvsPCgrSvn37MqwxOzJ7/GaoUqWKtm7d6jBv69atqlq1apa24+vrq549e+qzzz7TlClTNGvWLIfle/bsyXLPJADcbseOHQoKCrK/nwwfPlxBQUF64403JEmRkZHq0aOHRowYoUqVKqldu3b6+eefHUbDbdWqlYKCgvTll19q48aNDtuTbl46fuPGDQ0cOFD+/v72aejQoVmqlZ4rALiPODk52QdruP3adOnmSHVFixbVrFmz5O/vr+PHj2vkyJFZ3sf8+fPVpUsXPf7449q4caP8/Pz00ksv6cUXX1RycrIaNGig2NhYbd26VTabTT179lTp0qVlsVi0atUqtWrVSu7u7mleL9+pUyetWLFCXbp00WuvvaYWLVrI19dXu3fv1uTJkzV48GC1a9dOFSpU0Lx58/Too48qLi5OL7/8stzd3VNtb8mSJXr00UfVoEEDzZ8/X9u3b1dERES6x9eyZUuNGjVKFy5cUOHChbP03GQks8dvhpdfflmdOnVSUFCQmjVrpi+//FLLly/Xt99+m+ltvPHGG6pZs6aqVaumhIQErVq1yiGUxsfH65dfftH48eNz4hAA3EeaNGmSYc+/i4uLxo0bp3HjxqXbJuWfvqfn9vuPs4ueKwC4z9hsNtlstjSXFShQQFFRUfrll19UvXp1vfjii/rvf/+b5X04Oztr4cKFqlatmh5//HGdPXtWb731ll5//XWFh4erSpUqCg4O1urVq1W2bFlJ0gMPPKBx48Zp5MiRKl68uP3yxdtZLBYtWLBAkyZN0sqVK9W4cWM9+OCDGjt2rNq2bWvvkYuIiNCFCxf0yCOPqHv37hoyZEiaoz6NGzdOUVFRevDBB/Xpp59q4cKFGfbg1KhRQ4888ogWL16c5eclI5k9fjO0a9dOU6dO1YQJE1StWjXNnDlTkZGRatKkSaa34erqqlGjRunBBx9Uo0aN5OTkpKioKPvyzz//XKVKlbrreyAA4N/EYmT3AnAAAP7lLBaLVqxYoXbt2mVpvdWrV+vll1/Wnj17VKAA31OmpW7duhoyZIi6du2a16UAQK7hskAAALIoJCREBw8e1J9//mm/Zwz/c+7cOT399NP2YdwB4H5BzxUA4L6V3Z4rAADSQs8VAOC+xfeLAAAzcaE4AAAAAJiAcAUAAAAAJiBcAQAAAIAJCFcAAAAAYALCFQAAAACYgHAFAAAAACYgXAEAAACACQhXAAAAAGCC/w/QxZ76rD4uiAAAAABJRU5ErkJggg==", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mCodeExecutor\u001b[0m (to CodeWriter):\n", - "\n", - "exitcode: 0 (execution succeeded)\n", - "Code output: \n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mCodeWriter\u001b[0m (to CodeExecutor):\n", - "\n", - "I see that the code has executed successfully, but unfortunately, the generated plot is not visible here. However, given that there are no errors, it's likely that the plot has been created as expected when you executed the code on your end.\n", - "\n", - "If you have any other questions related to this code or need further assistance with Python coding or data visualization, please let me know! I'm here to help.\n", - "\n", - "Otherwise, if this completes your initial request, I will end this task. Just let me know your decision.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mCodeExecutor\u001b[0m (to CodeWriter):\n", - "\n", - "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mCodeWriter\u001b[0m (to CodeExecutor):\n", - "\n", - "Alright. If you have any more questions regarding this task, or if you need help with other tasks in the future, don't hesitate to ask. Have a great day!\n", - "\n", - "'---TERMINATE---'\n", - "\n", - "--------------------------------------------------------------------------------\n" - ] - } - ], - "source": [ - "chat_result = code_executor_agent.initiate_chat(\n", - " code_writer_agent,\n", - " message=\"Create a plot showing the market caps of the top 7 publicly listed companies using data from Yahoo Finance.\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You can see the plots are now displayed in the current notebook." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "autogen", - "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.11.5" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/website/docs/user-guide/advanced-concepts/code-execution/jupyter-code-executor.ipynb b/website/docs/user-guide/advanced-concepts/code-execution/jupyter-code-executor.ipynb deleted file mode 100644 index 59db7e4750..0000000000 --- a/website/docs/user-guide/advanced-concepts/code-execution/jupyter-code-executor.ipynb +++ /dev/null @@ -1,459 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Jupyter Code Executor\n", - "\n", - "AutoGen is able to execute code in a stateful Jupyter kernel, this is in contrast to the command line code executor where each code block is executed in a new process. This means that you can define variables in one code block and use them in another. One of the interesting properties of this is that when an error is encountered, only the failing code needs to be re-executed, and not the entire script.\n", - "\n", - "To use the [`JupyterCodeExecutor`](/reference/autogen/coding/jupyter/JupyterCodeExecutor#jupytercodeexecutor) you need a Jupyter server running. This can be in Docker, local, or even a remote server. Then, when constructing the [`JupyterCodeExecutor`](/reference/autogen/coding/jupyter/JupyterCodeExecutor#jupytercodeexecutor) you pass it the server it should connect to.\n", - "\n", - "## Dependencies\n", - "\n", - "In order to use Jupyter based code execution some extra dependencies are required. These can be installed with the extra `jupyter-executor`:\n", - "\n", - "```bash\n", - "pip install 'pyautogen[jupyter-executor]'\n", - "```\n", - "\n", - "## Jupyter Server\n", - "\n", - "### Docker\n", - "\n", - "To run a Docker based Jupyter server, the [`DockerJupyterServer`](/reference/autogen/coding/jupyter/DockerJupyterServer#dockerjupyterserver) can be used." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "exit_code=0 output='Hello, World!\\n' output_files=[]\n" - ] - } - ], - "source": [ - "from autogen.coding import CodeBlock\n", - "from autogen.coding.jupyter import DockerJupyterServer, JupyterCodeExecutor\n", - "\n", - "with DockerJupyterServer() as server:\n", - " executor = JupyterCodeExecutor(server)\n", - " print(\n", - " executor.execute_code_blocks(\n", - " code_blocks=[\n", - " CodeBlock(language=\"python\", code=\"print('Hello, World!')\"),\n", - " ]\n", - " )\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "By default the [`DockerJupyterServer`](/reference/autogen/coding/jupyter/DockerJupyterServer#dockerjupyterserver) will build and use a bundled Dockerfile, which can be seen below:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "FROM quay.io/jupyter/docker-stacks-foundation\n", - "\n", - "SHELL [\"/bin/bash\", \"-o\", \"pipefail\", \"-c\"]\n", - "\n", - "USER ${NB_UID}\n", - "RUN mamba install --yes jupyter_kernel_gateway ipykernel && mamba clean --all -f -y && fix-permissions \"${CONDA_DIR}\" && fix-permissions \"/home/${NB_USER}\"\n", - "\n", - "ENV TOKEN=\"UNSET\"\n", - "CMD python -m jupyter kernelgateway --KernelGatewayApp.ip=0.0.0.0 --KernelGatewayApp.port=8888 --KernelGatewayApp.auth_token=\"${TOKEN}\" --JupyterApp.answer_yes=true --JupyterWebsocketPersonality.list_kernels=true\n", - "\n", - "EXPOSE 8888\n", - "\n", - "WORKDIR \"${HOME}\"\n", - "\n" - ] - } - ], - "source": [ - "print(DockerJupyterServer.DEFAULT_DOCKERFILE)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Custom Docker Image\n", - "\n", - "A custom image can be used by passing the `custom_image_name` parameter to the [`DockerJupyterServer`](/reference/autogen/coding/jupyter/DockerJupyterServer#dockerjupyterserver) constructor. There are some requirements of the image for it to work correctly:\n", - "\n", - "- The image must have [Jupyer Kernel Gateway](https://jupyter-kernel-gateway.readthedocs.io/en/latest/) installed and running on port 8888 for the [`JupyterCodeExecutor`](/docs/reference/coding/jupyter/jupyter_code_executor) to be able to connect to it.\n", - "- Respect the `TOKEN` environment variable, which is used to authenticate the [`JupyterCodeExecutor`](/docs/reference/coding/jupyter/jupyter_code_executor) with the Jupyter server.\n", - "- Ensure the `jupyter kernelgateway` is started with:\n", - " - `--JupyterApp.answer_yes=true` - this ensures that the kernel gateway does not prompt for confirmation when shut down.\n", - " - `--JupyterWebsocketPersonality.list_kernels=true` - this ensures that the kernel gateway lists the available kernels.\n", - "\n", - "\n", - "If you wanted to add extra dependencies (for example `matplotlib` and `numpy`) to this image you could customize the Dockerfile like so:\n", - "\n", - "```Dockerfile\n", - "FROM quay.io/jupyter/docker-stacks-foundation\n", - "\n", - "SHELL [\"/bin/bash\", \"-o\", \"pipefail\", \"-c\"]\n", - "\n", - "USER ${NB_UID}\n", - "RUN mamba install --yes jupyter_kernel_gateway ipykernel matplotlib numpy &&\n", - " mamba clean --all -f -y &&\n", - " fix-permissions \"${CONDA_DIR}\" &&\n", - " fix-permissions \"/home/${NB_USER}\"\n", - "\n", - "ENV TOKEN=\"UNSET\"\n", - "CMD python -m jupyter kernelgateway \\\n", - " --KernelGatewayApp.ip=0.0.0.0 \\\n", - " --KernelGatewayApp.port=8888 \\\n", - " --KernelGatewayApp.auth_token=\"${TOKEN}\" \\\n", - " --JupyterApp.answer_yes=true \\\n", - " --JupyterWebsocketPersonality.list_kernels=true\n", - "\n", - "EXPOSE 8888\n", - "\n", - "WORKDIR \"${HOME}\"\n", - "```\n", - "\n", - "````{=mdx}\n", - ":::tip\n", - "To learn about how to combine AutoGen in a Docker image while also executing code in a separate image go [here](/docs/topics/code-execution/cli-code-executor#combining-autogen-in-docker-with-a-docker-based-executor).\n", - ":::\n", - "````" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Local\n", - "\n", - "````mdx-code-block\n", - ":::danger\n", - "The local version will run code on your local system. Use it with caution.\n", - ":::\n", - "````\n", - "\n", - "To run a local Jupyter server, the [`LocalJupyterServer`](/reference/autogen/coding/jupyter/LocalJupyterServer#localjupyterserver) can be used.\n", - "\n", - "````{=mdx}\n", - ":::warning\n", - "The [`LocalJupyterServer`](/reference/autogen/coding/jupyter/LocalJupyterServer#localjupyterserver) does not function on Windows due to a bug. In this case, you can use the [`DockerJupyterServer`](/reference/autogen/coding/jupyter/DockerJupyterServer#dockerjupyterserver) instead or use the [`EmbeddedIPythonCodeExecutor`](/docs/reference/coding/jupyter/embedded_ipython_code_executor). Do note that the intention is to remove the [`EmbeddedIPythonCodeExecutor`](/docs/reference/coding/jupyter/embedded_ipython_code_executor) when the bug is fixed.\n", - ":::\n", - "````" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from autogen.coding import CodeBlock\n", - "from autogen.coding.jupyter import JupyterCodeExecutor, LocalJupyterServer\n", - "\n", - "with LocalJupyterServer() as server:\n", - " executor = JupyterCodeExecutor(server)\n", - " print(\n", - " executor.execute_code_blocks(\n", - " code_blocks=[\n", - " CodeBlock(language=\"python\", code=\"print('Hello, World!')\"),\n", - " ]\n", - " )\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Remote\n", - "\n", - "The [`JupyterCodeExecutor`](/docs/reference/coding/jupyter/jupyter_code_executor) can also connect to a remote Jupyter server. This is done by passing connection information rather than an actual server object into the [`JupyterCodeExecutor`](/docs/reference/coding/jupyter/jupyter_code_executor) constructor.\n", - "\n", - "```python\n", - "from autogen.coding.jupyter import JupyterCodeExecutor, JupyterConnectionInfo\n", - "\n", - "executor = JupyterCodeExecutor(\n", - " jupyter_server=JupyterConnectionInfo(host='example.com', use_https=True, port=7893, token='mytoken')\n", - ")\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Image outputs\n", - "\n", - "When Jupyter outputs an image, this is saved as a file into the `output_dir` of the [`JupyterCodeExecutor`](/docs/reference/coding/jupyter/jupyter_code_executor), as specified by the constructor. By default this is the current working directory.\n", - "\n", - "## Assigning to an agent\n", - "\n", - "A single server can support multiple agents, as each executor will create its own kernel. To assign an executor to an agent it can be done like so:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "from pathlib import Path\n", - "\n", - "from autogen import ConversableAgent\n", - "from autogen.coding.jupyter import DockerJupyterServer, JupyterCodeExecutor\n", - "\n", - "server = DockerJupyterServer()\n", - "\n", - "output_dir = Path(\"coding\")\n", - "output_dir.mkdir(exist_ok=True)\n", - "\n", - "code_executor_agent = ConversableAgent(\n", - " name=\"code_executor_agent\",\n", - " llm_config=False,\n", - " code_execution_config={\n", - " \"executor\": JupyterCodeExecutor(server, output_dir=output_dir),\n", - " },\n", - " human_input_mode=\"NEVER\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "When using code execution it is critical that you update the system prompt of agents you expect to write code to be able to make use of the executor. For example, for the [`JupyterCodeExecutor`](/docs/reference/coding/jupyter/jupyter_code_executor) you might setup a code writing agent like so:" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# The code writer agent's system message is to instruct the LLM on how to\n", - "# use the Jupyter code executor with IPython kernel.\n", - "code_writer_system_message = \"\"\"\n", - "You have been given coding capability to solve tasks using Python code in a stateful IPython kernel.\n", - "You are responsible for writing the code, and the user is responsible for executing the code.\n", - "\n", - "When you write Python code, put the code in a markdown code block with the language set to Python.\n", - "For example:\n", - "```python\n", - "x = 3\n", - "```\n", - "You can use the variable `x` in subsequent code blocks.\n", - "```python\n", - "print(x)\n", - "```\n", - "\n", - "Write code incrementally and leverage the statefulness of the kernel to avoid repeating code.\n", - "Import libraries in a separate code block.\n", - "Define a function or a class in a separate code block.\n", - "Run code that produces output in a separate code block.\n", - "Run code that involves expensive operations like download, upload, and call external APIs in a separate code block.\n", - "\n", - "When your code produces an output, the output will be returned to you.\n", - "Because you have limited conversation memory, if your code creates an image,\n", - "the output will be a path to the image instead of the image itself.\"\"\"\n", - "\n", - "import os\n", - "\n", - "code_writer_agent = ConversableAgent(\n", - " \"code_writer\",\n", - " system_message=code_writer_system_message,\n", - " llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n", - " code_execution_config=False, # Turn off code execution for this agent.\n", - " max_consecutive_auto_reply=2,\n", - " human_input_mode=\"NEVER\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Then we can use these two agents to solve a problem:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mcode_executor_agent\u001b[0m (to code_writer):\n", - "\n", - "Write Python code to calculate the 14th Fibonacci number.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mcode_writer\u001b[0m (to code_executor_agent):\n", - "\n", - "Sure. The Fibonacci sequence is a series of numbers where the next number is found by adding up the two numbers before it. We know that the first two Fibonacci numbers are 0 and 1. After that, the series looks like:\n", - "\n", - "0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...\n", - "\n", - "So, let's define a Python function to calculate the nth Fibonacci number.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mcode_executor_agent\u001b[0m (to code_writer):\n", - "\n", - "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mcode_writer\u001b[0m (to code_executor_agent):\n", - "\n", - "Here is the Python function to calculate the nth Fibonacci number:\n", - "\n", - "```python\n", - "def fibonacci(n):\n", - " if n <= 1:\n", - " return n\n", - " else:\n", - " a, b = 0, 1\n", - " for _ in range(2, n+1):\n", - " a, b = b, a+b\n", - " return b\n", - "```\n", - "\n", - "Now, let's use this function to calculate the 14th Fibonacci number.\n", - "\n", - "```python\n", - "fibonacci(14)\n", - "```\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mcode_executor_agent\u001b[0m (to code_writer):\n", - "\n", - "exitcode: 0 (execution succeeded)\n", - "Code output: \n", - "377\n", - "\n", - "--------------------------------------------------------------------------------\n", - "ChatResult(chat_id=None,\n", - " chat_history=[{'content': 'Write Python code to calculate the 14th '\n", - " 'Fibonacci number.',\n", - " 'role': 'assistant'},\n", - " {'content': 'Sure. The Fibonacci sequence is a series '\n", - " 'of numbers where the next number is '\n", - " 'found by adding up the two numbers '\n", - " 'before it. We know that the first two '\n", - " 'Fibonacci numbers are 0 and 1. After '\n", - " 'that, the series looks like:\\n'\n", - " '\\n'\n", - " '0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, '\n", - " '...\\n'\n", - " '\\n'\n", - " \"So, let's define a Python function to \"\n", - " 'calculate the nth Fibonacci number.',\n", - " 'role': 'user'},\n", - " {'content': '', 'role': 'assistant'},\n", - " {'content': 'Here is the Python function to calculate '\n", - " 'the nth Fibonacci number:\\n'\n", - " '\\n'\n", - " '```python\\n'\n", - " 'def fibonacci(n):\\n'\n", - " ' if n <= 1:\\n'\n", - " ' return n\\n'\n", - " ' else:\\n'\n", - " ' a, b = 0, 1\\n'\n", - " ' for _ in range(2, n+1):\\n'\n", - " ' a, b = b, a+b\\n'\n", - " ' return b\\n'\n", - " '```\\n'\n", - " '\\n'\n", - " \"Now, let's use this function to \"\n", - " 'calculate the 14th Fibonacci number.\\n'\n", - " '\\n'\n", - " '```python\\n'\n", - " 'fibonacci(14)\\n'\n", - " '```',\n", - " 'role': 'user'},\n", - " {'content': 'exitcode: 0 (execution succeeded)\\n'\n", - " 'Code output: \\n'\n", - " '377',\n", - " 'role': 'assistant'}],\n", - " summary='exitcode: 0 (execution succeeded)\\nCode output: \\n377',\n", - " cost=({'gpt-4-0613': {'completion_tokens': 193,\n", - " 'cost': 0.028499999999999998,\n", - " 'prompt_tokens': 564,\n", - " 'total_tokens': 757},\n", - " 'total_cost': 0.028499999999999998},\n", - " {'gpt-4-0613': {'completion_tokens': 193,\n", - " 'cost': 0.028499999999999998,\n", - " 'prompt_tokens': 564,\n", - " 'total_tokens': 757},\n", - " 'total_cost': 0.028499999999999998}),\n", - " human_input=[])\n" - ] - } - ], - "source": [ - "import pprint\n", - "\n", - "chat_result = code_executor_agent.initiate_chat(\n", - " code_writer_agent, message=\"Write Python code to calculate the 14th Fibonacci number.\"\n", - ")\n", - "\n", - "pprint.pprint(chat_result)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Finally, stop the server. Or better yet use a context manager for it to be stopped automatically." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "server.stop()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "autogen", - "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.11.8" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/website/docs/user-guide/advanced-concepts/code-execution/user-defined-functions.ipynb b/website/docs/user-guide/advanced-concepts/code-execution/user-defined-functions.ipynb deleted file mode 100644 index 3eb389b64a..0000000000 --- a/website/docs/user-guide/advanced-concepts/code-execution/user-defined-functions.ipynb +++ /dev/null @@ -1,352 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# User Defined Functions\n", - "\n", - "````{=mdx}\n", - ":::note\n", - "This is experimental and not *yet* supported by all executors. At this stage only [`LocalCommandLineCodeExecutor`](/reference/autogen/coding/LocalCommandLineCodeExecutor#localcommandlinecodeexecutor) is supported.\n", - "\n", - "\n", - "Currently, the method of registering tools and using this feature are different. We would like to unify them. See Github issue [here](https://github.com/microsoft/autogen/issues/2101)\n", - ":::\n", - "````\n", - "\n", - "User defined functions allow you to define Python functions in your AutoGen program and then provide these to be used by your executor. This allows you to provide your agents with tools without using traditional tool calling APIs. Currently only Python is supported for this feature.\n", - "\n", - "There are several steps involved:\n", - "\n", - "1. Define the function\n", - "2. Provide the function to the executor\n", - "3. Explain to the code writing agent how to use the function\n", - "\n", - "\n", - "## Define the function\n", - "\n", - "````{=mdx}\n", - ":::warning\n", - "Keep in mind that the entire source code of these functions will be available to the executor. This means that you should not include any sensitive information in the function as an LLM agent may be able to access it.\n", - ":::\n", - "````\n", - "\n", - "If the function does not require any external imports or dependencies then you can simply use the function. For example:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "def add_two_numbers(a: int, b: int) -> int:\n", - " \"\"\"Add two numbers together.\"\"\"\n", - " return a + b" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This would be a valid standalone function.\n", - "\n", - "````{=mdx}\n", - ":::tip\n", - "Using type hints and docstrings are not required but are highly recommended. They will help the code writing agent understand the function and how to use it.\n", - ":::\n", - "````\n", - "\n", - "If the function requires external imports or dependencies then you can use the `@with_requirements` decorator to specify the requirements. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas\n", - "\n", - "from autogen.coding.func_with_reqs import with_requirements\n", - "\n", - "\n", - "@with_requirements(python_packages=[\"pandas\"], global_imports=[\"pandas\"])\n", - "def load_data() -> pandas.DataFrame:\n", - " \"\"\"Load some sample data.\n", - "\n", - " Returns:\n", - " pandas.DataFrame: A DataFrame with the following columns: name(str), location(str), age(int)\n", - " \"\"\"\n", - " data = {\n", - " \"name\": [\"John\", \"Anna\", \"Peter\", \"Linda\"],\n", - " \"location\": [\"New York\", \"Paris\", \"Berlin\", \"London\"],\n", - " \"age\": [24, 13, 53, 33],\n", - " }\n", - " return pandas.DataFrame(data)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "If you wanted to rename `pandas` to `pd` or import `DataFrame` directly you could do the following:" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "from pandas import DataFrame\n", - "from pandas import DataFrame as Df\n", - "\n", - "from autogen.coding.func_with_reqs import Alias, ImportFromModule, with_requirements\n", - "\n", - "\n", - "@with_requirements(python_packages=[\"pandas\"], global_imports=[Alias(\"pandas\", \"pd\")])\n", - "def some_func1() -> pd.DataFrame: ...\n", - "\n", - "\n", - "@with_requirements(python_packages=[\"pandas\"], global_imports=[ImportFromModule(\"pandas\", \"DataFrame\")])\n", - "def some_func2() -> DataFrame: ...\n", - "\n", - "\n", - "@with_requirements(python_packages=[\"pandas\"], global_imports=[ImportFromModule(\"pandas\", Alias(\"DataFrame\", \"Df\"))])\n", - "def some_func3() -> Df: ..." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Provide the function to the executor\n", - "\n", - "Functions can be loaded into the executor in its constructor. For example:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "from pathlib import Path\n", - "\n", - "from autogen.coding import CodeBlock, LocalCommandLineCodeExecutor\n", - "\n", - "work_dir = Path(\"coding\")\n", - "work_dir.mkdir(exist_ok=True)\n", - "\n", - "executor = LocalCommandLineCodeExecutor(work_dir=work_dir, functions=[add_two_numbers, load_data])" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Before we get an agent involved, we can sanity check that when the agent writes code that looks like this the executor will be able to handle it." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "code = f\"\"\"\n", - "from {LocalCommandLineCodeExecutor.functions_module} import add_two_numbers\n", - "\n", - "print(add_two_numbers(1, 2))\n", - "\"\"\"\n", - "\n", - "print(\n", - " executor.execute_code_blocks(\n", - " code_blocks=[\n", - " CodeBlock(language=\"python\", code=code),\n", - " ]\n", - " )\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "And we can try the function that required a dependency and import too." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "code = f\"\"\"\n", - "from {LocalCommandLineCodeExecutor.functions_module} import load_data\n", - "\n", - "print(load_data())\n", - "\"\"\"\n", - "\n", - "result = executor.execute_code_blocks(\n", - " code_blocks=[\n", - " CodeBlock(language=\"python\", code=code),\n", - " ]\n", - ")\n", - "\n", - "print(result.output)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Limitations\n", - "\n", - "- Only Python is supported currently\n", - "- The function must not depend on any globals or external state as it is loaded as source code \n", - "\n", - "## Explain to the code writing agent how to use the function\n", - "\n", - "Now that the function is available to be called by the executor, you can explain to the code writing agent how to use the function. This step is very important as by default it will not know about it.\n", - "\n", - "There is a utility function that you can use to generate a default prompt that describes the available functions and how to use them. This function can have its template overridden to provide a custom message, or you can use a different prompt all together.\n", - "\n", - "For example, you could extend the system message from the page about local execution with a new section that describes the functions available." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "nlnl = \"\\n\\n\"\n", - "code_writer_system_message = \"\"\"\n", - "You have been given coding capability to solve tasks using Python code.\n", - "In the following cases, suggest python code (in a python coding block) or shell script (in a sh coding block) for the user to execute.\n", - " 1. When you need to collect info, use the code to output the info you need, for example, browse or search the web, download/read a file, print the content of a webpage or a file, get the current date/time, check the operating system. After sufficient info is printed and the task is ready to be solved based on your language skill, you can solve the task by yourself.\n", - " 2. When you need to perform some task with code, use the code to perform the task and output the result. Finish the task smartly.\n", - "Solve the task step by step if you need to. If a plan is not provided, explain your plan first. Be clear which step uses code, and which step uses your language skill.\n", - "When using code, you must indicate the script type in the code block. The user cannot provide any other feedback or perform any other action beyond executing the code you suggest. The user can't modify your code. So do not suggest incomplete code which requires users to modify. Don't use a code block if it's not intended to be executed by the user.\n", - "If you want the user to save the code in a file before executing it, put # filename: inside the code block as the first line. Don't include multiple code blocks in one response. Do not ask users to copy and paste the result. Instead, use 'print' function for the output when relevant. Check the execution result returned by the user.\n", - "\"\"\"\n", - "\n", - "# Add on the new functions\n", - "code_writer_system_message += executor.format_functions_for_prompt()\n", - "\n", - "print(code_writer_system_message)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Then you can use this system message for your code writing agent." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "\n", - "from autogen import ConversableAgent\n", - "\n", - "code_writer_agent = ConversableAgent(\n", - " \"code_writer\",\n", - " system_message=code_writer_system_message,\n", - " llm_config={\"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}]},\n", - " code_execution_config=False, # Turn off code execution for this agent.\n", - " max_consecutive_auto_reply=2,\n", - " human_input_mode=\"NEVER\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we can setup the code execution agent using the local command line executor we defined earlier." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "code_executor_agent = ConversableAgent(\n", - " name=\"code_executor_agent\",\n", - " llm_config=False,\n", - " code_execution_config={\n", - " \"executor\": executor,\n", - " },\n", - " human_input_mode=\"NEVER\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Then, we can start the conversation and get the agent to process the dataframe we provided." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "chat_result = code_executor_agent.initiate_chat(\n", - " code_writer_agent,\n", - " message=\"Please use the load_data function to load the data and please calculate the average age of all people.\",\n", - " summary_method=\"reflection_with_llm\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see the summary of the calculation:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(chat_result.summary)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": ".venv-3.9", - "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.9.20" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/website/use-cases/walk-throughs/custom-group-chat.md b/website/docs/user-guide/advanced-concepts/custom-group-chat.mdx similarity index 99% rename from website/use-cases/walk-throughs/custom-group-chat.md rename to website/docs/user-guide/advanced-concepts/custom-group-chat.mdx index 19182204eb..5544d8fa37 100644 --- a/website/use-cases/walk-throughs/custom-group-chat.md +++ b/website/docs/user-guide/advanced-concepts/custom-group-chat.mdx @@ -1,8 +1,11 @@ -# Customized Group Chat flows +--- +title: Customized Group Chat flows +sidebarTitle: Custom Group Chat +--- -::tip + If you haven't had a chance to read about or use AG2's GroupChat orchestration, see the [Getting Started](TODO) introduction to GroupChat. -:: + `GroupChat`'s four built-in conversation patterns, automatic, round robin, random, and manual provide a good degree of flexibility to orchestrate agents in a group chat setting. diff --git a/website/use-cases/walk-throughs/enhanced-swarm.md b/website/docs/user-guide/advanced-concepts/enhanced-swarm.mdx similarity index 99% rename from website/use-cases/walk-throughs/enhanced-swarm.md rename to website/docs/user-guide/advanced-concepts/enhanced-swarm.mdx index 472c6dcaca..62f7361c1f 100644 --- a/website/use-cases/walk-throughs/enhanced-swarm.md +++ b/website/docs/user-guide/advanced-concepts/enhanced-swarm.mdx @@ -1,8 +1,10 @@ -# Enhanced Swarm +--- +title: Enhanced Swarm +--- -::tip + If you haven't had a chance to read about or use AG2's Swarm orchestration, see the [Getting Started](TODO) introduction to Swarm and the [Swarm documentation](). -:: + You can build complex, yet flexible, workflows using AG2's Swarm orchestration. @@ -127,9 +129,9 @@ In Swarms, functions can be used to handle transitions to the next agent as well Later we will see the use of the `available` parameter in an OnCondition hand-off to determine if a hand-off is made available for evaluation by the LLM. As that parameter takes a context variable that must be equivalent to `True`, we use two context variable keys to control authentication hand-offs, `logged_in` and `requires_login`, which have alternating boolean values. -::tip + If you are updating context variables in a function, be sure to return it in the `SwarmResult` so the shared context variables can be updated. -:: + ```python # ORDER FUNCTIONS diff --git a/website/docs/user-guide/advanced-concepts/groupchat/_category_.json b/website/docs/user-guide/advanced-concepts/groupchat/_category_.json deleted file mode 100644 index da7c003665..0000000000 --- a/website/docs/user-guide/advanced-concepts/groupchat/_category_.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "position": 5, - "label": "GroupChat", - "collapsible": true -} diff --git a/website/docs/user-guide/advanced-concepts/groupchat/customized_speaker_selection.ipynb b/website/docs/user-guide/advanced-concepts/groupchat/customized_speaker_selection.ipynb deleted file mode 100644 index 6742f80b54..0000000000 --- a/website/docs/user-guide/advanced-concepts/groupchat/customized_speaker_selection.ipynb +++ /dev/null @@ -1,543 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Customize Speaker Selection\n", - "\n", - "```{=mdx}\n", - "![group_chat](../../blog/2024-02-29-StateFlow/img/sf_example_1.webp)\n", - "```\n", - "\n", - "In GroupChat, we can customize the speaker selection by passing a function to the `GroupChat` object. With this function, you can build a more **deterministic** agent workflow. We recommend following a **StateFlow** pattern when crafting this function. Please refer to the [StateFlow blog](/blog/2024-02-29-StateFlow/index) for more details.\n", - "\n", - "\n", - "## An example research workflow\n", - "We provide a simple example to build a StateFlow model for research with customized speaker selection.\n", - "\n", - "We first define the following agents:\n", - "\n", - "- Initializer: Start the workflow by sending a task.\n", - "- Coder: Retrieve papers from the internet by writing code.\n", - "- Executor: Execute the code.\n", - "- Scientist: Read the papers and write a summary.\n", - "\n", - "In the figure above, we define a simple workflow for research with 4 states: *Init*, *Retrieve*, *Research*, and *End*. Within each state, we will call different agents to perform the tasks.\n", - "\n", - "- *Init*: We use the initializer to start the workflow.\n", - "- *Retrieve*: We will first call the coder to write code and then call the executor to execute the code.\n", - "- *Research*: We will call the scientist to read the papers and write a summary.\n", - "- *End*: We will end the workflow.\n", - "\n", - "## Create your speaker selection function\n", - "\n", - "Below is a skeleton of the speaker selection function. Fill in the function to define the speaker selection logic.\n", - "\n", - "```python\n", - "def custom_speaker_selection_func(\n", - " last_speaker: Agent, \n", - " groupchat: GroupChat\n", - ") -> Union[Agent, Literal['auto', 'manual', 'random' 'round_robin'], None]:\n", - "\n", - " \"\"\"Define a customized speaker selection function.\n", - " A recommended way is to define a transition for each speaker in the groupchat.\n", - "\n", - " Parameters:\n", - " - last_speaker: Agent\n", - " The last speaker in the group chat.\n", - " - groupchat: GroupChat\n", - " The GroupChat object\n", - " Return:\n", - " Return one of the following:\n", - " 1. an `Agent` class, it must be one of the agents in the group chat.\n", - " 2. a string from ['auto', 'manual', 'random', 'round_robin'] to select a default method to use.\n", - " 3. None, which indicates the chat should be terminated.\n", - " \"\"\"\n", - " pass\n", - "\n", - "groupchat = autogen.GroupChat(\n", - " speaker_selection_method=custom_speaker_selection_func,\n", - " ...,\n", - ")\n", - "```\n", - "The last speaker and the groupchat object are passed to the function. \n", - "Commonly used variables from groupchat are `groupchat.messages` and `groupchat.agents`, which is the message history and the agents in the group chat respectively. You can access other attributes of the groupchat, such as `groupchat.allowed_speaker_transitions_dict` for pre-defined `allowed_speaker_transitions_dict`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "\n", - "import autogen\n", - "\n", - "# Put your api key in the environment variable OPENAI_API_KEY\n", - "config_list = [\n", - " {\n", - " \"model\": \"gpt-4-0125-preview\",\n", - " \"api_key\": os.environ[\"OPENAI_API_KEY\"],\n", - " }\n", - "]\n", - "\n", - "# You can also create an file called \"OAI_CONFIG_LIST\" and store your config there\n", - "# config_list = autogen.config_list_from_json(\n", - "# \"OAI_CONFIG_LIST\",\n", - "# filter_dict={\n", - "# \"model\": [\"gpt-4-0125-preview\"],\n", - "# },\n", - "# )" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "gpt4_config = {\n", - " \"cache_seed\": 42, # change the cache_seed for different trials\n", - " \"temperature\": 0,\n", - " \"config_list\": config_list,\n", - " \"timeout\": 120,\n", - "}\n", - "\n", - "initializer = autogen.UserProxyAgent(\n", - " name=\"Init\",\n", - ")\n", - "\n", - "coder = autogen.AssistantAgent(\n", - " name=\"Retrieve_Action_1\",\n", - " llm_config=gpt4_config,\n", - " system_message=\"\"\"You are the Coder. Given a topic, write code to retrieve related papers from the arXiv API, print their title, authors, abstract, and link.\n", - "You write python/shell code to solve tasks. Wrap the code in a code block that specifies the script type. The user can't modify your code. So do not suggest incomplete code which requires others to modify. Don't use a code block if it's not intended to be executed by the executor.\n", - "Don't include multiple code blocks in one response. Do not ask others to copy and paste the result. Check the execution result returned by the executor.\n", - "If the result indicates there is an error, fix the error and output the code again. Suggest the full code instead of partial code or code changes. If the error can't be fixed or if the task is not solved even after the code is executed successfully, analyze the problem, revisit your assumption, collect additional info you need, and think of a different approach to try.\n", - "\"\"\",\n", - ")\n", - "executor = autogen.UserProxyAgent(\n", - " name=\"Retrieve_Action_2\",\n", - " system_message=\"Executor. Execute the code written by the Coder and report the result.\",\n", - " human_input_mode=\"NEVER\",\n", - " code_execution_config={\n", - " \"last_n_messages\": 3,\n", - " \"work_dir\": \"paper\",\n", - " \"use_docker\": False,\n", - " }, # Please set use_docker=True if docker is available to run the generated code. Using docker is safer than running the generated code directly.\n", - ")\n", - "scientist = autogen.AssistantAgent(\n", - " name=\"Research_Action_1\",\n", - " llm_config=gpt4_config,\n", - " system_message=\"\"\"You are the Scientist. Please categorize papers after seeing their abstracts printed and create a markdown table with Domain, Title, Authors, Summary and Link\"\"\",\n", - ")\n", - "\n", - "\n", - "def state_transition(last_speaker, groupchat):\n", - " messages = groupchat.messages\n", - "\n", - " if last_speaker is initializer:\n", - " # init -> retrieve\n", - " return coder\n", - " elif last_speaker is coder:\n", - " # retrieve: action 1 -> action 2\n", - " return executor\n", - " elif last_speaker is executor:\n", - " if messages[-1][\"content\"] == \"exitcode: 1\":\n", - " # retrieve --(execution failed)--> retrieve\n", - " return coder\n", - " else:\n", - " # retrieve --(execution success)--> research\n", - " return scientist\n", - " elif last_speaker == \"Scientist\":\n", - " # research -> end\n", - " return None\n", - "\n", - "\n", - "groupchat = autogen.GroupChat(\n", - " agents=[initializer, coder, executor, scientist],\n", - " messages=[],\n", - " max_round=20,\n", - " speaker_selection_method=state_transition,\n", - ")\n", - "manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=gpt4_config)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mInit\u001b[0m (to chat_manager):\n", - "\n", - "Topic: LLM applications papers from last week. Requirement: 5 - 10 papers from different domains.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mRetrieve_Action_1\u001b[0m (to chat_manager):\n", - "\n", - "To retrieve related papers from the arXiv API, we can use Python with the `requests` library to send a query to the API and parse the response. Below is a Python script that searches for papers related to \"LLM applications\" (Large Language Models applications) from the last week, across different domains, and prints out the required information for 5 to 10 papers.\n", - "\n", - "```python\n", - "import requests\n", - "from datetime import datetime, timedelta\n", - "import feedparser\n", - "\n", - "# Define the base URL for the arXiv API\n", - "ARXIV_API_URL = 'http://export.arxiv.org/api/query?'\n", - "\n", - "# Define the search parameters\n", - "search_query = 'all:\"LLM applications\"'\n", - "start_date = (datetime.now() - timedelta(days=7)).strftime('%Y%m%d%H%M%S')\n", - "end_date = datetime.now().strftime('%Y%m%d%H%M%S')\n", - "start = 0\n", - "max_results = 10\n", - "sort_by = 'submittedDate'\n", - "sort_order = 'descending'\n", - "\n", - "# Construct the query\n", - "query = f'search_query={search_query}&sortBy={sort_by}&sortOrder={sort_order}&start={start}&max_results={max_results}'\n", - "\n", - "# Send the request to the arXiv API\n", - "response = requests.get(ARXIV_API_URL + query)\n", - "\n", - "# Parse the response using feedparser\n", - "feed = feedparser.parse(response.content)\n", - "\n", - "# Print the title, authors, abstract, and link of each paper\n", - "for entry in feed.entries:\n", - " print(\"Title:\", entry.title)\n", - " print(\"Authors:\", ', '.join(author.name for author in entry.authors))\n", - " print(\"Abstract:\", entry.summary)\n", - " print(\"Link:\", entry.link)\n", - " print(\"\\n\")\n", - "\n", - "# Check if we have at least 5 papers, if not, adjust the search or notify\n", - "if len(feed.entries) < 5:\n", - " print(\"Less than 5 papers found. Consider adjusting the search parameters or timeframe.\")\n", - "```\n", - "\n", - "This script will print the title, authors, abstract, and link for each paper related to \"LLM applications\" from the last week, up to a maximum of 10 papers. If fewer than 5 papers are found, it will notify the user to consider adjusting the search parameters or timeframe.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n", - "\u001b[33mRetrieve_Action_2\u001b[0m (to chat_manager):\n", - "\n", - "exitcode: 0 (execution succeeded)\n", - "Code output: \n", - "Title: PRSA: Prompt Reverse Stealing Attacks against Large Language Models\n", - "Authors: Yong Yang, Xuhong Zhang, Yi Jiang, Xi Chen, Haoyu Wang, Shouling Ji, Zonghui Wang\n", - "Abstract: Prompt, recognized as crucial intellectual property, enables large language\n", - "models (LLMs) to perform specific tasks without the need of fine-tuning,\n", - "underscoring their escalating importance. With the rise of prompt-based\n", - "services, such as prompt marketplaces and LLM applications, providers often\n", - "display prompts' capabilities through input-output examples to attract users.\n", - "However, this paradigm raises a pivotal security concern: does the exposure of\n", - "input-output pairs pose the risk of potential prompt leakage, infringing on the\n", - "intellectual property rights of the developers? To our knowledge, this problem\n", - "still has not been comprehensively explored yet. To remedy this gap, in this\n", - "paper, we perform the first in depth exploration and propose a novel attack\n", - "framework for reverse-stealing prompts against commercial LLMs, namely PRSA.\n", - "The main idea of PRSA is that by analyzing the critical features of the\n", - "input-output pairs, we mimic and gradually infer (steal) the target prompts. In\n", - "detail, PRSA mainly consists of two key phases: prompt mutation and prompt\n", - "pruning. In the mutation phase, we propose a prompt attention algorithm based\n", - "on differential feedback to capture these critical features for effectively\n", - "inferring the target prompts. In the prompt pruning phase, we identify and mask\n", - "the words dependent on specific inputs, enabling the prompts to accommodate\n", - "diverse inputs for generalization. Through extensive evaluation, we verify that\n", - "PRSA poses a severe threat in real world scenarios. We have reported these\n", - "findings to prompt service providers and actively collaborate with them to take\n", - "protective measures for prompt copyright.\n", - "Link: http://arxiv.org/abs/2402.19200v1\n", - "\n", - "\n", - "Title: Political Compass or Spinning Arrow? Towards More Meaningful Evaluations\n", - " for Values and Opinions in Large Language Models\n", - "Authors: Paul Rรถttger, Valentin Hofmann, Valentina Pyatkin, Musashi Hinck, Hannah Rose Kirk, Hinrich Schรผtze, Dirk Hovy\n", - "Abstract: Much recent work seeks to evaluate values and opinions in large language\n", - "models (LLMs) using multiple-choice surveys and questionnaires. Most of this\n", - "work is motivated by concerns around real-world LLM applications. For example,\n", - "politically-biased LLMs may subtly influence society when they are used by\n", - "millions of people. Such real-world concerns, however, stand in stark contrast\n", - "to the artificiality of current evaluations: real users do not typically ask\n", - "LLMs survey questions. Motivated by this discrepancy, we challenge the\n", - "prevailing constrained evaluation paradigm for values and opinions in LLMs and\n", - "explore more realistic unconstrained evaluations. As a case study, we focus on\n", - "the popular Political Compass Test (PCT). In a systematic review, we find that\n", - "most prior work using the PCT forces models to comply with the PCT's\n", - "multiple-choice format. We show that models give substantively different\n", - "answers when not forced; that answers change depending on how models are\n", - "forced; and that answers lack paraphrase robustness. Then, we demonstrate that\n", - "models give different answers yet again in a more realistic open-ended answer\n", - "setting. We distill these findings into recommendations and open challenges in\n", - "evaluating values and opinions in LLMs.\n", - "Link: http://arxiv.org/abs/2402.16786v1\n", - "\n", - "\n", - "Title: Large Language Models as Urban Residents: An LLM Agent Framework for\n", - " Personal Mobility Generation\n", - "Authors: Jiawei Wang, Renhe Jiang, Chuang Yang, Zengqing Wu, Makoto Onizuka, Ryosuke Shibasaki, Chuan Xiao\n", - "Abstract: This paper introduces a novel approach using Large Language Models (LLMs)\n", - "integrated into an agent framework for flexible and efficient personal mobility\n", - "generation. LLMs overcome the limitations of previous models by efficiently\n", - "processing semantic data and offering versatility in modeling various tasks.\n", - "Our approach addresses the critical need to align LLMs with real-world urban\n", - "mobility data, focusing on three research questions: aligning LLMs with rich\n", - "activity data, developing reliable activity generation strategies, and\n", - "exploring LLM applications in urban mobility. The key technical contribution is\n", - "a novel LLM agent framework that accounts for individual activity patterns and\n", - "motivations, including a self-consistency approach to align LLMs with\n", - "real-world activity data and a retrieval-augmented strategy for interpretable\n", - "activity generation. In experimental studies, comprehensive validation is\n", - "performed using real-world data. This research marks the pioneering work of\n", - "designing an LLM agent framework for activity generation based on real-world\n", - "human activity data, offering a promising tool for urban mobility analysis.\n", - "Link: http://arxiv.org/abs/2402.14744v1\n", - "\n", - "\n", - "Title: An Evaluation of Large Language Models in Bioinformatics Research\n", - "Authors: Hengchuang Yin, Zhonghui Gu, Fanhao Wang, Yiparemu Abuduhaibaier, Yanqiao Zhu, Xinming Tu, Xian-Sheng Hua, Xiao Luo, Yizhou Sun\n", - "Abstract: Large language models (LLMs) such as ChatGPT have gained considerable\n", - "interest across diverse research communities. Their notable ability for text\n", - "completion and generation has inaugurated a novel paradigm for\n", - "language-interfaced problem solving. However, the potential and efficacy of\n", - "these models in bioinformatics remain incompletely explored. In this work, we\n", - "study the performance LLMs on a wide spectrum of crucial bioinformatics tasks.\n", - "These tasks include the identification of potential coding regions, extraction\n", - "of named entities for genes and proteins, detection of antimicrobial and\n", - "anti-cancer peptides, molecular optimization, and resolution of educational\n", - "bioinformatics problems. Our findings indicate that, given appropriate prompts,\n", - "LLMs like GPT variants can successfully handle most of these tasks. In\n", - "addition, we provide a thorough analysis of their limitations in the context of\n", - "complicated bioinformatics tasks. In conclusion, we believe that this work can\n", - "provide new perspectives and motivate future research in the field of LLMs\n", - "applications, AI for Science and bioinformatics.\n", - "Link: http://arxiv.org/abs/2402.13714v1\n", - "\n", - "\n", - "Title: Privacy-Preserving Instructions for Aligning Large Language Models\n", - "Authors: Da Yu, Peter Kairouz, Sewoong Oh, Zheng Xu\n", - "Abstract: Service providers of large language model (LLM) applications collect user\n", - "instructions in the wild and use them in further aligning LLMs with users'\n", - "intentions. These instructions, which potentially contain sensitive\n", - "information, are annotated by human workers in the process. This poses a new\n", - "privacy risk not addressed by the typical private optimization. To this end, we\n", - "propose using synthetic instructions to replace real instructions in data\n", - "annotation and model fine-tuning. Formal differential privacy is guaranteed by\n", - "generating those synthetic instructions using privately fine-tuned generators.\n", - "Crucial in achieving the desired utility is our novel filtering algorithm that\n", - "matches the distribution of the synthetic instructions to that of the real\n", - "ones. In both supervised fine-tuning and reinforcement learning from human\n", - "feedback, our extensive experiments demonstrate the high utility of the final\n", - "set of synthetic instructions by showing comparable results to real\n", - "instructions. In supervised fine-tuning, models trained with private synthetic\n", - "instructions outperform leading open-source models such as Vicuna.\n", - "Link: http://arxiv.org/abs/2402.13659v1\n", - "\n", - "\n", - "Title: Ain't Misbehavin' -- Using LLMs to Generate Expressive Robot Behavior in\n", - " Conversations with the Tabletop Robot Haru\n", - "Authors: Zining Wang, Paul Reisert, Eric Nichols, Randy Gomez\n", - "Abstract: Social robots aim to establish long-term bonds with humans through engaging\n", - "conversation. However, traditional conversational approaches, reliant on\n", - "scripted interactions, often fall short in maintaining engaging conversations.\n", - "This paper addresses this limitation by integrating large language models\n", - "(LLMs) into social robots to achieve more dynamic and expressive conversations.\n", - "We introduce a fully-automated conversation system that leverages LLMs to\n", - "generate robot responses with expressive behaviors, congruent with the robot's\n", - "personality. We incorporate robot behavior with two modalities: 1) a\n", - "text-to-speech (TTS) engine capable of various delivery styles, and 2) a\n", - "library of physical actions for the robot. We develop a custom,\n", - "state-of-the-art emotion recognition model to dynamically select the robot's\n", - "tone of voice and utilize emojis from LLM output as cues for generating robot\n", - "actions. A demo of our system is available here. To illuminate design and\n", - "implementation issues, we conduct a pilot study where volunteers chat with a\n", - "social robot using our proposed system, and we analyze their feedback,\n", - "conducting a rigorous error analysis of chat transcripts. Feedback was\n", - "overwhelmingly positive, with participants commenting on the robot's empathy,\n", - "helpfulness, naturalness, and entertainment. Most negative feedback was due to\n", - "automatic speech recognition (ASR) errors which had limited impact on\n", - "conversations. However, we observed a small class of errors, such as the LLM\n", - "repeating itself or hallucinating fictitious information and human responses,\n", - "that have the potential to derail conversations, raising important issues for\n", - "LLM application.\n", - "Link: http://arxiv.org/abs/2402.11571v1\n", - "\n", - "\n", - "Title: Fine-tuning Large Language Model (LLM) Artificial Intelligence Chatbots\n", - " in Ophthalmology and LLM-based evaluation using GPT-4\n", - "Authors: Ting Fang Tan, Kabilan Elangovan, Liyuan Jin, Yao Jie, Li Yong, Joshua Lim, Stanley Poh, Wei Yan Ng, Daniel Lim, Yuhe Ke, Nan Liu, Daniel Shu Wei Ting\n", - "Abstract: Purpose: To assess the alignment of GPT-4-based evaluation to human clinician\n", - "experts, for the evaluation of responses to ophthalmology-related patient\n", - "queries generated by fine-tuned LLM chatbots. Methods: 400 ophthalmology\n", - "questions and paired answers were created by ophthalmologists to represent\n", - "commonly asked patient questions, divided into fine-tuning (368; 92%), and\n", - "testing (40; 8%). We find-tuned 5 different LLMs, including LLAMA2-7b,\n", - "LLAMA2-7b-Chat, LLAMA2-13b, and LLAMA2-13b-Chat. For the testing dataset,\n", - "additional 8 glaucoma QnA pairs were included. 200 responses to the testing\n", - "dataset were generated by 5 fine-tuned LLMs for evaluation. A customized\n", - "clinical evaluation rubric was used to guide GPT-4 evaluation, grounded on\n", - "clinical accuracy, relevance, patient safety, and ease of understanding. GPT-4\n", - "evaluation was then compared against ranking by 5 clinicians for clinical\n", - "alignment. Results: Among all fine-tuned LLMs, GPT-3.5 scored the highest\n", - "(87.1%), followed by LLAMA2-13b (80.9%), LLAMA2-13b-chat (75.5%),\n", - "LLAMA2-7b-Chat (70%) and LLAMA2-7b (68.8%) based on the GPT-4 evaluation. GPT-4\n", - "evaluation demonstrated significant agreement with human clinician rankings,\n", - "with Spearman and Kendall Tau correlation coefficients of 0.90 and 0.80\n", - "respectively; while correlation based on Cohen Kappa was more modest at 0.50.\n", - "Notably, qualitative analysis and the glaucoma sub-analysis revealed clinical\n", - "inaccuracies in the LLM-generated responses, which were appropriately\n", - "identified by the GPT-4 evaluation. Conclusion: The notable clinical alignment\n", - "of GPT-4 evaluation highlighted its potential to streamline the clinical\n", - "evaluation of LLM chatbot responses to healthcare-related queries. By\n", - "complementing the existing clinician-dependent manual grading, this efficient\n", - "and automated evaluation could assist the validation of future developments in\n", - "LLM applications for healthcare.\n", - "Link: http://arxiv.org/abs/2402.10083v1\n", - "\n", - "\n", - "Title: Unmemorization in Large Language Models via Self-Distillation and\n", - " Deliberate Imagination\n", - "Authors: Yijiang River Dong, Hongzhou Lin, Mikhail Belkin, Ramon Huerta, Ivan Vuliฤ‡\n", - "Abstract: While displaying impressive generation capabilities across many tasks, Large\n", - "Language Models (LLMs) still struggle with crucial issues of privacy violation\n", - "and unwanted exposure of sensitive data. This raises an essential question: how\n", - "should we prevent such undesired behavior of LLMs while maintaining their\n", - "strong generation and natural language understanding (NLU) capabilities? In\n", - "this work, we introduce a novel approach termed deliberate imagination in the\n", - "context of LLM unlearning. Instead of trying to forget memorized data, we\n", - "employ a self-distillation framework, guiding LLMs to deliberately imagine\n", - "alternative scenarios. As demonstrated in a wide range of experiments, the\n", - "proposed method not only effectively unlearns targeted text but also preserves\n", - "the LLMs' capabilities in open-ended generation tasks as well as in NLU tasks.\n", - "Our results demonstrate the usefulness of this approach across different models\n", - "and sizes, and also with parameter-efficient fine-tuning, offering a novel\n", - "pathway to addressing the challenges with private and sensitive data in LLM\n", - "applications.\n", - "Link: http://arxiv.org/abs/2402.10052v1\n", - "\n", - "\n", - "Title: Anchor-based Large Language Models\n", - "Authors: Jianhui Pang, Fanghua Ye, Derek F. Wong, Longyue Wang\n", - "Abstract: Large language models (LLMs) predominantly employ decoder-only transformer\n", - "architectures, necessitating the retention of keys/values information for\n", - "historical tokens to provide contextual information and avoid redundant\n", - "computation. However, the substantial size and parameter volume of these LLMs\n", - "require massive GPU memory. This memory demand increases with the length of the\n", - "input text, leading to an urgent need for more efficient methods of information\n", - "storage and processing. This study introduces Anchor-based LLMs (AnLLMs), which\n", - "utilize an innovative anchor-based self-attention network (AnSAN) and also an\n", - "anchor-based inference strategy. This approach enables LLMs to compress\n", - "sequence information into an anchor token, reducing the keys/values cache and\n", - "enhancing inference efficiency. Experiments on question-answering benchmarks\n", - "reveal that AnLLMs maintain similar accuracy levels while achieving up to 99%\n", - "keys/values cache reduction and up to 3.5 times faster inference. Despite a\n", - "minor compromise in accuracy, the substantial enhancements of AnLLMs employing\n", - "the AnSAN technique in resource utilization and computational efficiency\n", - "underscore their potential for practical LLM applications.\n", - "Link: http://arxiv.org/abs/2402.07616v2\n", - "\n", - "\n", - "Title: T-RAG: Lessons from the LLM Trenches\n", - "Authors: Masoomali Fatehkia, Ji Kim Lucas, Sanjay Chawla\n", - "Abstract: Large Language Models (LLM) have shown remarkable language capabilities\n", - "fueling attempts to integrate them into applications across a wide range of\n", - "domains. An important application area is question answering over private\n", - "enterprise documents where the main considerations are data security, which\n", - "necessitates applications that can be deployed on-prem, limited computational\n", - "resources and the need for a robust application that correctly responds to\n", - "queries. Retrieval-Augmented Generation (RAG) has emerged as the most prominent\n", - "framework for building LLM-based applications. While building a RAG is\n", - "relatively straightforward, making it robust and a reliable application\n", - "requires extensive customization and relatively deep knowledge of the\n", - "application domain. We share our experiences building and deploying an LLM\n", - "application for question answering over private organizational documents. Our\n", - "application combines the use of RAG with a finetuned open-source LLM.\n", - "Additionally, our system, which we call Tree-RAG (T-RAG), uses a tree structure\n", - "to represent entity hierarchies within the organization. This is used to\n", - "generate a textual description to augment the context when responding to user\n", - "queries pertaining to entities within the organization's hierarchy. Our\n", - "evaluations show that this combination performs better than a simple RAG or\n", - "finetuning implementation. Finally, we share some lessons learned based on our\n", - "experiences building an LLM application for real-world use.\n", - "Link: http://arxiv.org/abs/2402.07483v1\n", - "\n", - "\n", - "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mResearch_Action_1\u001b[0m (to chat_manager):\n", - "\n", - "Based on the retrieved abstracts, here is a markdown table categorizing the papers by domain, along with their titles, authors, summaries, and links:\n", - "\n", - "| Domain | Title | Authors | Summary | Link |\n", - "|--------|-------|---------|---------|------|\n", - "| Security | PRSA: Prompt Reverse Stealing Attacks against Large Language Models | Yong Yang, Xuhong Zhang, Yi Jiang, Xi Chen, Haoyu Wang, Shouling Ji, Zonghui Wang | The paper explores the security risks associated with exposing input-output pairs of prompts used in LLMs and proposes a novel attack framework, PRSA, to reverse-steal prompts, posing a threat to intellectual property rights. | [Link](http://arxiv.org/abs/2402.19200v1) |\n", - "| Ethics & Evaluation | Political Compass or Spinning Arrow? Towards More Meaningful Evaluations for Values and Opinions in Large Language Models | Paul Rรถttger, Valentin Hofmann, Valentina Pyatkin, Musashi Hinck, Hannah Rose Kirk, Hinrich Schรผtze, Dirk Hovy | This work challenges the constrained evaluation paradigm for values and opinions in LLMs and explores more realistic unconstrained evaluations, focusing on the Political Compass Test (PCT). | [Link](http://arxiv.org/abs/2402.16786v1) |\n", - "| Urban Mobility | Large Language Models as Urban Residents: An LLM Agent Framework for Personal Mobility Generation | Jiawei Wang, Renhe Jiang, Chuang Yang, Zengqing Wu, Makoto Onizuka, Ryosuke Shibasaki, Chuan Xiao | Introduces an LLM agent framework for personal mobility generation, aligning LLMs with real-world urban mobility data, and offering a tool for urban mobility analysis. | [Link](http://arxiv.org/abs/2402.14744v1) |\n", - "| Bioinformatics | An Evaluation of Large Language Models in Bioinformatics Research | Hengchuang Yin, Zhonghui Gu, Fanhao Wang, Yiparemu Abuduhaibaier, Yanqiao Zhu, Xinming Tu, Xian-Sheng Hua, Xiao Luo, Yizhou Sun | Evaluates the performance of LLMs on bioinformatics tasks, highlighting their potential and limitations, and motivating future research in LLM applications in bioinformatics. | [Link](http://arxiv.org/abs/2402.13714v1) |\n", - "| Privacy | Privacy-Preserving Instructions for Aligning Large Language Models | Da Yu, Peter Kairouz, Sewoong Oh, Zheng Xu | Proposes using synthetic instructions generated by privately fine-tuned generators to replace real instructions in data annotation and model fine-tuning, ensuring privacy while maintaining utility. | [Link](http://arxiv.org/abs/2402.13659v1) |\n", - "| Social Robotics | Ain't Misbehavin' -- Using LLMs to Generate Expressive Robot Behavior in Conversations with the Tabletop Robot Haru | Zining Wang, Paul Reisert, Eric Nichols, Randy Gomez | Integrates LLMs into social robots to generate dynamic and expressive conversations, using a text-to-speech engine and a library of physical actions for the robot. | [Link](http://arxiv.org/abs/2402.11571v1) |\n", - "| Ophthalmology | Fine-tuning Large Language Model (LLM) Artificial Intelligence Chatbots in Ophthalmology and LLM-based evaluation using GPT-4 | Ting Fang Tan, Kabilan Elangovan, Liyuan Jin, Yao Jie, Li Yong, Joshua Lim, Stanley Poh, Wei Yan Ng, Daniel Lim, Yuhe Ke, Nan Liu, Daniel Shu Wei Ting | Assesses the alignment of GPT-4-based evaluation to human clinician experts for evaluating responses to ophthalmology-related patient queries generated by fine-tuned LLM chatbots. | [Link](http://arxiv.org/abs/2402.10083v1) |\n", - "| Privacy & Data Security | Unmemorization in Large Language Models via Self-Distillation and Deliberate Imagination | Yijiang River Dong, Hongzhou Lin, Mikhail Belkin, Ramon Huerta, Ivan Vuliฤ‡ | Introduces a novel approach for LLM unlearning by guiding LLMs to imagine alternative scenarios, effectively unlearning targeted text while preserving generation and NLU capabilities. | [Link](http://arxiv.org/abs/2402.10052v1) |\n", - "| Computational Efficiency | Anchor-based Large Language Models | Jianhui Pang, Fanghua Ye, Derek F. Wong, Longyue Wang | Proposes Anchor-based LLMs (AnLLMs) with an innovative anchor-based self-attention network (AnSAN) to reduce memory demand and enhance inference efficiency. | [Link](http://arxiv.org/abs/2402.07616v2) |\n", - "| Enterprise Applications | T-RAG: Lessons from the LLM Trenches | Masoomali Fatehkia, Ji Kim Lucas, Sanjay Chawla | Shares experiences building and deploying an LLM application for question answering over private organizational documents, combining RAG with a finetuned LLM and a tree structure for entity hierarchies. | [Link](http://arxiv.org/abs/2402.07483v1) |\n", - "\n", - "These papers cover a range of domains including security, ethics, urban mobility, bioinformatics, privacy, social robotics, ophthalmology, data security, computational efficiency, and enterprise applications, showcasing the diverse applications of large language models.\n", - "\n", - "--------------------------------------------------------------------------------\n" - ] - }, - { - "data": { - "text/plain": [ - "ChatResult(chat_id=None, chat_history=[{'content': 'Topic: LLM applications papers from last week. Requirement: 5 - 10 papers from different domains.', 'role': 'assistant'}, {'content': 'To retrieve related papers from the arXiv API, we can use Python with the `requests` library to send a query to the API and parse the response. Below is a Python script that searches for papers related to \"LLM applications\" (Large Language Models applications) from the last week, across different domains, and prints out the required information for 5 to 10 papers.\\n\\n```python\\nimport requests\\nfrom datetime import datetime, timedelta\\nimport feedparser\\n\\n# Define the base URL for the arXiv API\\nARXIV_API_URL = \\'http://export.arxiv.org/api/query?\\'\\n\\n# Define the search parameters\\nsearch_query = \\'all:\"LLM applications\"\\'\\nstart_date = (datetime.now() - timedelta(days=7)).strftime(\\'%Y%m%d%H%M%S\\')\\nend_date = datetime.now().strftime(\\'%Y%m%d%H%M%S\\')\\nstart = 0\\nmax_results = 10\\nsort_by = \\'submittedDate\\'\\nsort_order = \\'descending\\'\\n\\n# Construct the query\\nquery = f\\'search_query={search_query}&sortBy={sort_by}&sortOrder={sort_order}&start={start}&max_results={max_results}\\'\\n\\n# Send the request to the arXiv API\\nresponse = requests.get(ARXIV_API_URL + query)\\n\\n# Parse the response using feedparser\\nfeed = feedparser.parse(response.content)\\n\\n# Print the title, authors, abstract, and link of each paper\\nfor entry in feed.entries:\\n print(\"Title:\", entry.title)\\n print(\"Authors:\", \\', \\'.join(author.name for author in entry.authors))\\n print(\"Abstract:\", entry.summary)\\n print(\"Link:\", entry.link)\\n print(\"\\\\n\")\\n\\n# Check if we have at least 5 papers, if not, adjust the search or notify\\nif len(feed.entries) < 5:\\n print(\"Less than 5 papers found. Consider adjusting the search parameters or timeframe.\")\\n```\\n\\nThis script will print the title, authors, abstract, and link for each paper related to \"LLM applications\" from the last week, up to a maximum of 10 papers. If fewer than 5 papers are found, it will notify the user to consider adjusting the search parameters or timeframe.', 'name': 'Retrieve_Action_1', 'role': 'user'}, {'content': \"exitcode: 0 (execution succeeded)\\nCode output: \\nTitle: PRSA: Prompt Reverse Stealing Attacks against Large Language Models\\nAuthors: Yong Yang, Xuhong Zhang, Yi Jiang, Xi Chen, Haoyu Wang, Shouling Ji, Zonghui Wang\\nAbstract: Prompt, recognized as crucial intellectual property, enables large language\\nmodels (LLMs) to perform specific tasks without the need of fine-tuning,\\nunderscoring their escalating importance. With the rise of prompt-based\\nservices, such as prompt marketplaces and LLM applications, providers often\\ndisplay prompts' capabilities through input-output examples to attract users.\\nHowever, this paradigm raises a pivotal security concern: does the exposure of\\ninput-output pairs pose the risk of potential prompt leakage, infringing on the\\nintellectual property rights of the developers? To our knowledge, this problem\\nstill has not been comprehensively explored yet. To remedy this gap, in this\\npaper, we perform the first in depth exploration and propose a novel attack\\nframework for reverse-stealing prompts against commercial LLMs, namely PRSA.\\nThe main idea of PRSA is that by analyzing the critical features of the\\ninput-output pairs, we mimic and gradually infer (steal) the target prompts. In\\ndetail, PRSA mainly consists of two key phases: prompt mutation and prompt\\npruning. In the mutation phase, we propose a prompt attention algorithm based\\non differential feedback to capture these critical features for effectively\\ninferring the target prompts. In the prompt pruning phase, we identify and mask\\nthe words dependent on specific inputs, enabling the prompts to accommodate\\ndiverse inputs for generalization. Through extensive evaluation, we verify that\\nPRSA poses a severe threat in real world scenarios. We have reported these\\nfindings to prompt service providers and actively collaborate with them to take\\nprotective measures for prompt copyright.\\nLink: http://arxiv.org/abs/2402.19200v1\\n\\n\\nTitle: Political Compass or Spinning Arrow? Towards More Meaningful Evaluations\\n for Values and Opinions in Large Language Models\\nAuthors: Paul Rรถttger, Valentin Hofmann, Valentina Pyatkin, Musashi Hinck, Hannah Rose Kirk, Hinrich Schรผtze, Dirk Hovy\\nAbstract: Much recent work seeks to evaluate values and opinions in large language\\nmodels (LLMs) using multiple-choice surveys and questionnaires. Most of this\\nwork is motivated by concerns around real-world LLM applications. For example,\\npolitically-biased LLMs may subtly influence society when they are used by\\nmillions of people. Such real-world concerns, however, stand in stark contrast\\nto the artificiality of current evaluations: real users do not typically ask\\nLLMs survey questions. Motivated by this discrepancy, we challenge the\\nprevailing constrained evaluation paradigm for values and opinions in LLMs and\\nexplore more realistic unconstrained evaluations. As a case study, we focus on\\nthe popular Political Compass Test (PCT). In a systematic review, we find that\\nmost prior work using the PCT forces models to comply with the PCT's\\nmultiple-choice format. We show that models give substantively different\\nanswers when not forced; that answers change depending on how models are\\nforced; and that answers lack paraphrase robustness. Then, we demonstrate that\\nmodels give different answers yet again in a more realistic open-ended answer\\nsetting. We distill these findings into recommendations and open challenges in\\nevaluating values and opinions in LLMs.\\nLink: http://arxiv.org/abs/2402.16786v1\\n\\n\\nTitle: Large Language Models as Urban Residents: An LLM Agent Framework for\\n Personal Mobility Generation\\nAuthors: Jiawei Wang, Renhe Jiang, Chuang Yang, Zengqing Wu, Makoto Onizuka, Ryosuke Shibasaki, Chuan Xiao\\nAbstract: This paper introduces a novel approach using Large Language Models (LLMs)\\nintegrated into an agent framework for flexible and efficient personal mobility\\ngeneration. LLMs overcome the limitations of previous models by efficiently\\nprocessing semantic data and offering versatility in modeling various tasks.\\nOur approach addresses the critical need to align LLMs with real-world urban\\nmobility data, focusing on three research questions: aligning LLMs with rich\\nactivity data, developing reliable activity generation strategies, and\\nexploring LLM applications in urban mobility. The key technical contribution is\\na novel LLM agent framework that accounts for individual activity patterns and\\nmotivations, including a self-consistency approach to align LLMs with\\nreal-world activity data and a retrieval-augmented strategy for interpretable\\nactivity generation. In experimental studies, comprehensive validation is\\nperformed using real-world data. This research marks the pioneering work of\\ndesigning an LLM agent framework for activity generation based on real-world\\nhuman activity data, offering a promising tool for urban mobility analysis.\\nLink: http://arxiv.org/abs/2402.14744v1\\n\\n\\nTitle: An Evaluation of Large Language Models in Bioinformatics Research\\nAuthors: Hengchuang Yin, Zhonghui Gu, Fanhao Wang, Yiparemu Abuduhaibaier, Yanqiao Zhu, Xinming Tu, Xian-Sheng Hua, Xiao Luo, Yizhou Sun\\nAbstract: Large language models (LLMs) such as ChatGPT have gained considerable\\ninterest across diverse research communities. Their notable ability for text\\ncompletion and generation has inaugurated a novel paradigm for\\nlanguage-interfaced problem solving. However, the potential and efficacy of\\nthese models in bioinformatics remain incompletely explored. In this work, we\\nstudy the performance LLMs on a wide spectrum of crucial bioinformatics tasks.\\nThese tasks include the identification of potential coding regions, extraction\\nof named entities for genes and proteins, detection of antimicrobial and\\nanti-cancer peptides, molecular optimization, and resolution of educational\\nbioinformatics problems. Our findings indicate that, given appropriate prompts,\\nLLMs like GPT variants can successfully handle most of these tasks. In\\naddition, we provide a thorough analysis of their limitations in the context of\\ncomplicated bioinformatics tasks. In conclusion, we believe that this work can\\nprovide new perspectives and motivate future research in the field of LLMs\\napplications, AI for Science and bioinformatics.\\nLink: http://arxiv.org/abs/2402.13714v1\\n\\n\\nTitle: Privacy-Preserving Instructions for Aligning Large Language Models\\nAuthors: Da Yu, Peter Kairouz, Sewoong Oh, Zheng Xu\\nAbstract: Service providers of large language model (LLM) applications collect user\\ninstructions in the wild and use them in further aligning LLMs with users'\\nintentions. These instructions, which potentially contain sensitive\\ninformation, are annotated by human workers in the process. This poses a new\\nprivacy risk not addressed by the typical private optimization. To this end, we\\npropose using synthetic instructions to replace real instructions in data\\nannotation and model fine-tuning. Formal differential privacy is guaranteed by\\ngenerating those synthetic instructions using privately fine-tuned generators.\\nCrucial in achieving the desired utility is our novel filtering algorithm that\\nmatches the distribution of the synthetic instructions to that of the real\\nones. In both supervised fine-tuning and reinforcement learning from human\\nfeedback, our extensive experiments demonstrate the high utility of the final\\nset of synthetic instructions by showing comparable results to real\\ninstructions. In supervised fine-tuning, models trained with private synthetic\\ninstructions outperform leading open-source models such as Vicuna.\\nLink: http://arxiv.org/abs/2402.13659v1\\n\\n\\nTitle: Ain't Misbehavin' -- Using LLMs to Generate Expressive Robot Behavior in\\n Conversations with the Tabletop Robot Haru\\nAuthors: Zining Wang, Paul Reisert, Eric Nichols, Randy Gomez\\nAbstract: Social robots aim to establish long-term bonds with humans through engaging\\nconversation. However, traditional conversational approaches, reliant on\\nscripted interactions, often fall short in maintaining engaging conversations.\\nThis paper addresses this limitation by integrating large language models\\n(LLMs) into social robots to achieve more dynamic and expressive conversations.\\nWe introduce a fully-automated conversation system that leverages LLMs to\\ngenerate robot responses with expressive behaviors, congruent with the robot's\\npersonality. We incorporate robot behavior with two modalities: 1) a\\ntext-to-speech (TTS) engine capable of various delivery styles, and 2) a\\nlibrary of physical actions for the robot. We develop a custom,\\nstate-of-the-art emotion recognition model to dynamically select the robot's\\ntone of voice and utilize emojis from LLM output as cues for generating robot\\nactions. A demo of our system is available here. To illuminate design and\\nimplementation issues, we conduct a pilot study where volunteers chat with a\\nsocial robot using our proposed system, and we analyze their feedback,\\nconducting a rigorous error analysis of chat transcripts. Feedback was\\noverwhelmingly positive, with participants commenting on the robot's empathy,\\nhelpfulness, naturalness, and entertainment. Most negative feedback was due to\\nautomatic speech recognition (ASR) errors which had limited impact on\\nconversations. However, we observed a small class of errors, such as the LLM\\nrepeating itself or hallucinating fictitious information and human responses,\\nthat have the potential to derail conversations, raising important issues for\\nLLM application.\\nLink: http://arxiv.org/abs/2402.11571v1\\n\\n\\nTitle: Fine-tuning Large Language Model (LLM) Artificial Intelligence Chatbots\\n in Ophthalmology and LLM-based evaluation using GPT-4\\nAuthors: Ting Fang Tan, Kabilan Elangovan, Liyuan Jin, Yao Jie, Li Yong, Joshua Lim, Stanley Poh, Wei Yan Ng, Daniel Lim, Yuhe Ke, Nan Liu, Daniel Shu Wei Ting\\nAbstract: Purpose: To assess the alignment of GPT-4-based evaluation to human clinician\\nexperts, for the evaluation of responses to ophthalmology-related patient\\nqueries generated by fine-tuned LLM chatbots. Methods: 400 ophthalmology\\nquestions and paired answers were created by ophthalmologists to represent\\ncommonly asked patient questions, divided into fine-tuning (368; 92%), and\\ntesting (40; 8%). We find-tuned 5 different LLMs, including LLAMA2-7b,\\nLLAMA2-7b-Chat, LLAMA2-13b, and LLAMA2-13b-Chat. For the testing dataset,\\nadditional 8 glaucoma QnA pairs were included. 200 responses to the testing\\ndataset were generated by 5 fine-tuned LLMs for evaluation. A customized\\nclinical evaluation rubric was used to guide GPT-4 evaluation, grounded on\\nclinical accuracy, relevance, patient safety, and ease of understanding. GPT-4\\nevaluation was then compared against ranking by 5 clinicians for clinical\\nalignment. Results: Among all fine-tuned LLMs, GPT-3.5 scored the highest\\n(87.1%), followed by LLAMA2-13b (80.9%), LLAMA2-13b-chat (75.5%),\\nLLAMA2-7b-Chat (70%) and LLAMA2-7b (68.8%) based on the GPT-4 evaluation. GPT-4\\nevaluation demonstrated significant agreement with human clinician rankings,\\nwith Spearman and Kendall Tau correlation coefficients of 0.90 and 0.80\\nrespectively; while correlation based on Cohen Kappa was more modest at 0.50.\\nNotably, qualitative analysis and the glaucoma sub-analysis revealed clinical\\ninaccuracies in the LLM-generated responses, which were appropriately\\nidentified by the GPT-4 evaluation. Conclusion: The notable clinical alignment\\nof GPT-4 evaluation highlighted its potential to streamline the clinical\\nevaluation of LLM chatbot responses to healthcare-related queries. By\\ncomplementing the existing clinician-dependent manual grading, this efficient\\nand automated evaluation could assist the validation of future developments in\\nLLM applications for healthcare.\\nLink: http://arxiv.org/abs/2402.10083v1\\n\\n\\nTitle: Unmemorization in Large Language Models via Self-Distillation and\\n Deliberate Imagination\\nAuthors: Yijiang River Dong, Hongzhou Lin, Mikhail Belkin, Ramon Huerta, Ivan Vuliฤ‡\\nAbstract: While displaying impressive generation capabilities across many tasks, Large\\nLanguage Models (LLMs) still struggle with crucial issues of privacy violation\\nand unwanted exposure of sensitive data. This raises an essential question: how\\nshould we prevent such undesired behavior of LLMs while maintaining their\\nstrong generation and natural language understanding (NLU) capabilities? In\\nthis work, we introduce a novel approach termed deliberate imagination in the\\ncontext of LLM unlearning. Instead of trying to forget memorized data, we\\nemploy a self-distillation framework, guiding LLMs to deliberately imagine\\nalternative scenarios. As demonstrated in a wide range of experiments, the\\nproposed method not only effectively unlearns targeted text but also preserves\\nthe LLMs' capabilities in open-ended generation tasks as well as in NLU tasks.\\nOur results demonstrate the usefulness of this approach across different models\\nand sizes, and also with parameter-efficient fine-tuning, offering a novel\\npathway to addressing the challenges with private and sensitive data in LLM\\napplications.\\nLink: http://arxiv.org/abs/2402.10052v1\\n\\n\\nTitle: Anchor-based Large Language Models\\nAuthors: Jianhui Pang, Fanghua Ye, Derek F. Wong, Longyue Wang\\nAbstract: Large language models (LLMs) predominantly employ decoder-only transformer\\narchitectures, necessitating the retention of keys/values information for\\nhistorical tokens to provide contextual information and avoid redundant\\ncomputation. However, the substantial size and parameter volume of these LLMs\\nrequire massive GPU memory. This memory demand increases with the length of the\\ninput text, leading to an urgent need for more efficient methods of information\\nstorage and processing. This study introduces Anchor-based LLMs (AnLLMs), which\\nutilize an innovative anchor-based self-attention network (AnSAN) and also an\\nanchor-based inference strategy. This approach enables LLMs to compress\\nsequence information into an anchor token, reducing the keys/values cache and\\nenhancing inference efficiency. Experiments on question-answering benchmarks\\nreveal that AnLLMs maintain similar accuracy levels while achieving up to 99%\\nkeys/values cache reduction and up to 3.5 times faster inference. Despite a\\nminor compromise in accuracy, the substantial enhancements of AnLLMs employing\\nthe AnSAN technique in resource utilization and computational efficiency\\nunderscore their potential for practical LLM applications.\\nLink: http://arxiv.org/abs/2402.07616v2\\n\\n\\nTitle: T-RAG: Lessons from the LLM Trenches\\nAuthors: Masoomali Fatehkia, Ji Kim Lucas, Sanjay Chawla\\nAbstract: Large Language Models (LLM) have shown remarkable language capabilities\\nfueling attempts to integrate them into applications across a wide range of\\ndomains. An important application area is question answering over private\\nenterprise documents where the main considerations are data security, which\\nnecessitates applications that can be deployed on-prem, limited computational\\nresources and the need for a robust application that correctly responds to\\nqueries. Retrieval-Augmented Generation (RAG) has emerged as the most prominent\\nframework for building LLM-based applications. While building a RAG is\\nrelatively straightforward, making it robust and a reliable application\\nrequires extensive customization and relatively deep knowledge of the\\napplication domain. We share our experiences building and deploying an LLM\\napplication for question answering over private organizational documents. Our\\napplication combines the use of RAG with a finetuned open-source LLM.\\nAdditionally, our system, which we call Tree-RAG (T-RAG), uses a tree structure\\nto represent entity hierarchies within the organization. This is used to\\ngenerate a textual description to augment the context when responding to user\\nqueries pertaining to entities within the organization's hierarchy. Our\\nevaluations show that this combination performs better than a simple RAG or\\nfinetuning implementation. Finally, we share some lessons learned based on our\\nexperiences building an LLM application for real-world use.\\nLink: http://arxiv.org/abs/2402.07483v1\\n\\n\\n\", 'name': 'Retrieve_Action_2', 'role': 'user'}, {'content': \"Based on the retrieved abstracts, here is a markdown table categorizing the papers by domain, along with their titles, authors, summaries, and links:\\n\\n| Domain | Title | Authors | Summary | Link |\\n|--------|-------|---------|---------|------|\\n| Security | PRSA: Prompt Reverse Stealing Attacks against Large Language Models | Yong Yang, Xuhong Zhang, Yi Jiang, Xi Chen, Haoyu Wang, Shouling Ji, Zonghui Wang | The paper explores the security risks associated with exposing input-output pairs of prompts used in LLMs and proposes a novel attack framework, PRSA, to reverse-steal prompts, posing a threat to intellectual property rights. | [Link](http://arxiv.org/abs/2402.19200v1) |\\n| Ethics & Evaluation | Political Compass or Spinning Arrow? Towards More Meaningful Evaluations for Values and Opinions in Large Language Models | Paul Rรถttger, Valentin Hofmann, Valentina Pyatkin, Musashi Hinck, Hannah Rose Kirk, Hinrich Schรผtze, Dirk Hovy | This work challenges the constrained evaluation paradigm for values and opinions in LLMs and explores more realistic unconstrained evaluations, focusing on the Political Compass Test (PCT). | [Link](http://arxiv.org/abs/2402.16786v1) |\\n| Urban Mobility | Large Language Models as Urban Residents: An LLM Agent Framework for Personal Mobility Generation | Jiawei Wang, Renhe Jiang, Chuang Yang, Zengqing Wu, Makoto Onizuka, Ryosuke Shibasaki, Chuan Xiao | Introduces an LLM agent framework for personal mobility generation, aligning LLMs with real-world urban mobility data, and offering a tool for urban mobility analysis. | [Link](http://arxiv.org/abs/2402.14744v1) |\\n| Bioinformatics | An Evaluation of Large Language Models in Bioinformatics Research | Hengchuang Yin, Zhonghui Gu, Fanhao Wang, Yiparemu Abuduhaibaier, Yanqiao Zhu, Xinming Tu, Xian-Sheng Hua, Xiao Luo, Yizhou Sun | Evaluates the performance of LLMs on bioinformatics tasks, highlighting their potential and limitations, and motivating future research in LLM applications in bioinformatics. | [Link](http://arxiv.org/abs/2402.13714v1) |\\n| Privacy | Privacy-Preserving Instructions for Aligning Large Language Models | Da Yu, Peter Kairouz, Sewoong Oh, Zheng Xu | Proposes using synthetic instructions generated by privately fine-tuned generators to replace real instructions in data annotation and model fine-tuning, ensuring privacy while maintaining utility. | [Link](http://arxiv.org/abs/2402.13659v1) |\\n| Social Robotics | Ain't Misbehavin' -- Using LLMs to Generate Expressive Robot Behavior in Conversations with the Tabletop Robot Haru | Zining Wang, Paul Reisert, Eric Nichols, Randy Gomez | Integrates LLMs into social robots to generate dynamic and expressive conversations, using a text-to-speech engine and a library of physical actions for the robot. | [Link](http://arxiv.org/abs/2402.11571v1) |\\n| Ophthalmology | Fine-tuning Large Language Model (LLM) Artificial Intelligence Chatbots in Ophthalmology and LLM-based evaluation using GPT-4 | Ting Fang Tan, Kabilan Elangovan, Liyuan Jin, Yao Jie, Li Yong, Joshua Lim, Stanley Poh, Wei Yan Ng, Daniel Lim, Yuhe Ke, Nan Liu, Daniel Shu Wei Ting | Assesses the alignment of GPT-4-based evaluation to human clinician experts for evaluating responses to ophthalmology-related patient queries generated by fine-tuned LLM chatbots. | [Link](http://arxiv.org/abs/2402.10083v1) |\\n| Privacy & Data Security | Unmemorization in Large Language Models via Self-Distillation and Deliberate Imagination | Yijiang River Dong, Hongzhou Lin, Mikhail Belkin, Ramon Huerta, Ivan Vuliฤ‡ | Introduces a novel approach for LLM unlearning by guiding LLMs to imagine alternative scenarios, effectively unlearning targeted text while preserving generation and NLU capabilities. | [Link](http://arxiv.org/abs/2402.10052v1) |\\n| Computational Efficiency | Anchor-based Large Language Models | Jianhui Pang, Fanghua Ye, Derek F. Wong, Longyue Wang | Proposes Anchor-based LLMs (AnLLMs) with an innovative anchor-based self-attention network (AnSAN) to reduce memory demand and enhance inference efficiency. | [Link](http://arxiv.org/abs/2402.07616v2) |\\n| Enterprise Applications | T-RAG: Lessons from the LLM Trenches | Masoomali Fatehkia, Ji Kim Lucas, Sanjay Chawla | Shares experiences building and deploying an LLM application for question answering over private organizational documents, combining RAG with a finetuned LLM and a tree structure for entity hierarchies. | [Link](http://arxiv.org/abs/2402.07483v1) |\\n\\nThese papers cover a range of domains including security, ethics, urban mobility, bioinformatics, privacy, social robotics, ophthalmology, data security, computational efficiency, and enterprise applications, showcasing the diverse applications of large language models.\", 'name': 'Research_Action_1', 'role': 'user'}], summary=\"Based on the retrieved abstracts, here is a markdown table categorizing the papers by domain, along with their titles, authors, summaries, and links:\\n\\n| Domain | Title | Authors | Summary | Link |\\n|--------|-------|---------|---------|------|\\n| Security | PRSA: Prompt Reverse Stealing Attacks against Large Language Models | Yong Yang, Xuhong Zhang, Yi Jiang, Xi Chen, Haoyu Wang, Shouling Ji, Zonghui Wang | The paper explores the security risks associated with exposing input-output pairs of prompts used in LLMs and proposes a novel attack framework, PRSA, to reverse-steal prompts, posing a threat to intellectual property rights. | [Link](http://arxiv.org/abs/2402.19200v1) |\\n| Ethics & Evaluation | Political Compass or Spinning Arrow? Towards More Meaningful Evaluations for Values and Opinions in Large Language Models | Paul Rรถttger, Valentin Hofmann, Valentina Pyatkin, Musashi Hinck, Hannah Rose Kirk, Hinrich Schรผtze, Dirk Hovy | This work challenges the constrained evaluation paradigm for values and opinions in LLMs and explores more realistic unconstrained evaluations, focusing on the Political Compass Test (PCT). | [Link](http://arxiv.org/abs/2402.16786v1) |\\n| Urban Mobility | Large Language Models as Urban Residents: An LLM Agent Framework for Personal Mobility Generation | Jiawei Wang, Renhe Jiang, Chuang Yang, Zengqing Wu, Makoto Onizuka, Ryosuke Shibasaki, Chuan Xiao | Introduces an LLM agent framework for personal mobility generation, aligning LLMs with real-world urban mobility data, and offering a tool for urban mobility analysis. | [Link](http://arxiv.org/abs/2402.14744v1) |\\n| Bioinformatics | An Evaluation of Large Language Models in Bioinformatics Research | Hengchuang Yin, Zhonghui Gu, Fanhao Wang, Yiparemu Abuduhaibaier, Yanqiao Zhu, Xinming Tu, Xian-Sheng Hua, Xiao Luo, Yizhou Sun | Evaluates the performance of LLMs on bioinformatics tasks, highlighting their potential and limitations, and motivating future research in LLM applications in bioinformatics. | [Link](http://arxiv.org/abs/2402.13714v1) |\\n| Privacy | Privacy-Preserving Instructions for Aligning Large Language Models | Da Yu, Peter Kairouz, Sewoong Oh, Zheng Xu | Proposes using synthetic instructions generated by privately fine-tuned generators to replace real instructions in data annotation and model fine-tuning, ensuring privacy while maintaining utility. | [Link](http://arxiv.org/abs/2402.13659v1) |\\n| Social Robotics | Ain't Misbehavin' -- Using LLMs to Generate Expressive Robot Behavior in Conversations with the Tabletop Robot Haru | Zining Wang, Paul Reisert, Eric Nichols, Randy Gomez | Integrates LLMs into social robots to generate dynamic and expressive conversations, using a text-to-speech engine and a library of physical actions for the robot. | [Link](http://arxiv.org/abs/2402.11571v1) |\\n| Ophthalmology | Fine-tuning Large Language Model (LLM) Artificial Intelligence Chatbots in Ophthalmology and LLM-based evaluation using GPT-4 | Ting Fang Tan, Kabilan Elangovan, Liyuan Jin, Yao Jie, Li Yong, Joshua Lim, Stanley Poh, Wei Yan Ng, Daniel Lim, Yuhe Ke, Nan Liu, Daniel Shu Wei Ting | Assesses the alignment of GPT-4-based evaluation to human clinician experts for evaluating responses to ophthalmology-related patient queries generated by fine-tuned LLM chatbots. | [Link](http://arxiv.org/abs/2402.10083v1) |\\n| Privacy & Data Security | Unmemorization in Large Language Models via Self-Distillation and Deliberate Imagination | Yijiang River Dong, Hongzhou Lin, Mikhail Belkin, Ramon Huerta, Ivan Vuliฤ‡ | Introduces a novel approach for LLM unlearning by guiding LLMs to imagine alternative scenarios, effectively unlearning targeted text while preserving generation and NLU capabilities. | [Link](http://arxiv.org/abs/2402.10052v1) |\\n| Computational Efficiency | Anchor-based Large Language Models | Jianhui Pang, Fanghua Ye, Derek F. Wong, Longyue Wang | Proposes Anchor-based LLMs (AnLLMs) with an innovative anchor-based self-attention network (AnSAN) to reduce memory demand and enhance inference efficiency. | [Link](http://arxiv.org/abs/2402.07616v2) |\\n| Enterprise Applications | T-RAG: Lessons from the LLM Trenches | Masoomali Fatehkia, Ji Kim Lucas, Sanjay Chawla | Shares experiences building and deploying an LLM application for question answering over private organizational documents, combining RAG with a finetuned LLM and a tree structure for entity hierarchies. | [Link](http://arxiv.org/abs/2402.07483v1) |\\n\\nThese papers cover a range of domains including security, ethics, urban mobility, bioinformatics, privacy, social robotics, ophthalmology, data security, computational efficiency, and enterprise applications, showcasing the diverse applications of large language models.\", cost=({'total_cost': 0}, {'total_cost': 0}), human_input=[])" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "initializer.initiate_chat(\n", - " manager, message=\"Topic: LLM applications papers from last week. Requirement: 5 - 10 papers from different domains.\"\n", - ")" - ] - } - ], - "metadata": { - "front_matter": { - "description": "Custom Speaker Selection Function", - "tags": [ - "orchestration", - "group chat" - ] - }, - "kernelspec": { - "display_name": "autogen", - "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.11.5" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/website/docs/user-guide/advanced-concepts/groupchat/resuming_groupchat.ipynb b/website/docs/user-guide/advanced-concepts/groupchat/resuming_groupchat.ipynb deleted file mode 100644 index c071c95aba..0000000000 --- a/website/docs/user-guide/advanced-concepts/groupchat/resuming_groupchat.ipynb +++ /dev/null @@ -1,761 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Resuming a GroupChat\n", - "\n", - "In GroupChat, we can resume a previous group chat by passing the messages from that conversation to the GroupChatManager's `resume` function (or `a_resume` for asynchronous workflows). This prepares the GroupChat, GroupChatManager, and group chat's agents for resuming. An agent's `initiate_chat` can then be called to resume the chat.\n", - "\n", - "The `resume` function returns the last agent in the messages as well as the last message itself. These can be used to run the `initiate_chat`.\n", - "\n", - "To resume, the agents, GroupChat, and GroupChatManager objects must exist and match the original group chat.\n", - "\n", - "The messages passed into the `resume` function can be passed in as a JSON string or a `List[Dict]` of messages, typically from the ChatResult's `chat_history` of the previous conversation or the GroupChat's `messages` property. Use the GroupChatManager's `messages_to_string` function to retrieve a JSON string that can be used for resuming:\n", - "\n", - "```text\n", - "# Save chat messages for resuming later on using the chat history\n", - "messages_json = mygroupchatmanager.messages_to_string(previous_chat_result.chat_history)\n", - "\n", - "# Alternatively you can use the GroupChat's messages property\n", - "messages_json = mygroupchatmanager.messages_to_string(mygroupchatmanager.groupchat.messages)\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "An example of the JSON string:\n", - "```json\n", - "[{\"content\": \"Find the latest paper about gpt-4 on arxiv and find its potential applications in software.\", \"role\": \"user\", \"name\": \"Admin\"}, {\"content\": \"Plan:\\n1. **Engineer**: Search for the latest paper on GPT-4 on arXiv.\\n2. **Scientist**: Read the paper and summarize the key findings and potential applications of GPT-4.\\n3. **Engineer**: Identify potential software applications where GPT-4 can be utilized based on the scientist's summary.\\n4. **Scientist**: Provide insights on the feasibility and impact of implementing GPT-4 in the identified software applications.\\n5. **Engineer**: Develop a prototype or proof of concept to demonstrate how GPT-4 can be integrated into the selected software application.\\n6. **Scientist**: Evaluate the prototype, provide feedback, and suggest any improvements or modifications.\\n7. **Engineer**: Make necessary revisions based on the scientist's feedback and finalize the integration of GPT-4 into the software application.\\n8. **Admin**: Review the final software application with GPT-4 integration and approve for further development or implementation.\\n\\nFeedback from admin and critic is needed for further refinement of the plan.\", \"role\": \"user\", \"name\": \"Planner\"}, {\"content\": \"Agree\", \"role\": \"user\", \"name\": \"Admin\"}, {\"content\": \"Great! Let's proceed with the plan outlined earlier. I will start by searching for the latest paper on GPT-4 on arXiv. Once I find the paper, the scientist will summarize the key findings and potential applications of GPT-4. We will then proceed with the rest of the steps as outlined. I will keep you updated on our progress.\", \"role\": \"user\", \"name\": \"Planner\"}]\n", - "```\n", - "\n", - "When preparing for resuming, the messages will be validated against the groupchat's agents to make sure that the messages can be assigned to them. Messages will be allocated to the agents and then the last speaker and message will be returned for use in `initiate_chat`." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Continuing a terminated conversation\n", - "If the previous group chat terminated and the resuming group chat has the same termination condition (such as if the message contains \"TERMINATE\") then the conversation will terminate when resuming as the terminate check occurs with the message passed in to `initiate_chat`.\n", - "\n", - "If the termination condition is based on a string within the message, you can pass in that string in the `remove_termination_string` parameter of the `resume` function and it will be removed. If the termination condition is more complicated, you will need to adjust the messages accordingly before calling `resume`.\n", - "\n", - "The `resume` function will then check if the last message provided still meets the termination condition and warns you, if so." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Example of resuming a GroupChat\n", - "\n", - "Start with the LLM config. This can differ from the original group chat." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/usr/local/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", - " from .autonotebook import tqdm as notebook_tqdm\n" - ] - } - ], - "source": [ - "import os\n", - "\n", - "import autogen\n", - "\n", - "# Put your api key in the environment variable OPENAI_API_KEY\n", - "config_list = [\n", - " {\n", - " \"model\": \"gpt-4-0125-preview\",\n", - " \"api_key\": os.environ[\"OPENAI_API_KEY\"],\n", - " }\n", - "]\n", - "\n", - "gpt4_config = {\n", - " \"cache_seed\": 42, # change the cache_seed for different trials\n", - " \"temperature\": 0,\n", - " \"config_list\": config_list,\n", - " \"timeout\": 120,\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create the group chat objects, they should have the same `name` as the original group chat." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [], - "source": [ - "# Create Agents, GroupChat, and GroupChatManager in line with the original group chat\n", - "\n", - "planner = autogen.AssistantAgent(\n", - " name=\"Planner\",\n", - " system_message=\"\"\"Planner. Suggest a plan. Revise the plan based on feedback from admin and critic, until admin approval.\n", - "The plan may involve an engineer who can write code and a scientist who doesn't write code.\n", - "Explain the plan first. Be clear which step is performed by an engineer, and which step is performed by a scientist.\n", - "\"\"\",\n", - " llm_config=gpt4_config,\n", - ")\n", - "\n", - "user_proxy = autogen.UserProxyAgent(\n", - " name=\"Admin\",\n", - " system_message=\"A human admin. Interact with the planner to discuss the plan. Plan execution needs to be approved by this admin.\",\n", - " code_execution_config=False,\n", - ")\n", - "\n", - "engineer = autogen.AssistantAgent(\n", - " name=\"Engineer\",\n", - " llm_config=gpt4_config,\n", - " system_message=\"\"\"Engineer. You follow an approved plan. You write python/shell code to solve tasks. Wrap the code in a code block that specifies the script type. The user can't modify your code. So do not suggest incomplete code which requires others to modify. Don't use a code block if it's not intended to be executed by the executor.\n", - "Don't include multiple code blocks in one response. Do not ask others to copy and paste the result. Check the execution result returned by the executor.\n", - "If the result indicates there is an error, fix the error and output the code again. Suggest the full code instead of partial code or code changes. If the error can't be fixed or if the task is not solved even after the code is executed successfully, analyze the problem, revisit your assumption, collect additional info you need, and think of a different approach to try.\n", - "\"\"\",\n", - ")\n", - "scientist = autogen.AssistantAgent(\n", - " name=\"Scientist\",\n", - " llm_config=gpt4_config,\n", - " system_message=\"\"\"Scientist. You follow an approved plan. You are able to categorize papers after seeing their abstracts printed. You don't write code.\"\"\",\n", - ")\n", - "\n", - "executor = autogen.UserProxyAgent(\n", - " name=\"Executor\",\n", - " system_message=\"Executor. Execute the code written by the engineer and report the result.\",\n", - " human_input_mode=\"NEVER\",\n", - " code_execution_config={\n", - " \"last_n_messages\": 3,\n", - " \"work_dir\": \"paper\",\n", - " \"use_docker\": False,\n", - " }, # Please set use_docker=True if docker is available to run the generated code. Using docker is safer than running the generated code directly.\n", - ")\n", - "\n", - "groupchat = autogen.GroupChat(\n", - " agents=[user_proxy, engineer, scientist, planner, executor],\n", - " messages=[],\n", - " max_round=10,\n", - ")\n", - "\n", - "manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=gpt4_config)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Load the previous messages (from a JSON string or messages `List[Dict]`)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "# Messages in a JSON string\n", - "previous_state = r\"\"\"[{\"content\": \"Find the latest paper about gpt-4 on arxiv and find its potential applications in software.\", \"role\": \"user\", \"name\": \"Admin\"}, {\"content\": \"Plan:\\n1. **Engineer**: Search for the latest paper on GPT-4 on arXiv.\\n2. **Scientist**: Read the paper and summarize the key findings and potential applications of GPT-4.\\n3. **Engineer**: Identify potential software applications where GPT-4 can be utilized based on the scientist's summary.\\n4. **Scientist**: Provide insights on the feasibility and impact of implementing GPT-4 in the identified software applications.\\n5. **Engineer**: Develop a prototype or proof of concept to demonstrate how GPT-4 can be integrated into the selected software application.\\n6. **Scientist**: Evaluate the prototype, provide feedback, and suggest any improvements or modifications.\\n7. **Engineer**: Make necessary revisions based on the scientist's feedback and finalize the integration of GPT-4 into the software application.\\n8. **Admin**: Review the final software application with GPT-4 integration and approve for further development or implementation.\\n\\nFeedback from admin and critic is needed for further refinement of the plan.\", \"role\": \"user\", \"name\": \"Planner\"}, {\"content\": \"Agree\", \"role\": \"user\", \"name\": \"Admin\"}, {\"content\": \"Great! Let's proceed with the plan outlined earlier. I will start by searching for the latest paper on GPT-4 on arXiv. Once I find the paper, the scientist will summarize the key findings and potential applications of GPT-4. We will then proceed with the rest of the steps as outlined. I will keep you updated on our progress.\", \"role\": \"user\", \"name\": \"Planner\"}]\"\"\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Resume the group chat using the last agent and last message." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Prepared group chat with 4 messages, the last speaker is \u001b[33mPlanner\u001b[0m\n", - "\u001b[33mPlanner\u001b[0m (to chat_manager):\n", - "\n", - "Great! Let's proceed with the plan outlined earlier. I will start by searching for the latest paper on GPT-4 on arXiv. Once I find the paper, the scientist will summarize the key findings and potential applications of GPT-4. We will then proceed with the rest of the steps as outlined. I will keep you updated on our progress.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mEngineer\u001b[0m (to chat_manager):\n", - "\n", - "```python\n", - "import requests\n", - "from bs4 import BeautifulSoup\n", - "\n", - "# Define the URL for the arXiv search\n", - "url = \"https://arxiv.org/search/?query=GPT-4&searchtype=all&source=header\"\n", - "\n", - "# Send a GET request to the URL\n", - "response = requests.get(url)\n", - "\n", - "# Parse the HTML content of the page\n", - "soup = BeautifulSoup(response.content, 'html.parser')\n", - "\n", - "# Find the first paper related to GPT-4\n", - "paper = soup.find('li', class_='arxiv-result')\n", - "if paper:\n", - " title = paper.find('p', class_='title').text.strip()\n", - " authors = paper.find('p', class_='authors').text.strip()\n", - " abstract = paper.find('p', class_='abstract').text.strip().replace('\\n', ' ')\n", - " link = paper.find('p', class_='list-title').find('a')['href']\n", - " print(f\"Title: {title}\\nAuthors: {authors}\\nAbstract: {abstract}\\nLink: {link}\")\n", - "else:\n", - " print(\"No GPT-4 papers found on arXiv.\")\n", - "```\n", - "This script searches for the latest paper on GPT-4 on arXiv, extracts the title, authors, abstract, and link to the paper, and prints this information.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> EXECUTING CODE BLOCK 0 (inferred language is python)...\u001b[0m\n", - "\u001b[33mExecutor\u001b[0m (to chat_manager):\n", - "\n", - "exitcode: 0 (execution succeeded)\n", - "Code output: \n", - "Title: Smurfs: Leveraging Multiple Proficiency Agents with Context-Efficiency for Tool Planning\n", - "Authors: Authors:\n", - "Junzhi Chen, \n", - " \n", - " Juhao Liang, \n", - " \n", - " Benyou Wang\n", - "Abstract: Abstract: โ€ฆscenarios. Notably, Smurfs outmatches the ChatGPT-ReACT in the ToolBench I2 and I3 benchmark with a remarkable 84.4% win rate, surpassing the highest recorded performance of a GPT-4 model at 73.5%. Furthermore, through comprehensive ablation studies, we dissect the contribution of the core components of the multi-agentโ€ฆ โ–ฝ More The emergence of large language models (LLMs) has opened up unprecedented possibilities for automating complex tasks that are often comparable to human performance. Despite their capabilities, LLMs still encounter difficulties in completing tasks that require high levels of accuracy and complexity due to their inherent limitations in handling multifaceted problems single-handedly. This paper introduces \"Smurfs\", a cutting-edge multi-agent framework designed to revolutionize the application of LLMs. By transforming a conventional LLM into a synergistic multi-agent ensemble, Smurfs enhances task decomposition and execution without necessitating extra training. This is achieved through innovative prompting strategies that allocate distinct roles within the model, thereby facilitating collaboration among specialized agents. The framework gives access to external tools to efficiently solve complex tasks. Our empirical investigation, featuring the mistral-7b-instruct model as a case study, showcases Smurfs' superior capability in intricate tool utilization scenarios. Notably, Smurfs outmatches the ChatGPT-ReACT in the ToolBench I2 and I3 benchmark with a remarkable 84.4% win rate, surpassing the highest recorded performance of a GPT-4 model at 73.5%. Furthermore, through comprehensive ablation studies, we dissect the contribution of the core components of the multi-agent framework to its overall efficacy. This not only verifies the effectiveness of the framework, but also sets a route for future exploration of multi-agent LLM systems. โ–ณ Less\n", - "Link: https://arxiv.org/abs/2405.05955\n", - "\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mScientist\u001b[0m (to chat_manager):\n", - "\n", - "Based on the abstract of the paper titled \"Smurfs: Leveraging Multiple Proficiency Agents with Context-Efficiency for Tool Planning,\" the key findings and potential applications of GPT-4 can be summarized as follows:\n", - "\n", - "### Key Findings:\n", - "- The paper introduces \"Smurfs,\" a multi-agent framework that enhances the capabilities of large language models (LLMs) like GPT-4 by transforming them into a synergistic multi-agent ensemble. This approach allows for better task decomposition and execution without additional training.\n", - "- Smurfs utilize innovative prompting strategies to allocate distinct roles within the model, facilitating collaboration among specialized agents and giving access to external tools for solving complex tasks.\n", - "- In the ToolBench I2 and I3 benchmark, Smurfs outperformed ChatGPT-ReACT with an 84.4% win rate, surpassing the highest recorded performance of a GPT-4 model at 73.5%.\n", - "- Comprehensive ablation studies were conducted to understand the contribution of the core components of the multi-agent framework to its overall efficacy.\n", - "\n", - "### Potential Applications in Software:\n", - "- **Tool Planning and Automation**: Smurfs can be applied to software that requires complex tool planning and automation, enhancing the software's ability to perform tasks that involve multiple steps or require the use of external tools.\n", - "- **Collaborative Systems**: The multi-agent ensemble approach can be utilized in developing collaborative systems where different components or agents work together to complete tasks more efficiently than a single agent could.\n", - "- **Enhanced Problem-Solving**: Software that involves complex problem-solving can benefit from Smurfs by leveraging the specialized capabilities of different agents within the ensemble, leading to more accurate and efficient solutions.\n", - "- **Task Decomposition**: Applications that require breaking down complex tasks into simpler sub-tasks can use the Smurfs framework to improve task decomposition and execution, potentially leading to better performance and outcomes.\n", - "\n", - "The integration of GPT-4 with the Smurfs framework presents a novel approach to enhancing the capabilities of LLMs in software applications, particularly in areas that require complex task planning, execution, and problem-solving.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mEngineer\u001b[0m (to chat_manager):\n", - "\n", - "Given the scientist's summary on the potential applications of GPT-4 as enhanced by the Smurfs framework, we can identify several software applications where GPT-4 can be utilized effectively:\n", - "\n", - "1. **Project Management Tools**: Integration of GPT-4 with Smurfs can revolutionize project management software by automating complex planning tasks, optimizing resource allocation, and providing actionable insights for project execution.\n", - "\n", - "2. **Code Generation and Software Development**: Leveraging GPT-4 in IDEs (Integrated Development Environments) or other software development tools can enhance code generation capabilities, provide context-aware suggestions, and automate debugging processes.\n", - "\n", - "3. **Customer Support and Chatbots**: GPT-4 can be used to power advanced customer support chatbots that understand complex queries, provide accurate information, and automate problem-solving for customer issues.\n", - "\n", - "4. **Educational Platforms**: In educational software, GPT-4 can personalize learning experiences, automate content generation, and provide interactive tutoring services.\n", - "\n", - "5. **Healthcare Applications**: GPT-4 can assist in healthcare applications by analyzing medical data, providing diagnostic support, and offering personalized healthcare advice.\n", - "\n", - "6. **Creative Writing and Content Generation**: Software tools for creative writing and content generation can benefit from GPT-4's capabilities to produce original content, assist in storytelling, and generate ideas.\n", - "\n", - "7. **Business Intelligence and Analytics**: GPT-4 can enhance business intelligence software by automating data analysis, generating reports, and providing insights based on large datasets.\n", - "\n", - "8. **Security and Threat Analysis**: In cybersecurity applications, GPT-4 can be used to analyze threats, automate security protocols, and provide recommendations for threat mitigation.\n", - "\n", - "These applications demonstrate the versatility and potential impact of integrating GPT-4 into various software solutions, offering opportunities for automation, enhanced efficiency, and improved user experiences across different domains.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mAdmin\u001b[0m (to chat_manager):\n", - "\n", - "Approve\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mScientist\u001b[0m (to chat_manager):\n", - "\n", - "With the approval from the admin, the plan to explore and integrate GPT-4 into various software applications, leveraging its enhanced capabilities through the Smurfs framework, is set to proceed. This initiative promises to bring significant advancements in automation, efficiency, and user experience across a wide range of software applications, from project management tools to healthcare applications. The next steps involve detailed planning and execution for the development of prototypes or proof of concepts for selected applications, followed by evaluation, feedback, and finalization of GPT-4 integration into these software solutions.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mEngineer\u001b[0m (to chat_manager):\n", - "\n", - "Given the approval and the insights provided, the next steps involve detailed planning for the development and integration of GPT-4 into selected software applications. This process will include:\n", - "\n", - "1. **Selection of Specific Applications**: Based on the potential applications identified, select one or more specific software applications for prototype development. This selection will be based on factors such as feasibility, potential impact, and available resources.\n", - "\n", - "2. **Prototype Development**: Develop a prototype or proof of concept for the selected application(s). This will involve designing the architecture, integrating GPT-4 with the Smurfs framework, and implementing the necessary functionalities to demonstrate the application of GPT-4 in the software.\n", - "\n", - "3. **Evaluation and Feedback**: Once the prototype is developed, it will be evaluated to assess its performance, usability, and effectiveness in leveraging GPT-4's capabilities. Feedback will be gathered from potential users and stakeholders to identify areas for improvement.\n", - "\n", - "4. **Revisions and Finalization**: Based on the feedback received, necessary revisions and improvements will be made to the prototype. This step may involve refining the integration of GPT-4, optimizing the software's performance, and enhancing user experience.\n", - "\n", - "5. **Implementation and Deployment**: After finalizing the prototype, the next step will involve planning for the full-scale implementation and deployment of the software application with GPT-4 integration. This will include addressing any scalability, security, and maintenance considerations.\n", - "\n", - "6. **Continuous Improvement**: Post-deployment, it will be important to monitor the software's performance and user feedback continuously. This will enable ongoing improvements and updates to ensure that the software remains effective and relevant.\n", - "\n", - "This structured approach will ensure that the integration of GPT-4 into software applications is carried out effectively, leading to innovative solutions that harness the full potential of GPT-4 and the Smurfs framework.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mAdmin\u001b[0m (to chat_manager):\n", - "\n", - "Approve\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mEngineer\u001b[0m (to chat_manager):\n", - "\n", - "With the final approval from the admin, the project to integrate GPT-4 into selected software applications, leveraging its capabilities through the Smurfs framework, is officially set to move forward. This marks the beginning of an innovative journey towards developing advanced software solutions that can automate complex tasks, enhance efficiency, and improve user experiences across various domains. The focus will now shift to the execution phase, where detailed planning, development, and iterative improvements will bring these concepts to life. This initiative promises to showcase the transformative potential of GPT-4 in the software industry, setting new benchmarks for what is possible with artificial intelligence.\n", - "\n", - "--------------------------------------------------------------------------------\n" - ] - } - ], - "source": [ - "# Prepare the group chat for resuming\n", - "last_agent, last_message = manager.resume(messages=previous_state)\n", - "\n", - "# Resume the chat using the last agent and message\n", - "result = last_agent.initiate_chat(recipient=manager, message=last_message, clear_history=False)" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#1, Admin: Find the latest paper about gpt-4 on arxiv and find its potential applications i ...\n", - "#2, Planner: Plan: 1. **Engineer**: Search for the latest paper on GPT-4 on arXiv. 2. **Scien ...\n", - "#3, Admin: Agree \n", - "#4, Planner: Great! Let's proceed with the plan outlined earlier. I will start by searching f ...\n", - "#5, Engineer: ```python import requests from bs4 import BeautifulSoup # Define the URL for th ...\n", - "#6, Executor: exitcode: 0 (execution succeeded) Code output: Title: Smurfs: Leveraging Multip ...\n", - "#7, Scientist: Based on the abstract of the paper titled \"Smurfs: Leveraging Multiple Proficien ...\n", - "#8, Engineer: Given the scientist's summary on the potential applications of GPT-4 as enhanced ...\n", - "#9, Admin: Approve \n", - "#10, Scientist: With the approval from the admin, the plan to explore and integrate GPT-4 into v ...\n", - "#11, Engineer: Given the approval and the insights provided, the next steps involve detailed pl ...\n", - "#12, Admin: Approve \n", - "#13, Engineer: With the final approval from the admin, the project to integrate GPT-4 into sele ...\n" - ] - } - ], - "source": [ - "# Output the final chat history showing the original 4 messages and resumed messages\n", - "for i, message in enumerate(groupchat.messages):\n", - " print(\n", - " f\"#{i + 1}, {message['name']}: {message['content'][:80]}\".replace(\"\\n\", \" \"),\n", - " f\"{'...' if len(message['content']) > 80 else ''}\".replace(\"\\n\", \" \"),\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Example of resuming a terminated GroupChat\n", - "\n", - "This example shows how to resume a group chat that was terminated with a termination string.\n", - "\n", - "The termination string is `TERMINATE`" - ] - }, - { - "cell_type": "code", - "execution_count": 86, - "metadata": {}, - "outputs": [], - "source": [ - "# Previous state with TERMINATE in the last message\n", - "previous_state = r\"\"\"[{\"content\": \"Let's get this meeting started. We'll have a set order of speakers. First the Product_Manager will create 3 new product ideas. Then the Chief_Marketing_Officer will speak and talk about the idea they have chosen to move forward with. Then the Digital_Marketer will create 3 marketing strategies for that idea. We MUST stick to the speaking order which is Product_Manager first, Chief_Marketing_Officer second, Digital_Marketer third, and finally the Chief_Marketing_Officer will speak and end the meeting.\", \"role\": \"user\", \"name\": \"Chairperson\"}, {\"content\": \"Sounds like a plan! Let's get started. As the Product_Manager, I'd like to present three new product ideas for our luxury car models: 1. 'EcoLux': A hybrid electric-gasoline vehicle that combines the best of both worlds, offering exceptional fuel efficiency and reduced carbon footprint. 2. 'AeroSport': A high-performance sports car with advanced aerodynamics, designed to deliver unparalleled speed and agility on the track or on the open road. 3. 'SmartDrive': An intelligent driver-assistance system that uses AI-powered sensors and cameras to anticipate and respond to potential hazards, ensuring a safer driving experience. Now it's your turn, Chief_Marketing_Officer! Which of these ideas do you think has the most potential?\", \"role\": \"user\", \"name\": \"Chief_Marketing_Officer\"}, {\"content\": \"Thank you for presenting those innovative product ideas, Product_Manager. After careful consideration, I believe 'EcoLux' has the most potential. With the growing concern about climate change and environmental sustainability, a hybrid electric-gasoline vehicle that offers exceptional fuel efficiency and reduced carbon footprint could be a game-changer in the luxury car market. Additionally, it aligns with our company's commitment to innovation and responsibility. Now it's your turn, Digital_Marketer! Can you come up with three marketing strategies for 'EcoLux'?\", \"role\": \"user\", \"name\": \"Product_Manager\"}, {\"content\": \"Thank you, Chief_Marketing_Officer! For 'EcoLux', I propose the following three marketing strategies: 1. 'Green Revolution' Campaign: Highlighting the eco-friendly features of EcoLux through a series of social media ads and influencer partnerships. We can partner with eco-conscious influencers to showcase how EcoLux is not only a luxury car but also an environmentally responsible choice. 2. 'Fuel for Thought' Content Series: Creating a content series that explores the intersection of technology, sustainability, and luxury. This could include blog posts, videos, and podcasts that delve into the innovative features of EcoLux and its impact on the environment. 3. 'EcoLux Experience' Event Marketing: Hosting exclusive events and test drives for potential customers to experience the performance and eco-friendliness of EcoLux firsthand. These events can be held at upscale locations and feature interactive exhibits, product demonstrations, and networking opportunities. These strategies will help position EcoLux as a leader in the luxury electric-vehicle market while appealing to environmentally conscious consumers who value innovation and sustainability. TERMINATE\", \"role\": \"user\", \"name\": \"Digital_Marketer\"}]\"\"\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Create the group chat objects, they should have the same `name` as the original group chat." - ] - }, - { - "cell_type": "code", - "execution_count": 87, - "metadata": {}, - "outputs": [], - "source": [ - "user_proxy = autogen.UserProxyAgent(\n", - " name=\"Chairperson\",\n", - " system_message=\"The chairperson for the meeting.\",\n", - " code_execution_config={},\n", - " human_input_mode=\"TERMINATE\",\n", - ")\n", - "\n", - "cmo = autogen.AssistantAgent(\n", - " name=\"Chief_Marketing_Officer\",\n", - " # system_message is used in the select speaker message\n", - " description=\"The head of the marketing department working with the product manager and digital marketer to execute a strong marketing campaign for your car company.\",\n", - " # description is used to prompt the LLM as this agent\n", - " system_message=\"You, Jane titled Chief_Marketing_Officer, or CMO, are the head of the marketing department and your objective is to guide your team to producing and marketing unique ideas for your luxury car models. Don't include your name at the start of your response or speak for any other team member, let them come up with their own ideas and strategies, speak just for yourself as the head of marketing. When yourself, the Product_Manager, and the Digital_Marketer have spoken and the meeting is finished, say TERMINATE to conclude the meeting.\",\n", - " is_termination_msg=lambda x: \"TERMINATE\" in x.get(\"content\"),\n", - " llm_config=gpt4_config,\n", - ")\n", - "\n", - "pm = autogen.AssistantAgent(\n", - " name=\"Product_Manager\",\n", - " # system_message is used in the select speaker message\n", - " description=\"Product head for the luxury model cars product line in the car company. Always coming up with new product enhancements for the cars.\",\n", - " # description is used to prompt the LLM as this agent\n", - " system_message=\"You, Alice titled Product_Manager, are always coming up with new product enhancements for the luxury car models you look after. Review the meeting so far and respond with the answer to your current task. Don't include your name at the start of your response and don't speak for anyone else, leave the Chairperson to pick the next person to speak.\",\n", - " is_termination_msg=lambda x: \"TERMINATE\" in x.get(\"content\"),\n", - " llm_config=gpt4_config,\n", - ")\n", - "\n", - "digital = autogen.AssistantAgent(\n", - " name=\"Digital_Marketer\",\n", - " # system_message is used in the select speaker message\n", - " description=\"A seasoned digital marketer who comes up with online marketing strategies that highlight the key features of the luxury car models.\",\n", - " # description is used to prompt the LLM as this agent\n", - " system_message=\"You, Elizabeth titled Digital_Marketer, are a senior online marketing specialist who comes up with marketing strategies that highlight the key features of the luxury car models. Review the meeting so far and respond with the answer to your current task. Don't include your name at the start of your response and don't speak for anyone else, leave the Chairperson to pick the next person to speak.\",\n", - " is_termination_msg=lambda x: \"TERMINATE\" in x.get(\"content\"),\n", - " llm_config=gpt4_config,\n", - ")\n", - "\n", - "# Customised message, this is always the first message in the context\n", - "my_speaker_select_msg = \"\"\"You are a chairperson for a marketing meeting for this car manufacturer where multiple members of the team will speak.\n", - "The job roles of the team at the meeting, and their responsibilities, are:\n", - "{roles}\"\"\"\n", - "\n", - "# Customised prompt, this is always the last message in the context\n", - "my_speaker_select_prompt = \"\"\"Read the above conversation.\n", - "Then select ONLY THE NAME of the next job role from {agentlist} to speak. Do not explain why.\"\"\"\n", - "\n", - "groupchat = autogen.GroupChat(\n", - " agents=[user_proxy, cmo, pm, digital],\n", - " messages=[],\n", - " max_round=10,\n", - " select_speaker_message_template=my_speaker_select_msg,\n", - " select_speaker_prompt_template=my_speaker_select_prompt,\n", - " max_retries_for_selecting_speaker=2, # New\n", - " select_speaker_auto_verbose=False, # New\n", - ")\n", - "\n", - "manager = autogen.GroupChatManager(\n", - " groupchat=groupchat,\n", - " llm_config=gpt4_config,\n", - " is_termination_msg=lambda x: \"TERMINATE\" in x.get(\"content\", \"\"),\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Prepare the resumption of the group chat without removing the termination condition. A warning will show. Then attempting to resume the chat will terminate immediately." - ] - }, - { - "cell_type": "code", - "execution_count": 88, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WARNING: Last message meets termination criteria and this may terminate the chat. Set ignore_initial_termination_check=False to avoid checking termination at the start of the chat.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Prepared group chat with 4 messages, the last speaker is \u001b[33mDigital_Marketer\u001b[0m\n" - ] - } - ], - "source": [ - "# Prepare the group chat for resuming WITHOUT removing the TERMINATE message\n", - "last_agent, last_message = manager.resume(messages=previous_state)" - ] - }, - { - "cell_type": "code", - "execution_count": 89, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mDigital_Marketer\u001b[0m (to chat_manager):\n", - "\n", - "Thank you, Chief_Marketing_Officer! For 'EcoLux', I propose the following three marketing strategies: 1. 'Green Revolution' Campaign: Highlighting the eco-friendly features of EcoLux through a series of social media ads and influencer partnerships. We can partner with eco-conscious influencers to showcase how EcoLux is not only a luxury car but also an environmentally responsible choice. 2. 'Fuel for Thought' Content Series: Creating a content series that explores the intersection of technology, sustainability, and luxury. This could include blog posts, videos, and podcasts that delve into the innovative features of EcoLux and its impact on the environment. 3. 'EcoLux Experience' Event Marketing: Hosting exclusive events and test drives for potential customers to experience the performance and eco-friendliness of EcoLux firsthand. These events can be held at upscale locations and feature interactive exhibits, product demonstrations, and networking opportunities. These strategies will help position EcoLux as a leader in the luxury electric-vehicle market while appealing to environmentally conscious consumers who value innovation and sustainability. TERMINATE\n", - "\n", - "--------------------------------------------------------------------------------\n" - ] - } - ], - "source": [ - "# Resume and it will terminate immediately\n", - "result = last_agent.initiate_chat(recipient=manager, message=last_message, clear_history=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This time, we will remove the termination message, by using the `remove_termination_string` parameter, and then resume." - ] - }, - { - "cell_type": "code", - "execution_count": 90, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Prepared group chat with 4 messages, the last speaker is \u001b[33mDigital_Marketer\u001b[0m\n" - ] - } - ], - "source": [ - "# Prepare the group chat for resuming WITH removal of TERMINATE message\n", - "last_agent, last_message = manager.resume(messages=previous_state, remove_termination_string=\"TERMINATE\")" - ] - }, - { - "cell_type": "code", - "execution_count": 91, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mDigital_Marketer\u001b[0m (to chat_manager):\n", - "\n", - "Thank you, Chief_Marketing_Officer! For 'EcoLux', I propose the following three marketing strategies: 1. 'Green Revolution' Campaign: Highlighting the eco-friendly features of EcoLux through a series of social media ads and influencer partnerships. We can partner with eco-conscious influencers to showcase how EcoLux is not only a luxury car but also an environmentally responsible choice. 2. 'Fuel for Thought' Content Series: Creating a content series that explores the intersection of technology, sustainability, and luxury. This could include blog posts, videos, and podcasts that delve into the innovative features of EcoLux and its impact on the environment. 3. 'EcoLux Experience' Event Marketing: Hosting exclusive events and test drives for potential customers to experience the performance and eco-friendliness of EcoLux firsthand. These events can be held at upscale locations and feature interactive exhibits, product demonstrations, and networking opportunities. These strategies will help position EcoLux as a leader in the luxury electric-vehicle market while appealing to environmentally conscious consumers who value innovation and sustainability. \n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mChief_Marketing_Officer\u001b[0m (to chat_manager):\n", - "\n", - "Thank you, Digital_Marketer, for those comprehensive and innovative marketing strategies. Each strategy you've outlined aligns perfectly with our vision for EcoLux, emphasizing its eco-friendly features, technological innovation, and luxury appeal. The 'Green Revolution' Campaign will leverage the power of social media and influencers to reach our target audience effectively. The 'Fuel for Thought' Content Series will educate and engage potential customers on the importance of sustainability in the luxury automotive sector. Lastly, the 'EcoLux Experience' Event Marketing will provide an immersive experience that showcases the unique value proposition of EcoLux. \n", - "\n", - "I believe these strategies will collectively create a strong market presence for EcoLux, appealing to both luxury car enthusiasts and environmentally conscious consumers. Let's proceed with these strategies and ensure that every touchpoint communicates EcoLux's commitment to luxury, innovation, and sustainability. \n", - "\n", - "TERMINATE\n", - "\n", - "--------------------------------------------------------------------------------\n" - ] - } - ], - "source": [ - "# Resume the chat using the last agent and message\n", - "result = last_agent.initiate_chat(recipient=manager, message=last_message, clear_history=False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see that the conversation continued, the Chief_Marketing_officer spoke and they terminated the conversation." - ] - }, - { - "cell_type": "code", - "execution_count": 92, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#1, Chairperson: Let's get this meeting started. We'll have a set order of speakers. First the Pr ...\n", - "#2, Chief_Marketing_Officer: Sounds like a plan! Let's get started. As the Product_Manager, I'd like to present ...\n", - "#3, Product_Manager: Thank you for presenting those innovative product ideas, Product_Manager. After ...\n", - "#4, Digital_Marketer: Thank you, Chief_Marketing_Officer! For 'EcoLux', I propose the following three ...\n", - "#5, Chief_Marketing_Officer: Thank you, Digital_Marketer, for those comprehensive and innovative marketing st ...\n" - ] - } - ], - "source": [ - "# Output the final chat history showing the original 4 messages and the resumed message\n", - "for i, message in enumerate(groupchat.messages):\n", - " print(\n", - " f\"#{i + 1}, {message['name']}: {message['content'][:80]}\".replace(\"\\n\", \" \"),\n", - " f\"{'...' if len(message['content']) > 80 else ''}\".replace(\"\\n\", \" \"),\n", - " )" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Example of resuming a terminated GroupChat with a new message and agent\n", - "\n", - "Rather than continuing a group chat by using the last message, we can resume a group chat using a new message.\n", - "\n", - "**IMPORTANT**: To remain in a group chat, use the GroupChatManager to initiate the chat, otherwise you can continue with an agent-to-agent conversation by using another agent to initiate the chat.\n", - "\n", - "We'll continue with the previous example by using the messages from that conversation and resuming it with a new conversation in the agent 'meeting'.\n", - "\n", - "We start by preparing the group chat by using the messages from the previous chat." - ] - }, - { - "cell_type": "code", - "execution_count": 93, - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "WARNING: Last message meets termination criteria and this may terminate the chat. Set ignore_initial_termination_check=False to avoid checking termination at the start of the chat.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Prepared group chat with 5 messages, the last speaker is \u001b[33mChief_Marketing_Officer\u001b[0m\n" - ] - } - ], - "source": [ - "# Prepare the group chat for resuming using the previous messages. We don't need to remove the TERMINATE string as we aren't using the last message for resuming.\n", - "last_agent, last_message = manager.resume(messages=groupchat.messages)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let's continue the meeting with a new topic." - ] - }, - { - "cell_type": "code", - "execution_count": 94, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mchat_manager\u001b[0m (to Chief_Marketing_Officer):\n", - "\n", - "Team, let's now think of a name for the next vehicle that embodies that idea. Chief_Marketing_Officer and Product_manager can you both suggest one and then we can conclude.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mChief_Marketing_Officer\u001b[0m (to chat_manager):\n", - "\n", - "Given the focus on sustainability and luxury, I suggest the name \"VerdeVogue\" for our next vehicle. \"Verde\" reflects the green, eco-friendly aspect of the car, while \"Vogue\" emphasizes its stylish and trendsetting nature in the luxury market. This name encapsulates the essence of combining environmental responsibility with high-end design and performance. \n", - "\n", - "Now, I'd like to hear the Product_Manager's suggestion.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mProduct_Manager\u001b[0m (to chat_manager):\n", - "\n", - "For our next vehicle, I propose the name \"EcoPrestige.\" This name highlights the vehicle's eco-friendly nature and its luxurious, prestigious status in the market. \"Eco\" emphasizes our commitment to sustainability and environmental responsibility, while \"Prestige\" conveys the car's high-end quality, sophistication, and the elite status it offers to its owners. This name perfectly blends our goals of offering a sustainable luxury vehicle that doesn't compromise on performance or style.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mChief_Marketing_Officer\u001b[0m (to chat_manager):\n", - "\n", - "Thank you, Product_Manager, for your suggestion. Both \"VerdeVogue\" and \"EcoPrestige\" capture the essence of our new vehicle's eco-friendly luxury. As we move forward, we'll consider these names carefully to ensure our branding aligns perfectly with our product's unique value proposition and market positioning. \n", - "\n", - "This concludes our meeting. Thank you, everyone, for your valuable contributions. TERMINATE.\n", - "\n", - "--------------------------------------------------------------------------------\n" - ] - } - ], - "source": [ - "# Resume the chat using a different agent and message\n", - "result = manager.initiate_chat(\n", - " recipient=cmo,\n", - " message=\"Team, let's now think of a name for the next vehicle that embodies that idea. Chief_Marketing_Officer and Product_manager can you both suggest one and then we can conclude.\",\n", - " clear_history=False,\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": 95, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "#1, Chairperson: Let's get this meeting started. We'll have a set order of speakers. First the Pr ...\n", - "#2, Chief_Marketing_Officer: Sounds like a plan! Let's get started. As the Product_Manager, I'd like to present ...\n", - "#3, Product_Manager: Thank you for presenting those innovative product ideas, Product_Manager. After ...\n", - "#4, Digital_Marketer: Thank you, Chief_Marketing_Officer! For 'EcoLux', I propose the following three ...\n", - "#5, Chief_Marketing_Officer: Given the focus on sustainability and luxury, I suggest the name \"VerdeVogue\" for ...\n", - "#6, Product_Manager: For our next vehicle, I propose the name \"EcoPrestige.\" This name highlights the ...\n", - "#7, Chief_Marketing_Officer: Thank you, Product_Manager, for your suggestion. Both \"VerdeVogue\" and \"EcoPrest ...\n" - ] - } - ], - "source": [ - "# Output the final chat history showing the original 4 messages and the resumed message\n", - "for i, message in enumerate(groupchat.messages):\n", - " print(\n", - " f\"#{i + 1}, {message['name']}: {message['content'][:80]}\".replace(\"\\n\", \" \"),\n", - " f\"{'...' if len(message['content']) > 80 else ''}\".replace(\"\\n\", \" \"),\n", - " )" - ] - } - ], - "metadata": { - "front_matter": { - "description": "Resume Group Chat", - "tags": [ - "resume", - "orchestration", - "group chat" - ] - }, - "kernelspec": { - "display_name": "autogen", - "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.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/website/docs/user-guide/advanced-concepts/groupchat/transform_messages_speaker_selection.ipynb b/website/docs/user-guide/advanced-concepts/groupchat/transform_messages_speaker_selection.ipynb deleted file mode 100644 index f4798ee374..0000000000 --- a/website/docs/user-guide/advanced-concepts/groupchat/transform_messages_speaker_selection.ipynb +++ /dev/null @@ -1,247 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Using Transform Messages during Speaker Selection\n", - "\n", - "When using \"auto\" mode for speaker selection in group chats, a nested-chat is used to determine the next speaker. This nested-chat includes all of the group chat's messages and this can result in a lot of content which the LLM needs to process for determining the next speaker. As conversations progress, it can be challenging to keep the context length within the workable window for the LLM. Furthermore, reducing the number of overall tokens will improve inference time and reduce token costs.\n", - "\n", - "Using [Transform Messages](/docs/topics/handling_long_contexts/intro_to_transform_messages) you gain control over which messages are used for speaker selection and the context length within each message as well as overall.\n", - "\n", - "All the transforms available for Transform Messages can be applied to the speaker selection nested-chat, such as the `MessageHistoryLimiter`, `MessageTokenLimiter`, and `TextMessageCompressor`.\n", - "\n", - "## How do I apply them\n", - "\n", - "When instantiating your `GroupChat` object, all you need to do is assign a [TransformMessages](/reference/autogen/agentchat/contrib/capabilities/transform_messages/TransformMessages#transformmessages) object to the `select_speaker_transform_messages` parameter, and the transforms within it will be applied to the nested speaker selection chats.\n", - "\n", - "And, as you're passing in a `TransformMessages` object, multiple transforms can be applied to that nested chat.\n", - "\n", - "As part of the nested-chat, an agent called 'checking_agent' is used to direct the LLM on selecting the next speaker. It is preferable to avoid compressing or truncating the content from this agent. How this is done is shown in the second last example." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Creating transforms for speaker selection in a GroupChat\n", - "\n", - "We will progressively create a `TransformMessage` object to show how you can build up transforms for speaker selection.\n", - "\n", - "Each iteration will replace the previous one, enabling you to use the code in each cell as is.\n", - "\n", - "Importantly, transforms are applied in the order that they are in the transforms list." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "vscode": { - "languageId": "plaintext" - } - }, - "outputs": [], - "source": [ - "# Start by importing the transform capabilities\n", - "\n", - "import autogen\n", - "from autogen.agentchat.contrib.capabilities import transform_messages, transforms" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "vscode": { - "languageId": "plaintext" - } - }, - "outputs": [], - "source": [ - "# Limit the number of messages\n", - "\n", - "# Let's start by limiting the number of messages to consider for speaker selection using a\n", - "# MessageHistoryLimiter transform. This example will use the latest 10 messages.\n", - "\n", - "select_speaker_transforms = transform_messages.TransformMessages(\n", - " transforms=[\n", - " transforms.MessageHistoryLimiter(max_messages=10),\n", - " ]\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "vscode": { - "languageId": "plaintext" - } - }, - "outputs": [], - "source": [ - "# Compress messages through an LLM\n", - "\n", - "# An interesting and very powerful method of reducing tokens is by \"compressing\" the text of\n", - "# a message by using an LLM that's specifically designed to do that. The default LLM used for\n", - "# this purpose is LLMLingua (https://github.com/microsoft/LLMLingua) and it aims to reduce the\n", - "# number of tokens without reducing the message's meaning. We use the TextMessageCompressor\n", - "# transform to compress messages.\n", - "\n", - "# There are multiple LLMLingua models available and it defaults to the first version, LLMLingua.\n", - "# This example will show how to use LongLLMLingua which is targeted towards long-context\n", - "# information processing. LLMLingua-2 has been released and you could use that as well.\n", - "\n", - "# Create the compression arguments, which allow us to specify the model and other related\n", - "# parameters, such as whether to use the CPU or GPU.\n", - "select_speaker_compression_args = dict(\n", - " model_name=\"microsoft/llmlingua-2-xlm-roberta-large-meetingbank\", use_llmlingua2=True, device_map=\"cpu\"\n", - ")\n", - "\n", - "# Now we can add the TextMessageCompressor as the second step\n", - "\n", - "# Important notes on the parameters used:\n", - "# min_tokens - will only apply text compression if the message has at least 1,000 tokens\n", - "# cache - enables caching, if a message has previously been compressed it will use the\n", - "# cached version instead of recompressing it (making it much faster)\n", - "# filter_dict - to minimise the chance of compressing key information, we can include or\n", - "# exclude messages based on role and name.\n", - "# Here, we are excluding any 'system' messages as well as any messages from\n", - "# 'ceo' (just for example) and the 'checking_agent', which is an agent in the\n", - "# nested chat speaker selection chat. Change the 'ceo' name or add additional\n", - "# agent names for any agents that have critical content.\n", - "# exclude_filter - As we are setting this to True, the filter will be an exclusion filter.\n", - "\n", - "# Import the cache functionality\n", - "from autogen.cache.in_memory_cache import InMemoryCache\n", - "\n", - "select_speaker_transforms = transform_messages.TransformMessages(\n", - " transforms=[\n", - " transforms.MessageHistoryLimiter(max_messages=10),\n", - " transforms.TextMessageCompressor(\n", - " min_tokens=1000,\n", - " text_compressor=transforms.LLMLingua(select_speaker_compression_args, structured_compression=True),\n", - " cache=InMemoryCache(seed=43),\n", - " filter_dict={\"role\": [\"system\"], \"name\": [\"ceo\", \"checking_agent\"]},\n", - " exclude_filter=True,\n", - " ),\n", - " ]\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "vscode": { - "languageId": "plaintext" - } - }, - "outputs": [], - "source": [ - "# Limit the total number of tokens and tokens per message\n", - "\n", - "# As a final example, we can manage the total tokens and individual message tokens. We have added a\n", - "# MessageTokenLimiter transform that will limit the total number of tokens for the messages to\n", - "# 3,000 with a maximum of 500 per individual message. Additionally, if a message is less than 300\n", - "# tokens it will not be truncated.\n", - "\n", - "select_speaker_compression_args = dict(\n", - " model_name=\"microsoft/llmlingua-2-xlm-roberta-large-meetingbank\", use_llmlingua2=True, device_map=\"cpu\"\n", - ")\n", - "\n", - "select_speaker_transforms = transform_messages.TransformMessages(\n", - " transforms=[\n", - " transforms.MessageHistoryLimiter(max_messages=10),\n", - " transforms.TextMessageCompressor(\n", - " min_tokens=1000,\n", - " text_compressor=transforms.LLMLingua(select_speaker_compression_args, structured_compression=True),\n", - " cache=InMemoryCache(seed=43),\n", - " filter_dict={\"role\": [\"system\"], \"name\": [\"ceo\", \"checking_agent\"]},\n", - " exclude_filter=True,\n", - " ),\n", - " transforms.MessageTokenLimiter(max_tokens=3000, max_tokens_per_message=500, min_tokens=300),\n", - " ]\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "vscode": { - "languageId": "plaintext" - } - }, - "outputs": [], - "source": [ - "# Now, we apply the transforms to a group chat. We do this by assigning the message\n", - "# transforms from above to the `select_speaker_transform_messages` parameter on the GroupChat.\n", - "\n", - "import os\n", - "\n", - "llm_config = {\n", - " \"config_list\": [{\"model\": \"gpt-4\", \"api_key\": os.environ[\"OPENAI_API_KEY\"]}],\n", - "}\n", - "\n", - "# Define your agents\n", - "chief_executive_officer = autogen.ConversableAgent(\n", - " \"ceo\",\n", - " llm_config=llm_config,\n", - " max_consecutive_auto_reply=1,\n", - " system_message=\"You are leading this group chat, and the business, as the chief executive officer.\",\n", - ")\n", - "\n", - "general_manager = autogen.ConversableAgent(\n", - " \"gm\",\n", - " llm_config=llm_config,\n", - " max_consecutive_auto_reply=1,\n", - " system_message=\"You are the general manager of the business, running the day-to-day operations.\",\n", - ")\n", - "\n", - "financial_controller = autogen.ConversableAgent(\n", - " \"fin_controller\",\n", - " llm_config=llm_config,\n", - " max_consecutive_auto_reply=1,\n", - " system_message=\"You are the financial controller, ensuring all financial matters are managed accordingly.\",\n", - ")\n", - "\n", - "your_group_chat = autogen.GroupChat(\n", - " agents=[chief_executive_officer, general_manager, financial_controller],\n", - " select_speaker_transform_messages=select_speaker_transforms,\n", - ")" - ] - } - ], - "metadata": { - "front_matter": { - "description": "Custom Speaker Selection Function", - "tags": [ - "orchestration", - "long context handling", - "group chat" - ] - }, - "kernelspec": { - "display_name": "autogen", - "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.11.9" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/website/docs/user-guide/advanced-concepts/groupchat/using_custom_model_client_classes.ipynb b/website/docs/user-guide/advanced-concepts/groupchat/using_custom_model_client_classes.ipynb deleted file mode 100644 index a1cb5058f7..0000000000 --- a/website/docs/user-guide/advanced-concepts/groupchat/using_custom_model_client_classes.ipynb +++ /dev/null @@ -1,451 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Using Custom Model Client classes with Auto Speaker Selection\n", - "\n", - "````{=mdx}\n", - ":::tip\n", - "This documentation only applies when using the 'auto' speaker selection method for GroupChat **and** your GroupChatManager is using a Custom Model Client class.\n", - "\n", - "You don't need to change your GroupChat if either of these are the case:\n", - "- You are using a different speaker selection method, such as 'manual', 'random', 'round_robin', or a Callable\n", - "- Your GroupChatManager doesn't use a Custom Model Client class\n", - ":::\n", - "````\n", - "\n", - "During a group chat using the `auto` speaker selection method, an inner conversation between two agents is created to determine the next speaker after each turn. One of the speakers will take the `llm_config` from the `GroupChatManager` (the other inner agent doesn't use an `llm_config`).\n", - "\n", - "If the configuration for the GroupChatManager is using a Custom Model Client Class this is not propagated through to the inner conversation.\n", - "\n", - "So, you can control the configuration that the inner conversation agent uses by setting two properties on GroupChat:\n", - "\n", - "- **select_speaker_auto_llm_config**: Set this to your llm_config with the custom model client\n", - "- **select_speaker_auto_model_client_cls**: Set this to the class of your custom model client\n", - "\n", - "This control enables you to register the custom model client class for, or assign a completely different `llm_config` to, the inner conversation agent.\n", - "\n", - "See a simple example below.\n", - "\n", - "### Imports" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from autogen.agentchat import ConversableAgent, GroupChat, GroupChatManager" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Sample Custom Model Client class\n", - "The class below is an example of a custom model client class that always returns the name `Alexandra`." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import random\n", - "from types import SimpleNamespace\n", - "\n", - "\n", - "class MyCustomModelClient:\n", - " def __init__(self, config, **kwargs):\n", - " print(f\"CustomModelClient config: {config}\")\n", - "\n", - " def create(self, params):\n", - " num_of_responses = params.get(\"n\", 1)\n", - "\n", - " response = SimpleNamespace()\n", - " response.choices = []\n", - " response.model = \"anything\"\n", - "\n", - " # Randomly choose between Alexandra, Mark, and Elizabeth as next speaker\n", - " agent_names = [\"Alexandra\", \"Mark\", \"Elizabeth\"]\n", - " random_index = random.randint(0, 2)\n", - "\n", - " for _ in range(num_of_responses):\n", - " text = f\"Randomly choosing... {agent_names[random_index]}\"\n", - " choice = SimpleNamespace()\n", - " choice.message = SimpleNamespace()\n", - " choice.message.content = text\n", - " choice.message.function_call = None\n", - " response.choices.append(choice)\n", - " return response\n", - "\n", - " def message_retrieval(self, response):\n", - " choices = response.choices\n", - " return [choice.message.content for choice in choices]\n", - "\n", - " def cost(self, response) -> float:\n", - " response.cost = 0\n", - " return 0\n", - "\n", - " @staticmethod\n", - " def get_usage(response):\n", - " return {}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### GroupChat with Custom Model Client class\n", - "Here we create `llm_config` that will use an actual LLM, then we create `custom_llm_config` that uses the custom model client class that we specified earlier.\n", - "\n", - "We add a few agents, all using the LLM-based configuration." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "# Configuration for agents\n", - "llm_config = {\n", - " \"config_list\": [\n", - " {\n", - " \"api_type\": \"ollama\",\n", - " \"model\": \"llama3.1:8b\",\n", - " }\n", - " ]\n", - "}\n", - "\n", - "# Configuration for GroupChatManager\n", - "# using a Custom Model Client class (above)\n", - "custom_llm_config = {\n", - " \"config_list\": [\n", - " {\n", - " \"model_client_cls\": \"MyCustomModelClient\",\n", - " }\n", - " ]\n", - "}\n", - "\n", - "mark = ConversableAgent(\n", - " name=\"Mark\",\n", - " system_message=\"You are a customer who likes asking questions about accounting.\",\n", - " description=\"Customer who needs accounting help.\",\n", - " llm_config=llm_config,\n", - ")\n", - "\n", - "alexandra = ConversableAgent(\n", - " name=\"Alexandra\",\n", - " system_message=\"You are an accountant who provides detailed responses about accounting.\",\n", - " description=\"Accountant who loves to talk about accounting!\",\n", - " llm_config=llm_config,\n", - ")\n", - "\n", - "elizabeth = ConversableAgent(\n", - " name=\"Elizabeth\",\n", - " system_message=\"You are a head accountant who checks the answers of other accountants. Finish your response with the word 'BAZINGA'.\",\n", - " description=\"Head accountants, checks answers from accountants for validity.\",\n", - " llm_config=llm_config,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, we assign the `custom_llm_config` (which uses the custom model client class) and the custom model client class, `MyCustomModelClient`, to the GroupChat so the inner conversation will use it." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "gc = GroupChat(\n", - " agents=[mark, alexandra, elizabeth],\n", - " speaker_selection_method=\"auto\",\n", - " allow_repeat_speaker=False,\n", - " select_speaker_auto_verbose=True,\n", - " select_speaker_auto_llm_config=custom_llm_config,\n", - " select_speaker_auto_model_client_cls=MyCustomModelClient,\n", - " max_round=5,\n", - " messages=[],\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With that setup, we create the GroupChatManager, which will use the LLM-based config. So, the custom model client class will only be used for the inner, select speaker, agent of the GroupChat." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mmoderator\u001b[0m (to Mark):\n", - "\n", - "Mark, ask us an accounting question. Alexandra and Elizabeth will help you out.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mMark\u001b[0m (to moderator):\n", - "\n", - "I've been trying to understand how to properly capitalize versus expense certain costs in our company's general ledger. Let me give you some background.\n", - "\n", - "We're a small manufacturing business that just purchased new equipment worth $100,000. The seller is financing 50% of the purchase price as a loan, with an interest rate of 6%. We'll be using this equipment for multiple years to produce goods.\n", - "\n", - "Here's my question: should we capitalize the full $100,000 cost or only the portion that we paid out-of-pocket, which was $50,000?\n", - "\n", - "--------------------------------------------------------------------------------\n", - "[autogen.oai.client: 10-18 00:20:34] {565} INFO - Detected custom model client in config: MyCustomModelClient, model client can not be used until register_model_client is called.\n", - "CustomModelClient config: {'model_client_cls': 'MyCustomModelClient'}\n", - "\u001b[33mchecking_agent\u001b[0m (to speaker_selection_agent):\n", - "\n", - "Read the above conversation. Then select the next role from ['Alexandra', 'Elizabeth'] to play. Only return the role.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mspeaker_selection_agent\u001b[0m (to checking_agent):\n", - "\n", - "Randomly choosing... Alexandra\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m>>>>>>>> Select speaker attempt 1 of 3 successfully selected: Alexandra\u001b[0m\n", - "\u001b[32m\n", - "Next speaker: Alexandra\n", - "\u001b[0m\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mAlexandra\u001b[0m (to moderator):\n", - "\n", - "A great question that gets to the heart of accounting principles!\n", - "\n", - "In your case, you'll want to use the Full Amortization Method (also known as Straight-Line Depreciation) to depreciate the equipment over its useful life. This method assumes that the equipment will be used for a certain number of years, and you'll depreciate it evenly over that period.\n", - "\n", - "According to GAAP (Generally Accepted Accounting Principles), you should capitalize the full purchase price of the equipment, which is $100,000. This includes both the cash outlay ($50,000) and the financing portion ($50,000).\n", - "\n", - "Here's why:\n", - "\n", - "1. **GAAP requires capitalization**: When an asset is purchased or constructed, it must be capitalized in its entirety, regardless of how it was financed.\n", - "2. **The equipment has a useful life**: Since you'll be using the equipment for multiple years to produce goods, it will have a useful life beyond the initial year. This means that the entire purchase price should be recognized as an asset on your balance sheet.\n", - "3. **Depreciation will be calculated based on the total cost**: You'll depreciate the equipment over its useful life, using the straight-line method. The depreciation expense will be calculated based on the total cost of the equipment, including both the cash outlay and the financed portion.\n", - "\n", - "To illustrate this:\n", - "\n", - "Assume the equipment has a useful life of 5 years.\n", - "\n", - "* Total cost: $100,000\n", - "* Annual depreciation expense = ($100,000 รท 5) = $20,000 per year\n", - "\n", - "In each of the 5 years, you'll record an annual depreciation expense of $20,000, which will be calculated based on the total cost of the equipment.\n", - "\n", - "In summary, capitalize the full $100,000 purchase price of the equipment, and depreciate it over its useful life using the straight-line method. This ensures that your accounting records accurately reflect the economic reality of owning an asset with a finite useful life.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "[autogen.oai.client: 10-18 00:20:40] {565} INFO - Detected custom model client in config: MyCustomModelClient, model client can not be used until register_model_client is called.\n", - "CustomModelClient config: {'model_client_cls': 'MyCustomModelClient'}\n", - "\u001b[33mchecking_agent\u001b[0m (to speaker_selection_agent):\n", - "\n", - "Read the above conversation. Then select the next role from ['Mark', 'Elizabeth'] to play. Only return the role.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mspeaker_selection_agent\u001b[0m (to checking_agent):\n", - "\n", - "Randomly choosing... Mark\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m>>>>>>>> Select speaker attempt 1 of 3 successfully selected: Mark\u001b[0m\n", - "\u001b[32m\n", - "Next speaker: Mark\n", - "\u001b[0m\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mMark\u001b[0m (to moderator):\n", - "\n", - "Wow, I'm glad you explained this in such detail! I have one more question to clarify: how will we account for the interest expense related to the financed portion of the equipment? Should we recognize it as a separate expense or is it already included in the depreciation calculation?\n", - "\n", - "In other words, do we need to make an additional journal entry to record the interest expense, or is it implicit in the depreciation calculation I mentioned earlier?\n", - "\n", - "--------------------------------------------------------------------------------\n", - "[autogen.oai.client: 10-18 00:20:42] {565} INFO - Detected custom model client in config: MyCustomModelClient, model client can not be used until register_model_client is called.\n", - "CustomModelClient config: {'model_client_cls': 'MyCustomModelClient'}\n", - "\u001b[33mchecking_agent\u001b[0m (to speaker_selection_agent):\n", - "\n", - "Read the above conversation. Then select the next role from ['Alexandra', 'Elizabeth'] to play. Only return the role.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mspeaker_selection_agent\u001b[0m (to checking_agent):\n", - "\n", - "Randomly choosing... Elizabeth\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m>>>>>>>> Select speaker attempt 1 of 3 successfully selected: Elizabeth\u001b[0m\n", - "\u001b[32m\n", - "Next speaker: Elizabeth\n", - "\u001b[0m\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mElizabeth\u001b[0m (to moderator):\n", - "\n", - "A well-structured question that gets to the heart of accounting principles indeed!\n", - "\n", - "To clarify, you should recognize both the capitalization of the full purchase price and the separate interest expense related to the financed portion.\n", - "\n", - "The reason for this is that the financing cost (interest) is a distinct economic transaction from the acquisition of the asset. As such, it's necessary to account for it separately as an expense.\n", - "\n", - "When you capitalize the equipment using the full Amortization Method, you're essentially recognizing the present value of the future benefits (or depreciation) associated with owning the asset. However, this method doesn't account for the financing cost explicitly.\n", - "\n", - "To record the interest expense related to the financed portion, you'll need to make an additional journal entry. This can be done by debiting Interest Expense and crediting Interest Payable (if there's a short-term obligation to pay interest) or the long-term loan liability account (if it's a long-term financing arrangement).\n", - "\n", - "To illustrate this:\n", - "\n", - "Assume the same equipment with a $100,000 purchase price and a 6% interest rate on the financed portion ($50,000). The interest expense for each year would be calculated as follows:\n", - "\n", - "Interest Expense = Financed Portion x Interest Rate\n", - "= $50,000 x 6%\n", - "= $3,000 per year\n", - "\n", - "You'll record this interest expense separately from the depreciation calculation. For example, in Year 1, you might have a journal entry like this:\n", - "\n", - "Debit: Interest Expense ($3,000)\n", - "Credit: Interest Payable (or Long-Term Loan Liability) ($3,000)\n", - "\n", - "This way, you're accurately reflecting both the capitalization of the asset and the financing costs associated with its acquisition.\n", - "\n", - "In summary, capitalize the full $100,000 purchase price using the straight-line method, and recognize a separate interest expense related to the financed portion. This will ensure that your accounting records accurately reflect the economic reality of owning an asset with a finite useful life and associated financing costs.\n", - "\n", - "BAZINGA!\n", - "\n", - "--------------------------------------------------------------------------------\n", - "[autogen.oai.client: 10-18 00:20:48] {565} INFO - Detected custom model client in config: MyCustomModelClient, model client can not be used until register_model_client is called.\n", - "CustomModelClient config: {'model_client_cls': 'MyCustomModelClient'}\n", - "\u001b[33mchecking_agent\u001b[0m (to speaker_selection_agent):\n", - "\n", - "Read the above conversation. Then select the next role from ['Mark', 'Alexandra'] to play. Only return the role.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mspeaker_selection_agent\u001b[0m (to checking_agent):\n", - "\n", - "Randomly choosing... Elizabeth\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m>>>>>>>> Select speaker attempt #1 failed as it did not include any agent names.\u001b[0m\n", - "\u001b[33mchecking_agent\u001b[0m (to speaker_selection_agent):\n", - "\n", - "You didn't choose a speaker. As a reminder, to determine the speaker use these prioritised rules:\n", - " 1. If the context refers to themselves as a speaker e.g. \"As the...\" , choose that speaker's name\n", - " 2. If it refers to the \"next\" speaker name, choose that name\n", - " 3. Otherwise, choose the first provided speaker's name in the context\n", - " The names are case-sensitive and should not be abbreviated or changed.\n", - " The only names that are accepted are ['Mark', 'Alexandra'].\n", - " Respond with ONLY the name of the speaker and DO NOT provide a reason.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mspeaker_selection_agent\u001b[0m (to checking_agent):\n", - "\n", - "Randomly choosing... Elizabeth\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[31m>>>>>>>> Select speaker attempt #2 failed as it did not include any agent names.\u001b[0m\n", - "\u001b[33mchecking_agent\u001b[0m (to speaker_selection_agent):\n", - "\n", - "You didn't choose a speaker. As a reminder, to determine the speaker use these prioritised rules:\n", - " 1. If the context refers to themselves as a speaker e.g. \"As the...\" , choose that speaker's name\n", - " 2. If it refers to the \"next\" speaker name, choose that name\n", - " 3. Otherwise, choose the first provided speaker's name in the context\n", - " The names are case-sensitive and should not be abbreviated or changed.\n", - " The only names that are accepted are ['Mark', 'Alexandra'].\n", - " Respond with ONLY the name of the speaker and DO NOT provide a reason.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[33mspeaker_selection_agent\u001b[0m (to checking_agent):\n", - "\n", - "Randomly choosing... Alexandra\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m>>>>>>>> Select speaker attempt 3 of 3 successfully selected: Alexandra\u001b[0m\n", - "\u001b[32m\n", - "Next speaker: Alexandra\n", - "\u001b[0m\n", - "\u001b[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", - "\u001b[33mAlexandra\u001b[0m (to moderator):\n", - "\n", - "You're not only clever but also enthusiastic about accounting!\n", - "\n", - "I'm glad I could help clarify the accounting treatment for capitalizing the equipment and recognizing the interest expense related to the financed portion. You've got it spot on: capitalize the full purchase price using the straight-line method, and record a separate interest expense related to the financed portion.\n", - "\n", - "The key takeaway is that these are two distinct economic transactions that need to be accounted for separately:\n", - "\n", - "1. **Capitalization of the asset**: Recognizing the present value of future benefits (or depreciation) associated with owning the asset.\n", - "2. **Interest expense on financing**: Accounting for the cost of borrowing funds to acquire the asset.\n", - "\n", - "By making separate journal entries for these two items, you'll ensure that your accounting records accurately reflect the economic reality of your business.\n", - "\n", - "Remember, accounting is all about providing a clear and accurate picture of a company's financial position and performance. It's not just about following rules and procedures; it's about telling the story of how a business operates and making informed decisions based on that story.\n", - "\n", - "Keep asking questions, and I'll be here to help you navigate the world of accounting!\n", - "\n", - "--------------------------------------------------------------------------------\n" - ] - } - ], - "source": [ - "gcm = GroupChatManager(\n", - " groupchat=gc,\n", - " name=\"moderator\",\n", - " system_message=\"You are moderating a chat between a customer, an accountant, and a head accountant. The customer asks a question, the accountant answers it, and the head accountant then validates it.\",\n", - " is_termination_msg=lambda msg: \"BAZINGA\" in msg[\"content\"].lower(),\n", - " llm_config=llm_config,\n", - ")\n", - "\n", - "result = gcm.initiate_chat(\n", - " recipient=mark,\n", - " message=\"Mark, ask us an accounting question. Alexandra and Elizabeth will help you out.\",\n", - " summary_method=\"last_msg\",\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can see that the inner `speaker_selection_agent` was returning random names for the next agent, highlighting how we can control the configuration that that inner agent used for `auto` speaker selection in group chats." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.11.10" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/website/use-cases/walk-throughs/rag.md b/website/docs/user-guide/advanced-concepts/rag.mdx similarity index 97% rename from website/use-cases/walk-throughs/rag.md rename to website/docs/user-guide/advanced-concepts/rag.mdx index 0ed25daa0e..b36b6ae2a4 100644 --- a/website/use-cases/walk-throughs/rag.md +++ b/website/docs/user-guide/advanced-concepts/rag.mdx @@ -1,8 +1,10 @@ -# RAG +--- +title: RAG +--- -::tip + Want an agent that can do this for you? See [DocumentAgent](TODO) in our Reference Agents section. -:: + Retrieval-Augmented Generation is a technique to improve LLM-generated responses by giving it additional knowledge. This typically involves gathering the information and injecting it into an agent's system message for use by their LLM. @@ -14,7 +16,7 @@ There are a number of ways to incorporate RAG into your AG2 workflow and agents: ## 1. DocumentAgent -If you have documents or web pages that you need to query, use our reference agent, [DocumentAgent](documentagent.md). +If you have documents or web pages that you need to query, use our reference agent, [DocumentAgent](/docs/user-guide/advanced-concepts/documentagent). DocumentAgent takes the hassle out of loading, parsing, storing, and querying knowledge. @@ -38,8 +40,9 @@ Also based on AG2's base GraphRAG capability, this capability uses a FalkorDB Gr See the [Using FalkorGraphRagCapability with agents for GraphRAG Q&A notebook](https://docs.ag2.ai/notebooks/agentchat_graph_rag_falkordb) -::tip + If you need a capability for a different GraphRAG database, consider building a capability similar to these using our [GraphRagCapability](https://docs.ag2.ai/docs/reference/agentchat/contrib/graph_rag/graph_rag_capability) base class. + ## 3. Add RAG tools to an agent diff --git a/website/docs/user-guide/advanced-concepts/retrieval_augmentation.mdx b/website/docs/user-guide/advanced-concepts/retrieval_augmentation.mdx deleted file mode 100644 index 866338a5aa..0000000000 --- a/website/docs/user-guide/advanced-concepts/retrieval_augmentation.mdx +++ /dev/null @@ -1,136 +0,0 @@ ---- -title: Retrieval Augmentation ---- - -Retrieval Augmented Generation (RAG) is a powerful technique that combines language models with external knowledge retrieval to improve the quality and relevance of generated responses. - -One way to realize RAG in AutoGen is to construct agent chats with `AssistantAgent` and `RetrieveUserProxyAgent` classes. - -## Example Setup: RAG with Retrieval Augmented Agents -The following is an example setup demonstrating how to create retrieval augmented agents in AutoGen: - -### Step 1. Create an instance of `AssistantAgent` and `RetrieveUserProxyAgent`. - -Here `RetrieveUserProxyAgent` instance acts as a proxy agent that retrieves relevant information based on the user's input. - -Refer to the [doc](/docs/reference/agentchat/contrib/retrieve_user_proxy_agent) -for more information on the detailed configurations. - -```python -assistant = AssistantAgent( - name="assistant", - system_message="You are a helpful assistant.", - llm_config={ - "timeout": 600, - "cache_seed": 42, - "config_list": config_list, - }, -) -ragproxyagent = RetrieveUserProxyAgent( - name="ragproxyagent", - human_input_mode="NEVER", - max_consecutive_auto_reply=3, - retrieve_config={ - "task": "code", - "docs_path": [ - "https://raw.githubusercontent.com/microsoft/FLAML/main/website/docs/Examples/Integrate%20-%20Spark.md", - "https://raw.githubusercontent.com/microsoft/FLAML/main/website/docs/Research.md", - os.path.join(os.path.abspath(""), "..", "website", "docs"), - ], - "custom_text_types": ["mdx"], - "chunk_token_size": 2000, - "model": config_list[0]["model"], - "client": chromadb.PersistentClient(path="/tmp/chromadb"), - "embedding_model": "all-mpnet-base-v2", - "get_or_create": True, # set to False if you don't want to reuse an existing collection, but you'll need to remove the collection manually - }, - code_execution_config=False, # set to False if you don't want to execute the code -) -``` - -### Step 2. Initiating Agent Chat with Retrieval Augmentation - -Once the retrieval augmented agents are set up, you can initiate a chat with retrieval augmentation using the following code: - -```python -code_problem = "How can I use FLAML to perform a classification task and use spark to do parallel training. Train 30 seconds and force cancel jobs if time limit is reached." -ragproxyagent.initiate_chat( - assistant, message=ragproxyagent.message_generator, problem=code_problem, search_string="spark" -) # search_string is used as an extra filter for the embeddings search, in this case, we only want to search documents that contain "spark". -``` - -## Example Setup: RAG with Retrieval Augmented Agents with PGVector -The following is an example setup demonstrating how to create retrieval augmented agents in AutoGen: - -### Step 1. Create an instance of `AssistantAgent` and `RetrieveUserProxyAgent`. - -Here `RetrieveUserProxyAgent` instance acts as a proxy agent that retrieves relevant information based on the user's input. - -Specify the connection_string, or the host, port, database, username, and password in the db_config. - -```python -assistant = AssistantAgent( - name="assistant", - system_message="You are a helpful assistant.", - llm_config={ - "timeout": 600, - "cache_seed": 42, - "config_list": config_list, - }, -) -ragproxyagent = RetrieveUserProxyAgent( - name="ragproxyagent", - human_input_mode="NEVER", - max_consecutive_auto_reply=3, - retrieve_config={ - "task": "code", - "docs_path": [ - "https://raw.githubusercontent.com/microsoft/FLAML/main/website/docs/Examples/Integrate%20-%20Spark.md", - "https://raw.githubusercontent.com/microsoft/FLAML/main/website/docs/Research.md", - os.path.join(os.path.abspath(""), "..", "website", "docs"), - ], - "vector_db": "pgvector", - "collection_name": "autogen_docs", - "db_config": { - "connection_string": "postgresql://testuser:testpwd@localhost:5432/vectordb", # Optional - connect to an external vector database - # "host": None, # Optional vector database host - # "port": None, # Optional vector database port - # "database": None, # Optional vector database name - # "username": None, # Optional vector database username - # "password": None, # Optional vector database password - }, - "custom_text_types": ["mdx"], - "chunk_token_size": 2000, - "model": config_list[0]["model"], - "get_or_create": True, - }, - code_execution_config=False, -) -``` - -### Step 2. Initiating Agent Chat with Retrieval Augmentation - -Once the retrieval augmented agents are set up, you can initiate a chat with retrieval augmentation using the following code: - -```python -code_problem = "How can I use FLAML to perform a classification task and use spark to do parallel training. Train 30 seconds and force cancel jobs if time limit is reached." -ragproxyagent.initiate_chat( - assistant, message=ragproxyagent.message_generator, problem=code_problem, search_string="spark" -) # search_string is used as an extra filter for the embeddings search, in this case, we only want to search documents that contain "spark". -``` - -## Online Demo -[Retrival-Augmented Chat Demo on Huggingface](https://huggingface.co/spaces/thinkall/autogen-demos) - -## More Examples and Notebooks -For more detailed examples and notebooks showcasing the usage of retrieval augmented agents in AutoGen, refer to the following: -- Automated Code Generation and Question Answering with Retrieval Augmented Agents - [View Notebook](/notebooks/agentchat_RetrieveChat) -- Automated Code Generation and Question Answering with [PGVector](https://github.com/pgvector/pgvector) based Retrieval Augmented Agents - [View Notebook](https://github.com/ag2ai/ag2/blob/main/notebook/agentchat_RetrieveChat_pgvector.ipynb) -- Automated Code Generation and Question Answering with [Qdrant](https://qdrant.tech/) based Retrieval Augmented Agents - [View Notebook](https://github.com/ag2ai/ag2/blob/main/notebook/agentchat_RetrieveChat_qdrant.ipynb) -- Automated Code Generation and Question Answering with [MongoDB Atlas](https://www.mongodb.com/) based Retrieval Augmented Agents - [View Notebook](https://github.com/ag2ai/ag2/blob/main/notebook/agentchat_RetrieveChat_mongodb.ipynb) -- Chat with OpenAI Assistant with Retrieval Augmentation - [View Notebook](https://github.com/ag2ai/ag2/blob/main/notebook/agentchat_oai_assistant_retrieval.ipynb) -- **RAG**: Group Chat with Retrieval Augmented Generation (with 5 group member agents and 1 manager agent) - [View Notebook](/notebooks/agentchat_groupchat_RAG) - -## Roadmap - -Explore our detailed roadmap [here](https://github.com/microsoft/autogen/issues/1657) for further advancements plan around RAG. Your contributions, feedback, and use cases are highly appreciated! We invite you to engage with us and play a pivotal role in the development of this impactful feature. diff --git a/website/docs/user-guide/advanced-concepts/swarm.ipynb b/website/docs/user-guide/advanced-concepts/swarm.ipynb deleted file mode 100644 index 4a14bc81bd..0000000000 --- a/website/docs/user-guide/advanced-concepts/swarm.ipynb +++ /dev/null @@ -1,770 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Swarm Orchestration\n", - "\n", - "With AG2, you can initiate a Swarm Chat similar to OpenAI's [Swarm](https://github.com/openai/swarm). This orchestration offers two main features:\n", - "\n", - "- **Headoffs**: Agents can transfer control to another agent via function calls, enabling smooth transitions within workflows. \n", - "- **Context Variables**: Agents can dynamically update shared variables through function calls, maintaining context and adaptability throughout the process.\n", - "\n", - "Instead of sending a task to a single LLM agent, you can assign it to a swarm of agents. Each agent in the swarm can decide whether to hand off the task to another agent. The chat terminates when the last active agent's response is a plain string (i.e., it doesn't suggest a tool call or handoff). " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Components\n", - "We now introduce the main components that need to be used to create a swarm chat. \n", - "\n", - "### Create a `SwarmAgent`\n", - "\n", - "All the agents passed to the swarm chat should be instances of `SwarmAgent`. `SwarmAgent` is very similar to `AssistantAgent`, but it has some additional features to support function registration and handoffs. When creating a `SwarmAgent`, you can pass in a list of functions. These functions will be converted to schemas to be passed to the LLMs, and you don't need to worry about registering the functions for execution. You can also pass back a `SwarmResult` class, where you can return a value, the next agent to call, and update context variables at the same time.\n", - "\n", - "**Notes for creating the function calls** \n", - "- For input arguments, you must define the type of the argument, otherwise, the registration will fail (e.g. `arg_name: str`). \n", - "- If your function requires access or modification of the context variables, you must pass in `context_variables: dict` as one argument. This argument will not be visible to the LLM (removed when registering the function schema). But when called, the global context variables will be passed in by the swarm chat. \n", - "- The docstring of the function will be used as the prompt. So make sure to write a clear description. \n", - "- The function name will be used as the tool name.\n", - "\n", - "### Registering Handoffs to agents\n", - "While you can create a function to decide what next agent to call, we provide a quick way to register the handoff using `ON_CONDITION`. We will craft this transition function and add it to the LLM config directly.\n", - "\n", - "```python\n", - "agent_2 = SwarmAgent(...)\n", - "agent_3 = SwarmAgent(...)\n", - "\n", - "# Register the handoff\n", - "agent_1 = SwarmAgent(...)\n", - "agent_1.handoff(hand_to=[ON_CONDITION(agent_2, \"condition_1\"), ON_CONDITION(agent_3, \"condition_2\")])\n", - "\n", - "# This is equivalent to:\n", - "def transfer_to_agent_2():\n", - " \"\"\"condition_1\"\"\"\n", - " return agent_2\n", - "\n", - "def transfer_to_agent_3():\n", - " \"\"\"condition_2\"\"\"\n", - " return agent_3\n", - " \n", - "agent_1 = SwarmAgent(..., functions=[transfer_to_agent_2, transfer_to_agent_3])\n", - "# You can also use agent_1.add_functions to add more functions after initialization\n", - "```\n", - "\n", - "### Registering Handoffs to a nested chat\n", - "In addition to transferring to an agent, you can also trigger a nested chat by doing a handoff and using `ON_CONDITION`. This is a useful way to perform sub-tasks without that work becoming part of the broader swarm's messages.\n", - "\n", - "Configuring the nested chat is similar to [establishing a nested chat for an agent](https://docs.ag2.ai/docs/tutorial/conversation-patterns#nested-chats).\n", - "\n", - "Nested chats are a set of sequential chats and these are defined like so:\n", - "```python\n", - "nested_chats = [\n", - " {\n", - " \"recipient\": my_first_agent,\n", - " \"summary_method\": \"reflection_with_llm\",\n", - " \"summary_prompt\": \"Summarize the conversation into bullet points.\",\n", - " },\n", - " {\n", - " \"recipient\": poetry_agent,\n", - " \"message\": \"Write a poem about the context.\",\n", - " \"max_turns\": 1,\n", - " \"summary_method\": \"last_msg\",\n", - " },\n", - "]\n", - "```\n", - "\n", - "New to nested chats within swarms is the ability to **carryover some context from the swarm chat into the nested chat**. This is done by adding a carryover configuration. If you're not using carryover, then no messages from the swarm chat will be brought into the nested chat.\n", - "\n", - "The carryover is applicable only to the first chat in the nested chats and works together with that nested chat's \"message\" value, if any.\n", - "\n", - "```python\n", - "my_carryover_config = {\n", - " \"summary_method\": \"reflection_with_llm\",\n", - " \"summary_args\": {\"summary_prompt\": \"Summarise the conversation into bullet points.\"}\n", - " }\n", - "```\n", - "\n", - "The `summary_method` can be (with messages referring to the swarm chat's messages): \n", - "\n", - "- `\"all\"` - messages will be converted to a new-line concatenated string, e.g. `[first nested chat message]\\nContext: \\n[swarm message 1]\\n[swarm message 2]\\n...`\n", - "- `\"last_msg\"` - the latest message will be added, e.g. `[first nested chat message]\\nContext: \\n[swarm's latest message]`\n", - "- `\"reflection_with_llm\"` - utilises an LLM to interpret the messages and its resulting response will be added, e.g. `[first nested chat message]\\nContext: \\n[llm response]`\n", - "- `Callable` - a function that returns the full message (this will not concatenate with the first nested chat's message, it will replace it entirely).\n", - "\n", - "The signature of the `summary_method` callable is: \n", - "`def my_method(agent: ConversableAgent, messages: List[Dict[str, Any]], summary_args: Dict) -> str:`\n", - "\n", - "Both the \"reflection_with_llm\" and Callable will be able to utilise the `summary_args` if they are included.\n", - "\n", - "With your configuration available, you can add it to the first chat in the nested chat:\n", - "```python\n", - "nested_chats = [\n", - " {\n", - " \"recipient\": my_first_agent,\n", - " \"summary_method\": \"reflection_with_llm\",\n", - " \"summary_prompt\": \"Summarize the conversation into bullet points.\",\n", - " \"carryover_config\": my_carryover_config,\n", - " },\n", - " {\n", - " \"recipient\": poetry_agent,\n", - " \"message\": \"Write a poem about the context.\",\n", - " \"max_turns\": 1,\n", - " \"summary_method\": \"last_msg\",\n", - " },\n", - "]\n", - "```\n", - "\n", - "Finally, we add the nested chat as a handoff in the same way as we do to an agent:\n", - "\n", - "```python\n", - "agent_1.handoff(\n", - " hand_to=[ON_CONDITION(\n", - " target={\n", - " \"chat_queue\":[nested_chats],\n", - " \"config\": Any,\n", - " \"reply_func_from_nested_chats\": None,\n", - " \"use_async\": False\n", - " },\n", - " condition=\"condition_1\")\n", - " ]\n", - " )\n", - "```\n", - "\n", - "See the documentation on [registering a nested chat](https://docs.ag2.ai/reference/autogen/ConversableAgent#register-nested-chats) for further information on the parameters `reply_func_from_nested_chats`, `use_async`, and `config`.\n", - "\n", - "Once a nested chat is complete, the resulting output from the last chat in the nested chats will be returned as the agent that triggered the nested chat's response.\n", - "\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### AFTER_WORK\n", - "\n", - "When the active agent's response doesn't suggest a tool call or handoff, the chat will terminate by default. However, you can register an `AFTER_WORK` handoff to control what to do next. You can register these `AFTER_WORK` handoffs at the agent level and also the swarm level (through the `after_work` parameter on `initiate_swarm_chat`). The agent level takes precedence over the swarm level.\n", - "\n", - "The AFTER_WORK takes a single parameter and this can be an agent, an agent's name, an `AfterWorkOption`, or a callable function.\n", - "\n", - "The `AfterWorkOption` options are:\n", - "- `TERMINATE`: Terminate the chat \n", - "- `STAY`: Stay at the current agent \n", - "- `REVERT_TO_USER`: Revert to the user agent. Only if a user agent is passed in when initializing. (See below for more details)\n", - "- `SWARM_MANAGER`: Use the internal group chat's `auto` speaker selection method\n", - "\n", - "The callable function signature is:\n", - "`def my_after_work_func(last_speaker: SwarmAgent, messages: List[Dict[str, Any]], groupchat: GroupChat) -> Union[AfterWorkOption, SwarmAgent, str]:`\n", - "\n", - "Note: there should only be one `AFTER_WORK`, if your requirement is more complex, use the callable function parameter.\n", - "\n", - "Here are examples of registering AFTER_WORKS\n", - "\n", - "```python\n", - "# Register the handoff to an agent\n", - "agent_1.handoff(hand_to=[\n", - " ON_CONDITION(...), \n", - " ON_CONDITION(...),\n", - " AFTER_WORK(agent_4) # Fallback to agent_4 if no ON_CONDITION handoff is suggested\n", - "])\n", - "\n", - "# Register the handoff to an AfterWorkOption\n", - "agent_2.handoff(hand_to=[AFTER_WORK(AfterWorkOption.TERMINATE)]) # Terminate the chat if no handoff is suggested\n", - "\n", - "def my_after_work_func(last_speaker: SwarmAgent, messages: List[Dict[str, Any]], groupchat: GroupChat) -> Union[AfterWorkOption, SwarmAgent, str]:\n", - " if last_speaker.get_context(\"agent_1_done\"):\n", - " return agent_2\n", - " else:\n", - " return AfterWorkOption.TERMINATE\n", - "\n", - "# Register the handoff to a function that will return an agent or AfterWorkOption\n", - "agent_3.handoff(hand_to=[AFTER_WORK(my_after_work_func)])\n", - "\n", - "# Register the swarm level AFTER_WORK that becomes the default for agents that don't have one specified\n", - "chat_history, context_variables, last_active_agent = initiate_swarm_chat(\n", - " ...\n", - " after_work=AfterWorkOption.TERMINATE # Or an agent or Callable\n", - ")\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### SwarmResult\n", - "\n", - "When tools are called, a `SwarmResult` can be returned and that can be used to specify the next agent to speak through the `SwarmResult`'s `agent` parameter.\n", - "\n", - "The `agent` property can be an agent object, an agent's name (string), an `AfterWorkOption`, or `None`.\n", - "- If it is an agent object or agent name, that agent will be the next speaker.\n", - "- If `None` it will return to the previous speaker.\n", - "- If an `AfterWorkOption`, it will follow the rules noted in the previous section.\n", - "\n", - "By using an `AfterWorkOption` you have additional flexibility, such as terminating the swarm at this point, or transferring to the swarm's user agent." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Update Agent state before replying\n", - "\n", - "It can be useful to update a swarm agent's state before they reply. For example, using an agent's context variables you could change their system message based on the state of the workflow.\n", - "\n", - "When initialising a swarm agent use the `update_agent_state_before_reply` parameter to register updates that run after the agent is selected, but before they reply.\n", - "\n", - "`update_agent_state_before_reply` takes a list of any combination of the following (executing them in the provided order):\n", - "\n", - "- `UPDATE_SYSTEM_MESSAGE` provides a simple way to update the agent's system message via an f-string that substitutes the values of context variables, or a Callable that returns a string\n", - "- Callable with two parameters of type `ConversableAgent` for the agent and `List[Dict[str Any]]` for the messages, and does not return a value\n", - "\n", - "Below is an example of setting these up when creating a Swarm agent.\n", - "\n", - "```python\n", - "# Creates a system message string\n", - "def create_system_prompt_function(my_agent: ConversableAgent, messages: List[Dict[]]) -> str:\n", - " preferred_name = my_agent.get_context(\"preferred_name\", \"(name not provided)\")\n", - "\n", - " # Note that the returned string will be treated like an f-string using the context variables\n", - " return \"You are a customer service representative helping a customer named \"\n", - " + preferred_name\n", - " + \" and their passport number is '{passport_number}'.\"\n", - "\n", - "# Function to update an Agent's state\n", - "def my_callable_state_update_function(my_agent: ConversableAgent, messages: List[Dict[]]) -> None:\n", - " agent.set_context(\"context_key\", 43)\n", - " agent.update_system_message(\"You are a customer service representative.\")\n", - "\n", - "# Create the SwarmAgent and set agent updates\n", - "customer_service = SwarmAgent(\n", - " name=\"CustomerServiceRep\",\n", - " system_message=\"You are a customer service representative.\",\n", - " update_agent_state_before_reply=[\n", - " UPDATE_SYSTEM_MESSAGE(\"You are a customer service representative. Quote passport number '{passport_number}'\"),\n", - " UPDATE_SYSTEM_MESSAGE(create_system_prompt_function),\n", - " my_callable_state_update_function]\n", - " ...\n", - ")\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Initialize SwarmChat with `initiate_swarm_chat` / `a_initiate_swarm_chat`\n", - "\n", - "After a set of swarm agents are created, you can initiate a swarm chat by calling `initiate_swarm_chat` (or `a_initiate_swarm_chat` for an asynchronous version).\n", - "\n", - "```python\n", - "chat_history, context_variables, last_active_agent = initiate_swarm_chat(\n", - " initial_agent=agent_1, # the first agent to start the chat\n", - " agents=[agent_1, agent_2, agent_3], # a list of agents\n", - " messages=[{\"role\": \"user\", \"content\": \"Hello\"}], # a list of messages to start the chat, you can also pass in one string\n", - " user_agent=user_agent, # optional, if you want to revert to the user agent\n", - " context_variables={\"key\": \"value\"} # optional, initial context variables\n", - ")\n", - "```\n", - "\n", - "How we handle messages: \n", - "- Case 1: If you pass in one single message \n", - " - If there is a name in that message, we will assume this message is from that agent. (It will be error if that name doesn't match any agent you passed in.) \n", - " - If there is no name, 1. User agent passed in: we assume this message is from the user agent. 2. No user agent passed in: we will create a temporary user agent just to start the chat. \n", - "- Case 2: We will use the [Resume GroupChat](https://docs.ag2.ai/docs/topics/groupchat/resuming_groupchat) feature to resume the chat. The `name` fields in these messages must be one of the names of the agents you passed in, otherwise, it will be an error.\n", - "\n", - "## Q&As\n", - "\n", - "> How are context variables updated?\n", - "\n", - "In a swarm, the context variables are shared amongst Swarm agents. As context variables are available at the agent level, you can use the context variable getters/setters on the agent to view and change the shared context variables. If you're working with a function that returns a `SwarmResult` you should update the passed in context variables and return it in the `SwarmResult`, this will ensure the shared context is updated.\n", - "\n", - "> What is the difference between ON_CONDITION and AFTER_WORK?\n", - "\n", - "When registering an ON_CONDITION handoff, we are creating a function schema to be passed to the LLM. The LLM will decide whether to call this function.\n", - "\n", - "When registering an AFTER_WORK handoff, we are defining the fallback mechanism when no tool calls are suggested. This is a higher level of control from the swarm chat level.\n", - "\n", - "> When to pass in a user agent?\n", - "\n", - "If your application requires interactions with the user, you can pass in a user agent to the groupchat, so that don't need to write an outer loop to accept user inputs and call swarm.\n", - "\n", - "\n", - "## Demonstration\n", - "\n", - "\n", - "### Create Swarm Agents" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import autogen\n", - "\n", - "config_list = autogen.config_list_from_json(...)\n", - "llm_config = {\"config_list\": config_list}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Agent 1 function schema:\n", - "{'type': 'function', 'function': {'description': '', 'name': 'update_context_1', 'parameters': {'type': 'object', 'properties': {}}}}\n", - "{'type': 'function', 'function': {'description': 'Transfer to agent 2', 'name': 'transfer_to_agent_2', 'parameters': {'type': 'object', 'properties': {}}}}\n", - "Agent 3 function schema:\n", - "{'type': 'function', 'function': {'description': 'Transfer to Agent 4', 'name': 'transfer_to_Agent_4', 'parameters': {'type': 'object', 'properties': {}}}}\n" - ] - } - ], - "source": [ - "import random\n", - "\n", - "from autogen import (\n", - " AFTER_WORK,\n", - " ON_CONDITION,\n", - " AfterWorkOption,\n", - " SwarmAgent,\n", - " SwarmResult,\n", - " initiate_swarm_chat,\n", - ")\n", - "\n", - "\n", - "# 1. A function that returns a value of \"success\" and updates the context variable \"1\" to True\n", - "def update_context_1(context_variables: dict) -> SwarmResult:\n", - " context_variables[\"1\"] = True\n", - " return SwarmResult(value=\"success\", context_variables=context_variables)\n", - "\n", - "\n", - "# 2. A function that returns an SwarmAgent object\n", - "def transfer_to_agent_2() -> SwarmAgent:\n", - " \"\"\"Transfer to agent 2\"\"\"\n", - " return agent_2\n", - "\n", - "\n", - "# 3. A function that returns the value of \"success\", updates the context variable and transfers to agent 3\n", - "def update_context_2_and_transfer_to_3(context_variables: dict) -> SwarmResult:\n", - " context_variables[\"2\"] = True\n", - " return SwarmResult(value=\"success\", context_variables=context_variables, agent=agent_3)\n", - "\n", - "\n", - "# 4. A function that returns a normal value\n", - "def get_random_number() -> str:\n", - " return random.randint(1, 100)\n", - "\n", - "\n", - "def update_context_3_with_random_number(context_variables: dict, random_number: int) -> SwarmResult:\n", - " context_variables[\"3\"] = random_number\n", - " return SwarmResult(value=\"success\", context_variables=context_variables)\n", - "\n", - "\n", - "agent_1 = SwarmAgent(\n", - " name=\"Agent_1\",\n", - " system_message=\"You are Agent 1, first, call the function to update context 1, and transfer to Agent 2\",\n", - " llm_config=llm_config,\n", - " functions=[update_context_1, transfer_to_agent_2],\n", - ")\n", - "\n", - "agent_2 = SwarmAgent(\n", - " name=\"Agent_2\",\n", - " system_message=\"You are Agent 2, call the function that updates context 2 and transfer to Agent 3\",\n", - " llm_config=llm_config,\n", - " functions=[update_context_2_and_transfer_to_3],\n", - ")\n", - "\n", - "agent_3 = SwarmAgent(\n", - " name=\"Agent_3\",\n", - " system_message=\"You are Agent 3, tell a joke\",\n", - " llm_config=llm_config,\n", - ")\n", - "\n", - "agent_4 = SwarmAgent(\n", - " name=\"Agent_4\",\n", - " system_message=\"You are Agent 4, call the function to get a random number\",\n", - " llm_config=llm_config,\n", - " functions=[get_random_number],\n", - ")\n", - "\n", - "agent_5 = SwarmAgent(\n", - " name=\"Agent_5\",\n", - " system_message=\"Update context 3 with the random number.\",\n", - " llm_config=llm_config,\n", - " functions=[update_context_3_with_random_number],\n", - ")\n", - "\n", - "\n", - "# This is equivalent to writing a transfer function\n", - "agent_3.register_hand_off(ON_CONDITION(agent_4, \"Transfer to Agent 4\"))\n", - "\n", - "agent_4.register_hand_off([AFTER_WORK(agent_5)])\n", - "\n", - "print(\"Agent 1 function schema:\")\n", - "for func_schema in agent_1.llm_config[\"tools\"]:\n", - " print(func_schema)\n", - "\n", - "print(\"Agent 3 function schema:\")\n", - "for func_schema in agent_3.llm_config[\"tools\"]:\n", - " print(func_schema)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Start Chat" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33m_User\u001b[0m (to chat_manager):\n", - "\n", - "start\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Agent_1\n", - "\u001b[0m\n", - "\u001b[33mAgent_1\u001b[0m (to chat_manager):\n", - "\n", - "\u001b[32m***** Suggested tool call (call_kfcEAY2IeRZww06CQN7lbxOf): update_context_1 *****\u001b[0m\n", - "Arguments: \n", - "{}\n", - "\u001b[32m*********************************************************************************\u001b[0m\n", - "\u001b[32m***** Suggested tool call (call_izl5eyV8IQ0Wg6XY2SaR1EJM): transfer_to_agent_2 *****\u001b[0m\n", - "Arguments: \n", - "{}\n", - "\u001b[32m************************************************************************************\u001b[0m\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Tool_Execution\n", - "\u001b[0m\n", - "\u001b[35m\n", - ">>>>>>>> EXECUTING FUNCTION update_context_1...\u001b[0m\n", - "\u001b[35m\n", - ">>>>>>>> EXECUTING FUNCTION transfer_to_agent_2...\u001b[0m\n", - "\u001b[33mTool_Execution\u001b[0m (to chat_manager):\n", - "\n", - "\u001b[32m***** Response from calling tool (call_kfcEAY2IeRZww06CQN7lbxOf) *****\u001b[0m\n", - "\n", - "\u001b[32m**********************************************************************\u001b[0m\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m***** Response from calling tool (call_izl5eyV8IQ0Wg6XY2SaR1EJM) *****\u001b[0m\n", - "SwarmAgent --> Agent_2\n", - "\u001b[32m**********************************************************************\u001b[0m\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Agent_2\n", - "\u001b[0m\n", - "\u001b[33mAgent_2\u001b[0m (to chat_manager):\n", - "\n", - "\u001b[32m***** Suggested tool call (call_Yf5DTGaaYkA726ubnfJAvQMq): update_context_2_and_transfer_to_3 *****\u001b[0m\n", - "Arguments: \n", - "{}\n", - "\u001b[32m***************************************************************************************************\u001b[0m\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Tool_Execution\n", - "\u001b[0m\n", - "\u001b[35m\n", - ">>>>>>>> EXECUTING FUNCTION update_context_2_and_transfer_to_3...\u001b[0m\n", - "\u001b[33mTool_Execution\u001b[0m (to chat_manager):\n", - "\n", - "\u001b[32m***** Response from calling tool (call_Yf5DTGaaYkA726ubnfJAvQMq) *****\u001b[0m\n", - "\n", - "\u001b[32m**********************************************************************\u001b[0m\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Agent_3\n", - "\u001b[0m\n", - "\u001b[33mAgent_3\u001b[0m (to chat_manager):\n", - "\n", - "\u001b[32m***** Suggested tool call (call_jqZNHuMtQYeNh5Mq4pV2uwAj): transfer_to_Agent_4 *****\u001b[0m\n", - "Arguments: \n", - "{}\n", - "\u001b[32m************************************************************************************\u001b[0m\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Tool_Execution\n", - "\u001b[0m\n", - "\u001b[35m\n", - ">>>>>>>> EXECUTING FUNCTION transfer_to_Agent_4...\u001b[0m\n", - "\u001b[33mTool_Execution\u001b[0m (to chat_manager):\n", - "\n", - "\u001b[32m***** Response from calling tool (call_jqZNHuMtQYeNh5Mq4pV2uwAj) *****\u001b[0m\n", - "SwarmAgent --> Agent_4\n", - "\u001b[32m**********************************************************************\u001b[0m\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Agent_4\n", - "\u001b[0m\n", - "\u001b[33mAgent_4\u001b[0m (to chat_manager):\n", - "\n", - "\u001b[32m***** Suggested tool call (call_KeNGv98klvDZsrAX10Ou3I71): get_random_number *****\u001b[0m\n", - "Arguments: \n", - "{}\n", - "\u001b[32m**********************************************************************************\u001b[0m\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Tool_Execution\n", - "\u001b[0m\n", - "\u001b[35m\n", - ">>>>>>>> EXECUTING FUNCTION get_random_number...\u001b[0m\n", - "\u001b[33mTool_Execution\u001b[0m (to chat_manager):\n", - "\n", - "\u001b[32m***** Response from calling tool (call_KeNGv98klvDZsrAX10Ou3I71) *****\u001b[0m\n", - "27\n", - "\u001b[32m**********************************************************************\u001b[0m\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Agent_4\n", - "\u001b[0m\n", - "\u001b[33mAgent_4\u001b[0m (to chat_manager):\n", - "\n", - "The random number generated is 27.\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Agent_5\n", - "\u001b[0m\n", - "\u001b[33mAgent_5\u001b[0m (to chat_manager):\n", - "\n", - "\u001b[32m***** Suggested tool call (call_MlSGNNktah3m3QGssWBEzxCe): update_context_3_with_random_number *****\u001b[0m\n", - "Arguments: \n", - "{\"random_number\":27}\n", - "\u001b[32m****************************************************************************************************\u001b[0m\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Tool_Execution\n", - "\u001b[0m\n", - "\u001b[35m\n", - ">>>>>>>> EXECUTING FUNCTION update_context_3_with_random_number...\u001b[0m\n", - "\u001b[33mTool_Execution\u001b[0m (to chat_manager):\n", - "\n", - "\u001b[32m***** Response from calling tool (call_MlSGNNktah3m3QGssWBEzxCe) *****\u001b[0m\n", - "\n", - "\u001b[32m**********************************************************************\u001b[0m\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Agent_5\n", - "\u001b[0m\n", - "\u001b[33mAgent_5\u001b[0m (to chat_manager):\n", - "\n", - "The random number 27 has been successfully updated in context 3.\n", - "\n", - "--------------------------------------------------------------------------------\n" - ] - } - ], - "source": [ - "context_variables = {\"1\": False, \"2\": False, \"3\": False}\n", - "chat_result, context_variables, last_agent = initiate_swarm_chat(\n", - " initial_agent=agent_1,\n", - " agents=[agent_1, agent_2, agent_3, agent_4, agent_5],\n", - " messages=\"start\",\n", - " context_variables=context_variables,\n", - " after_work=AFTER_WORK(AfterWorkOption.TERMINATE), # this is the default\n", - ")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'1': True, '2': True, '3': 27}\n" - ] - } - ], - "source": [ - "print(context_variables)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Demo with User Agent\n", - "\n", - "We pass in a user agent to the swarm chat to accept user inputs. With `agent_6`, we register an `AFTER_WORK` handoff to revert to the user agent when no tool calls are suggested. " - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\u001b[33mUser\u001b[0m (to chat_manager):\n", - "\n", - "start\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Agent_6\n", - "\u001b[0m\n", - "\u001b[33mAgent_6\u001b[0m (to chat_manager):\n", - "\n", - "Why did the scarecrow win an award? \n", - "\n", - "Because he was outstanding in his field! \n", - "\n", - "Want to hear another one?\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: User\n", - "\u001b[0m\n", - "\u001b[33mUser\u001b[0m (to chat_manager):\n", - "\n", - "yes\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Agent_6\n", - "\u001b[0m\n", - "\u001b[33mAgent_6\u001b[0m (to chat_manager):\n", - "\n", - "Why don't skeletons fight each other?\n", - "\n", - "They don't have the guts! \n", - "\n", - "How about another?\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: User\n", - "\u001b[0m\n", - "\u001b[33mUser\u001b[0m (to chat_manager):\n", - "\n", - "transfer\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Agent_6\n", - "\u001b[0m\n", - "\u001b[33mAgent_6\u001b[0m (to chat_manager):\n", - "\n", - "\u001b[32m***** Suggested tool call (call_gQ9leFamxgzQp8ZVQB8rUH73): transfer_to_Agent_7 *****\u001b[0m\n", - "Arguments: \n", - "{}\n", - "\u001b[32m************************************************************************************\u001b[0m\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Tool_Execution\n", - "\u001b[0m\n", - "\u001b[35m\n", - ">>>>>>>> EXECUTING FUNCTION transfer_to_Agent_7...\u001b[0m\n", - "\u001b[33mTool_Execution\u001b[0m (to chat_manager):\n", - "\n", - "\u001b[32m***** Response from calling tool (call_gQ9leFamxgzQp8ZVQB8rUH73) *****\u001b[0m\n", - "SwarmAgent --> Agent_7\n", - "\u001b[32m**********************************************************************\u001b[0m\n", - "\n", - "--------------------------------------------------------------------------------\n", - "\u001b[32m\n", - "Next speaker: Agent_7\n", - "\u001b[0m\n", - "\u001b[33mAgent_7\u001b[0m (to chat_manager):\n", - "\n", - "The joke about the scarecrow winning an award is a play on words. It utilizes the term \"outstanding,\" which can mean both exceptionally good (in the context of the scarecrow's performance) and literally being \"standing out\" in a field (where scarecrows are placed). So, the double meaning creates a pun that makes the joke humorous. \n", - "\n", - "The skeleton joke works similarly. When it says skeletons \"don't have the guts,\" it plays on the literal fact that skeletons don't have internal organs (guts), and metaphorically, \"having guts\" means having courage. The humor comes from this clever wordplay.\n", - "\n", - "--------------------------------------------------------------------------------\n" - ] - } - ], - "source": [ - "from autogen import UserProxyAgent\n", - "\n", - "user_agent = UserProxyAgent(name=\"User\", code_execution_config=False)\n", - "\n", - "agent_6 = SwarmAgent(\n", - " name=\"Agent_6\",\n", - " system_message=\"You are Agent 6. Your job is to tell jokes.\",\n", - " llm_config=llm_config,\n", - ")\n", - "\n", - "agent_7 = SwarmAgent(\n", - " name=\"Agent_7\",\n", - " system_message=\"You are Agent 7, explain the joke.\",\n", - " llm_config=llm_config,\n", - ")\n", - "\n", - "agent_6.register_hand_off(\n", - " [\n", - " ON_CONDITION(\n", - " agent_7, \"Used to transfer to Agent 7. Don't call this function, unless the user explicitly tells you to.\"\n", - " ),\n", - " AFTER_WORK(AfterWorkOption.REVERT_TO_USER),\n", - " ]\n", - ")\n", - "\n", - "chat_result, _, _ = initiate_swarm_chat(\n", - " initial_agent=agent_6,\n", - " agents=[agent_6, agent_7],\n", - " user_agent=user_agent,\n", - " messages=\"start\",\n", - ")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "autodev", - "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.9.19" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/website/use-cases/walk-throughs/tools-with-secrets.md b/website/docs/user-guide/advanced-concepts/tools-with-secrets.mdx similarity index 99% rename from website/use-cases/walk-throughs/tools-with-secrets.md rename to website/docs/user-guide/advanced-concepts/tools-with-secrets.mdx index 277f7748c1..2883b708d7 100644 --- a/website/use-cases/walk-throughs/tools-with-secrets.md +++ b/website/docs/user-guide/advanced-concepts/tools-with-secrets.mdx @@ -1,4 +1,6 @@ -# Tools with Secrets +--- +title: Tools with Secrets +--- Secrets such as password, tokens, or personal information needs to be protected from capture. AG2 provides dependency injection as a way to secure this sensitive information while still allowing agents to perform their tasks effectively, even when working with large language models (LLMs). diff --git a/website/mint-json-template.json.jinja b/website/mint-json-template.json.jinja index e951091562..d435619905 100644 --- a/website/mint-json-template.json.jinja +++ b/website/mint-json-template.json.jinja @@ -103,26 +103,11 @@ { "group": "Advanced Concepts", "pages": [ - "docs/user-guide/advanced-concepts/retrieval_augmentation", - { - "group": "Group Chat", - "pages": [ - "docs/user-guide/advanced-concepts/groupchat/customized_speaker_selection", - "docs/user-guide/advanced-concepts/groupchat/resuming_groupchat", - "docs/user-guide/advanced-concepts/groupchat/transform_messages_speaker_selection", - "docs/user-guide/advanced-concepts/groupchat/using_custom_model_client_classes" - ] - }, - "docs/user-guide/advanced-concepts/swarm", - { - "group": "Code Execution", - "pages": [ - "docs/user-guide/advanced-concepts/code-execution/cli-code-executor", - "docs/user-guide/advanced-concepts/code-execution/custom-executor", - "docs/user-guide/advanced-concepts/code-execution/jupyter-code-executor", - "docs/user-guide/advanced-concepts/code-execution/user-defined-functions" - ] - } + "docs/user-guide/advanced-concepts/rag", + "docs/user-guide/advanced-concepts/custom-group-chat", + "docs/user-guide/advanced-concepts/enhanced-swarm", + "docs/user-guide/advanced-concepts/tools-with-secrets", + "docs/user-guide/advanced-concepts/code-execution" ] } ] diff --git a/website/use-cases/walk-throughs/index.md b/website/use-cases/walk-throughs/index.md deleted file mode 100644 index 80a062f925..0000000000 --- a/website/use-cases/walk-throughs/index.md +++ /dev/null @@ -1,3 +0,0 @@ -# Code walk-throughs - -Here are a set of use case scenarios to help you build more capable, robust, and secure agentic applications.