AI智能体开发实战AutoGen篇(四)——会干活的导诊 Agent(Planner + Tools 实战)

> Wise玩转AI

AI 不是用来玩的,是用来提升效率的;AI 不是玩具,是你的数字员工和助手。

> 在 `Stage 1`,我们构建了一个"导诊顾问",它能聊天,能给出建议。但真正的智能体,核心是"做事",而不是"回答问题"。要让它做事,就必须让它具备两项核心能力:规划(Planning)行动(Action)

这就是 `Stage 2` 的核心:引入 Planner(规划器)Tools(工具)

> 没有 Planner,智能体只是在长篇大论,它无法将一个复杂目标拆解成可执行的步骤。

> 没有 Tools,智能体就没有"手"和"脚",它无法与真实世界交互,无法执行任何有意义的操作。

Stage 2 是我们从"聊天机器人"迈向"数字员工"的关键一步,是整个智能体工程的基石。

1. 产品背景:从"顾问"到"助理"的进化

Stage 1 中,我们的导诊助手像一个"顾问",你问一句,它答一句,所有的知识和逻辑都固化在 Prompt 里。这在简单场景下可行,但暴露了三个核心问题:

  1. 逻辑僵化:一旦就诊流程变化,就需要去修改非常复杂的 Prompt,维护成本极高。

  2. 能力受限:它无法执行任何实际操作,比如查询医生排班、确认挂号费用等,因为它没有"手脚"(工具)。

  3. 黑盒决策:我们不清楚它给出建议的具体步骤,整个过程不可控,不可观测。

Stage 2 的目标就是解决这些问题。我们把导诊 Agent 的角色从"顾问"升级为"助理",它不仅能给建议,更能**"自动去做事"**。

本次升级的核心是:

  1. 引入 Planner(规划器):在执行任何任务前,Agent 会先生成一个清晰的、结构化的行动计划(Plan),明确"先做什么,后做什么"。

  2. 引入 Tools(工具):我们将核心业务能力(如"推荐科室"、"查询挂号流程")从 Prompt 中剥离,封装成独立的、可复用、可维护的 Python 函数(工具)。

通过这次改造,我们的智能体将首次具备"规划与执行"分离的架构,这是构建任何高级智能体的基础。

2. 技术背景与实现流程

2.1 技术升级:autogen 0.7 的 Planner 与 Tool Calling

本阶段我们将在 Stage 1 的基础上,重点利用 autogen 框架的以下核心能力:

  • 多 Agent 协作:我们将引入两个角色的 Agent:

  • Planner Agent:一个专门负责任务规划的智能体,它接收用户需求,输出结构化的 JSON 行动计划。

  • Worker Agent:一个带有工具的执行者,它理解 Planner 的计划,并按步骤调用正确的工具来完成任务。

  • Tool Calling(工具调用):通过 `AgentTool` 将我们的 Python 函数(如 `recommend_department`)封装起来,让 `Worker Agent` 能够像调用 API 一样使用它们。

2.2 核心实现流程

本阶段的智能体工作流程可以用下面这张图清晰地展示:

复制代码
graph TD
    A[用户输入症状] --> B{Planner Agent};
    B --"生成任务规划 (JSON)"--> C{Worker Agent};
    C --"步骤1:分析症状"--> D[调用 recommend_department 工具];
    D --"返回推荐科室"--> C;
    C --"步骤2:查询流程"--> E[调用 registration_guide 工具];
    E --"返回挂号流程"--> C;
    C --"综合所有信息"--> F[生成最终导诊建议];
    F --> G[流式输出给用户];

这个流程清晰地体现了"规划与执行分离"的思想:Planner 负责高层次的"怎么做",WorkerTools 负责底层的"具体执行"。

3. 环境准备与运行

3.1 环境要求

  • Python 版本: `3.11`

  • 核心依赖: `autogen-agentchat`, `autogen-ext[openai]`, `python-dotenv`

3.2 安装与配置

  1. 安装依赖

    pip install -U "autogen-agentchat>=0.7.0" "autogen-ext[openai]>=0.7.0" python-dotenv

  2. 配置环境变量

在项目根目录创建 .env 文件,填入你的 DeepSeek API 密钥。模型我们将统一使用 deepseek-chat

复制代码
DEEPSEEK_API_KEY="你的_DeepSeek_API_密钥"

DEEPSEEK_MODEL="deepseek-chat"

DEEPSEEK_BASE_URL="https://api.deepseek.com"

LOG_LEVEL="INFO"

3.3 运行 Stage 2

执行以下命令,启动"会干活的"导诊 Agent:

复制代码
python -m hospital_agent_course.stage2_agent_tools_planner.main

3.4 新功能使用示例

双参数工具的使用非常自然,Agent会自动从用户输入中提取年龄信息:

示例1:包含年龄信息的询问

你:我今年30岁,最近经常头痛,有时候还有点头晕,请问应该挂什么科?

Agent会自动调用:comprehensive_triage_recommendation("经常头痛头晕", 30)

示例2:不包含年龄信息的询问

你:最近咳嗽发热,需要挂哪个科室?

Agent会调用:comprehensive_triage_recommendation("咳嗽发热", None)

工具会自动使用35岁作为默认年龄进行推荐

示例3:儿童患者

你:我家小孩8岁,发热咳嗽,有点喘不过气,应该看什么科?

Agent会自动调用:comprehensive_triage_recommendation("发热咳嗽喘不过气", 8)

优先推荐儿科相关的科室

4. 预期结果展示

当你运行程序并输入症状后,你将看到与 Stage 1 完全不同的交互过程。

输入示例:

我这两天一直咳嗽,还有点低烧,需要挂哪个科室?

复制代码
============================================================
 Wise玩转AI · Stage 2:会干活的导诊智能体(Planner + Tools)
============================================================
请输入您的症状描述 (输入 "exit"、"quit" 或 "q" 退出): 我这两天一直咳嗽,还有点低烧,需要挂哪个科室?

[调试信息] 当前任务规划:
{
  "goal": "根据患者症状推荐科室并给出挂号流程说明",
  "steps": [
    {
      "id": 1,
      "action": "分析症状,为患者推荐合适的科室",
      "tool": "recommend_department",
      "input": "患者的原始症状描述"
    },
    {
      "id": 2,
      "action": "根据推荐的科室,为患者提供详细的挂号流程",
      "tool": "registration_guide",
      "input": "上一步骤推荐的科室名称"
    }
  ]
}

------------------------------------------------------------
[导诊 Agent]:

您好,根据您"咳嗽、低烧"的症状,我为您做出以下导诊建议:

【1】推荐科室
   - **建议挂号科室**:呼吸内科、发热门诊。
   - **说明**:这些科室专门处理与呼吸系统相关的疾病,如咳嗽、发烧等。

【2】挂号流程
   - **科室**:呼吸内科 / 发热门诊
   - **挂号流程**:
     1. 前往医院门诊大厅的挂号窗口或使用自助挂号机。
     2. 选择"呼吸内科"或直接前往"发热门诊"分诊台。
     3. 告知工作人员您的症状,完成挂号。
     4. 根据挂号单上的指引,前往对应诊区候诊。

【温馨提示】
   - 这仅为教学示例,不构成医疗建议。
   - 如果症状加重或出现呼吸困难,请立即前往医院急诊或拨打120。
------------------------------------------------------------

结果解析

  1. 任务规划先行:在 Agent 回答之前,程序首先打印出了 `Planner` 生成的 JSON 任务计划。这清晰地展示了 Agent 的"思考过程",让整个决策过程变得"透明、可观测"。

  2. 工具调用驱动:最终的回答内容,是由 `Worker Agent` 先后调用 `recommend_department` 和 `registration_guide` 两个工具,并将结果组合、润色后生成的。这证明 Agent 真正具备了"干活"的能力。

  3. 结构化输出:回答内容条理清晰,分为"推荐科室"、"挂号流程"、"温馨提示"三部分,体验远超 `Stage 1`。

5. 关键代码解析

5.1 Planner Agent (`planner/task_planner.py`)

这是 `Stage 2` 的大脑。我们通过一个精心设计的 `_PLANNER_SYSTEM_MESSAGE` 来约束它的行为,让它只做一件事:生成 JSON 格式的行动计划

  • 角色定义:明确告诉模型,你是一个"医院导诊任务规划器"。

  • 任务约束:要求它把任务拆解成 2-4 个步骤,并且每一步都必须包含 `id`, `action`, `tool`, `input` 四个字段。

  • 输出格式约束:强制要求输出严格的 JSON,`tool` 字段只允许从我们提供的工具列表(`recommend_department`, `registration_guide`)中选择。

    摘自 planner/task_planner.py

    _PLANNER_SYSTEM_MESSAGE = """
    你是"医院导诊任务规划器"(Triage Task Planner)。
    你的唯一职责是:根据患者的症状描述,生成一个结构化的、可执行的 JSON 任务计划。
    ...
    输出严格为 JSON 格式,不包含任何额外的解释或Markdown标记。
    """

    async def generate_plan(planner: AssistantAgent, user_input: str) -> Dict[str, Any]:
    # ...
    # 调用 planner.run() 获取规划
    # ...
    try:
    plan = json.loads(raw_plan)
    except (json.JSONDecodeError, TypeError):
    # 如果 LLM 输出的不是合法 JSON,则使用预设的兜底计划
    plan = _fallback_plan(user_input)
    # ...
    return plan

Wise玩转AI观点 :对于工程级 Agent,永远不要完全相信模型的输出。如此处的 `_fallback_plan`,当 Planner 输出的格式异常时,系统能自动切换到预设的兜底方案,保证了流程的健壮性。这是智能体工程化中"异常处理"和"容错设计"的体现。

5.2 Tools(`tools/` 目录)

这是 Stage 2 的"手和脚"。我们将业务逻辑封装成独立的 Python 函数。

5.2.1 基础工具
  • `department_tools.py`:`recommend_department` 函数。它内部通过简单的关键词匹配规则,实现从症状到科室的推荐。这是一个纯函数(Pure Function),相同的输入永远对应相同的输出,非常易于测试和维护。
  • registration_tools.pyregistration_guide 函数。它根据科室名称,从一个字典中查找预设的挂号流程。
5.2.2 双参数综合导诊工具(🆕 新功能)

为了提供更精准的科室推荐,我们在 Stage 2 中引入了支持双参数输入的综合导诊工具:

  • comprehensive_triage_tools.pycomprehensive_triage_recommendation 函数。这是本阶段的核心新增功能,支持两个参数输入:

    • symptom_description: str - 患者的自然语言症状描述

    • patient_age: int = None - 患者年龄(可选,未提供时使用默认值35岁)

双参数工具的核心优势:

  1. 智能年龄分组:将患者分为儿童(0-12)、青少年(13-18)、青年(19-45)、中年(46-65)、老年(65+)等不同年龄段,针对不同年龄段的相同症状给出差异化推荐。

  2. 精准匹配策略

  • 首先应用年龄段特殊规则(如儿童的发热优先推荐儿科)

  • 然后应用基础科室匹配规则

  • 避免重复推荐,提供最优的3个科室选择

  1. 结构化输出:返回完整的导诊建议,包括:

    患者信息:<年龄组>,<年龄>岁

    推荐科室:

    1. <科室名称>
      推荐理由:<具体理由>
    2. <科室名称>
      推荐理由:<具体理由>

    就诊建议:

    • 携带证件建议
    • 病史准备建议
    • 紧急情况处理建议

实际应用示例:

复制代码
输入:我今年30岁,最近经常头痛,有时候还有点头晕 
输出:推荐科室:神经内科(成人头痛头晕症状) 
输入:我今年8岁,发热咳嗽,有点喘不过气 
输出:推荐科室:儿科(儿童发热咳嗽症状)
5.2.3 工具注册与优先级

系统现在支持3个工具,按优先级排序:

复制代码
# 摘自 tools/__init__.py

def get_function_map() -> Dict[str, Callable]:
    """返回工具名称到实现函数的映射。"""
    function_map: Dict[str, Callable] = {
        "comprehensive_triage_recommendation": comprehensive_triage_recommendation,  # 🥇 主要推荐工具
        "recommend_department": recommend_department,                       # 🥈 备选推荐工具
        "registration_guide": registration_guide,                           # 🥉 挂号流程工具
    }
    return function_map

在Agent的系统消息中,我们明确标注了使用优先级:

复制代码
1)comprehensive_triage_recommendation(...) 【主要推荐工具,支持症状+年龄双参数,推荐科室更精准】
2)recommend_department(...) 【备选工具,仅基于症状的单参数推荐】  
3)registration_guide(...) 【挂号流程说明工具】

# 摘自 tools/__init__.py

def get_function_map() -> Dict[str, Callable]:
    """返回工具名称到实现函数的映射。"""
    function_map: Dict[str, Callable] = {
        "comprehensive_triage_recommendation": comprehensive_triage_recommendation,  # 🥇 主要推荐工具
        "recommend_department": recommend_department,                       # 🥈 备选推荐工具
        "registration_guide": registration_guide,                           # 🥉 挂号流程工具
    }
    return function_map

def get_tools_schema() -> List[dict]:
    """基于函数签名构建 OpenAI Tools Schema 列表。"""
    function_map = get_function_map()
    schemas: List[dict] = []
    
    for name, func in function_map.items():
        if name == "comprehensive_triage_recommendation":
            desc = "根据患者症状描述和年龄提供综合导诊建议,包括科室推荐、推荐理由和就诊建议。支持双参数输入(症状+年龄),年龄为可选参数,未提供时使用通用推荐。仅用于教学示例,不构成医疗建议。"
        elif name == "recommend_department":
            desc = "根据患者自然语言症状描述,推荐 1~2 个可能需要挂号的科室。仅用于教学示例,不构成医疗建议。"
        elif name == "registration_guide":
            desc = "根据科室名称返回挂号窗口、排队顺序等流程说明。仅用于教学示例,不构成真实流程承诺。"
        else:
            desc = "医院导诊相关工具函数。"

        schema = ag_tools.get_function_schema(func, name=name, description=desc)
        schemas.append(schema)
    
    return schemas

Wise玩转AI观点工具必须是原子化的。每个工具只做一件小事。`recommend_department` 只负责推荐科室,`registration_guide` 只负责挂号流程。LLM 非常擅长组合这些小而美的原子工具来完成复杂任务,但很难操控一个大而全的"巨型工具"。

6. Stage 2 新功能对比与升级

6.1 功能对比矩阵

|-----------|--------------|------------------|------------------|
| 特性维度 | Stage 1 单智能体 | Stage 2 基础版 | Stage 2 双参数增强版 |
| 架构 | 单智能体 | Planner + Worker | Planner + Worker |
| 规划能力 | ❌ 无 | ✅ JSON任务规 | ✅ JSON任务规 |
| 工具调用 | ❌ 无 | ✅ 单参数工具 | ✅ 双参数+单参数工具 |
| 推荐精度 | 基于Prompt知识 | 基于症状关键词 | 基于症状+年龄智能匹配 |
| 个性化程度 | 低 | 中 | |
| 年龄感知 | ❌ 无 | ❌ 无 | ✅ 智能年龄分组 |
| 容错能力 | 低 | 中 | 高 |
| 可观测性 | 黑盒 | 任务规划可见 | 任务规划+推荐逻辑可见 |

6.2 双参数工具的核心价值

  1. 精准度提升:结合年龄因素的推荐比单纯基于症状的推荐准确率显著提升
  • 儿童"发热" → 优先推荐儿科

  • 成人"发热" → 推荐呼吸内科/发热门诊

  • 老年"胸闷" → 考虑心血管内科

  1. 用户体验优化
  • 自然语言输入:用户可以像平时说话一样提及年龄

  • 智能提取:Agent自动从"我今年30岁"中提取年龄

  • 容错处理:未提供年龄时使用合理默认值

  1. 工程化进步
  • 工具原子化:每个工具职责单一,易于测试维护

  • 参数灵活性:支持可选参数,向下兼容

  • 扩展性强:可以轻松添加更多参数(如性别、既往病史等)

6.3 实际应用场景

场景1:儿童就诊

复制代码
用户:我家宝宝5岁,突然起皮疹很痒,怎么办?
系统:调用 comprehensive_triage_recommendation("起皮疹很痒", 5)
推荐:儿科、皮肤科
理由:儿童出现皮肤症状,优先考虑儿科,同时皮肤科也是合适选择

场景2:中年体检

复制代码
用户:我45岁了,最近体检发现血压有点高,需要挂什么科? 
系统:调用 comprehensive_triage_recommendation("血压高", 45) 
推荐:心血管内科、内科 
理由:中年高血压患者,建议心血管内科专科就诊

场景3:老年症状

复制代码
用户:我爷爷70岁,经常头晕走路不稳,要看哪个科? 
系统:调用 comprehensive_triage_recommendation("头晕走路不稳", 70) 
推荐:神经内科、老年病科 
理由:老年患者头晕症状,需要考虑神经内科和老年病科

7. 总结与下一步

通过 Stage 2 的改造,特别是双参数工具的引入,我们的导诊助手已经从一个简单的"聊天机器人"进化成了一个具备"**规划-执行**"能力和"**个性化推荐**"的高级智能体。

7.1 Stage 2 核心成就

  1. 架构升级:实现了"规划-执行"分离的企业级智能体架构

  2. 工具化改造:将业务逻辑从Prompt中解耦,提升可维护性

  3. 个性化突破:引入双参数工具,实现基于年龄的精准推荐

  4. 工程化完善:具备容错、可观测、可扩展等特性

7.2 下一步展望

下一步, Stage 3我们将挑战一个更有趣的问题:如何让 Agent 拥有记忆?

基于 Stage 2 的坚实基础,Stage 3 将在以下方向继续演进:

  • 记忆能力:让Agent记住患者的就诊历史和偏好

  • 知识库集成:接入真实的医学知识库和医院信息

  • 多轮对话:支持连续的上下文对话,而非单次问答

这些功能将使我们的智能体从"工具使用者"进化为"知识工作者"。

相关推荐
南极星10051 小时前
OPENCV(python)--初学之路(十)
人工智能·python·opencv
AI小云1 小时前
【数据操作与可视化】Serborn绘图-单变量分布
python·数据可视化
www7691 小时前
构建企业级代码知识图谱系统:从理论到实践
人工智能
AndrewHZ1 小时前
【复杂网络分析】复杂网络分析技术在图像处理中的经典算法与应用实践
图像处理·人工智能·算法·计算机视觉·图像分割·复杂网络·图论算法
最晚的py1 小时前
机器学习--损失函数
人工智能·python·机器学习·损失函数
free-elcmacom1 小时前
机器学习入门<4>RBFN算法详解
开发语言·人工智能·python·算法·机器学习
Qinana1 小时前
当AI为你写SQL,连数据库都开始谈恋爱了
人工智能·python·sql
严文文-Chris1 小时前
神经网络的组成有哪些?激活函数是什么?有什么作用?
人工智能·深度学习·神经网络
sdyeswlw1 小时前
一二三物联网:领航济南制造业数字化绿色化协同转型
人工智能·科技·物联网