diff --git a/cookbooks/end2end_application/agent/chatflow.ipynb b/cookbooks/end2end_application/agent/chatflow.ipynb
new file mode 100644
index 000000000..c0d022d3d
--- /dev/null
+++ b/cookbooks/end2end_application/agent/chatflow.ipynb
@@ -0,0 +1,356 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# 前言 - 学习本项目你可以获得什么\n",
+ "- 入门百度智能云千帆AppBuilder,搭建一个工作流Agent应用\n",
+ "- 使用AppBuilder-SDK进行工作流Agent对话\n",
+ "- 了解如何使用AppBuilder-SDK简化多轮对话的开发"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## 1. 项目背景\n",
+ "\n",
+ "### 1.1、 什么是AppBuilder\n",
+ "[百度智能云千帆AppBuilder](https://appbuilder.cloud.baidu.com/)(以下简称AppBuilder)是基于大模型搭建AI原生应用的工作台,旨在降低AI原生应用的开发门槛,赋能开发者和企业快速实现应用搭建。\n",
+ "\n",
+ "平台提供了RAG(检索增强生成)、Agent(智能体)等应用框架,内置了文档问答、表格问答、多轮对话、生成创作等多种应用组件,还包括百度搜索和百度地图等特色组件,以及文本处理、图像处理和语音处理等传统AI组件,支持零代码、低代码、全代码三种开发方式,满足不同开发能力的开发者和企业的场景需求。\n",
+ "\n",
+ "### 1.2、 什么是AppBuilder-SDK\n",
+ "\n",
+ "[百度智能云千帆AppBuilder-SDK](https://github.com/baidubce/app-builder)(以下简称AB-SDK),百度智能云千帆AppBuilder-SDK是百度智能云千帆AppBuilder面向AI原生应用开发者提供的一站式开发平台的客户端SDK。\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# 2. 创建工作流Agent应用并对话\n",
+ "\n",
+ "## 2.1 什么是工作流Agent?\n",
+ "通过工作流编排的形式还原业务流程,每轮对话均严格按照工作流执行,提高了AI应用的可控性,并可编排出复杂业务流程,适用于客服、营销、生成、办公等高可控及高复杂度等场景。\n",
+ "\n",
+ "**工作流Agent无需设置角色人设,通过工作流编排的形式实现应用功能。**\n",
+ "\n",
+ "用户的所有对话均会触发此工作流处理,适用于严格按照流程执行的任务,例如:\n",
+ "\n",
+ "* 客服对话智能体,判断终端用户的意图后严格按照任务分支自动执行,无需大模型思考选择。\n",
+ "* MBTI小助手,根据开发者编排的问题逐个提问,严格按照任务分支和结果执行后续的流程。\n",
+ "\n",
+ "工作流Agent支持用户配置工作流完成整个应用的对话过程,通过开始节点的Rawquery传入首轮对话,利用信息收集节点可以进行一组工作流中的多轮对话,最后以结束节点作为整个工作流结束的标志。开始节点和结束节点之前的完整流程构成一组工作流,每个信息收集节点都可以支持终端用户和应用的一次交互。\n",
+ "\n",
+ "## 2.2 创建工作流Agent应用-飞行客服小助手\n",
+ "\n",
+ "参考产品文档[飞行客服小助手](https://cloud.baidu.com/doc/AppBuilder/s/cm38k8nqr)创建示例应用。通过阅读本篇最佳实践,读者可以深度理解问答节点、信息处理节点、全局跳转节点的功能点和使用方式,搭建自己的工作流agent。对话效果如下:\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ "
\n",
+ "\n",
+ "## 2.3 使用AppBuilder-SDK进行对话\n",
+ "### 2.3.1 方式一:使用SDK直接对话(不推荐)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import appbuilder\n",
+ "import os\n",
+ "from appbuilder.core.console.appbuilder_client import data_class\n",
+ "\n",
+ "# 请前往千帆AppBuilder官网创建密钥,流程详见:https://cloud.baidu.com/doc/AppBuilder/s/Olq6grrt6#1%E3%80%81%E5%88%9B%E5%BB%BA%E5%AF%86%E9%92%A5\n",
+ "# 设置环境变量\n",
+ "os.environ[\"APPBUILDER_TOKEN\"] = \"...\"\n",
+ "appbuilder.logger.setLoglevel(\"ERROR\")\n",
+ "\n",
+ "# 飞行客服小助手的应用id\n",
+ "app_id = \"...\"\n",
+ "# 初始化智能体\n",
+ "client = appbuilder.AppBuilderClient(app_id)\n",
+ "# 创建会话\n",
+ "conversation_id = client.create_conversation()\n",
+ "interrupt_ids = []\n",
+ "\n",
+ "msg = client.run(conversation_id, \"查天气\", stream=True)\n",
+ "interrupt_event_id = None\n",
+ "for ans in msg.content:\n",
+ " for event in ans.events:\n",
+ " if event.content_type == \"publish_message\":\n",
+ " print(event.detail.get(\"message\"))\n",
+ " if event.content_type == \"chatflow_interrupt\":\n",
+ " interrupt_event_id = event.detail.get(\"interrupt_event_id\")\n",
+ " break\n",
+ "interrupt_ids.append(interrupt_event_id)\n",
+ "\n",
+ "msg2 = client.run(\n",
+ " conversation_id,\n",
+ " \"查航班\",\n",
+ " stream=True,\n",
+ " action=data_class.Action.create_resume_action(interrupt_event_id),\n",
+ ")\n",
+ "interrupt_event_id = None\n",
+ "for ans in msg2.content:\n",
+ " for event in ans.events:\n",
+ " if event.content_type == \"publish_message\":\n",
+ " print(event.detail.get(\"message\"))\n",
+ " if event.content_type == \"chatflow_interrupt\":\n",
+ " interrupt_event_id = event.detail.get(\"interrupt_event_id\")\n",
+ " break\n",
+ " interrupt_ids.append(interrupt_event_id)\n",
+ "\n",
+ "msg3 = client.run(\n",
+ " conversation_id=conversation_id,\n",
+ " query=\"CA1234\",\n",
+ " stream=True,\n",
+ " action=data_class.Action.create_resume_action(interrupt_ids.pop()),\n",
+ ")\n",
+ "interrupt_event_id = None\n",
+ "for ans in msg3.content:\n",
+ " for event in ans.events:\n",
+ " if event.content_type == \"text\":\n",
+ " print(event.detail.get(\"text\"))\n",
+ " if event.content_type == \"chatflow_interrupt\":\n",
+ " interrupt_event_id = event.detail.get(\"interrupt_event_id\")\n",
+ " break\n",
+ "interrupt_ids.append(interrupt_event_id)\n",
+ "\n",
+ "msg4 = client.run(\n",
+ " conversation_id=conversation_id,\n",
+ " query=\"北京的\",\n",
+ " stream=True,\n",
+ " action=data_class.Action.create_resume_action(interrupt_ids.pop()),\n",
+ ")\n",
+ "has_multiple_dialog_event = False\n",
+ "for ans in msg4.content:\n",
+ " for event in ans.events:\n",
+ " if event.content_type == \"text\":\n",
+ " print(event.detail.get(\"text\"))\n",
+ " if event.content_type == \"multiple_dialog_event\":\n",
+ " has_multiple_dialog_event = True\n",
+ " break"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 2.3.2 方式二 实现自己的EventHandler,更方便地进行对话(推荐)\n",
+ "直接调用处理较为繁琐。SDK提供了使用AppBuilderEventHandler简化tool_call操作的功能。**继承AppBuilderEventHandler类,并实现针对各类型event的处理方法。**"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import appbuilder\n",
+ "from appbuilder.core.console.appbuilder_client.event_handler import (\n",
+ " AppBuilderEventHandler,\n",
+ ")\n",
+ "\n",
+ "\n",
+ "class MyEventHandler(AppBuilderEventHandler):\n",
+ " def __init__(self):\n",
+ " super().__init__()\n",
+ " self.interrupt_ids = []\n",
+ "\n",
+ " def handle_content_type(self, run_context, run_response):\n",
+ " interrupt_event_id = None\n",
+ " event = run_response.events[-1]\n",
+ " if event.content_type == \"chatflow_interrupt\":\n",
+ " interrupt_event_id = event.detail.get(\"interrupt_event_id\")\n",
+ " if interrupt_event_id is not None:\n",
+ " self.interrupt_ids.append(interrupt_event_id)\n",
+ "\n",
+ " def _create_action(self):\n",
+ " if len(self.interrupt_ids) == 0:\n",
+ " return None\n",
+ " event_id = self.interrupt_ids.pop()\n",
+ " return {\n",
+ " \"action_type\": \"resume\",\n",
+ " \"parameters\": {\"interrupt_event\": {\"id\": event_id, \"type\": \"chat\"}},\n",
+ " }\n",
+ "\n",
+ " def run(self, query=None):\n",
+ " super().new_dialog(\n",
+ " query=query,\n",
+ " action=self._create_action(),\n",
+ " )\n",
+ "\n",
+ "\n",
+ "def main():\n",
+ " # 请前往千帆AppBuilder官网创建密钥,流程详见:https://cloud.baidu.com/doc/AppBuilder/s/Olq6grrt6#1%E3%80%81%E5%88%9B%E5%BB%BA%E5%AF%86%E9%92%A5\n",
+ " # 设置环境变量\n",
+ " os.environ[\"APPBUILDER_TOKEN\"] = \"...\"\n",
+ " appbuilder.logger.setLoglevel(\"DEBUG\")\n",
+ "\n",
+ " # 飞行客服小助手的应用id\n",
+ " app_id = \"...\"\n",
+ " # 初始化智能体\n",
+ " client = appbuilder.AppBuilderClient(app_id)\n",
+ " conversation_id = client.create_conversation()\n",
+ "\n",
+ " event_handler = MyEventHandler()\n",
+ " event_handler.init(\n",
+ " appbuilder_client=client,\n",
+ " conversation_id=conversation_id,\n",
+ " stream=True,\n",
+ " query=\"查天气\",\n",
+ " )\n",
+ " for data in event_handler:\n",
+ " pass\n",
+ " event_handler.run(\n",
+ " query=\"查航班\",\n",
+ " )\n",
+ " for data in event_handler:\n",
+ " pass\n",
+ " event_handler.run(\n",
+ " query=\"CA1234\",\n",
+ " )\n",
+ " for data in event_handler:\n",
+ " pass\n",
+ " event_handler.run(\n",
+ " query=\"北京的\",\n",
+ " )\n",
+ " for data in event_handler:\n",
+ " pass\n",
+ "\n",
+ "\n",
+ "if __name__ == \"__main__\":\n",
+ " main()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### 2.3.3 方式三、实现自己的EventHandler,更方便地进行多轮对话(推荐)\n",
+ "SDK提供了run_multiple_dialog_with_handler方法来进行多轮对话,按需传入iterable对象(queries、actions等参数),即可一次调用完成多轮对话。"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import appbuilder\n",
+ "from appbuilder.core.console.appbuilder_client.event_handler import (\n",
+ " AppBuilderEventHandler,\n",
+ ")\n",
+ "\n",
+ "\n",
+ "class MyEventHandler(AppBuilderEventHandler):\n",
+ " def __init__(self):\n",
+ " super().__init__()\n",
+ " self.interrupt_ids = []\n",
+ "\n",
+ " def handle_content_type(self, run_context, run_response):\n",
+ " interrupt_event_id = None\n",
+ " event = run_response.events[-1]\n",
+ " if event.content_type == \"chatflow_interrupt\":\n",
+ " interrupt_event_id = event.detail.get(\"interrupt_event_id\")\n",
+ " if interrupt_event_id is not None:\n",
+ " self.interrupt_ids.append(interrupt_event_id)\n",
+ "\n",
+ " def _create_action(self):\n",
+ " if len(self.interrupt_ids) == 0:\n",
+ " return None\n",
+ " event_id = self.interrupt_ids.pop()\n",
+ " return {\n",
+ " \"action_type\": \"resume\",\n",
+ " \"parameters\": {\"interrupt_event\": {\"id\": event_id, \"type\": \"chat\"}},\n",
+ " }\n",
+ "\n",
+ " def gen_action(self):\n",
+ " while True:\n",
+ " yield self._create_action()\n",
+ "\n",
+ "\n",
+ "def main():\n",
+ " # 请前往千帆AppBuilder官网创建密钥,流程详见:https://cloud.baidu.com/doc/AppBuilder/s/Olq6grrt6#1%E3%80%81%E5%88%9B%E5%BB%BA%E5%AF%86%E9%92%A5\n",
+ " # 设置环境变量\n",
+ " os.environ[\"APPBUILDER_TOKEN\"] = \"...\"\n",
+ " appbuilder.logger.setLoglevel(\"DEBUG\")\n",
+ "\n",
+ " # 飞行客服小助手的应用id\n",
+ " app_id = \"...\"\n",
+ " # 初始化智能体\n",
+ " client = appbuilder.AppBuilderClient(app_id)\n",
+ " conversation_id = client.create_conversation()\n",
+ "\n",
+ " queries = [\"查天气\", \"查航班\", \"CA1234\", \"北京的\"]\n",
+ " event_handler = MyEventHandler()\n",
+ " event_handler = client.run_multiple_dialog_with_handler(\n",
+ " conversation_id=conversation_id,\n",
+ " queries=queries,\n",
+ " event_handler=event_handler,\n",
+ " stream=True,\n",
+ " actions=event_handler.gen_action(),\n",
+ " )\n",
+ " for data in event_handler:\n",
+ " for ans in data:\n",
+ " pass\n",
+ "\n",
+ "\n",
+ "if __name__ == \"__main__\":\n",
+ " main()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# 3、项目总结\n",
+ "\n",
+ "本项目最终完成了一个工作流Agent应用的创建,并使用Appbuilder-SDK进行对话功能。\n",
+ "\n",
+ "希望您可以不吝`Star`,给`AppBuilder-SDK`一些鼓励,期待您的`PR`,一起共建AIAgent生态。\n",
+ "\n",
+ "Github地址:https://github.com/baidubce/app-builder\n",
+ "\n",
+ "\n",
+ "\n",
+ "最后,您也可以进入`AppBuilder-SDK`的WX交流群,和大家一起交流AppBuilder使用及开发心得。\n",
+ "\n",
+ ""
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "testenv",
+ "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.9.20"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}
diff --git a/docs/BasisModule/Platform/Application/appbuilder_client.md b/docs/BasisModule/Platform/Application/appbuilder_client.md
index 08dcc44ca..cf48bff57 100644
--- a/docs/BasisModule/Platform/Application/appbuilder_client.md
+++ b/docs/BasisModule/Platform/Application/appbuilder_client.md
@@ -60,29 +60,32 @@ AppBuilderClient组件支持调用在[百度智能云千帆AppBuilder](https://c
#### 方法参数
-| 参数名称 | 参数类型 | 是否必须 | 描述 | 示例值 |
-| --------------- | ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
-| conversation_id | String | 是 | 会话ID | |
-| query | String | 否 | query问题内容 | "今天天气怎么样?" |
-| file_ids | list[String] | 否 | 对话可引用的文档ID | |
-| stream | Bool | 否 | 为true时则流式返回,为false时则一次性返回所有内容, 推荐设为true,降低首token时延 | False |
-| end_user_id | String | 否 | 终端用户ID,限制6 - 64字符 | |
-| tools | List[Tool] | 否 | 一个列表,其中每个字典对应一个工具的配置 | |
-| tools[0] | Tool | 否 | 工具配置 | |
+| 参数名称 | 参数类型 | 是否必须 | 描述 | 示例值 |
+| --------------- | ------------------ | -------- | ------------------------------------------------------------ | ----------------- |
+| conversation_id | String | 是 | 会话ID | |
+| query | String | 否 | query问题内容 | "今天天气怎么样?" |
+| file_ids | list[String] | 否 | 对话可引用的文档ID | |
+| stream | Bool | 否 | 为true时则流式返回,为false时则一次性返回所有内容, 推荐设为true,降低首token时延 | False |
+| end_user_id | String | 否 | 终端用户ID,限制6 - 64字符 | |
+| tools | List[Tool] | 否 | 一个列表,其中每个字典对应一个工具的配置 | |
+| tools[0] | Tool | 否 | 工具配置 | |
| +type | String | 否 | 枚举:
**file_retrieval**: 知识库检索工具能够理解文档内容,支持用户针对文档内容的问答。
**code_interpreter**: 代码解释器, 代码解释器能够生成并执行代码,从而协助用户解决复杂问题,涵盖科学计算(包括普通数学计算题)、数据可视化、文件编辑处理(图片、PDF文档、视频、音频等)、文件格式转换(如WAV、MP3、text、SRT、PNG、jpg、MP4、GIF、MP3等)、数据分析&清洗&处理(文件以excel、csv格式为主)、机器学习&深度学习建模&自然语言处理等多个领域。
**function**: 支持fucntion call模式调用工具 | |
-| +function | Function | 否 | Function工具描述
仅当**type为**`**function**` 时需要且必须填写 | |
-| ++name | String | 否 | 函数名
只允许数字、大小写字母和中划线和下划线,最大长度为64个字符。一次运行中唯一。 | |
-| ++description | String | 否 | 工具描述 | |
-| ++parameters | Dict | 否 | 工具参数, json_schema格式 | |
-| tool_outputs | List[ToolOutput] | 否 | 内容为本地的工具执行结果,以自然语言/json dump str描述 | |
-| tool_outputs[0] | ToolOutput | 否 | 工具执行结果 | |
-| +tool_call_id | String | 否 | 工具调用ID | |
-| +output | String | 否 | 工具输出 | |
-| tool_choice | ToolChoice | 否 | 控制大模型使用组件的方式,仅对自主规划Agent生效。 | |
-| +type | String | 否 | auto/function,auto表示由LLM自动判断调什么组件;function表示由用户指定调用哪个组件。 | |
-| +function | ToolChoiceFunction | 否 | 组件对象,包括组件的英文名称和入参 | |
-| ++name | String | 否 | 组件的英文名称(唯一标识) | |
-| ++input | String | 否 | 组件入参,当组件没有入参时填入空对象{} | |
+| +function | Function | 否 | Function工具描述
仅当**type为**`**function**` 时需要且必须填写 | |
+| ++name | String | 否 | 函数名
只允许数字、大小写字母和中划线和下划线,最大长度为64个字符。一次运行中唯一。 | |
+| ++description | String | 否 | 工具描述 | |
+| ++parameters | Dict | 否 | 工具参数, json_schema格式 | |
+| tool_outputs | List[ToolOutput] | 否 | 内容为本地的工具执行结果,以自然语言/json dump str描述 | |
+| tool_outputs[0] | ToolOutput | 否 | 工具执行结果 | |
+| +tool_call_id | String | 否 | 工具调用ID | |
+| +output | String | 否 | 工具输出 | |
+| tool_choice | ToolChoice | 否 | 控制大模型使用组件的方式,仅对自主规划Agent生效。 | |
+| +type | String | 否 | auto/function,auto表示由LLM自动判断调什么组件;function表示由用户指定调用哪个组件。 | |
+| +function | ToolChoiceFunction | 否 | 组件对象,包括组件的英文名称和入参 | |
+| ++name | String | 否 | 组件的英文名称(唯一标识) | |
+| ++input | String | 否 | 组件入参,当组件没有入参时填入空对象{} | |
+| action | Action | 否 | 对话时要进行的特殊操作。如回复工作流agent中“信息收集节点“的消息 | |
+| +action_type | String | 是 | 要执行的操作。
可选值为:
resume:回复“信息收集节点” 的消息 | |
+| +parameters | Object | 是 | 执行操作时所需的参数 | |
#### Run方法非流式返回值
@@ -443,6 +446,244 @@ answer = app_builder_client.run(
)
```
+
+
+#### Run方法回复工作流Agent “信息收集节点”使用示例:
+
+使用[“飞行客服小助手”](https://cloud.baidu.com/doc/AppBuilder/s/cm38k8nqr)作为工作流Agent的示例应用。
+
+**方式1:** SDK直接进行对话(不推荐)
+
+```python
+import appbuilder
+import os
+from appbuilder.core.console.appbuilder_client import data_class
+
+# 请前往千帆AppBuilder官网创建密钥,流程详见:https://cloud.baidu.com/doc/AppBuilder/s/Olq6grrt6#1%E3%80%81%E5%88%9B%E5%BB%BA%E5%AF%86%E9%92%A5
+# 设置环境变量
+os.environ["APPBUILDER_TOKEN"] = (
+ "..."
+)
+appbuilder.logger.setLoglevel("ERROR")
+
+# 飞行客服小助手的应用id
+app_id = "..."
+# 初始化智能体
+client = appbuilder.AppBuilderClient(app_id)
+# 创建会话
+conversation_id = client.create_conversation()
+interrupt_ids = []
+
+msg = client.run(conversation_id, "查天气", stream=True)
+interrupt_event_id = None
+for ans in msg.content:
+ for event in ans.events:
+ if event.content_type == "publish_message":
+ print(event.detail.get("message"))
+ if event.content_type == "chatflow_interrupt":
+ interrupt_event_id = event.detail.get("interrupt_event_id")
+ break
+interrupt_ids.append(interrupt_event_id)
+
+msg2 = client.run(
+ conversation_id,
+ "查航班",
+ stream=True,
+ action=data_class.Action.create_resume_action(interrupt_event_id),
+)
+interrupt_event_id = None
+for ans in msg2.content:
+ for event in ans.events:
+ if event.content_type == "publish_message":
+ print(event.detail.get("message"))
+ if event.content_type == "chatflow_interrupt":
+ interrupt_event_id = event.detail.get("interrupt_event_id")
+ break
+ interrupt_ids.append(interrupt_event_id)
+
+msg3 = client.run(
+ conversation_id=conversation_id,
+ query="CA1234",
+ stream=True,
+ action=data_class.Action.create_resume_action(interrupt_ids.pop()),
+)
+interrupt_event_id = None
+for ans in msg3.content:
+ for event in ans.events:
+ if event.content_type == "text":
+ print(event.detail.get("text"))
+ if event.content_type == "chatflow_interrupt":
+ interrupt_event_id = event.detail.get("interrupt_event_id")
+ break
+interrupt_ids.append(interrupt_event_id)
+
+msg4 = client.run(
+ conversation_id=conversation_id,
+ query="北京的",
+ stream=True,
+ action=data_class.Action.create_resume_action(interrupt_ids.pop()),
+)
+has_multiple_dialog_event = False
+for ans in msg4.content:
+ for event in ans.events:
+ if event.content_type == "text":
+ print(event.detail.get("text"))
+ if event.content_type == "multiple_dialog_event":
+ has_multiple_dialog_event = True
+ break
+
+```
+
+**方式2:** 实现自己的EventHandler,更方便地进行对话(推荐)
+
+```python
+import os
+import appbuilder
+from appbuilder.core.console.appbuilder_client.event_handler import (
+ AppBuilderEventHandler,
+)
+
+
+class MyEventHandler(AppBuilderEventHandler):
+ def __init__(self):
+ super().__init__()
+ self.interrupt_ids = []
+
+ def handle_content_type(self, run_context, run_response):
+ interrupt_event_id = None
+ event = run_response.events[-1]
+ if event.content_type == "chatflow_interrupt":
+ interrupt_event_id = event.detail.get("interrupt_event_id")
+ if interrupt_event_id is not None:
+ self.interrupt_ids.append(interrupt_event_id)
+
+ def _create_action(self):
+ if len(self.interrupt_ids) == 0:
+ return None
+ event_id = self.interrupt_ids.pop()
+ return {
+ "action_type": "resume",
+ "parameters": {"interrupt_event": {"id": event_id, "type": "chat"}},
+ }
+
+ def run(self, query=None):
+ super().new_dialog(
+ query=query,
+ action=self._create_action(),
+ )
+
+
+def main():
+ # 请前往千帆AppBuilder官网创建密钥,流程详见:https://cloud.baidu.com/doc/AppBuilder/s/Olq6grrt6#1%E3%80%81%E5%88%9B%E5%BB%BA%E5%AF%86%E9%92%A5
+ # 设置环境变量
+ os.environ["APPBUILDER_TOKEN"] = "..."
+ appbuilder.logger.setLoglevel("DEBUG")
+
+ # 飞行客服小助手的应用id
+ app_id = "..."
+ # 初始化智能体
+ client = appbuilder.AppBuilderClient(app_id)
+ conversation_id = client.create_conversation()
+
+ event_handler = MyEventHandler()
+ event_handler.init(
+ appbuilder_client=client,
+ conversation_id=conversation_id,
+ stream=True,
+ query="查天气",
+ )
+ for data in event_handler:
+ pass
+ event_handler.run(
+ query="查航班",
+ )
+ for data in event_handler:
+ pass
+ event_handler.run(
+ query="CA1234",
+ )
+ for data in event_handler:
+ pass
+ event_handler.run(
+ query="北京的",
+ )
+ for data in event_handler:
+ pass
+
+
+if __name__ == "__main__":
+ main()
+```
+
+**方式3:** 实现自己的EventHandler,更方便地进行多轮对话(推荐)
+
+```python
+import os
+import appbuilder
+from appbuilder.core.console.appbuilder_client.event_handler import (
+ AppBuilderEventHandler,
+)
+
+
+class MyEventHandler(AppBuilderEventHandler):
+ def __init__(self):
+ super().__init__()
+ self.interrupt_ids = []
+
+ def handle_content_type(self, run_context, run_response):
+ interrupt_event_id = None
+ event = run_response.events[-1]
+ if event.content_type == "chatflow_interrupt":
+ interrupt_event_id = event.detail.get("interrupt_event_id")
+ if interrupt_event_id is not None:
+ self.interrupt_ids.append(interrupt_event_id)
+
+ def _create_action(self):
+ if len(self.interrupt_ids) == 0:
+ return None
+ event_id = self.interrupt_ids.pop()
+ return {
+ "action_type": "resume",
+ "parameters": {"interrupt_event": {"id": event_id, "type": "chat"}},
+ }
+
+ def gen_action(self):
+ while True:
+ yield self._create_action()
+
+
+def main():
+ # 请前往千帆AppBuilder官网创建密钥,流程详见:https://cloud.baidu.com/doc/AppBuilder/s/Olq6grrt6#1%E3%80%81%E5%88%9B%E5%BB%BA%E5%AF%86%E9%92%A5
+ # 设置环境变量
+ os.environ["APPBUILDER_TOKEN"] = "..."
+ appbuilder.logger.setLoglevel("DEBUG")
+
+ # 飞行客服小助手的应用id
+ app_id = "..."
+ # 初始化智能体
+ client = appbuilder.AppBuilderClient(app_id)
+ conversation_id = client.create_conversation()
+
+ queries = ["查天气", "查航班", "CA1234", "北京的"]
+ event_handler = MyEventHandler()
+ event_handler = client.run_multiple_dialog_with_handler(
+ conversation_id=conversation_id,
+ queries=queries,
+ event_handler=event_handler,
+ stream=True,
+ actions=event_handler.gen_action(),
+ )
+ for data in event_handler:
+ for ans in data:
+ pass
+
+
+if __name__ == "__main__":
+ main()
+```
+
+
+
## Java基本用法
### ```new AppBuilderClient(appId)```
@@ -473,27 +714,30 @@ answer = app_builder_client.run(
#### Run方法入参`AppBuilderCientRunRequest`
-| 参数名称 | 参数类型 | 是否必须 | 描述 | 示例值 |
-| --------------- | ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
-| query | String | 是 | query内容 | "汽车性能参数怎么样" |
-| conversationId | String | 是 | 对话id,可以通过createConversation()获取 | |
-| stream | boolean | 是 | 为true时则流式返回,为false时则一次性返回所有内容, 推荐设为true,降低首token时延 | |
-| tools | List[Tool] | 否 | 一个列表,其中每个字典对应一个工具的配置 | |
-| tools[0] | Tool | 否 | 工具配置 | |
+| 参数名称 | 参数类型 | 是否必须 | 描述 | 示例值 |
+| --------------- | ------------------ | -------- | ------------------------------------------------------------ | -------------------- |
+| query | String | 是 | query内容 | "汽车性能参数怎么样" |
+| conversationId | String | 是 | 对话id,可以通过createConversation()获取 | |
+| stream | boolean | 是 | 为true时则流式返回,为false时则一次性返回所有内容, 推荐设为true,降低首token时延 | |
+| tools | List[Tool] | 否 | 一个列表,其中每个字典对应一个工具的配置 | |
+| tools[0] | Tool | 否 | 工具配置 | |
| +type | String | 否 | 枚举:
**file_retrieval**: 知识库检索工具能够理解文档内容,支持用户针对文档内容的问答。
**code_interpreter**: 代码解释器, 代码解释器能够生成并执行代码,从而协助用户解决复杂问题,涵盖科学计算(包括普通数学计算题)、数据可视化、文件编辑处理(图片、PDF文档、视频、音频等)、文件格式转换(如WAV、MP3、text、SRT、PNG、jpg、MP4、GIF、MP3等)、数据分析&清洗&处理(文件以excel、csv格式为主)、机器学习&深度学习建模&自然语言处理等多个领域。
**function**: 支持fucntion call模式调用工具 | |
-| +function | Function | 否 | Function工具描述
仅当**type为**`**function**` 时需要且必须填写 | |
-| ++name | String | 否 | 函数名
只允许数字、大小写字母和中划线和下划线,最大长度为64个字符。一次运行中唯一。 | |
-| ++description | String | 否 | 工具描述 | |
-| ++parameters | Dict | 否 | 工具参数, json_schema格式 | |
-| tool_outputs | List[ToolOutput] | 否 | 内容为本地的工具执行结果,以自然语言/json dump str描述 | |
-| tool_outputs[0] | ToolOutput | 否 | 工具执行结果 | |
-| +tool_call_id | String | 否 | 工具调用ID | |
-| +output | String | 否 | 工具输出 | |
-| tool_choice | ToolChoice | 否 | 控制大模型使用组件的方式,仅对自主规划Agent生效。 | |
-| +type | String | 否 | auto/function,auto表示由LLM自动判断调什么组件;function表示由用户指定调用哪个组件。 | |
-| +function | ToolChoiceFunction | 否 | 组件对象,包括组件的英文名称和入参 | |
-| ++name | String | 否 | 组件的英文名称(唯一标识) | |
-| ++input | String | 否 | 组件入参,当组件没有入参时填入空对象{} | |
+| +function | Function | 否 | Function工具描述
仅当**type为**`**function**` 时需要且必须填写 | |
+| ++name | String | 否 | 函数名
只允许数字、大小写字母和中划线和下划线,最大长度为64个字符。一次运行中唯一。 | |
+| ++description | String | 否 | 工具描述 | |
+| ++parameters | Dict | 否 | 工具参数, json_schema格式 | |
+| tool_outputs | List[ToolOutput] | 否 | 内容为本地的工具执行结果,以自然语言/json dump str描述 | |
+| tool_outputs[0] | ToolOutput | 否 | 工具执行结果 | |
+| +tool_call_id | String | 否 | 工具调用ID | |
+| +output | String | 否 | 工具输出 | |
+| tool_choice | ToolChoice | 否 | 控制大模型使用组件的方式,仅对自主规划Agent生效。 | |
+| +type | String | 否 | auto/function,auto表示由LLM自动判断调什么组件;function表示由用户指定调用哪个组件。 | |
+| +function | ToolChoiceFunction | 否 | 组件对象,包括组件的英文名称和入参 | |
+| ++name | String | 否 | 组件的英文名称(唯一标识) | |
+| ++input | String | 否 | 组件入参,当组件没有入参时填入空对象{} | |
+| action | Action | 否 | 对话时要进行的特殊操作。如回复工作流agent中“信息收集节点“的消息 | |
+| +action_type | String | 是 | 要执行的操作。
可选值为:
resume:回复“信息收集节点” 的消息 | |
+| +parameters | Object | 是 | 执行操作时所需的参数 | |
#### Run方法出参
| 参数名称 | 参数类型 | 描述 | 示例值 |
@@ -832,6 +1076,116 @@ class AppBuilderClientDemo {
```
+#### Run方法回复工作流Agent “信息收集节点”使用示例:
+
+使用[“飞行客服小助手”](https://cloud.baidu.com/doc/AppBuilder/s/cm38k8nqr)作为工作流Agent的示例应用
+
+```java
+package org.example;
+
+import java.io.IOException;
+import java.util.*;
+
+import com.google.gson.annotations.SerializedName;
+
+import com.baidubce.appbuilder.base.exception.AppBuilderServerException;
+import com.baidubce.appbuilder.console.appbuilderclient.AppBuilderClient;
+import com.baidubce.appbuilder.model.appbuilderclient.AppBuilderClientIterator;
+import com.baidubce.appbuilder.model.appbuilderclient.AppBuilderClientResult;
+import com.baidubce.appbuilder.model.appbuilderclient.AppBuilderClientRunRequest;
+import com.baidubce.appbuilder.model.appbuilderclient.Event;
+import com.baidubce.appbuilder.base.utils.json.JsonUtils;
+
+class AppBuilderClientDemo {
+
+ public static void main(String[] args) throws IOException, AppBuilderServerException {
+ System.setProperty("APPBUILDER_TOKEN", "请设置正确的应用密钥");
+ String chatflowAppId = "请设置正确的应用ID";
+ AppBuilderClient builder = new AppBuilderClient(chatflowAppId);
+ String conversationId = builder.createConversation();
+
+ AppBuilderClientRunRequest request = new AppBuilderClientRunRequest(chatflowAppId, conversationId, "查天气", true);
+ Stack interruptStack = new Stack();
+ AppBuilderClientIterator itor = builder.run(request);
+ String interruptEventId = "";
+ while (itor.hasNext()) {
+ AppBuilderClientResult result = itor.next();
+ for (Event event : result.getEvents()) {
+ if (event.getContentType().equals(EventContent.PublishMessageContentType)) {
+ String message = event.getDetail().get("message").toString();
+ System.out.println(message);
+ }
+ if (event.getContentType().equals(EventContent.ChatflowInterruptContentType)) {
+ interruptEventId = event.getDetail().get("interrupt_event_id").toString();
+ interruptStack.push(interruptEventId);
+ break;
+ }
+ }
+ }
+
+ interruptEventId = "";
+ AppBuilderClientRunRequest request2 = new AppBuilderClientRunRequest(chatflowAppId, conversationId, "我先查个航班动态", true);
+ request2.setAction(AppBuilderClientRunRequest.Action.createAction(interruptStack.pop()));
+ AppBuilderClientIterator itor2 = builder.run(request2);
+ while (itor2.hasNext()) {
+ AppBuilderClientResult result2 = itor2.next();
+ for (Event event : result2.getEvents()) {
+ if (event.getContentType().equals(EventContent.PublishMessageContentType)) {
+ String message = event.getDetail().get("message").toString();
+ System.out.println(message);
+ }
+ if (event.getContentType().equals(EventContent.ChatflowInterruptContentType)) {
+ interruptEventId = event.getDetail().get("interrupt_event_id").toString();
+ interruptStack.push(interruptEventId);
+ break;
+ }
+ }
+ }
+
+ interruptEventId = "";
+ AppBuilderClientRunRequest request3 = new AppBuilderClientRunRequest(chatflowAppId, conversationId, "CA1234", true);
+ request3.setAction(AppBuilderClientRunRequest.Action.createAction(interruptStack.pop()));
+ AppBuilderClientIterator itor3 = builder.run(request3);
+ while (itor3.hasNext()) {
+ AppBuilderClientResult result3 = itor3.next();
+ for (Event event : result3.getEvents()) {
+ if (event.getContentType().equals(EventContent.TextContentType)) {
+ String text = event.getDetail().get("text").toString();
+ System.out.println(text);
+ }
+ if (event.getContentType().equals(EventContent.ChatflowInterruptContentType)) {
+ interruptEventId = event.getDetail().get("interrupt_event_id").toString();
+ interruptStack.push(interruptEventId);
+ break;
+ }
+ }
+ }
+
+ boolean hasMultipleContentType = false;
+ AppBuilderClientRunRequest request4 = new AppBuilderClientRunRequest(chatflowAppId, conversationId, "北京的",
+ true);
+ request4.setAction(AppBuilderClientRunRequest.Action.createAction(interruptStack.pop()));
+ AppBuilderClientIterator itor4 = builder.run(request4);
+ while (itor4.hasNext()) {
+ AppBuilderClientResult result4 = itor4.next();
+ for (Event event : result4.getEvents()) {
+ if (event.getContentType().equals(EventContent.TextContentType)) {
+ String text = event.getDetail().get("text").toString();
+ System.out.println(text);
+ }
+ if (event.getContentType().equals(EventContent.MultipleDialogEventContentType)) {
+ hasMultipleContentType = true;
+ break;
+ }
+ }
+ }
+ }
+}
+
+```
+
+
+
## Go基本用法
### ```NewAppBuilderClient()```
@@ -1170,3 +1524,169 @@ func main() {
}
}
```
+
+#### Run方法回复工作流Agent “信息收集节点”使用示例:
+
+使用[“飞行客服小助手”](https://cloud.baidu.com/doc/AppBuilder/s/cm38k8nqr)作为工作流Agent的示例应用
+
+```go
+package main
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/baidubce/app-builder/go/appbuilder"
+)
+
+func main() {
+ // 设置APPBUILDER_TOKEN、GATEWAY_URL_V2环境变量
+ os.Setenv("APPBUILDER_TOKEN", "请设置正确的应用密钥")
+ // 默认可不填,默认值是 https://qianfan.baidubce.com
+ os.Setenv("GATEWAY_URL_V2", "")
+ config, err := appbuilder.NewSDKConfig("", "")
+ if err != nil {
+ fmt.Println("new config failed: ", err)
+ return
+ }
+ // 初始化实例
+ appID := "请填写正确的应用ID"
+ client, err := appbuilder.NewAppBuilderClient(appID, config)
+ if err != nil {
+ fmt.Println("new agent builder failed: ", err)
+ return
+ }
+ // 创建对话ID
+ conversationID, err := client.CreateConversation()
+ if err != nil {
+ fmt.Println("create conversation failed: ", err)
+ return
+ }
+ i, err := client.Run(appbuilder.AppBuilderClientRunRequest{
+ ConversationID: conversationID,
+ AppID: appID,
+ Query: "查天气",
+ Stream: true,
+ })
+
+ if err != nil {
+ fmt.Println("run failed: ", err)
+ return
+ }
+
+ var interruptId string
+ interruptStack := make([]string, 0)
+ for answer, err := i.Next(); err == nil; answer, err = i.Next() {
+ for _, ev := range answer.Events {
+ if ev.ContentType == appbuilder.PublishMessageContentType {
+ detail := ev.Detail.(appbuilder.PublishMessageDetail)
+ message := detail.Message
+ fmt.Println(message)
+ break
+ }
+ if ev.ContentType == appbuilder.ChatflowInterruptContentType {
+ deatil := ev.Detail.(appbuilder.ChatflowInterruptDetail)
+ interruptId = deatil.InterruptEventID
+ interruptStack = append(interruptStack, interruptId)
+ break
+ }
+ }
+ }
+ if len(interruptId) == 0 {
+ fmt.Println("interrupt id is empty")
+ return
+ }
+
+ interruptId = ""
+ i2, err := client.Run(appbuilder.AppBuilderClientRunRequest{
+ ConversationID: conversationID,
+ AppID: appID,
+ Query: "我先查个航班动态",
+ Stream: true,
+ Action: appbuilder.NewResumeAction(interruptStack[len(interruptStack)-1]),
+ })
+ if err != nil {
+ fmt.Println("run failed:", err)
+ return
+ }
+ interruptStack = interruptStack[:len(interruptStack)-1]
+ for answer, err := i2.Next(); err == nil; answer, err = i2.Next() {
+ for _, ev := range answer.Events {
+ if ev.ContentType == appbuilder.PublishMessageContentType {
+ detail := ev.Detail.(appbuilder.PublishMessageDetail)
+ message := detail.Message
+ fmt.Println(message)
+ break
+ }
+ if ev.ContentType == appbuilder.ChatflowInterruptContentType {
+ deatil := ev.Detail.(appbuilder.ChatflowInterruptDetail)
+ interruptId = deatil.InterruptEventID
+ interruptStack = append(interruptStack, interruptId)
+ break
+ }
+ }
+ }
+ if len(interruptId) == 0 {
+ fmt.Println("interrupt id is empty")
+ return
+ }
+
+ interruptId = ""
+ i3, err := client.Run(appbuilder.AppBuilderClientRunRequest{
+ ConversationID: conversationID,
+ AppID: appID,
+ Query: "CA1234",
+ Stream: true,
+ Action: appbuilder.NewResumeAction(interruptStack[len(interruptStack)-1]),
+ })
+ if err != nil {
+ fmt.Println("run failed:", err)
+ return
+ }
+ interruptStack = interruptStack[:len(interruptStack)-1]
+ for answer, err := i3.Next(); err == nil; answer, err = i3.Next() {
+ for _, ev := range answer.Events {
+ if ev.ContentType == appbuilder.TextContentType {
+ detail := ev.Detail.(appbuilder.TextDetail)
+ text := detail.Text
+ fmt.Println(text)
+ break
+ }
+ if ev.ContentType == appbuilder.ChatflowInterruptContentType {
+ deatil := ev.Detail.(appbuilder.ChatflowInterruptDetail)
+ interruptId = deatil.InterruptEventID
+ interruptStack = append(interruptStack, interruptId)
+ break
+ }
+ }
+ }
+ if len(interruptId) == 0 {
+ fmt.Println("interrupt id is empty")
+ return
+ }
+
+ i4, err := client.Run(appbuilder.AppBuilderClientRunRequest{
+ ConversationID: conversationID,
+ AppID: appID,
+ Query: "北京的",
+ Stream: true,
+ Action: appbuilder.NewResumeAction(interruptStack[len(interruptStack)-1]),
+ })
+ if err != nil {
+ fmt.Println("run failed:", err)
+ return
+ }
+ for answer, err := i4.Next(); err == nil; answer, err = i4.Next() {
+ for _, ev := range answer.Events {
+ if ev.ContentType == appbuilder.TextContentType {
+ detail := ev.Detail.(appbuilder.TextDetail)
+ text := detail.Text
+ fmt.Println(text)
+ break
+ }
+ }
+ }
+}
+
+```
+
diff --git a/go/appbuilder/app_builder_client_test.go b/go/appbuilder/app_builder_client_test.go
index e6b817566..28141b9e1 100644
--- a/go/appbuilder/app_builder_client_test.go
+++ b/go/appbuilder/app_builder_client_test.go
@@ -648,58 +648,117 @@ func TestAppBuilderClientRunChatflow(t *testing.T) {
}
var interruptId string
+ interruptStack := make([]string, 0)
for answer, err := i.Next(); err == nil; answer, err = i.Next() {
for _, ev := range answer.Events {
+ if ev.ContentType == PublishMessageContentType {
+ detail := ev.Detail.(PublishMessageDetail)
+ message := detail.Message
+ fmt.Println(message)
+ break
+ }
if ev.ContentType == ChatflowInterruptContentType {
- if ev.EventType != ChatflowEventType {
- t.Logf("%s========== FAIL: %s ==========%s", "\033[31m", t.Name(), "\033[0m")
- t.Fatalf("event type error:%v", err)
- }
-
deatil := ev.Detail.(ChatflowInterruptDetail)
interruptId = deatil.InterruptEventID
+ interruptStack = append(interruptStack, interruptId)
break
}
}
}
-
if len(interruptId) == 0 {
t.Logf("%s========== FAIL: %s ==========%s", "\033[31m", t.Name(), "\033[0m")
t.Fatalf("interrupt id is empty")
}
+ interruptId = ""
i2, err := client.Run(AppBuilderClientRunRequest{
ConversationID: conversationID,
AppID: appID,
Query: "我先查个航班动态",
Stream: true,
- Action: NewResumeAction(interruptId),
+ Action: NewResumeAction(interruptStack[len(interruptStack)-1]),
})
if err != nil {
t.Logf("%s========== FAIL: %s ==========%s", "\033[31m", t.Name(), "\033[0m")
t.Fatalf("run failed:%v", err)
}
-
- var message string
+ interruptStack = interruptStack[:len(interruptStack)-1]
for answer, err := i2.Next(); err == nil; answer, err = i2.Next() {
for _, ev := range answer.Events {
if ev.ContentType == PublishMessageContentType {
- if ev.EventType != ChatflowEventType {
- t.Logf("%s========== FAIL: %s ==========%s", "\033[31m", t.Name(), "\033[0m")
- t.Fatalf("event type error:%v", err)
- }
-
detail := ev.Detail.(PublishMessageDetail)
- message = detail.Message
+ message := detail.Message
+ fmt.Println(message)
+ break
+ }
+ if ev.ContentType == ChatflowInterruptContentType {
+ deatil := ev.Detail.(ChatflowInterruptDetail)
+ interruptId = deatil.InterruptEventID
+ interruptStack = append(interruptStack, interruptId)
+ break
+ }
+ }
+ }
+ if len(interruptId) == 0 {
+ t.Logf("%s========== FAIL: %s ==========%s", "\033[31m", t.Name(), "\033[0m")
+ t.Fatalf("interrupt id is empty")
+ }
+
+ interruptId = ""
+ i3, err := client.Run(AppBuilderClientRunRequest{
+ ConversationID: conversationID,
+ AppID: appID,
+ Query: "CA1234",
+ Stream: true,
+ Action: NewResumeAction(interruptStack[len(interruptStack)-1]),
+ })
+ if err != nil {
+ t.Logf("%s========== FAIL: %s ==========%s", "\033[31m", t.Name(), "\033[0m")
+ t.Fatalf("run failed:%v", err)
+ }
+ interruptStack = interruptStack[:len(interruptStack)-1]
+ for answer, err := i3.Next(); err == nil; answer, err = i3.Next() {
+ for _, ev := range answer.Events {
+ if ev.ContentType == TextContentType {
+ detail := ev.Detail.(TextDetail)
+ text := detail.Text
+ fmt.Println(text)
+ break
+ }
+ if ev.ContentType == ChatflowInterruptContentType {
+ deatil := ev.Detail.(ChatflowInterruptDetail)
+ interruptId = deatil.InterruptEventID
+ interruptStack = append(interruptStack, interruptId)
break
}
}
}
- if len(message) == 0 {
+ if len(interruptId) == 0 {
+ t.Logf("%s========== FAIL: %s ==========%s", "\033[31m", t.Name(), "\033[0m")
+ t.Fatalf("interrupt id is empty")
+ }
+
+ i4, err := client.Run(AppBuilderClientRunRequest{
+ ConversationID: conversationID,
+ AppID: appID,
+ Query: "北京的",
+ Stream: true,
+ Action: NewResumeAction(interruptStack[len(interruptStack)-1]),
+ })
+ if err != nil {
t.Logf("%s========== FAIL: %s ==========%s", "\033[31m", t.Name(), "\033[0m")
- t.Fatalf("message is empty")
+ t.Fatalf("run failed:%v", err)
+ }
+ for answer, err := i4.Next(); err == nil; answer, err = i4.Next() {
+ for _, ev := range answer.Events {
+ if ev.ContentType == TextContentType {
+ detail := ev.Detail.(TextDetail)
+ text := detail.Text
+ fmt.Println(text)
+ break
+ }
+ }
}
- fmt.Println(message)
// 如果测试失败,则输出缓冲区中的日志
if t.Failed() {
diff --git a/java/src/main/java/com/baidubce/appbuilder/model/appbuilderclient/EventContent.java b/java/src/main/java/com/baidubce/appbuilder/model/appbuilderclient/EventContent.java
index 4c6a672af..1d0879177 100644
--- a/java/src/main/java/com/baidubce/appbuilder/model/appbuilderclient/EventContent.java
+++ b/java/src/main/java/com/baidubce/appbuilder/model/appbuilderclient/EventContent.java
@@ -15,6 +15,7 @@ public class EventContent {
public static final String StatusContentType = "status";
public static final String ChatflowInterruptContentType = "chatflow_interrupt";
public static final String PublishMessageContentType = "publish_message";
+ public static final String MultipleDialogEventContentType = "multiple_dialog_event";
@SerializedName("event_code")
private String eventCode;
diff --git a/java/src/test/java/com/baidubce/appbuilder/AppBuilderClientTest.java b/java/src/test/java/com/baidubce/appbuilder/AppBuilderClientTest.java
index cb33dc655..61376b2b3 100644
--- a/java/src/test/java/com/baidubce/appbuilder/AppBuilderClientTest.java
+++ b/java/src/test/java/com/baidubce/appbuilder/AppBuilderClientTest.java
@@ -9,6 +9,8 @@
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
+import java.util.Stack;
+
import com.baidubce.appbuilder.model.appbuilderclient.AppBuilderClientIterator;
import com.baidubce.appbuilder.model.appbuilderclient.AppBuilderClientResult;
import com.baidubce.appbuilder.model.appbuilderclient.AppListRequest;
@@ -133,33 +135,91 @@ public void AppBuilderClientRunChatflowTest() throws IOException, AppBuilderServ
AppBuilderClientRunRequest request = new AppBuilderClientRunRequest(chatflowAppId, conversationId, "查天气", true);
AppBuilderClientIterator itor = builder.run(request);
assertTrue(itor.hasNext());
+ Stack interruptStack = new Stack();
String interruptEventId = "";
while (itor.hasNext()) {
AppBuilderClientResult result = itor.next();
for (Event event : result.getEvents()) {
- System.out.println(event.getContentType());
+ if (event.getContentType().equals(EventContent.PublishMessageContentType)) {
+ String message = event.getDetail().get("message").toString();
+ System.out.println(message);
+ }
if (event.getContentType().equals(EventContent.ChatflowInterruptContentType)) {
assertEquals(event.getEventType(), Event.ChatflowEventType);
interruptEventId = event.getDetail().get("interrupt_event_id").toString();
+ interruptStack.push(interruptEventId);
+ break;
}
}
}
-
assert interruptEventId != null && !interruptEventId.isEmpty();
+
+ interruptEventId = "";
AppBuilderClientRunRequest request2 = new AppBuilderClientRunRequest(chatflowAppId, conversationId, "我先查个航班动态",
true);
- request2.setAction(AppBuilderClientRunRequest.Action.createAction(interruptEventId));
+ request2.setAction(AppBuilderClientRunRequest.Action.createAction(interruptStack.pop()));
AppBuilderClientIterator itor2 = builder.run(request2);
assertTrue(itor2.hasNext());
- String message = "";
while (itor2.hasNext()) {
AppBuilderClientResult result2 = itor2.next();
for (Event event : result2.getEvents()) {
if (event.getContentType().equals(EventContent.PublishMessageContentType)) {
- message = event.getDetail().get("message").toString();
+ String message = event.getDetail().get("message").toString();
+ System.out.println(message);
+ }
+ if (event.getContentType().equals(EventContent.ChatflowInterruptContentType)) {
+ assertEquals(event.getEventType(), Event.ChatflowEventType);
+ interruptEventId = event.getDetail().get("interrupt_event_id").toString();
+ interruptStack.push(interruptEventId);
+ break;
+ }
+ }
+ }
+ assert interruptEventId != null && !interruptEventId.isEmpty();
+
+ interruptEventId = "";
+ AppBuilderClientRunRequest request3 = new AppBuilderClientRunRequest(chatflowAppId, conversationId, "CA1234",
+ true);
+ request3.setAction(AppBuilderClientRunRequest.Action.createAction(interruptStack.pop()));
+ AppBuilderClientIterator itor3 = builder.run(request3);
+ assertTrue(itor3.hasNext());
+ while (itor3.hasNext()) {
+ AppBuilderClientResult result3 = itor3.next();
+ for (Event event : result3.getEvents()) {
+ if (event.getContentType().equals(EventContent.TextContentType)) {
+ String text = event.getDetail().get("text").toString();
+ System.out.println(text);
+ }
+ if (event.getContentType().equals(EventContent.ChatflowInterruptContentType)) {
+ assertEquals(event.getEventType(), Event.ChatflowEventType);
+ interruptEventId = event.getDetail().get("interrupt_event_id").toString();
+ interruptStack.push(interruptEventId);
+ break;
+ }
+ }
+ }
+ assert interruptEventId != null && !interruptEventId.isEmpty();
+
+ boolean hasMultipleContentType = false;
+ AppBuilderClientRunRequest request4 = new AppBuilderClientRunRequest(chatflowAppId, conversationId, "北京的",
+ true);
+ request4.setAction(AppBuilderClientRunRequest.Action.createAction(interruptStack.pop()));
+ AppBuilderClientIterator itor4 = builder.run(request4);
+ assertTrue(itor4.hasNext());
+ while (itor4.hasNext()) {
+ AppBuilderClientResult result4 = itor4.next();
+ for (Event event : result4.getEvents()) {
+ if (event.getContentType().equals(EventContent.TextContentType)) {
+ String text = event.getDetail().get("text").toString();
+ System.out.println(text);
+ }
+ if (event.getContentType().equals(EventContent.MultipleDialogEventContentType)) {
+ assertEquals(event.getEventType(), Event.ChatflowEventType);
+ hasMultipleContentType = true;
+ break;
}
}
}
- assert message != null && !message.isEmpty();
+ assertTrue(hasMultipleContentType);
}
}