From d7c816b991a073d2f1132084b9cd6fa36073d558 Mon Sep 17 00:00:00 2001 From: userpj Date: Mon, 23 Dec 2024 21:01:58 +0800 Subject: [PATCH] =?UTF-8?q?Agent=20cookbook=E5=A2=9E=E5=8A=A0=E5=BC=82?= =?UTF-8?q?=E6=AD=A5=E8=B0=83=E7=94=A8=E5=86=85=E5=AE=B9(appbuilder=5Fclie?= =?UTF-8?q?nt=E3=80=81chatflow=E3=80=81tool=5Fcall)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agent/appbuilder_client.ipynb | 58 ++++++++- .../end2end_application/agent/chatflow.ipynb | 97 +++++++++++++++ .../end2end_application/agent/tool_call.ipynb | 110 +++++++++++++++++- 3 files changed, 263 insertions(+), 2 deletions(-) diff --git a/cookbooks/end2end_application/agent/appbuilder_client.ipynb b/cookbooks/end2end_application/agent/appbuilder_client.ipynb index 10f10fc5c..22fad2c37 100644 --- a/cookbooks/end2end_application/agent/appbuilder_client.ipynb +++ b/cookbooks/end2end_application/agent/appbuilder_client.ipynb @@ -15,7 +15,7 @@ "1. 在[百度智能云千帆AppBuilder官网](https://cloud.baidu.com/product/AppBuilder)创建并发布应用、获取应用ID、获取密钥\n", "2. 引用AppBuilderSDK代码,初始化AppBuilderClient实例、创建会话、上传文档(可选)、执行对话\n", "\n", - "以下分别提供三个样例,快递查询小助手、植物识别小助手、篮球教练来说明使用流程,注意以下流程用到的密钥可在图示位置中获取:\n", + "以下分别提供三个样例,快递查询小助手、植物识别小助手、篮球教练来说明使用流程,并提供了一个异步调用示例加速调用流程。注意以下流程用到的密钥可在图示位置中获取:\n", "\"drawing\"\n", "\n", "\n", @@ -179,6 +179,62 @@ "msg = builder.run(conversation_id, \"突破技巧中如何运用胯下变向?\", )\n", "print(\"篮球教练回答内容:\", msg.content.answer)" ] + }, + { + "cell_type": "markdown", + "id": "7acaf6bb", + "metadata": {}, + "source": [ + "## 4. 使用异步调用加速AppBuilderClient并发执行\n", + "SDK提供异步调用工作流Agent的接口。下面以3章节的“篮球教练”为例,演示如何使用异步调用加速AppBuilderClient并发执行。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fa87ffcb", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import appbuilder\n", + "import asyncio\n", + "\n", + "# 注意以下示例正确运行依赖的条件包括:\n", + "# 1. 在百度智能云千帆AppBuilder官网使用AppBuilderClient创建应用且应用已发布\n", + "# 2. 密钥正确有效\n", + "# 3. 密钥需要与发布的应用正确对应,即需要使用发布应用的账户下的密钥\n", + "\n", + "# 配置密钥与应用ID\n", + "os.environ[\"APPBUILDER_TOKEN\"] = \"...\"\n", + "app_id = \"4316a7cb-b6b2-4448-b6fa-ff131c484ec9\"\n", + "\n", + "async def agent_run(client, conversation_id, text):\n", + " ans = await client.run(conversation_id, text, stream=True)\n", + " async for data in ans.content:\n", + " print(data)\n", + "\n", + "\n", + "async def agent_sample():\n", + " client = appbuilder.AsyncAppBuilderClient(app_id)\n", + " conversation_id = await client.create_conversation()\n", + " file_id = await client.upload_local_file(\n", + " conversation_id, \"./python/tests/data/qa_appbuilder_client_demo.pdf\"\n", + " )\n", + " print(\"file_id is {}\".format(file_id))\n", + " task1 = asyncio.create_task(\n", + " agent_run(client, conversation_id, \"篮球技巧中如何三步上篮?\")\n", + " )\n", + " task2 = asyncio.create_task(\n", + " agent_run(client, conversation_id, \"突破技巧中如何运用胯下变向?\")\n", + " )\n", + " await asyncio.gather(task1, task2)\n", + " await client.http_client.session.close()\n", + "\n", + "if __name__ == \"__main__\":\n", + " loop = asyncio.get_event_loop()\n", + " loop.run_until_complete(agent_sample())" + ] } ], "metadata": { diff --git a/cookbooks/end2end_application/agent/chatflow.ipynb b/cookbooks/end2end_application/agent/chatflow.ipynb index c0d022d3d..0a7bb6d55 100644 --- a/cookbooks/end2end_application/agent/chatflow.ipynb +++ b/cookbooks/end2end_application/agent/chatflow.ipynb @@ -312,6 +312,103 @@ " main()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 2.3.4 异步调用工作流Agent\n", + "SDK提供异步调用工作流Agent的接口,下面是一个异步调用工作流Agent的实例。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Copyright (c) 2024 Baidu, Inc. All Rights Reserved.\n", + "#\n", + "# Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# http://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License.\n", + "import os\n", + "import asyncio\n", + "import appbuilder\n", + "from appbuilder.core.console.appbuilder_client.async_event_handler import (\n", + " AsyncAppBuilderEventHandler,\n", + ")\n", + "\n", + "class MyEventHandler(AsyncAppBuilderEventHandler):\n", + " def __init__(self):\n", + " super().__init__()\n", + " self.interrupt_ids = []\n", + "\n", + " async 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", + " async def run(self, query=None):\n", + " await super().new_dialog(\n", + " query=query,\n", + " action=self._create_action(),\n", + " )\n", + "\n", + " def gen_action(self):\n", + " while True:\n", + " yield self._create_action()\n", + "\n", + "\n", + "async def agent_run():\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", + " client = appbuilder.AsyncAppBuilderClient(app_id)\n", + " conversation_id = await client.create_conversation()\n", + " event_handler = MyEventHandler()\n", + " queries = [\"查天气\", \"查航班\", \"CA1234\", \"北京的\"]\n", + " event_handler = client.run_multiple_dialog_with_handler(\n", + " conversation_id=conversation_id,\n", + " queries=queries,\n", + " event_handler=event_handler,\n", + " stream=False,\n", + " actions=event_handler.gen_action(),\n", + " )\n", + " async for data in event_handler:\n", + " async for answer in data:\n", + " print(answer)\n", + "\n", + " await client.http_client.session.close()\n", + "\n", + "if __name__ == \"__main__\":\n", + " loop = asyncio.get_event_loop()\n", + " loop.run_until_complete(agent_run())" + ] + }, { "cell_type": "markdown", "metadata": {}, diff --git a/cookbooks/end2end_application/agent/tool_call.ipynb b/cookbooks/end2end_application/agent/tool_call.ipynb index 6cdcaf186..1b92432c7 100644 --- a/cookbooks/end2end_application/agent/tool_call.ipynb +++ b/cookbooks/end2end_application/agent/tool_call.ipynb @@ -1147,7 +1147,115 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# 6、项目总结\n", + "# 6 使用异步调用优化toolcall并发执行效率\n", + "SDK提供了异步调用接口,可以大幅提升并发执行效率。" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Copyright (c) 2024 Baidu, Inc. All Rights Reserved.\n", + "#\n", + "# Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# http://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License.\n", + "\n", + "import appbuilder\n", + "import asyncio\n", + "from appbuilder.core.console.appbuilder_client.async_event_handler import (\n", + " AsyncAppBuilderEventHandler,\n", + ")\n", + "\n", + "\n", + "class MyEventHandler(AsyncAppBuilderEventHandler):\n", + " def get_current_weather(self, location=None, unit=\"摄氏度\"):\n", + " return \"{} 的温度是 {} {}\".format(location, 20, unit)\n", + "\n", + " async def interrupt(self, run_context, run_response):\n", + " thought = run_context.current_thought\n", + " # 绿色打印\n", + " print(\"\\033[1;32m\", \"-> Agent 中间思考: \", thought, \"\\033[0m\")\n", + "\n", + " tool_output = []\n", + " for tool_call in run_context.current_tool_calls:\n", + " tool_call_id = tool_call.id\n", + " tool_res = self.get_current_weather(**tool_call.function.arguments)\n", + " # 蓝色打印\n", + " print(\"\\033[1;34m\", \"-> 本地ToolCallId: \", tool_call_id, \"\\033[0m\")\n", + " print(\"\\033[1;34m\", \"-> ToolCall结果: \", tool_res, \"\\033[0m\\n\")\n", + " tool_output.append({\"tool_call_id\": tool_call_id, \"output\": tool_res})\n", + " return tool_output\n", + "\n", + " async def success(self, run_context, run_response):\n", + " print(\"\\n\\033[1;31m\", \"-> Agent 非流式回答: \", run_response.answer, \"\\033[0m\")\n", + "\n", + "\n", + "def main():\n", + " app_id = \"b2a972c5-e082-46e5-b313-acbf51792422\"\n", + " tools = [\n", + " {\n", + " \"type\": \"function\",\n", + " \"function\": {\n", + " \"name\": \"get_current_weather\",\n", + " \"description\": \"仅支持中国城市的天气查询,参数location为中国城市名称,其他国家城市不支持天气查询\",\n", + " \"parameters\": {\n", + " \"type\": \"object\",\n", + " \"properties\": {\n", + " \"location\": {\n", + " \"type\": \"string\",\n", + " \"description\": \"城市名,举例:北京\",\n", + " },\n", + " \"unit\": {\"type\": \"string\", \"enum\": [\"摄氏度\", \"华氏度\"]},\n", + " },\n", + " \"required\": [\"location\", \"unit\"],\n", + " },\n", + " },\n", + " }\n", + " ]\n", + "\n", + " appbuilder.logger.setLoglevel(\"ERROR\")\n", + "\n", + " async def agent_run(client, query):\n", + " conversation_id = await client.create_conversation()\n", + " with await client.run_with_handler(\n", + " conversation_id=conversation_id,\n", + " query=query,\n", + " tools=tools,\n", + " event_handler=MyEventHandler(),\n", + " ) as run:\n", + " await run.until_done()\n", + "\n", + " async def agent_handle():\n", + " client = appbuilder.AsyncAppBuilderClient(app_id)\n", + " task1 = asyncio.create_task(agent_run(client, \"北京的天气怎么样\"))\n", + " task2 = asyncio.create_task(agent_run(client, \"上海的天气怎么样\"))\n", + " await asyncio.gather(task1, task2)\n", + " await client.http_client.session.close()\n", + "\n", + " loop = asyncio.get_event_loop()\n", + " loop.run_until_complete(agent_handle())\n", + "\n", + "\n", + "if __name__ == \"__main__\":\n", + " main()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 7、项目总结\n", "\n", "本项目通过多个知识点的学习,以及两个使用AppBuilder-SDK的实操,最终完成了一个支持ToolCall AIAgent的构建。\n", "\n",