大家好,今天跟大家介绍一下,我是如何在鸿蒙智能体中开发“添加服药计划”工作流的。在开发这个工作流之前,我已经完成了一个添加服药计划的插件,但是只依靠插件来完成整个添加流程,仍然存在很多不确定性。例如,智能体应该在什么时候调用插件、如何从用户输入中提取参数、缺少必要参数时如何追问,以及插件执行后如何根据返回结果进行回复等。我的需求是,首先从用户的自然语言中提取尽可能多的服药信息;如果缺少必要参数,就继续向用户追问;如果用户说的是“今天”“明天”“下周一”等相对日期,还要将其转换成具体日期。为了让这些环节按照确定的顺序执行,就需要通过工作流将整个流程串联起来。接下来为大家介绍这个工作流的具体开发过程。
新建工作流
在小艺开放平台的最新版本中,工作流、插件、卡片和知识库等模块都被放到了资源库中。进入资源库后,选择新建工作流即可,如图所示:
新建工作流后,默认会包含一个开始节点和一个结束节点,如图所示:
开始节点用于接收输入,结束节点用于输出结果,它们是工作流两端必不可少的节点。我们可以在开始节点和结束节点之间,根据实际需求添加插件、大模型、选择器和提问器等工作节点。
获取当前时间
我首先添加的是一个获取当前时间的插件,这个插件来自插件市场,如图所示:
添加这个节点的原因是,大模型和插件在运行时会受到上下文影响,无法保证每次都能获取准确的当前时间。如果用户说“今天开始吃”“明天开始服用”或者“吃到下周五”,就需要先获得准确的当前日期,才能将这些相对日期转换成具体日期。将开始节点连接到获取时间节点,并把开始节点接收到的用户输入内容传递给获取时间插件,如图所示:
这个节点会输出当前日期或当前时间,后续再将它和用户输入一起传递给大模型。
使用大模型提取服药信息
在获取时间插件节点后,我添加了一个大模型节点,用来初步提取用户指令中的参数。这个节点会同时接收两个输入:
- 获取时间插件返回的当前时间 currentDate
大模型需要尽量从用户输入中提取药品名称、每次服用剂量、剂量单位、服药频率、服药时间、开始日期、结束日期、持续天数和备注等信息。输出参数包括 name、dose、unit、frequency、times、startDateString、endDateString、duration 和 note 等。我为这个节点设置的系统 Prompt 如下:
你是一个用药信息提取助手。你的任务是从用户输入中提取添加药品参数,并只输出合法 JSON,不要输出解释、Markdown 或多余文字。你会收到两个输入:-${currentDate}:当前日期或当前时间,作为解析“今天、明天、后天、本周五、下周一”等相对日期的基准。-${userInput}:用户的自然语言用药描述。输出 JSON 格式必须严格如下:{ "name": "", "dose": 0, "unit": "", "frequency": "", "times": [], "startDateString": "", "endDateString": "", "duration": 0, "note": ""}字段规则:1. name药品名称,例如阿司匹林、布洛芬、阿莫西林。如果用户未说明药品名称,返回空字符串。2. dose每次服用剂量的数字部分。例如:- “每次1片” → 1- “一次两片” → 2- “每次5毫升” → 5如果未说明剂量,返回 0。3. unit剂量单位,例如片、粒、颗、袋、毫升、ml、mg、克。只提取跟在剂量后的单位。如果用户未说明单位,返回空字符串。4. frequency用药频率。必须从以下枚举值中选择一个:["每天", "每隔1天", "每隔2天", "每隔3天", "每隔4天", "每隔5天", "每隔6天", "每周", "每隔1周", "每隔2周", "每隔3周"]规则:- “一天一次、一天三次、每日、每天、每天早晚、每天饭后、早中晚各一次” → "每天"- “隔天、每两天一次” → "每隔1天"- “每三天一次” → "每隔2天"- “每四天一次” → "每隔3天"- “每周一次、每周三” → "每周"- 无法匹配枚举值时返回空字符串。5. times服药时间点数组,格式为 ["HH:mm"]。明确时间优先:- “早上8点” → ["08:00"]- “晚上9点半” → ["21:30"]- “早上8点和晚上9点” → ["08:00", "21:00"]模糊时间按默认时间推断:- 早上 / 上午 / 早餐后 / 早饭后 → "08:00"- 中午 / 午饭后 / 中饭后 → "12:00"- 下午 → "15:00"- 晚上 / 晚饭后 / 晚餐后 → "19:00"- 睡前 → "22:00"常见表达:- “早晚各一次、早晚吃” → ["08:00", "19:00"]- “早中晚、三餐后、饭后吃、每天三次、一天三次” → ["08:00", "12:00", "19:00"]- “每天两次、一天两次”,未说明具体时间 → ["08:00", "19:00"]- “每天一次、一天一次”,未说明具体时间 → ["08:00"]- 无法推断服药时间 → []6. startDateString服药开始日期字符串,格式为 yyyy-MM-dd。只有用户明确表达开始日期时才提取,例如:- “从今天开始”- “今天开始吃”- “明天开始”- “后天开始”- “7月1日开始”- “下周一开始”相对日期必须基于 currentDate 计算:- “今天” → currentDate 对应日期- “明天” → currentDate + 1 天- “后天” → currentDate + 2 天- “本周五 / 这周五” → currentDate 所在周的周五- “下周一 / 下周五” → currentDate 下一周对应日期如果用户没有说明开始日期,返回空字符串。不要因为用户说了“吃3天”就自动推断开始日期。7. endDateString服药结束日期字符串,格式为 yyyy-MM-dd。只有用户明确表达结束日期时才提取,例如:- “吃到明天”- “吃到后天”- “截止到周五”- “到7月10日为止”- “服用到下周一”相对日期必须基于 currentDate 计算。如果用户没有说明结束日期,返回空字符串。不要根据 duration 自动计算 endDateString,除非用户明确说“吃到、截止到、到……为止”。8. duration服药持续天数,数字类型。当用户明确说了持续时间时提取:- “吃3天” → 3- “吃五天” → 5- “连续吃10天” → 10- “服用一周” → 7- “吃两周” → 14- “吃半个月” → 15- “吃一个月” → 30注意:- “今天开始吃5天” → startDateString 填今天,duration 填 5,endDateString 为空。- “吃到明天” → endDateString 填明天,duration 填 0。- 如果用户同时明确说了结束日期和持续天数,优先保留 endDateString,duration 可以返回用户明确说出的天数;如果两者明显冲突,不要自行修正,把原始冲突信息放入 note。- 如果没有说明持续时间,返回 0。9. note备注信息,例如:- 饭后吃- 饭前吃- 睡前吃- 随餐服用- 医生要求- 疼的时候吃- 必要时服用如果“饭后、饭前、睡前”等信息已经用于推断 times,也仍然可以保留在 note 中。如果没有备注,返回空字符串。其他要求:- 只输出 JSON。- 不要输出解释文字。- JSON 中字符串使用双引号。- dose 和 duration 必须是数字。- times 必须是字符串数组。- 不确定的字段按默认空值返回,不要编造。
节点的具体配置如图所示:
通过这个大模型节点,可以先完成一次整体的信息提取。如果用户在一句话中已经提供了完整信息,后面的流程就不需要重复追问;如果缺少部分信息,则继续进入对应的判断和追问节点。
逐项判断并追问缺少的信息
用户一般不会一次性说出所有服药信息。例如,用户可能只说“帮我添加阿司匹林”,但是没有说明每次服用多少、什么时候服用以及从哪一天开始。因此,工作流还需要对提取结果进行逐项判断。我首先判断的是药品名称。这里先添加一个选择器节点,选择器节点可以连接 if 和 else 两条分支。当 name 为空字符串时,说明大模型没有从用户输入中提取到药品名称,此时进入提问器节点,继续询问用户要添加什么药品。用户回答后,再使用一个大模型节点,从补充内容中提取药品名称。如果 name 不为空,则不需要追问,直接进入下一项内容的判断,如图所示:
按照同样的方式,还可以依次判断服药剂量、剂量单位、服药时间、服药频率、开始日期和结束方式等信息。这里需要注意,只有插件执行时必须使用的参数才需要追问。对于备注等非必要信息,如果用户没有提供,可以直接使用默认值,不需要为了补齐所有字段增加过多对话,否则会让整个添加过程变得比较繁琐。
使用固定选项补充服药频率
在所有追问中,服药频率的处理方式有所不同。因为插件中的服药频率只能使用固定的枚举值,不允许用户随意定义,所以我没有让用户通过自然语言输入,而是在提问器中直接设置了多个固定选项。用户只需要从“每天”“每周”“每隔1天”等选项中进行选择,不仅省略了手动输入的步骤,也可以避免大模型提取出的内容不符合插件参数要求,如图所示:
需要特别注意的是,提问器中的每一个选项都要连接到下一个节点。如果有某个选项没有连接后续节点,在工作流试运行时就会报错。
调用添加服药计划插件
当工作流已经提取并补充完所有必要信息后,就可以将药品名称、服药剂量、服药时间、服药频率和开始日期等参数统一传递给添加服药计划插件。添加服药计划插件的输入和输出参数如下:
在配置插件参数时,需要注意每个参数的数据类型。例如,dose 和 duration 应该传递数字,times 应该传递字符串数组,日期则需要按照插件要求传递具体格式的字符串。通过前面的大模型提取、选择器判断和提问器追问,可以尽量确保传递给插件的参数是完整且符合要求的,从而减少插件调用失败的情况。
处理端插件调用失败的情况
我这里使用的是一个端插件,它需要依赖设备中已经安装的 App。如果用户的设备没有安装对应应用,或者应用版本不符合要求,调用插件时就可能出现报错。因此,我在添加服药计划插件后面紧跟了一个大模型节点,用来分析插件返回的信息。当插件执行成功时,大模型可以根据返回结果告诉用户服药计划已经添加完成;当插件返回错误时,则根据错误信息给出对应的提醒,例如提示用户先安装应用、升级应用版本,或者检查当前设备是否支持该能力,如图所示:
这样处理后,不管插件执行成功还是失败,工作流都能向用户返回更容易理解的结果,而不是直接将插件的原始错误信息展示给用户。相比直接调用插件,工作流可以把参数提取、信息追问、相对日期转换、固定选项限制以及错误处理等环节按照确定的顺序连接起来,让添加服药计划的过程更加稳定,也更符合用户通过自然语言进行操作的习惯。以上就是鸿蒙智能体中添加服药计划工作流的具体开发过程,感谢阅读。
AI时代,技术岗位正在加速升级,掌握AI技术能力和权威认证,将成为未来职业发展的重要竞争力。如果你正在规划AI方向学习路线,想了解HCIA-AI认证要求、学习内容及课程优惠,这个活动建议你一定要参加👇