AutoGen: 搭建一个医疗系统

关注公众号:闲人张,了解更多内容:

AutoGen入门学习:hello world!

AutoGen: 代码执行与工具调用

AutoGen: ReAct 和 RAG

本文主要介绍AutoGen中的Group Chat功能,通过模拟医院看病的流程来对Group Chat的功能及用法进行说明。同时也对Nested chats进行简要的介绍。

Group Chat是AutoGen 提供的一种更通用的对话模式,它涉及两个以上的Agent。其的核心思想是,所有Agent都为单个对话线程做出贡献,并共享相同的上下文。这对于需要多个Agent之间协作的任务非常有用。

先简单看下Group Chat的实现过程,然后通过模拟一个医院看病流程来体会下Group Chat的用法。

实现过程

Group Chat由特殊Agent类型GroupChatManager编排,第一步GroupChatManager 会选择一个Agent发言。然后,被选中的Agent发言,并将消息发回给GroupChatManager,GroupChatManager再将消息广播给群组中的所有其他Agent。 此过程重复进行,直到对话停止 GroupChatManager可以使用多种策略来选择下一个Agent。目前支持以下策略:

  • round_robin:GroupChatManager会根据提供的Agent顺序以循环方式选择Agent
  • random:GroupChatManager会随机选择Agent
  • manual:GroupChatManager通过要求人工输入来选择Agent
  • auto:默认策略,使用GroupChatManager的 LLM 选择Agent

Group Chat中尽可能的设置Agent的description。如果没有description,GroupChatManager将使用Agent的system_message。

Group Chat是一种强大的对话模式,但如果参与的Agent数量很大,则很难控制。AutoGen 提供了一些列参数来解决这个问题,满足多场景的需求,后面将对这些参数进行逐一说明。

模拟就医流程,实现Group Chat

一般我们就医的流程是挂号->就诊->缴费->取药。因此我们需要构建这些Agent来模拟完成整个流程。

ini 复制代码
# 患者代理
user_agent = ConversableAgent(
   name="liming",
   human_input_mode="ALWAYS",
   system_message='你是一个人类,姓名:李明,25岁,男,昨天打球时脚崴了',
)

# 挂号代理
registered_agent = ConversableAgent(
    name="registered",
    system_message="你是医院的挂号系统,患者来到医院,引导患者完成挂号。需要根据患者选择的科室推荐对应科室的医生及收费情况,当患者选择对应医生并且输入对应医生的挂号费用时,告诉患者:挂号完成,并可前往诊室候诊 ",
    llm_config={"config_list": config.config_list},
    human_input_mode="NEVER",
    function_map={
        "get_doctor_info": get_doctor_info
    }
)

# 医生代理,可以创建多个
doctor_zhao_agent = ConversableAgent(
    name="doctor_zhao",
    system_message="你是一名骨科医生,名字赵六,只接收挂号完成的患者,应该介绍自己然后询问患者病情,根据患者病情给予合适的治疗方案,并开具对应的药品处方",
    llm_config={"config_list": config.config_list},
    human_input_mode="NEVER"
)

# 药房代理
medicine_agent = ConversableAgent(
    name="medicine_store",
    system_message="你是一名药房管理员,根据用户的处方及缴费信息给用户出售对应的药品,当用户未缴费时提醒用户先去缴费窗口进行缴费",
    llm_config={"config_list": config.config_list},
    human_input_mode="NEVER"
)

# 收费代理
cashier_agent = ConversableAgent(
    name="cashier",
    system_message="你是一名药品收费员,根据用户的处方收取对应药品的费用,当用户输入费用时,代表用户缴费完成,并开具收据,提醒用户取药房取药",
    llm_config={"config_list": config.config_list},
    human_input_mode="NEVER"
)

这里我们user_agent被设置为始终要求人类输入来模拟人的真实行为,并且给registered_agent注册获取医生信息的工具,以便根据患者病情给出合适的医生信息,并让患者付费及找到对应的医生。

ini 复制代码
registered_agent.register_for_llm(name="get_doctor_info", description="获取医生信息")(get_doctor_info)

将所有Agent加入到Group Chat并交由GroupChatManager管理,然后开始就医

ini 复制代码
group_chat = GroupChat(
    agents=[user_agent, registered_agent, doctor_li_agent, doctor_zhao_agent, medicine_agent, cashier_agent],
    messages=[],
    max_round=30,
    send_introductions=True
)

group_chat_manager = GroupChatManager(
    groupchat=group_chat,
    llm_config={"config_list": config.config_list},
)

user_agent.initiate_chat(
    group_chat_manager,
    message="你好,我的脚受伤了",
    summary_method="last_msg",
    silent=True
)

查看整个过程,基本和现实世界就诊流程一致

sql 复制代码
registered (to chat_manager):
你好,李明先生。根据你的描述,你可能需要去我们医院的骨科进行看诊。我马上为你寻找骨科的医生。
### functions.get_doctor_info
    ```json
    {
      "subject": "骨科"
    }
    ```
--------------------------------------------------------------------------------
registered (to chat_manager):

***** Suggested tool call (call_A8n3hxHIYkYeksD9TiKfVCSJ): get_doctor_info *****
Arguments: 
{
  "subject": "骨科"
}
********************************************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION get_doctor_info...
registered (to chat_manager):
registered (to chat_manager):

***** Response from calling tool (call_A8n3hxHIYkYeksD9TiKfVCSJ) *****
[{'name': '李四', 'price': 10, 'level': '专家'}, {'name': '赵六', 'price': 15, 'level': '主任'}]
**********************************************************************
--------------------------------------------------------------------------------
registered (to chat_manager):

在我们医院的骨科,我们有两位医生可供您选择:
1. 李四医生,他是我们的专家,的挂号费用为10元。
2. 赵六医生,他是我们的主任医生,挂号费为15元。
请问您想选择哪位医生进行看诊呢?
--------------------------------------------------------------------------------
Provide feedback to chat_manager. Press enter to skip and use auto-reply, or type 'exit' to end the conversation: 赵六
liming (to chat_manager):
赵六
--------------------------------------------------------------------------------
registered (to chat_manager):
好的,李明先生,你选择的是我们的主任医生赵六,挂号费为15元。请你确认并支付挂号费用。
--------------------------------------------------------------------------------
Provide feedback to chat_manager. Press enter to skip and use auto-reply, or type 'exit' to end the conversation: 15
liming (to chat_manager):
15
--------------------------------------------------------------------------------
doctor_zhao (to chat_manager):
你好,我是骨科主任医生赵六,李明先生,我看到你的挂号信息了。你能详细的描述一下你的脚受伤的情况吗?例如疼痛的部位,疼痛的程度,是哪只脚受的伤,活动是否方便等等。
--------------------------------------------------------------------------------
Provide feedback to chat_manager. Press enter to skip and use auto-reply, or type 'exit' to end the conversation: 左脚,昨天打球扭到了,目前红肿,走路疼痛
liming (to chat_manager):
左脚,昨天打球扭到了,目前红肿,走路疼痛
--------------------------------------------------------------------------------
doctor_zhao (to chat_manager):

你好,李明先生,看起来像是踝关节扭伤。我建议需要立即进行RICE疗法(即:休息、冰敷、压迫、抬高)来控制你的脚部肿胀和疼痛,并需要尽快去医院进行X光检查确认是否骨折。
你应该立即使用弹性绷带紧紧包扎,然后左脚抬高,尽量避免下地行走。在接下来的24小时内,你的脚应该处于冰敷状态,每次20分钟,间隔40分钟再敷,见效快且能缓解你的疼痛。同时服用消炎止痛药,我会给你开一份处方。
### functions.write_prescription
    ```json
    {
      "patient_name": "李明",
      "medicines": [{"name": "布洛芬", "dosage": "每次1片,一天3次"}]
    }
    ```
--------------------------------------------------------------------------------
cashier (to chat_manager):
 {
  "patient_name": "李明",
  "medicines": [{"name": "布洛芬", "dosage": "每次1片,一天3次"}]
}
--------------------------------------------------------------------------------
medicine_store (to chat_manager):
你好,李明先生,根据赵六医生的处方,你需要购买的药物是布洛芬,用法是每次1片,一天3次。现在请你去收银台缴费,缴费完成后拿着收据前来取药。
--------------------------------------------------------------------------------
cashier (to chat_manager):
你好,李明先生。根据赵六医生开的处方,你需要购买的药品是布洛芬。这个药品的价格是15元。请你支付费用。
--------------------------------------------------------------------------------
Provide feedback to chat_manager. Press enter to skip and use auto-reply, or type 'exit' to end the conversation: 15
liming (to chat_manager):
15
--------------------------------------------------------------------------------
medicine_store (to chat_manager):
你好,李明先生,你已经成功缴费,这是你的收据。现在你可以拿着收据去药房取药了。记得按照医生的指示正确服用药物。祝你早日康复!
--------------------------------------------------------------------------------
Provide feedback to chat_manager. Press enter to skip and use auto-reply, or type 'exit' to end the conversation: 这个是缴费收据,请取药
liming (to chat_manager):
这个是缴费收据,请取药
--------------------------------------------------------------------------------
medicine_store (to chat_manager):
你好,李明先生,这是你的布洛芬药片,每次1片,一天3次。请按照医嘱按时服用,如果病情没有明显改善或者出现其他症状,建议你再次来医院挂号就诊。祝你早日康复。
--------------------------------------------------------------------------------
Provide feedback to chat_manager. Press enter to skip and use auto-reply, or type 'exit' to end the conversation: exit
Process finished with exit code 0

当我们不告诉病情,将message改为你好,我想看医生时,可以看到需要人类手动选择科室,通过这种方式可以扩展助理Agent给出参数建议,人类决定是否执行及修改来满足更加精准的业务流程执行。

markdown 复制代码
registered (to chat_manager):
你好,李明先生。我是医院的挂号系统。请问您需要去哪个科室?您刚刚提到打球崴到了脚,是否需要去骨科看医生?
--------------------------------------------------------------------------------
Provide feedback to chat_manager. Press enter to skip and use auto-reply, or type 'exit' to end the conversation: 眼科
liming (to chat_manager):
眼科
--------------------------------------------------------------------------------
registered (to chat_manager):
***** Suggested tool call (call_PxAFYuAX5j4v4WlZ5xIfRlhA): get_doctor_info *****
Arguments: 
{
"subject": "眼科"
}
********************************************************************************
--------------------------------------------------------------------------------
>>>>>>>> EXECUTING FUNCTION get_doctor_info...
registered (to chat_manager):
registered (to chat_manager):
***** Response from calling tool (call_PxAFYuAX5j4v4WlZ5xIfRlhA) *****
[{'name': '张三', 'price': 10, 'level': '专家'}, {'name': '李四', 'price': 15, 'level': '主任'}]
**********************************************************************
--------------------------------------------------------------------------------
registered (to chat_manager):
您好,李明先生。在眼科我们有以下医生供您选择:
1. 张三医生,专家,挂号费10元
2. 李四医生,主任,挂号费15元
请问您要选择哪位医生看诊?
--------------------------------------------------------------------------------

GroupChat 参数说明

  • agents:List,参与的Agent列表。

  • messages:List,GroupChat中的消息列表。

  • max_round:最大轮次数,默认10。

  • admin_name:如果有的话,管理员Agent的名称。默认为"Admin"。 管理员将会接管中断。

  • func_call_filter:是否强制执行函数调用过滤。默认为True。当设置为真时,如果消息是函数调用建议,下一个发言者将从包含相应函数名称的Agent的function_map中选择。

  • select_speaker_message_template:自定义选择发言者的消息模板(用于"auto"选择发言者),它出现在消息上下文的首位,通常包括Agent描述和Agent列表。

  • select_speaker_prompt_template:自定义选择发言者的提示模板(用于"auto"选择发言者),它出现在消息上下文的最后,通常包括Agent列表和指引LLM选择下一个Agent。

  • speaker_selection_method:选择下一个发言者的方法。默认是"auto"。 可以是以下任何一种(不区分大小写),如果无法识别将引发ValueError错误:

    • "auto":下一个发言者由LLM自动选择。

    • "manual":下一个发言者由用户输入手动选择。

    • "random":下一个发言者随机选择。

    • "round_robin":按照agents提供的顺序,循环方式选择下一个发言者。

      • 自定义发言者选择函数(Callable):调用该函数来选择下一个发言者。 函数应该以最后一个发言者和GroupChat作为输入,并返回以下任一项:

        1. 一个Agent类,它必须是GroupChat中的一个Agent。
        2. 一个字符串,从['auto', 'manual', 'random', 'round_robin']中选择一个默认方法使用。
        3. None,这会优雅地终止对话。
        python 复制代码
        def custom_speaker_selection_func(last_speaker: Agent, groupchat: GroupChat ) -> Union[Agent, str, None]: 
  • allow_repeat_speaker:是否允许同一个发言者连续发言。默认为True,在这种情况下所有发言者都被允许连续发言。如果allow_repeat_speaker是一个Agent列表,则只有列出的Agent被允许重复。如果设置为False,则没有发言者被允许重复。 allow_repeat_speaker和allowed_or_disallowed_speaker_transitions是互斥的。

  • allowed_or_disallowed_speaker_transitions:字典。Key是源Agent,Value是Key中的Agent可以/不能过渡到的Agent, 取决于speaker_transitions_type。默认为None,这意味着所有Agent都可以过渡到所有其他Agent。 allow_repeat_speaker和allowed_or_disallowed_speaker_transitions是互斥的。

  • speaker_transitions_type:是否为包含允许或不允许的Agent列表的字典。 "allowed"表示allowed_or_disallowed_speaker_transitions是一个包含允许Agent列表的字典。 如果设置为"disallowed",则allowed_or_disallowed_speaker_transitions是一个包含不允许Agent列表的字典。 如果allowed_or_disallowed_speaker_transitions不为空,则必须提供。

  • enable_clear_history:通过在用户提示中提供"clear history"短语,使Agent能够手动清除消息历史的可能性。这是一个实验功能。有关详细信息,请参阅GroupChatManager.clear_agents_history函数的描述。

  • send_introductions:在Group Chat开始时发送一轮介绍,以便Agent知道他们可以与谁交谈(默认值:False)

  • role_for_select_speaker_messages:在'auto'模式下设置选择发言者消息的角色名称,通常是'user'或'system'。(默认值:'system')

通过上述的例子,我们可以看到GroupChat的强大之处,对于构建复杂的工作流提供了极大的便利。但所有对话都是通过GroupChatManager进行管理,AutoGen同时也提供了另一种聊天方式:Nested chats

Nested chats

Nested chats(嵌套聊天),可以将工作流打包到单个Agent中以便在更大的工作流中重用。

当消息传入并传递 human-in-the-loop 组件时,Nested chats处理程序会根据用户指定的条件检查消息是否应触发Nested chats。如果满足条件,Nested chats处理程序将启动使用顺序聊天模式指定的Nested chats序列。在每个Nested chats中,发件人Agent始终是触发Nested chats的同一Agent。最后,Nested chats处理程序使用Nested chats的结果来生成对原始消息的响应。默认情况下,Nested chats处理程序使用上次聊天的摘要作为响应。

Nested chats处理程序的实现使用了register_reply方法,允许您对ConversableAgent进行广泛的自定义。GroupChatManager 使用相同的机制来实现群组聊天。 允许您将复杂的工作流程打包到单个Agent中。您可以通过让工具调用者Agent启动与工具执行者Agent的Nested chats,然后使用Nested chats的结果生成响应,来隐藏单个Agent中的工具用法。 具体的示例用法可以参考官方的示例:microsoft.github.io/autogen/doc...

这里仅对register_nested_chats方法的参数进行说明:

  • chat_queue (list):需要启动的聊天对象列表。

  • trigger (Agent 类,str,Agent 实例,可调用对象或列表):详情参考 register_reply。

  • reply_func_from_nested_chats (Callable, str):嵌套聊天的回复函数。该函数接受嵌套聊天的 chat_queue,接收者代理,消息列表,发送者代理和配置作为输入,并返回回复消息。默认为 "summary_from_nested_chats",对应一个内置的回复功能,从嵌套的 chat_queue 获取摘要。

    python 复制代码
    def reply_func_from_nested_chats(chat_queue: List[Dict],recipient: ConversableAgent,messages: Optional[List[Dict]] = None,sender: Optional[Agent] = None,config: Optional[Any] = None,) -> Tuple[bool, Union[str, Dict, None]]:  
  • position (int):详情参考 register_reply。默认为 2。这意味着我们首先检查终止和人类回复,然后检查已注册的嵌套聊天回复。

  • kwargs:详情参考 register_reply。

以上是关于AutoGen群聊功能的介绍,这些模式可以支持我们创建复杂的工作流,更加灵活的配置业务。

解锁更多精彩关注公众号:闲人张

相关推荐
xier_ran几秒前
【BUG问题】5060Ti显卡Windows配置Anaconda中的CUDA及Pytorch,sm_120问题
人工智能·pytorch·windows
nix.gnehc1 分钟前
AI Coding 演进史:从代码补全到智能体军团的四次范式革命
人工智能
前端之虎陈随易4 分钟前
为什么今天还会有新语言?MoonBit 想解决什么问题?
大数据·linux·javascript·人工智能·算法·microsoft·typescript
python零基础入门小白4 分钟前
Transformer、Token、RAG全解析,一篇读懂大模型核心机制!
人工智能·深度学习·学习·语言模型·大模型·transformer·产品经理
庞轩px7 分钟前
AI辅助编程的边界——Cursor实战与工程判断力
人工智能·ai·大模型·prompt·code review·aicoding
Baihai IDP10 分钟前
为什么 AI Agent 重新爱上了文件系统(Filesystems)
人工智能·ai·llm·agi
70asunflower14 分钟前
从需求洞察到生态博弈
人工智能·芯片
夕除20 分钟前
spring boot
java·spring boot·后端
~kiss~20 分钟前
How OpenAI delivers low-latency voice AI at scale - OpenAI 如何规模化实现低延迟语音 AI
人工智能
后端小肥肠20 分钟前
白嫖小云雀 API 200 秒免费额度,封装 Skill,玩转 Seedance2.0 视频
人工智能·agent