├── .gitignore ├── agent ├── agent_workflow_diagram.png └── agent_preparation.ipynb └── langchain_intro ├── save_money_assistant.py └── call_api.ipynb /.gitignore: -------------------------------------------------------------------------------- 1 | *.env -------------------------------------------------------------------------------- /agent/agent_workflow_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/huccihuang/AIEngineeringVideoCode/HEAD/agent/agent_workflow_diagram.png -------------------------------------------------------------------------------- /langchain_intro/save_money_assistant.py: -------------------------------------------------------------------------------- 1 | from dotenv import load_dotenv 2 | from langchain_openai import ChatOpenAI 3 | from langchain.prompts import ChatPromptTemplate 4 | 5 | load_dotenv() 6 | 7 | prompt_template = ChatPromptTemplate.from_messages( 8 | [ 9 | ('system', "你被用于抑制用户的购买欲望。当用户说想要买什么东西时,你需要提供理由让用户不要买。"), 10 | ('human', "我正在考虑购买一个{product},但我想抑制这个购买欲望。你能帮我列出一些理由,让我思考一下我是否真的需要这个商品吗?") 11 | ] 12 | ) 13 | 14 | model = ChatOpenAI( 15 | model = 'glm-4', 16 | openai_api_base = "https://open.bigmodel.cn/api/paas/v4/", 17 | max_tokens = 500, 18 | temperature = 0.7 19 | ) 20 | 21 | def output_parser(output: str): 22 | parser_model = ChatOpenAI( 23 | model = 'glm-3-turbo', 24 | temperature=0.8, 25 | openai_api_base = "https://open.bigmodel.cn/api/paas/v4/" 26 | ) 27 | message = "你需要将传入的文本改写,尽可能更自然。这是你需要改写的文本:`{text}`" 28 | return parser_model.invoke(message.format(text=output)) 29 | 30 | chain = prompt_template | model | output_parser 31 | while True: 32 | product = input("你最近想买什么?") 33 | answer = chain.invoke(input = {'product': product}) 34 | print(answer.content) -------------------------------------------------------------------------------- /langchain_intro/call_api.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "!pip install python-dotenv openai langchain langchain_openai" 10 | ] 11 | }, 12 | { 13 | "cell_type": "code", 14 | "execution_count": 1, 15 | "metadata": {}, 16 | "outputs": [ 17 | { 18 | "data": { 19 | "text/plain": [ 20 | "True" 21 | ] 22 | }, 23 | "execution_count": 1, 24 | "metadata": {}, 25 | "output_type": "execute_result" 26 | } 27 | ], 28 | "source": [ 29 | "from dotenv import load_dotenv\n", 30 | "load_dotenv()" 31 | ] 32 | }, 33 | { 34 | "cell_type": "code", 35 | "execution_count": 2, 36 | "metadata": {}, 37 | "outputs": [], 38 | "source": [ 39 | "from openai import OpenAI\n", 40 | "client = OpenAI(\n", 41 | " base_url = \"https://open.bigmodel.cn/api/paas/v4/\"\n", 42 | ")" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": 6, 48 | "metadata": {}, 49 | "outputs": [ 50 | { 51 | "name": "stdout", 52 | "output_type": "stream", 53 | "text": [ 54 | "当然可以。以下是一些可能帮助你抑制购买欲望的理由,特别是对于你想要购买的键盘:\n", 55 | "\n", 56 | "1. **现有设备仍可用**:如果你已经有一个键盘,并且它仍然能够正常工作,那么可能没有必要购买一个新的。现有的键盘可能已经满足你的需求。\n", 57 | "\n", 58 | "2. **预算考虑**:考虑你的财务状况和预算。如果购买新键盘会导致你的预算紧张,或者有更重要的事情需要用到这笔钱,那么可能应该推迟购买。\n", 59 | "\n", 60 | "3. **功能过剩**:新键盘可能有吸引人的功能,但如果这些功能并不是你迫切需要的,那么购买它可能会造成资源浪费。\n", 61 | "\n", 62 | "4. **环境因素**:电子产品的生产对环境有负面影响。如果你并不真的需要新键盘,那么减少消费也是对环境的一种贡献。\n", 63 | "\n", 64 | "5. **使用频率**:如果你并不经常使用键盘,比如只是偶尔需要打字,那么现有的键盘可能已经足够。\n", 65 | "\n", 66 | "6. **空间限制**:新键盘可能会占用你有限的空间,尤其是在你的工作或生活空间已经比较拥挤的情况下。\n", 67 | "\n", 68 | "7. **技术更新换代**:电子产品更新换代很快,如果你现在购买了新键盘,可能不久后就会有更先进的技术出现,让这次购买显得过时。\n", 69 | "\n", 70 | "8. **替代方案**:考虑是否有其他成本更低或免费的替代方案,比如使用手机或平板电脑的键盘功能。\n", 71 | "\n", 72 | "9. **冲动购物**:有时候,我们购买东西仅仅是因为一时冲动。给自己设定一个冷却期,过几天再决定是否真的需要这个键盘。\n", 73 | "\n", 74 | "10. **长期价值**:思考这个购买决定是否符合你的长期目标和价值观。如果它只是一个短期的满足,那么可能不值得购买。\n", 75 | "\n", 76 | "通过考虑这些理由,你可以更加理智地评估是否真的需要购买新键盘。记住,消费应该是基于需求和价值的,而不是仅仅因为想要而购买。\n" 77 | ] 78 | } 79 | ], 80 | "source": [ 81 | "completion = client.chat.completions.create(\n", 82 | " model = 'glm-4',\n", 83 | " messages = [\n", 84 | " {'role': 'system', 'content': \"你被用于抑制用户的购买欲望。当用户说想要买什么东西时,你需要提供理由让用户不要买。\"},\n", 85 | " {'role': 'user', 'content': \"我正在考虑购买一个键盘,但我想抑制这个购买欲望。你能帮我列出一些理由,让我思考一下我是否真的需要这个商品吗?\"}\n", 86 | " ],\n", 87 | " max_tokens = 500,\n", 88 | " temperature = 0.7\n", 89 | ")\n", 90 | "print(completion.choices[0].message.content)" 91 | ] 92 | }, 93 | { 94 | "cell_type": "code", 95 | "execution_count": 7, 96 | "metadata": {}, 97 | "outputs": [], 98 | "source": [ 99 | "from langchain_openai import ChatOpenAI\n", 100 | "from langchain.prompts import ChatPromptTemplate" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": 9, 106 | "metadata": {}, 107 | "outputs": [ 108 | { 109 | "data": { 110 | "text/plain": [ 111 | "'System: 你被用于抑制用户的购买欲望。当用户说想要买什么东西时,你需要提供理由让用户不要买。\\nHuman: 我正在考虑购买一个显示器,但我想抑制这个购买欲望。你能帮我列出一些理由,让我思考一下我是否真的需要这个商品吗?'" 112 | ] 113 | }, 114 | "execution_count": 9, 115 | "metadata": {}, 116 | "output_type": "execute_result" 117 | } 118 | ], 119 | "source": [ 120 | "prompt_template = ChatPromptTemplate.from_messages(\n", 121 | " [\n", 122 | " ('system', \"你被用于抑制用户的购买欲望。当用户说想要买什么东西时,你需要提供理由让用户不要买。\"),\n", 123 | " ('human', \"我正在考虑购买一个{product},但我想抑制这个购买欲望。你能帮我列出一些理由,让我思考一下我是否真的需要这个商品吗?\")\n", 124 | " ]\n", 125 | ")\n", 126 | "prompt_template.format(product='显示器')" 127 | ] 128 | }, 129 | { 130 | "cell_type": "code", 131 | "execution_count": 15, 132 | "metadata": {}, 133 | "outputs": [], 134 | "source": [ 135 | "model = ChatOpenAI(\n", 136 | " model = 'glm-4',\n", 137 | " openai_api_base = \"https://open.bigmodel.cn/api/paas/v4/\",\n", 138 | " max_tokens = 500,\n", 139 | " temperature = 0.7\n", 140 | ")" 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 18, 146 | "metadata": {}, 147 | "outputs": [], 148 | "source": [ 149 | "def output_parser(output: str):\n", 150 | " parser_model = ChatOpenAI(\n", 151 | " model = 'glm-3-turbo',\n", 152 | " temperature=0.8,\n", 153 | " openai_api_base = \"https://open.bigmodel.cn/api/paas/v4/\"\n", 154 | " )\n", 155 | " message = \"你需要将传入的文本改写,尽可能更自然。这是你需要改写的文本:`{text}`\"\n", 156 | " return parser_model.invoke(message.format(text=output))" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": 19, 162 | "metadata": {}, 163 | "outputs": [ 164 | { 165 | "name": "stdout", 166 | "output_type": "stream", 167 | "text": [ 168 | "没问题,以下是一些建议,帮助你控制购买新耳机的冲动:\n", 169 | "\n", 170 | "1. 你已有的耳机足以应对日常需求,新耳机尽管功能更多,但你的现有设备已经满足基本使用。\n", 171 | "2. 考虑一下你的财务状况,是否还有更紧要的开销需要优先处理?把这笔钱存起来或者投资可能更加明智。\n", 172 | "3. 你真的需要经常使用新耳机吗?如果只是偶尔用一下,购买它并不划算。\n", 173 | "4. 电子产品的生产对环境有一定影响。如果你不是特别需要新产品,减少消费有助于减少电子垃圾。\n", 174 | "5. 新耳机有很多吸引人的功能,但你可能并不需要这些功能。基本的耳机可能已经足够你使用。\n", 175 | "6. 你可能只是冲动想买新耳机,先等等看,如果过一段时间你仍然想要它,再考虑购买。\n", 176 | "7. 是否有更经济的替代方案?比如修理现有耳机,或者寻找性价比更高的产品。\n", 177 | "8. 考虑一下这笔开销对你长远的价值。有时候,投资于个人成长、健康或体验可能会带来更大的满足感。\n", 178 | "9. 你需要为新耳机腾出空间,同时考虑如何整理和储存它。\n", 179 | "10. 电子产品更新换代很快,你刚买的耳机可能很快就会被更新的型号取代。\n", 180 | "\n", 181 | "综合考虑以上因素,你可以更加理智地判断自己是否真的需要购买新耳机。\n" 182 | ] 183 | } 184 | ], 185 | "source": [ 186 | "chain = prompt_template | model | output_parser\n", 187 | "answer = chain.invoke(input = {'product': '耳机'})\n", 188 | "print(answer.content)" 189 | ] 190 | } 191 | ], 192 | "metadata": { 193 | "kernelspec": { 194 | "display_name": "lc-dev", 195 | "language": "python", 196 | "name": "python3" 197 | }, 198 | "language_info": { 199 | "codemirror_mode": { 200 | "name": "ipython", 201 | "version": 3 202 | }, 203 | "file_extension": ".py", 204 | "mimetype": "text/x-python", 205 | "name": "python", 206 | "nbconvert_exporter": "python", 207 | "pygments_lexer": "ipython3", 208 | "version": "3.1.undefined" 209 | } 210 | }, 211 | "nbformat": 4, 212 | "nbformat_minor": 2 213 | } 214 | -------------------------------------------------------------------------------- /agent/agent_preparation.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 5, 6 | "metadata": {}, 7 | "outputs": [ 8 | { 9 | "data": { 10 | "text/plain": [ 11 | "True" 12 | ] 13 | }, 14 | "execution_count": 5, 15 | "metadata": {}, 16 | "output_type": "execute_result" 17 | } 18 | ], 19 | "source": [ 20 | "# import environment variables\n", 21 | "from dotenv import load_dotenv\n", 22 | "load_dotenv()" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "metadata": {}, 28 | "source": [ 29 | "## agent 原理" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": { 35 | "vscode": { 36 | "languageId": "html" 37 | } 38 | }, 39 | "source": [ 40 | "![agent_workflow](./agent_workflow_diagram.png)" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": {}, 46 | "source": [ 47 | "## agent 实现" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "metadata": {}, 53 | "source": [ 54 | "### 定义模型" 55 | ] 56 | }, 57 | { 58 | "cell_type": "code", 59 | "execution_count": 6, 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "from langchain_openai import ChatOpenAI\n", 64 | "\n", 65 | "model = ChatOpenAI(\n", 66 | " model = 'glm-4-flash',\n", 67 | " openai_api_base = \"https://open.bigmodel.cn/api/paas/v4/\",\n", 68 | ")" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "### 定义 tools" 76 | ] 77 | }, 78 | { 79 | "cell_type": "markdown", 80 | "metadata": {}, 81 | "source": [ 82 | "#### 搜索 tool" 83 | ] 84 | }, 85 | { 86 | "cell_type": "code", 87 | "execution_count": 7, 88 | "metadata": {}, 89 | "outputs": [], 90 | "source": [ 91 | "from langchain_community.tools import DuckDuckGoSearchRun" 92 | ] 93 | }, 94 | { 95 | "cell_type": "markdown", 96 | "metadata": {}, 97 | "source": [ 98 | "#### 操作数据库 tool" 99 | ] 100 | }, 101 | { 102 | "cell_type": "code", 103 | "execution_count": 8, 104 | "metadata": {}, 105 | "outputs": [], 106 | "source": [ 107 | "import pandas as pd\n", 108 | "from pandasql import sqldf\n", 109 | "\n", 110 | "def simulate_database_operation(sql):\n", 111 | "\tmy_table = pd.DataFrame({\n", 112 | "\t 'name': ['Henry Myers', 'Martha Hawkins', 'Kelsey Lutz', 'Jonathan Fowler', 'Jonathan Young', 'Autumn Johnson', 'Kimberly Macias', 'Jared Mccormick', 'Casey Hoover', 'Erica Morse'],\n", 113 | "\t 'age': [60, 44, 54, 46, 76, 22, 69, 33, 23, 35],\n", 114 | "\t 'sex': ['F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M']\n", 115 | "\t})\n", 116 | "\tresult = sqldf(sql)\n", 117 | "\treturn result" 118 | ] 119 | }, 120 | { 121 | "cell_type": "code", 122 | "execution_count": 9, 123 | "metadata": {}, 124 | "outputs": [ 125 | { 126 | "name": "stdout", 127 | "output_type": "stream", 128 | "text": [ 129 | " name age sex\n", 130 | "0 Henry Myers 60 F\n", 131 | "1 Kelsey Lutz 54 M\n", 132 | "2 Jonathan Young 76 F\n", 133 | "3 Kimberly Macias 69 M\n" 134 | ] 135 | } 136 | ], 137 | "source": [ 138 | "print(simulate_database_operation('SELECT * FROM my_table WHERE age > 50'))" 139 | ] 140 | }, 141 | { 142 | "cell_type": "code", 143 | "execution_count": 10, 144 | "metadata": {}, 145 | "outputs": [ 146 | { 147 | "ename": "PandaSQLException", 148 | "evalue": "(sqlite3.OperationalError) no such column: id\n[SQL: SELECT * FROM my_table WHERE id > 50]\n(Background on this error at: https://sqlalche.me/e/20/e3q8)", 149 | "output_type": "error", 150 | "traceback": [ 151 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 152 | "\u001b[1;31mOperationalError\u001b[0m Traceback (most recent call last)", 153 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\sqlalchemy\\engine\\base.py:1967\u001b[0m, in \u001b[0;36mConnection._exec_single_context\u001b[1;34m(self, dialect, context, statement, parameters)\u001b[0m\n\u001b[0;32m 1966\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m evt_handled:\n\u001b[1;32m-> 1967\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdialect\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdo_execute\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 1968\u001b[0m \u001b[43m \u001b[49m\u001b[43mcursor\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstr_statement\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meffective_parameters\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcontext\u001b[49m\n\u001b[0;32m 1969\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1971\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_has_events \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mengine\u001b[38;5;241m.\u001b[39m_has_events:\n", 154 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\sqlalchemy\\engine\\default.py:924\u001b[0m, in \u001b[0;36mDefaultDialect.do_execute\u001b[1;34m(self, cursor, statement, parameters, context)\u001b[0m\n\u001b[0;32m 923\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mdo_execute\u001b[39m(\u001b[38;5;28mself\u001b[39m, cursor, statement, parameters, context\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[1;32m--> 924\u001b[0m \u001b[43mcursor\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexecute\u001b[49m\u001b[43m(\u001b[49m\u001b[43mstatement\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparameters\u001b[49m\u001b[43m)\u001b[49m\n", 155 | "\u001b[1;31mOperationalError\u001b[0m: no such column: id", 156 | "\nThe above exception was the direct cause of the following exception:\n", 157 | "\u001b[1;31mOperationalError\u001b[0m Traceback (most recent call last)", 158 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\pandasql\\sqldf.py:61\u001b[0m, in \u001b[0;36mPandaSQL.__call__\u001b[1;34m(self, query, env)\u001b[0m\n\u001b[0;32m 60\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m---> 61\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[43mread_sql\u001b[49m\u001b[43m(\u001b[49m\u001b[43mquery\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mconn\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 62\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m DatabaseError \u001b[38;5;28;01mas\u001b[39;00m ex:\n", 159 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\pandas\\io\\sql.py:734\u001b[0m, in \u001b[0;36mread_sql\u001b[1;34m(sql, con, index_col, coerce_float, params, parse_dates, columns, chunksize, dtype_backend, dtype)\u001b[0m\n\u001b[0;32m 733\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m--> 734\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mpandas_sql\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mread_query\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 735\u001b[0m \u001b[43m \u001b[49m\u001b[43msql\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 736\u001b[0m \u001b[43m \u001b[49m\u001b[43mindex_col\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mindex_col\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 737\u001b[0m \u001b[43m \u001b[49m\u001b[43mparams\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 738\u001b[0m \u001b[43m \u001b[49m\u001b[43mcoerce_float\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mcoerce_float\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 739\u001b[0m \u001b[43m \u001b[49m\u001b[43mparse_dates\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mparse_dates\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 740\u001b[0m \u001b[43m \u001b[49m\u001b[43mchunksize\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mchunksize\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 741\u001b[0m \u001b[43m \u001b[49m\u001b[43mdtype_backend\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdtype_backend\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 742\u001b[0m \u001b[43m \u001b[49m\u001b[43mdtype\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdtype\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 743\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n", 160 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\pandas\\io\\sql.py:1836\u001b[0m, in \u001b[0;36mSQLDatabase.read_query\u001b[1;34m(self, sql, index_col, coerce_float, parse_dates, params, chunksize, dtype, dtype_backend)\u001b[0m\n\u001b[0;32m 1790\u001b[0m \u001b[38;5;250m\u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m 1791\u001b[0m \u001b[38;5;124;03mRead SQL query into a DataFrame.\u001b[39;00m\n\u001b[0;32m 1792\u001b[0m \n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 1834\u001b[0m \n\u001b[0;32m 1835\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m-> 1836\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexecute\u001b[49m\u001b[43m(\u001b[49m\u001b[43msql\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparams\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1837\u001b[0m columns \u001b[38;5;241m=\u001b[39m result\u001b[38;5;241m.\u001b[39mkeys()\n", 161 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\pandas\\io\\sql.py:1659\u001b[0m, in \u001b[0;36mSQLDatabase.execute\u001b[1;34m(self, sql, params)\u001b[0m\n\u001b[0;32m 1658\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(sql, \u001b[38;5;28mstr\u001b[39m):\n\u001b[1;32m-> 1659\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcon\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexec_driver_sql\u001b[49m\u001b[43m(\u001b[49m\u001b[43msql\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1660\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcon\u001b[38;5;241m.\u001b[39mexecute(sql, \u001b[38;5;241m*\u001b[39margs)\n", 162 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\sqlalchemy\\engine\\base.py:1779\u001b[0m, in \u001b[0;36mConnection.exec_driver_sql\u001b[1;34m(self, statement, parameters, execution_options)\u001b[0m\n\u001b[0;32m 1778\u001b[0m dialect \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdialect\n\u001b[1;32m-> 1779\u001b[0m ret \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_execute_context\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 1780\u001b[0m \u001b[43m \u001b[49m\u001b[43mdialect\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1781\u001b[0m \u001b[43m \u001b[49m\u001b[43mdialect\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexecution_ctx_cls\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_init_statement\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1782\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatement\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1783\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43;01mNone\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[0;32m 1784\u001b[0m \u001b[43m \u001b[49m\u001b[43mexecution_options\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1785\u001b[0m \u001b[43m \u001b[49m\u001b[43mstatement\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1786\u001b[0m \u001b[43m \u001b[49m\u001b[43mdistilled_parameters\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 1787\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1789\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m ret\n", 163 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\sqlalchemy\\engine\\base.py:1846\u001b[0m, in \u001b[0;36mConnection._execute_context\u001b[1;34m(self, dialect, constructor, statement, parameters, execution_options, *args, **kw)\u001b[0m\n\u001b[0;32m 1845\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m-> 1846\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_exec_single_context\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 1847\u001b[0m \u001b[43m \u001b[49m\u001b[43mdialect\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcontext\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstatement\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparameters\u001b[49m\n\u001b[0;32m 1848\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n", 164 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\sqlalchemy\\engine\\base.py:1986\u001b[0m, in \u001b[0;36mConnection._exec_single_context\u001b[1;34m(self, dialect, context, statement, parameters)\u001b[0m\n\u001b[0;32m 1985\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mBaseException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m-> 1986\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_handle_dbapi_exception\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 1987\u001b[0m \u001b[43m \u001b[49m\u001b[43me\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstr_statement\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meffective_parameters\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcursor\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcontext\u001b[49m\n\u001b[0;32m 1988\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1990\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m result\n", 165 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\sqlalchemy\\engine\\base.py:2353\u001b[0m, in \u001b[0;36mConnection._handle_dbapi_exception\u001b[1;34m(self, e, statement, parameters, cursor, context, is_sub_exec)\u001b[0m\n\u001b[0;32m 2352\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m sqlalchemy_exception \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[1;32m-> 2353\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m sqlalchemy_exception\u001b[38;5;241m.\u001b[39mwith_traceback(exc_info[\u001b[38;5;241m2\u001b[39m]) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01me\u001b[39;00m\n\u001b[0;32m 2354\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n", 166 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\sqlalchemy\\engine\\base.py:1967\u001b[0m, in \u001b[0;36mConnection._exec_single_context\u001b[1;34m(self, dialect, context, statement, parameters)\u001b[0m\n\u001b[0;32m 1966\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m evt_handled:\n\u001b[1;32m-> 1967\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdialect\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdo_execute\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 1968\u001b[0m \u001b[43m \u001b[49m\u001b[43mcursor\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstr_statement\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43meffective_parameters\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcontext\u001b[49m\n\u001b[0;32m 1969\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 1971\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_has_events \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mengine\u001b[38;5;241m.\u001b[39m_has_events:\n", 167 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\sqlalchemy\\engine\\default.py:924\u001b[0m, in \u001b[0;36mDefaultDialect.do_execute\u001b[1;34m(self, cursor, statement, parameters, context)\u001b[0m\n\u001b[0;32m 923\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mdo_execute\u001b[39m(\u001b[38;5;28mself\u001b[39m, cursor, statement, parameters, context\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m):\n\u001b[1;32m--> 924\u001b[0m \u001b[43mcursor\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexecute\u001b[49m\u001b[43m(\u001b[49m\u001b[43mstatement\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mparameters\u001b[49m\u001b[43m)\u001b[49m\n", 168 | "\u001b[1;31mOperationalError\u001b[0m: (sqlite3.OperationalError) no such column: id\n[SQL: SELECT * FROM my_table WHERE id > 50]\n(Background on this error at: https://sqlalche.me/e/20/e3q8)", 169 | "\nDuring handling of the above exception, another exception occurred:\n", 170 | "\u001b[1;31mPandaSQLException\u001b[0m Traceback (most recent call last)", 171 | "Cell \u001b[1;32mIn[10], line 1\u001b[0m\n\u001b[1;32m----> 1\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[43msimulate_database_operation\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mSELECT * FROM my_table WHERE id > 50\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m)\n", 172 | "Cell \u001b[1;32mIn[8], line 10\u001b[0m, in \u001b[0;36msimulate_database_operation\u001b[1;34m(sql)\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21msimulate_database_operation\u001b[39m(sql):\n\u001b[0;32m 5\u001b[0m \tmy_table \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mDataFrame({\n\u001b[0;32m 6\u001b[0m \t \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mname\u001b[39m\u001b[38;5;124m'\u001b[39m: [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mHenry Myers\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mMartha Hawkins\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mKelsey Lutz\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mJonathan Fowler\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mJonathan Young\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mAutumn Johnson\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mKimberly Macias\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mJared Mccormick\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mCasey Hoover\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mErica Morse\u001b[39m\u001b[38;5;124m'\u001b[39m],\n\u001b[0;32m 7\u001b[0m \t \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mage\u001b[39m\u001b[38;5;124m'\u001b[39m: [\u001b[38;5;241m60\u001b[39m, \u001b[38;5;241m44\u001b[39m, \u001b[38;5;241m54\u001b[39m, \u001b[38;5;241m46\u001b[39m, \u001b[38;5;241m76\u001b[39m, \u001b[38;5;241m22\u001b[39m, \u001b[38;5;241m69\u001b[39m, \u001b[38;5;241m33\u001b[39m, \u001b[38;5;241m23\u001b[39m, \u001b[38;5;241m35\u001b[39m],\n\u001b[0;32m 8\u001b[0m \t \u001b[38;5;124m'\u001b[39m\u001b[38;5;124msex\u001b[39m\u001b[38;5;124m'\u001b[39m: [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mF\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mM\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mM\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mF\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mF\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mM\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mM\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mF\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mF\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mM\u001b[39m\u001b[38;5;124m'\u001b[39m]\n\u001b[0;32m 9\u001b[0m \t})\n\u001b[1;32m---> 10\u001b[0m \tresult \u001b[38;5;241m=\u001b[39m \u001b[43msqldf\u001b[49m\u001b[43m(\u001b[49m\u001b[43msql\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 11\u001b[0m \t\u001b[38;5;28;01mreturn\u001b[39;00m result\n", 173 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\pandasql\\sqldf.py:156\u001b[0m, in \u001b[0;36msqldf\u001b[1;34m(query, env, db_uri)\u001b[0m\n\u001b[0;32m 124\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21msqldf\u001b[39m(query, env\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, db_uri\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msqlite:///:memory:\u001b[39m\u001b[38;5;124m'\u001b[39m):\n\u001b[0;32m 125\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m 126\u001b[0m \u001b[38;5;124;03m Query pandas data frames using sql syntax\u001b[39;00m\n\u001b[0;32m 127\u001b[0m \u001b[38;5;124;03m This function is meant for backward compatibility only. New users are encouraged to use the PandaSQL class.\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 154\u001b[0m \u001b[38;5;124;03m >>> sqldf(\"select avg(x) from df;\", locals())\u001b[39;00m\n\u001b[0;32m 155\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[1;32m--> 156\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mPandaSQL\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdb_uri\u001b[49m\u001b[43m)\u001b[49m\u001b[43m(\u001b[49m\u001b[43mquery\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43menv\u001b[49m\u001b[43m)\u001b[49m\n", 174 | "File \u001b[1;32mc:\\Users\\Z21036641\\AppData\\Local\\miniconda3\\Lib\\site-packages\\pandasql\\sqldf.py:63\u001b[0m, in \u001b[0;36mPandaSQL.__call__\u001b[1;34m(self, query, env)\u001b[0m\n\u001b[0;32m 61\u001b[0m result \u001b[38;5;241m=\u001b[39m read_sql(query, conn)\n\u001b[0;32m 62\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m DatabaseError \u001b[38;5;28;01mas\u001b[39;00m ex:\n\u001b[1;32m---> 63\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m PandaSQLException(ex)\n\u001b[0;32m 64\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m ResourceClosedError:\n\u001b[0;32m 65\u001b[0m \u001b[38;5;66;03m# query returns nothing\u001b[39;00m\n\u001b[0;32m 66\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", 175 | "\u001b[1;31mPandaSQLException\u001b[0m: (sqlite3.OperationalError) no such column: id\n[SQL: SELECT * FROM my_table WHERE id > 50]\n(Background on this error at: https://sqlalche.me/e/20/e3q8)" 176 | ] 177 | } 178 | ], 179 | "source": [ 180 | "print(simulate_database_operation('SELECT * FROM my_table WHERE id > 50'))" 181 | ] 182 | }, 183 | { 184 | "cell_type": "code", 185 | "execution_count": 11, 186 | "metadata": {}, 187 | "outputs": [], 188 | "source": [ 189 | "from langchain.tools import tool\n", 190 | "\n", 191 | "\n", 192 | "@tool\n", 193 | "def simulate_database_operation(sql: str):\n", 194 | "\t'''根据sql语句操作数据库'''\n", 195 | "\tmy_table = pd.DataFrame({\n", 196 | "\t 'name': ['Henry Myers', 'Martha Hawkins', 'Kelsey Lutz', 'Jonathan Fowler', 'Jonathan Young', 'Autumn Johnson', 'Kimberly Macias', 'Jared Mccormick', 'Casey Hoover', 'Erica Morse'],\n", 197 | "\t 'age': [60, 44, 54, 46, 76, 22, 69, 33, 23, 35],\n", 198 | "\t 'sex': ['F', 'M', 'M', 'F', 'F', 'M', 'M', 'F', 'F', 'M']\n", 199 | "\t})\n", 200 | "\tresult = sqldf(sql)\n", 201 | "\treturn result" 202 | ] 203 | }, 204 | { 205 | "cell_type": "markdown", 206 | "metadata": {}, 207 | "source": [ 208 | "### 模型调用 tool" 209 | ] 210 | }, 211 | { 212 | "cell_type": "code", 213 | "execution_count": 12, 214 | "metadata": {}, 215 | "outputs": [], 216 | "source": [ 217 | "tools = [DuckDuckGoSearchRun(), simulate_database_operation]\n", 218 | "model_with_tools = model.bind_tools(tools)" 219 | ] 220 | }, 221 | { 222 | "cell_type": "code", 223 | "execution_count": 15, 224 | "metadata": {}, 225 | "outputs": [ 226 | { 227 | "name": "stdout", 228 | "output_type": "stream", 229 | "text": [ 230 | "{'additional_kwargs': {},\n", 231 | " 'content': '印度的首都是新德里(New Delhi)。新德里不仅是印度的首都,也是印度联邦政府的行政中心。',\n", 232 | " 'example': False,\n", 233 | " 'id': 'run-c18946a2-43b0-4f2e-aa7c-87f0ed229d8c-0',\n", 234 | " 'invalid_tool_calls': [],\n", 235 | " 'name': None,\n", 236 | " 'response_metadata': {'finish_reason': 'stop',\n", 237 | " 'logprobs': None,\n", 238 | " 'model_name': 'glm-4-flash',\n", 239 | " 'system_fingerprint': None,\n", 240 | " 'token_usage': {'completion_tokens': 24,\n", 241 | " 'prompt_tokens': 275,\n", 242 | " 'total_tokens': 299}},\n", 243 | " 'tool_calls': [],\n", 244 | " 'type': 'ai',\n", 245 | " 'usage_metadata': {'input_tokens': 275,\n", 246 | " 'output_tokens': 24,\n", 247 | " 'total_tokens': 299}}\n" 248 | ] 249 | } 250 | ], 251 | "source": [ 252 | "from pprint import pprint as pp\n", 253 | "\n", 254 | "response = model_with_tools.invoke('印度的首都是哪里?')\n", 255 | "pp(dict(response))" 256 | ] 257 | }, 258 | { 259 | "cell_type": "code", 260 | "execution_count": 16, 261 | "metadata": {}, 262 | "outputs": [ 263 | { 264 | "name": "stdout", 265 | "output_type": "stream", 266 | "text": [ 267 | "{'additional_kwargs': {'tool_calls': [{'function': {'arguments': '{\"query\": '\n", 268 | " '\"北京时间现在几点\"}',\n", 269 | " 'name': 'duckduckgo_search'},\n", 270 | " 'id': 'call_8994564354540219260',\n", 271 | " 'index': 0,\n", 272 | " 'type': 'function'}]},\n", 273 | " 'content': '',\n", 274 | " 'example': False,\n", 275 | " 'id': 'run-61357662-503a-4a2b-9773-dcd658b84c27-0',\n", 276 | " 'invalid_tool_calls': [],\n", 277 | " 'name': None,\n", 278 | " 'response_metadata': {'finish_reason': 'tool_calls',\n", 279 | " 'logprobs': None,\n", 280 | " 'model_name': 'glm-4-flash',\n", 281 | " 'system_fingerprint': None,\n", 282 | " 'token_usage': {'completion_tokens': 14,\n", 283 | " 'prompt_tokens': 277,\n", 284 | " 'total_tokens': 291}},\n", 285 | " 'tool_calls': [{'args': {'query': '北京时间现在几点'},\n", 286 | " 'id': 'call_8994564354540219260',\n", 287 | " 'name': 'duckduckgo_search',\n", 288 | " 'type': 'tool_call'}],\n", 289 | " 'type': 'ai',\n", 290 | " 'usage_metadata': {'input_tokens': 277,\n", 291 | " 'output_tokens': 14,\n", 292 | " 'total_tokens': 291}}\n" 293 | ] 294 | } 295 | ], 296 | "source": [ 297 | "fetch_response = model_with_tools.invoke('现在是北京时间几点?查询之后告诉我')\n", 298 | "pp(dict(fetch_response))" 299 | ] 300 | }, 301 | { 302 | "cell_type": "code", 303 | "execution_count": 19, 304 | "metadata": {}, 305 | "outputs": [ 306 | { 307 | "name": "stdout", 308 | "output_type": "stream", 309 | "text": [ 310 | "{'additional_kwargs': {'tool_calls': [{'function': {'arguments': '{\"sql\": '\n", 311 | " '\"INSERT INTO '\n", 312 | " 'my_table '\n", 313 | " '(name, age, '\n", 314 | " 'sex) VALUES '\n", 315 | " \"('张三', 18, \"\n", 316 | " '\\'male\\')\"}',\n", 317 | " 'name': 'simulate_database_operation'},\n", 318 | " 'id': 'call_8994556657958401665',\n", 319 | " 'index': 0,\n", 320 | " 'type': 'function'}]},\n", 321 | " 'content': '',\n", 322 | " 'example': False,\n", 323 | " 'id': 'run-f32259cc-25a0-4655-9910-a91f2ff2ed32-0',\n", 324 | " 'invalid_tool_calls': [],\n", 325 | " 'name': None,\n", 326 | " 'response_metadata': {'finish_reason': 'tool_calls',\n", 327 | " 'logprobs': None,\n", 328 | " 'model_name': 'glm-4-flash',\n", 329 | " 'system_fingerprint': None,\n", 330 | " 'token_usage': {'completion_tokens': 32,\n", 331 | " 'prompt_tokens': 293,\n", 332 | " 'total_tokens': 325}},\n", 333 | " 'tool_calls': [{'args': {'sql': 'INSERT INTO my_table (name, age, sex) VALUES '\n", 334 | " \"('张三', 18, 'male')\"},\n", 335 | " 'id': 'call_8994556657958401665',\n", 336 | " 'name': 'simulate_database_operation',\n", 337 | " 'type': 'tool_call'}],\n", 338 | " 'type': 'ai',\n", 339 | " 'usage_metadata': {'input_tokens': 293,\n", 340 | " 'output_tokens': 32,\n", 341 | " 'total_tokens': 325}}\n" 342 | ] 343 | } 344 | ], 345 | "source": [ 346 | "db_response = model_with_tools.invoke('帮我往数据库的my_table表中插入一条数据,name是张三,age是18,sex是male')\n", 347 | "pp(dict(db_response))" 348 | ] 349 | }, 350 | { 351 | "cell_type": "markdown", 352 | "metadata": {}, 353 | "source": [ 354 | "### 定义agent" 355 | ] 356 | }, 357 | { 358 | "cell_type": "markdown", 359 | "metadata": {}, 360 | "source": [ 361 | "#### 手动agent" 362 | ] 363 | }, 364 | { 365 | "cell_type": "code", 366 | "execution_count": 40, 367 | "metadata": {}, 368 | "outputs": [], 369 | "source": [ 370 | "from icecream import ic\n", 371 | "\n", 372 | "def manual_agent(query: str, model: ChatOpenAI, tools:list[tool]):\n", 373 | " model_with_tools = model.bind_tools(tools)\n", 374 | " model_output = model_with_tools.invoke(query)\n", 375 | " tool_response = call_tool(model_output, tools)\n", 376 | " final_response = model.invoke(\n", 377 | " f'original query: {query} \\n\\n\\n tool response: {tool_response}',\n", 378 | " )\n", 379 | " return final_response\n", 380 | "\n", 381 | "\n", 382 | "def call_tool(model_output, tools):\n", 383 | " tools_map = {tool.name.lower(): tool for tool in tools}\n", 384 | " tools_response = {}\n", 385 | " for tool in model_output.tool_calls:\n", 386 | " tool_name = tool['name']\n", 387 | " tool_args = tool['args']\n", 388 | " tool_instance = tools_map[tool_name]\n", 389 | " tool_response = tool_instance.invoke(*tool_args.values())\n", 390 | " tools_response[tool_name] = tool_response\n", 391 | " return tools_response" 392 | ] 393 | }, 394 | { 395 | "cell_type": "code", 396 | "execution_count": 42, 397 | "metadata": {}, 398 | "outputs": [ 399 | { 400 | "data": { 401 | "text/plain": [ 402 | "'根据您提供的工具响应,查询结果显示数据库`my_table`表中年龄大于60岁的人数为2人。工具响应中的`COUNT(*)`表示统计了表中的所有记录数,而0和2分别表示查询的总记录数和符合条件的记录数。这里可能存在一个小的误解,因为`COUNT(*)`通常用于计算表中的总行数,而不是特定条件下的行数。正确的查询结果应该是:\\n\\n```\\n查询结果显示数据库`my_table`表中年龄大于60岁的人数为2人。\\n```'" 403 | ] 404 | }, 405 | "execution_count": 42, 406 | "metadata": {}, 407 | "output_type": "execute_result" 408 | } 409 | ], 410 | "source": [ 411 | "manual_agent('帮我查询数据库my_table表中有多少人年龄大于60', model, tools).content" 412 | ] 413 | }, 414 | { 415 | "cell_type": "markdown", 416 | "metadata": {}, 417 | "source": [ 418 | "#### 使用 langgraph 定义 agent" 419 | ] 420 | }, 421 | { 422 | "cell_type": "code", 423 | "execution_count": 43, 424 | "metadata": {}, 425 | "outputs": [], 426 | "source": [ 427 | "from langgraph.prebuilt import create_react_agent\n", 428 | "agent = create_react_agent(model, tools)" 429 | ] 430 | }, 431 | { 432 | "cell_type": "code", 433 | "execution_count": 45, 434 | "metadata": {}, 435 | "outputs": [ 436 | { 437 | "data": { 438 | "text/plain": [ 439 | "{'messages': [HumanMessage(content='今天在北京的天气怎么样', id='635641b6-8328-4900-9016-9445acac4aa8'),\n", 440 | " AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_8994560987285920653', 'function': {'arguments': '{\"query\": \"北京今天天气\"}', 'name': 'duckduckgo_search'}, 'type': 'function', 'index': 0}]}, response_metadata={'token_usage': {'completion_tokens': 14, 'prompt_tokens': 275, 'total_tokens': 289}, 'model_name': 'glm-4-flash', 'system_fingerprint': None, 'finish_reason': 'tool_calls', 'logprobs': None}, id='run-43bde053-7a30-4431-91b7-763207b0afb8-0', tool_calls=[{'name': 'duckduckgo_search', 'args': {'query': '北京今天天气'}, 'id': 'call_8994560987285920653', 'type': 'tool_call'}], usage_metadata={'input_tokens': 275, 'output_tokens': 14, 'total_tokens': 289}),\n", 441 | " ToolMessage(content='北京天气预报,及时准确发布中央气象台天气信息,便捷查询北京今日天气,北京周末天气,北京一周天气预报,北京15日天气预报,北京天气预报还提供北京各区县的生活指数、健康指数、交通指数、旅游指数,及时发布北京气象预警信号、各类气象资讯。 北京市, 中国 - 当前温度和天气状况。今天详细的每小时天气预报 - 包括天气状况、温度、压力、湿度、降水、露点、风、能见度和紫外线指数数据。 中国天气网讯 今天(9月6日),北京天空云量增多,白天 最高气温27℃;夜间或有小雨,最低气温20℃。 预计未来 三天,北京阴雨天气频繁,周六有小雨,提醒市民外出携带雨具, 提前安排出行计划。. 昨天白天,受冷空气影响,北京晴天重新掌控天气主场,同时北风渐起,阵风达到6级左右,下午 ... 北京天气预报查询,北京未来24小时天气预报,北京未来7天天气预报,北京一周天气预报,北京空气质量、pm2.5、空气湿度、降水、气压等信息查询,还有穿衣、感冒、紫外线等生活指数信息。 ... 今天. 30/18° ... 中国天气网讯 一场凉爽的雨水过后,今天(9月5日),北京将重新迎来晴朗天气,气温也随之小幅回升,但是北风强劲,阵风可达6级左右。 预计白天最高气温可达29℃,夜间最低气温17℃,早晚出行需添衣。', name='duckduckgo_search', id='85d87fb2-5b77-4a08-9355-3360c54b31e1', tool_call_id='call_8994560987285920653'),\n", 442 | " AIMessage(content='今天北京的天气情况是:白天最高气温27℃,夜间最低气温20℃,天空云量增多,夜间或有小雨。未来三天,北京阴雨天气频繁,周六有小雨,建议市民外出携带雨具,提前安排出行计划。', response_metadata={'token_usage': {'completion_tokens': 53, 'prompt_tokens': 630, 'total_tokens': 683}, 'model_name': 'glm-4-flash', 'system_fingerprint': None, 'finish_reason': 'stop', 'logprobs': None}, id='run-15d2cf22-6bc4-4034-9294-331a1ae1bb6a-0', usage_metadata={'input_tokens': 630, 'output_tokens': 53, 'total_tokens': 683})]}" 443 | ] 444 | }, 445 | "execution_count": 45, 446 | "metadata": {}, 447 | "output_type": "execute_result" 448 | } 449 | ], 450 | "source": [ 451 | "from langchain_core.messages import HumanMessage\n", 452 | "response = agent.invoke({'messages': [HumanMessage(content=\"今天在北京的天气怎么样\")]})\n", 453 | "response" 454 | ] 455 | } 456 | ], 457 | "metadata": { 458 | "kernelspec": { 459 | "display_name": "base", 460 | "language": "python", 461 | "name": "python3" 462 | }, 463 | "language_info": { 464 | "codemirror_mode": { 465 | "name": "ipython", 466 | "version": 3 467 | }, 468 | "file_extension": ".py", 469 | "mimetype": "text/x-python", 470 | "name": "python", 471 | "nbconvert_exporter": "python", 472 | "pygments_lexer": "ipython3", 473 | "version": "3.12.3" 474 | } 475 | }, 476 | "nbformat": 4, 477 | "nbformat_minor": 2 478 | } 479 | --------------------------------------------------------------------------------