Kaynağa Gözat

agno练习+转账agent

iTTsShuu 1 ay önce
ebeveyn
işleme
5388e63135

BIN
transfer/tmp/agents.db


Dosya farkı çok büyük olduğundan ihmal edildi
+ 8 - 27
曹航/2/chatbot.ipynb


+ 17 - 25
曹航/3/agent_test1.ipynb

@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 8,
+   "execution_count": 1,
    "id": "8f58232e",
    "metadata": {},
    "outputs": [],
@@ -46,7 +46,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "b8dba8b1142d4e78b13a51496be46d95",
+       "model_id": "a917f0961fca4339bce6bb54a2e494c9",
        "version_major": 2,
        "version_minor": 0
       },
@@ -110,14 +110,14 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 3,
    "id": "389236b4",
    "metadata": {},
    "outputs": [
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "b1683a2f5e664bd58207674eae611741",
+       "model_id": "c557671b95194a308e03957184726d5f",
        "version_major": 2,
        "version_minor": 0
       },
@@ -392,14 +392,14 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 10,
+   "execution_count": 4,
    "id": "595e81bb",
    "metadata": {},
    "outputs": [
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "d30e05211dbc466caa6cfbe96855dd52",
+       "model_id": "15d791b433274c4ab422b583169426f5",
        "version_major": 2,
        "version_minor": 0
       },
@@ -423,7 +423,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "c1da05284d4b4438a77e421352c5274e",
+       "model_id": "17467c587eec477fb111cb58cb20dc82",
        "version_major": 2,
        "version_minor": 0
       },
@@ -447,7 +447,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "8c0296dac7464ca48c8ffbf97485c3fa",
+       "model_id": "d0c6a7cada684caa82ac98fd745f4990",
        "version_major": 2,
        "version_minor": 0
       },
@@ -471,7 +471,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "dde342ffffe6412bb7dd7de7a5e10063",
+       "model_id": "328410a4e1f144c2b19d0d286c247e0c",
        "version_major": 2,
        "version_minor": 0
       },
@@ -495,7 +495,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "f7d74a23df1b4396bcfb012cd1f88b03",
+       "model_id": "486e315eeb5e4130967fdcd53cdf5e1d",
        "version_major": 2,
        "version_minor": 0
       },
@@ -553,14 +553,14 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": null,
    "id": "54fce47a",
    "metadata": {},
    "outputs": [
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "a813b71508b3424eac865edc9902a814",
+       "model_id": "3bdc3e79f1444be680451ae5566bd84a",
        "version_major": 2,
        "version_minor": 0
       },
@@ -584,7 +584,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "8c38d9d97ddf4afe8a771cc80bb8264c",
+       "model_id": "9402012548f345c8899a30bb3c07a0a0",
        "version_major": 2,
        "version_minor": 0
       },
@@ -608,7 +608,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "c94473f3849348acaa1f3e6680cb81da",
+       "model_id": "6723870b70ec488c8c311ff3749060ef",
        "version_major": 2,
        "version_minor": 0
       },
@@ -632,7 +632,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "5c2cf0fb836d4dce9d70341053947065",
+       "model_id": "880b75df788f47fcb02dceacf699b090",
        "version_major": 2,
        "version_minor": 0
       },
@@ -656,7 +656,7 @@
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "d4081a2d82bb45df9682265dd5d0388c",
+       "model_id": "59643333ac1549dc97188ae1fdea365d",
        "version_major": 2,
        "version_minor": 0
       },
@@ -687,7 +687,7 @@
     "agent.user_id=\"user_shuu\"\n",
     "agent.search_previous_sessions_history=True\n",
     "agent.num_history_sessions=5\n",
-    "# agent.storage=SqliteStorage(table_name=\"agent_history\",db_file=\"temp/agent_history.db\")\n",
+    "agent.storage=SqliteStorage(table_name=\"agent_history\",db_file=\"temp/agent_history.db\")\n",
     "\n",
     "#session设置\n",
     "session_1_id = \"session_1_id\"\n",
@@ -704,14 +704,6 @@
     "    \"What did I discuss in my previous conversations?\", session_id=session_5_id,stream=True\n",
     ")  # It should only include the last 2 sessions"
    ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "7b06e0e2",
-   "metadata": {},
-   "source": [
-    "**Agent state**"
-   ]
   }
  ],
  "metadata": {

+ 153 - 488
曹航/3/agent_test2.ipynb

@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": 11,
+   "execution_count": 1,
    "id": "a4856341",
    "metadata": {},
    "outputs": [
@@ -12,25 +12,36 @@
        "True"
       ]
      },
-     "execution_count": 11,
+     "execution_count": 1,
      "metadata": {},
      "output_type": "execute_result"
     }
    ],
    "source": [
     "from textwrap import dedent\n",
+    "\n",
     "from agno.agent import Agent\n",
-    "from dotenv import load_dotenv \n",
     "from agno.models.openai import OpenAILike\n",
     "from agno.memory.v2.db.sqlite import SqliteMemoryDb\n",
+    "from agno.exceptions import StopAgentRun\n",
     "from agno.memory.v2.memory import Memory\n",
-    "from rich.pretty import pprint\n",
+    "from agno.tools import tool,FunctionCall\n",
+    "from agno.tools.dalle import DalleTools\n",
     "from agno.storage.sqlite import SqliteStorage\n",
-    "from typing import List,Dict\n",
+    "\n",
+    "from dotenv import load_dotenv \n",
+    "\n",
+    "from typing import List,Iterator\n",
     "from pydantic import BaseModel, Field\n",
+    "\n",
+    "from rich.console import Console\n",
+    "from rich.prompt import Prompt\n",
+    "from rich.pretty import pprint\n",
+    "\n",
+    "import httpx\n",
     "import os\n",
-    "load_dotenv()\n",
-    "\n"
+    "import json\n",
+    "load_dotenv()\n"
    ]
   },
   {
@@ -43,14 +54,14 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 2,
    "id": "46403d1a",
    "metadata": {},
    "outputs": [
     {
      "data": {
       "application/vnd.jupyter.widget-view+json": {
-       "model_id": "9b3d2e36a97047dcaf90b8a373c1c2c1",
+       "model_id": "b5e36e3099374134807dcb494a113ff1",
        "version_major": 2,
        "version_minor": 0
       },
@@ -75,7 +86,7 @@
      "name": "stdout",
      "output_type": "stream",
      "text": [
-      "Final session state: {'shopping_list': ['milk', 'eggs', 'bread'], 'current_session_id': 'fb205638-5e39-40e7-8722-1aedcd7995e0'}\n"
+      "Final session state: {'shopping_list': ['milk', 'eggs', 'bread'], 'current_session_id': 'c0e056e2-5ea1-4e62-a955-227f6485ffa6'}\n"
      ]
     }
    ],
@@ -113,168 +124,13 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 6,
+   "execution_count": null,
    "id": "8e7e7a5b",
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "application/vnd.jupyter.widget-view+json": {
-       "model_id": "1dbdd22b0ef44e0ca820d7469715ad9c",
-       "version_major": 2,
-       "version_minor": 0
-      },
-      "text/plain": [
-       "Output()"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
-      ],
-      "text/plain": []
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Session state: {'shopping_list': ['milk', 'eggs', 'bread'], 'current_session_id': '7d5889cc-c85a-46a8-bd6d-617eb4fc56fb'}\n"
-     ]
-    },
-    {
-     "data": {
-      "application/vnd.jupyter.widget-view+json": {
-       "model_id": "df0130bb33ad4782a54af20fd62e96ca",
-       "version_major": 2,
-       "version_minor": 0
-      },
-      "text/plain": [
-       "Output()"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
-      ],
-      "text/plain": []
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Session state: {'shopping_list': ['milk', 'eggs'], 'current_session_id': '7d5889cc-c85a-46a8-bd6d-617eb4fc56fb'}\n"
-     ]
-    },
-    {
-     "data": {
-      "application/vnd.jupyter.widget-view+json": {
-       "model_id": "33b95577fd9a41f4b1ba01af0d8c9d16",
-       "version_major": 2,
-       "version_minor": 0
-      },
-      "text/plain": [
-       "Output()"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
-      ],
-      "text/plain": []
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Session state: {'shopping_list': ['milk', 'eggs', 'apples', 'oranges'], 'current_session_id': '7d5889cc-c85a-46a8-bd6d-617eb4fc56fb'}\n"
-     ]
-    },
-    {
-     "data": {
-      "application/vnd.jupyter.widget-view+json": {
-       "model_id": "22a01dc2c8cf44ca8fee0e64115ccf46",
-       "version_major": 2,
-       "version_minor": 0
-      },
-      "text/plain": [
-       "Output()"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
-      ],
-      "text/plain": []
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Session state: {'shopping_list': ['milk', 'eggs', 'apples', 'oranges'], 'current_session_id': '7d5889cc-c85a-46a8-bd6d-617eb4fc56fb'}\n"
-     ]
-    },
-    {
-     "data": {
-      "application/vnd.jupyter.widget-view+json": {
-       "model_id": "c3f890d603fa4dbb9497ec8481340014",
-       "version_major": 2,
-       "version_minor": 0
-      },
-      "text/plain": [
-       "Output()"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
-      ],
-      "text/plain": []
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Session state: {'shopping_list': ['bananas', 'yogurt'], 'current_session_id': '7d5889cc-c85a-46a8-bd6d-617eb4fc56fb'}\n"
-     ]
-    }
-   ],
+   "outputs": [],
    "source": [
     "# Define tools to manage our shopping list\n",
+    "@tool(description=\"Add an item to the shopping list.\")\n",
     "def add_item(agent: Agent, item: str) -> str:\n",
     "    \"\"\"Add an item to the shopping list and return confirmation.\"\"\"\n",
     "    # Add the item if it's not already in the list\n",
@@ -290,7 +146,7 @@
     "    else:\n",
     "        return f\"'{item}' is already in the shopping list\"\n",
     "\n",
-    "\n",
+    "@tool(description=\"Remove an item from the shopping list by name.\")\n",
     "def remove_item(agent: Agent, item: str) -> str:\n",
     "    \"\"\"Remove an item from the shopping list by name.\"\"\"\n",
     "    # Case-insensitive search\n",
@@ -306,7 +162,7 @@
     "\n",
     "    return f\"'{item}' was not found in the shopping list\"\n",
     "\n",
-    "\n",
+    "@tool(description=\"List all items in the shopping list.\")\n",
     "def list_items(agent: Agent) -> str:\n",
     "    \"\"\"List all items in the shopping list.\"\"\"\n",
     "    if agent.session_state is None:\n",
@@ -372,131 +228,10 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 14,
+   "execution_count": null,
    "id": "1f118e71",
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "application/vnd.jupyter.widget-view+json": {
-       "model_id": "c3b320b12c3540849310be03a5e4ae27",
-       "version_major": 2,
-       "version_minor": 0
-      },
-      "text/plain": [
-       "Output()"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
-      ],
-      "text/plain": []
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Memories about Ava:\n"
-     ]
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">[</span>\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   </span><span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">UserMemory</span><span style=\"font-weight: bold\">(</span>\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   │   </span><span style=\"color: #808000; text-decoration-color: #808000\">memory</span>=<span style=\"color: #008000; text-decoration-color: #008000\">'Ava likes to ski.'</span>,\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   │   </span><span style=\"color: #808000; text-decoration-color: #808000\">topics</span>=<span style=\"font-weight: bold\">[</span><span style=\"color: #008000; text-decoration-color: #008000\">'name'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'hobbies'</span><span style=\"font-weight: bold\">]</span>,\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   │   </span><span style=\"color: #808000; text-decoration-color: #808000\">input</span>=<span style=\"color: #008000; text-decoration-color: #008000\">'My name is Ava and I like to ski.'</span>,\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   │   </span><span style=\"color: #808000; text-decoration-color: #808000\">last_updated</span>=<span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">datetime</span><span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">.datetime</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2025</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">7</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">14</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">17</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">48</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">3</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">101965</span><span style=\"font-weight: bold\">)</span>,\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   │   </span><span style=\"color: #808000; text-decoration-color: #808000\">memory_id</span>=<span style=\"color: #008000; text-decoration-color: #008000\">'c97cfac1-5166-49c3-b002-dac0530182ab'</span>\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   </span><span style=\"font-weight: bold\">)</span>\n",
-       "<span style=\"font-weight: bold\">]</span>\n",
-       "</pre>\n"
-      ],
-      "text/plain": [
-       "\u001b[1m[\u001b[0m\n",
-       "\u001b[2;32m│   \u001b[0m\u001b[1;35mUserMemory\u001b[0m\u001b[1m(\u001b[0m\n",
-       "\u001b[2;32m│   │   \u001b[0m\u001b[33mmemory\u001b[0m=\u001b[32m'Ava likes to ski.'\u001b[0m,\n",
-       "\u001b[2;32m│   │   \u001b[0m\u001b[33mtopics\u001b[0m=\u001b[1m[\u001b[0m\u001b[32m'name'\u001b[0m, \u001b[32m'hobbies'\u001b[0m\u001b[1m]\u001b[0m,\n",
-       "\u001b[2;32m│   │   \u001b[0m\u001b[33minput\u001b[0m=\u001b[32m'My name is Ava and I like to ski.'\u001b[0m,\n",
-       "\u001b[2;32m│   │   \u001b[0m\u001b[33mlast_updated\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m7\u001b[0m, \u001b[1;36m14\u001b[0m, \u001b[1;36m17\u001b[0m, \u001b[1;36m48\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m101965\u001b[0m\u001b[1m)\u001b[0m,\n",
-       "\u001b[2;32m│   │   \u001b[0m\u001b[33mmemory_id\u001b[0m=\u001b[32m'c97cfac1-5166-49c3-b002-dac0530182ab'\u001b[0m\n",
-       "\u001b[2;32m│   \u001b[0m\u001b[1m)\u001b[0m\n",
-       "\u001b[1m]\u001b[0m\n"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "application/vnd.jupyter.widget-view+json": {
-       "model_id": "3bda0ba0f3a64809bd63d042d95fd2a3",
-       "version_major": 2,
-       "version_minor": 0
-      },
-      "text/plain": [
-       "Output()"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
-      ],
-      "text/plain": []
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Memories about Ava:\n"
-     ]
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">[</span>\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   </span><span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">UserMemory</span><span style=\"font-weight: bold\">(</span>\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   │   </span><span style=\"color: #808000; text-decoration-color: #808000\">memory</span>=<span style=\"color: #008000; text-decoration-color: #008000\">'Ava likes to ski.'</span>,\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   │   </span><span style=\"color: #808000; text-decoration-color: #808000\">topics</span>=<span style=\"font-weight: bold\">[</span><span style=\"color: #008000; text-decoration-color: #008000\">'name'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'hobbies'</span><span style=\"font-weight: bold\">]</span>,\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   │   </span><span style=\"color: #808000; text-decoration-color: #808000\">input</span>=<span style=\"color: #008000; text-decoration-color: #008000\">'My name is Ava and I like to ski.'</span>,\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   │   </span><span style=\"color: #808000; text-decoration-color: #808000\">last_updated</span>=<span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">datetime</span><span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">.datetime</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2025</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">7</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">14</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">17</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">48</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">3</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">101965</span><span style=\"font-weight: bold\">)</span>,\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   │   </span><span style=\"color: #808000; text-decoration-color: #808000\">memory_id</span>=<span style=\"color: #008000; text-decoration-color: #008000\">'c97cfac1-5166-49c3-b002-dac0530182ab'</span>\n",
-       "<span style=\"color: #7fbf7f; text-decoration-color: #7fbf7f\">│   </span><span style=\"font-weight: bold\">)</span>\n",
-       "<span style=\"font-weight: bold\">]</span>\n",
-       "</pre>\n"
-      ],
-      "text/plain": [
-       "\u001b[1m[\u001b[0m\n",
-       "\u001b[2;32m│   \u001b[0m\u001b[1;35mUserMemory\u001b[0m\u001b[1m(\u001b[0m\n",
-       "\u001b[2;32m│   │   \u001b[0m\u001b[33mmemory\u001b[0m=\u001b[32m'Ava likes to ski.'\u001b[0m,\n",
-       "\u001b[2;32m│   │   \u001b[0m\u001b[33mtopics\u001b[0m=\u001b[1m[\u001b[0m\u001b[32m'name'\u001b[0m, \u001b[32m'hobbies'\u001b[0m\u001b[1m]\u001b[0m,\n",
-       "\u001b[2;32m│   │   \u001b[0m\u001b[33minput\u001b[0m=\u001b[32m'My name is Ava and I like to ski.'\u001b[0m,\n",
-       "\u001b[2;32m│   │   \u001b[0m\u001b[33mlast_updated\u001b[0m=\u001b[1;35mdatetime\u001b[0m\u001b[1;35m.datetime\u001b[0m\u001b[1m(\u001b[0m\u001b[1;36m2025\u001b[0m, \u001b[1;36m7\u001b[0m, \u001b[1;36m14\u001b[0m, \u001b[1;36m17\u001b[0m, \u001b[1;36m48\u001b[0m, \u001b[1;36m3\u001b[0m, \u001b[1;36m101965\u001b[0m\u001b[1m)\u001b[0m,\n",
-       "\u001b[2;32m│   │   \u001b[0m\u001b[33mmemory_id\u001b[0m=\u001b[32m'c97cfac1-5166-49c3-b002-dac0530182ab'\u001b[0m\n",
-       "\u001b[2;32m│   \u001b[0m\u001b[1m)\u001b[0m\n",
-       "\u001b[1m]\u001b[0m\n"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    }
-   ],
+   "outputs": [],
    "source": [
     "# UserId for the memories\n",
     "user_id = \"ava\"\n",
@@ -507,9 +242,9 @@
     "memory = Memory(\n",
     "    # Use any model for creating memories\n",
     "    model=OpenAILike(id=\"qwen3-30b-a3b\", \n",
-    "    api_key=os.getenv(\"BAILIAN_API_KEY\"), \n",
-    "    base_url=os.getenv(\"BAILIAN_API_BASE_URL\"),\n",
-    "    request_params={\"extra_body\": {\"enable_thinking\": False}},),\n",
+    "                    api_key=os.getenv(\"BAILIAN_API_KEY\"), \n",
+    "                    base_url=os.getenv(\"BAILIAN_API_BASE_URL\"),\n",
+    "                    request_params={\"extra_body\": {\"enable_thinking\": False}},),\n",
     "    db=SqliteMemoryDb(table_name=\"user_memories\", db_file=db_file),\n",
     ")\n",
     "# Initialize storage\n",
@@ -566,220 +301,150 @@
   },
   {
    "cell_type": "code",
-   "execution_count": 13,
+   "execution_count": null,
    "id": "5cddde6d",
    "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "application/vnd.jupyter.widget-view+json": {
-       "model_id": "7745304024a946c3b1e7bcba04f464ca",
-       "version_major": 2,
-       "version_minor": 0
-      },
-      "text/plain": [
-       "Output()"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #808000; text-decoration-color: #808000\">WARNING </span> Failed to parse cleaned JSON: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">6</span> validation errors for MovieScript                                         \n",
-       "         setting                                                                                                   \n",
-       "           Input should be a valid string <span style=\"font-weight: bold\">[</span><span style=\"color: #808000; text-decoration-color: #808000\">type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">string_type</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_value</span>=<span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'location'</span>: <span style=\"color: #008000; text-decoration-color: #008000\">'New York Ci...t hold hidden </span>\n",
-       "         <span style=\"color: #008000; text-decoration-color: #008000\">stories.'</span><span style=\"font-weight: bold\">}</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">dict</span><span style=\"font-weight: bold\">]</span>                                                                              \n",
-       "             For further information visit <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://errors.pydantic.dev/2.11/v/string_type</span>                          \n",
-       "         ending                                                                                                    \n",
-       "           Field required <span style=\"font-weight: bold\">[</span><span style=\"color: #808000; text-decoration-color: #808000\">type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">missing</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_value</span>=<span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'title'</span>: <span style=\"color: #008000; text-decoration-color: #008000\">'New York'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'ge...s a central character.'</span><span style=\"font-weight: bold\">}</span>,         \n",
-       "         <span style=\"color: #808000; text-decoration-color: #808000\">input_type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">dict</span><span style=\"font-weight: bold\">]</span>                                                                                          \n",
-       "             For further information visit <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://errors.pydantic.dev/2.11/v/missing</span>                              \n",
-       "         name                                                                                                      \n",
-       "           Field required <span style=\"font-weight: bold\">[</span><span style=\"color: #808000; text-decoration-color: #808000\">type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">missing</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_value</span>=<span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'title'</span>: <span style=\"color: #008000; text-decoration-color: #008000\">'New York'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'ge...s a central character.'</span><span style=\"font-weight: bold\">}</span>,         \n",
-       "         <span style=\"color: #808000; text-decoration-color: #808000\">input_type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">dict</span><span style=\"font-weight: bold\">]</span>                                                                                          \n",
-       "             For further information visit <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://errors.pydantic.dev/2.11/v/missing</span>                              \n",
-       "         characters                                                                                                \n",
-       "           Field required <span style=\"font-weight: bold\">[</span><span style=\"color: #808000; text-decoration-color: #808000\">type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">missing</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_value</span>=<span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'title'</span>: <span style=\"color: #008000; text-decoration-color: #008000\">'New York'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'ge...s a central character.'</span><span style=\"font-weight: bold\">}</span>,         \n",
-       "         <span style=\"color: #808000; text-decoration-color: #808000\">input_type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">dict</span><span style=\"font-weight: bold\">]</span>                                                                                          \n",
-       "             For further information visit <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://errors.pydantic.dev/2.11/v/missing</span>                              \n",
-       "         storyline                                                                                                 \n",
-       "           Field required <span style=\"font-weight: bold\">[</span><span style=\"color: #808000; text-decoration-color: #808000\">type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">missing</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_value</span>=<span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'title'</span>: <span style=\"color: #008000; text-decoration-color: #008000\">'New York'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'ge...s a central character.'</span><span style=\"font-weight: bold\">}</span>,         \n",
-       "         <span style=\"color: #808000; text-decoration-color: #808000\">input_type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">dict</span><span style=\"font-weight: bold\">]</span>                                                                                          \n",
-       "             For further information visit <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://errors.pydantic.dev/2.11/v/missing</span>                              \n",
-       "         rating                                                                                                    \n",
-       "           Field required <span style=\"font-weight: bold\">[</span><span style=\"color: #808000; text-decoration-color: #808000\">type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">missing</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_value</span>=<span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'title'</span>: <span style=\"color: #008000; text-decoration-color: #008000\">'New York'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'ge...s a central character.'</span><span style=\"font-weight: bold\">}</span>,         \n",
-       "         <span style=\"color: #808000; text-decoration-color: #808000\">input_type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">dict</span><span style=\"font-weight: bold\">]</span>                                                                                          \n",
-       "             For further information visit <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://errors.pydantic.dev/2.11/v/missing</span>                              \n",
-       "</pre>\n"
-      ],
-      "text/plain": [
-       "\u001b[33mWARNING \u001b[0m Failed to parse cleaned JSON: \u001b[1;36m6\u001b[0m validation errors for MovieScript                                         \n",
-       "         setting                                                                                                   \n",
-       "           Input should be a valid string \u001b[1m[\u001b[0m\u001b[33mtype\u001b[0m=\u001b[35mstring_type\u001b[0m, \u001b[33minput_value\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'location'\u001b[0m: \u001b[32m'New York Ci...t hold hidden \u001b[0m\n",
-       "         \u001b[32mstories.'\u001b[0m\u001b[1m}\u001b[0m, \u001b[33minput_type\u001b[0m=\u001b[35mdict\u001b[0m\u001b[1m]\u001b[0m                                                                              \n",
-       "             For further information visit \u001b[4;94mhttps://errors.pydantic.dev/2.11/v/string_type\u001b[0m                          \n",
-       "         ending                                                                                                    \n",
-       "           Field required \u001b[1m[\u001b[0m\u001b[33mtype\u001b[0m=\u001b[35mmissing\u001b[0m, \u001b[33minput_value\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'title'\u001b[0m: \u001b[32m'New York'\u001b[0m, \u001b[32m'ge...s a central character.'\u001b[0m\u001b[1m}\u001b[0m,         \n",
-       "         \u001b[33minput_type\u001b[0m=\u001b[35mdict\u001b[0m\u001b[1m]\u001b[0m                                                                                          \n",
-       "             For further information visit \u001b[4;94mhttps://errors.pydantic.dev/2.11/v/missing\u001b[0m                              \n",
-       "         name                                                                                                      \n",
-       "           Field required \u001b[1m[\u001b[0m\u001b[33mtype\u001b[0m=\u001b[35mmissing\u001b[0m, \u001b[33minput_value\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'title'\u001b[0m: \u001b[32m'New York'\u001b[0m, \u001b[32m'ge...s a central character.'\u001b[0m\u001b[1m}\u001b[0m,         \n",
-       "         \u001b[33minput_type\u001b[0m=\u001b[35mdict\u001b[0m\u001b[1m]\u001b[0m                                                                                          \n",
-       "             For further information visit \u001b[4;94mhttps://errors.pydantic.dev/2.11/v/missing\u001b[0m                              \n",
-       "         characters                                                                                                \n",
-       "           Field required \u001b[1m[\u001b[0m\u001b[33mtype\u001b[0m=\u001b[35mmissing\u001b[0m, \u001b[33minput_value\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'title'\u001b[0m: \u001b[32m'New York'\u001b[0m, \u001b[32m'ge...s a central character.'\u001b[0m\u001b[1m}\u001b[0m,         \n",
-       "         \u001b[33minput_type\u001b[0m=\u001b[35mdict\u001b[0m\u001b[1m]\u001b[0m                                                                                          \n",
-       "             For further information visit \u001b[4;94mhttps://errors.pydantic.dev/2.11/v/missing\u001b[0m                              \n",
-       "         storyline                                                                                                 \n",
-       "           Field required \u001b[1m[\u001b[0m\u001b[33mtype\u001b[0m=\u001b[35mmissing\u001b[0m, \u001b[33minput_value\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'title'\u001b[0m: \u001b[32m'New York'\u001b[0m, \u001b[32m'ge...s a central character.'\u001b[0m\u001b[1m}\u001b[0m,         \n",
-       "         \u001b[33minput_type\u001b[0m=\u001b[35mdict\u001b[0m\u001b[1m]\u001b[0m                                                                                          \n",
-       "             For further information visit \u001b[4;94mhttps://errors.pydantic.dev/2.11/v/missing\u001b[0m                              \n",
-       "         rating                                                                                                    \n",
-       "           Field required \u001b[1m[\u001b[0m\u001b[33mtype\u001b[0m=\u001b[35mmissing\u001b[0m, \u001b[33minput_value\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'title'\u001b[0m: \u001b[32m'New York'\u001b[0m, \u001b[32m'ge...s a central character.'\u001b[0m\u001b[1m}\u001b[0m,         \n",
-       "         \u001b[33minput_type\u001b[0m=\u001b[35mdict\u001b[0m\u001b[1m]\u001b[0m                                                                                          \n",
-       "             For further information visit \u001b[4;94mhttps://errors.pydantic.dev/2.11/v/missing\u001b[0m                              \n"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #808000; text-decoration-color: #808000\">WARNING </span> Validation failed on merged data: <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">6</span> validation errors for MovieScript                                     \n",
-       "         setting                                                                                                   \n",
-       "           Input should be a valid string <span style=\"font-weight: bold\">[</span><span style=\"color: #808000; text-decoration-color: #808000\">type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">string_type</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_value</span>=<span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'location'</span>: <span style=\"color: #008000; text-decoration-color: #008000\">'New York Ci...t hold hidden </span>\n",
-       "         <span style=\"color: #008000; text-decoration-color: #008000\">stories.'</span><span style=\"font-weight: bold\">}</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">dict</span><span style=\"font-weight: bold\">]</span>                                                                              \n",
-       "             For further information visit <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://errors.pydantic.dev/2.11/v/string_type</span>                          \n",
-       "         ending                                                                                                    \n",
-       "           Field required <span style=\"font-weight: bold\">[</span><span style=\"color: #808000; text-decoration-color: #808000\">type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">missing</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_value</span>=<span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'setting'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'location'</span>: <span style=\"color: #808000; text-decoration-color: #808000\">...</span>genre': <span style=\"color: #008000; text-decoration-color: #008000\">'Drama / Crime'</span><span style=\"font-weight: bold\">}</span>,         \n",
-       "         <span style=\"color: #808000; text-decoration-color: #808000\">input_type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">dict</span><span style=\"font-weight: bold\">]</span>                                                                                          \n",
-       "             For further information visit <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://errors.pydantic.dev/2.11/v/missing</span>                              \n",
-       "         name                                                                                                      \n",
-       "           Field required <span style=\"font-weight: bold\">[</span><span style=\"color: #808000; text-decoration-color: #808000\">type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">missing</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_value</span>=<span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'setting'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'location'</span>: <span style=\"color: #808000; text-decoration-color: #808000\">...</span>genre': <span style=\"color: #008000; text-decoration-color: #008000\">'Drama / Crime'</span><span style=\"font-weight: bold\">}</span>,         \n",
-       "         <span style=\"color: #808000; text-decoration-color: #808000\">input_type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">dict</span><span style=\"font-weight: bold\">]</span>                                                                                          \n",
-       "             For further information visit <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://errors.pydantic.dev/2.11/v/missing</span>                              \n",
-       "         characters                                                                                                \n",
-       "           Field required <span style=\"font-weight: bold\">[</span><span style=\"color: #808000; text-decoration-color: #808000\">type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">missing</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_value</span>=<span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'setting'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'location'</span>: <span style=\"color: #808000; text-decoration-color: #808000\">...</span>genre': <span style=\"color: #008000; text-decoration-color: #008000\">'Drama / Crime'</span><span style=\"font-weight: bold\">}</span>,         \n",
-       "         <span style=\"color: #808000; text-decoration-color: #808000\">input_type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">dict</span><span style=\"font-weight: bold\">]</span>                                                                                          \n",
-       "             For further information visit <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://errors.pydantic.dev/2.11/v/missing</span>                              \n",
-       "         storyline                                                                                                 \n",
-       "           Field required <span style=\"font-weight: bold\">[</span><span style=\"color: #808000; text-decoration-color: #808000\">type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">missing</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_value</span>=<span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'setting'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'location'</span>: <span style=\"color: #808000; text-decoration-color: #808000\">...</span>genre': <span style=\"color: #008000; text-decoration-color: #008000\">'Drama / Crime'</span><span style=\"font-weight: bold\">}</span>,         \n",
-       "         <span style=\"color: #808000; text-decoration-color: #808000\">input_type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">dict</span><span style=\"font-weight: bold\">]</span>                                                                                          \n",
-       "             For further information visit <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://errors.pydantic.dev/2.11/v/missing</span>                              \n",
-       "         rating                                                                                                    \n",
-       "           Field required <span style=\"font-weight: bold\">[</span><span style=\"color: #808000; text-decoration-color: #808000\">type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">missing</span>, <span style=\"color: #808000; text-decoration-color: #808000\">input_value</span>=<span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'setting'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'location'</span>: <span style=\"color: #808000; text-decoration-color: #808000\">...</span>genre': <span style=\"color: #008000; text-decoration-color: #008000\">'Drama / Crime'</span><span style=\"font-weight: bold\">}</span>,         \n",
-       "         <span style=\"color: #808000; text-decoration-color: #808000\">input_type</span>=<span style=\"color: #800080; text-decoration-color: #800080\">dict</span><span style=\"font-weight: bold\">]</span>                                                                                          \n",
-       "             For further information visit <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">https://errors.pydantic.dev/2.11/v/missing</span>                              \n",
-       "</pre>\n"
-      ],
-      "text/plain": [
-       "\u001b[33mWARNING \u001b[0m Validation failed on merged data: \u001b[1;36m6\u001b[0m validation errors for MovieScript                                     \n",
-       "         setting                                                                                                   \n",
-       "           Input should be a valid string \u001b[1m[\u001b[0m\u001b[33mtype\u001b[0m=\u001b[35mstring_type\u001b[0m, \u001b[33minput_value\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'location'\u001b[0m: \u001b[32m'New York Ci...t hold hidden \u001b[0m\n",
-       "         \u001b[32mstories.'\u001b[0m\u001b[1m}\u001b[0m, \u001b[33minput_type\u001b[0m=\u001b[35mdict\u001b[0m\u001b[1m]\u001b[0m                                                                              \n",
-       "             For further information visit \u001b[4;94mhttps://errors.pydantic.dev/2.11/v/string_type\u001b[0m                          \n",
-       "         ending                                                                                                    \n",
-       "           Field required \u001b[1m[\u001b[0m\u001b[33mtype\u001b[0m=\u001b[35mmissing\u001b[0m, \u001b[33minput_value\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'setting'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'location'\u001b[0m: \u001b[33m...\u001b[0mgenre': \u001b[32m'Drama / Crime'\u001b[0m\u001b[1m}\u001b[0m,         \n",
-       "         \u001b[33minput_type\u001b[0m=\u001b[35mdict\u001b[0m\u001b[1m]\u001b[0m                                                                                          \n",
-       "             For further information visit \u001b[4;94mhttps://errors.pydantic.dev/2.11/v/missing\u001b[0m                              \n",
-       "         name                                                                                                      \n",
-       "           Field required \u001b[1m[\u001b[0m\u001b[33mtype\u001b[0m=\u001b[35mmissing\u001b[0m, \u001b[33minput_value\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'setting'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'location'\u001b[0m: \u001b[33m...\u001b[0mgenre': \u001b[32m'Drama / Crime'\u001b[0m\u001b[1m}\u001b[0m,         \n",
-       "         \u001b[33minput_type\u001b[0m=\u001b[35mdict\u001b[0m\u001b[1m]\u001b[0m                                                                                          \n",
-       "             For further information visit \u001b[4;94mhttps://errors.pydantic.dev/2.11/v/missing\u001b[0m                              \n",
-       "         characters                                                                                                \n",
-       "           Field required \u001b[1m[\u001b[0m\u001b[33mtype\u001b[0m=\u001b[35mmissing\u001b[0m, \u001b[33minput_value\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'setting'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'location'\u001b[0m: \u001b[33m...\u001b[0mgenre': \u001b[32m'Drama / Crime'\u001b[0m\u001b[1m}\u001b[0m,         \n",
-       "         \u001b[33minput_type\u001b[0m=\u001b[35mdict\u001b[0m\u001b[1m]\u001b[0m                                                                                          \n",
-       "             For further information visit \u001b[4;94mhttps://errors.pydantic.dev/2.11/v/missing\u001b[0m                              \n",
-       "         storyline                                                                                                 \n",
-       "           Field required \u001b[1m[\u001b[0m\u001b[33mtype\u001b[0m=\u001b[35mmissing\u001b[0m, \u001b[33minput_value\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'setting'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'location'\u001b[0m: \u001b[33m...\u001b[0mgenre': \u001b[32m'Drama / Crime'\u001b[0m\u001b[1m}\u001b[0m,         \n",
-       "         \u001b[33minput_type\u001b[0m=\u001b[35mdict\u001b[0m\u001b[1m]\u001b[0m                                                                                          \n",
-       "             For further information visit \u001b[4;94mhttps://errors.pydantic.dev/2.11/v/missing\u001b[0m                              \n",
-       "         rating                                                                                                    \n",
-       "           Field required \u001b[1m[\u001b[0m\u001b[33mtype\u001b[0m=\u001b[35mmissing\u001b[0m, \u001b[33minput_value\u001b[0m=\u001b[1m{\u001b[0m\u001b[32m'setting'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'location'\u001b[0m: \u001b[33m...\u001b[0mgenre': \u001b[32m'Drama / Crime'\u001b[0m\u001b[1m}\u001b[0m,         \n",
-       "         \u001b[33minput_type\u001b[0m=\u001b[35mdict\u001b[0m\u001b[1m]\u001b[0m                                                                                          \n",
-       "             For further information visit \u001b[4;94mhttps://errors.pydantic.dev/2.11/v/missing\u001b[0m                              \n"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #808000; text-decoration-color: #808000\">WARNING </span> All parsing attempts failed.                                                                              \n",
-       "</pre>\n"
-      ],
-      "text/plain": [
-       "\u001b[33mWARNING \u001b[0m All parsing attempts failed.                                                                              \n"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #808000; text-decoration-color: #808000\">WARNING </span> Failed to convert response to response_model                                                              \n",
-       "</pre>\n"
-      ],
-      "text/plain": [
-       "\u001b[33mWARNING \u001b[0m Failed to convert response to response_model                                                              \n"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
-      ],
-      "text/plain": []
-     },
-     "metadata": {},
-     "output_type": "display_data"
-    }
-   ],
+   "outputs": [],
    "source": [
     "class MovieScript(BaseModel):\n",
     "    setting: str = Field(\n",
-    "        ..., description=\"Provide a nice setting for a blockbuster movie.\"\n",
+    "        ...,\n",
+    "        description=\"A richly detailed, atmospheric description of the movie's primary location and time period. Include sensory details and mood.\",\n",
     "    )\n",
     "    ending: str = Field(\n",
     "        ...,\n",
-    "        description=\"Ending of the movie. If not available, provide a happy ending.\",\n",
+    "        description=\"The movie's powerful conclusion that ties together all plot threads. Should deliver emotional impact and satisfaction.\",\n",
     "    )\n",
     "    genre: str = Field(\n",
     "        ...,\n",
-    "        description=\"Genre of the movie. If not available, select action, thriller or romantic comedy.\",\n",
+    "        description=\"The film's primary and secondary genres (e.g., 'Sci-fi Thriller', 'Romantic Comedy'). Should align with setting and tone.\",\n",
     "    )\n",
-    "    name: str = Field(..., description=\"Give a name to this movie\")\n",
-    "    characters: List[str] = Field(..., description=\"Name of characters for this movie.\")\n",
-    "    storyline: str = Field(\n",
-    "        ..., description=\"3 sentence storyline for the movie. Make it exciting!\"\n",
+    "    name: str = Field(\n",
+    "        ...,\n",
+    "        description=\"An attention-grabbing, memorable title that captures the essence of the story and appeals to target audience.\",\n",
+    "    )\n",
+    "    characters: List[str] = Field(\n",
+    "        ...,\n",
+    "        description=\"4-6 main characters with distinctive names and brief role descriptions (e.g., 'Sarah Chen - brilliant quantum physicist with a dark secret').\",\n",
     "    )\n",
-    "    rating: Dict[str, int] = Field(\n",
+    "    storyline: str = Field(\n",
     "        ...,\n",
-    "        description=\"Your own rating of the movie. 1-10. Return a dictionary with the keys 'story' and 'acting'.\",\n",
+    "        description=\"A compelling three-sentence plot summary: Setup, Conflict, and Stakes. Hook readers with intrigue and emotion.\",\n",
     "    )\n",
     "\n",
     "\n",
-    "# Agent that uses structured outputs with streaming\n",
+    "# Agent that uses JSON mode\n",
+    "json_mode_agent = Agent(\n",
+    "    model=OpenAILike(id=\"qwen3-30b-a3b\", \n",
+    "                    api_key=os.getenv(\"BAILIAN_API_KEY\"), \n",
+    "                    base_url=os.getenv(\"BAILIAN_API_BASE_URL\"),\n",
+    "                    request_params={\"extra_body\": {\"enable_thinking\": False}},),\n",
+    "    description=dedent(\"\"\"\\\n",
+    "        You are an acclaimed Hollywood screenwriter known for creating unforgettable blockbusters! 🎬\n",
+    "        With the combined storytelling prowess of Christopher Nolan, Aaron Sorkin, and Quentin Tarantino,\n",
+    "        you craft unique stories that captivate audiences worldwide.\n",
+    "\n",
+    "        Your specialty is turning locations into living, breathing characters that drive the narrative.\\\n",
+    "    \"\"\"),\n",
+    "    instructions=dedent(\"\"\"\\\n",
+    "        When crafting movie concepts, follow these principles:\n",
+    "\n",
+    "        1. Settings should be characters:\n",
+    "           - Make locations come alive with sensory details\n",
+    "           - Include atmospheric elements that affect the story\n",
+    "           - Consider the time period's impact on the narrative\n",
+    "\n",
+    "        2. Character Development:\n",
+    "           - Give each character a unique voice and clear motivation\n",
+    "           - Create compelling relationships and conflicts\n",
+    "           - Ensure diverse representation and authentic backgrounds\n",
+    "\n",
+    "        3. Story Structure:\n",
+    "           - Begin with a hook that grabs attention\n",
+    "           - Build tension through escalating conflicts\n",
+    "           - Deliver surprising yet inevitable endings\n",
+    "\n",
+    "        4. Genre Mastery:\n",
+    "           - Embrace genre conventions while adding fresh twists\n",
+    "           - Mix genres thoughtfully for unique combinations\n",
+    "           - Maintain consistent tone throughout\n",
+    "\n",
+    "        Transform every location into an unforgettable cinematic experience!\\\n",
+    "    \"\"\"),\n",
+    "    response_model=MovieScript,\n",
+    "    use_json_mode=True,\n",
+    ")\n",
+    "\n",
+    "# Agent that uses structured outputs\n",
     "structured_output_agent = Agent(\n",
     "    model=OpenAILike(id=\"qwen3-30b-a3b\", \n",
-    "        api_key=os.getenv(\"BAILIAN_API_KEY\"), \n",
-    "        base_url=os.getenv(\"BAILIAN_API_BASE_URL\"),\n",
-    "        request_params={\"extra_body\": {\"enable_thinking\": False}},),\n",
-    "    description=\"You write movie json scripts.\",\n",
+    "                    api_key=os.getenv(\"BAILIAN_API_KEY\"), \n",
+    "                    base_url=os.getenv(\"BAILIAN_API_BASE_URL\"),\n",
+    "                    request_params={\"extra_body\": {\"enable_thinking\": False}},),\n",
+    "    description=dedent(\"\"\"\\\n",
+    "        You are an acclaimed Hollywood screenwriter known for creating unforgettable blockbusters! 🎬\n",
+    "        With the combined storytelling prowess of Christopher Nolan, Aaron Sorkin, and Quentin Tarantino,\n",
+    "        you craft unique stories that captivate audiences worldwide.\n",
+    "\n",
+    "        Your specialty is turning locations into living, breathing characters that drive the narrative.\\\n",
+    "    \"\"\"),\n",
+    "    instructions=dedent(\"\"\"\\\n",
+    "        When crafting movie concepts in json, follow these principles:\n",
+    "\n",
+    "        1. Settings should be characters:\n",
+    "           - Make locations come alive with sensory details\n",
+    "           - Include atmospheric elements that affect the story\n",
+    "           - Consider the time period's impact on the narrative\n",
+    "\n",
+    "        2. Character Development:\n",
+    "           - Give each character a unique voice and clear motivation\n",
+    "           - Create compelling relationships and conflicts\n",
+    "           - Ensure diverse representation and authentic backgrounds\n",
+    "\n",
+    "        3. Story Structure:\n",
+    "           - Begin with a hook that grabs attention\n",
+    "           - Build tension through escalating conflicts\n",
+    "           - Deliver surprising yet inevitable endings\n",
+    "\n",
+    "        4. Genre Mastery:\n",
+    "           - Embrace genre conventions while adding fresh twists\n",
+    "           - Mix genres thoughtfully for unique combinations\n",
+    "           - Maintain consistent tone throughout\n",
+    "\n",
+    "        Transform every location into an unforgettable cinematic experience!\\\n",
+    "    \"\"\"),\n",
     "    response_model=MovieScript,\n",
     ")\n",
     "\n",
-    "structured_output_agent.print_response(\n",
-    "    \"New York\", stream=True, stream_intermediate_steps=True\n",
-    ")"
+    "# Example usage with different locations\n",
+    "json_mode_agent.print_response(\"Tokyo\", stream=True)\n",
+    "structured_output_agent.print_response(\"Ancient Rome\", stream=True)\n",
+    "\n",
+    "# More examples to try:\n",
+    "\"\"\"\n",
+    "Creative location prompts to explore:\n",
+    "1. \"Underwater Research Station\" - For a claustrophobic sci-fi thriller\n",
+    "2. \"Victorian London\" - For a gothic mystery\n",
+    "3. \"Dubai 2050\" - For a futuristic heist movie\n",
+    "4. \"Antarctic Research Base\" - For a survival horror story\n",
+    "5. \"Caribbean Island\" - For a tropical adventure romance\n",
+    "\"\"\"\n",
+    "\n",
+    "# To get the response in a variable:\n",
+    "# from rich.pretty import pprint\n",
+    "\n",
+    "# json_mode_response: RunResponse = json_mode_agent.run(\"New York\")\n",
+    "# pprint(json_mode_response.content)\n",
+    "# structured_output_response: RunResponse = structured_output_agent.run(\"New York\")\n",
+    "# pprint(structured_output_response.content)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "80d94c56",
+   "metadata": {},
+   "source": [
+    "**Multimodal Agent**"
    ]
   },
   {

+ 332 - 0
曹航/3/agent_test3.ipynb

@@ -0,0 +1,332 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "id": "b4617320",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "True"
+      ]
+     },
+     "execution_count": 1,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "from textwrap import dedent\n",
+    "\n",
+    "from agno.agent import Agent\n",
+    "from agno.models.openai import OpenAILike\n",
+    "from agno.exceptions import StopAgentRun\n",
+    "from agno.tools import tool,FunctionCall\n",
+    "from agno.tools.function import UserInputField\n",
+    "from agno.utils import pprint\n",
+    "\n",
+    "from dotenv import load_dotenv \n",
+    "\n",
+    "from typing import Iterator,List\n",
+    "\n",
+    "from rich.console import Console\n",
+    "from rich.prompt import Prompt\n",
+    "\n",
+    "import httpx\n",
+    "import os\n",
+    "import json\n",
+    "load_dotenv()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "72dce64b",
+   "metadata": {},
+   "source": [
+    "**User Control Flows(Human in loop)**"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "id": "cb6ea5c6",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "26ccd24ca6fa453490acd99692ca1ba6",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "Output()"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
+       "About to run <span style=\"color: #000080; text-decoration-color: #000080; font-weight: bold\">get_top_hackernews_stories</span>\n",
+       "</pre>\n"
+      ],
+      "text/plain": [
+       "\n",
+       "About to run \u001b[1;34mget_top_hackernews_stories\u001b[0m\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Do you want to continue? <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">[y/n]</span> <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">(y)</span>: </pre>\n"
+      ],
+      "text/plain": [
+       "Do you want to continue? \u001b[1;35m[y/n]\u001b[0m \u001b[1;36m(y)\u001b[0m: "
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"></pre>\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "# This is the console instance used by the print_response method\n",
+    "# We can use this to stop and restart the live display and ask for user confirmation\n",
+    "console = Console()\n",
+    "\n",
+    "\n",
+    "def pre_hook(fc: FunctionCall):\n",
+    "    # Get the live display instance from the console\n",
+    "    live = console._live\n",
+    "\n",
+    "    # Stop the live display temporarily so we can ask for user confirmation\n",
+    "    live.stop()  # type: ignore\n",
+    "\n",
+    "    # Ask for confirmation\n",
+    "    console.print(f\"\\nAbout to run [bold blue]{fc.function.name}[/]\")\n",
+    "    message = (\n",
+    "        Prompt.ask(\"Do you want to continue?\", choices=[\"y\", \"n\"], default=\"y\")\n",
+    "        .strip()\n",
+    "        .lower()\n",
+    "    )\n",
+    "\n",
+    "    # Restart the live display\n",
+    "    live.start()  # type: ignore\n",
+    "\n",
+    "    # If the user does not want to continue, raise a StopExecution exception\n",
+    "    if message != \"y\":\n",
+    "        raise StopAgentRun(\n",
+    "            \"Tool call cancelled by user\",  \n",
+    "            agent_message=\"Stopping execution as permission was not granted.\",\n",
+    "        )\n",
+    "\n",
+    "\n",
+    "@tool(pre_hook=pre_hook)\n",
+    "def get_top_hackernews_stories(num_stories: int) -> Iterator[str]:\n",
+    "    \"\"\"Fetch top stories from Hacker News after user confirmation.\n",
+    "\n",
+    "    Args:\n",
+    "        num_stories (int): Number of stories to retrieve\n",
+    "\n",
+    "    Returns:\n",
+    "        str: JSON string containing story details\n",
+    "    \"\"\"\n",
+    "    # Fetch top story IDs\n",
+    "    response = httpx.get(\"https://hacker-news.firebaseio.com/v0/topstories.json\")\n",
+    "    story_ids = response.json()\n",
+    "\n",
+    "    # Yield story details\n",
+    "    for story_id in story_ids[:num_stories]:\n",
+    "        story_response = httpx.get(\n",
+    "            f\"https://hacker-news.firebaseio.com/v0/item/{story_id}.json\"\n",
+    "        )\n",
+    "        story = story_response.json()\n",
+    "        if \"text\" in story:\n",
+    "            story.pop(\"text\", None)\n",
+    "        yield json.dumps(story)\n",
+    "\n",
+    "\n",
+    "# Initialize the agent with a tech-savvy personality and clear instructions\n",
+    "agent = Agent(\n",
+    "    model=OpenAILike(id=\"qwen3-30b-a3b\", \n",
+    "                    api_key=os.getenv(\"BAILIAN_API_KEY\"), \n",
+    "                    base_url=os.getenv(\"BAILIAN_API_BASE_URL\"),\n",
+    "                    request_params={\"extra_body\": {\"enable_thinking\": False}},),\n",
+    "    description=\"A Tech News Assistant that fetches and summarizes Hacker News stories\",\n",
+    "    instructions=dedent(\"\"\"\\\n",
+    "        You are an enthusiastic Tech Reporter\n",
+    "\n",
+    "        Your responsibilities:\n",
+    "        - Present Hacker News stories in an engaging and informative way\n",
+    "        - Provide clear summaries of the information you gather\n",
+    "\n",
+    "        Style guide:\n",
+    "        - Use emoji to make your responses more engaging\n",
+    "        - Keep your summaries concise but informative\n",
+    "        - End with a friendly tech-themed sign-off\\\n",
+    "    \"\"\"),\n",
+    "    tools=[get_top_hackernews_stories],\n",
+    "    show_tool_calls=True,\n",
+    "    markdown=True,\n",
+    ")\n",
+    "\n",
+    "# Example questions to try:\n",
+    "# - \"What are the top 3 HN stories right now?\"\n",
+    "# - \"Show me the most recent story from Hacker News\"\n",
+    "# - \"Get the top 5 stories (you can try accepting and declining the confirmation)\"\n",
+    "agent.print_response(\n",
+    "    \"What are the top 2 hackernews stories?\", stream=True, console=console\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "9485bd62",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "\n",
+      "Field: subject\n",
+      "Description: The subject of the email.\n",
+      "Type: <class 'str'>\n",
+      "\n",
+      "Field: body\n",
+      "Description: The body of the email.\n",
+      "Type: <class 'str'>\n",
+      "Value: Hello, world!\n",
+      "\n",
+      "Field: to_address\n",
+      "Description: The address to send the email to.\n",
+      "Type: <class 'str'>\n"
+     ]
+    },
+    {
+     "data": {
+      "text/html": [
+       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #000080; text-decoration-color: #000080\">╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮</span>\n",
+       "<span style=\"color: #000080; text-decoration-color: #000080\">│</span> The email with the body \"Hello, world!\" has been successfully sent. Let me know if there's anything else I can  <span style=\"color: #000080; text-decoration-color: #000080\">│</span>\n",
+       "<span style=\"color: #000080; text-decoration-color: #000080\">│</span> assist you with!                                                                                                <span style=\"color: #000080; text-decoration-color: #000080\">│</span>\n",
+       "<span style=\"color: #000080; text-decoration-color: #000080\">╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯</span>\n",
+       "</pre>\n"
+      ],
+      "text/plain": [
+       "\u001b[34m╭─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮\u001b[0m\n",
+       "\u001b[34m│\u001b[0m The email with the body \"Hello, world!\" has been successfully sent. Let me know if there's anything else I can  \u001b[34m│\u001b[0m\n",
+       "\u001b[34m│\u001b[0m assist you with!                                                                                                \u001b[34m│\u001b[0m\n",
+       "\u001b[34m╰─────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
+   "source": [
+    "# You can either specify the user_input_fields leave empty for all fields to be provided by the user\n",
+    "@tool(requires_user_input=True, user_input_fields=[\"subject\", \"to_address\"])\n",
+    "def send_email(subject: str, body: str, to_address: str) -> str:\n",
+    "    \"\"\"\n",
+    "    Send an email.\n",
+    "\n",
+    "    Args:\n",
+    "        subject (str): The subject of the email.\n",
+    "        body (str): The body of the email.\n",
+    "        to_address (str): The address to send the email to.\n",
+    "    \"\"\"\n",
+    "    return f\"Sent email to {to_address} with subject {subject} and body {body}\"\n",
+    "\n",
+    "agent = Agent(\n",
+    "    model=OpenAILike(id=\"qwen3-32b\", \n",
+    "                    api_key=os.getenv(\"BAILIAN_API_KEY\"), \n",
+    "                    base_url=os.getenv(\"BAILIAN_API_BASE_URL\"),\n",
+    "                    request_params={\"extra_body\": {\"enable_thinking\": False}},),\n",
+    "    tools=[send_email],\n",
+    "    show_tool_calls=True,\n",
+    "    markdown=True,\n",
+    ")\n",
+    "\n",
+    "agent.run(\"Send an email with the body 'Hello, world!'\")\n",
+    "if agent.is_paused and agent.run_response:\n",
+    "    for tool in agent.run_response.tools_requiring_user_input:\n",
+    "        if tool.user_input_schema:\n",
+    "            input_schema: List[UserInputField] = tool.user_input_schema\n",
+    "\n",
+    "        for field in input_schema:\n",
+    "            # Display field information to the user\n",
+    "            print(f\"\\nField: {field.name}\")\n",
+    "            print(f\"Description: {field.description}\")\n",
+    "            print(f\"Type: {field.field_type}\")\n",
+    "\n",
+    "            # Get user input\n",
+    "            if field.value is None:\n",
+    "                user_value = input(f\"Please enter a value for {field.name}: \")\n",
+    "                # Update the field value\n",
+    "                field.value = user_value\n",
+    "            else:\n",
+    "                print(f\"Value: {field.value}\")\n",
+    "\n",
+    "    run_response = agent.continue_run()\n",
+    "    pprint.pprint_run_response(run_response)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "fd9fbd3d",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": ".venv",
+   "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.11.13"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}

+ 258 - 0
曹航/3/agno_transfer_agent.ipynb

@@ -0,0 +1,258 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "id": "38787c0b",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from textwrap import dedent\n",
+    "\n",
+    "from agno.agent import Agent\n",
+    "from agno.models.openai import OpenAILike\n",
+    "from agno.playground import Playground\n",
+    "from agno.storage.sqlite import SqliteStorage\n",
+    "from agno.tools.yfinance import YFinanceTools\n",
+    "from agno.tools import tool\n",
+    "\n",
+    "import os\n",
+    "from dotenv import load_dotenv\n",
+    "load_dotenv()\n",
+    "#数据存储位置\n",
+    "agent_storage: str = \"transfer/tmp/agents.db\"\n",
+    "\n",
+    "#测试\n",
+    "finance_agent = Agent(\n",
+    "    name=\"Finance Agent\",\n",
+    "    model=OpenAILike(id=\"qwen3-32b\",\n",
+    "                    api_key=os.getenv(\"BAILIAN_API_KEY\"), \n",
+    "                    base_url=os.getenv(\"BAILIAN_API_BASE_URL\"),\n",
+    "                    request_params={\"extra_body\": {\"enable_thinking\": False}},),\n",
+    "    tools=[YFinanceTools(stock_price=True, analyst_recommendations=True, company_info=True, company_news=True)],\n",
+    "    instructions=[\"Always use tables to display data\"],\n",
+    "    storage=SqliteStorage(table_name=\"finance_agent\", db_file=agent_storage),\n",
+    "    add_datetime_to_instructions=True,\n",
+    "    add_history_to_messages=True,\n",
+    "    num_history_responses=5,\n",
+    "    markdown=True,\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "id": "ee6a0633",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "# 从transfer/prompt目录读取prompt文件\n",
+    "# with open(\"transfer/prompt/prompt.txt\", \"r\", encoding=\"utf-8\") as f:\n",
+    "#     prompt_text = f.read()\n",
+    "\n",
+    "prompt_text=\"\"\"\n",
+    "    ## 背景与目标\n",
+    "    你是一个金融助手 Agent,使用 Qwen3-32B 模型驱动,负责协助用户完成向他人账户转账的流程。/\n",
+    "    当用户提问你其它与转账不相关的问题时,你应该时刻提醒并保持礼貌。/\n",
+    "    你将通过自然语言与用户对话,收集必要信息,确认并调用转账接口完成操作。\n",
+    "    请根据以下流程与规则进行对话与操作。\n",
+    "\n",
+    "    ## 任务流程\n",
+    "\n",
+    "    ### 第一步:信息收集\n",
+    "    请通过对话与用户交互,依次确认并记录以下三项转账信息:\n",
+    "\n",
+    "    1. 通过对方姓名查询账户是否存在(`get_contact`)\n",
+    "    2. 确认转账金额是否大于账户余额(`get_balance`)\n",
+    "    3. 余额不足时,请重新向用户收集信息,继续转账(`replay_to_user`)\n",
+    "\n",
+    "    > 请在用户表达不清或信息缺失时,请通过方法 `replay_to_user` 发起澄清。\n",
+    "\n",
+    "    ### 第二步:执行转账\n",
+    "    请使用适当方法发起转账(`transfer`)\n",
+    "\n",
+    "\"\"\"\n",
+    "# 创建用户列表\n",
+    "users = [\n",
+    "    {\"name\": \"张三\",\"phone\": \"13800138000\",\"amount\": 1000.0},\n",
+    "    {\"name\": \"李四\",\"phone\": \"13800138001\",\"amount\": 500.0},\n",
+    "]\n",
+    "\n",
+    "# 定义转账相关的工具函数\n",
+    "def get_contact(user_name: str) -> bool:\n",
+    "    \"\"\"\n",
+    "    检查账户是否存在\n",
+    "    Args:\n",
+    "        account_number: 账号\n",
+    "    Returns:\n",
+    "        bool: 账户是否存在\n",
+    "    \"\"\"\n",
+    "    # 这里模拟账户检查逻辑\n",
+    "    if user_name == \"张三\":\n",
+    "        return True\n",
+    "    else:\n",
+    "        return False\n",
+    "\n",
+    "def get_balance() -> float:\n",
+    "    \"\"\"\n",
+    "    查询账户余额\n",
+    "    Returns:\n",
+    "        float: 账户余额\n",
+    "    \"\"\"\n",
+    "    balance=users[1][\"amount\"]\n",
+    "    return balance\n",
+    "\n",
+    "#TODO 做用户确认\n",
+    "# @tool(requires_user_input=True,user_input_fields=[\"amount\"])\n",
+    "def transfer(user_name, phone: str, amount: float) -> bool:\n",
+    "    \"\"\"\n",
+    "    执行转账操作\n",
+    "    Args:\n",
+    "        to_account: 转入账号 \n",
+    "        amount: 转账金额\n",
+    "    Returns:\n",
+    "        bool: 转账是否成功\n",
+    "    \"\"\"\n",
+    "    # 这里模拟转账逻辑\n",
+    "    users[0][\"amount\"] += amount\n",
+    "    print(f\"向{user_name}转账{amount}元成功\")\n",
+    "    return True\n",
+    "\n",
+    "def replay_to_user(message: str) -> str:\n",
+    "    \"\"\"\n",
+    "    当当前步骤需要用户输入时,请通过此方法向用户提问\n",
+    "    向用户提问获取信息\n",
+    "    Args:\n",
+    "    Returns:\n",
+    "        str: 用户回答\n",
+    "    \"\"\"\n",
+    "    # 这里实现向用户提问的逻辑\n",
+    "    return input(message)\n",
+    "\n",
+    "\n",
+    "transfer_agent = Agent(\n",
+    "    name=\"Transfer Agent\",\n",
+    "    model=OpenAILike(id=\"qwen3-32b\",\n",
+    "                    api_key=os.getenv(\"BAILIAN_API_KEY\"), \n",
+    "                    base_url=os.getenv(\"BAILIAN_API_BASE_URL\"),\n",
+    "                    request_params={\"extra_body\": {\"enable_thinking\": False}},),\n",
+    "    tools=[get_contact,get_balance,transfer,replay_to_user],\n",
+    "    #TODO memory记忆\n",
+    "    # memory=SqliteStorage(table_name=\"transfer_agent\", db_file=agent_storage),\n",
+    "    instructions=dedent(prompt_text),\n",
+    "    # Store the agent sessions in a sqlite database\n",
+    "    storage=SqliteStorage(table_name=\"transfer_agent\", db_file=agent_storage),\n",
+    "    show_tool_calls=True,\n",
+    "    # Adds the current date and time to the instructions\n",
+    "    add_datetime_to_instructions=True,\n",
+    "    # Adds the history of the conversation to the messages\n",
+    "    add_history_to_messages=True,\n",
+    "    # Number of history responses to add to the messages\n",
+    "    num_history_responses=5,\n",
+    "    # Adds markdown formatting to the messages\n",
+    "    markdown=True,\n",
+    ")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "df67e40a",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "c5c13c01",
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #000080; text-decoration-color: #000080\">INFO</span> Starting playground on <span style=\"color: #0000ff; text-decoration-color: #0000ff; text-decoration: underline\">http://localhost:7777</span>                                                                  \n",
+       "</pre>\n"
+      ],
+      "text/plain": [
+       "\u001b[34mINFO\u001b[0m Starting playground on \u001b[4;94mhttp://localhost:7777\u001b[0m                                                                  \n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "data": {
+      "text/html": [
+       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #008080; text-decoration-color: #008080\">┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Agent Playground ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓</span>\n",
+       "<span style=\"color: #008080; text-decoration-color: #008080\">┃</span>                                                                                <span style=\"color: #008080; text-decoration-color: #008080\">┃</span>\n",
+       "<span style=\"color: #008080; text-decoration-color: #008080\">┃</span>                                                                                <span style=\"color: #008080; text-decoration-color: #008080\">┃</span>\n",
+       "<span style=\"color: #008080; text-decoration-color: #008080\">┃</span>  <span style=\"color: #008000; text-decoration-color: #008000; font-weight: bold\">Playground URL:</span> <a href=\"https://app.agno.com/playground?endpoint=localhost%3A7777/v1\" target=\"_blank\">https://app.agno.com/playground?endpoint=localhost%3A7777/v1</a>  <span style=\"color: #008080; text-decoration-color: #008080\">┃</span>\n",
+       "<span style=\"color: #008080; text-decoration-color: #008080\">┃</span>                                                                                <span style=\"color: #008080; text-decoration-color: #008080\">┃</span>\n",
+       "<span style=\"color: #008080; text-decoration-color: #008080\">┃</span>                                                                                <span style=\"color: #008080; text-decoration-color: #008080\">┃</span>\n",
+       "<span style=\"color: #008080; text-decoration-color: #008080\">┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛</span>\n",
+       "</pre>\n"
+      ],
+      "text/plain": [
+       "\u001b[36m┏━\u001b[0m\u001b[36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[36m Agent Playground \u001b[0m\u001b[36m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[36m━┓\u001b[0m\n",
+       "\u001b[36m┃\u001b[0m                                                                                \u001b[36m┃\u001b[0m\n",
+       "\u001b[36m┃\u001b[0m                                                                                \u001b[36m┃\u001b[0m\n",
+       "\u001b[36m┃\u001b[0m  \u001b[1;32mPlayground URL:\u001b[0m \u001b]8;id=527383;https://app.agno.com/playground?endpoint=localhost%3A7777/v1\u001b\\https://app.agno.com/playground?endpoint=localhost%3A7777/v1\u001b]8;;\u001b\\  \u001b[36m┃\u001b[0m\n",
+       "\u001b[36m┃\u001b[0m                                                                                \u001b[36m┃\u001b[0m\n",
+       "\u001b[36m┃\u001b[0m                                                                                \u001b[36m┃\u001b[0m\n",
+       "\u001b[36m┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛\u001b[0m\n"
+      ]
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "INFO:     Will watch for changes in these directories: ['d:\\\\yusys\\\\ai_learning\\\\曹航\\\\3']\n",
+      "INFO:     Uvicorn running on http://localhost:7777 (Press CTRL+C to quit)\n",
+      "INFO:     Started reloader process [21576] using WatchFiles\n",
+      "INFO:     Stopping reloader process [21576]\n"
+     ]
+    }
+   ],
+   "source": [
+    "# 启动playground-server\n",
+    "playground = Playground(agents=[transfer_agent, finance_agent])\n",
+    "app = playground.get_app()\n",
+    "\n",
+    "playground.serve(\"agno_transfer_agent:app\", reload=True)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "bc32bba1",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": ".venv",
+   "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.11.13"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}

+ 146 - 0
曹航/3/agno_transfer_agent.py

@@ -0,0 +1,146 @@
+from logging import log
+from textwrap import dedent
+
+from agno.agent import Agent
+from agno.models.openai import OpenAILike
+from agno.playground import Playground
+from agno.storage.sqlite import SqliteStorage
+from agno.tools.yfinance import YFinanceTools
+from agno.tools import tool
+
+import os
+from agno.utils.log import log_info
+from dotenv import load_dotenv
+load_dotenv()
+#数据存储位置
+agent_storage: str = "transfer/tmp/agents.db"
+
+#测试
+finance_agent = Agent(
+    name="Finance Agent",
+    model=OpenAILike(id="qwen3-32b",
+                    api_key=os.getenv("BAILIAN_API_KEY"), 
+                    base_url=os.getenv("BAILIAN_API_BASE_URL"),
+                    request_params={"extra_body": {"enable_thinking": False}},),
+    tools=[YFinanceTools(stock_price=True, analyst_recommendations=True, company_info=True, company_news=True)],
+    instructions=["Always use tables to display data"],
+    storage=SqliteStorage(table_name="finance_agent", db_file=agent_storage),
+    add_datetime_to_instructions=True,
+    add_history_to_messages=True,
+    num_history_responses=5,
+    markdown=True,
+)
+# 从transfer/prompt目录读取prompt文件
+# with open("transfer/prompt/prompt.txt", "r", encoding="utf-8") as f:
+#     prompt_text = f.read()
+
+prompt_text="""
+    ## 背景与目标
+    你是一个金融助手 Agent,使用 Qwen3-32B 模型驱动,负责协助用户完成向他人账户转账的流程。/
+    当用户提问你其它与转账不相关的问题时,你应该时刻提醒并保持礼貌。/
+    你将通过自然语言与用户对话,收集必要信息,确认并调用转账接口完成操作。
+    请根据以下流程与规则进行对话与操作。
+
+    ## 任务流程
+
+    ### 进行信息收集
+    请通过对话与用户交互,依次确认并记录以下三项转账信息:
+
+    1. 通过对方姓名查询账户是否存在(`get_contact`)
+    2. 确认转账金额是否大于账户余额(`get_balance`)
+    3. 余额不足时,请重新向用户收集信息,继续转账(`replay_to_user`)
+
+    > 请在用户表达不清或信息缺失时,请通过方法 `replay_to_user` 发起澄清。
+
+    ### 执行转账
+    确认收集信息后,请总结信息,并请发起转账(`transfer`)
+
+"""
+# 创建用户列表
+users = [
+    {"name": "张三","phone": "13800138000","amount": 1000.0},
+    {"name": "李四","phone": "13800138001","amount": 500.0},
+]
+
+# 定义转账相关的工具函数
+def get_contact(user_name: str) -> bool:
+    """
+    检查账户是否存在
+    Args:
+        account_number: 账号
+    Returns:
+        bool: 账户是否存在
+    """
+    # 这里模拟账户检查逻辑
+    if user_name == "张三":
+        return True
+    else:
+        return False
+
+def get_balance() -> float:
+    """
+    查询账户余额
+    Returns:
+        float: 账户余额
+    """
+    balance=users[1]["amount"]
+    return balance
+
+#TODO 做用户确认
+# @tool(requires_user_input=True,user_input_fields=["amount"])
+def transfer(user_name, phone: str, amount: float) -> bool:
+    """
+    执行转账操作
+    Args:
+        to_account: 转入账号 
+        amount: 转账金额
+    Returns:
+        bool: 转账是否成功
+    """
+    # 这里模拟转账逻辑
+    users[0]["amount"] += amount
+    print(f"向{user_name}转账{amount}元成功")
+    return True
+
+def replay_to_user(message: str)->str:
+    """
+    当前步骤需要用户输入时,请通过此方法向用户提问
+    向用户提问获取信息,并记录到log
+    Args:
+        message: 提问内容
+    
+    """
+    # 这里实现向用户提问的逻辑
+    #只是记录log
+    log_info(message)
+    return "请等待用户回答"
+
+transfer_agent = Agent(
+    name="Transfer Agent",
+    model=OpenAILike(id="qwen3-32b",
+                    api_key=os.getenv("BAILIAN_API_KEY"), 
+                    base_url=os.getenv("BAILIAN_API_BASE_URL"),
+                    request_params={"extra_body": {"enable_thinking": False}},),
+    tools=[get_contact,get_balance,transfer,replay_to_user],
+    #TODO memory记忆
+    # memory=SqliteStorage(table_name="transfer_agent", db_file=agent_storage),
+    instructions=dedent(prompt_text),
+    # Store the agent sessions in a sqlite database
+    storage=SqliteStorage(table_name="transfer_agent", db_file=agent_storage),
+    show_tool_calls=True,
+    # Adds the current date and time to the instructions
+    add_datetime_to_instructions=True,
+    # Adds the history of the conversation to the messages
+    add_history_to_messages=True,
+    # Number of history responses to add to the messages
+    num_history_responses=5,
+    # Adds markdown formatting to the messages
+    markdown=True,
+)
+
+# 启动playground-server
+playground = Playground(agents=[transfer_agent, finance_agent])
+app = playground.get_app()
+
+if __name__ == "__main__":
+    playground.serve("agno_transfer_agent:app", reload=True)

BIN
曹航/3/temp/agent.db


BIN
曹航/3/tmp/agent.db


+ 18 - 0
曹航/3/transfer/prompt/prompt.txt

@@ -0,0 +1,18 @@
+# Agent 任务定义:协助用户完成转账操作
+
+## 背景与目标
+你是一个金融助手 Agent,使用 Qwen3-32B 模型驱动,负责协助用户完成向他人账户转账的流程。你将通过自然语言与用户对话,收集必要信息,确认并调用转账接口完成操作。请根据以下流程与规则进行对话与操作。
+
+## 任务流程
+
+### 第一步:信息收集
+请通过对话与用户交互,依次确认并记录以下三项转账信息:
+
+1. 对方姓名(`recipient_name`)
+2. 对方卡号(`recipient_account_number`)
+3. 转账金额(`transfer_amount`)
+
+> 请在用户表达不清或信息缺失时调用 `clarify(question: str)` 方法发起澄清。
+
+### 第二步:执行转账
+信息收集完毕后,调用以下方法发起转账操作:

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor