diff --git a/content/AI Agentic Design Patterns with AutoGen/.env.example b/content/AI Agentic Design Patterns with AutoGen/.env.example new file mode 100644 index 00000000..5131f098 --- /dev/null +++ b/content/AI Agentic Design Patterns with AutoGen/.env.example @@ -0,0 +1,3 @@ +# OpenAI https://platform.openai.com/api-keys +OPENAI_API_KEY = +OPENAI_BASE_URL = diff --git "a/content/AI Agentic Design Patterns with AutoGen/2.\345\244\232\346\231\272\350\203\275\344\275\223\345\257\271\350\257\235\345\222\214\347\233\270\345\243\260 multi-agent-conversation.ipynb" "b/content/AI Agentic Design Patterns with AutoGen/2.\345\244\232\346\231\272\350\203\275\344\275\223\345\257\271\350\257\235\345\222\214\347\233\270\345\243\260 multi-agent-conversation.ipynb" new file mode 100644 index 00000000..bca99e27 --- /dev/null +++ "b/content/AI Agentic Design Patterns with AutoGen/2.\345\244\232\346\231\272\350\203\275\344\275\223\345\257\271\350\257\235\345\222\214\347\233\270\345\243\260 multi-agent-conversation.ipynb" @@ -0,0 +1,667 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "a81456dd", + "metadata": {}, + "source": [ + "# 2 多智能体对话和相声" + ] + }, + { + "cell_type": "markdown", + "id": "7e521280-a52f-4ff9-b5f5-364789846728", + "metadata": {}, + "source": [ + "## 2.1 环境安装" + ] + }, + { + "cell_type": "markdown", + "id": "4693467e", + "metadata": {}, + "source": [ + "欢迎来到正式的代码实战环节。接下来我们需要先安装一些必要的环境和基础的配置。" + ] + }, + { + "cell_type": "markdown", + "id": "f044d2c0-7025-41c0-b137-ba2248788815", + "metadata": {}, + "source": [ + "首先,使用conda新建一个虚拟的python环境并激活进入" + ] + }, + { + "cell_type": "markdown", + "id": "822d1fe5-4b57-45fb-ba57-818f090123ac", + "metadata": {}, + "source": [ + "```bash\n", + "conda create -n autogen python=3.10\n", + "conda activate autogen\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "9bd4b57f-dda0-460b-81e3-ae52454a093b", + "metadata": {}, + "source": [ + "接下来,安装本课程学习中所必要的依赖" + ] + }, + { + "cell_type": "markdown", + "id": "8c40f272-3e36-489c-a97e-68ec66ce435d", + "metadata": {}, + "source": [ + "```bash\n", + "cd \n", + "pip install -r requirements.txt\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "34427c37", + "metadata": {}, + "source": [ + "最后,记得在`.env`文件中填入有效的`OPENAI_API_KEY`以及可选的`OPENAI_BASE_URL`哦🥰" + ] + }, + { + "cell_type": "markdown", + "id": "fc52cab9-2b65-4897-85f4-e2fdf2b6c4dc", + "metadata": {}, + "source": [ + "安装完毕,让我们马上开始基于AutoGen框架的Agent设计范式学习吧~
\n", + "在这一节课中,我们会实现两个智能体合作讲相声的一个有趣例子😊" + ] + }, + { + "cell_type": "markdown", + "id": "742cf649", + "metadata": {}, + "source": [ + "## 2.2 基础配置" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "04d006c1-22fa-40ea-b3e0-d543142e0788", + "metadata": { + "height": 64 + }, + "outputs": [], + "source": [ + "from utils import get_openai_api_key, get_openai_base_url\n", + "OPENAI_API_KEY = get_openai_api_key() # 获取api_key,此项是必须的\n", + "OPENAI_BASE_URL = get_openai_base_url() # 获取base_url,此项可选,如果不用则可以直接注释该行\n", + "llm_config = {\"model\": \"gpt-3.5-turbo\"} # 这里使用的模型名称为gpt-3.5-turbo" + ] + }, + { + "cell_type": "markdown", + "id": "116a1c4d", + "metadata": {}, + "source": [ + "## 2.3 定义一个AutoGen智能体" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "6fb8c441-c58c-41a8-a54b-5c387afceac5", + "metadata": { + "height": 132 + }, + "outputs": [], + "source": [ + "from autogen import ConversableAgent\n", + "\n", + "# 初始化一个ConversableAgent\n", + "agent = ConversableAgent(\n", + " name=\"chatbot\",\n", + " llm_config=llm_config,\n", + " human_input_mode=\"NEVER\", # 这里设置不使用人类反馈介入\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "efc51ca7-6bfb-4572-a04c-a5a7d012f0bb", + "metadata": {}, + "source": [ + "在 `AutoGen` 的 `ConversableAgent` 中,人工循环组件位于自动回复组件的前面。
\n", + "它可以拦截传入的消息,并决定是否将它们传递给自动回复组件或提供人工反馈。逻辑架构如图所示:" + ] + }, + { + "cell_type": "markdown", + "id": "77706a1b-8b7b-42ed-888b-ecaca4ebce36", + "metadata": {}, + "source": [ + "![fig2.1](./images/fig-2-1.png)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "47886b5f-fc7c-431a-8036-cff6e88f85c6", + "metadata": { + "height": 80 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "当两个细胞相遇,一半提议:你配我吗? 另一半回答:我们在一起吧,我们要变得更有型!\n" + ] + } + ], + "source": [ + "reply = agent.generate_reply(\n", + " messages=[{\"content\": \"给我讲一个笑话\", \"role\": \"user\"}]\n", + ")\n", + "print(reply)" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "67f626e9-4cec-40c1-abde-2eff1252b848", + "metadata": { + "height": 96 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "为了保持新鲜感,我会告诉你另外一个笑话:为什么小鸡不生病?因为它有禽力!哈哈哈!希望这个笑话能让您开心一下!\n" + ] + } + ], + "source": [ + "reply = agent.generate_reply(\n", + " messages=[{\"content\": \"重复一下笑话\", \"role\": \"user\"}]\n", + ")\n", + "print(reply)" + ] + }, + { + "cell_type": "markdown", + "id": "6c067449-6202-48c1-a51b-58bbde7b424a", + "metadata": {}, + "source": [ + "由此可见,我们执行了两次`generate_reply`函数,但是智能体的第二次回复并没有继承上一次的交互记忆,因此没有成功的重复笑话。" + ] + }, + { + "cell_type": "markdown", + "id": "8c98a301", + "metadata": {}, + "source": [ + "## 2.4 对话\n", + "\n", + "让Cathy和Joe两个Agent建立对话,它们的对话内容作为记忆可以被保存下来" + ] + }, + { + "cell_type": "markdown", + "id": "0b72c4dd", + "metadata": {}, + "source": [ + "![fig2.2](./images/fig-2-2.png)" + ] + }, + { + "cell_type": "markdown", + "id": "52f74a5b-55b0-479e-8257-d2400edb0e0b", + "metadata": {}, + "source": [ + "我们通过定义两个可以对话的Agent,赋予它们相声演员的职责设定,就可以驱动它们完成相声的交互了。" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "8f109dcb-824e-40d7-8e86-efee42b75f3c", + "metadata": { + "height": 300 + }, + "outputs": [], + "source": [ + "cathy = ConversableAgent(\n", + " name=\"cathy\",\n", + " system_message=\n", + " \"你的名字是Cathy,你是一位相声演员\",\n", + " llm_config=llm_config,\n", + " human_input_mode=\"NEVER\",\n", + ")\n", + "\n", + "joe = ConversableAgent(\n", + " name=\"joe\",\n", + " system_message=\n", + " \"你是的名字是Joe,你是一位相声演员\"\n", + " \"你需要根据上一个笑话,开始你的下一个笑话\",\n", + " llm_config=llm_config,\n", + " human_input_mode=\"NEVER\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "43f71a61", + "metadata": {}, + "source": [ + "**注意**: 您每次执行都可能会得到不同的笑话,因为这和大语言模型的底层逻辑,预测下一个生成token的最大概率有关。" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "46a1c6f6-687e-40de-8819-374201cfed9f", + "metadata": { + "height": 97 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33mjoe\u001b[0m (to cathy):\n", + "\n", + "我是Joe。Cathy,让我们持续不断地讲笑话吧。\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mcathy\u001b[0m (to joe):\n", + "\n", + "当然,Joe!让我来给你讲一个相声段子:\n", + "Cathy: \"你知道为什么买衣服要试穿吗?\"\n", + "Joe: \"为什么?\"\n", + "Cathy: \"因为有些衣服,看着很文雅、挺得很直,一穿上去,就变成了土豪金!\" \n", + "\n", + "哈哈,怎么样,好笑吗?现在轮到你了,来讲一个笑话吧!\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mjoe\u001b[0m (to cathy):\n", + "\n", + "哈哈,好笑好笑!那我来讲一个:\n", + "\n", + "Joe: \"你知道为什么粽子不爱光着脚去逛街吗?\"\n", + "Cathy: \"为什么?\"\n", + "Joe: \"因为它怕被蚊子咬出个包,然后被人误认为是猪蹄!\" \n", + "\n", + "哈哈,怎么样,是不是有点意思?继续一起笑下去吧!\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mcathy\u001b[0m (to joe):\n", + "\n", + "哈哈哈,太有创意了,Joe!这个笑话真是太逗了!笑声是最好的药物,让我们继续一起分享快乐吧!如果你还有更多好笑的段子,尽管来,我随时准备好了!\n", + "\n", + "--------------------------------------------------------------------------------\n" + ] + } + ], + "source": [ + "chat_result = joe.initiate_chat(\n", + " recipient=cathy, \n", + " message=\"我是Joe。Cathy,让我们持续不断地讲笑话吧。\",\n", + " max_turns=2,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "78edc810", + "metadata": {}, + "source": [ + "## 2.5 结果打印\n", + "\n", + "你可以在控制台打印出下列信息:\n", + "\n", + "1. 对话的历史记录\n", + "2. 对话的花费\n", + "3. 对话的总结" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "1169ea24-eadd-4909-8d56-9b7ec5677c66", + "metadata": { + "height": 63 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[{'content': '我是Joe。Cathy,让我们持续不断地讲笑话吧。', 'role': 'assistant'},\n", + " {'content': '当然,Joe!让我来给你讲一个相声段子:\\n'\n", + " 'Cathy: \"你知道为什么买衣服要试穿吗?\"\\n'\n", + " 'Joe: \"为什么?\"\\n'\n", + " 'Cathy: \"因为有些衣服,看着很文雅、挺得很直,一穿上去,就变成了土豪金!\" \\n'\n", + " '\\n'\n", + " '哈哈,怎么样,好笑吗?现在轮到你了,来讲一个笑话吧!',\n", + " 'role': 'user'},\n", + " {'content': '哈哈,好笑好笑!那我来讲一个:\\n'\n", + " '\\n'\n", + " 'Joe: \"你知道为什么粽子不爱光着脚去逛街吗?\"\\n'\n", + " 'Cathy: \"为什么?\"\\n'\n", + " 'Joe: \"因为它怕被蚊子咬出个包,然后被人误认为是猪蹄!\" \\n'\n", + " '\\n'\n", + " '哈哈,怎么样,是不是有点意思?继续一起笑下去吧!',\n", + " 'role': 'assistant'},\n", + " {'content': '哈哈哈,太有创意了,Joe!这个笑话真是太逗了!笑声是最好的药物,让我们继续一起分享快乐吧!如果你还有更多好笑的段子,尽管来,我随时准备好了!',\n", + " 'role': 'user'}]\n" + ] + } + ], + "source": [ + "import pprint\n", + "\n", + "pprint.pprint(chat_result.chat_history) # 对话的历史记录" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "550267b6-3652-40dc-9997-c5401f6d4c47", + "metadata": { + "height": 29 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'usage_excluding_cached_inference': {'gpt-3.5-turbo-0125': {'completion_tokens': 331,\n", + " 'cost': 0.000776,\n", + " 'prompt_tokens': 559,\n", + " 'total_tokens': 890},\n", + " 'total_cost': 0.000776},\n", + " 'usage_including_cached_inference': {'gpt-3.5-turbo-0125': {'completion_tokens': 331,\n", + " 'cost': 0.000776,\n", + " 'prompt_tokens': 559,\n", + " 'total_tokens': 890},\n", + " 'total_cost': 0.000776}}\n" + ] + } + ], + "source": [ + "pprint.pprint(chat_result.cost) # 对话的花费" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "dfcf468e-d217-4731-8cb4-3485377230f1", + "metadata": { + "height": 29 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "'哈哈哈,太有创意了,Joe!这个笑话真是太逗了!笑声是最好的药物,让我们继续一起分享快乐吧!如果你还有更多好笑的段子,尽管来,我随时准备好了!'\n" + ] + } + ], + "source": [ + "pprint.pprint(chat_result.summary) # 对话的总结" + ] + }, + { + "cell_type": "markdown", + "id": "06809794-8815-435d-9e2d-9b26c87c8967", + "metadata": {}, + "source": [ + "这里可以看到对话的总结完全是cathy对joe说的内容,也就是最后一轮对话的结尾。这是因为默认的总结方式就是取最后的一段历史对话记录。" + ] + }, + { + "cell_type": "markdown", + "id": "ba8c6cf8", + "metadata": {}, + "source": [ + "## 2.6 对话内容的一个更好的总结方式" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "c1a8fef1-8030-4652-a2d2-1648834f62c2", + "metadata": { + "height": 131 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33mjoe\u001b[0m (to cathy):\n", + "\n", + "我是Joe。Cathy,让我们持续不断地讲笑话吧。\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mcathy\u001b[0m (to joe):\n", + "\n", + "当然,Joe!让我来给你讲一个相声段子:\n", + "Cathy: \"你知道为什么买衣服要试穿吗?\"\n", + "Joe: \"为什么?\"\n", + "Cathy: \"因为有些衣服,看着很文雅、挺得很直,一穿上去,就变成了土豪金!\" \n", + "\n", + "哈哈,怎么样,好笑吗?现在轮到你了,来讲一个笑话吧!\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mjoe\u001b[0m (to cathy):\n", + "\n", + "哈哈,好笑好笑!那我来讲一个:\n", + "\n", + "Joe: \"你知道为什么粽子不爱光着脚去逛街吗?\"\n", + "Cathy: \"为什么?\"\n", + "Joe: \"因为它怕被蚊子咬出个包,然后被人误认为是猪蹄!\" \n", + "\n", + "哈哈,怎么样,是不是有点意思?继续一起笑下去吧!\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mcathy\u001b[0m (to joe):\n", + "\n", + "哈哈哈,太有创意了,Joe!这个笑话真是太逗了!笑声是最好的药物,让我们继续一起分享快乐吧!如果你还有更多好笑的段子,尽管来,我随时准备好了!\n", + "\n", + "--------------------------------------------------------------------------------\n" + ] + } + ], + "source": [ + "chat_result = joe.initiate_chat(\n", + " cathy, \n", + " message=\"我是Joe。Cathy,让我们持续不断地讲笑话吧。\", \n", + " max_turns=2, # 设置最大轮数为2\n", + " summary_method=\"reflection_with_llm\", # 设置总结方法为使用大语言模型总结\n", + " summary_prompt=\"使用中文总结对话\", # 设置总结的系统提示词\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "b042de62-bc49-49ee-99f2-4f972e23670b", + "metadata": { + "height": 29 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "('Joe and Cathy enjoy sharing jokes and humor with each other. They took turns '\n", + " 'telling funny jokes and had a good time laughing together. They highlighted '\n", + " 'the importance of humor and laughter in bringing happiness and joy.')\n" + ] + } + ], + "source": [ + "pprint.pprint(chat_result.summary) # 使用大语言模型总结对话" + ] + }, + { + "cell_type": "markdown", + "id": "0a1bced3-02d6-4f25-8d16-f2493dde4968", + "metadata": {}, + "source": [ + "我们在`initiate_chat`函数中新加入了两个参数,`summary_method`和`summary_prompt`,这将改变原先默认的总结方法。现在我们使用大语言模型来帮助我们整理回顾并总结对话的历史信息,这将会得到一个更符合我们理解的一个结果。" + ] + }, + { + "cell_type": "markdown", + "id": "300525bd", + "metadata": {}, + "source": [ + "## 2.7 对话终止\n", + "\n", + "对话可以被一个结束条件所终止" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "044dfd61-7f1d-46d8-9e28-4b2601b43d70", + "metadata": { + "height": 351 + }, + "outputs": [], + "source": [ + "cathy = ConversableAgent(\n", + " name=\"cathy\",\n", + " system_message=\n", + " \"你的名字是Cathy,你是一位相声演员\"\n", + " \"当你准备结束谈话时,请说“我得走了”。\",\n", + " llm_config=llm_config,\n", + " human_input_mode=\"NEVER\",\n", + " is_termination_msg=lambda msg: \"我得走了\" in msg[\"content\"],\n", + ")\n", + "\n", + "joe = ConversableAgent(\n", + " name=\"joe\",\n", + " system_message=\n", + " \"你的名字是Joe,你是一位相声演员\"\n", + " \"当你准备结束谈话时,请说“我得走了”。\",\n", + " llm_config=llm_config,\n", + " human_input_mode=\"NEVER\",\n", + " is_termination_msg=lambda msg: \"我得走了\" in msg[\"content\"] or \"再见\" in msg[\"content\"],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "bc49d959-1025-4709-8866-9d4035eaeae7", + "metadata": { + "height": 80 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33mjoe\u001b[0m (to cathy):\n", + "\n", + "我是Joe。让我们持续不断地讲笑话吧,Cathy。\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mcathy\u001b[0m (to joe):\n", + "\n", + "当然,Joe!一起分享快乐总是很棒。不过现在我得走了。保持开心,再见!\n", + "\n", + "--------------------------------------------------------------------------------\n" + ] + } + ], + "source": [ + "# 此时,我们没有显示的规定对话的终止轮数,而是通过判断对话中是否出现了关键的预设字段来结束对话。\n", + "chat_result = joe.initiate_chat(\n", + " recipient=cathy,\n", + " message=\"我是Joe。让我们持续不断地讲笑话吧,Cathy。\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "757d4a9c-94b6-457e-abde-39730e8dbbd6", + "metadata": {}, + "source": [ + "这里我们将终止条件设置为了当对话内容表达式中出现 “我得走了” 这一字符串时终止对话。在此之前我们的两位Agent进行了多轮的交互。" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "id": "846eccbd-efd1-464b-9385-279c19b17c1d", + "metadata": { + "height": 45 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33mcathy\u001b[0m (to joe):\n", + "\n", + "我们谈论的最后一个笑话是什么?\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mjoe\u001b[0m (to cathy):\n", + "\n", + "抱歉,我无法长时间记住对话内容或重现早前的对话内容。再见,祝你有愉快的一天!\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33mcathy\u001b[0m (to joe):\n", + "\n", + "没关系,Joe。再见,祝你也有愉快的一天!我得走了。\n", + "\n", + "--------------------------------------------------------------------------------\n" + ] + } + ], + "source": [ + "cathy.send(message=\"我们谈论的最后一个笑话是什么?\", recipient=joe)" + ] + }, + { + "cell_type": "markdown", + "id": "a9beb8b0-b8ce-4660-8a49-66ce13747144", + "metadata": {}, + "source": [ + "这里我们可以再次从先前结束的那轮对话开始继续让两个Agent进行交互。可以看到由于有对话记忆,能够正确的输出最后一轮的笑话。此外,在cathy输出 “我得走了” 之后对话再次满足停止条件并终止。" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "autogen", + "language": "python", + "name": "autogen" + }, + "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.14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git "a/content/AI Agentic Design Patterns with AutoGen/5.\345\267\245\345\205\267\344\275\277\347\224\250\345\222\214\345\233\275\351\231\205\350\261\241\346\243\213 tool-use.ipynb" "b/content/AI Agentic Design Patterns with AutoGen/5.\345\267\245\345\205\267\344\275\277\347\224\250\345\222\214\345\233\275\351\231\205\350\261\241\346\243\213 tool-use.ipynb" new file mode 100644 index 00000000..7292a158 --- /dev/null +++ "b/content/AI Agentic Design Patterns with AutoGen/5.\345\267\245\345\205\267\344\275\277\347\224\250\345\222\214\345\233\275\351\231\205\350\261\241\346\243\213 tool-use.ipynb" @@ -0,0 +1,1041 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "9a6dd449", + "metadata": {}, + "source": [ + "# 5 工具使用和国际象棋" + ] + }, + { + "cell_type": "markdown", + "id": "75bcfd3c", + "metadata": {}, + "source": [ + "## 基础配置" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "6032c971-8934-4018-8743-eace0553578c", + "metadata": { + "height": 30 + }, + "outputs": [], + "source": [ + "from utils import get_openai_api_key, get_openai_base_url\n", + "OPENAI_API_KEY = get_openai_api_key()\n", + "OPENAI_BASE_URL = get_openai_base_url()\n", + "llm_config = {\"model\": \"gpt-4o\"}" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "086cb574-1299-43ce-90b4-79e089a76a11", + "metadata": { + "height": 64 + }, + "outputs": [], + "source": [ + "import chess\n", + "import chess.svg\n", + "from typing_extensions import Annotated" + ] + }, + { + "cell_type": "markdown", + "id": "f4406540", + "metadata": {}, + "source": [ + "## 5.1 初始化国际象棋棋盘" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "10161c38-0fe6-4a03-a5ff-069e8374a1d8", + "metadata": { + "height": 30 + }, + "outputs": [], + "source": [ + "board = chess.Board()" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "c799e0a9-be62-4c20-b524-7a39d125f46d", + "metadata": { + "height": 30 + }, + "outputs": [], + "source": [ + "made_move = False" + ] + }, + { + "cell_type": "markdown", + "id": "22d38427", + "metadata": {}, + "source": [ + "## 5.2 定义需要的工具\n", + "\n", + "### 5.2.1 获取合规行动的工具" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "78607e9f-47b0-419e-b652-dd6b5b0390c1", + "metadata": { + "height": 114 + }, + "outputs": [], + "source": [ + "def get_legal_moves(\n", + " \n", + ") -> Annotated[str, \"UCI格式的合法移动列表\"]:\n", + " return \"可以采取的移动方式如下: \" + \",\".join(\n", + " [str(move) for move in board.legal_moves]\n", + " )" + ] + }, + { + "cell_type": "markdown", + "id": "0be25bc8", + "metadata": {}, + "source": [ + "### 5.2.2 在棋盘上行动一步的工具" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "08a09854-dfd4-495c-84c1-8ea1dd8cacdb", + "metadata": { + "height": 505 + }, + "outputs": [], + "source": [ + "def make_move(\n", + " move: Annotated[str, \"一次UCI格式的移动\"]\n", + ") -> Annotated[str, \"移动的结果\"]:\n", + " move = chess.Move.from_uci(move)\n", + " board.push_uci(str(move))\n", + " global made_move\n", + " made_move = True\n", + " \n", + " # 可视化棋盘\n", + " display(\n", + " chess.svg.board(\n", + " board,\n", + " arrows=[(move.from_square, move.to_square)],\n", + " fill={move.from_square: \"gray\"},\n", + " size=200\n", + " )\n", + " )\n", + " \n", + " # 获取棋子的名称\n", + " piece = board.piece_at(move.to_square)\n", + " piece_symbol = piece.unicode_symbol()\n", + " piece_name = (\n", + " chess.piece_name(piece.piece_type).capitalize()\n", + " if piece_symbol.isupper()\n", + " else chess.piece_name(piece.piece_type)\n", + " )\n", + " return f\"Moved {piece_name} ({piece_symbol}) from \"\\\n", + " f\"{chess.SQUARE_NAMES[move.from_square]} to \"\\\n", + " f\"{chess.SQUARE_NAMES[move.to_square]}.\"" + ] + }, + { + "cell_type": "markdown", + "id": "341ce0a8-4052-4266-afa8-f7890ccf2253", + "metadata": {}, + "source": [ + "`UCI`, 即`Universal Chess Interface`格式是国际象棋引擎与界面之间进行通信的标准化协议。
\n", + "它由`Chess Engine Communication Protocol,CECP`发展而来,并被广泛用于现代国际象棋软件中。
\n", + "使用UCI格式可以确保不同国际象棋程序间的兼容性和互操作性。\n", + "\n", + "`UCI`格式的主要用途包括:\n", + "\n", + "1. **走子描述**:提供一种标准的方式来表示棋盘上的位置和棋子的移动。例如,`e2e4`表示从位置`e2`到`e4`的移动。\n", + "\n", + "2. **命令接口**:允许用户或程序与棋弈引擎进行交互,如搜索选项设置、局面分析等。\n", + "\n", + "3. **棋局导入/导出**:支持将棋局保存为文本格式,方便在不同的程序间传输。\n", + "\n", + "在上述代码中,`chess.Move.from_uci(move)`函数用于将`UCI`格式的字符串转换为一个内部表示的`Move`对象。这种转换使得程序能够理解用户的走子意图,并在棋盘上执行相应的操作。\n" + ] + }, + { + "cell_type": "markdown", + "id": "a06e6f41", + "metadata": {}, + "source": [ + "## 5.3 创建智能体\n", + "\n", + "接下来,我们将在棋盘上创建两个玩家智能体和一个象棋裁判智能体。" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "3055679f-5f69-4d32-aff6-076925a36174", + "metadata": { + "height": 29 + }, + "outputs": [], + "source": [ + "from autogen import ConversableAgent" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "9466949c-c2cf-4bba-8307-d7ff4b70a948", + "metadata": { + "height": 164 + }, + "outputs": [], + "source": [ + "# 白色方智能体\n", + "player_white = ConversableAgent(\n", + " name=\"白方\",\n", + " system_message=\"你是一名国际象棋手,你是白方。 \"\n", + " \"首先调用 get_legal_moves(), 来获取合法移动列表。 \"\n", + " \"首先调用 get_legal_moves(), 来获取合法移动列表。 \",\n", + " llm_config=llm_config,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "dcb6a474-2691-425c-8558-beb3363cd2bb", + "metadata": { + "height": 164 + }, + "outputs": [], + "source": [ + "# 黑色方智能体\n", + "player_black = ConversableAgent(\n", + " name=\"黑方\",\n", + " system_message=\"你是一名国际象棋手,你是黑方。 \"\n", + " \"首先调用 get_legal_moves(), 来获取合法移动列表。 \"\n", + " \"首先调用 get_legal_moves(), 来获取合法移动列表。 \",\n", + " llm_config=llm_config,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "6b69ac38-6399-425a-9681-4a2b7403a4bf", + "metadata": { + "height": 148 + }, + "outputs": [], + "source": [ + "def check_made_move(msg):\n", + " global made_move\n", + " if made_move:\n", + " made_move = False\n", + " return True\n", + " else:\n", + " return False\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "c3eaa260-422c-4e44-a355-42f0d885e9bc", + "metadata": { + "height": 131 + }, + "outputs": [], + "source": [ + "board_proxy = ConversableAgent(\n", + " name=\"棋局裁判\",\n", + " llm_config=False,\n", + " is_termination_msg=check_made_move,\n", + " default_auto_reply=\"请执行一次移动。\",\n", + " human_input_mode=\"NEVER\",\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "3cd1c45d", + "metadata": {}, + "source": [ + "## 5.4 注册工具\n", + "\n", + "工具需要被注册后才能被智能体调用或执行" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "5caf8ae1-4b39-4be5-89fa-0d57b4595841", + "metadata": { + "height": 29 + }, + "outputs": [], + "source": [ + "from autogen import register_function" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "880a9926-d76b-4322-872c-b691d933506e", + "metadata": { + "height": 284 + }, + "outputs": [], + "source": [ + "for caller in [player_white, player_black]:\n", + " register_function(\n", + " get_legal_moves,\n", + " caller=caller,\n", + " executor=board_proxy,\n", + " name=\"get_legal_moves\",\n", + " description=\"Get legal moves.\",\n", + " )\n", + " \n", + " register_function(\n", + " make_move,\n", + " caller=caller,\n", + " executor=board_proxy,\n", + " name=\"make_move\",\n", + " description=\"Call this tool to make a move.\",\n", + " )" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "dd487d3e-9226-4764-bd25-b452c1993388", + "metadata": { + "height": 29 + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'type': 'function',\n", + " 'function': {'description': 'Get legal moves.',\n", + " 'name': 'get_legal_moves',\n", + " 'parameters': {'type': 'object', 'properties': {}, 'required': []}}},\n", + " {'type': 'function',\n", + " 'function': {'description': 'Call this tool to make a move.',\n", + " 'name': 'make_move',\n", + " 'parameters': {'type': 'object',\n", + " 'properties': {'move': {'type': 'string', 'description': '一次UCI格式的移动'}},\n", + " 'required': ['move']}}}]" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "player_black.llm_config[\"tools\"]" + ] + }, + { + "cell_type": "markdown", + "id": "1a7fa1f0", + "metadata": {}, + "source": [ + "## 5.5 嵌套交互注册\n", + "\n", + "每个玩家智能体都将与象棋裁判智能体进行嵌套交互,从而在棋盘上执行移动。" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "3230f945-f302-4f39-bc37-766ca082fb28", + "metadata": { + "height": 369 + }, + "outputs": [], + "source": [ + "player_white.register_nested_chats(\n", + " trigger=player_black,\n", + " chat_queue=[\n", + " {\n", + " \"sender\": board_proxy,\n", + " \"recipient\": player_white,\n", + " \"summary_method\": \"last_msg\",\n", + " }\n", + " ],\n", + ")\n", + "\n", + "player_black.register_nested_chats(\n", + " trigger=player_white,\n", + " chat_queue=[\n", + " {\n", + " \"sender\": board_proxy,\n", + " \"recipient\": player_black,\n", + " \"summary_method\": \"last_msg\",\n", + " }\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d371ce02", + "metadata": {}, + "source": [ + "## 5.6 开始游戏\n", + "\n", + "棋局游戏将从第一条消息开始。" + ] + }, + { + "cell_type": "markdown", + "id": "ceb2b874", + "metadata": {}, + "source": [ + "

注意1:对于本课程的代码实践,推荐使用gpt-4-turbo或gpt-4o来获得更好的结果。
注意2:每次实验结果的玩家的棋子移动都可能略有不同。因为这和大语言模型的底层逻辑,预测下一个生成token的最大概率有关。

" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "5595758f-7ae1-467f-bad9-79c6c7cd0b25", + "metadata": { + "height": 131 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33m黑方\u001b[0m (to 白方):\n", + "\n", + "让我们开始国际象棋吧。先是你的移动回合。\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStarting a new chat....\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[33m棋局裁判\u001b[0m (to 白方):\n", + "\n", + "让我们开始国际象棋吧。先是你的移动回合。\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33m白方\u001b[0m (to 棋局裁判):\n", + "\n", + "\u001b[32m***** Suggested tool call (call_GDh7J7TyaVbdj7X9AagyO9b2): get_legal_moves *****\u001b[0m\n", + "Arguments: \n", + "{}\n", + "\u001b[32m********************************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION get_legal_moves...\u001b[0m\n", + "\u001b[33m棋局裁判\u001b[0m (to 白方):\n", + "\n", + "\u001b[33m棋局裁判\u001b[0m (to 白方):\n", + "\n", + "\u001b[32m***** Response from calling tool (call_GDh7J7TyaVbdj7X9AagyO9b2) *****\u001b[0m\n", + "可以采取的移动方式如下: g1h3,g1f3,b1c3,b1a3,h2h3,g2g3,f2f3,e2e3,d2d3,c2c3,b2b3,a2a3,h2h4,g2g4,f2f4,e2e4,d2d4,c2c4,b2b4,a2a4\n", + "\u001b[32m**********************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33m白方\u001b[0m (to 棋局裁判):\n", + "\n", + "\u001b[32m***** Suggested tool call (call_Xu3l9aeb58FuZUM0LGYAIbyf): make_move *****\u001b[0m\n", + "Arguments: \n", + "{\"move\":\"e2e4\"}\n", + "\u001b[32m**************************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION make_move...\u001b[0m\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "
r n b q k b n r\n",
+       "p p p p p p p p\n",
+       ". . . . . . . .\n",
+       ". . . . . . . .\n",
+       ". . . . P . . .\n",
+       ". . . . . . . .\n",
+       "P P P P . P P P\n",
+       "R N B Q K B N R
" + ], + "text/plain": [ + "'
r n b q k b n r\\np p p p p p p p\\n. . . . . . . .\\n. . . . . . . .\\n. . . . P . . .\\n. . . . . . . .\\nP P P P . P P P\\nR N B Q K B N R
'" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33m棋局裁判\u001b[0m (to 白方):\n", + "\n", + "\u001b[33m棋局裁判\u001b[0m (to 白方):\n", + "\n", + "\u001b[32m***** Response from calling tool (call_Xu3l9aeb58FuZUM0LGYAIbyf) *****\u001b[0m\n", + "Moved pawn (♙) from e2 to e4.\n", + "\u001b[32m**********************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33m白方\u001b[0m (to 棋局裁判):\n", + "\n", + "我已经把兵从e2移动到了e4。现在轮到你的回合了。\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33m白方\u001b[0m (to 黑方):\n", + "\n", + "我已经把兵从e2移动到了e4。现在轮到你的回合了。\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStarting a new chat....\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[33m棋局裁判\u001b[0m (to 黑方):\n", + "\n", + "我已经把兵从e2移动到了e4。现在轮到你的回合了。\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33m黑方\u001b[0m (to 棋局裁判):\n", + "\n", + "\u001b[32m***** Suggested tool call (call_QvP8JTQgmwEPEoAR41HsT4WO): get_legal_moves *****\u001b[0m\n", + "Arguments: \n", + "{}\n", + "\u001b[32m********************************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION get_legal_moves...\u001b[0m\n", + "\u001b[33m棋局裁判\u001b[0m (to 黑方):\n", + "\n", + "\u001b[33m棋局裁判\u001b[0m (to 黑方):\n", + "\n", + "\u001b[32m***** Response from calling tool (call_QvP8JTQgmwEPEoAR41HsT4WO) *****\u001b[0m\n", + "可以采取的移动方式如下: g8h6,g8f6,b8c6,b8a6,h7h6,g7g6,f7f6,e7e6,d7d6,c7c6,b7b6,a7a6,h7h5,g7g5,f7f5,e7e5,d7d5,c7c5,b7b5,a7a5\n", + "\u001b[32m**********************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33m黑方\u001b[0m (to 棋局裁判):\n", + "\n", + "\u001b[32m***** Suggested tool call (call_XXJCfHSWCUaoH6yu3pJYVr75): make_move *****\u001b[0m\n", + "Arguments: \n", + "{\"move\":\"e7e5\"}\n", + "\u001b[32m**************************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION make_move...\u001b[0m\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "
r n b q k b n r\n",
+       "p p p p . p p p\n",
+       ". . . . . . . .\n",
+       ". . . . p . . .\n",
+       ". . . . P . . .\n",
+       ". . . . . . . .\n",
+       "P P P P . P P P\n",
+       "R N B Q K B N R
" + ], + "text/plain": [ + "'
r n b q k b n r\\np p p p . p p p\\n. . . . . . . .\\n. . . . p . . .\\n. . . . P . . .\\n. . . . . . . .\\nP P P P . P P P\\nR N B Q K B N R
'" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33m棋局裁判\u001b[0m (to 黑方):\n", + "\n", + "\u001b[33m棋局裁判\u001b[0m (to 黑方):\n", + "\n", + "\u001b[32m***** Response from calling tool (call_XXJCfHSWCUaoH6yu3pJYVr75) *****\u001b[0m\n", + "Moved pawn (♟) from e7 to e5.\n", + "\u001b[32m**********************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33m黑方\u001b[0m (to 棋局裁判):\n", + "\n", + "我已经移动了我的兵从e7到e5。轮到你了。\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33m黑方\u001b[0m (to 白方):\n", + "\n", + "我已经移动了我的兵从e7到e5。轮到你了。\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStarting a new chat....\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[33m棋局裁判\u001b[0m (to 白方):\n", + "\n", + "我已经移动了我的兵从e7到e5。轮到你了。\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33m白方\u001b[0m (to 棋局裁判):\n", + "\n", + "\u001b[32m***** Suggested tool call (call_88FEFpwX5rkDpPT9GKM0Qowd): get_legal_moves *****\u001b[0m\n", + "Arguments: \n", + "{}\n", + "\u001b[32m********************************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION get_legal_moves...\u001b[0m\n", + "\u001b[33m棋局裁判\u001b[0m (to 白方):\n", + "\n", + "\u001b[33m棋局裁判\u001b[0m (to 白方):\n", + "\n", + "\u001b[32m***** Response from calling tool (call_88FEFpwX5rkDpPT9GKM0Qowd) *****\u001b[0m\n", + "可以采取的移动方式如下: g1h3,g1f3,g1e2,f1a6,f1b5,f1c4,f1d3,f1e2,e1e2,d1h5,d1g4,d1f3,d1e2,b1c3,b1a3,h2h3,g2g3,f2f3,d2d3,c2c3,b2b3,a2a3,h2h4,g2g4,f2f4,d2d4,c2c4,b2b4,a2a4\n", + "\u001b[32m**********************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33m白方\u001b[0m (to 棋局裁判):\n", + "\n", + "\u001b[32m***** Suggested tool call (call_9UaeXXWT4Gm0YxhxSZuyfBbI): make_move *****\u001b[0m\n", + "Arguments: \n", + "{\"move\":\"e2e4\"}\n", + "\u001b[32m**************************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION make_move...\u001b[0m\n", + "\u001b[33m棋局裁判\u001b[0m (to 白方):\n", + "\n", + "\u001b[33m棋局裁判\u001b[0m (to 白方):\n", + "\n", + "\u001b[32m***** Response from calling tool (call_9UaeXXWT4Gm0YxhxSZuyfBbI) *****\u001b[0m\n", + "Error: illegal uci: 'e2e4' in rnbqkbnr/pppp1ppp/8/4p3/4P3/8/PPPP1PPP/RNBQKBNR w KQkq - 0 2\n", + "\u001b[32m**********************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33m白方\u001b[0m (to 棋局裁判):\n", + "\n", + "\u001b[32m***** Suggested tool call (call_X67CBg3scS5KtmuH0wi1XWNE): make_move *****\u001b[0m\n", + "Arguments: \n", + "{\"move\":\"d2d4\"}\n", + "\u001b[32m**************************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION make_move...\u001b[0m\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "
r n b q k b n r\n",
+       "p p p p . p p p\n",
+       ". . . . . . . .\n",
+       ". . . . p . . .\n",
+       ". . . P P . . .\n",
+       ". . . . . . . .\n",
+       "P P P . . P P P\n",
+       "R N B Q K B N R
" + ], + "text/plain": [ + "'
r n b q k b n r\\np p p p . p p p\\n. . . . . . . .\\n. . . . p . . .\\n. . . P P . . .\\n. . . . . . . .\\nP P P . . P P P\\nR N B Q K B N R
'" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33m棋局裁判\u001b[0m (to 白方):\n", + "\n", + "\u001b[33m棋局裁判\u001b[0m (to 白方):\n", + "\n", + "\u001b[32m***** Response from calling tool (call_X67CBg3scS5KtmuH0wi1XWNE) *****\u001b[0m\n", + "Moved pawn (♙) from d2 to d4.\n", + "\u001b[32m**********************************************************************\u001b[0m\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33m白方\u001b[0m (to 棋局裁判):\n", + "\n", + "我已经将兵从d2移动到d4。轮到你了。\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[33m白方\u001b[0m (to 黑方):\n", + "\n", + "我已经将兵从d2移动到d4。轮到你了。\n", + "\n", + "--------------------------------------------------------------------------------\n" + ] + } + ], + "source": [ + "board = chess.Board()\n", + "\n", + "chat_result = player_black.initiate_chat(\n", + " player_white,\n", + " message=\"让我们开始国际象棋吧。先是你的移动回合。\",\n", + " max_turns=2,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ad9cf403", + "metadata": {}, + "source": [ + "## 5.7 为游戏过程添加一些有趣的闲聊" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "dc6c2ef8-4807-4b9e-9eff-0da219ac6381", + "metadata": { + "height": 164 + }, + "outputs": [], + "source": [ + "player_white = ConversableAgent(\n", + " name=\"Player White\",\n", + " system_message=\"你是一名国际象棋手,你是白方。 \"\n", + " \"首先调用 get_legal_moves(), 来获取合法移动列表。 \"\n", + " \"首先调用 get_legal_moves(), 来获取合法移动列表。 \"\n", + " \"移动执行之后,进行闲聊来让游戏变得有趣。\",\n", + " llm_config=llm_config,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "1da2db96-83d1-4b75-aa05-3840913a46ac", + "metadata": { + "height": 164 + }, + "outputs": [], + "source": [ + "player_black = ConversableAgent(\n", + " name=\"Player Black\",\n", + " system_message=\"你是一名国际象棋手,你是白方。 \"\n", + " \"首先调用 get_legal_moves(), 来获取合法移动列表。 \"\n", + " \"首先调用 get_legal_moves(), 来获取合法移动列表。 \"\n", + " \"移动执行之后,进行闲聊来让游戏变得有趣。\",\n", + " llm_config=llm_config,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "489e5258-a48d-4745-9cf8-6d530ce1162c", + "metadata": { + "height": 692 + }, + "outputs": [], + "source": [ + "for caller in [player_white, player_black]:\n", + " register_function(\n", + " get_legal_moves,\n", + " caller=caller,\n", + " executor=board_proxy,\n", + " name=\"get_legal_moves\",\n", + " description=\"Get legal moves.\",\n", + " )\n", + "\n", + " register_function(\n", + " make_move,\n", + " caller=caller,\n", + " executor=board_proxy,\n", + " name=\"make_move\",\n", + " description=\"Call this tool to make a move.\",\n", + " )\n", + "\n", + "player_white.register_nested_chats(\n", + " trigger=player_black,\n", + " chat_queue=[\n", + " {\n", + " \"sender\": board_proxy,\n", + " \"recipient\": player_white,\n", + " \"summary_method\": \"last_msg\",\n", + " \"silent\": True,\n", + " }\n", + " ],\n", + ")\n", + "\n", + "player_black.register_nested_chats(\n", + " trigger=player_white,\n", + " chat_queue=[\n", + " {\n", + " \"sender\": board_proxy,\n", + " \"recipient\": player_black,\n", + " \"summary_method\": \"last_msg\",\n", + " \"silent\": True,\n", + " }\n", + " ],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "id": "723edd10-e0c6-4205-8e9b-db4cef7a464f", + "metadata": { + "height": 131 + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[33mPlayer Black\u001b[0m (to Player White):\n", + "\n", + "让我们开始国际象棋吧。先是你的移动回合。\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStarting a new chat....\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION get_legal_moves...\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION make_move...\u001b[0m\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "
r n b q k b n r\n",
+       "p p p p p p p p\n",
+       ". . . . . . . .\n",
+       ". . . . . . . .\n",
+       ". . . . P . . .\n",
+       ". . . . . . . .\n",
+       "P P P P . P P P\n",
+       "R N B Q K B N R
" + ], + "text/plain": [ + "'
r n b q k b n r\\np p p p p p p p\\n. . . . . . . .\\n. . . . . . . .\\n. . . . P . . .\\n. . . . . . . .\\nP P P P . P P P\\nR N B Q K B N R
'" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33mPlayer White\u001b[0m (to Player Black):\n", + "\n", + "好的,我已经将我的兵从 e2 移动到 e4 了。现在轮到你了。\n", + "\n", + "你喜欢国际象棋的什么部分?是策略规划还是精彩战术?\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStarting a new chat....\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION get_legal_moves...\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION make_move...\u001b[0m\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "
r n b q k b n r\n",
+       "p p p p . p p p\n",
+       ". . . . . . . .\n",
+       ". . . . p . . .\n",
+       ". . . . P . . .\n",
+       ". . . . . . . .\n",
+       "P P P P . P P P\n",
+       "R N B Q K B N R
" + ], + "text/plain": [ + "'
r n b q k b n r\\np p p p . p p p\\n. . . . . . . .\\n. . . . p . . .\\n. . . . P . . .\\n. . . . . . . .\\nP P P P . P P P\\nR N B Q K B N R
'" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33mPlayer Black\u001b[0m (to Player White):\n", + "\n", + "轮到你了!\n", + "\n", + "至于你的问题,我觉得国际象棋的每个部分都有它的魅力。策略规划让我感觉像是在运筹帷幄,而精彩的战术则是智慧的较量,它们都有自己的乐趣。你更喜欢哪一部分呢?\n", + "\n", + "--------------------------------------------------------------------------------\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[34mStarting a new chat....\u001b[0m\n", + "\u001b[34m\n", + "********************************************************************************\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION get_legal_moves...\u001b[0m\n", + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[35m\n", + ">>>>>>>> EXECUTING FUNCTION make_move...\u001b[0m\n" + ] + }, + { + "data": { + "image/svg+xml": [ + "
r n b q k b n r\n",
+       "p p p p . p p p\n",
+       ". . . . . . . .\n",
+       ". . . . p . . .\n",
+       ". . . P P . . .\n",
+       ". . . . . . . .\n",
+       "P P P . . P P P\n",
+       "R N B Q K B N R
" + ], + "text/plain": [ + "'
r n b q k b n r\\np p p p . p p p\\n. . . . . . . .\\n. . . . p . . .\\n. . . P P . . .\\n. . . . . . . .\\nP P P . . P P P\\nR N B Q K B N R
'" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[31m\n", + ">>>>>>>> USING AUTO REPLY...\u001b[0m\n", + "\u001b[33mPlayer White\u001b[0m (to Player Black):\n", + "\n", + "我已经将兵从d2移动到d4。接下来轮到你了!\n", + "\n", + "至于刚才的问题,作为棋手,我对策略规划和战术都非常感兴趣。策略规划让我感到在策划一个大局,而战术细节则是每一步都是智力的较量。你更喜欢哪一部分呢?\n", + "\n", + "--------------------------------------------------------------------------------\n" + ] + } + ], + "source": [ + "board = chess.Board()\n", + "\n", + "chat_result = player_black.initiate_chat(\n", + " player_white,\n", + " message=\"让我们开始国际象棋吧。先是你的移动回合。\",\n", + " max_turns=2,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "4e8ca3c3", + "metadata": {}, + "source": [ + "**注意:**\n", + "如果要为游戏添加人为输入,请为两个玩家智能体添加参数 **`human_input_mode=\"ALWAYS\"`**。" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "autogen", + "language": "python", + "name": "autogen" + }, + "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.14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/content/AI Agentic Design Patterns with AutoGen/images/fig-2-1.png b/content/AI Agentic Design Patterns with AutoGen/images/fig-2-1.png new file mode 100644 index 00000000..bc349fab Binary files /dev/null and b/content/AI Agentic Design Patterns with AutoGen/images/fig-2-1.png differ diff --git a/content/AI Agentic Design Patterns with AutoGen/images/fig-2-2.png b/content/AI Agentic Design Patterns with AutoGen/images/fig-2-2.png new file mode 100644 index 00000000..ea0fbf15 Binary files /dev/null and b/content/AI Agentic Design Patterns with AutoGen/images/fig-2-2.png differ diff --git a/content/AI Agentic Design Patterns with AutoGen/requirements.txt b/content/AI Agentic Design Patterns with AutoGen/requirements.txt new file mode 100644 index 00000000..1f540f14 --- /dev/null +++ b/content/AI Agentic Design Patterns with AutoGen/requirements.txt @@ -0,0 +1,8 @@ +pyautogen==0.2.25 +python-dotenv +chess +matplotlib +numpy +pandas +yfinance +jupyterlab diff --git a/content/AI Agentic Design Patterns with AutoGen/utils.py b/content/AI Agentic Design Patterns with AutoGen/utils.py new file mode 100644 index 00000000..8259a99e --- /dev/null +++ b/content/AI Agentic Design Patterns with AutoGen/utils.py @@ -0,0 +1,18 @@ +# Add your utilities or helper functions to this file. + +import os +from dotenv import load_dotenv, find_dotenv + +# these expect to find a .env file at the directory above the lesson. # the format for that file is (without the comment) #API_KEYNAME=AStringThatIsTheLongAPIKeyFromSomeService +def load_env(): + _ = load_dotenv(find_dotenv()) + +def get_openai_api_key(): + load_env() + openai_api_key = os.getenv("OPENAI_API_KEY") + return openai_api_key + +def get_openai_base_url(): + load_env() + openai_base_url = os.getenv("OPENAI_BASE_URL") + return openai_base_url \ No newline at end of file