Parcourir la source

Merge pull request #81 from Tasselszcx/add_chapter1

fix: LLM-based Considering universality
jjyaoao il y a 10 mois
Parent
commit
1be838be5f
1 fichiers modifiés avec 616 ajouts et 0 suppressions
  1. 616 0
      code/chapter1/FirstAgentTest.ipynb

+ 616 - 0
code/chapter1/FirstAgentTest.ipynb

@@ -0,0 +1,616 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "id": "938b2e36-f95c-4b0f-8770-335c6bb5bc0e",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import requests\n",
+    "import json\n",
+    "import os\n",
+    "import re\n",
+    "from openai import OpenAI\n",
+    "from tavily import TavilyClient\n",
+    "from dotenv import load_dotenv\n",
+    "\n",
+    "# 加载环境变量\n",
+    "load_dotenv()\n",
+    "\n",
+    "# 配置API密钥\n",
+    "API_KEY = os.getenv(\"API_KEY\")\n",
+    "BASE_URL = os.getenv(\"BASE_URL\")\n",
+    "MODEL_ID = os.getenv(\"MODEL_ID\")\n",
+    "TAVILY_API_KEY = os.getenv(\"TAVILY_API_KEY\")\n",
+    "\n",
+    "os.environ['TAVILY_API_KEY'] = TAVILY_API_KEY\n",
+    "\n",
+    "# 系统提示词\n",
+    "AGENT_SYSTEM_PROMPT = \"\"\"\n",
+    "你是一个智能旅行助手。你的任务是分析用户的请求,并使用可用工具一步步地解决问题。\n",
+    "\n",
+    "# 可用工具:\n",
+    "- `get_weather(city: str)`: 查询指定城市的实时天气。\n",
+    "- `get_attraction(city: str, weather: str)`: 根据城市和天气搜索推荐的旅游景点。\n",
+    "\n",
+    "# 行动格式:\n",
+    "你的回答必须严格遵循以下格式。首先是你的思考过程,然后是你要执行的具体行动。\n",
+    "Thought: [这里是你的思考过程和下一步计划]\n",
+    "Action: [这里是你要调用的工具,格式为 function_name(arg_name=\"arg_value\")]\n",
+    "\n",
+    "# 任务完成:\n",
+    "当你收集到足够的信息,能够回答用户的最终问题时,你必须使用 `finish(answer=\"...\")` 来输出最终答案。\n",
+    "\n",
+    "请开始吧!\n",
+    "\"\"\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "id": "66d9d404-3c95-42f2-8975-436769b3cb87",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "✅ 工具函数定义完成!\n"
+     ]
+    }
+   ],
+   "source": [
+    "def get_weather(city: str) -> str:\n",
+    "    \"\"\"\n",
+    "    通过调用 wttr.in API 查询真实的天气信息。\n",
+    "    \"\"\"\n",
+    "    # API端点,我们请求JSON格式的数据\n",
+    "    url = f\"https://wttr.in/{city}?format=j1\"\n",
+    "    \n",
+    "    try:\n",
+    "        # 发起网络请求\n",
+    "        response = requests.get(url)\n",
+    "        # 检查响应状态码是否为200 (成功)\n",
+    "        response.raise_for_status() \n",
+    "        # 解析返回的JSON数据\n",
+    "        data = response.json()\n",
+    "        \n",
+    "        # 提取当前天气状况\n",
+    "        current_condition = data['current_condition'][0]\n",
+    "        weather_desc = current_condition['weatherDesc'][0]['value']\n",
+    "        temp_c = current_condition['temp_C']\n",
+    "        \n",
+    "        # 格式化成自然语言返回\n",
+    "        return f\"{city}当前天气:{weather_desc},气温{temp_c}摄氏度\"\n",
+    "        \n",
+    "    except requests.exceptions.RequestException as e:\n",
+    "        # 处理网络错误\n",
+    "        return f\"错误:查询天气时遇到网络问题 - {e}\"\n",
+    "    except (KeyError, IndexError) as e:\n",
+    "        # 处理数据解析错误\n",
+    "        return f\"错误:解析天气数据失败,可能是城市名称无效 - {e}\"\n",
+    "\n",
+    "def get_attraction(city: str, weather: str) -> str:\n",
+    "    \"\"\"\n",
+    "    根据城市和天气,使用Tavily Search API搜索并返回优化后的景点推荐。\n",
+    "    \"\"\"\n",
+    "    api_key = os.environ.get(\"TAVILY_API_KEY\")\n",
+    "\n",
+    "    if not api_key:\n",
+    "        return \"错误:未配置TAVILY_API_KEY。\"\n",
+    "\n",
+    "    # 初始化Tavily客户端\n",
+    "    tavily = TavilyClient(api_key=api_key)\n",
+    "    \n",
+    "    # 构造一个精确的查询\n",
+    "    query = f\"'{city}' 在'{weather}'天气下最值得去的旅游景点推荐及理由\"\n",
+    "    \n",
+    "    try:\n",
+    "        # 调用API,include_answer=True会返回一个综合性的回答\n",
+    "        response = tavily.search(query=query, search_depth=\"basic\", include_answer=True)\n",
+    "        \n",
+    "        # Tavily返回的结果已经非常干净,可以直接使用\n",
+    "        if response.get(\"answer\"):\n",
+    "            return response[\"answer\"]\n",
+    "        \n",
+    "        # 如果没有综合性回答,则格式化原始结果\n",
+    "        formatted_results = []\n",
+    "        for result in response.get(\"results\", []):\n",
+    "            formatted_results.append(f\"- {result['title']}: {result['content']}\")\n",
+    "        \n",
+    "        if not formatted_results:\n",
+    "             return \"抱歉,没有找到相关的旅游景点推荐。\"\n",
+    "\n",
+    "        return \"根据搜索,为您找到以下信息:\\n\" + \"\\n\".join(formatted_results)\n",
+    "\n",
+    "    except Exception as e:\n",
+    "        return f\"错误:执行Tavily搜索时出现问题 - {e}\"\n",
+    "\n",
+    "# 将所有工具函数放入一个字典,方便后续调用\n",
+    "available_tools = {\n",
+    "    \"get_weather\": get_weather,\n",
+    "    \"get_attraction\": get_attraction,\n",
+    "}\n",
+    "print(\"✅ 工具函数定义完成!\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "id": "e953fee4-9e3c-4e34-bf48-4ea002c3bb92",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "✅ 智能助手类定义完成!\n"
+     ]
+    }
+   ],
+   "source": [
+    "class OpenAICompatibleClient:\n",
+    "    \"\"\"\n",
+    "    一个用于调用任何兼容OpenAI接口的LLM服务的客户端。\n",
+    "    \"\"\"\n",
+    "    def __init__(self, model: str, api_key: str, base_url: str):\n",
+    "        self.model = model\n",
+    "        self.client = OpenAI(api_key=api_key, base_url=base_url)\n",
+    "\n",
+    "    def generate(self, prompt: str, system_prompt: str) -> str:\n",
+    "        \"\"\"调用LLM API来生成回应。\"\"\"\n",
+    "        print(\"正在调用大语言模型...\")\n",
+    "        try:\n",
+    "            messages = [\n",
+    "                {'role': 'system', 'content': system_prompt},\n",
+    "                {'role': 'user', 'content': prompt}\n",
+    "            ]\n",
+    "            response = self.client.chat.completions.create(\n",
+    "                model=self.model,\n",
+    "                messages=messages,\n",
+    "                stream=False\n",
+    "            )\n",
+    "            answer = response.choices[0].message.content\n",
+    "            print(\"大语言模型响应成功。\")\n",
+    "            return answer\n",
+    "        except Exception as e:\n",
+    "            print(f\"调用LLM API时发生错误: {e}\")\n",
+    "            return \"错误:调用语言模型服务时出错。\"\n",
+    "\n",
+    "class TravelAssistant:\n",
+    "    \"\"\"\n",
+    "    智能旅行助手类\n",
+    "    \"\"\"\n",
+    "    def __init__(self):\n",
+    "        self.llm = OpenAICompatibleClient(\n",
+    "            model=MODEL_ID,\n",
+    "            api_key=API_KEY,\n",
+    "            base_url=BASE_URL\n",
+    "        )\n",
+    "        self.prompt_history = []\n",
+    "    \n",
+    "    def reset(self):\n",
+    "        \"\"\"重置对话历史\"\"\"\n",
+    "        self.prompt_history = []\n",
+    "    \n",
+    "    def add_user_message(self, message: str):\n",
+    "        \"\"\"添加用户消息到历史\"\"\"\n",
+    "        self.prompt_history.append(f\"用户请求: {message}\")\n",
+    "    \n",
+    "    def add_assistant_message(self, message: str):\n",
+    "        \"\"\"添加助手消息到历史\"\"\"\n",
+    "        self.prompt_history.append(message)\n",
+    "    \n",
+    "    def add_observation(self, observation: str):\n",
+    "        \"\"\"添加观察结果到历史\"\"\"\n",
+    "        self.prompt_history.append(f\"Observation: {observation}\")\n",
+    "print(\"✅ 智能助手类定义完成!\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "id": "ab5d3142-c119-46ad-a7a1-ec1aa2e79435",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "✅ 显示函数定义完成!\n"
+     ]
+    }
+   ],
+   "source": [
+    "def display_conversation(history):\n",
+    "    \"\"\"美观地显示对话历史\"\"\"\n",
+    "    print(\"\\n\" + \"=\"*60)\n",
+    "    print(\"📝 对话历史\")\n",
+    "    print(\"=\"*60)\n",
+    "    \n",
+    "    for i, message in enumerate(history, 1):\n",
+    "        if message.startswith(\"用户请求:\"):\n",
+    "            print(f\"\\n👤 用户 [{i}]: {message[5:]}\")\n",
+    "        elif message.startswith(\"Thought:\"):\n",
+    "            print(f\"\\n🤔 思考 [{i}]: {message[8:].strip()}\")\n",
+    "        elif message.startswith(\"Action:\"):\n",
+    "            print(f\"🛠️  行动 [{i}]: {message[7:].strip()}\")\n",
+    "        elif message.startswith(\"Observation:\"):\n",
+    "            print(f\"📊 观察 [{i}]: {message[12:].strip()}\")\n",
+    "        else:\n",
+    "            print(f\"💬 消息 [{i}]: {message}\")\n",
+    "    \n",
+    "    print(\"=\"*60 + \"\\n\")\n",
+    "\n",
+    "def parse_action(action_str):\n",
+    "    \"\"\"解析行动字符串\"\"\"\n",
+    "    if action_str.startswith(\"finish\"):\n",
+    "        match = re.search(r'finish\\(answer=\"(.*)\"\\)', action_str)\n",
+    "        if match:\n",
+    "            return \"finish\", {\"answer\": match.group(1)}\n",
+    "        return \"finish\", {\"answer\": \"任务完成\"}\n",
+    "    \n",
+    "    tool_name_match = re.search(r\"(\\w+)\\(\", action_str)\n",
+    "    if not tool_name_match:\n",
+    "        return None, {}\n",
+    "    \n",
+    "    tool_name = tool_name_match.group(1)\n",
+    "    args_match = re.search(r\"\\((.*)\\)\", action_str)\n",
+    "    if args_match:\n",
+    "        args_str = args_match.group(1)\n",
+    "        kwargs = dict(re.findall(r'(\\w+)=\"([^\"]*)\"', args_str))\n",
+    "    else:\n",
+    "        kwargs = {}\n",
+    "    \n",
+    "    return tool_name, kwargs\n",
+    "print(\"✅ 显示函数定义完成!\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "id": "cc543309-fe16-44a9-9735-bce828b9c7ad",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def run_assistant(user_input, max_iterations=5, display=True):\n",
+    "    \"\"\"\n",
+    "    运行旅行助手的主函数\n",
+    "    \n",
+    "    Args:\n",
+    "        user_input: 用户输入的问题\n",
+    "        max_iterations: 最大循环次数\n",
+    "        display: 是否显示对话历史\n",
+    "    \n",
+    "    Returns:\n",
+    "        tuple: (最终答案, 完整的对话历史)\n",
+    "    \"\"\"\n",
+    "    assistant = TravelAssistant()\n",
+    "    assistant.add_user_message(user_input)\n",
+    "    \n",
+    "    if display:\n",
+    "        print(f\"👤 用户输入: {user_input}\")\n",
+    "        print(\"=\"*50)\n",
+    "    \n",
+    "    for i in range(max_iterations):\n",
+    "        if display:\n",
+    "            print(f\"\\n🔄 循环 {i+1}/{max_iterations}\")\n",
+    "        \n",
+    "        # 构建完整prompt并调用LLM\n",
+    "        full_prompt = \"\\n\".join(assistant.prompt_history)\n",
+    "        llm_output = assistant.llm.generate(full_prompt, AGENT_SYSTEM_PROMPT)\n",
+    "        \n",
+    "        assistant.add_assistant_message(llm_output)\n",
+    "        \n",
+    "        if display:\n",
+    "            print(f\"🤖 模型输出:\\n{llm_output}\")\n",
+    "        \n",
+    "        # 解析行动\n",
+    "        action_match = re.search(r\"Action: (.*)\", llm_output, re.DOTALL)\n",
+    "        if not action_match:\n",
+    "            print(\"❌ 解析错误:模型输出中未找到 Action。\")\n",
+    "            break\n",
+    "            \n",
+    "        action_str = action_match.group(1).strip()\n",
+    "        tool_name, kwargs = parse_action(action_str)\n",
+    "        \n",
+    "        # 处理完成行动\n",
+    "        if tool_name == \"finish\":\n",
+    "            final_answer = kwargs.get(\"answer\", \"任务完成\")\n",
+    "            if display:\n",
+    "                print(f\"🎉 任务完成!\")\n",
+    "                print(f\"📋 最终答案: {final_answer}\")\n",
+    "            return final_answer, assistant.prompt_history\n",
+    "        \n",
+    "        # 处理工具调用\n",
+    "        if tool_name in available_tools:\n",
+    "            if display:\n",
+    "                print(f\"🛠️  调用工具: {tool_name}({kwargs})\")\n",
+    "            observation = available_tools[tool_name](**kwargs)\n",
+    "        else:\n",
+    "            observation = f\"错误:未定义的工具 '{tool_name}'\"\n",
+    "        \n",
+    "        # 记录观察结果\n",
+    "        if display:\n",
+    "            print(f\"📊 观察结果: {observation}\")\n",
+    "            print(\"=\"*50)\n",
+    "        \n",
+    "        assistant.add_observation(observation)\n",
+    "    \n",
+    "    # 如果达到最大循环次数仍未完成\n",
+    "    timeout_answer = \"抱歉,经过多次尝试仍未完成您的请求。请尝试简化您的问题或稍后重试。\"\n",
+    "    if display:\n",
+    "        print(f\"⏰ 达到最大循环次数: {timeout_answer}\")\n",
+    "    \n",
+    "    return timeout_answer, assistant.prompt_history"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 6,
+   "id": "3f6e44eb-ff3d-4060-b4c2-ea3e139bf307",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "🚀 开始测试北京天气+景点推荐示例\n",
+      "👤 用户输入: 你好,请帮我查询一下今天北京的天气,然后根据天气推荐一个合适的旅游景点。\n",
+      "==================================================\n",
+      "\n",
+      "🔄 循环 1/5\n",
+      "正在调用大语言模型...\n",
+      "大语言模型响应成功。\n",
+      "🤖 模型输出:\n",
+      "Thought: 用户希望查询今天北京的天气情况,然后基于该天气推荐一个合适的旅游景点。我的第一步是获取北京的实时天气信息,以便了解当前的天气状况。执行查询天气的操作。\n",
+      "\n",
+      "Action: get_weather(city=\"北京\")\n",
+      "🛠️  调用工具: get_weather({'city': '北京'})\n",
+      "📊 观察结果: 北京当前天气:Clear,气温9摄氏度\n",
+      "==================================================\n",
+      "\n",
+      "🔄 循环 2/5\n",
+      "正在调用大语言模型...\n",
+      "大语言模型响应成功。\n",
+      "🤖 模型输出:\n",
+      "Thought: 我已经获得了北京当前的天气信息:晴天,气温9摄氏度。接下来的步骤是根据这个天气条件推荐一个合适的旅游景点。晴天通常适合户外活动,这将影响我的选择。接下来,我将调用工具获取推荐的旅游景点。 \n",
+      "\n",
+      "Action: get_attraction(city=\"北京\", weather=\"Clear\")\n",
+      "🛠️  调用工具: get_attraction({'city': '北京', 'weather': 'Clear'})\n",
+      "📊 观察结果: 在晴天,北京的长城(如八达岭)和故宫是最值得去的景点。晴天下,这些地方的景色最美,游览最舒适。\n",
+      "==================================================\n",
+      "\n",
+      "🔄 循环 3/5\n",
+      "正在调用大语言模型...\n",
+      "大语言模型响应成功。\n",
+      "🤖 模型输出:\n",
+      "Thought: 我已经获得了关于北京当前天气的信息,并找到了两个适合在晴天游览的旅游景点。长城和故宫都是著名的地标性景点,特别在晴天时更是吸引游客。接下来,我准备输出最终的推荐答案。\n",
+      "\n",
+      "Action: finish(answer=\"今天北京的天气晴,气温9摄氏度。推荐您去长城(如八达岭)或故宫游览,这两个景点在这样的天气下非常适合。\")\n",
+      "🎉 任务完成!\n",
+      "📋 最终答案: 今天北京的天气晴,气温9摄氏度。推荐您去长城(如八达岭)或故宫游览,这两个景点在这样的天气下非常适合。\n",
+      "\n",
+      "============================================================\n",
+      "📊 测试完成!\n",
+      "============================================================\n",
+      "最终答案: 今天北京的天气晴,气温9摄氏度。推荐您去长城(如八达岭)或故宫游览,这两个景点在这样的天气下非常适合。\n",
+      "\n",
+      "============================================================\n",
+      "📝 对话历史\n",
+      "============================================================\n",
+      "\n",
+      "👤 用户 [1]:  你好,请帮我查询一下今天北京的天气,然后根据天气推荐一个合适的旅游景点。\n",
+      "\n",
+      "🤔 思考 [2]: 用户希望查询今天北京的天气情况,然后基于该天气推荐一个合适的旅游景点。我的第一步是获取北京的实时天气信息,以便了解当前的天气状况。执行查询天气的操作。\n",
+      "\n",
+      "Action: get_weather(city=\"北京\")\n",
+      "📊 观察 [3]: 北京当前天气:Clear,气温9摄氏度\n",
+      "\n",
+      "🤔 思考 [4]: 我已经获得了北京当前的天气信息:晴天,气温9摄氏度。接下来的步骤是根据这个天气条件推荐一个合适的旅游景点。晴天通常适合户外活动,这将影响我的选择。接下来,我将调用工具获取推荐的旅游景点。 \n",
+      "\n",
+      "Action: get_attraction(city=\"北京\", weather=\"Clear\")\n",
+      "📊 观察 [5]: 在晴天,北京的长城(如八达岭)和故宫是最值得去的景点。晴天下,这些地方的景色最美,游览最舒适。\n",
+      "\n",
+      "🤔 思考 [6]: 我已经获得了关于北京当前天气的信息,并找到了两个适合在晴天游览的旅游景点。长城和故宫都是著名的地标性景点,特别在晴天时更是吸引游客。接下来,我准备输出最终的推荐答案。\n",
+      "\n",
+      "Action: finish(answer=\"今天北京的天气晴,气温9摄氏度。推荐您去长城(如八达岭)或故宫游览,这两个景点在这样的天气下非常适合。\")\n",
+      "============================================================\n",
+      "\n"
+     ]
+    }
+   ],
+   "source": [
+    "# 测试示例\n",
+    "def test_basic_example():\n",
+    "    \"\"\"测试北京天气+景点推荐的示例\"\"\"\n",
+    "    print(\"🚀 开始测试北京天气+景点推荐示例\")\n",
+    "    user_input = \"你好,请帮我查询一下今天北京的天气,然后根据天气推荐一个合适的旅游景点。\"\n",
+    "    \n",
+    "    final_answer, history = run_assistant(user_input, display=True)\n",
+    "    \n",
+    "    print(\"\\n\" + \"=\"*60)\n",
+    "    print(\"📊 测试完成!\")\n",
+    "    print(\"=\"*60)\n",
+    "    print(f\"最终答案: {final_answer}\")\n",
+    "    \n",
+    "    # 显示完整对话历史\n",
+    "    display_conversation(history)\n",
+    "    \n",
+    "    return final_answer, history\n",
+    "\n",
+    "# 运行测试示例\n",
+    "final_answer, history = test_basic_example()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "id": "68c735c1-eb3e-40e7-8b70-2be941798187",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def interactive_travel_assistant():\n",
+    "    \"\"\"\n",
+    "    交互式旅行助手\n",
+    "    \"\"\"\n",
+    "    print(\"🌍 欢迎使用智能旅行助手!\")\n",
+    "    print(\"💡 您可以询问任何城市的天气和旅游景点推荐\")\n",
+    "    print(\"❌ 输入 'quit' 或 '退出' 来结束对话\\n\")\n",
+    "    \n",
+    "    while True:\n",
+    "        user_input = input(\"👤 请输入您的问题: \").strip()\n",
+    "        \n",
+    "        if user_input.lower() in ['quit', '退出', 'exit']:\n",
+    "            print(\"👋 感谢使用智能旅行助手,再见!\")\n",
+    "            break\n",
+    "        \n",
+    "        if not user_input:\n",
+    "            print(\"⚠️  请输入有效的问题\")\n",
+    "            continue\n",
+    "        \n",
+    "        print(\"\\n\" + \"=\"*50)\n",
+    "        print(\"🔄 正在处理您的请求...\")\n",
+    "        \n",
+    "        final_answer, history = run_assistant(user_input, display=True)\n",
+    "        \n",
+    "        print(\"\\n🎯 最终回答:\")\n",
+    "        print(\"=\"*30)\n",
+    "        print(final_answer)\n",
+    "        print(\"=\"*30)\n",
+    "        \n",
+    "        # 询问是否显示完整对话历史\n",
+    "        show_history = input(\"\\n📖 是否显示完整对话历史? (y/n): \").strip().lower()\n",
+    "        if show_history in ['y', 'yes', '是']:\n",
+    "            display_conversation(history)\n",
+    "        \n",
+    "        print(\"\\n\" + \"=\"*60)\n",
+    "        print(\"🔄 准备接受下一个问题...\\n\")\n",
+    "\n",
+    "# 快速测试函数\n",
+    "def quick_test(city=\"上海\"):\n",
+    "    \"\"\"快速测试指定城市的天气和景点\"\"\"\n",
+    "    user_input = f\"请帮我查询{city}的天气,并推荐适合的旅游景点\"\n",
+    "    print(f\"🚀 快速测试: {user_input}\")\n",
+    "    final_answer, _ = run_assistant(user_input, display=True)\n",
+    "    return final_answer"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "id": "bc58c911-8502-4cf5-aa3f-a9f57a94b679",
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "选择运行模式:\n",
+      "1. 运行测试示例 (北京)\n",
+      "2. 交互模式\n",
+      "3. 快速测试其他城市\n"
+     ]
+    },
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "请输入选择 (1/2/3):  3\n",
+      "请输入要测试的城市:  伦敦\n"
+     ]
+    },
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "🚀 快速测试: 请帮我查询伦敦的天气,并推荐适合的旅游景点\n",
+      "👤 用户输入: 请帮我查询伦敦的天气,并推荐适合的旅游景点\n",
+      "==================================================\n",
+      "\n",
+      "🔄 循环 1/5\n",
+      "正在调用大语言模型...\n",
+      "大语言模型响应成功。\n",
+      "🤖 模型输出:\n",
+      "Thought: 我需要先查询伦敦的实时天气,这样才能根据天气情况推荐合适的旅游景点。接下来,我将调用天气查询工具获取伦敦的天气信息。 \n",
+      "Action: get_weather(city=\"伦敦\")\n",
+      "🛠️  调用工具: get_weather({'city': '伦敦'})\n",
+      "📊 观察结果: 伦敦当前天气:Partly cloudy,气温16摄氏度\n",
+      "==================================================\n",
+      "\n",
+      "🔄 循环 2/5\n",
+      "正在调用大语言模型...\n",
+      "大语言模型响应成功。\n",
+      "🤖 模型输出:\n",
+      "Thought: 现在我已经查询到了伦敦的实时天气情况:部分多云,气温为16摄氏度。接下来,我将根据这个天气情况推荐适合在伦敦游玩的旅游景点。 \n",
+      "Action: get_attraction(city=\"伦敦\", weather=\"Partly cloudy\")\n",
+      "🛠️  调用工具: get_attraction({'city': '伦敦', 'weather': 'Partly cloudy'})\n",
+      "📊 观察结果: 在伦敦多云天气下,伦敦眼是最值得去的景点。它提供了伟大的城市景观。此外,博物馆和画廊也适合参观。\n",
+      "==================================================\n",
+      "\n",
+      "🔄 循环 3/5\n",
+      "正在调用大语言模型...\n",
+      "大语言模型响应成功。\n",
+      "🤖 模型输出:\n",
+      "Thought: 我已经获取了伦敦的天气情况和适合的旅游景点推荐。当前天气为部分多云,推荐旅游景点为伦敦眼,同时博物馆和画廊也非常适合在这种天气下参观。最终我将整合这些信息并给出用户的建议。 \n",
+      "Action: finish(answer=\"伦敦当前天气为部分多云,气温16摄氏度。根据天气情况,推荐您去伦敦眼欣赏城市景观,此外博物馆和画廊也是很好的选择。\")\n",
+      "🎉 任务完成!\n",
+      "📋 最终答案: 伦敦当前天气为部分多云,气温16摄氏度。根据天气情况,推荐您去伦敦眼欣赏城市景观,此外博物馆和画廊也是很好的选择。\n"
+     ]
+    }
+   ],
+   "source": [
+    "# 主启动入口\n",
+    "if __name__ == \"__main__\":\n",
+    "    # 可以选择直接运行测试示例\n",
+    "    print(\"选择运行模式:\")\n",
+    "    print(\"1. 运行测试示例 (北京)\")\n",
+    "    print(\"2. 交互模式\")\n",
+    "    print(\"3. 快速测试其他城市\")\n",
+    "    \n",
+    "    choice = input(\"请输入选择 (1/2/3): \").strip()\n",
+    "    \n",
+    "    if choice == \"1\":\n",
+    "        test_basic_example()\n",
+    "    elif choice == \"2\":\n",
+    "        interactive_travel_assistant()\n",
+    "    elif choice == \"3\":\n",
+    "        city = input(\"请输入要测试的城市: \").strip() or \"上海\"\n",
+    "        quick_test(city)\n",
+    "    else:\n",
+    "        print(\"无效选择,运行测试示例...\")\n",
+    "        test_basic_example()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b84ad2cf-d240-4322-9e91-5da2af51f53f",
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3.11 (hello_agents Environment)",
+   "language": "python",
+   "name": "hello_agents"
+  },
+  "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.14"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}