diff --git a/autogen/oai/anthropic.py b/autogen/oai/anthropic.py index 9f9203ef2299..e2448929e618 100644 --- a/autogen/oai/anthropic.py +++ b/autogen/oai/anthropic.py @@ -49,10 +49,10 @@ "claude-3-5-sonnet-20240620": (0.003, 0.015), "claude-3-sonnet-20240229": (0.003, 0.015), "claude-3-opus-20240229": (0.015, 0.075), - "claude-2.0": (0.008, 0.024), + "claude-3-haiku-20240307": (0.00025, 0.00125), "claude-2.1": (0.008, 0.024), - "claude-3.0-opus": (0.015, 0.075), - "claude-3.0-haiku": (0.00025, 0.00125), + "claude-2.0": (0.008, 0.024), + "claude-instant-1.2": (0.008, 0.024), } @@ -181,7 +181,7 @@ def create(self, params: Dict[str, Any]) -> Completion: response_oai = ChatCompletion( id=response.id, model=anthropic_params["model"], - created=int(time.time() * 1000), + created=int(time.time()), object="chat.completion", choices=choices, usage=CompletionUsage( @@ -242,86 +242,106 @@ def oai_messages_to_anthropic_messages(params: Dict[str, Any]) -> list[dict[str, # Convert messages to Anthropic compliant format processed_messages = [] + + # Used to interweave user messages to ensure user/assistant alternating + user_continue_message = {"content": "Please continue.", "role": "user"} + assistant_continue_message = {"content": "Please continue.", "role": "assistant"} + tool_use_messages = 0 tool_result_messages = 0 last_tool_use_index = -1 + last_tool_result_index = -1 for message in params["messages"]: if message["role"] == "system": params["system"] = message["content"] - elif "tool_calls" in message: - # Map the tool call options to Anthropic's ToolUseBlock - tool_uses = [] - tool_names = [] - for tool_call in message["tool_calls"]: - tool_uses.append( - ToolUseBlock( - type="tool_use", - id=tool_call["id"], - name=tool_call["function"]["name"], - input=json.loads(tool_call["function"]["arguments"]), + else: + # New messages will be added here, manage role alternations + expected_role = "user" if len(processed_messages) % 2 == 0 else "assistant" + + if "tool_calls" in message: + # Map the tool call options to Anthropic's ToolUseBlock + tool_uses = [] + tool_names = [] + for tool_call in message["tool_calls"]: + tool_uses.append( + ToolUseBlock( + type="tool_use", + id=tool_call["id"], + name=tool_call["function"]["name"], + input=json.loads(tool_call["function"]["arguments"]), + ) ) - ) - tool_names.append(tool_call["function"]["name"]) - - if has_tools: - processed_messages.append({"role": "assistant", "content": tool_uses}) - tool_use_messages += 1 - last_tool_use_index = len(processed_messages) - 1 - else: - # Not using tools, so put in a plain text message - processed_messages.append( - { - "role": "assistant", - "content": f"Some internal function(s) that could be used: [{', '.join(tool_names)}]", - } - ) - elif "tool_call_id" in message: - if has_tools: - # Map the tool usage call to tool_result for Anthropic - processed_messages.append( - { - "role": "user", - "content": [ - { - "type": "tool_result", - "tool_use_id": message["tool_call_id"], - "content": message["content"], - } - ], + if has_tools: + tool_use_messages += 1 + tool_names.append(tool_call["function"]["name"]) + + if expected_role == "user": + # Insert an extra user message as we will append an assistant message + processed_messages.append(user_continue_message) + + if has_tools: + processed_messages.append({"role": "assistant", "content": tool_uses}) + last_tool_use_index = len(processed_messages) - 1 + else: + # Not using tools, so put in a plain text message + processed_messages.append( + { + "role": "assistant", + "content": f"Some internal function(s) that could be used: [{', '.join(tool_names)}]", + } + ) + elif "tool_call_id" in message: + if has_tools: + # Map the tool usage call to tool_result for Anthropic + tool_result = { + "type": "tool_result", + "tool_use_id": message["tool_call_id"], + "content": message["content"], } - ) - tool_result_messages += 1 + + # If the previous message also had a tool_result, add it to that + # Otherwise append a new message + if last_tool_result_index == len(processed_messages) - 1: + processed_messages[-1]["content"].append(tool_result) + else: + if expected_role == "assistant": + # Insert an extra assistant message as we will append a user message + processed_messages.append(assistant_continue_message) + + processed_messages.append({"role": "user", "content": [tool_result]}) + last_tool_result_index = len(processed_messages) - 1 + + tool_result_messages += 1 + else: + # Not using tools, so put in a plain text message + processed_messages.append( + {"role": "user", "content": f"Running the function returned: {message['content']}"} + ) + elif message["content"] == "": + # Ignoring empty messages + pass else: - # Not using tools, so put in a plain text message - processed_messages.append( - {"role": "user", "content": f"Running the function returned: {message['content']}"} - ) - elif message["content"] == "": - message["content"] = ( - "I'm done. Please send TERMINATE" # TODO: Determine why we would be getting a blank response. Typically this is because 'assistant' is the last message role. - ) - processed_messages.append(message) - else: - processed_messages.append(message) + if expected_role != message["role"]: + # Inserting the alternating continue message + processed_messages.append( + user_continue_message if expected_role == "user" else assistant_continue_message + ) - # We'll drop the last tool_use if there's no tool_result (occurs if we finish the conversation before running the function) - if tool_use_messages != tool_result_messages: - # Too many tool_use messages, drop the last one as we haven't run it. - processed_messages.pop(last_tool_use_index) + processed_messages.append(message) - # Check for interleaving roles and correct, for Anthropic must be: user, assistant, user, etc. - for i, message in enumerate(processed_messages): - if message["role"] is not ("user" if i % 2 == 0 else "assistant"): - message["role"] = "user" if i % 2 == 0 else "assistant" + # We'll replace the last tool_use if there's no tool_result (occurs if we finish the conversation before running the function) + if has_tools and tool_use_messages != tool_result_messages: + processed_messages[last_tool_use_index] = assistant_continue_message - # Also remove name key from message as it is not supported - message.pop("name", None) + # name is not a valid field on messages + for message in processed_messages: + if "name" in message: + message.pop("name", None) # Note: When using reflection_with_llm we may end up with an "assistant" message as the last message and that may cause a blank response + # So, if the last role is not user, add a 'user' continue message at the end if processed_messages[-1]["role"] != "user": - # If the last role is not user, add a continue message at the end - continue_message = {"content": "continue", "role": "user"} - processed_messages.append(continue_message) + processed_messages.append(user_continue_message) return processed_messages diff --git a/autogen/oai/gemini.py b/autogen/oai/gemini.py index 3f82c976c7be..41431491e3fb 100644 --- a/autogen/oai/gemini.py +++ b/autogen/oai/gemini.py @@ -268,7 +268,7 @@ def create(self, params: Dict) -> ChatCompletion: response_oai = ChatCompletion( id=str(random.randint(0, 1000)), model=model_name, - created=int(time.time() * 1000), + created=int(time.time()), object="chat.completion", choices=choices, usage=CompletionUsage( diff --git a/autogen/oai/mistral.py b/autogen/oai/mistral.py index 832369376af9..8017e3536324 100644 --- a/autogen/oai/mistral.py +++ b/autogen/oai/mistral.py @@ -175,7 +175,7 @@ def create(self, params: Dict[str, Any]) -> ChatCompletion: response_oai = ChatCompletion( id=mistral_response.id, model=mistral_response.model, - created=int(time.time() * 1000), + created=int(time.time()), object="chat.completion", choices=choices, usage=CompletionUsage( diff --git a/autogen/oai/together.py b/autogen/oai/together.py index ef6c09804a46..bbbe851ba776 100644 --- a/autogen/oai/together.py +++ b/autogen/oai/together.py @@ -209,7 +209,7 @@ def create(self, params: Dict) -> ChatCompletion: response_oai = ChatCompletion( id=response.id, model=together_params["model"], - created=int(time.time() * 1000), + created=int(time.time()), object="chat.completion", choices=choices, usage=CompletionUsage( diff --git a/autogen/version.py b/autogen/version.py index 4f6b515ecb20..77fc1e2ea295 100644 --- a/autogen/version.py +++ b/autogen/version.py @@ -1 +1 @@ -__version__ = "0.2.29" +__version__ = "0.2.31" diff --git a/notebook/agentchat_agentops.ipynb b/notebook/agentchat_agentops.ipynb index 293efa8e4bd6..71106e45d3c4 100644 --- a/notebook/agentchat_agentops.ipynb +++ b/notebook/agentchat_agentops.ipynb @@ -7,7 +7,7 @@ "collapsed": false }, "source": [ - "# AgentOps" + "# Agent Tracking with AgentOps" ] }, { @@ -15,7 +15,7 @@ "id": "a447802c88c8a240", "metadata": {}, "source": [ - "![logo](https://raw.githubusercontent.com/AgentOps-AI/agentops/35d5682866921a9e28d8ef66ae3c3b3d92d8fa6b/img/logo.png)\n", + "\n", "\n", "[AgentOps](https://agentops.ai/?=autogen) provides session replays, metrics, and monitoring for AI agents.\n", "\n", @@ -27,8 +27,11 @@ "id": "b354c068", "metadata": {}, "source": [ - "### Dashboard\n", - "![Agent Dashboard](https://github.com/AgentOps-AI/agentops/assets/14807319/158e082a-9a7d-49b7-9b41-51a49a1f7d3d)" + "### Overview Dashboard\n", + "\n", + "\n", + "### Session Replays\n", + "" ] }, { @@ -39,7 +42,7 @@ "## Adding AgentOps to an existing Autogen service.\n", "To get started, you'll need to install the AgentOps package and set an API key.\n", "\n", - "AgentOps automatically configures itself when it's initialized. This means your agents will be tracked and logged to your AgentOps account right away." + "AgentOps automatically configures itself when it's initialized meaning your agent run data will be tracked and logged to your AgentOps account right away." ] }, { @@ -69,7 +72,7 @@ "\n", "By default, the AgentOps `init()` function will look for an environment variable named `AGENTOPS_API_KEY`. Alternatively, you can pass one in as an optional parameter.\n", "\n", - "Create an account and API key at [AgentOps.ai](https://agentops.ai/)" + "Create an account and obtain an API key at [AgentOps.ai](https://agentops.ai/settings/projects)" ] }, { @@ -87,12 +90,14 @@ "name": "stderr", "output_type": "stream", "text": [ - "πŸ–‡ AgentOps: \u001B[34m\u001B[34mSession Replay: https://app.agentops.ai/drilldown?session_id=8bfaeed1-fd51-4c68-b3ec-276b1a3ce8a4\u001B[0m\u001B[0m\n" + "πŸ–‡ AgentOps: \u001b[34m\u001b[34mSession Replay: https://app.agentops.ai/drilldown?session_id=8bfaeed1-fd51-4c68-b3ec-276b1a3ce8a4\u001b[0m\u001b[0m\n" ] }, { "data": { - "text/plain": "UUID('8bfaeed1-fd51-4c68-b3ec-276b1a3ce8a4')" + "text/plain": [ + "UUID('8bfaeed1-fd51-4c68-b3ec-276b1a3ce8a4')" + ] }, "execution_count": 1, "metadata": {}, @@ -104,7 +109,7 @@ "\n", "from autogen import ConversableAgent, UserProxyAgent, config_list_from_json\n", "\n", - "agentops.init(api_key=\"7c94212b-b89d-47a6-a20c-23b2077d3226\") # or agentops.init(api_key=\"...\")" + "agentops.init(api_key=\"...\")" ] }, { @@ -144,19 +149,19 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001B[33magent\u001B[0m (to user):\n", + "\u001b[33magent\u001b[0m (to user):\n", "\n", "How can I help you today?\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[33muser\u001B[0m (to agent):\n", + "\u001b[33muser\u001b[0m (to agent):\n", "\n", "2+2\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001B[0m\n", - "\u001B[33magent\u001B[0m (to user):\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33magent\u001b[0m (to user):\n", "\n", "2 + 2 equals 4.\n", "\n", @@ -168,7 +173,7 @@ "output_type": "stream", "text": [ "πŸ–‡ AgentOps: This run's cost $0.000960\n", - "πŸ–‡ AgentOps: \u001B[34m\u001B[34mSession Replay: https://app.agentops.ai/drilldown?session_id=8bfaeed1-fd51-4c68-b3ec-276b1a3ce8a4\u001B[0m\u001B[0m\n" + "πŸ–‡ AgentOps: \u001b[34m\u001b[34mSession Replay: https://app.agentops.ai/drilldown?session_id=8bfaeed1-fd51-4c68-b3ec-276b1a3ce8a4\u001b[0m\u001b[0m\n" ] } ], @@ -185,7 +190,7 @@ "# Create the agent that represents the user in the conversation.\n", "user_proxy = UserProxyAgent(\"user\", code_execution_config=False)\n", "\n", - "# Let the assistant start the conversation. It will end when the user types exit.\n", + "# Let the assistant start the conversation. It will end when the user types \"exit\".\n", "assistant.initiate_chat(user_proxy, message=\"How can I help you today?\")\n", "\n", "# Close your AgentOps session to indicate that it completed.\n", @@ -204,13 +209,13 @@ }, { "cell_type": "markdown", - "source": [ - "![Session_Overview](https://github.com/AgentOps-AI/agentops/assets/14807319/d7228019-1488-40d3-852f-a61e998658ad)" - ], + "id": "cbd689b0f5617013", "metadata": { "collapsed": false }, - "id": "cbd689b0f5617013" + "source": [ + "![session replay](https://github.com/AgentOps-AI/agentops/blob/main/docs/images/external/app_screenshots/session-overview.png?raw=true)" + ] }, { "cell_type": "markdown", @@ -236,70 +241,70 @@ "name": "stderr", "output_type": "stream", "text": [ - "πŸ–‡ AgentOps: \u001B[34m\u001B[34mSession Replay: https://app.agentops.ai/drilldown?session_id=880c206b-751e-4c23-9313-8684537fc04d\u001B[0m\u001B[0m\n" + "πŸ–‡ AgentOps: \u001b[34m\u001b[34mSession Replay: https://app.agentops.ai/drilldown?session_id=880c206b-751e-4c23-9313-8684537fc04d\u001b[0m\u001b[0m\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ - "\u001B[33mUser\u001B[0m (to Assistant):\n", + "\u001b[33mUser\u001b[0m (to Assistant):\n", "\n", "What is (1423 - 123) / 3 + (32 + 23) * 5?\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001B[0m\n", - "\u001B[33mAssistant\u001B[0m (to User):\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33mAssistant\u001b[0m (to User):\n", "\n", - "\u001B[32m***** Suggested tool call (call_aINcGyo0Xkrh9g7buRuhyCz0): calculator *****\u001B[0m\n", + "\u001b[32m***** Suggested tool call (call_aINcGyo0Xkrh9g7buRuhyCz0): calculator *****\u001b[0m\n", "Arguments: \n", "{\n", " \"a\": 1423,\n", " \"b\": 123,\n", " \"operator\": \"-\"\n", "}\n", - "\u001B[32m***************************************************************************\u001B[0m\n", + "\u001b[32m***************************************************************************\u001b[0m\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[35m\n", - ">>>>>>>> EXECUTING FUNCTION calculator...\u001B[0m\n", - "\u001B[33mUser\u001B[0m (to Assistant):\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION calculator...\u001b[0m\n", + "\u001b[33mUser\u001b[0m (to Assistant):\n", "\n", - "\u001B[33mUser\u001B[0m (to Assistant):\n", + "\u001b[33mUser\u001b[0m (to Assistant):\n", "\n", - "\u001B[32m***** Response from calling tool (call_aINcGyo0Xkrh9g7buRuhyCz0) *****\u001B[0m\n", + "\u001b[32m***** Response from calling tool (call_aINcGyo0Xkrh9g7buRuhyCz0) *****\u001b[0m\n", "1300\n", - "\u001B[32m**********************************************************************\u001B[0m\n", + "\u001b[32m**********************************************************************\u001b[0m\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001B[0m\n", - "\u001B[33mAssistant\u001B[0m (to User):\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33mAssistant\u001b[0m (to User):\n", "\n", - "\u001B[32m***** Suggested tool call (call_prJGf8V0QVT7cbD91e0Fcxpb): calculator *****\u001B[0m\n", + "\u001b[32m***** Suggested tool call (call_prJGf8V0QVT7cbD91e0Fcxpb): calculator *****\u001b[0m\n", "Arguments: \n", "{\n", " \"a\": 1300,\n", " \"b\": 3,\n", " \"operator\": \"/\"\n", "}\n", - "\u001B[32m***************************************************************************\u001B[0m\n", + "\u001b[32m***************************************************************************\u001b[0m\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[35m\n", - ">>>>>>>> EXECUTING FUNCTION calculator...\u001B[0m\n", - "\u001B[33mUser\u001B[0m (to Assistant):\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION calculator...\u001b[0m\n", + "\u001b[33mUser\u001b[0m (to Assistant):\n", "\n", - "\u001B[33mUser\u001B[0m (to Assistant):\n", + "\u001b[33mUser\u001b[0m (to Assistant):\n", "\n", - "\u001B[32m***** Response from calling tool (call_prJGf8V0QVT7cbD91e0Fcxpb) *****\u001B[0m\n", + "\u001b[32m***** Response from calling tool (call_prJGf8V0QVT7cbD91e0Fcxpb) *****\u001b[0m\n", "433\n", - "\u001B[32m**********************************************************************\u001B[0m\n", + "\u001b[32m**********************************************************************\u001b[0m\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001B[0m\n" + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n" ] }, { @@ -316,94 +321,94 @@ "name": "stdout", "output_type": "stream", "text": [ - "\u001B[33mAssistant\u001B[0m (to User):\n", + "\u001b[33mAssistant\u001b[0m (to User):\n", "\n", - "\u001B[32m***** Suggested tool call (call_CUIgHRsySLjayDKuUphI1TGm): calculator *****\u001B[0m\n", + "\u001b[32m***** Suggested tool call (call_CUIgHRsySLjayDKuUphI1TGm): calculator *****\u001b[0m\n", "Arguments: \n", "{\n", " \"a\": 32,\n", " \"b\": 23,\n", " \"operator\": \"+\"\n", "}\n", - "\u001B[32m***************************************************************************\u001B[0m\n", + "\u001b[32m***************************************************************************\u001b[0m\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[35m\n", - ">>>>>>>> EXECUTING FUNCTION calculator...\u001B[0m\n", - "\u001B[33mUser\u001B[0m (to Assistant):\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION calculator...\u001b[0m\n", + "\u001b[33mUser\u001b[0m (to Assistant):\n", "\n", - "\u001B[33mUser\u001B[0m (to Assistant):\n", + "\u001b[33mUser\u001b[0m (to Assistant):\n", "\n", - "\u001B[32m***** Response from calling tool (call_CUIgHRsySLjayDKuUphI1TGm) *****\u001B[0m\n", + "\u001b[32m***** Response from calling tool (call_CUIgHRsySLjayDKuUphI1TGm) *****\u001b[0m\n", "55\n", - "\u001B[32m**********************************************************************\u001B[0m\n", + "\u001b[32m**********************************************************************\u001b[0m\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001B[0m\n", - "\u001B[33mAssistant\u001B[0m (to User):\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33mAssistant\u001b[0m (to User):\n", "\n", - "\u001B[32m***** Suggested tool call (call_L7pGtBLUf9V0MPL90BASyesr): calculator *****\u001B[0m\n", + "\u001b[32m***** Suggested tool call (call_L7pGtBLUf9V0MPL90BASyesr): calculator *****\u001b[0m\n", "Arguments: \n", "{\n", " \"a\": 55,\n", " \"b\": 5,\n", " \"operator\": \"*\"\n", "}\n", - "\u001B[32m***************************************************************************\u001B[0m\n", + "\u001b[32m***************************************************************************\u001b[0m\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[35m\n", - ">>>>>>>> EXECUTING FUNCTION calculator...\u001B[0m\n", - "\u001B[33mUser\u001B[0m (to Assistant):\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION calculator...\u001b[0m\n", + "\u001b[33mUser\u001b[0m (to Assistant):\n", "\n", - "\u001B[33mUser\u001B[0m (to Assistant):\n", + "\u001b[33mUser\u001b[0m (to Assistant):\n", "\n", - "\u001B[32m***** Response from calling tool (call_L7pGtBLUf9V0MPL90BASyesr) *****\u001B[0m\n", + "\u001b[32m***** Response from calling tool (call_L7pGtBLUf9V0MPL90BASyesr) *****\u001b[0m\n", "275\n", - "\u001B[32m**********************************************************************\u001B[0m\n", + "\u001b[32m**********************************************************************\u001b[0m\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001B[0m\n", - "\u001B[33mAssistant\u001B[0m (to User):\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33mAssistant\u001b[0m (to User):\n", "\n", - "\u001B[32m***** Suggested tool call (call_Ygo6p4XfcxRjkYBflhG3UVv6): calculator *****\u001B[0m\n", + "\u001b[32m***** Suggested tool call (call_Ygo6p4XfcxRjkYBflhG3UVv6): calculator *****\u001b[0m\n", "Arguments: \n", "{\n", " \"a\": 433,\n", " \"b\": 275,\n", " \"operator\": \"+\"\n", "}\n", - "\u001B[32m***************************************************************************\u001B[0m\n", + "\u001b[32m***************************************************************************\u001b[0m\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[35m\n", - ">>>>>>>> EXECUTING FUNCTION calculator...\u001B[0m\n", - "\u001B[33mUser\u001B[0m (to Assistant):\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION calculator...\u001b[0m\n", + "\u001b[33mUser\u001b[0m (to Assistant):\n", "\n", - "\u001B[33mUser\u001B[0m (to Assistant):\n", + "\u001b[33mUser\u001b[0m (to Assistant):\n", "\n", - "\u001B[32m***** Response from calling tool (call_Ygo6p4XfcxRjkYBflhG3UVv6) *****\u001B[0m\n", + "\u001b[32m***** Response from calling tool (call_Ygo6p4XfcxRjkYBflhG3UVv6) *****\u001b[0m\n", "708\n", - "\u001B[32m**********************************************************************\u001B[0m\n", + "\u001b[32m**********************************************************************\u001b[0m\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001B[0m\n", - "\u001B[33mAssistant\u001B[0m (to User):\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33mAssistant\u001b[0m (to User):\n", "\n", "The result of the calculation is 708.\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[33mUser\u001B[0m (to Assistant):\n", + "\u001b[33mUser\u001b[0m (to Assistant):\n", "\n", "\n", "\n", "--------------------------------------------------------------------------------\n", - "\u001B[31m\n", - ">>>>>>>> USING AUTO REPLY...\u001B[0m\n", - "\u001B[33mAssistant\u001B[0m (to User):\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33mAssistant\u001b[0m (to User):\n", "\n", "TERMINATE\n", "\n", @@ -415,7 +420,7 @@ "output_type": "stream", "text": [ "πŸ–‡ AgentOps: This run's cost $0.001800\n", - "πŸ–‡ AgentOps: \u001B[34m\u001B[34mSession Replay: https://app.agentops.ai/drilldown?session_id=880c206b-751e-4c23-9313-8684537fc04d\u001B[0m\u001B[0m\n" + "πŸ–‡ AgentOps: \u001b[34m\u001b[34mSession Replay: https://app.agentops.ai/drilldown?session_id=880c206b-751e-4c23-9313-8684537fc04d\u001b[0m\u001b[0m\n" ] } ], @@ -474,7 +479,7 @@ " description=\"A simple calculator\", # A description of the tool.\n", ")\n", "\n", - "# Let the assistant start the conversation. It will end when the user types exit.\n", + "# Let the assistant start the conversation. It will end when the user types \"exit\".\n", "user_proxy.initiate_chat(assistant, message=\"What is (1423 - 123) / 3 + (32 + 23) * 5?\")\n", "\n", "agentops.end_session(\"Success\")" @@ -493,13 +498,13 @@ }, { "cell_type": "markdown", - "source": [ - "![Session Drilldown](https://github.com/AgentOps-AI/agentops/assets/14807319/561d59f3-c441-4066-914b-f6cfe32a598c)" - ], + "id": "a922a52ab5fce31", "metadata": { "collapsed": false }, - "id": "a922a52ab5fce31" + "source": [ + "![Session Drilldown](https://github.com/AgentOps-AI/agentops/blob/main/docs/images/external/app_screenshots/session-replay.png?raw=true)" + ] } ], "metadata": { diff --git a/notebook/autogen_uniformed_api_calling.ipynb b/notebook/autogen_uniformed_api_calling.ipynb new file mode 100644 index 000000000000..08f747e1722f --- /dev/null +++ b/notebook/autogen_uniformed_api_calling.ipynb @@ -0,0 +1,398 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# A Uniform interface to call different LLMs\n", + "\n", + "Autogen provides a uniform interface for API calls to different LLMs, and creating LLM agents from them.\n", + "Through setting up a configuration file, you can easily switch between different LLMs by just changing the model name, while enjoying all the [enhanced features](https://microsoft.github.io/autogen/docs/topics/llm-caching) such as [caching](https://microsoft.github.io/autogen/docs/Use-Cases/enhanced_inference/#usage-summary) and [cost calculation](https://microsoft.github.io/autogen/docs/Use-Cases/enhanced_inference/#usage-summary)!\n", + "\n", + "In this notebook, we will show you how to use AutoGen to call different LLMs and create LLM agents from them.\n", + "\n", + "Currently, we support the following model families:\n", + "- [OpenAI](https://platform.openai.com/docs/overview)\n", + "- [Azure OpenAI](https://azure.microsoft.com/en-us/products/ai-services/openai-service/?ef_id=_k_CjwKCAjwps-zBhAiEiwALwsVYdbpVkqA3IbY7WnxtrjNSefBnTfrijwRAFaYd8uuLCjeWsPdfZmxUBoC_ZAQAvD_BwE_k_&OCID=AIDcmm5edswduu_SEM__k_CjwKCAjwps-zBhAiEiwALwsVYdbpVkqA3IbY7WnxtrjNSefBnTfrijwRAFaYd8uuLCjeWsPdfZmxUBoC_ZAQAvD_BwE_k_&gad_source=1&gclid=CjwKCAjwps-zBhAiEiwALwsVYdbpVkqA3IbY7WnxtrjNSefBnTfrijwRAFaYd8uuLCjeWsPdfZmxUBoC_ZAQAvD_BwE)\n", + "- [Anthropic Claude](https://docs.anthropic.com/en/docs/welcome)\n", + "- [Google Gemini](https://ai.google.dev/gemini-api/docs)\n", + "- [Mistral](https://docs.mistral.ai/) (API to open and closed-source models)\n", + "- [DeepInfra](https://deepinfra.com/) (API to open-source models)\n", + "- [TogetherAI](https://www.together.ai/) (API to open-source models)\n", + "\n", + "... and more to come!\n", + "\n", + "You can also [plug in your local deployed LLM](https://microsoft.github.io/autogen/blog/2024/01/26/Custom-Models) into AutoGen if needed." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install required packages\n", + "\n", + "You may want to install AutoGen with options to different LLMs. Here we install AutoGen with all the supported LLMs.\n", + "By default, AutoGen is installed with OpenAI support.\n", + " \n", + "```bash\n", + "pip install pyautogen[gemini,anthropic,mistral,together]\n", + "```\n", + "\n", + "\n", + "## Config list setup\n", + "\n", + "\n", + "First, create a `OAI_CONFIG_LIST` file to specify the api keys for the LLMs you want to use.\n", + "Generally, you just need to specify the `model`, `api_key` and `api_type` from the provider.\n", + "\n", + "```python\n", + "[\n", + " { \n", + " # using OpenAI\n", + " \"model\": \"gpt-35-turbo-1106\", \n", + " \"api_key\": \"YOUR_API_KEY\"\n", + " # default api_type is openai\n", + " },\n", + " {\n", + " # using Azure OpenAI\n", + " \"model\": \"gpt-4-turbo-1106\",\n", + " \"api_key\": \"YOUR_API_KEY\",\n", + " \"api_type\": \"azure\",\n", + " \"base_url\": \"YOUR_BASE_URL\",\n", + " \"api_version\": \"YOUR_API_VERSION\"\n", + " },\n", + " { \n", + " # using Google gemini\n", + " \"model\": \"gemini-1.5-pro-latest\",\n", + " \"api_key\": \"YOUR_API_KEY\",\n", + " \"api_type\": \"google\"\n", + " },\n", + " {\n", + " # using DeepInfra\n", + " \"model\": \"meta-llama/Meta-Llama-3-70B-Instruct\",\n", + " \"api_key\": \"YOUR_API_KEY\",\n", + " \"base_url\": \"https://api.deepinfra.com/v1/openai\" # need to specify the base_url\n", + " },\n", + " {\n", + " # using Anthropic Claude\n", + " \"model\": \"claude-1.0\",\n", + " \"api_type\": \"anthropic\",\n", + " \"api_key\": \"YOUR_API_KEY\"\n", + " },\n", + " {\n", + " # using Mistral\n", + " \"model\": \"mistral-large-latest\",\n", + " \"api_type\": \"mistral\",\n", + " \"api_key\": \"YOUR_API_KEY\"\n", + " },\n", + " {\n", + " # using TogetherAI\n", + " \"model\": \"google/gemma-7b-it\",\n", + " \"api_key\": \"YOUR_API_KEY\",\n", + " \"api_type\": \"together\"\n", + " }\n", + " ...\n", + "]\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Uniform Interface to call different LLMs\n", + "We first demonstrate how to use AutoGen to call different LLMs with the same wrapper class.\n", + "\n", + "After you install relevant packages and setup your config list, you only need three steps to call different LLMs:\n", + "1. Extract the config with the model name you want to use.\n", + "2. create a client with the model name.\n", + "3. call the client `create` to get the response.\n", + "\n", + "Below, we define a helper function `model_call_example_function` to implement the above steps." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "import autogen\n", + "from autogen import OpenAIWrapper\n", + "\n", + "\n", + "def model_call_example_function(model: str, message: str, cache_seed: int = 41, print_cost: bool = False):\n", + " \"\"\"\n", + " A helper function that demonstrates how to call different models using the OpenAIWrapper class.\n", + " Note the name `OpenAIWrapper` is not accurate, as now it is a wrapper for multiple models, not just OpenAI.\n", + " This might be changed in the future.\n", + " \"\"\"\n", + " config_list = autogen.config_list_from_json(\n", + " \"OAI_CONFIG_LIST\",\n", + " filter_dict={\n", + " \"model\": [model],\n", + " },\n", + " )\n", + " client = OpenAIWrapper(config_list=config_list)\n", + " response = client.create(messages=[{\"role\": \"user\", \"content\": message}], cache_seed=cache_seed)\n", + "\n", + " print(f\"Response from model {model}: {response.choices[0].message.content}\")\n", + "\n", + " # Print the cost of the API call\n", + " if print_cost:\n", + " client.print_usage_summary()" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Response from model gpt-35-turbo-1106: Why couldn't the bicycle stand up by itself?\n", + "\n", + "Because it was two-tired!\n" + ] + } + ], + "source": [ + "model_call_example_function(model=\"gpt-35-turbo-1106\", message=\"Tell me a joke.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Response from model gemini-1.5-pro-latest: Why don't scientists trust atoms? \n", + "\n", + "Because they make up everything! \n", + " \n", + "Let me know if you'd like to hear another one! \n", + "\n" + ] + } + ], + "source": [ + "model_call_example_function(model=\"gemini-1.5-pro-latest\", message=\"Tell me a joke.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Response from model meta-llama/Meta-Llama-3-70B-Instruct: Here's one:\n", + "\n", + "Why couldn't the bicycle stand up by itself?\n", + "\n", + "(wait for it...)\n", + "\n", + "Because it was two-tired!\n", + "\n", + "How was that? Do you want to hear another one?\n" + ] + } + ], + "source": [ + "model_call_example_function(model=\"meta-llama/Meta-Llama-3-70B-Instruct\", message=\"Tell me a joke. \")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Response from model mistral-large-latest: Sure, here's a light-hearted joke for you:\n", + "\n", + "Why don't scientists trust atoms?\n", + "\n", + "Because they make up everything!\n", + "----------------------------------------------------------------------------------------------------\n", + "Usage summary excluding cached usage: \n", + "Total cost: 0.00042\n", + "* Model 'mistral-large-latest': cost: 0.00042, prompt_tokens: 9, completion_tokens: 32, total_tokens: 41\n", + "\n", + "All completions are non-cached: the total cost with cached completions is the same as actual cost.\n", + "----------------------------------------------------------------------------------------------------\n" + ] + } + ], + "source": [ + "model_call_example_function(model=\"mistral-large-latest\", message=\"Tell me a joke. \", print_cost=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using different LLMs in agents\n", + "Below we give a quick demo of using different LLMs agents in a groupchat. \n", + "\n", + "We mock a debate scenario where each LLM agent is a debater, either in affirmative or negative side. We use a round-robin strategy to let each debater from different teams to speak in turn." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "def get_llm_config(model_name):\n", + " return {\n", + " \"config_list\": autogen.config_list_from_json(\"OAI_CONFIG_LIST\", filter_dict={\"model\": [model_name]}),\n", + " \"cache_seed\": 41,\n", + " }\n", + "\n", + "\n", + "affirmative_system_message = \"You are in the Affirmative team of a debate. When it is your turn, please give at least one reason why you are for the topic. Keep it short.\"\n", + "negative_system_message = \"You are in the Negative team of a debate. The affirmative team has given their reason, please counter their argument. Keep it short.\"\n", + "\n", + "gpt35_agent = autogen.AssistantAgent(\n", + " name=\"GPT35\", system_message=affirmative_system_message, llm_config=get_llm_config(\"gpt-35-turbo-1106\")\n", + ")\n", + "\n", + "llama_agent = autogen.AssistantAgent(\n", + " name=\"Llama3\",\n", + " system_message=negative_system_message,\n", + " llm_config=get_llm_config(\"meta-llama/Meta-Llama-3-70B-Instruct\"),\n", + ")\n", + "\n", + "mistral_agent = autogen.AssistantAgent(\n", + " name=\"Mistral\", system_message=affirmative_system_message, llm_config=get_llm_config(\"mistral-large-latest\")\n", + ")\n", + "\n", + "gemini_agent = autogen.AssistantAgent(\n", + " name=\"Gemini\", system_message=negative_system_message, llm_config=get_llm_config(\"gemini-1.5-pro-latest\")\n", + ")\n", + "\n", + "claude_agent = autogen.AssistantAgent(\n", + " name=\"Claude\", system_message=affirmative_system_message, llm_config=get_llm_config(\"claude-3-opus-20240229\")\n", + ")\n", + "\n", + "user_proxy = autogen.UserProxyAgent(\n", + " name=\"User\",\n", + " code_execution_config=False,\n", + ")\n", + "\n", + "# initilize the groupchat with round robin speaker selection method\n", + "groupchat = autogen.GroupChat(\n", + " agents=[claude_agent, gemini_agent, mistral_agent, llama_agent, gpt35_agent, user_proxy],\n", + " messages=[],\n", + " max_round=8,\n", + " speaker_selection_method=\"round_robin\",\n", + ")\n", + "manager = autogen.GroupChatManager(groupchat=groupchat)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33mUser\u001b[0m (to chat_manager):\n", + "\n", + "Debate Topic: Should vaccination be mandatory?\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[32m\n", + "Next speaker: Claude\n", + "\u001b[0m\n", + "\u001b[33mClaude\u001b[0m (to chat_manager):\n", + "\n", + "As a member of the Affirmative team, I believe that vaccination should be mandatory for several reasons:\n", + "\n", + "1. Herd immunity: When a large percentage of the population is vaccinated, it helps protect those who cannot receive vaccines due to medical reasons or weakened immune systems. Mandatory vaccination ensures that we maintain a high level of herd immunity, preventing the spread of dangerous diseases.\n", + "\n", + "2. Public health: Vaccines have been proven to be safe and effective in preventing the spread of infectious diseases. By making vaccination mandatory, we prioritize public health and reduce the risk of outbreaks that could lead to widespread illness and loss of life.\n", + "\n", + "3. Societal benefits: Mandatory vaccination not only protects individuals but also benefits society as a whole. It reduces healthcare costs associated with treating preventable diseases and minimizes the economic impact of disease outbreaks on businesses and communities.\n", + "\n", + "In summary, mandatory vaccination is a critical tool in protecting public health, maintaining herd immunity, and promoting the well-being of our society.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[32m\n", + "Next speaker: Gemini\n", + "\u001b[0m\n", + "\u001b[33mGemini\u001b[0m (to chat_manager):\n", + "\n", + "While we acknowledge the importance of herd immunity and public health, mandating vaccinations infringes upon individual autonomy and medical freedom. Blanket mandates fail to consider individual health circumstances and potential vaccine risks, which are often overlooked in favor of a one-size-fits-all approach. \n", + "\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[32m\n", + "Next speaker: Mistral\n", + "\u001b[0m\n", + "\u001b[33mMistral\u001b[0m (to chat_manager):\n", + "\n", + "I understand your concerns and the value of individual autonomy. However, it's important to note that mandatory vaccination policies often include exemptions for medical reasons. This allows for individual health circumstances to be taken into account, ensuring that those who cannot safely receive vaccines are not put at risk. The goal is to strike a balance between protecting public health and respecting individual choices, while always prioritizing the well-being and safety of all members of society.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[32m\n", + "Next speaker: Llama3\n", + "\u001b[0m\n", + "\u001b[33mLlama3\u001b[0m (to chat_manager):\n", + "\n", + "I understand your point, but blanket exemptions for medical reasons are not sufficient to address the complexities of individual health circumstances. What about those who have experienced adverse reactions to vaccines in the past or have a family history of such reactions? What about those who have compromised immune systems or are taking medications that may interact with vaccine components? A one-size-fits-all approach to vaccination ignores the nuances of individual health and puts some people at risk of harm. Additionally, mandating vaccination undermines trust in government and healthcare institutions, leading to further divides and mistrust. We need to prioritize informed consent and individual autonomy in medical decisions, rather than relying solely on a blanket mandate.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[32m\n", + "Next speaker: GPT35\n", + "\u001b[0m\n", + "\u001b[33mGPT35\u001b[0m (to chat_manager):\n", + "\n", + "I understand your point, but mandatory vaccination policies can still allow for exemptions based on medical history, allergic reactions, and compromised immunity. This would address the individual circumstances you mentioned. Furthermore, mandating vaccination can also help strengthen trust in public health measures by demonstrating a commitment to protecting the entire community. Informed consent is important, but it is also essential to consider the potential consequences of not being vaccinated on public health and the well-being of others.\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[32m\n", + "Next speaker: User\n", + "\u001b[0m\n" + ] + } + ], + "source": [ + "chat_history = user_proxy.initiate_chat(recipient=manager, message=\"Debate Topic: Should vaccination be mandatory?\")" + ] + } + ], + "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.12.4" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/website/blog/2023-06-28-MathChat/index.mdx b/website/blog/2023-06-28-MathChat/index.mdx index 4c1007c611b8..be2423de9eed 100644 --- a/website/blog/2023-06-28-MathChat/index.mdx +++ b/website/blog/2023-06-28-MathChat/index.mdx @@ -75,7 +75,7 @@ We found that compared to basic prompting, which demonstrates the innate capabil For categories like Algebra and Prealgebra, PoT and PS showed little improvement, and in some instances, even led to a decrease in accuracy. However, MathChat was able to enhance total accuracy by around 6% compared to PoT and PS, showing competitive performance across all categories. Remarkably, MathChat improved accuracy in the Algebra category by about 15% over other methods. Note that categories like Intermediate Algebra and Precalculus remained challenging for all methods, with only about 20% of problems solved accurately. -The code for experiments can be found at this [repository](https://github.com/kevin666aa/FLAML/tree/gpt_math_solver/flaml/autogen/math). +The code for experiments can be found at this [repository](https://github.com/yiranwu0/FLAML/tree/gpt_math_solver/flaml/autogen/math). We now provide an implementation of MathChat using the interactive agents in AutoGen. See this [notebook](https://github.com/microsoft/autogen/blob/main/notebook/agentchat_MathChat.ipynb) for example usage. ## Future Directions diff --git a/website/blog/2023-11-13-OAI-assistants/index.mdx b/website/blog/2023-11-13-OAI-assistants/index.mdx index e73e31ad591f..07216a25969c 100644 --- a/website/blog/2023-11-13-OAI-assistants/index.mdx +++ b/website/blog/2023-11-13-OAI-assistants/index.mdx @@ -112,6 +112,6 @@ Checkout more examples [here](https://github.com/microsoft/autogen/tree/main/not `GPTAssistantAgent` was made possible through collaboration with [@IANTHEREAL](https://github.com/IANTHEREAL), [Jiale Liu](https://leoljl.github.io), -[Yiran Wu](https://github.com/kevin666aa), +[Yiran Wu](https://github.com/yiranwu0), [Qingyun Wu](https://qingyun-wu.github.io/), [Chi Wang](https://www.microsoft.com/en-us/research/people/chiw/), and many other AutoGen maintainers. diff --git a/website/blog/authors.yml b/website/blog/authors.yml index 302bb8fceaaf..189853724ff6 100644 --- a/website/blog/authors.yml +++ b/website/blog/authors.yml @@ -13,8 +13,8 @@ qingyunwu: yiranwu: name: Yiran Wu title: PhD student at Pennsylvania State University - url: https://github.com/kevin666aa - image_url: https://github.com/kevin666aa.png + url: https://github.com/yiranwu0 + image_url: https://github.com/yiranwu0.png jialeliu: name: Jiale Liu diff --git a/website/docs/ecosystem/agentops.md b/website/docs/ecosystem/agentops.md index 76995b6eb5e4..581fb2671e97 100644 --- a/website/docs/ecosystem/agentops.md +++ b/website/docs/ecosystem/agentops.md @@ -1,29 +1,37 @@ -# AgentOps πŸ–‡οΈ +# Agent Monitoring and Debugging with AgentOps -![logo](https://raw.githubusercontent.com/AgentOps-AI/agentops/35d5682866921a9e28d8ef66ae3c3b3d92d8fa6b/img/logo.png) +AgentOps logo -[AgentOps](https://agentops.ai/?=autogen) provides session replays, metrics, and monitoring for agents. +[AgentOps](https://agentops.ai/?=autogen) provides session replays, metrics, and monitoring for AI agents. At a high level, AgentOps gives you the ability to monitor LLM calls, costs, latency, agent failures, multi-agent interactions, tool usage, session-wide statistics, and more. For more info, check out the [AgentOps Repo](https://github.com/AgentOps-AI/agentops). +| | | +| ------------------------------------- | ------------------------------------------------------------- | +| πŸ“Š **Replay Analytics and Debugging** | Step-by-step agent execution graphs | +| πŸ’Έ **LLM Cost Management** | Track spend with LLM foundation model providers | +| πŸ§ͺ **Agent Benchmarking** | Test your agents against 1,000+ evals | +| πŸ” **Compliance and Security** | Detect common prompt injection and data exfiltration exploits | +| 🀝 **Framework Integrations** | Native Integrations with CrewAI, AutoGen, & LangChain | +
- Agent Dashboard + Agent Dashboard - Agent Dashboard + Agent Dashboard
- Session Analytics + Session Analytics - Session Analytics + Session Analytics
- Session Replays + Session Replays - Session Replays + Session Replays
@@ -38,7 +46,7 @@ pip install agentops ``` 2. **Create an API Key:** -Create a user API key here: [Create API Key](https://app.agentops.ai/account) +Create a user API key here: [Create API Key](https://app.agentops.ai/settings/projects) 3. **Configure Your Environment:** Add your API key to your environment variables diff --git a/website/docs/topics/groupchat/customized_speaker_selection.ipynb b/website/docs/topics/groupchat/customized_speaker_selection.ipynb index 830215a5e90b..2b800f3c8678 100644 --- a/website/docs/topics/groupchat/customized_speaker_selection.ipynb +++ b/website/docs/topics/groupchat/customized_speaker_selection.ipynb @@ -6,7 +6,34 @@ "source": [ "# Customize Speaker Selection\n", "\n", - "In GroupChat, we can also customize the speaker selection by passing in a function to `speaker_selection_method`:\n", + "```{=mdx}\n", + "![group_chat](../../../blog/2024-02-29-StateFlow/img/sf_example_1.png)\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) 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", @@ -35,28 +62,7 @@ ")\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`.\n", - "\n", - "Heres is a simple example to build workflow for research with customized speaker selection.\n", - "\n", - "\n", - "```{=mdx}\n", - "![group_chat](../../../blog/2024-02-29-StateFlow/img/sf_example_1.png)\n", - "```\n", - "\n", - "We 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, 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." + "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`." ] }, { diff --git a/website/docs/topics/llm-observability.md b/website/docs/topics/llm-observability.md index 6a95d185f979..f80b55ea0982 100644 --- a/website/docs/topics/llm-observability.md +++ b/website/docs/topics/llm-observability.md @@ -1,42 +1,37 @@ -# LLM Observability +# Agent Observability -AutoGen supports advanced LLM observability and monitoring through built-in logging and partner providers. +AutoGen supports advanced LLM agent observability and monitoring through built-in logging and partner providers. -## What is LLM Observability -AI agent observability is the ability to monitor, measure, and understand the internal states and behaviors of AI agent systems. -Observability is crucial for ensuring transparency, reliability, and accountability in your agent systems. +## AutoGen Observability Integrations +### Built-In Logging +AutoGen's SQLite and File Logger - [Tutorial Notebook](/docs/notebooks/agentchat_logging) -## Development +### Full-Service Partner Integrations +AutoGen partners with [AgentOps](https://agentops.ai) to provide multi-agent tracking, metrics, and monitoring - [Tutorial Notebook](/docs/notebooks/agentchat_agentops) -### Agent Development in Terminal is Limited -- Lose track of what your agents did in between executions -- Parsing through terminal output searching for LLM completions -- Printing β€œtool called” -### Agent Development Dashboards Enable More -- Visual dashboard so you can see what your agents did in human-readable format -- LLM calls are magically recorded - prompt, completion, timestamps for each - with one line of code -- Agents and their events (including tool calls) are recorded with one more line of code -- Errors are magically associated to its causal event -- Record any other events to your session with two more lines of code -- Tons of other useful data if you’re developing with supported agent frameworks: SDK version +## What is Observability? +Observability provides developers with the necessary insights to understand and improve the internal workings of their agents. Observability is necessary for maintaining reliability, tracking costs, and ensuring AI safety. -## Compliance +**Without observability tools, developers face significant hurdles:** -Observability and monitoring is critical to ensure AI agent systems adhere to laws and regulations in industries like finance and healthcare, preventing violations such as data breaches and privacy issues. +- Tracking agent activities across sessions becomes a complex, error-prone task. +- Manually sifting through verbose terminal outputs to understand LLM interactions is inefficient. +- Pinpointing the exact moments of tool invocations is often like finding a needle in a haystack. -- Insights into AI decision-making, allowing organizations to explain outcomes and build trust with stakeholders. -- Helps detect anomalies and unintended behaviors early, mitigating operational, financial, and reputational risks. -- Ensures compliance with data privacy regulations, preventing unauthorized access and misuse of sensitive information. -- Quick identification and response to compliance violations, supporting incident analysis and prevention. -## Available Observability Integrations +**Key Features of Observability Dashboards:** +- Human-readable overview analytics and replays of agent activities. +- LLM cost, prompt, completion, timestamp, and metadata tracking for performance monitoring. +- Tool invocation, events, and agent-to-agent interactions for workflow monitoring. +- Error flagging and notifications for faster debugging. +- Access to a wealth of data for developers using supported agent frameworks, such as environments, SDK versions, and more. -### Logging -- Autogen SQLite and File Logger - [Tutorial](/docs/notebooks/agentchat_logging) +### Compliance -### Full-Service Partners -Autogen is currently partnered with [AgentOps](https://agentops.ai) for seamless observability integration. - -[Learn how to install AgentOps](/docs/notebooks/agentchat_agentops) +Observability is not just a development convenienceβ€”it's a compliance necessity, especially in regulated industries: +- It offers insights into AI decision-making processes, fostering trust and transparency. +- Anomalies and unintended behaviors are detected promptly, reducing various risks. +- Ensuring adherence to data privacy regulations, thereby safeguarding sensitive information. +- Compliance violations are quickly identified and addressed, enhancing incident management. diff --git a/website/docs/topics/non-openai-models/cloud-anthropic.ipynb b/website/docs/topics/non-openai-models/cloud-anthropic.ipynb index 183ced1a8a9b..c5b757f8288b 100644 --- a/website/docs/topics/non-openai-models/cloud-anthropic.ipynb +++ b/website/docs/topics/non-openai-models/cloud-anthropic.ipynb @@ -131,7 +131,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Coding Example with Two Agent" + "## Two-agent Coding Example" ] }, { @@ -139,7 +139,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Construct Agents\n", + "### Construct Agents\n", "\n", "Construct a simple conversation between a User proxy and an ConversableAgent based on Claude-3 model.\n" ] @@ -173,7 +173,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Initiate Chat" + "### Initiate Chat" ] }, { @@ -283,7 +283,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Function Call in Latest Anthropic API \n", + "## Tool Call Example with the Latest Anthropic API \n", "Anthropic just announced that tool use is now supported in the Anthropic API. To use this feature, please install `anthropic>=0.23.1`." ] }, @@ -291,7 +291,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Register the function" + "### Register the function" ] }, { @@ -396,7 +396,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# GroupChat with Claude and GPT Agents " + "## Group Chat Example with both Claude and GPT Agents " ] }, { @@ -706,7 +706,6 @@ "\n", "manager = GroupChatManager(\n", " groupchat=groupchat,\n", - " # is_termination_msg=lambda x: x.get(\"content\", \"\").find(\"TERMINATE\") >= 0,\n", " llm_config={\n", " \"config_list\": config_list_gpt4,\n", " },\n", diff --git a/website/docs/tutorial/conversation-patterns.ipynb b/website/docs/tutorial/conversation-patterns.ipynb index eeaaa409b784..7ea8f0bfa517 100644 --- a/website/docs/tutorial/conversation-patterns.ipynb +++ b/website/docs/tutorial/conversation-patterns.ipynb @@ -12,7 +12,18 @@ "In this chapter, we will first dig a little bit more into the two-agent \n", "chat pattern and chat result, \n", "then we will show you several conversation patterns that involve \n", - "more than two agents.\n" + "more than two agents.\n", + "\n", + "### An Overview\n", + "\n", + "1. **Two-agent chat**: the simplest form of conversation pattern where two agents chat with each other.\n", + "2. **Sequential chat**: a sequence of chats between two agents, chained together by a carryover mechanism, which brings the summary of the previous chat to the context of the next chat.\n", + "3. **Group Chat**: a single chat involving more than two agents. An important question in group chat is: What agent should be next to speak? To support different scenarios, we provide different ways to organize agents in a group chat:\n", + " - We support several strategies to select the next agent: `round_robin`, `random`, `manual` (human selection), and `auto` (Default, using an LLM to decide).\n", + " - We provide a way to constrain the selection of the next speaker (See examples below).\n", + " - We allow you to pass in a function to customize the selection of the next speaker. With this feature, you can build a **StateFlow** model which allows a deterministic workflow among your agents.\n", + " Please refer to this [guide](/docs/topics/groupchat/customized_speaker_selection) and this [blog post](/blog/2024/02/29/StateFlow) on StateFlow for more details.\n", + "4. **Nested Chat**: package a workflow into a single agent for reuse in a larger workflow." ] }, {