Skip to content

Commit 3b8a12c

Browse files
joshkyhfreedeathssonichi
authored
Blog regarding finite-state machine (microsoft#1622)
* Initialization of fsm blog * Pre-commit pass * Pinyin name correction * Updated title * Updated title * Added summary of notebook and note about DAG * Update index.mdx * Update website/blog/2024-02-11-FSM-GroupChat/index.mdx Co-authored-by: Chi Wang <[email protected]> * Update website/blog/2024-02-11-FSM-GroupChat/index.mdx Co-authored-by: Chi Wang <[email protected]> * Removed outdated filename and followed SoM notebook format * Pre-commit pass * Update notebook link * Corrected link to rendered notebook * Removed agentchat_hierarchy_flow_using_select_speaker and modified agentchat_groupchat_finite_state_machine * Add notebook/agentchat_groupchat_finite_state_machine.ipynb to paths --------- Co-authored-by: freedeaths <[email protected]> Co-authored-by: Chi Wang <[email protected]>
1 parent 40e4993 commit 3b8a12c

9 files changed

+924
-680
lines changed

.github/workflows/openai.yml

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ on:
1111
- "test/**"
1212
- "notebook/agentchat_auto_feedback_from_code_execution.ipynb"
1313
- "notebook/agentchat_function_call.ipynb"
14+
- "notebook/agentchat_groupchat_finite_state_machine.ipynb"
1415
- ".github/workflows/openai.yml"
1516
permissions: {}
1617
# actions: read

notebook/agentchat_graph_modelling_language_using_select_speaker.ipynb

-668
This file was deleted.

notebook/agentchat_groupchat_finite_state_machine.ipynb

+620
Large diffs are not rendered by default.

test/test_notebook.py

+2-11
Original file line numberDiff line numberDiff line change
@@ -101,21 +101,12 @@ def _test_oai_chatgpt_gpt4(save=False):
101101
run_notebook("oai_chatgpt_gpt4.ipynb", save=save)
102102

103103

104-
@pytest.mark.skipif(
105-
skip or not sys.version.startswith("3.11"),
106-
reason="do not run if openai is not installed or py!=3.11",
107-
)
108-
def _test_hierarchy_flow_using_select_speaker(save=False):
109-
# TODO: recover this test after rewriting after the new group chat api
110-
run_notebook("agentchat_hierarchy_flow_using_select_speaker.ipynb", save=save)
111-
112-
113104
@pytest.mark.skipif(
114105
skip or not sys.version.startswith("3.12"),
115106
reason="do not run if openai is not installed or py!=3.12",
116107
)
117-
def test_graph_modelling_language_using_select_speaker(save=False):
118-
run_notebook("agentchat_graph_modelling_language_using_select_speaker.ipynb", save=save)
108+
def test_agentchat_groupchat_finite_state_machine(save=False):
109+
run_notebook("agentchat_groupchat_finite_state_machine.ipynb", save=save)
119110

120111

121112
@pytest.mark.skipif(
Loading
Loading
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,288 @@
1+
---
2+
title: "FSM Group Chat -- User-specified agent transitions"
3+
authors:
4+
- joshkyh
5+
- freedeaths
6+
tags: [AutoGen]
7+
---
8+
9+
![FSM Group Chat](img/teaser.jpg)
10+
<p align="center"><em>Finite State Machine (FSM) Group Chat allows the user to constrain agent transitions.</em></p>
11+
12+
13+
## TL;DR
14+
Recently, FSM Group Chat is released that allows the user to input a transition graph to constrain agent transitions. This is useful as the number of agents increases because the number of transition pairs (N choose 2 combinations) increases exponentially increasing the risk of sub-optimal transitions, which leads to wastage of tokens and/or poor outcomes.
15+
16+
## Possible use-cases for transition graph
17+
1. One-pass workflow, i.e., we want each agent to only have one pass at the problem, Agent A -> B -> C.
18+
2. Decision tree flow, like a decision tree, we start with a root node (agent), and flow down the decision tree with agents being nodes. For example, if the query is a SQL query, hand over to the SQL agent, else if the query is a RAG query, hand over to the RAG agent.
19+
3. Sequential Team Ops. Suppose we have a team of 3 developer agents, each responsible for a different GitHub repo. We also have a team of business analyst that discuss and debate the overall goal of the user. We could have the manager agent of the developer team speak to the manager agent of the business analysis team. That way, the discussions are more focused team-wise, and better outcomes can be expected.
20+
21+
Note that we are not enforcing a directed acyclic graph; the user can specify the graph to be acyclic, but cyclic workflows can also be useful to iteratively work on a problem, and layering additional analysis onto the solution.
22+
23+
24+
## Usage Guide
25+
We have added two parameters `allowed_or_disallowed_speaker_transitions` and `speaker_transitions_type`.
26+
- `allowed_or_disallowed_speaker_transitions`: is a dictionary with the type expectation of `{Agent: [Agent]}`. The key refers to the source agent, while the value(s) in the list refers to the target agent(s). If none, a fully connection graph is assumed.
27+
- `speaker_transitions_type`: is a string with the type expectation of string, and specifically, one of ["allowed", "disallowed"]. We wanted the user to be able to supply a dictionary of allowed or disallowed transitions to improve the ease of use. In the code base, we would invert the disallowed transition into a allowed transition dictionary `allowed_speaker_transitions_dict`.
28+
29+
30+
### Application of the FSM Feature
31+
32+
A quick demonstration of how to initiate a FSM-based `GroupChat` in the `AutoGen` framework. In this demonstration, if we consider each agent as a state, and each agent speaks according to certain conditions. For example, User always initiates the task first, followed by Planner creating a plan. Then Engineer and Executor work alternately, with Critic intervening when necessary, and after Critic, only Planner should revise additional plans. Each state can only exist at a time, and there are transition conditions between states. Therefore, GroupChat can be well abstracted as a Finite-State Machine (FSM).
33+
34+
![visualization](img/FSM_logic.png)
35+
36+
37+
### Usage
38+
39+
0. Pre-requisites
40+
```bash
41+
pip install autogen[graph]
42+
```
43+
44+
1. Import dependencies
45+
46+
```python
47+
from autogen.agentchat import GroupChat, AssistantAgent, UserProxyAgent, GroupChatManager
48+
from autogen.oai.openai_utils import config_list_from_dotenv
49+
```
50+
2. Configure LLM parameters
51+
52+
```python
53+
# Please feel free to change it as you wish
54+
config_list = config_list_from_dotenv(
55+
dotenv_file_path='.env',
56+
model_api_key_map={'gpt-4-1106-preview':'OPENAI_API_KEY'},
57+
filter_dict={
58+
"model": {
59+
"gpt-4-1106-preview"
60+
}
61+
}
62+
)
63+
64+
gpt_config = {
65+
"cache_seed": None,
66+
"temperature": 0,
67+
"config_list": config_list,
68+
"timeout": 100,
69+
}
70+
```
71+
72+
3. Define the task
73+
74+
```python
75+
# describe the task
76+
task = """Add 1 to the number output by the previous role. If the previous number is 20, output "TERMINATE"."""
77+
```
78+
79+
4. Define agents
80+
81+
```python
82+
# agents configuration
83+
engineer = AssistantAgent(
84+
name="Engineer",
85+
llm_config=gpt_config,
86+
system_message=task,
87+
description="""I am **ONLY** allowed to speak **immediately** after `Planner`, `Critic` and `Executor`.
88+
If the last number mentioned by `Critic` is not a multiple of 5, the next speaker must be `Engineer`.
89+
"""
90+
)
91+
92+
planner = AssistantAgent(
93+
name="Planner",
94+
system_message=task,
95+
llm_config=gpt_config,
96+
description="""I am **ONLY** allowed to speak **immediately** after `User` or `Critic`.
97+
If the last number mentioned by `Critic` is a multiple of 5, the next speaker must be `Planner`.
98+
"""
99+
)
100+
101+
executor = AssistantAgent(
102+
name="Executor",
103+
system_message=task,
104+
is_termination_msg=lambda x: x.get("content", "") and x.get("content", "").rstrip().endswith("FINISH"),
105+
llm_config=gpt_config,
106+
description="""I am **ONLY** allowed to speak **immediately** after `Engineer`.
107+
If the last number mentioned by `Engineer` is a multiple of 3, the next speaker can only be `Executor`.
108+
"""
109+
)
110+
111+
critic = AssistantAgent(
112+
name="Critic",
113+
system_message=task,
114+
llm_config=gpt_config,
115+
description="""I am **ONLY** allowed to speak **immediately** after `Engineer`.
116+
If the last number mentioned by `Engineer` is not a multiple of 3, the next speaker can only be `Critic`.
117+
"""
118+
)
119+
120+
user_proxy = UserProxyAgent(
121+
name="User",
122+
system_message=task,
123+
code_execution_config=False,
124+
human_input_mode="NEVER",
125+
llm_config=False,
126+
description="""
127+
Never select me as a speaker.
128+
"""
129+
)
130+
```
131+
132+
1. Here, I have configured the `system_messages` as "task" because every agent should know what it needs to do. In this example, each agent has the same task, which is to count in sequence.
133+
2. **The most important point is the `description` parameter, where I have used natural language to describe the transition conditions of the FSM. Because the manager knows which agents are available next based on the constraints of the graph, I describe in the `description` field of each candidate agent when it can speak, effectively describing the transition conditions in the FSM.**
134+
135+
5. Define the graph
136+
137+
```python
138+
graph_dict = {}
139+
graph_dict[user_proxy] = [planner]
140+
graph_dict[planner] = [engineer]
141+
graph_dict[engineer] = [critic, executor]
142+
graph_dict[critic] = [engineer, planner]
143+
graph_dict[executor] = [engineer]
144+
```
145+
146+
1. **The graph here and the transition conditions mentioned above together form a complete FSM. Both are essential and cannot be missing.**
147+
2. You can visualize it as you wish, which is shown as follows
148+
149+
![visualization](img/FSM_of_multi-agents.png)
150+
151+
6. Define a `GroupChat` and a `GroupChatManager`
152+
153+
```python
154+
agents = [user_proxy, engineer, planner, executor, critic]
155+
156+
# create the groupchat
157+
group_chat = GroupChat(agents=agents, messages=[], max_round=25, allowed_or_disallowed_speaker_transitions=graph_dict, allow_repeat_speaker=None, speaker_transitions_type="allowed")
158+
159+
# create the manager
160+
manager = GroupChatManager(
161+
groupchat=group_chat,
162+
llm_config=gpt_config,
163+
is_termination_msg=lambda x: x.get("content", "") and x.get("content", "").rstrip().endswith("TERMINATE"),
164+
code_execution_config=False,
165+
)
166+
```
167+
168+
7. Initiate the chat
169+
170+
```python
171+
# initiate the task
172+
user_proxy.initiate_chat(
173+
manager,
174+
message="1",
175+
clear_history=True
176+
)
177+
```
178+
179+
8. You may get the following output(I deleted the ignorable warning):
180+
181+
```
182+
User (to chat_manager):
183+
184+
1
185+
186+
--------------------------------------------------------------------------------
187+
Planner (to chat_manager):
188+
189+
2
190+
191+
--------------------------------------------------------------------------------
192+
Engineer (to chat_manager):
193+
194+
3
195+
196+
--------------------------------------------------------------------------------
197+
Executor (to chat_manager):
198+
199+
4
200+
201+
--------------------------------------------------------------------------------
202+
Engineer (to chat_manager):
203+
204+
5
205+
206+
--------------------------------------------------------------------------------
207+
Critic (to chat_manager):
208+
209+
6
210+
211+
--------------------------------------------------------------------------------
212+
Engineer (to chat_manager):
213+
214+
7
215+
216+
--------------------------------------------------------------------------------
217+
Critic (to chat_manager):
218+
219+
8
220+
221+
--------------------------------------------------------------------------------
222+
Engineer (to chat_manager):
223+
224+
9
225+
226+
--------------------------------------------------------------------------------
227+
Executor (to chat_manager):
228+
229+
10
230+
231+
--------------------------------------------------------------------------------
232+
Engineer (to chat_manager):
233+
234+
11
235+
236+
--------------------------------------------------------------------------------
237+
Critic (to chat_manager):
238+
239+
12
240+
241+
--------------------------------------------------------------------------------
242+
Engineer (to chat_manager):
243+
244+
13
245+
246+
--------------------------------------------------------------------------------
247+
Critic (to chat_manager):
248+
249+
14
250+
251+
--------------------------------------------------------------------------------
252+
Engineer (to chat_manager):
253+
254+
15
255+
256+
--------------------------------------------------------------------------------
257+
Executor (to chat_manager):
258+
259+
16
260+
261+
--------------------------------------------------------------------------------
262+
Engineer (to chat_manager):
263+
264+
17
265+
266+
--------------------------------------------------------------------------------
267+
Critic (to chat_manager):
268+
269+
18
270+
271+
--------------------------------------------------------------------------------
272+
Engineer (to chat_manager):
273+
274+
19
275+
276+
--------------------------------------------------------------------------------
277+
Critic (to chat_manager):
278+
279+
20
280+
281+
--------------------------------------------------------------------------------
282+
Planner (to chat_manager):
283+
284+
TERMINATE
285+
```
286+
287+
## Notebook examples
288+
More examples can be found in the [notebook](https://microsoft.github.io/autogen/docs/notebooks/agentchat_groupchat_finite_state_machine/). The notebook includes more examples of possible transition paths such as (1) hub and spoke, (2) sequential team operations, and (3) think aloud and debate. It also uses the function `visualize_speaker_transitions_dict` from `autogen.graph_utils` to visualize the various graphs.

website/blog/authors.yml

+13-1
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,16 @@ olgavrou:
104104
name: Olga Vrousgou
105105
title: Senior Software Engineer at Microsoft Research
106106
url: https://github.com/olgavrou/
107-
image_url: https://github.com/olgavrou.png
107+
image_url: https://github.com/olgavrou.png
108+
109+
joshkyh:
110+
name: Joshua Kim
111+
title: AI Freelancer at SpectData
112+
url: https://github.com/joshkyh/
113+
image_url: https://github.com/joshkyh.png
114+
115+
freedeaths:
116+
name: Yishen Sun
117+
title: Data Scientist at PingCAP LAB
118+
url: https://github.com/freedeaths/
119+
image_url: https://github.com/freedeaths.png

0 commit comments

Comments
 (0)