commit a7840cea657bd4dd1caddbc90253c9db0051fe2a
Author: kyo <12390900721cs@example.com>
Date: Tue Oct 15 17:17:28 2024 +0800
上传文件至 /
diff --git a/function call作业基础版.ipynb b/function call作业基础版.ipynb
new file mode 100644
index 0000000..22982b5
--- /dev/null
+++ b/function call作业基础版.ipynb
@@ -0,0 +1,272 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "b646cf4a-18a8-4eb0-882e-4f087b779ffe",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import json\n",
+ "os.environ['http_proxy'] = 'http://10.10.9.50:3000'\n",
+ "os.environ['https_proxy'] = 'http://10.10.9.50:3000'\n",
+ "os.environ['no_proxy'] = 'localhost,127.0.0.1'"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8bb7790a-b2c5-46ac-a283-491529b2c0e5",
+ "metadata": {},
+ "source": [
+ "## 1.描述外部函数"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "72f06bfc-67d2-4c7b-a394-ffb6df2c5d9b",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "tools = [\n",
+ " {\n",
+ " \"type\": \"function\",\n",
+ " \"function\": {\n",
+ " \"name\": \"get_weather_info\",\n",
+ " \"description\": \"Get the weather information of a city\",\n",
+ " \"parameters\": {\n",
+ " \"type\": \"object\",\n",
+ " \"properties\": {\n",
+ " \"city\": {\n",
+ " \"type\": \"string\",\n",
+ " \"description\": \"The name of the city, e.g. Shanghai\",\n",
+ " },\n",
+ " },\n",
+ " \"required\": [\"city\"],\n",
+ " },\n",
+ " }\n",
+ " }\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "48d76891-be79-4b3a-ae4d-9a4fd1f8b4c0",
+ "metadata": {},
+ "source": [
+ "#### 初始化ZhipuAI"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "e868149d-e207-4fa0-be87-2bd834778dfa",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from zhipuai import ZhipuAI\n",
+ "client = ZhipuAI(api_key=\"cc28e0d694973a7276d02d6822e5958c.5h0H2TcNId2qBGBi\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10b89c40-9e78-4aaf-900c-4501101a4bd9",
+ "metadata": {},
+ "source": [
+ "## 2. 与模型交互,触发模型对函数的调用"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "47b1fdaf-c013-42d2-b57b-51acc5c4bfed",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'content': None, 'role': 'assistant', 'tool_calls': [{'id': 'call_9106863387107282637', 'function': {'arguments': '{\"city\": \"Beijing\"}', 'name': 'get_weather_info'}, 'type': 'function', 'index': 0}]}\n"
+ ]
+ }
+ ],
+ "source": [
+ "query = \"What is the weather like in Beijing?\"\n",
+ "messages=[{\"role\": \"user\", \"content\": query}]\n",
+ "response = client.chat.completions.create(\n",
+ " model=\"GLM-4-Plus\",\n",
+ " messages=messages,\n",
+ " tools=tools,\n",
+ " #这个地方我注释掉了,因为默认就是auto。\n",
+ " #tool_choice=\"auto\", \n",
+ " )\n",
+ "message = response.dict()[\"choices\"][0][\"message\"]\n",
+ "print(message)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6837d5b3-568c-4c2b-b3e3-29e55a1edc6b",
+ "metadata": {},
+ "source": [
+ "## 3. 使用模型生成的参数调用函数"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "90c428ef-6e79-42b3-b6fd-5e135a0aef3c",
+ "metadata": {},
+ "source": [
+ "### 3.1 先实现函数"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "2e292953-6420-4120-aaba-88c0daca7030",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import requests\n",
+ "\n",
+ "def get_weather_info(city=\"Beijing\"):\n",
+ " return {\"weather in beijing\": \"sunny\"}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "14ee8b16-0a31-45b9-b86a-b9fd3e50b381",
+ "metadata": {},
+ "source": [
+ "### 3.2 定义处理 Function call 的函数:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "51b83a05-efeb-4532-849c-19e0f1c3fe65",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def parse_function_call(model_response,messages):\n",
+ " # 处理函数调用结果,根据模型返回参数,调用对应的函数。\n",
+ " # 调用函数返回结果后构造tool message,再次调用模型,将函数结果输入模型\n",
+ " # 模型会将函数调用结果以自然语言格式返回给用户。\n",
+ " if model_response.choices[0].message.tool_calls:\n",
+ " tool_call = model_response.choices[0].message.tool_calls[0]\n",
+ " args = tool_call.function.arguments\n",
+ " function_result = {}\n",
+ " if tool_call.function.name == \"get_weather_info\":\n",
+ " function_result = get_weather_info(**json.loads(args))\n",
+ " messages.append({\n",
+ " \"role\": \"tool\",\n",
+ " \"content\": f\"{json.dumps(function_result)}\",\n",
+ " \"tool_call_id\":tool_call.id\n",
+ " })\n",
+ " response = client.chat.completions.create(\n",
+ " model=\"glm-4\", # 填写需要调用的模型名称\n",
+ " messages=messages,\n",
+ " tools=tools,\n",
+ " )\n",
+ " print(response.choices[0].message)\n",
+ " messages.append(response.choices[0].message.model_dump())"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "a3183e74-944d-4596-91b3-4caadbdf5718",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CompletionMessage(content=None, role='assistant', tool_calls=[CompletionMessageToolCall(id='call_9106863215308436029', function=Function(arguments='{\"city\":\"Beijing\"}', name='get_weather_info'), type='function', index=0)])\n",
+ "CompletionMessage(content='According to the weather information API, the weather in Beijing is currently sunny.', role='assistant', tool_calls=None)\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 清空对话\n",
+ "messages = []\n",
+ " \n",
+ "messages.append({\"role\": \"user\", \"content\": \"What is the weather like in Beijing?\"})\n",
+ " \n",
+ "response = client.chat.completions.create(\n",
+ " model=\"glm-4\", # 填写需要调用的模型名称\n",
+ " messages=messages,\n",
+ " tools=tools,\n",
+ ")\n",
+ "print(response.choices[0].message)\n",
+ "messages.append(response.choices[0].message.model_dump())\n",
+ " \n",
+ "parse_function_call(response,messages)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "04d00aae-254f-4120-b657-b493d3a4f410",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{'content': None,\n",
+ " 'role': 'assistant',\n",
+ " 'tool_calls': [{'id': 'call_9106863215308436029',\n",
+ " 'function': {'arguments': '{\"city\":\"Beijing\"}', 'name': 'get_weather_info'},\n",
+ " 'type': 'function',\n",
+ " 'index': 0}]}"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "response.choices[0].message.model_dump()"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "87c09ed4-b719-4fd9-a151-6f0ffd93aed9",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "c9ab6bb0-1ebf-4358-ba09-12950bd4d107",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "python3.10(base)",
+ "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.10.8"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/说明文档.ipynb b/说明文档.ipynb
new file mode 100644
index 0000000..813b7f2
--- /dev/null
+++ b/说明文档.ipynb
@@ -0,0 +1,468 @@
+{
+ "cells": [
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "85d95a29-ba5b-4826-a332-9e6a65f6d26f",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import os\n",
+ "import json\n",
+ "os.environ['http_proxy'] = 'http://10.10.9.50:3000'\n",
+ "os.environ['https_proxy'] = 'http://10.10.9.50:3000'\n",
+ "os.environ['no_proxy'] = 'localhost,127.0.0.1'"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ea48874f-d8ec-4b97-90d8-da3a100e68ff",
+ "metadata": {},
+ "source": [
+ "本教程包括以下3个部分:\n",
+ "\n",
+ "1. 如何使用 Chat Completion 接口向模型描述外部函数。
\n",
+ "2. 如何与模型交互,触发模型对函数的调用。
\n",
+ "3. 如何使用模型生成的结果调用外部函数。"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a3517065-57e0-4484-8d5e-8b9032ac872b",
+ "metadata": {},
+ "source": [
+ "· tools 是内容生成 API 中的可选参数,用于向模型提供函数定义。
\n",
+ "· 通过此参数,模型能够生成符合用户所提供规范的函数参数。
\n",
+ "· 请注意,API 实际上不会执行任何函数调用,仅返回调用函数所需要的参数。开发者可以利用模型输出的参数在应用中执行函数调用。"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d1da160e-02f1-4915-8432-0a1adc760ca1",
+ "metadata": {},
+ "source": [
+ "## 1. 如何描述外部函数\n",
+ "假设我们要创建一个具备查询航班功能的聊天机器人。我们定义如下两个外部函数供模型选择调用:\n",
+ "\n",
+ "· 查询两地之间某日航班号函数:get_flight_number(departure: str, destination: str, date: str)
\n",
+ "· 查询某航班某日票价函数:get_ticket_price(flight_number: str, date: str)"
+ ]
+ },
+ {
+ "attachments": {
+ "2d8136c7-fd31-43b7-91df-45439311b27b.png": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAAAy0AAAD+CAIAAAC4MH1NAAAgAElEQVR4Ae2dwW4rOc6250q9zC10ju+ig4PkJrobznLw708jSDbfDTQa/SUG5kPvZzAb/yAlSqRKtE3FcSpVb2NwYlexKPERJb6lqmT+ccB/IAACIAACIAACIAACn0HgH5/RKNoEARAAARAAARAAARA4QIchCUAABEAABEAABEDgcwhAh30Od7QKAiAAAiAAAiAAAtBhyAEQAAEQAAEQAAEQ+BwC0GGfwx2tggAIgAAIgAAIgAB0GHIABEAABEAABEAABD6HAHTY53BHqyAAAiAAAiAAAiCQddjr6+vf+O8MAgsDtbBwzhhAY7Ly8A0LfAEBEAABEPhIAq+vr13RmXXY33///e///Bf/O0ngX//6v5M2X8hgYeFEya88/Cgu2IMACIAACAwT+Pvvv6HDLiA0F1a5FxZOdHqsPPwoLtiDAAiAAAgME4AOu4AI+/d//ruwyr2wcKLTY+XhR3HBHgRAAARAYJgAdBh0WIfAyoXIysMfXk1wIQiAAAiAQJQAdFhHhUQhYj9sgNicL4EOm/PooG8gAAIgsCQC0GHQYR0CKxciKw9/SQscYgEBEACBmROADuuokIExW1jlXlg40QFdefhRXLAHARAAARAYJgAdBh3WIbByIbLy8IdXE1wIAiAAAiAQJQAd1lEhUYh4P2yA2JwvgQ6b8+igbyAAAiCwJALQYdBhHQIrFyIrD39JCxxiAQEQAIGZE4AO66iQgTFbWOVeWDjRAV15+FFcsAcBEAABEBgmAB0GHdYhsHIhsvLwh1cTXAgCIAACIBAlAB3WUSFRiHg/bIDYnC+BDpvz6KBvIAACILAkAtBh0GEdAisXIisPf0kLHGIBARAAgZkT+EAd9scv3zbffvvjP//99+8/b77/MCD+/O0ne+rH95vvv//33//58X3z84//dJQBXf7nbz9tvv36p3NWrvrx/WazuUlNUx+apsXM9OfdB8OV+/eff/rlr9yHQoO78ccv3xgFhUn933A46t+ffvmrxCXcTjCJBhsOJ42y6qTtdhnTv3791oZjLfnsdMgsomk4BYg6dTSXjo74SPjFYc3SaQf++vVbSmA5JVNjOo7myJ+//WSYyOWlUfshTwE1HCWjFJ8L5ww8gwAIgAAIDBD4GB32+8+bzU3RGX/8+RcVBlNIRJxxHaolp603qlRQeeuX8NRQkSylXVZ1p3XbALXpJdHK/eOXbxROEqNKZHAF/fb9d5FoVF9L0f3xXWRokR0Vna3E0x6GjkTDIee//5zDaXtS+q9Gs9hQqpw3Rtbyj1++qYFmwUoJdkTnFS3Y60bpD38YCZ8u/PG9jCndNvz1B/W5aTfR4H9FhHG3G7PsreinH9/rhNKf//2f/xrVxbPMGhCT4ieUBjAGARAAARD4aAIX12FHCmGVYkUz6b2Q779Ptn+STPF3wqbyTpfnbiu6eF8Q7lDllt2RosNIa3brcTo4ex3mCOWJFmElVIX1zz9YuHtaoWrNItMnoIowVWN6VP9Z4aWuor4NjGY32SS9ZUxryOqO4vsP3uhVR4owLYmRpgBPh2mkVXWJsKtHKEzosNPKu0kAfAUBEACBqxG4uA6rS95EJFUZkcPj6qv2yZSBqkBc4X7+UbeFUhNUXaaiSukw5S0XXdqu8Ir9O4lHKjfvmriSRerxt9/+6JZtuvDnX+V5a9UoR4VFNLpIODLi5++HpXFPilMpqryv0+yb8n6PHTU7stlb4vbt1z+7eEUJnUdpJPzimfpjmrOqSLbNlI0yEGlevNGHbkSUBukJfr1c6TCRgDmdLEAZMtMKDoIACIAACHwCgYvqMFc3iLZg8ZHEExfdb7/+Qk8w05OpP375+af89ow8tUwvSJVdMa64sm3WPMzq7MNllSaSbrqREFUnR+xHKzfX3d9/++mbekzZVMeqb6r+KLHMS4e54lJ0SdJMWmkpHZbwiuxO+oNG2caY9Xej8gsQ9RhXptOkiSPjmE4FR7OTe40Moq8pjZnAT7/8Rk8w07P7P3/7/q08Y+3u4dVxrz1XQWX9muDjuWQzffAVBEAABOZN4KI6rIRatwS4hPzePm6rRTTdwWcBR8+nikqb7nVREcplTL8+JeWWW6e9gW/y+wGpP6LDag0r/bzch2DlzoHkV6NSTc0QWLNWpUI1XjYzOvXYahSD4j3xhsO5HMnabRGgKsYswshGCZH8Cw0ZWnf3SITgef0cDZ+aToPFe1Q/1Njx0Jh58fMPeZvt++8/vheVVh4+yv0JK8vmrsOE390PU9NHp9DFMqQO03lIYQ8CIAACINAlcHEdxlWQakkqh99+/fOvP/787x9/8gZAlRdUD9QehpSHrJmmgqNbXCfPXMrWAus58p+e7n37rffGtDR6iUISqNxJb2kUrVJM+yskHWqJpU5qLAXIpEJfOZwsicyWZ2c3iFRFfY7mGJATEZ38+jlTEh3GIStucrzJpcmWklVs3WnQHAyMptDO+7u8e5c2uv74869///nXr/Tbu1YFdvqTH0c6w13GuoFceWbVlZ9LKrVK3YMOu+RMb1IFX0EABEDgnQQuqsPodr+8oFOLBBddlgu8m7X5/sM8SUnPU9J+ANcMvaGlLG0xU/VPKvdfv37/jX4PMf89CKpedEpUTt2Ek2vfyU5fHqncXlm1VTYDaUrIRGR8QCxjL6prGlYyNiE04lKf1YpBhi+9H/YL/basjKxcIhtmVtN38faTx/ZZ3Ibf06cWf/qFfym46MiU6rnPqUv51xGsBs0ymu8Zvtk/y1Jkd/qQv+a7FyXmqnpTOsy2UtWtFzKOgwAIgAAIfAqBi+owpQmoWiSBJZsBtVqQma64tjBnMVeLInNx9UfZFElv6Jf39PNmmPpFMxYHH1WQIjqsCY13L+obQp2zQtIKNYv3stkzFI4e06kYqkrIZoKOV3lQGitpcVHbyb5Ik+y25Bs945OUy0yUZDmT0lD43DFqKw9T7rAKxOrF5i99ZDGneliE12/0Pr5EkXWYmmvqXoV/JZks9S6poqquUg3pIcBnEAABEACBqxK4vA6Timjqrn7eRAXgzx8//qTykBVGfdgk9bseSTgmxVUqStFhP75Ti1mH6VIk+2G5Cvb3md4LfbRyMwR5+qZ+ddTrj8vhsmV1JBwjoLOG6PbqLB2mxrdNHjqlOOSdJ7XhKkqo0a9WyXmE6fhI+KLAaiupYyaT//rxO/8N3omGFi1VZ03aU/z+Pf8h4iK/yocCwfKsGSXwocOOjbVQgg0IgAAIfA6By+uwsq5JafG2oLLk+v5d/ugr1y1+9sS1xAgm0We9ElsrX9FhUsWpM0qHlb5d/EO8cueI9LO2LGFN4E1aKP2hY7z053A4PHZ1KM2rbE0I/OJXbxyTbKqjmZTNt99+zf9fC8qP3WRqR5MvTGA5CfXmkHLiQwuHr11lXVj/Wl7TvTwvvv8sf/SVM4EHnROg9JaPk4zj6SCbfFWHUZhat1Fo7Lw5CB121qA3w4SvIAACIHAdAhfXYalm0EZXLai6SvHnaXW0FYjWTTpSFYmrP8p+WOJVnkvS11MV8YKIA5VbeuXyyQbffn2pD7marZ3mq+tqQv7MkAPhZM6l9tcEaDpZXle3+ze6RirFQBBEkQgx7bAbMmeR/IWIGnvqknirx3XT5nMsfHaYm9648qskpFbe/LTRvvdG6oq7mu8fihqTHiZ5moSs2WxLCV8GQuvdevDMBIAZCIAACIDAdQhcXIdJtTij2l0nwuu0MlC5r9OxsVYWFk4UwsrDj+KCPQiAAAiAwDAB6LDLCMeFVe6FhROdHisPP4oL9iAAAiAAAsMEoMOgwzoEVi5EVh7+8GqCC0EABEAABKIEoMM6KiQKcfA37Gb86HblQmTl4Q/kPy4BARAAARAYIwAdBh3WIbByIbLy8MeWElwFAiAAAiAwQAA6rKNCBjgurHIvLJzogK48/Cgu2IMACIAACAwTgA6DDusQWLkQWXn4w6sJLgQBEAABEIgSgA7rqJAoRLwfNkBszpdAh815dNA3EAABEFgSAegw6LAOgZULkZWHv6QFDrGAAAiAwMwJQId1VMjAmC2sci8snOiArjz8KC7YgwAIgAAIDBOADoMO6xBYuRBZefjDqwkuBAEQAAEQiBKADuuokChEvB82QGzOl0CHzXl00DcQAAEQWBIB6DDosA6BlQuRlYe/pAUOsYAACIDAzAmc0GGvr6//+tf/4X8nCfzv/y4K1MLCOTl8jcHKw29o4CsIgAAIgMDHEXh9fT30/vtHOujJtN4lqz62MFALCyeamisPP4oL9iAAAiAAAsMEvIoDHRZD6nGMeZmN9cLCiXJdefhRXLAHARAAARAYJuBVHOiwGFKPY8zLbKwXFk6U68rDj+KCPQiAAAiAwDABr+JAh8WQehxjXmZjvbBwolxXHn4UF+xBAARAAASGCXgVBzoshtTjGPMyG+uFhRPluvLwo7hgDwIgAAIgMEzAqzjQYTGkHseYl9lYLyycKNeVhx/FBXsQAAEQAIFhAl7FgQ6LIfU4xrzMxnph4US5rjz8KC7YgwAIgAAIDBPwKg50WAypxzHmZTbWCwsnynXl4UdxwR4EQAAEQGCYgFdxoMNiSD2OMS+zsV5YOFGuKw8/igv2IAACIAACwwS8igMdFkPqcYx5mY31wsKJcl15+FFcsAcBEAABEBgm4FUc6LAYUo9jzMtsrBcWTpTrysOP4oI9CIAACIDAMAGv4kCHxZB6HGNeZmO9sHCiXFcefhQX7EEABEAABIYJeBUHOiyG1OMY8zIb64WFE+W68vCjuGAPAiAAAiAwTMCrONBhMaQex5iX2ViPhPNyt9ncOP+7e55NaOd0JBz+fne72T7us++33dZyUOEfo5ToFT/7x235fHjbbW930sA5McAGBEAABEDgKxDwKg50WGz0PI6uF12P759cMznxfH+zOcNMzN/7MxzO4XB4udtsd2+dlp8eNkqIdAxmd2gkfCXFjGai4yr8SqnKLNJteXCfHpSeO3g+p8ByOqmGpjZjR1QfxhzgKhAAARAAgSMEvIozqMNURTnS6AJPeRy7oRIlJVmed0m+2BrcvfJaB0Ph5E5pZdlujH2APvhIFCPh1/7sH7c3Dy/yfarDWjjNJmLdAyMX+90tS7Tn+xt/P+zCmbPaWSxjhp8gAAIgcD0CXsWBDouNgcex68WpqReupt2mzzwYCif7rDs9TSPr2A+ToEnE6A2wRoeJWf65390qRd6c1F+dnGGT401oL+d9hg47jxOsQAAEQOACBLyCO6LD6NmZ3Os/vNhdgQN9pRv6VK3L3okpQk8Pcrl/63+BmD/Chcex21azH0Y2VEqFHjPhWrh73N5s+EFVLY0M8Lm8gaQfViqqZKBPdfvhHwyFk92U1ksg9cOi98Mk8JzeWoTx0PIg8jj+jxrlCkfGvR65e+b5UmaT90FaFA/3T5xIlXZNmwOr/JfSgWqjc+92t7ez+HBIF8qbaeRQ+lkmaWqlXFiO+/mFMyAAAiAAApmAV3BHdNjhQG8Tl/KvP9fykIqWSAT12hOJMHmaM6OdoTMzxePoXZ6Klq1YJmouePURVYXJAPOFrN4yNDouxTWpOoHs9eHI8Wg4R1x9xVMD4R/brzqC4B37YbVFvR+mP5v5yDc5+baHboryPCX7kmZPj/yrADXZqOc1LTknJcfoeJ6wfFwmL+VhcXgkcpwCARAAARAgAl7FuYAOa1fwJAuap1elbNjj5k3nrzBSHsejfedyWItWLXiNojVfLahSjMuH1KItpUd70TsZC4cGUbZkjn0oJbzX5JyOxcLnngv/NKYTGkoTJ9VSdpWaD3IrYnEYtZROUUPZuEyivLFaOas0MNlVfqlCum2aU1dpHaZaZPNiVj7w4dbMuMYXEAABEAABS8CrOBfRYQdZ5euvhpUCIN3ILw/RUt6UcFW6xHi+Pz2Op3tc97FMpbS1TW009nVYW/yay093w1qMh5P9mFis7y/wbSB8SXUtXFKkdd8ofT8yNM/3Iq0spLxtbNSYGvFxHaacqBZtD8tQlg9iKqlo7fs+5Rr8BAEQAAEQMAS8inMZHZZVl374Imt37kUpIS935YGm6eAX+eJxPKP7pbyVD3SRrW3qqwUo5Z+Kn37KqR74ntGFiclQOLoA81MwI6zrJs2ktdkdGAg/DcTbbkt7VEZbm3HJI2vImM2zzn5Y9Ub7XTLQKlvKJLrufhiFyTdLNld1GsxuZNEhEAABEJgbAa/iXEiHUdnY3pYHKOmvTMlrJaqopF2E/mbA3JB1++Nx7Bo/3ytRUqusqqxhHcZC7XPfD6NAyotBJpYuhDkfDI1mCiS98Ne+oldTvYZrVUs9fjjQ/nGrwwxVZexqL7X9RjbyHph6zYu8FDVv/L/j/bC6ew0dpoYJH0EABEDgFAGv4gzqMH4njO7vSzmhqlP0gRSAx/KblXX5tr8zWCv6qQjmcd7j2O0dMym7IFWT5eP19yXr33etxbtUUHYt+2H0RaTAzWa7u/bvS1I5v3m4p395W25tOkyJj6R+SAClX3ctSijnQh3KSXI0OowHtEhbY82pIpmjNZnc6tBTfpMGdkR0FvHYpbcCZNrm7Uz+ai7MKcr7eWKsNmupjwqF6TK+gAAIgAAIdAh4+mFYh7VttFVHF4DW9gt/9zh+Vkhanw30IRYOFXLRBMf+4EKxGejRVS+JhV+7luRLq5xEu9z9c/oSpPOA8uGFXem7lPzMscj3eqtT28cnEAABEACBr0bAqzgX0mF0p27LEnTYFVLEPGwaac9LixFfX/CalYf/BUcMXQYBEACBr0rAqzjv12H0eEI/oMyEoMM+KFXU0yX1ntZgY15aDLr7apetPPyvNlzoLwiAAAh8YQJexXm/DvvCUAa67nEccDWHSxYWThTpysOP4oI9CIAACIDAMAGv4kCHxZB6HGNeZmO9sHCiXFcefhQX7EEABEAABIYJeBUHOiyG1OMY8zIb64WFE+W68vCjuGAPAiAAAiAwTMCrONBhMaQex5iX2VgvLJwo15WHH8UFexAAARAAgWECXsWBDosh9TjGvMzGemHhRLmuPPwoLtiDAAiAAAgME/AqDnRYDKnHMeZlNtYLCyfKdeXhR3HBHgRAAARAYJiAV3Ggw2JIPY4xL7OxXlg4Ua4rDz+KC/YgAAIgAALDBLyKAx0WQ+pxjHmZjfXCwolyXXn4UVywBwEQAAEQGCbgVRzosBhSj2PMy2ysFxZOlOvKw4/igj0IgAAIgMAwAa/iQIfFkHocY15mY72wcKJcVx5+FBfsQQAEQAAEhgl4FQc6LIbU4xjzMhvrhYUT5bry8KO4YA8CIAACIDBMwKs40GExpB7HmJfZWC8snCjXlYcfxQV7EAABEACBYQJexck67PX19W/8dwaBhYFaWDhnDKAxWXn4hgW+gAAIgAAIfCSB19fXrobDflgXi3vQ07PuBfM+sbBworBXHn4UF+xBAARAAASGCXgVBzoshtTjGPMyG+uFhRPluvLwo7hgDwIgAAIgMEzAqzjQYTGkHseYl9lYLyycKNeVhx/FBXsQAAEQAIFhAl7FgQ6LIfU4xrzMxnph4US5rjz8KC7YgwAIgAAIDBPwKg50WAypxzHmZTbWCwsnynXl4UdxwR4EQAAEQGCYgFdxoMNiSD2OMS+zsV5YOFGuKw8/igv2IAACIAACwwS8igMdFkPqcYx5mY31wsKJcl15+FFcsAcBEAABEBgm4FUc6LAYUo9jzMtsrBcWTpTrysOP4oI9CIAACIDAMAGv4kCHxZB6HGNeZmO9sHCiXFcefhQX7EEABEAABIYJeBUHOiyG1OMY8zIb64WFE+W68vCjuGAPAiAAAiAwTMCrONBhMaQex5iX2VgvLJwo15WHH8UFexAAARAAgWECXsWBDosh9TjGvMzGemHhRLmuPPwoLtiDAAiAAAgME/AqDnRYDKnHMeZlNtYLCyfKdeXhR3HBHgRAAARAYJiAV3Ggw2JIPY4xL7OxHgnn5W6zuXH+d/c8m9DO6chI+Of4hQ0IgAAIgAAIWAJexRnXYc/3XIzvn2xDF/j2tttutru3C3i6vAuP45GWKJwqXIxSoVM9gFcjMBDO4eXOGZ2nh42J7giTmZwaCX8mXUc3QAAEQAAEvhQBr+KM6jC3GA9Seb6/ud3tBy++4mUeR68LrFaVOuHNpIeXbO7pMM/b0eNPD5vtYxBhNBzqAPbDjg4DToIACIAACIDAlIBXcAd12EUFBPV2mTqMJIsSYWlYlIS9KMYr6rD+biX2w6bzDkdAAARAAARAgAhcUoflJ5L8rO3h5WDFxP5xe5P2e9LxYmy2u9SeysMLXSJP7nhHRymVw+HpofNQL7VSToX3gYaTwuPYdeiIyyqYEiL6N8VYnlE6BDTDApak3n53Wyj1RVK3g25a9K3TUTV2Mmpl+Cai85ijzz8XGs3P7y56AAIgAAIg8GUJeBXnAvthx3TYJmsyfpglaknvEu13j/yQzkiWqkJIaRXxQQ1lkZGkW676pEgi4uM9g+hx7PmsktSerceTApMA6Xj+bAnIc8wq4ChkEW1vux2/HV/P2uaOfYuEc8zPFz238vC/6Kih2yAAAiDwFQl4FeeDdZhohcOhiI/ywWDs67AqR5JxkRrWCe0GXWknxuNogslfbCerRT1uJSy/epUEZQm8fODL33ZbEmr9eAuc2tLJT5FwDtxu2fo68uFKY3EyupMGsfBPuoMBCIAACIAACDgEvIpzfR3WlwtdHdbKFE/M9XWJQ+J9hz2OXa8mqGpRCbQB7ne3VoelDTPz+O/+yfmNxeq2NnXqUyicnrORRnt+PufYu8P/nG6jVRAAARAAgS9HwKs419dhdTdIQzSSpWwClQ/ZdP+4TQ83rZO56rC+YFJBtTqsnNIf6p6iAOvHOyKJvLSQlro/Nfzyil7ZHvsym2FH3prsho2DIAACIAACIDBMwCu4F9Bh/O5Xrr5p/0a/py89rsWbbaRav+P9MHlrKj0vE4fS3gf99Dh6zbXvrtG7cfKe3IF/xaF+JU2Tgyo6jH9NoUaamyGYn/Z+mAlhRPx5rK5/PDqa1+8hWgQBEAABEFgGAa/iXEKH8V+dSM/ObndPze9LCr6qww5Zf6QdFBEltMdzkzVKVSEH8/uS9WV84815X0pavuhPj+ORRuyzRaMXeT9sV35dVF7YVy+KHZq3sgQXP6LNzysFS25Ivh7pUjkVDod/WfLhnv6kPvcWOqywxAcQAAEQAAEQcAl4BXdQh7ntLP2Ex/GycbM+u/z/UcG0k7Fw9C+6aiFY/mRG/mC05rTR+RyJhT+ffqMnIAACIAACX42AV3Ggw2Ij6XGMeTlhbXf7Thi/6/RVwnlXDz/04pWH/6Fs4RwEQAAEQEAT8CoOdJimdPqzx/H0lWdZ8Itfm/ru11kXvcPog8N5R8+ucunKw78KYzQCAiAAAiBABLyKAx0Wyw+PY8zLbKwXFk6U68rDj+KCPQiAAAiAwDABr+JAh8WQehxjXmZjvbBwolxXHn4UF+xBAARAAASGCXgVBzoshtTjGPMyG+uFhRPluvLwo7hgDwIgAAIgMEzAqzjQYTGkHseYl9lYLyycKNeVhx/FBXsQAAEQAIFhAl7FgQ6LIfU4xrzMxnph4US5rjz8KC7YgwAIgAAIDBPwKg50WAypxzHmZTbWCwsnynXl4UdxwR4EQAAEQGCYgFdxoMNiSD2OMS+zsV5YOFGuKw8/igv2IAACIAACwwS8igMdFkPqcYx5mY31wsKJcl15+FFcsAcBEAABEBgm4FUc6LAYUo9jzMtsrBcWTpTrysOP4oI9CIAACIDAMAGv4kCHxZB6HGNeZmO9sHCiXFcefhQX7EEABEAABIYJeBUHOiyG1OMY8zIb64WFE+W68vCjuGAPAiAAAiAwTMCrONBhMaQex5iX2VgvLJwo15WHH8UFexAAARAAgWECXsXJOuz19fVv/HcGgYWBWlg4ZwygMVl5+IYFvoAACIAACHwkgdfX166Gw35YF4t70NOz7gXzPrGwcKKwVx5+FBfsQQAEQAAEhgl4FQc6LIbU4xjzMhvrhYUT5bry8KO4YA8CIAACIDBMwKs40GExpB7HmJfZWC8snCjXlYcfxQV7EAABEACBYQJexYEOiyH1OMa8zMZ6YeFEua48/Cgu2IMACIAACAwT8CoOdFgMqccx5mU21gsLJ8p15eFHccEeBEAABEBgmIBXcaDDYkg9jjEvs7FeWDhRrisPP4oL9iAAAiAAAsMEvIoDHRZD6nGMeZmN9cLCiXJdefhRXLAHARAAARAYJuBVHOiwGFKPY8zLbKwXFk6U68rDj+KCPQiAAAiAwDABr+JAh8WQehxjXmZjvbBwolxXHn4UF+xBAARAAASGCXgVBzoshtTjGPMyG+uFhRPluvLwo7hgDwIgAAIgMEzAqzjQYTGkHseYl9lYLyycKNeVhx/FBXsQAAEQAIFhAl7FgQ6LIfU4xrzMxnph4US5rjz8KC7YgwAIgAAIDBPwKg50WAypxzHmZTbWCwsnynXl4UdxwR4EQAAEQGCYgFdxoMNiSD2OMS+zsR4J5+Vus7lx/nf3PJvQzunIQPhvu60T+81mu3vLre4ft9vH/eFweHrYMJOXu8390+FweL6/eXjxurZ/3N7c7uiyY/9l/ux/v7tN/o9dgHMgAAIgAAKfT8CrONBhsbHxOLpetGrhSuxa8onn+5tUsI+bXepsOJzD4fBypwSH7ohoDn1s3p9Hwp9GlIa4irBkkWjwvyLCDof949aTqiTC+goveSbJxQaqoef7M3TbtMM4AgIgAAIgcHUCXsWBDosNhcex64X2TnTV3KX9kqeHTdos6V501YOhcHLPtLJsN8Y8kXHVoM5vLBp+0j1qT+vpYSO6eb+7vd89bnm7q2gmzef+6dAeL2ng7IQRaot0v7stGdV6a1Xa+RxgCQIgAAIg8NEEvIoDHWZfVxsAACAASURBVBYj73HsenG2K76+DitSwIS9/P0wHtCntxfemqLdTRlKEkzbxz3JKfXYkVWaElIqH8qDy0MSZw8v7SPLRsRn0kqHKW/55JU3U83g4wsIgAAIgMBRAp5+GNNhqd6kMnPDFUgaV5sl8qaLNabqRUf4EUzZDziog7LBIC5n9dPj2O1kp5TqPQxWM2TD+ygJI3+lF4nS47/n8jaSfqZZIG93ZKBPdfvhHwyFk92U1vVmT/5sN2/8dmdyJhq+kj5JgaV/i6hSOowp3e52tGG24aeH+93DdiuTQjQr5UOZBbK7xkkilhkVJUYDPKthaZ2u+mL8Z5IG6AYIgAAIXIGAV3HGdVh5YkJ34bJB8nwvlYDqUPqcVFf6nKRbLjzq9p1spPCoYnYFMMEmPI6eG4oxleFqIZsofITra6nEB6PDyoVcmPNGSwWbt1KurcNqIF/+08BoSpbS9hXLrO3DfXn6LKlbxyjprTQFbh5enh7STDn2jl2dTR2+dOFWSbd0A1Pzp3MJDoEACIAACMyAgFdxxnVYff7SvxEvakOKE1NQ2ku98d14qO81z4Cc7YLH0Vo131IZLsWykCGzKrz4ovrVluqyE1M+pDaqfdPmeV9j4bAcbHdlmk0a+ipa/Lw+fKJVLHz+bUfSYbzXtbl/etvv0qt+SW0/vJhU5weODYq8d9UMYvo9Shds3e/cP95v+f0w1nM0HOlh6PZxT3c4dUp+IlM0DQIgAAIg0CPgVZxL6zBTqpPyMMXpbVcezSgdlgqbruiywdaL5TOPeRxP98nskRRNFtVhBuZUxp3uhrUYDyf7MZrS+v4C36LhJ72lhKYKX3KYxJB8VtIqjzjpZr2hpSz7Kkrdk7zt7h5f6nv6cksjzyVrgn0B8ugiCIAACKyNgFdxLqrDzLZWKVFGOvR1mHr7eOYD43E8o9sFSPlAFzUbWvVrfz+MYJZHY3kfpe6XnNELazIUjh7Q8o5geuHvK22GHQ6HaPh1H6voJ3PDUMnUcZRX/eRPixExPYJpQNTvYNoRKjoszZEyU/JmmHkuKcrMesA3EAABEACBGRDwKs5FdZiWDlSozt4P4zf3p8VpBtzaLngcWzv+Xt+WS8U4P7B7jw5j3VYe/KXdxyvrsDqy6e+U1r29LoQ5HwyNZlK9R7O06LD988uepFje4q1PJyc7ahnPaR32ckcbZlmHaTku+2EkyfRb/3MGj76BAAiAwOoIeBXnojqs/iLkzeb+Tv5KVilOBL2/H0ZnzM5K/xnNDEbN49jtmqrEZqMoH+etFLNxorfHtKgtbyZxM1LL6YXua/++JO8DPdzTn9RnRWI0ZRfCnA+GRvPEW1zyVL2kbh4mmgjp1XvO8DLo9dckiVAdU/EjGs7++nDZD6tYlQ6rB/EJBEAABEBgXgS8ijOmw+YV2zV743G8Zh90W/VJmT569udYOCTCytYOyeuqFYx6KDZn9+OTDGPhn+6k3HKwWjU7Z7xzOTlStxJP74el1o0OK7cuXwb4aYSwAAEQAIGFEvAqDnRYbMA9jjEvl7I2jwhHnM4rnJEI3nXNysN/FztcDAIgAAIgECHgVRzosAjF+JvdMe/nWPNei2xE1Q2Vcy6d2nhpMbVc5JGVh7/IMUVQIAACIDBPAl7FgQ6LjZfHMeZlNtYLCyfKdeXhR3HBHgRAAARAYJiAV3Ggw2JIPY4xL7OxXlg4Ua4rDz+KC/YgAAIgAALDBLyKAx0WQ+pxjHmZjfXCwolyXXn4UVywBwEQAAEQGCbgVRzosBhSj2PMy2ysFxZOlOvKw4/igj0IgAAIgMAwAa/iQIfFkHocY15mY72wcKJcVx5+FBfsQQAEQAAEhgl4FQc6LIbU4xjzMhvrhYUT5bry8KO4YA8CIAACIDBMwKs40GExpB7HmJfZWC8snCjXlYcfxQV7EAABEACBYQJexYEOiyH1OMa8zMZ6YeFEua48/Cgu2IMACIAACAwT8CoOdFgMqccx5mU21gsLJ8p15eFHccEeBEAABEBgmIBXcaDDYkg9jjEvs7FeWDhRrisPP4oL9iAAAiAAAsMEvIoDHRZD6nGMeZmN9cLCiXJdefhRXLAHARAAARAYJuBVnKzDXl9f/8Z/ZxBYGKiFhXPGABqTlYdvWOALCIAACIDARxJ4fX3tajjsh3WxuAc9PeteMO8TCwsnCnvl4UdxwR4EQAAEQGCYgFdxoMNiSD2OMS+zsV5YOFGuKw8/igv2IAACIAACwwS8igMdFkPqcYx5mY31wsKJcl15+FFcsAcBEAABEBgm4FUc6LAYUo9jzMtsrBcWTpTrysOP4oI9CIAACIDAMAGv4kCHxZB6HGNeZmO9sHCiXFcefhQX7EEABEAABIYJeBUHOiyG1OMY8zIb64WFE+W68vCjuGAPAiAAAiAwTMCrONBhMaQex5iX2VgvLJwo15WHH8UFexAAARAAgWECXsWBDosh9TjGvMzGemHhRLmuPPwoLtiDAAiAAAgME/AqDnRYDKnHMeZlNtYLCyfKdeXhR3HBHgRAAARAYJiAV3Ggw2JIPY4xL7OxXlg4Ua4rDz+KC/YgAAIgAALDBLyKAx0WQ+pxjHmZjfXCwolyXXn4UVywBwEQAAEQGCbgVRzosBhSj2PMy2ysFxZOlOvKw4/igj0IgAAIgMAwAa/iQIfFkHocY15mY72wcKJcVx5+FBfsQQAEQAAEhgl4FQc6LIbU4xjzMhvrhYUT5bry8KO4YA8CIAACIDBMwKs40GExpB7HmJfZWI+E83K32dw4/7t7nk1o53QkHv7+cevFno8/vHDL+92tSylZVlbP9zf5Krr06WGzfdyzk5e7zf2TBLJ/3MpxOXQ4HJ7vb253+8PL3Wa7e1PH33ZbZ4xulGXx+fSw4f5Ii7ZLyq/5KFeZg+nL08NGB0X9LDHmPneuOnaIIqo0lEPpc7r4+b4zQA8vAupQQp60lYZMNWEsVCu9JurQvO22NCI8NN0hSGffdtsCJDdEHah+TOvpC0+9PNwqu7QfzflSuTTpyZFxr7aFQz2kPl0+P+sUoNw7Qv5AOdA3KFdppKXX1Gc7y8qp3oecaRxpnew9SxxbCwGv4lxEh6nKcSmeJ5ekSUO0OHpr6MR4+IDH0XWoVcsZ3btOFKW34XAOh2nJF29nrc5iPIuf8fCbKt5kPq3v3RWcK6K7FufaeUy6cXnuTYqkad72HSnWIk6p2BaSNGr8b5Ua+8et7a1OYypySS44I079TJdXgxxjURJt505/Fx12pIiKiNnvblOYtSendBh1jC6nCdgi4r5VOEoC5l6bNCj6w0qibFrOGpEk0UuM8p1/ciG32r1qjrYzl86lOoKqT92D6nz6yPnsTIeJcVpYNlP4qS3+tw7BJD+TPxrEu2d9J6PaUeSHZzGnxxnLODcrOuycuan6iY8LJuBVnLnqsLOGwix/Z13xbiOPY9cxLaBqTX/epR2LT+h2t3uHwyEUTnbSlmR9Z2mLt9fqbI7Hwx9ewZ3SpWHm9V2lRy08gmxypLu3lA4qHcA7BMn/fnd7v8t6kStl2QPIH+6fDu3xib7J3ekFpSPK2xKibzZyp6TkkQR2+mejUWp0EybU/4AOS8Kupi5vd0nIRR+ULZb7p9p05cD2htvdQ29nbrPh/ct0Ifecm9OTSH3mKJrA03ZO2lRLu25Z62jyl8sluu8qe6UFgvqge9LmkjJLp1JXPyo/m+E4HGomHA5hHWZGUw1KG9TdP4/sPRvjmmOn0x0WSyTgVRzosNhoexy7Xro1snsf3L38CgdD4eT+qHtx28NeVbYWc/sWD//IZkxeqZ0NgGNwJnX9BCe1QTIpD1yAOfGe3l742SgdEW1HNXX7uG/27dJznFokVN5a3Wn0zaRprTB0BKT8rHZxU0hfpj5rhbG5edh1n/myErKWVRZsd4/pAa59Lpk0UGfIUg1WN1FaDPWUU9Vtpd53h7WcVeGd+NgZ7iyz6EI5m4ev2+iRBuTyzmiWxws6dnKlZLQO52TTxeDi+SlRpFHgbE/JX2TQ/ZPqangWq2uPsGxPlXjbE/i+VgJexRnWYTWVb3e7+kZLXRdu8l0UEa8P7MvNk77n5oNcG9IKS8ufVI7kkGdRvV/Pa4GsHdO7Rr0c1zWrmZ+18JyfFR7HrgdaHdRSTjb6Hqt2m/Yn0mORuuRxrXoud1o1Cn4ymNaX7Y4M9KluP/yDoXCyG822LHP5wwhSv3cffiYevtUlKku5r42+0f0/S4f1CjwlOU0QwW5EAx+sc0oaVEIqzaP0b+m86mf2sEuv1JCr/e5hm99w4pmrxrTosNSQqsdpk6bsdlQBJE+apFLmOTvts/Td+8kLTkr1pht0RQmNvtRJpHooTMSSZ2KKt/8mX9kXpEZV6/zilxkFmwalZusyXLuU4uuOZg2dFszSRHttNet8Ko1eKpc6bSiqJdiOmX9IxqK8DXmR/ExOik9uXqWK6qrkQO5huTB9V7NDQlAdlkNn/CxjcYYtTFZBwKs4YzqMMrWspDzh8+0gLRmiPMryoZJ4//zCbyDTTC53kE+P9Forr3Rybb2DF2EnzemmzfwpzXHFKs4b+/L+ATcXVzAeRy+J0moonU9Wk25XFKqE6BLLNSOvy3RcSiMfv7YO80L9gsejo9nUe52lHD0lFQ2TVFkjR1rNWt6y4pdO+JldXbhV/dDTx7x/xpPoNr1xbDNZXULO053Sw32Zm7qfKZeSTORJQQrg6SHNxGbjSvWK4jVfxWcjU4zNO1IkpXp6slk+G6Rlyqv5RZYyWXLjTQ0+r0t1QKmVOkz5atWirFcb3oFzEiB3Vfwk7LWftGioAa0rGzdHX03g+o738rnEuvYu/+JIileNaRU3/UGRW+XSYc6rj8nPMgr0gbK9NEof6Iisw00OlAtzeGaW8TFH1OqUm0RqduCSZ/y7dgJexRnSYe3qVvK4rsXMO+8BNMtK/SUvMyjTa3OWN8sQFbks10q75KiY6UlOJxx7ddz04/gXj+PRq9I6qydt+Vy7nTyUKJrulaDKh9b+aA+8k7Fwzlxq28rnNf75x2PhU3/TUE7WXLXil20MG56zHyYFPl0lhdlIHDXiao7QWFAWpbM0xeo9TD5IKcTC5W2fd6xTOXl4UX7yHm0VAdztXKhU0+mwvHeVYqszK5MpUZgSSB0zLVKSq95aUP1v1JMtbf1S4b+/y69/VdtSWU1D+gma2orOwTrFtRncBHn7uEu/u0oK9bHz4hfPaBnNVO/raKrVqXZ5Klh575B2uC0cwlUT7O7ZwqRRTqJNWi+jkFNRySY1oArU0VzinL97PjH364KmAjTrszr+QflZmuvPtSoZw7NYsSphEJBm1phpS4ZlaMpV+LBuAl7FGdJhZv3V+8D1+aMsHHl+5iUvry+9tG4WF7XVX6VJGsK6rJSJRyfEbOK8Thhj3widM9PD43j6clol07w13ZBuZwf1q4UsC2gbXbU/3YOOxXg42ZmJpdPAvA/Fw2+W+Cb8dnRU9M2F6oyqx54yUPfxvN/GRbGU23SWMkE2VsVPqROqn7pay2eZrXWLjrxtt2rTmjtcpx59lZxMsdTYtf6QPTM5m8q52uwxILwv3G59BJ+cVGmSlFNXCkxKo9eEnW7GKkWtamoKUNV1qrgyRrQQ8WeWhrvOH3nJ8kiNe2mOB9FshqmVrVj595bKp+RAIyvLcwwzIkdyiUbQjhd7LqmlekUfiyDWdaGxoczhlCtOLpKfycnTw/0d/xEWU4weXsq4pI6Vpqf9FDKl15Rvk+yig9oJW9sJIslfHOHD2gl4FWdIhzUpWNNUT8IOcV7c6XcG7QqeLJvsrzOTrtILQV0xq41erVrndW4Y+2vrsKosTTea6OrXGibxkaCIUlnx03EDp0P92CEvLY5dYxSzWezs2nrUxzxOhsOvuZQCMEOZdstKlbUhnqvD8uWqIRn6sudkGlVna3muB4vSMlssda7VfDM7x6k4mUyjcGimF9FjuqELsFRZUQDUNLVI6WG6YQkd+fZyl+pom+qKkrp6mpPSk9T5Th/kOSx5mYwUt673NkRoUkMP90lpbR/SGxd8Q8gzlP3YWZwmbMkQ8UOtJmgi4KjDxcyMUY4zrQP0Vl8xS2eKz/JBq4GaGHkWm0FUZ00umSbS4j8RZ9IvrU6mA5GFS23okvmZmuOtOxriGlpCIfp4Ks2rJUdRZ0dB2iZeO1ly9Bo1H9Ke9Wexx8+VEfAqzpAOoxSvazSvIPl2gZaMdpnbP97LX5gsqxJNv3KHUd8PUxO+Zi35VMZq6ak2WofRilnt04KV/iymsb+CDnu+VzdM1Kv01XSjWWTr18KKM7WsXExD3Ka6qEVqMK29tDjmxuA1sRy7apbnwuGrTREOqAm/XcFV0JPqrs6Vklk+6AW9DH1X56mz1WP3YD1dlTS9r8kZlZSK5JXIAslYrsosYuQeQE+r5LiiqFEk6UYLQkNGaFAuGc2hOtl+lKkxre5FZpUlRV3b12rKgIKtgdOJJDWMCROQiVYD5AmoVi26Jtf7NH/tLLY6jALJ+lItp7lZNctS4HWYUjfS3G8XW9JzqT/lw/tySUYqdUvFK8NhMOlaMHl7slpePj9rppVbVpMnZj8sNIvVQNQAztVhLK/reHGaRXLetIgvX5+AV3HGdFi+XZY1tC7B5cYunUq3Eer+WK13ko5y5zddqZW24794lHxKJaAxyWsTL0ZmXVDOlb3p5xV0WF06qdjU2N1u16er9X405Z5euSrP6/++JINNewAM1iL9avPEmxVOHE2KnvFEozjqlnY5W0pmHdm0cyP/phyWsz21Ia7ST7EsAqXzoaiHbExPc9J+FRewMqfqLU1pgw1ElOSjFGDuWAmHTmUZZNE1BydipbSkP5gJntUS/w2LiRbRV0kHzDH9xU5SBkUOJ4ldizfFota3LKeKT9ZhT0d+Y4PJp6vaa4uT+kGWMrWOpQ4Q7TR2ZSi1zvNyIJZL9nmrur+lDjK6mo389e6ZO3x8cfD6lqlaaR7Lz5qH7QjKfphNRYqjsVQGablL/w8ZdUjoE/WqmQKSkxJFIpMni2SvOD8v522b+PblCXgVZ1iHXY+IZPD1WjzSksfxyCUfekrrs4GGYuHQqlTUZCoGUpBEMfAaVGwGenTVS2Lhd3ZW8grOFSihaGLnVTjBma7a6a6azvYUjJDIQ1x0gBRmWe6bIWg6IF7MT1UMmp0Y3vBQJT9tDtVay0Wr7oWrwGtZyjqMXVEnOXBjWRqVWLSSMD1VX/I6IJfUfffS0Gb7+P8672P1QElESmeopvhjAZ5O1K8d8cRaYfv4P/m5Lf2Fs6QOJ+U2w6ntqgwxk6imUw68dKN9FplmYhZAH5NLWUy0iOg7n9ru3i65OIznp7kHSN2t6cE7hefPYopI8oRd2RxWE22ak4ZUHuKc5GJ8Ts4bN/jy9Ql4FQc6LDa2HseYl0tZT1aKqON5hRPt/bvtVx7+u/nBAQiAAAiAwLkEvIoDHXYuwWTncYx5eY+13E7xXb65XRvw+vnhDHT6cpesPPzLgYQnEAABEACBEwS8ivMFdNiJyK572uN43V5crLWFhRPlsvLwo7hgDwIgAAIgMEzAqzjQYTGkHseYl9lYLyycKNeVhx/FBXsQAAEQAIFhAl7FgQ6LIfU4xrzMxnph4US5rjz8KC7YgwAIgAAIDBPwKg50WAypxzHmZTbWCwsnynXl4UdxwR4EQAAEQGCYgFdxoMNiSD2OMS+zsV5YOFGuKw8/igv2IAACIAACwwS8igMdFkPqcYx5mY31wsKJcl15+FFcsAcBEAABEBgm4FUc6LAYUo9jzMtsrBcWTpTrysOP4oI9CIAACIDAMAGv4kCHxZB6HGNeZmO9sHCiXFcefhQX7EEABEAABIYJeBUHOiyG1OMY8zIb64WFE+W68vCjuGAPAiAAAiAwTMCrONBhMaQex5iX2VgvLJwo15WHH8UFexAAARAAgWECXsWBDosh9TjGvMzGemHhRLmuPPwoLtiDAAiAAAgME/AqTtZhr6+vf+O/MwgsDNTCwjljAI3JysM3LPAFBEAABEDgIwm8vr52NRz2w7pY3IOennUvmPeJhYUThb3y8KO4YA8CIAACIDBMwKs40GExpB7HmJfZWC8snCjXlYcfxQV7EAABEACBYQJexYEOiyH1OMa8zMZ6YeFEua48/Cgu2IMACIAACAwT8CoOdFgMqccx5mU21gsLJ8p15eFHccEeBEAABEBgmIBXcaDDYkg9jjEvs7FeWDhRrisPP4oL9iAAAiAAAsMEvIoDHRZD6nGMeZmN9cLCiXJdefhRXLAHARAAARAYJuBVHOiwGFKPY8zLbKwXFk6U68rDj+KCPQiAAAiAwDABr+JAh8WQehxjXmZjvbBwolxXHn4UF+xBAARAAASGCXgVBzoshtTjGPMyG+uFhRPluvLwo7hgDwIgAAIgMEzAqzjQYTGkHseYl9lYLyycKNeVhx/FBXsQAAEQAIFhAl7FgQ6LIfU4xrzMxnph4US5rjz8KC7YgwAIgAAIDBPwKg50WAypxzHmZTbWCwsnynXl4UdxwR4EQAAEQGCYgFdxoMNiSD2OMS+zsV5YOFGuKw8/igv2IAACIAACwwS8igMdFkPqcYx5mY31wsKJcl15+FFcsAcBEAABEBgm4FUc6LAYUo9jzMtsrEfCebnbbG6c/909zya0czoyEv45fr+qzdPDZvu4P9H75/ubDZvxh5IJdejt8WKgPtw/URvHEqkaP7yU/tju7Xe3m9poMZIP+8ftze3uVDBiHfr5tttujjUdcrY043b001iXKPujRoO1aSzLJbEP+8et5PDL3Wa7e1OXv+22bkqUjk2uUg7KRz+7ip9iezhQwpyI7unhvIwivDYo1c7hcHh6cBfnmzqVXu5SfwSIQNvvbn3nnPbCNreamxPP0yh8ULbf9I3Q5YkvDunw830zkcmnNph6IkoMXAJUJkOxq+vf9dGrONBhMawexyNeOH1LXTGVw5ufdNyfD0faip4aCIfKZ79v00kY7c617UfCv3Yfr9seaSOTotI8V8q0SkpFUevjsaHvLIXitP6sBcBfZFPiqcW6uRmYLM1UJCYHa5uDn6gD29vzdIM3wQebNpfpitsdMrZ2Z6vx9UFfOuH3ZEor3TjNRgdOJAWHpFKUvutUtILGyIXne5M2tnskROwRK4xUgKX1DocJcduf5rS+AzFdPcNznrkNz4SC/33SynWiU/PlNNfyxNeJN5Vlk1TsZKDyKcKL/LtlxbZS14qGUh7ijZr1b/un6f3Y2bF3/L/zkFdxlqDDSrq/k9E5l3scvWt5xqrU5D2AMiXOmEWe4+lxPVenZ/tHouGQl2PbGCrSfoPzOjoS/mwiuEDy+JpGSxxOV1o6S94SA5YjsnmmdNix9Ch3I9lVW8/0omw1X7otVh0w5dYdE1UUXZvYiaLtyodj119gjLruDfzD4WUnAzGx7lTBic1FD2itkz73R1mpeTWslFjv2xuziWETQPctybJ010HDNM09PlJ0SRFnptxY/wRSHSmW5H+7zZs9SW2QWZ0O/daVLimupk1UeqlpJVM4rixinu+3j7t8C90bkZ6+pDGaTHzacrPCqOaPrAN+dNJbscwFpRYOE2mzmDCQSefLtVogtmz1OE5oe7HXwC71yas40GExwh7HvhdKo5IlYqJWxosu00emhzQ9+RkLJ12u+m/9qallT8z220j4swnmAsmjlmwnrLIKc3W0lUOWVKmd6Y55kh5N8dMre11za09Ki6z4pVpb2cfVTlUpp/PymKY48e3OO0MLfVnQ2y71XFxgjHpu/T3pifVkOCYWFz9QlJAaytKIkilZctmkamtkeOxK67lJnX76c+kRi5UbtVC3Htjy6YHzTYzbMs9P6s0cud3tG8VA86XkeflQ+tF8aAz642iX3KzD9o/y5oCkH3fs/qlJmxSLzWepVvLwTs9W6WC/0Jhgs4BTcs2MO3tSEdG1+RI1v5JEKwmQgKir2IslkLtI8da4rDhOJufFnt1d8IdXccZ0WJpgNe3Uiqw0qSyUnA07usvJOtqzeZKxpGxIpDZ64TObMWmMax/Eud6wKXnAqbPjF5t4XKUhby/UJe9x7F5Qy4w5XfOYyTyVSGXjl0MQevqRv86tGsLm7lnff9QLTavdL6FwsofmHsUsozKNu43N72A0fHe80k18RlEgNFmnc9XavOSbYx7fMjuKjegJ9p9yQI1+2aYqF5Y1iOfpjp23VUQ5dwdU2XRui48OZ/G53T3zSzmlw00O56+16nCf0zththjwBK8xtgW7+1yDVu3trXv7fjSE5iRPsQo/lQc+qFa/5hrzYlAhoJ6/6HAK7USgnCqLmHJO7faO88s0QoYdct16Lvs9pap11tKUZtvHU9lY1yv1AEh1rixfUiPrOOrtIpI7D/fmhS3yrJcvfaFp4MiXrorK9mVPS13PndTrp1nQBLLK5zcyZrblA80OsZSDabhTwqR1gxqtea66cNZHyocm06rb5EGazlt991xZkvxK415FTFqL7h5zYlA4z/fb221OQiVYk6XoThqdWr8mHZcRzyfKV3OJzh/JVfFf4TNPnQCEjvYULQRpogxQ9TD1ma49P/ZJfO8+4FWccR1WdQ8Nv2Thy51gqnnD3MWA579jkxHrDOanYDk52s8yY43cofFQ9tmGF7WyBtV0PLy9POkXOU9y9jj2Lkzr6fRMPZ4yUioTHc+faw8rRhZkGSMhknDedjt+O97k+rTV7pFIOF0HX/tgNHx3vPa7h/xKuBrE9M6sDNPhiE3KUppH5b689aOmTM4B6kxxzm1NbMhJLWxqmT68PB37jQpe1MRbGmJypY6w52bJq505NyuqNGlcla/skyPd1VJHwcocP9ZUZmhBHbvAO8f9rCuYnn35NsmJvTZdZ3RZc2hqy9xnxZYXq8Q2B0htyUJnupcKjz2lO5aXBTbLrXCC5UE8TbijVwAAC8ZJREFUsk6eyMb9431++Z2isx0oPaQ1eVvOquTRSahutt167IAtDU0+KEnUnvNPmV5NzWSkkopijJMOS3ooV6UwTdOAM6ojFBq3asbpDEmBTRZ81TRv1rLMur+rAi4nYZ4X9YU5yaXn3ZZbVOOlb8CyiORiWmZo+pCHKU/MY9EVddiOjv4uobU6jBJPaUQt6/PlNScTDTXv2CIUu+7SZT57FWdch+kUKQmnO1sO1izUp/lz30avEUp9F2O+tM4WfVx/5j3VND1kXFMHjP9Jn44e8Dj2LtLZrM/X4y2ZkjTTD+wgp6Ceb9WxjbEeP/YpEk5K+tNrR9XBx1qexblY+Kls6MJQhklFo8bUHRHHpq4R5Y6WHNtWyjKknHg2NdPID6WNVAvV4eajruXqFLmqReL+KS30RcyVnYZjS7Beu5v6TVPS7dvz/d2z3nJIZUN7o88TZVan+XQgbDitKxXpdvdPdc+TgEwR0Vg0EbFpHaPaGYFqh1XdZU1HbRKa+CD/Rcx1lwXbSlkeywf2VNZSDYq6YWSizvzUgW6L9VS9vOawc0lOG82QLLX0l5hP/CyxTOymTZdBMadaDzTjtrxvV3UYj0i9Sl1SD9Zf9DNpMMXIPa02k47LATMi0ySUKZlye/u43z/f860adYnVvJMM4p+XkXZqq2ysOixP1Umfk0SrE5kM9JieG6nkYTPTxVWNPXeJ/aYwc//TgrB/2+/feH+3ZHIK1uY/H0uaTw1fsrzsv17FuYwOK7WheeSfgp+MVkqUvNh1bDTcqsPMVakkJC2omHo2Mq4Fah7gmjHlzPEPHsfuVapj+nztTEumBC4ThgyaIjF5zC+uq1s5cvpnKJyeu5FGe34+51g0fHe8zPOgslXZwsnFJg1ovYOsSVjUjNZh/RywotCxUWtoApyWKilvpj9NmumvtPxNXOnfJ5d07Y2it3fVmaptqqc+5MVXlbq2GdmuMMdth4/10Fx2zpdaBk5Zq4WRixxF5NWw0uHygb2fLgwUPq2E3RjtQVmROvB5LTUZ281G6pOpjo5GLEVRENF74nu9gWH6QK1LcuY0kKIrDs78qfNEfzbPiJMvoTFpuib/9nFPb4alZ+vUw+3uzOeS+g8u8LpB+1L6V/moD2q/p11buuESIsLI831CXgAWzaF8Cm2Zy+1cU8uR/V1gubBOxpokHf90O2QvqTApfOlbb1OtNiHBKz4ZvpzJySkVMwNJBOqKkTQGgWKDm9vd/5j7ydSiG7s0drmfXsW5jA6ThKYBSNpokoX8F4MonjNsBC6HX0ddrwuajLROxxyb6kRfyDO/VkFzyvniceyb20Uw26iDKo/5ZDmlP0zvnyjbJpOwCtZ+X7pHY+FkF3oEp9Np2rFuy7M4GA3fGy+dgcrGZN2ZNmX6VD96MVLYqoFd0JWJHil1mFKlzlN9ol/LyaLnKlUFeu3SDDp1zC6+zVdZi1PLU890xNqkDigFU4s0xTIx5r8sUG1y/6dmJvazv5yvw/SgZ/cJ2n4qm4posED6k930NbfStSwrCV9R+nPOOqltarJph90WqaE0gvQnA0o+q/BNttRb9yxxZOdmuu6ZoL0vGWO6x6iti3asR/SCaQIpA1GbyHo6FSZxZbNa6gi7oveu7ul155RylZ7d3i4G+b7Lzpp+upL/quZrF4l6qQvEP3VPxatTTi9NJt948uoBUpY1/Gxg4qKu6Jsu/bkjgrVCyFFwaG2HSxoYVSBx9w7W20slyJRbFZFd1iaxSyuX++lVnHEdVvcbKS/TwOgI6/poR+sMGwNX2deGDBidzXyvptMoWSonJI3v5Ne8zXHj1PnicXTMJ/WAQpAZm0V6+aqqY13s1MHaBk8zSdBrvx9mQggDrEHM4FN0NHmiTsdLL2R6aDScc2zMXYSaNd0caJa2ro1ulFZhWYzscT0QNfH00VxZH144Oq4WyRUDaWWQ7XmajLVFs0XEk5Huv3MFunum7GodcldqdXzb79OWzO1u1xVh3KvuIjCRBU2U5309W4fVBOitOTRkpdZSn7tloxZX1bk6lPl3OHg4eHSaZcEOaF0q+2tp7XBzT1vGtHwQ6TDlzJmZYrGtUwAqHKmXaUJx5+mqVL9rwtSw+32u5/kTUaV0Eg50kJOKENEHmb+6b6pXrAvFRnxzRrFb3hvLzutVJTk5Cmm90G6hpb7R5bWf2kaanfxMl0wDTIa1P5ML04ESMr0eKqBUEvLoUJglLfV4JR86+Sd9rtpLBpdckVnO7bZjdGojvxoytdG3oEYViJ8SER/IjVY/aTjsaJ4fO6s0yqXqUNod/elVnHEd9pB+D4tyosbJWNOqevfQvRuQHUJeeR0bQ9wsDcq/opOzM3ejZ2OcpGmZln6pTOdy9Tgeud70Z7pzcJ9+k9Rmv04vPfcqapnwKktyQ5GkCYeTVrT7Uiwt2CMUZnkqGj4R9sYrKwn6FTCpARYOo+Osc236OxC5eqVppadbXklzDnfyxBYzZVDX2WZc9MKnTsmqWmd6XrIp2VI3aj1mSmn/u6zLtSeNDiuN2GkyFUyl1JUr+CZnsrHHXa2dqdaC0Y3dmB77Qk3oMt+xtUMjUmCy5tRaqNb6yooc06hNwlFDaR91TZYFvZLoR8lmHS5rqclYJxtrn2/v7zp9ozwvHZ6M2jScPC8kterl1JBen1VedYjnQ/XydCD1VpzngaB3p8yeq+WZhin/ywOtklb1qsaSwrQ+mfA02USckZ/bHW0ZJlzHo5PZUcDmB20qbY48XS1LRxnoYsxrEXNOTTBwhiaBm1S3eCd9LvNdBigPLnVAD6WczlM4oZ6y0pWabCalbdKB5LjMAjXupUlZBzabE7FT69Qieet2Xrs887NXcd6hw+r/38iZfViCmcfxsrE56XXZRshbLBwzCUuuq0metUhdLC7f44t6jIWfSteJAnzR/l3PWSpX7nLZPJfsaJ1Uydq1u6zLvJbJnVte1Gzxa1bhrPwq7UlFz3BUXUxv6U0Wa0ux1hh7PPDtDB0W8LYsU2eY1FjLQMsCUnImrx665rGN5IDWhWdBYxEwraBKVImbqqjkiPPTrMx8lf7TD+1FKuqq7aS0C4e8XVcNhAPvS+X3mapx04Y04RpoeyUslFYmi+mM5iT/p/olZfmzJur/KkzTyBOWoquLidZwyUDvqTfijLyZ2HnbW0afbkjy1Fb+68ZE3hhmD478okBT1pkK5cSe/4YtOTyxpGjEJz57FQc67AS45rTHsTF731cuWleRuVcJ530wPvLqaPh63fnIfsE3CIBAQ6Bo+uY4voLAlyHgVRzosNgQehxjXlxrc4/oWl3uxAeHc7mOfoynaPjQYR8zDvAKAiAAAssn4FWcMR22fF5ehB5Hz37mxxcWTpT2ysOP4oI9CIAACIDAMAGv4kCHxZB6HGNeZmO9sHCiXFcefhQX7EEABEAABIYJeBUHOiyG1OMY8zIb64WFE+W68vCjuGAPAiAAAiAwTMCrONBhMaQex5iX2VgvLJwo15WHH8UFexAAARAAgWECXsWBDosh9TjGvMzGemHhRLmuPPwoLtiDAAiAAAgME/AqDnRYDKnHMeZlNtYLCyfKdeXhR3HBHgRAAARAYJiAV3Ggw2JIPY4xL7OxXlg4Ua4rDz+KC/YgAAIgAALDBLyKAx0WQ+pxjHmZjfXCwolyXXn4UVywBwEQAAEQGCbgVRzosBhSj2PMy2ysFxZOlOvKw4/igj0IgAAIgMAwAa/iQIfFkHocY15mY72wcKJcVx5+FBfsQQAEQAAEhgl4FQc6LIbU4xjzMhvrhYUT5bry8KO4YA8CIAACIDBMwKs4WYe9vr7+jf/OILAwUAsL54wBNCYrD9+wwBcQAAEQAIGPJPD6+trVcFmHdc/hIAiAAAiAAAiAAAiAwMcRgA77OLbwDAIgAAIgAAIgAALHCECHHaODcyAAAiAAAiAAAiDwcQSgwz6OLTyDAAiAAAiAAAiAwDEC0GHH6OAcCIAACIAACIAACHwcAeiwj2MLzyAAAiAAAiAAAiBwjMD/B/eW0KkKFHZOAAAAAElFTkSuQmCC"
+ }
+ },
+ "cell_type": "markdown",
+ "id": "53561f75-fd14-4370-a823-696c2bb3abf0",
+ "metadata": {},
+ "source": [
+ "### 1.1 描述函数功能\n",
+ "为了向模型描述外部函数库,需要向 tools 字段传入可以调用的函数列表。参数如下表:\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "编写函数参数列表的 JSON 描述:
\n",
+ "为了准确定义函数的参数列表,在编写参数列表的 JSON Schema 时建议最少包含以下字段:
\n",
+ "\n",
+ "description :说明函数方法的用途。
\n",
+ "type :定义 JSON 数据的数据类型约束。
\n",
+ "properties:一个Object,其中的每个属性代表要定义的 JSON 数据中的一个键。
\n",
+ "required:指定哪些属性在数据中必须被包含。
\n",
+ "enum:如果一个属性是枚举类型,则此字段应当设置为枚举值的数组。
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "78547d7d-00bd-4290-9339-0f44f27b2043",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "tools = [\n",
+ " {\n",
+ " \"type\": \"function\",\n",
+ " \"function\": {\n",
+ " \"name\": \"get_flight_number\",\n",
+ " \"description\": \"根据始发地、目的地和日期,查询对应日期的航班号\",\n",
+ " \"parameters\": {\n",
+ " \"type\": \"object\",\n",
+ " \"properties\": {\n",
+ " \"departure\": {\n",
+ " \"description\": \"出发地\",\n",
+ " \"type\": \"string\"\n",
+ " },\n",
+ " \"destination\": {\n",
+ " \"description\": \"目的地\",\n",
+ " \"type\": \"string\"\n",
+ " },\n",
+ " \"date\": {\n",
+ " \"description\": \"日期\",\n",
+ " \"type\": \"string\",\n",
+ " }\n",
+ " },\n",
+ " \"required\": [ \"departure\", \"destination\", \"date\" ]\n",
+ " },\n",
+ " }\n",
+ " },\n",
+ " {\n",
+ " \"type\": \"function\",\n",
+ " \"function\": {\n",
+ " \"name\": \"get_ticket_price\",\n",
+ " \"description\": \"查询某航班在某日的票价\",\n",
+ " \"parameters\": {\n",
+ " \"type\": \"object\",\n",
+ " \"properties\": {\n",
+ " \"flight_number\": {\n",
+ " \"description\": \"航班号\",\n",
+ " \"type\": \"string\"\n",
+ " },\n",
+ " \"date\": {\n",
+ " \"description\": \"日期\",\n",
+ " \"type\": \"string\",\n",
+ " }\n",
+ " },\n",
+ " \"required\": [ \"flight_number\", \"date\"]\n",
+ " },\n",
+ " }\n",
+ " },\n",
+ "]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1e3b2c65-51bc-4c12-a2e2-682430ddebed",
+ "metadata": {},
+ "source": [
+ "## 2.与模型交互,触发函数调用\n",
+ "函数调用选择
\n",
+ "在 tools 参数中,如果填写了 functions 参数,则默认情况下模型将决定何时适合使用其中一个函数。 如果要控制模型如何选择函数调用,需要设置 tool_choice 参数。参数默认值为auto,此时模型根据上下文信息自行选择是否返回函数调用。还可以通过将 tool_choice 参数设置为 “none” 来强制 API 不返回任何函数的调用。目前函数调用仅支持 auto 模式。"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d69bc6af-a3bb-4fcf-a4e7-77ec9f09095f",
+ "metadata": {},
+ "source": [
+ "Function Call 流程实践
\n",
+ "本节将以上文定义的具备查询航班功能的聊天机器人为例,介绍如何与模型对话完成函数调用。\n",
+ "\n",
+ "初始化函数定义和client:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "0d1cd0f4-6fb5-4c06-8af2-a69d3793b6dd",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from zhipuai import ZhipuAI\n",
+ "client = ZhipuAI(api_key=\"cc28e0d694973a7276d02d6822e5958c.5h0H2TcNId2qBGBi\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f87a33d2-221f-4248-abf3-4f7c24c67c81",
+ "metadata": {},
+ "source": [
+ "### 2.1 我们想查询2024年1月20日从北京前往上海的航班。我们向模型提供这个信息:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "c7140a94-70c0-465a-bda8-81a620ec0ee8",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CompletionMessage(content=None, role='assistant', tool_calls=[CompletionMessageToolCall(id='call_9106862906070347132', function=Function(arguments='{\"date\":\"2024-01-20\",\"departure\":\"北京\",\"destination\":\"上海\"}', name='get_flight_number'), type='function', index=0)])\n"
+ ]
+ }
+ ],
+ "source": [
+ "messages = []\n",
+ "messages.append({\"role\": \"user\", \"content\": \"帮我查询从2024年1月20日,从北京出发前往上海的航班\"})\n",
+ "response = client.chat.completions.create(\n",
+ " model=\"glm-4\", # 填写需要调用的模型名称\n",
+ " messages=messages,\n",
+ " tools=tools,\n",
+ ")\n",
+ "print(response.choices[0].message)\n",
+ "messages.append(response.choices[0].message.model_dump())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cd87fc15-b5f0-49ee-acef-26e99d7e52a9",
+ "metadata": {},
+ "source": [
+ "### 可以看到,此时模型成功触发对get_flight_number函数的调用,参数为:date=“2024-01-20”,departure=“北京”,destination=“上海”"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9e738426-2198-4d44-b7a6-6473cba220b9",
+ "metadata": {},
+ "source": [
+ "### 2.2 现在,清空消息历史。我们尝试提供信息,触发模型对get_ticket_price函数的调用。"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "742678ba-abb0-4794-b1f3-e6e1daf014c6",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CompletionMessage(content=None, role='assistant', tool_calls=[CompletionMessageToolCall(id='call_9106862974789889531', function=Function(arguments='{\"date\":\"2024-01-20\",\"flight_number\":\"1234\"}', name='get_ticket_price'), type='function', index=0)])\n"
+ ]
+ }
+ ],
+ "source": [
+ "messages = []\n",
+ "messages.append({\"role\": \"system\", \"content\": \"不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息\"})\n",
+ "messages.append({\"role\": \"user\", \"content\": \"帮我查询2024年1月20日1234航班的票价\"})\n",
+ "response = client.chat.completions.create(\n",
+ " model=\"glm-4\", # 填写需要调用的模型名称\n",
+ " messages=messages,\n",
+ " tools=tools,\n",
+ ")\n",
+ "print(response.choices[0].message)\n",
+ "messages.append(response.choices[0].message.model_dump())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9b77346f-9260-4f42-9ad7-a7dabc0c6fd1",
+ "metadata": {},
+ "source": [
+ "### 2.3 我们也可以强制模型使用特定函数\n",
+ "比如,我们通过设置tool_choice为{“type”: “function”, “function”: {“name”: “get_ticket_price”}}以强制模型生成调用get_ticket_price的参数。
\n",
+ "我们也可以强制模型不调用函数。需要设置tool_choice为none。"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "060a52aa-77f5-4bd2-b245-0b2cd7274584",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CompletionMessage(content=None, role='assistant', tool_calls=[CompletionMessageToolCall(id='call_9106867063600082356', function=Function(arguments='{\"date\":\"2021-06-01\",\"flight_number\":\"1234\"}', name='get_ticket_price'), type='function', index=0)])\n"
+ ]
+ }
+ ],
+ "source": [
+ "messages = []\n",
+ "messages.append({\"role\": \"system\", \"content\": \"不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息\"})\n",
+ "messages.append({\"role\": \"user\", \"content\": \"帮我查询1234航班的票价\"})\n",
+ "response = client.chat.completions.create(\n",
+ " model=\"glm-4\", # 填写需要调用的模型名称\n",
+ " messages=messages,\n",
+ " tools=tools,\n",
+ " tool_choice={\"type\": \"function\", \"function\": {\"name\": \"get_ticket_price\"}},\n",
+ ")\n",
+ "print(response.choices[0].message)\n",
+ "messages.append(response.choices[0].message.model_dump())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7832e7d2-4626-48d9-bc46-3a175d4b344e",
+ "metadata": {},
+ "source": [
+ "## 3. 使用模型生成的参数调用函数"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "051e031b-8b4e-4ae6-9f55-a4f8451c203c",
+ "metadata": {},
+ "source": [
+ "### 3.1 将所需要的函数实现"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "5e3bb5a2-03e1-4a51-9863-530de9e1068d",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def get_flight_number(date:str , departure:str , destination:str):\n",
+ " flight_number = {\n",
+ " \"北京\":{\n",
+ " \"上海\" : \"1234\",\n",
+ " \"广州\" : \"8321\",\n",
+ " },\n",
+ " \"上海\":{\n",
+ " \"北京\" : \"1233\",\n",
+ " \"广州\" : \"8123\",\n",
+ " }\n",
+ " }\n",
+ " return { \"flight_number\":flight_number[departure][destination] }\n",
+ "def get_ticket_price(date:str , flight_number:str):\n",
+ " return {\"ticket_price\": \"1000\"}"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f6645956-1127-4b59-8a97-4f46ae6f6943",
+ "metadata": {},
+ "source": [
+ "### 3.2 定义处理 Function call 的函数:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "53b9c7ef-aafd-4aa0-b9aa-68f84841eb04",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "def parse_function_call(model_response,messages):\n",
+ " # 处理函数调用结果,根据模型返回参数,调用对应的函数。\n",
+ " # 调用函数返回结果后构造tool message,再次调用模型,将函数结果输入模型\n",
+ " # 模型会将函数调用结果以自然语言格式返回给用户。\n",
+ " if model_response.choices[0].message.tool_calls:\n",
+ " tool_call = model_response.choices[0].message.tool_calls[0]\n",
+ " args = tool_call.function.arguments\n",
+ " function_result = {}\n",
+ " if tool_call.function.name == \"get_flight_number\":\n",
+ " function_result = get_flight_number(**json.loads(args))\n",
+ " if tool_call.function.name == \"get_ticket_price\":\n",
+ " function_result = get_ticket_price(**json.loads(args))\n",
+ " messages.append({\n",
+ " \"role\": \"tool\",\n",
+ " \"content\": f\"{json.dumps(function_result)}\",\n",
+ " \"tool_call_id\":tool_call.id\n",
+ " })\n",
+ " response = client.chat.completions.create(\n",
+ " model=\"glm-4\", # 填写需要调用的模型名称\n",
+ " messages=messages,\n",
+ " tools=tools,\n",
+ " )\n",
+ " print(response.choices[0].message)\n",
+ " messages.append(response.choices[0].message.model_dump())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7072b593-5c64-40a1-b027-feca709f9e77",
+ "metadata": {},
+ "source": [
+ "### 3.3 查询北京到广州的航班:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "bbd70f8e-4f47-4a69-ba13-f76a09b8a23c",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CompletionMessage(content=None, role='assistant', tool_calls=[CompletionMessageToolCall(id='call_9106862837350813170', function=Function(arguments='{\"date\":\"2022-01-23\",\"departure\":\"北京\",\"destination\":\"广州\"}', name='get_flight_number'), type='function', index=0)])\n",
+ "CompletionMessage(content='根据您的请求,我已经查询到1月23日从北京到广州的航班号是8321。', role='assistant', tool_calls=None)\n"
+ ]
+ }
+ ],
+ "source": [
+ "# 清空对话\n",
+ "messages = []\n",
+ " \n",
+ "messages.append({\"role\": \"system\", \"content\": \"不要假设或猜测传入函数的参数值。如果用户的描述不明确,请要求用户提供必要信息\"})\n",
+ "messages.append({\"role\": \"user\", \"content\": \"帮我查询1月23日,北京到广州的航班\"})\n",
+ " \n",
+ "response = client.chat.completions.create(\n",
+ " model=\"glm-4\", # 填写需要调用的模型名称\n",
+ " messages=messages,\n",
+ " tools=tools,\n",
+ ")\n",
+ "print(response.choices[0].message)\n",
+ "messages.append(response.choices[0].message.model_dump())\n",
+ " \n",
+ "parse_function_call(response,messages)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "088b8eb6-524f-4c16-b47b-eca5abb0efad",
+ "metadata": {},
+ "source": [
+ "### 3.4 查询1234航班票价:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "f5bf78ec-cc23-41f1-8c79-2b9929d8890c",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CompletionMessage(content=None, role='assistant', tool_calls=[CompletionMessageToolCall(id='call_9106862528112856677', function=Function(arguments='{\"date\":\"2022-01-23\",\"flight_number\":\"8321\"}', name='get_ticket_price'), type='function', index=0)])\n",
+ "CompletionMessage(content='这趟航班的价格是1000元。', role='assistant', tool_calls=None)\n"
+ ]
+ }
+ ],
+ "source": [
+ "messages.append({\"role\": \"user\", \"content\": \"这趟航班的价格是多少?\"})\n",
+ "response = client.chat.completions.create(\n",
+ " model=\"glm-4\", # 填写需要调用的模型名称\n",
+ " messages=messages,\n",
+ " tools=tools,\n",
+ ")\n",
+ "print(response.choices[0].message)\n",
+ "messages.append(response.choices[0].message.model_dump())\n",
+ " \n",
+ "parse_function_call(response,messages)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "d1d7abf4-300f-4cf0-a635-8d58db0d8a1a",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "python3.10(base)",
+ "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.10.8"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}