Browse Source

SSE+FastAPI

iTTsShuu 1 tháng trước cách đây
mục cha
commit
b32a3f480f

+ 1 - 1
pyproject.toml

@@ -13,7 +13,7 @@ dependencies = [
     "pandas",
     "yfinance>=0.2.65",
     "ipywidgets",
-    "sqlalchemy"
+    "sqlalchemy",
     "pandas>=2.3.1",
 ]
 

+ 485 - 888
曹航/3/agent_test2.ipynb

@@ -1,891 +1,488 @@
 {
- "cells": [
-  {
-   "cell_type": "code",
-<<<<<<< HEAD
-<<<<<<< HEAD
-   "execution_count": 1,
-=======
-   "execution_count": 11,
->>>>>>> bad0e67 (多轮对话+agno agent学习实践)
-=======
-   "execution_count": 1,
->>>>>>> d788ac0 (agno练习+转账agent)
-   "id": "a4856341",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "True"
-      ]
-     },
-<<<<<<< HEAD
-<<<<<<< HEAD
-     "execution_count": 1,
-=======
-     "execution_count": 11,
->>>>>>> bad0e67 (多轮对话+agno agent学习实践)
-=======
-     "execution_count": 1,
->>>>>>> d788ac0 (agno练习+转账agent)
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "from textwrap import dedent\n",
-<<<<<<< HEAD
-<<<<<<< HEAD
-    "\n",
-    "from agno.agent import Agent\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 agno.tools import tool,FunctionCall\n",
-    "from agno.tools.dalle import DalleTools\n",
-    "from agno.storage.sqlite import SqliteStorage\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",
-    "import json\n",
-    "load_dotenv()\n"
-=======
-=======
-    "\n",
->>>>>>> d788ac0 (agno练习+转账agent)
-    "from agno.agent import Agent\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 agno.tools import tool,FunctionCall\n",
-    "from agno.tools.dalle import DalleTools\n",
-    "from agno.storage.sqlite import SqliteStorage\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",
-<<<<<<< HEAD
-    "load_dotenv()\n",
-    "\n"
->>>>>>> bad0e67 (多轮对话+agno agent学习实践)
-=======
-    "import json\n",
-    "load_dotenv()\n"
->>>>>>> d788ac0 (agno练习+转账agent)
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "aecbb750",
-   "metadata": {},
-   "source": [
-    "**agent state**"
-   ]
-  },
-  {
-   "cell_type": "code",
-<<<<<<< HEAD
-<<<<<<< HEAD
-   "execution_count": 2,
-=======
-   "execution_count": null,
->>>>>>> bad0e67 (多轮对话+agno agent学习实践)
-=======
-   "execution_count": 2,
->>>>>>> d788ac0 (agno练习+转账agent)
-   "id": "46403d1a",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "application/vnd.jupyter.widget-view+json": {
-<<<<<<< HEAD
-<<<<<<< HEAD
-       "model_id": "b5e36e3099374134807dcb494a113ff1",
-=======
-       "model_id": "9b3d2e36a97047dcaf90b8a373c1c2c1",
->>>>>>> bad0e67 (多轮对话+agno agent学习实践)
-=======
-       "model_id": "b5e36e3099374134807dcb494a113ff1",
->>>>>>> d788ac0 (agno练习+转账agent)
-       "version_major": 2,
-       "version_minor": 0
-      },
-      "text/plain": [
-       "Output()"
-      ]
-     },
-     "metadata": {},
-     "output_type": "display_data"
+    "cells": [
+        {
+            "cell_type": "code",
+            "execution_count": 1,
+            "id": "a4856341",
+            "metadata": {},
+            "outputs": [
+                {
+                    "data": {
+                        "text/plain": [
+                            "True"
+                        ]
+                    },
+                    "execution_count": 1,
+                    "metadata": {},
+                    "output_type": "execute_result"
+                }
+            ],
+            "source": [
+                "from textwrap import dedent\n",
+                "from agno.agent import Agent\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 agno.tools import tool,FunctionCall\n",
+                "from agno.tools.dalle import DalleTools\n",
+                "from agno.storage.sqlite import SqliteStorage\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",
+                "import json\n",
+                "load_dotenv()\n"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "aecbb750",
+            "metadata": {},
+            "source": [
+                "**agent state**"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": 2,
+            "id": "46403d1a",
+            "metadata": {},
+            "outputs": [
+                {
+                    "data": {
+                        "application/vnd.jupyter.widget-view+json": {
+                            "model_id": "b5e36e3099374134807dcb494a113ff1",
+                            "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": [
+                        "Final session state: {'shopping_list': ['milk', 'eggs', 'bread'], 'current_session_id': 'c0e056e2-5ea1-4e62-a955-227f6485ffa6'}\n"
+                    ]
+                }
+            ],
+            "source": [
+                "# Define a tool that adds an item to the shopping list\n",
+                "def add_item(agent: Agent, item: str) -> str:\n",
+                "    \"\"\"Add an item to the shopping list.\"\"\"\n",
+                "    if agent.session_state is None:\n",
+                "        agent.session_state = {}\n",
+                "    if \"shopping_list\" not in agent.session_state:\n",
+                "        agent.session_state[\"shopping_list\"] = []\n",
+                "    agent.session_state[\"shopping_list\"].append(item)\n",
+                "    return f\"The shopping list is now {agent.session_state['shopping_list']}\"\n",
+                "\n",
+                "agent = Agent(\n",
+                "name=\"my_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",
+                "markdown=True,\n",
+                "# Initialize the session state with a counter starting at 0\n",
+                "session_state={\"shopping_list\": []},\n",
+                "tools=[add_item],\n",
+                "# You can use variables from the session state in the instructions\n",
+                "instructions=\"Current state (shopping list) is: {shopping_list}\",\n",
+                "# Important: Add the state to the messages\n",
+                "add_state_in_messages=True,\n",
+                ")\n",
+                "\n",
+                "# Example usage\n",
+                "agent.print_response(\"Add milk, eggs, and bread to the shopping list\", stream=True)\n",
+                "print(f\"Final session state: {agent.session_state}\")"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": null,
+            "id": "8e7e7a5b",
+            "metadata": {},
+            "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",
+                "    if agent.session_state is None:\n",
+                "        agent.session_state = {}\n",
+                "    if \"shopping_list\" not in agent.session_state:\n",
+                "        agent.session_state[\"shopping_list\"] = []\n",
+                "\n",
+                "    # Add the item if it's not already in the list\n",
+                "    if item.lower() not in [i.lower() for i in agent.session_state[\"shopping_list\"]]:\n",
+                "        agent.session_state[\"shopping_list\"].append(item)\n",
+                "        return f\"Added '{item}' to the shopping list\"\n",
+                "    else:\n",
+                "        return f\"'{item}' is already in the shopping list\"\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",
+                "    if agent.session_state is None:\n",
+                "        agent.session_state = {}\n",
+                "    if \"shopping_list\" not in agent.session_state:\n",
+                "        agent.session_state[\"shopping_list\"] = []\n",
+                "\n",
+                "    for i, list_item in enumerate(agent.session_state[\"shopping_list\"]):\n",
+                "        if list_item.lower() == item.lower():\n",
+                "            agent.session_state[\"shopping_list\"].pop(i)\n",
+                "            return f\"Removed '{list_item}' from the shopping list\"\n",
+                "\n",
+                "    return f\"'{item}' was not found in the shopping list\"\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",
+                "        agent.session_state = {}\n",
+                "    if \"shopping_list\" not in agent.session_state:\n",
+                "        agent.session_state[\"shopping_list\"] = []\n",
+                "        \n",
+                "    shopping_list = agent.session_state[\"shopping_list\"]\n",
+                "\n",
+                "    if not shopping_list:\n",
+                "        return \"The shopping list is empty.\"\n",
+                "\n",
+                "    items_text = \"\\n\".join([f\"- {item}\" for item in shopping_list])\n",
+                "    return f\"Current shopping list:\\n{items_text}\"\n",
+                "\n",
+                "\n",
+                "# Create a Shopping List Manager Agent that maintains state\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",
+                "    # Initialize the session state with an empty shopping list\n",
+                "    session_state={\"shopping_list\": []},\n",
+                "    tools=[add_item, remove_item, list_items],\n",
+                "    # You can use variables from the session state in the instructions\n",
+                "    instructions=dedent(\"\"\"\\\n",
+                "        Your job is to manage a shopping list.\n",
+                "\n",
+                "        The shopping list starts empty. You can add items, remove items by name, and list all items.\n",
+                "\n",
+                "        Current shopping list: {shopping_list}\n",
+                "    \"\"\"),\n",
+                "    show_tool_calls=True,\n",
+                "    add_state_in_messages=True,\n",
+                "    markdown=True,\n",
+                ")\n",
+                "\n",
+                "# Example usage\n",
+                "agent.print_response(\"Add milk, eggs, and bread to the shopping list\", stream=True)\n",
+                "print(f\"Session state: {agent.session_state}\")\n",
+                "\n",
+                "agent.print_response(\"I got bread\", stream=True)\n",
+                "print(f\"Session state: {agent.session_state}\")\n",
+                "\n",
+                "agent.print_response(\"I need apples and oranges\", stream=True)\n",
+                "print(f\"Session state: {agent.session_state}\")\n",
+                "\n",
+                "agent.print_response(\"whats on my list?\", stream=True)\n",
+                "print(f\"Session state: {agent.session_state}\")\n",
+                "\n",
+                "agent.print_response(\"Clear everything from my list and start over with just bananas and yogurt\", stream=True)\n",
+                "print(f\"Session state: {agent.session_state}\")"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "e6e0404f",
+            "metadata": {},
+            "source": [
+                "**Memory**"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": null,
+            "id": "1f118e71",
+            "metadata": {},
+            "outputs": [],
+            "source": [
+                "# UserId for the memories\n",
+                "user_id = \"ava\"\n",
+                "# Database file for memory and storage\n",
+                "db_file = \"temp/agent.db\"\n",
+                "\n",
+                "# Initialize memory.v2\n",
+                "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",
+                "    db=SqliteMemoryDb(table_name=\"user_memories\", db_file=db_file),\n",
+                ")\n",
+                "# Initialize storage\n",
+                "storage = SqliteStorage(table_name=\"agent_sessions\", db_file=db_file)\n",
+                "\n",
+                "# Initialize Agent\n",
+                "memory_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",
+                "    # Store memories in a database\n",
+                "    memory=memory,\n",
+                "    # Give the Agent the ability to update memories\n",
+                "    enable_agentic_memory=True,\n",
+                "    # OR - Run the MemoryManager after each response\n",
+                "    enable_user_memories=True,\n",
+                "    # Store the chat history in the database\n",
+                "    storage=storage,\n",
+                "    # Add the chat history to the messages\n",
+                "    add_history_to_messages=True,\n",
+                "    # Number of history runs\n",
+                "    num_history_runs=3,\n",
+                "    markdown=True,\n",
+                ")\n",
+                "\n",
+                "memory.clear()\n",
+                "memory_agent.print_response(\n",
+                "    \"My name is Ava and I like to ski.\",\n",
+                "    user_id=user_id,\n",
+                "    stream=True,\n",
+                "    stream_intermediate_steps=True,\n",
+                ")\n",
+                "print(\"Memories about Ava:\")\n",
+                "pprint(memory.get_user_memories(user_id=user_id))\n",
+                "\n",
+                "memory_agent.print_response(\n",
+                "    \"I live in san francisco, where should i move within a 4 hour drive?\",\n",
+                "    user_id=user_id,\n",
+                "    stream=True,\n",
+                "    stream_intermediate_steps=True,\n",
+                ")\n",
+                "print(\"Memories about Ava:\")\n",
+                "pprint(memory.get_user_memories(user_id=user_id))"
+            ]
+        },
+        {
+            "cell_type": "markdown",
+            "id": "cd046ec3",
+            "metadata": {},
+            "source": [
+                "**structured output**"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": null,
+            "id": "67fbf2a4",
+            "metadata": {},
+            "outputs": [],
+            "source": [
+                "class MovieScript(BaseModel):\n",
+                "    setting: str = Field(\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=\"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=\"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(\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",
+                "    storyline: str = Field(\n",
+                "        ...,\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 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=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",
+                ")\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": "5cddde6d",
+            "metadata": {},
+            "source": []
+        },
+        {
+            "cell_type": "markdown",
+            "id": "80d94c56",
+            "metadata": {},
+            "source": [
+                "**Multimodal Agent**"
+            ]
+        },
+        {
+            "cell_type": "code",
+            "execution_count": null,
+            "id": "accc8ac2",
+            "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"
+        }
     },
-    {
-     "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": [
-<<<<<<< HEAD
-<<<<<<< HEAD
-      "Final session state: {'shopping_list': ['milk', 'eggs', 'bread'], 'current_session_id': 'c0e056e2-5ea1-4e62-a955-227f6485ffa6'}\n"
-=======
-      "Final session state: {'shopping_list': ['milk', 'eggs', 'bread'], 'current_session_id': 'fb205638-5e39-40e7-8722-1aedcd7995e0'}\n"
->>>>>>> bad0e67 (多轮对话+agno agent学习实践)
-=======
-      "Final session state: {'shopping_list': ['milk', 'eggs', 'bread'], 'current_session_id': 'c0e056e2-5ea1-4e62-a955-227f6485ffa6'}\n"
->>>>>>> d788ac0 (agno练习+转账agent)
-     ]
-    }
-   ],
-   "source": [
-    "# Define a tool that adds an item to the shopping list\n",
-    "def add_item(agent: Agent, item: str) -> str:\n",
-    "    \"\"\"Add an item to the shopping list.\"\"\"\n",
-    "    if agent.session_state is None:\n",
-    "        agent.session_state = {}\n",
-    "    if \"shopping_list\" not in agent.session_state:\n",
-    "        agent.session_state[\"shopping_list\"] = []\n",
-    "    agent.session_state[\"shopping_list\"].append(item)\n",
-    "    return f\"The shopping list is now {agent.session_state['shopping_list']}\"\n",
-    "\n",
-    "agent = Agent(\n",
-    "name=\"my_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",
-    "markdown=True,\n",
-    "# Initialize the session state with a counter starting at 0\n",
-    "session_state={\"shopping_list\": []},\n",
-    "tools=[add_item],\n",
-    "# You can use variables from the session state in the instructions\n",
-    "instructions=\"Current state (shopping list) is: {shopping_list}\",\n",
-    "# Important: Add the state to the messages\n",
-    "add_state_in_messages=True,\n",
-    ")\n",
-    "\n",
-    "# Example usage\n",
-    "agent.print_response(\"Add milk, eggs, and bread to the shopping list\", stream=True)\n",
-    "print(f\"Final session state: {agent.session_state}\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-<<<<<<< HEAD
-<<<<<<< HEAD
-   "execution_count": null,
-   "id": "8e7e7a5b",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Define tools to manage our shopping list\n",
-    "@tool(description=\"Add an item to the shopping list.\")\n",
-=======
-   "execution_count": 6,
-=======
-   "execution_count": null,
->>>>>>> d788ac0 (agno练习+转账agent)
-   "id": "8e7e7a5b",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "# Define tools to manage our shopping list\n",
-<<<<<<< HEAD
->>>>>>> bad0e67 (多轮对话+agno agent学习实践)
-=======
-    "@tool(description=\"Add an item to the shopping list.\")\n",
->>>>>>> d788ac0 (agno练习+转账agent)
-    "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",
-    "    if agent.session_state is None:\n",
-    "        agent.session_state = {}\n",
-    "    if \"shopping_list\" not in agent.session_state:\n",
-    "        agent.session_state[\"shopping_list\"] = []\n",
-    "\n",
-    "    # Add the item if it's not already in the list\n",
-    "    if item.lower() not in [i.lower() for i in agent.session_state[\"shopping_list\"]]:\n",
-    "        agent.session_state[\"shopping_list\"].append(item)\n",
-    "        return f\"Added '{item}' to the shopping list\"\n",
-    "    else:\n",
-    "        return f\"'{item}' is already in the shopping list\"\n",
-    "\n",
-<<<<<<< HEAD
-<<<<<<< HEAD
-    "@tool(description=\"Remove an item from the shopping list by name.\")\n",
-=======
-    "\n",
->>>>>>> bad0e67 (多轮对话+agno agent学习实践)
-=======
-    "@tool(description=\"Remove an item from the shopping list by name.\")\n",
->>>>>>> d788ac0 (agno练习+转账agent)
-    "def remove_item(agent: Agent, item: str) -> str:\n",
-    "    \"\"\"Remove an item from the shopping list by name.\"\"\"\n",
-    "    # Case-insensitive search\n",
-    "    if agent.session_state is None:\n",
-    "        agent.session_state = {}\n",
-    "    if \"shopping_list\" not in agent.session_state:\n",
-    "        agent.session_state[\"shopping_list\"] = []\n",
-    "\n",
-    "    for i, list_item in enumerate(agent.session_state[\"shopping_list\"]):\n",
-    "        if list_item.lower() == item.lower():\n",
-    "            agent.session_state[\"shopping_list\"].pop(i)\n",
-    "            return f\"Removed '{list_item}' from the shopping list\"\n",
-    "\n",
-    "    return f\"'{item}' was not found in the shopping list\"\n",
-    "\n",
-<<<<<<< HEAD
-<<<<<<< HEAD
-    "@tool(description=\"List all items in the shopping list.\")\n",
-=======
-    "\n",
->>>>>>> bad0e67 (多轮对话+agno agent学习实践)
-=======
-    "@tool(description=\"List all items in the shopping list.\")\n",
->>>>>>> d788ac0 (agno练习+转账agent)
-    "def list_items(agent: Agent) -> str:\n",
-    "    \"\"\"List all items in the shopping list.\"\"\"\n",
-    "    if agent.session_state is None:\n",
-    "        agent.session_state = {}\n",
-    "    if \"shopping_list\" not in agent.session_state:\n",
-    "        agent.session_state[\"shopping_list\"] = []\n",
-    "        \n",
-    "    shopping_list = agent.session_state[\"shopping_list\"]\n",
-    "\n",
-    "    if not shopping_list:\n",
-    "        return \"The shopping list is empty.\"\n",
-    "\n",
-    "    items_text = \"\\n\".join([f\"- {item}\" for item in shopping_list])\n",
-    "    return f\"Current shopping list:\\n{items_text}\"\n",
-    "\n",
-    "\n",
-    "# Create a Shopping List Manager Agent that maintains state\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",
-    "    # Initialize the session state with an empty shopping list\n",
-    "    session_state={\"shopping_list\": []},\n",
-    "    tools=[add_item, remove_item, list_items],\n",
-    "    # You can use variables from the session state in the instructions\n",
-    "    instructions=dedent(\"\"\"\\\n",
-    "        Your job is to manage a shopping list.\n",
-    "\n",
-    "        The shopping list starts empty. You can add items, remove items by name, and list all items.\n",
-    "\n",
-    "        Current shopping list: {shopping_list}\n",
-    "    \"\"\"),\n",
-    "    show_tool_calls=True,\n",
-    "    add_state_in_messages=True,\n",
-    "    markdown=True,\n",
-    ")\n",
-    "\n",
-    "# Example usage\n",
-    "agent.print_response(\"Add milk, eggs, and bread to the shopping list\", stream=True)\n",
-    "print(f\"Session state: {agent.session_state}\")\n",
-    "\n",
-    "agent.print_response(\"I got bread\", stream=True)\n",
-    "print(f\"Session state: {agent.session_state}\")\n",
-    "\n",
-    "agent.print_response(\"I need apples and oranges\", stream=True)\n",
-    "print(f\"Session state: {agent.session_state}\")\n",
-    "\n",
-    "agent.print_response(\"whats on my list?\", stream=True)\n",
-    "print(f\"Session state: {agent.session_state}\")\n",
-    "\n",
-    "agent.print_response(\"Clear everything from my list and start over with just bananas and yogurt\", stream=True)\n",
-    "print(f\"Session state: {agent.session_state}\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "e6e0404f",
-   "metadata": {},
-   "source": [
-    "**Memory**"
-   ]
-  },
-  {
-   "cell_type": "code",
-<<<<<<< HEAD
-<<<<<<< HEAD
-   "execution_count": null,
-   "id": "1f118e71",
-   "metadata": {},
-   "outputs": [],
-=======
-   "execution_count": 14,
-   "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"
-    }
-   ],
->>>>>>> bad0e67 (多轮对话+agno agent学习实践)
-=======
-   "execution_count": null,
-   "id": "1f118e71",
-   "metadata": {},
-   "outputs": [],
->>>>>>> d788ac0 (agno练习+转账agent)
-   "source": [
-    "# UserId for the memories\n",
-    "user_id = \"ava\"\n",
-    "# Database file for memory and storage\n",
-    "db_file = \"temp/agent.db\"\n",
-    "\n",
-    "# Initialize memory.v2\n",
-    "memory = Memory(\n",
-    "    # Use any model for creating memories\n",
-    "    model=OpenAILike(id=\"qwen3-30b-a3b\", \n",
-<<<<<<< HEAD
-<<<<<<< HEAD
-    "                    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",
->>>>>>> bad0e67 (多轮对话+agno agent学习实践)
-=======
-    "                    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",
->>>>>>> d788ac0 (agno练习+转账agent)
-    "    db=SqliteMemoryDb(table_name=\"user_memories\", db_file=db_file),\n",
-    ")\n",
-    "# Initialize storage\n",
-    "storage = SqliteStorage(table_name=\"agent_sessions\", db_file=db_file)\n",
-    "\n",
-    "# Initialize Agent\n",
-    "memory_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",
-    "    # Store memories in a database\n",
-    "    memory=memory,\n",
-    "    # Give the Agent the ability to update memories\n",
-    "    enable_agentic_memory=True,\n",
-    "    # OR - Run the MemoryManager after each response\n",
-    "    enable_user_memories=True,\n",
-    "    # Store the chat history in the database\n",
-    "    storage=storage,\n",
-    "    # Add the chat history to the messages\n",
-    "    add_history_to_messages=True,\n",
-    "    # Number of history runs\n",
-    "    num_history_runs=3,\n",
-    "    markdown=True,\n",
-    ")\n",
-    "\n",
-    "memory.clear()\n",
-    "memory_agent.print_response(\n",
-    "    \"My name is Ava and I like to ski.\",\n",
-    "    user_id=user_id,\n",
-    "    stream=True,\n",
-    "    stream_intermediate_steps=True,\n",
-    ")\n",
-    "print(\"Memories about Ava:\")\n",
-    "pprint(memory.get_user_memories(user_id=user_id))\n",
-    "\n",
-    "memory_agent.print_response(\n",
-    "    \"I live in san francisco, where should i move within a 4 hour drive?\",\n",
-    "    user_id=user_id,\n",
-    "    stream=True,\n",
-    "    stream_intermediate_steps=True,\n",
-    ")\n",
-    "print(\"Memories about Ava:\")\n",
-    "pprint(memory.get_user_memories(user_id=user_id))"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "cd046ec3",
-   "metadata": {},
-   "source": [
-    "**structured output**"
-   ]
-  },
-  {
-   "cell_type": "code",
-<<<<<<< HEAD
-<<<<<<< HEAD
-   "execution_count": null,
-   "id": "5cddde6d",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "class MovieScript(BaseModel):\n",
-    "    setting: str = Field(\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=\"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=\"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(\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",
-    "    storyline: str = Field(\n",
-    "        ...,\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 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=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",
-    "# 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**"
-=======
-   "execution_count": 13,
-=======
-   "execution_count": null,
->>>>>>> d788ac0 (agno练习+转账agent)
-   "id": "5cddde6d",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "class MovieScript(BaseModel):\n",
-    "    setting: str = Field(\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=\"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=\"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(\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",
-    "    storyline: str = Field(\n",
-    "        ...,\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 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=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",
-<<<<<<< HEAD
-    "structured_output_agent.print_response(\n",
-    "    \"New York\", stream=True, stream_intermediate_steps=True\n",
-    ")"
->>>>>>> bad0e67 (多轮对话+agno agent学习实践)
-=======
-    "# 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**"
->>>>>>> d788ac0 (agno练习+转账agent)
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "accc8ac2",
-   "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
+    "nbformat": 4,
+    "nbformat_minor": 5
 }

BIN
曹航/3/transfer/tmp/agents.db


+ 216 - 0
曹航/4/SSE.html

@@ -0,0 +1,216 @@
+<!DOCTYPE html>
+<html lang="zh">
+<head>
+    <meta charset="UTF-8">
+    <title>SSE 多轮对话演示</title>
+    <style>
+        body {
+            background: #f6f8fa;
+            font-family: "Segoe UI", "PingFang SC", "Microsoft YaHei", Arial, sans-serif;
+        }
+        #chatbox {
+            width: 480px;
+            margin: 40px auto;
+            background: #fff;
+            border-radius: 10px;
+            box-shadow: 0 2px 12px #0001;
+            padding: 24px 24px 12px 24px;
+        }
+        #history {
+            min-height: 240px;
+            max-height: 400px;
+            overflow-y: auto;
+            margin-bottom: 16px;
+            padding-right: 8px;
+        }
+        .msg-row {
+            display: flex;
+            margin-bottom: 8px;
+        }
+        .msg-user {
+            justify-content: flex-end;
+        }
+        .msg-ai {
+            justify-content: flex-start;
+        }
+        .bubble {
+            max-width: 70%;
+            padding: 10px 16px;
+            border-radius: 18px;
+            font-size: 15px;
+            line-height: 1.6;
+            box-shadow: 0 1px 4px #0001;
+            word-break: break-all;
+            position: relative;
+        }
+        .bubble-user {
+            background: linear-gradient(90deg, #6ec1e4 0%, #367be2 100%);
+            color: #fff;
+            border-bottom-right-radius: 4px;
+        }
+        .bubble-ai {
+            background: #f0f1f5;
+            color: #222;
+            border-bottom-left-radius: 4px;
+        }
+        .bubble-label {
+            font-size: 12px;
+            color: #888;
+            position: absolute;
+            top: -18px;
+            left: 0;
+            white-space: nowrap;
+        }
+        .bubble-user .bubble-label {
+            right: 0;
+            left: auto;
+            color: #6ec1e4;
+        }
+        .bubble-ai .bubble-label {
+            left: 0;
+            color: #888;
+        }
+        #input-area {
+            display: flex;
+            gap: 8px;
+            margin-top: 8px;
+        }
+        #input {
+            flex: 1;
+            padding: 8px 12px;
+            border-radius: 6px;
+            border: 1px solid #d0d7de;
+            font-size: 15px;
+        }
+        #output {
+            display: none;
+        }
+        #username, #userid {
+            width: 90px;
+            margin-right: 8px;
+            padding: 4px 8px;
+            border-radius: 4px;
+            border: 1px solid #d0d7de;
+        }
+        #send-btn {
+            background: #367be2;
+            color: #fff;
+            border: none;
+            border-radius: 6px;
+            padding: 0 18px;
+            font-size: 15px;
+            cursor: pointer;
+            transition: background 0.2s;
+        }
+        #send-btn:hover {
+            background: #265bb5;
+        }
+    </style>
+</head>
+<body>
+    <div id="chatbox">
+        <div style="margin-bottom: 10px;">
+            用户名:<input id="username" value="web_user">
+            用户ID:<input id="userid" value="web_001">
+        </div>
+        <div id="history"></div>
+        <div id="output"></div>
+        <div id="input-area">
+            <input id="input" type="text" placeholder="请输入你的问题...">
+            <button id="send-btn" onclick="send()">发送</button>
+        </div>
+    </div>
+    <script>
+        // 获取页面元素
+        let historyDiv = document.getElementById('history');
+        let output = document.getElementById('output');
+        let inputBox = document.getElementById('input');
+        let usernameBox = document.getElementById('username');
+        let useridBox = document.getElementById('userid');
+        // 对话上下文数组,每条消息包含role和content
+        let context = [];
+        // 自动滚动到底部
+        function scrollToBottom() {
+            historyDiv.scrollTop = historyDiv.scrollHeight;
+        }
+        // 渲染历史消息(用户和AI气泡)
+        function renderHistory() {
+            historyDiv.innerHTML = '';
+            const username = usernameBox.value;
+            for (const msg of context) {
+                if (msg.role === 'user') {
+                    historyDiv.innerHTML += `<div class='msg-row msg-user'><div class='bubble bubble-user'><span class='bubble-label'>${username}</span>${msg.content}</div></div>`;
+                } else {
+                    historyDiv.innerHTML += `<div class='msg-row msg-ai'><div class='bubble bubble-ai'><span class='bubble-label'>${agentname}</span>${msg.content}</div></div>`;
+                }
+            }
+            scrollToBottom();
+        }
+        // 发送消息主函数
+        function send() {
+            const agentname = "AI Agent";
+            const username = usernameBox.value;
+            const user_id = useridBox.value;
+            const user_message = inputBox.value.trim();
+            if (!user_message) return;
+            // 1. 添加用户消息到上下文
+            context.push({role: 'user', content: user_message});
+            // 2. 插入空AI气泡,后续AI回复会填充到这里
+            context.push({role: 'assistant', content: ''});
+            renderHistory();
+            inputBox.value = '';
+            inputBox.focus();
+            // 3. 关闭上一个EventSource,防止多路并发
+            if (window.es) { window.es.close(); window.es = null; }
+            // 4. 拼接上下文为字符串,传给后端,便于多轮对话
+            
+            // 5. 构造SSE GET请求URL
+            const url = `http://127.0.0.1:8000/agents/stream?username=${encodeURIComponent(username)}&user_id=${encodeURIComponent(user_id)}&user_message=${encodeURIComponent(user_message)}`;
+            window.es = new EventSource(url);
+            let aiMsg = '';
+            let aiQueue = []; // 存储待打字的新片段
+            let isTyping = false; // 标记当前是否在打字
+            // 6. SSE消息到达时,入队并启动typeWriter动画
+            window.es.onmessage = function(e) {
+                const text = e.data;
+                aiQueue.push(text); // 新片段入队
+                if (!isTyping) typeWriter();
+                
+            };
+            // 7. 打字机动画:每次只对新片段做动画,顺序拼接
+            function typeWriter() {
+                if (aiQueue.length === 0) {
+                    isTyping = false;
+                    return;
+                }
+                isTyping = true;
+                const text = aiQueue.shift();
+                let i = 0;
+                function typeOneByOne() {
+                    if (i < text.length) {
+                        aiMsg += text[i]; // 逐字追加到AI回复
+                        context[context.length-1].content = aiMsg; // 更新最后一个assistant气泡
+                        renderHistory();
+                        i++;
+                        setTimeout(typeOneByOne, 50); // 打字速度
+                    } else {
+                        // 递归处理下一个片段
+                        setTimeout(typeWriter,50)
+                        // typeWriter();
+                    }
+                }
+                typeOneByOne();
+            }
+            // 8. SSE错误处理,关闭连接
+            window.es.onerror = function() {
+                window.es && window.es.close();
+                window.es = null;
+            };
+        }
+        // 支持回车快捷发送
+        inputBox.addEventListener('keydown', function(e) {
+            if (e.key === 'Enter') send();
+        });
+    </script>
+</body>
+</html>

+ 55 - 0
曹航/4/agents/simple_agent.py

@@ -0,0 +1,55 @@
+from agno.agent import Agent
+from agno.memory.v2.memory import Memory
+from agno.memory.v2.db.sqlite import SqliteMemoryDb
+from agno.models.openai import OpenAILike
+from agno.storage.sqlite import SqliteStorage
+import os
+from textwrap import dedent
+from dotenv import load_dotenv
+load_dotenv()
+
+agent_storage = "./曹航/4/agents/tmp/agents.db"
+
+simple_info_agent_prompt = dedent('''
+你是一个专业的信息收集助手。你的任务是收集用户的姓名、年龄和用户感兴趣的行业。
+
+信息收集策略:
+1. 使用开放式问题引导用户提供更多信息
+2. 对模糊的信息进行澄清和确认
+3. 根据上下文,智能地推断和补充相关信息
+4. 保持对话的自然性和连贯性
+
+对话要求:
+1. 保持友好、专业的语调
+2. 每次回复要简洁明了
+3. 适时总结已收集的信息
+4. 当用户询问一些其他问题时,请礼貌地告诉用户,你是一个信息收集助手,不回答其它不相关问题。提醒用户还没收集完成。
+''')
+
+memory = Memory(
+    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}},
+    ),
+    db=SqliteMemoryDb(table_name="simple_info_agent_memory", db_file=agent_storage),
+)
+
+simple_info_agent = Agent(
+    name="SimpleInfoAgent",
+    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}},
+    ),
+    instructions=simple_info_agent_prompt,
+    storage=SqliteStorage(table_name="simple_info_agent", db_file=agent_storage),
+    # 记忆
+    memory=memory,
+    add_datetime_to_instructions=True,
+    add_history_to_messages=True,
+    num_history_responses=5,
+    markdown=True,
+) 

BIN
曹航/4/agents/tmp/agents.db


+ 8 - 0
曹航/4/event.txt

@@ -0,0 +1,8 @@
+RunResponseContentEvent(created_at=1752740344, event='RunResponseContent', agent_id='f7b85cb1-6778-44f2-8533-58f93e685818', agent_name='SimpleInfoAgent', run_id='042ae108-65c7-4fb2-8347-c54dcc9b2d5b', session_id='f282b73b-d835-4923-a6d1-04449684a6e9', team_session_id=None, content='', content_type='str', thinking='', citations=None, response_audio=None, image=None, extra_data=None)
+RunResponseContentEvent(created_at=1752740344, event='RunResponseContent', agent_id='f7b85cb1-6778-44f2-8533-58f93e685818', agent_name='SimpleInfoAgent', run_id='042ae108-65c7-4fb2-8347-c54dcc9b2d5b', session_id='f282b73b-d835-4923-a6d1-04449684a6e9', team_session_id=None, content='你好', content_type='str', thinking='', citations=None, response_audio=None, image=None, extra_data=None)
+RunResponseContentEvent(created_at=1752740344, event='RunResponseContent', agent_id='f7b85cb1-6778-44f2-8533-58f93e685818', agent_name='SimpleInfoAgent', run_id='042ae108-65c7-4fb2-8347-c54dcc9b2d5b', session_id='f282b73b-d835-4923-a6d1-04449684a6e9', team_session_id=None, content='!', content_type='str', thinking='', citations=None, response_audio=None, image=None, extra_data=None)
+RunResponseContentEvent(created_at=1752740344, event='RunResponseContent', agent_id='f7b85cb1-6778-44f2-8533-58f93e685818', agent_name='SimpleInfoAgent', run_id='042ae108-65c7-4fb2-8347-c54dcc9b2d5b', session_id='f282b73b-d835-4923-a6d1-04449684a6e9', team_session_id=None, content='很高兴', content_type='str', thinking='', citations=None, response_audio=None, image=None, extra_data=None)
+RunResponseContentEvent(created_at=1752740344, event='RunResponseContent', agent_id='f7b85cb1-6778-44f2-8533-58f93e685818', agent_name='SimpleInfoAgent', run_id='042ae108-65c7-4fb2-8347-c54dcc9b2d5b', session_id='f282b73b-d835-4923-a6d1-04449684a6e9', team_session_id=None, content='见到', content_type='str', thinking='', citations=None, response_audio=None, image=None, extra_data=None)
+RunResponseContentEvent(created_at=1752740344, event='RunResponseContent', agent_id='f7b85cb1-6778-44f2-8533-58f93e685818', agent_name='SimpleInfoAgent', run_id='042ae108-65c7-4fb2-8347-c54dcc9b2d5b', session_id='f282b73b-d835-4923-a6d1-04449684a6e9', team_session_id=None, content='你。请问你的', content_type='str', thinking='', citations=None, response_audio=None, image=None, extra_data=None)
+RunResponseContentEvent(created_at=1752740344, event='RunResponseContent', agent_id='f7b85cb1-6778-44f2-8533-58f93e685818', agent_name='SimpleInfoAgent', run_id='042ae108-65c7-4fb2-8347-c54dcc9b2d5b', session_id='f282b73b-d835-4923-a6d1-04449684a6e9', team_session_id=None, content='名字是?', content_type='str', thinking='', citations=None, response_audio=None, image=None, extra_data=None)
+RunResponseContentEvent(created_at=1752740344, event='RunResponseContent', agent_id='f7b85cb1-6778-44f2-8533-58f93e685818', agent_name='SimpleInfoAgent', run_id='042ae108-65c7-4fb2-8347-c54dcc9b2d5b', session_id='f282b73b-d835-4923-a6d1-04449684a6e9', team_session_id=None, content='', content_type='str', thinking='', citations=None, response_audio=None, image=None, extra_data=None)

+ 35 - 0
曹航/4/routes/sse_agents_route.py

@@ -0,0 +1,35 @@
+from fastapi import APIRouter, Query
+from fastapi.responses import StreamingResponse
+import sys
+import os
+
+sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+from agents.simple_agent import simple_info_agent  # 导入基于agno框架的信息收集Agent
+
+agents_route = APIRouter(prefix="/agents",tags=["agents"])
+
+@agents_route.get("/stream")
+async def chat_stream(
+    username: str = Query(..., description="用户名"),
+    user_id: str = Query(..., description="用户ID"),
+    user_message: str = Query(..., description="用户消息")
+):
+    """
+    SSE接口,流式输出Agent响应。
+    用户输入通过GET的query参数传递,包含username、user_id、user_message。
+    """
+    if not user_message:
+        user_message = "你好,请介绍一下你自己。"
+
+    def agno_stream():
+        """
+        生成SSE数据流,逐步输出Agent的响应内容。
+        agno的Agent.run支持stream=True,返回事件生成器。
+        """
+        for event in simple_info_agent.run(user_message, stream=True,username=username,user_id=user_id):
+            if hasattr(event, "content") and event.content:
+                yield f"data: {event.content}\n\n"
+
+    return StreamingResponse(agno_stream(), media_type="text/event-stream")
+
+

+ 38 - 0
曹航/4/sse_client.py

@@ -0,0 +1,38 @@
+import requests
+import sys
+import time
+
+# 定义SSE客户端函数,使用GET方法通过query参数调用SSE接口
+# 参数:用户名、用户ID、用户消息
+# 会逐步打印SSE返回的内容,实现打字机效果
+def sse_client(username, user_id, user_message):
+    url = "http://127.0.0.1:8000/agents/stream"  # SSE接口地址
+    params = {
+        "username": username,
+        "user_id": user_id,
+        "user_message": user_message
+    }
+    # 以GET方式发送参数,stream=True用于流式接收响应
+    with requests.get(url, params=params, stream=True) as resp:
+        print("Agent:", end='', flush=True)
+        for line in resp.iter_lines(decode_unicode=True):
+            if line.startswith('data: '):
+                content = line[6:]
+                print(content, end='', flush=True)  # 打字机效果输出
+                time.sleep(0.1)
+            elif line == '':
+                continue
+
+if __name__ == "__main__":
+    print("开始信息收集对话...\n")
+    # 这里直接使用固定用户名和用户ID,如需动态输入可自行修改
+    username =  "test_user"
+    user_id =  "10001"
+    while True:
+        # 用户输入消息,前缀显示用户名
+        user_message = input(f"{username}:")
+        if user_message.strip().lower() in ["exit", "退出"]:
+            print("对话结束。")
+            break
+        sse_client(username, user_id, user_message)
+        print()  # 换行,便于阅读 

+ 23 - 0
曹航/4/sse_fastapi.py

@@ -0,0 +1,23 @@
+from fastapi import FastAPI
+from fastapi.middleware.cors import CORSMiddleware
+
+from routes.sse_agents_route import agents_route
+
+# 创建FastAPI应用
+app = FastAPI()
+
+app.include_router(agents_route)
+
+# 允许跨域,方便本地和前端调试
+app.add_middleware(
+    CORSMiddleware,
+    allow_origins=["*"],  # 允许所有来源
+    allow_credentials=True,
+    allow_methods=["*"],
+    allow_headers=["*"],
+)
+
+if __name__ == "__main__":
+    # 本地调试时直接运行FastAPI服务
+    import uvicorn
+    uvicorn.run(app, host="0.0.0.0", port=8000)