{ "cells": [ { "cell_type": "code", "execution_count": null, "id": "938b2e36-f95c-4b0f-8770-335c6bb5bc0e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "API 配置完成!\n" ] } ], "source": [ "import requests\n", "import json\n", "import os\n", "import re\n", "from tavily import TavilyClient\n", "from IPython.display import display, Markdown, HTML, clear_output\n", "import time\n", "from openai import OpenAI\n", "\n", "# 配置 API(改为 OpenAI)\n", "OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\")\n", "OPENAI_BASE_URL = os.getenv(\"OPENAI_BASE_URL\", \"https://api.openai.com/v1\")\n", "MODEL_NAME = os.getenv(\"OPENAI_MODEL_ID\", \"gpt-4o-mini\")\n", "\n", "# 配置 Tavily(从环境变量读取)\n", "TAVILY_API_KEY = os.getenv(\"TAVILY_API_KEY\")\n", "if TAVILY_API_KEY:\n", " os.environ[\"TAVILY_API_KEY\"] = TAVILY_API_KEY\n", "\n", "print(\"API 配置完成!\")" ] }, { "cell_type": "code", "execution_count": 2, "id": "66d9d404-3c95-42f2-8975-436769b3cb87", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "✅ 工具函数定义完成!\n" ] } ], "source": [ "# 单元块 2: 定义工具函数\n", "def get_weather(city: str) -> str:\n", " \"\"\"查询城市天气\"\"\"\n", " url = f\"https://wttr.in/{city}?format=j1\"\n", " \n", " try:\n", " response = requests.get(url)\n", " response.raise_for_status()\n", " data = response.json()\n", " \n", " current_condition = data['current_condition'][0]\n", " weather_desc = current_condition['weatherDesc'][0]['value']\n", " temp_c = current_condition['temp_C']\n", " humidity = current_condition['humidity']\n", " wind_speed = current_condition['windspeedKmph']\n", " \n", " return f\"{city}当前天气:{weather_desc},气温{temp_c}°C,湿度{humidity}%,风速{wind_speed}km/h\"\n", " \n", " except Exception as e:\n", " return f\"错误:查询天气时遇到问题 - {e}\"\n", "\n", "def get_attraction(city: str, weather: str) -> str:\n", " \"\"\"查询景点推荐\"\"\"\n", " try:\n", " tavily = TavilyClient(api_key=os.environ['TAVILY_API_KEY'])\n", " query = f\"'{city}' 在'{weather}'天气下最值得去的旅游景点推荐及理由\"\n", " \n", " response = tavily.search(query=query, search_depth=\"basic\", include_answer=True)\n", " \n", " if response.get(\"answer\"):\n", " return response[\"answer\"]\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\"错误:执行搜索时出现问题 - {e}\"\n", "\n", "print(\"✅ 工具函数定义完成!\")" ] }, { "cell_type": "code", "execution_count": null, "id": "e953fee4-9e3c-4e34-bf48-4ea002c3bb92", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "✅ 智能助手类定义完成!\n" ] } ], "source": [ "# 单元块 3: 定义智能助手类\n", "class OpenAICompatibleClient:\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", " messages = [\n", " {\"role\": \"system\", \"content\": system_prompt},\n", " {\"role\": \"user\", \"content\": prompt},\n", " ]\n", " resp = self.client.chat.completions.create(\n", " model=self.model,\n", " messages=messages,\n", " stream=False\n", " )\n", " return resp.choices[0].message.content\n", "\n", "class NotebookTravelAssistant:\n", " def __init__(self, model_name):\n", " # 初始化 OpenAI 客户端\n", " try:\n", " self.client = OpenAICompatibleClient(\n", " model=model_name,\n", " api_key=os.getenv(\"OPENAI_API_KEY\"),\n", " base_url=os.getenv(\"OPENAI_BASE_URL\", \"https://api.openai.com/v1\"),\n", " )\n", " except Exception as e:\n", " print(f\"⚠️ 模型 {model_name} 初始化失败: {e},使用默认模型回退\")\n", " self.client = OpenAICompatibleClient(\n", " model=os.getenv(\"OPENAI_MODEL_ID\", \"gpt-4o-mini\"),\n", " api_key=os.getenv(\"OPENAI_API_KEY\"),\n", " base_url=os.getenv(\"OPENAI_BASE_URL\", \"https://api.openai.com/v1\"),\n", " )\n", "\n", " # 定义工具\n", " self.available_tools = {\n", " \"get_weather\": get_weather,\n", " \"get_attraction\": get_attraction,\n", " }\n", "\n", " # 系统提示词\n", " self.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", "\"\"\"\n", "\n", " def generate_response(self, prompt: str) -> str:\n", " \"\"\"调用 OpenAI 生成回应\"\"\"\n", " return self.client.generate(prompt, system_prompt=self.system_prompt)\n", "\n", " def parse_action(self, text: str):\n", " \"\"\"解析行动指令\"\"\"\n", " action_match = re.search(r\"Action: (.*)\", text, re.DOTALL)\n", " if not action_match:\n", " return None, None\n", "\n", " action_str = action_match.group(1).strip()\n", "\n", " if action_str.startswith(\"finish\"):\n", " final_answer_match = re.search(r'finish\\(answer=\"(.*)\"\\)', action_str)\n", " if final_answer_match:\n", " return \"finish\", final_answer_match.group(1)\n", " return \"finish\", \"抱歉,我无法提供完整的答案。\"\n", "\n", " tool_match = re.search(r\"(\\w+)\\((.*)\\)\", action_str)\n", " if not tool_match:\n", " return None, None\n", "\n", " tool_name = tool_match.group(1)\n", " args_str = tool_match.group(2)\n", "\n", " kwargs = {}\n", " if args_str:\n", " arg_matches = re.findall(r'(\\w+)=\"([^\"]*)\"', args_str)\n", " kwargs = dict(arg_matches)\n", "\n", " return tool_name, kwargs\n", "\n", "print(\"✅ 智能助手类定义完成!\")" ] }, { "cell_type": "code", "execution_count": 5, "id": "ab5d3142-c119-46ad-a7a1-ec1aa2e79435", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "✅ 显示函数定义完成!\n" ] } ], "source": [ "# 单元块 4: 定义显示函数\n", "def display_user_input(user_input):\n", " \"\"\"显示用户输入\"\"\"\n", " display(HTML(f\"\"\"\n", "
\n", "
👤 用户:
\n", "
{user_input}
\n", "
\n", " \"\"\"))\n", "\n", "def display_cycle_header(cycle_num):\n", " \"\"\"显示循环标题\"\"\"\n", " display(HTML(f\"\"\"\n", "
\n", " 🔄 循环 {cycle_num}:\n", "
\n", " \"\"\"))\n", "\n", "def display_thought(thought_text):\n", " \"\"\"显示思考过程\"\"\"\n", " display(HTML(f\"\"\"\n", "
\n", "
🧠 智能体响应:
\n", "
Thought: {thought_text}
\n", "
\n", " \"\"\"))\n", "\n", "def display_action(tool_name, args):\n", " \"\"\"显示行动\"\"\"\n", " display(HTML(f\"\"\"\n", "
\n", " ⚡ 执行工具: {tool_name}({', '.join([f'{k}=\"{v}\"' for k, v in args.items()])})\n", "
\n", " \"\"\"))\n", "\n", "def display_observation(observation):\n", " \"\"\"显示观察结果\"\"\"\n", " display(HTML(f\"\"\"\n", "
\n", "
👁️ 观察结果:
\n", "
{observation}
\n", "
\n", " \"\"\"))\n", "\n", "def display_final_result(result):\n", " \"\"\"显示最终结果\"\"\"\n", " display(HTML(f\"\"\"\n", "
\n", "
✅ 任务完成!
\n", "
{result}
\n", "
\n", " \"\"\"))\n", "\n", "print(\"✅ 显示函数定义完成!\")" ] }, { "cell_type": "code", "execution_count": 6, "id": "cc543309-fe16-44a9-9735-bce828b9c7ad", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "✅ 主运行函数定义完成!\n" ] } ], "source": [ "# 单元块 5: 定义主运行函数\n", "def run_assistant(user_input, max_iterations=5):\n", " \"\"\"运行智能助手\"\"\"\n", " # 创建助手实例\n", " assistant = NotebookTravelAssistant(model_name=MODEL_NAME)\n", " \n", " # 显示用户输入\n", " display_user_input(user_input)\n", " \n", " prompt_history = [f\"用户请求: {user_input}\"]\n", " \n", " for i in range(max_iterations):\n", " # 显示循环标题\n", " display_cycle_header(i+1)\n", " \n", " # 调用模型\n", " full_prompt = \"\\n\".join(prompt_history)\n", " llm_output = assistant.generate_response(full_prompt)\n", " \n", " # 提取思考过程\n", " thought_match = re.search(r\"Thought: (.*?)(?=Action:|$)\", llm_output, re.DOTALL)\n", " thought_text = thought_match.group(1).strip() if thought_match else \"思考过程未明确显示\"\n", " \n", " # 显示思考过程\n", " display_thought(thought_text)\n", " \n", " # 解析并执行行动\n", " tool_name, args = assistant.parse_action(llm_output)\n", " \n", " if tool_name == \"finish\":\n", " # 显示最终结果\n", " display_final_result(args)\n", " return args\n", " \n", " elif tool_name in assistant.available_tools:\n", " # 显示行动\n", " display_action(tool_name, args)\n", " \n", " # 执行工具\n", " observation = assistant.available_tools[tool_name](**args)\n", " \n", " # 显示观察结果\n", " display_observation(observation)\n", " \n", " # 更新历史\n", " prompt_history.append(llm_output)\n", " prompt_history.append(f\"Observation: {observation}\")\n", " \n", " # 添加短暂延迟,使输出更易读\n", " time.sleep(1)\n", " else:\n", " display(HTML(f\"
❌ 无法解析行动: {tool_name}
\"))\n", " break\n", " \n", " return \"抱歉,我无法完成这个请求。请尝试更具体的查询。\"\n", "\n", "print(\"✅ 主运行函数定义完成!\")" ] }, { "cell_type": "code", "execution_count": 7, "id": "3f6e44eb-ff3d-4060-b4c2-ea3e139bf307", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", "
\n", "
👤 用户:
\n", "
你好,请帮我查询一下今天北京的天气,然后根据天气推荐一个合适的旅游景点
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " 🔄 循环 1:\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "ename": "InvalidArgument", "evalue": "400 API key not valid. Please pass a valid API key. [reason: \"API_KEY_INVALID\"\ndomain: \"googleapis.com\"\nmetadata {\n key: \"service\"\n value: \"generativelanguage.googleapis.com\"\n}\n, locale: \"en-US\"\nmessage: \"API key not valid. Please pass a valid API key.\"\n]", "output_type": "error", "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mInvalidArgument\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[7]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m# 单元块 6: 运行示例\u001b[39;00m\n\u001b[32m 2\u001b[39m user_input = \u001b[33m\"\u001b[39m\u001b[33m你好,请帮我查询一下今天北京的天气,然后根据天气推荐一个合适的旅游景点\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m result = \u001b[43mrun_assistant\u001b[49m\u001b[43m(\u001b[49m\u001b[43muser_input\u001b[49m\u001b[43m)\u001b[49m\n", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[6]\u001b[39m\u001b[32m, line 18\u001b[39m, in \u001b[36mrun_assistant\u001b[39m\u001b[34m(user_input, max_iterations)\u001b[39m\n\u001b[32m 16\u001b[39m \u001b[38;5;66;03m# 调用模型\u001b[39;00m\n\u001b[32m 17\u001b[39m full_prompt = \u001b[33m\"\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m\"\u001b[39m.join(prompt_history)\n\u001b[32m---> \u001b[39m\u001b[32m18\u001b[39m llm_output = \u001b[43massistant\u001b[49m\u001b[43m.\u001b[49m\u001b[43mgenerate_response\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfull_prompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 20\u001b[39m \u001b[38;5;66;03m# 提取思考过程\u001b[39;00m\n\u001b[32m 21\u001b[39m thought_match = re.search(\u001b[33mr\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mThought: (.*?)(?=Action:|$)\u001b[39m\u001b[33m\"\u001b[39m, llm_output, re.DOTALL)\n", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[4]\u001b[39m\u001b[32m, line 40\u001b[39m, in \u001b[36mNotebookTravelAssistant.generate_response\u001b[39m\u001b[34m(self, prompt)\u001b[39m\n\u001b[32m 38\u001b[39m \u001b[38;5;250m\u001b[39m\u001b[33;03m\"\"\"调用Gemini生成回应\"\"\"\u001b[39;00m\n\u001b[32m 39\u001b[39m full_prompt = \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m.system_prompt\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m用户请求: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mprompt\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m---> \u001b[39m\u001b[32m40\u001b[39m response = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mmodel\u001b[49m\u001b[43m.\u001b[49m\u001b[43mgenerate_content\u001b[49m\u001b[43m(\u001b[49m\u001b[43mfull_prompt\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 41\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m response.text\n", "\u001b[36mFile \u001b[39m\u001b[32md:\\Anaconda\\envs\\hello_agents\\Lib\\site-packages\\google\\generativeai\\generative_models.py:331\u001b[39m, in \u001b[36mGenerativeModel.generate_content\u001b[39m\u001b[34m(self, contents, generation_config, safety_settings, stream, tools, tool_config, request_options)\u001b[39m\n\u001b[32m 329\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m generation_types.GenerateContentResponse.from_iterator(iterator)\n\u001b[32m 330\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m331\u001b[39m response = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_client\u001b[49m\u001b[43m.\u001b[49m\u001b[43mgenerate_content\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 332\u001b[39m \u001b[43m \u001b[49m\u001b[43mrequest\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 333\u001b[39m \u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mrequest_options\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 334\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 335\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m generation_types.GenerateContentResponse.from_response(response)\n\u001b[32m 336\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m google.api_core.exceptions.InvalidArgument \u001b[38;5;28;01mas\u001b[39;00m e:\n", "\u001b[36mFile \u001b[39m\u001b[32md:\\Anaconda\\envs\\hello_agents\\Lib\\site-packages\\google\\ai\\generativelanguage_v1beta\\services\\generative_service\\client.py:835\u001b[39m, in \u001b[36mGenerativeServiceClient.generate_content\u001b[39m\u001b[34m(self, request, model, contents, retry, timeout, metadata)\u001b[39m\n\u001b[32m 832\u001b[39m \u001b[38;5;28mself\u001b[39m._validate_universe_domain()\n\u001b[32m 834\u001b[39m \u001b[38;5;66;03m# Send the request.\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m835\u001b[39m response = \u001b[43mrpc\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 836\u001b[39m \u001b[43m \u001b[49m\u001b[43mrequest\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 837\u001b[39m \u001b[43m \u001b[49m\u001b[43mretry\u001b[49m\u001b[43m=\u001b[49m\u001b[43mretry\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 838\u001b[39m \u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m=\u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 839\u001b[39m \u001b[43m \u001b[49m\u001b[43mmetadata\u001b[49m\u001b[43m=\u001b[49m\u001b[43mmetadata\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 840\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 842\u001b[39m \u001b[38;5;66;03m# Done; return the response.\u001b[39;00m\n\u001b[32m 843\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m response\n", "\u001b[36mFile \u001b[39m\u001b[32md:\\Anaconda\\envs\\hello_agents\\Lib\\site-packages\\google\\api_core\\gapic_v1\\method.py:131\u001b[39m, in \u001b[36m_GapicCallable.__call__\u001b[39m\u001b[34m(self, timeout, retry, compression, *args, **kwargs)\u001b[39m\n\u001b[32m 128\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m._compression \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 129\u001b[39m kwargs[\u001b[33m\"\u001b[39m\u001b[33mcompression\u001b[39m\u001b[33m\"\u001b[39m] = compression\n\u001b[32m--> \u001b[39m\u001b[32m131\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mwrapped_func\u001b[49m\u001b[43m(\u001b[49m\u001b[43m*\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", "\u001b[36mFile \u001b[39m\u001b[32md:\\Anaconda\\envs\\hello_agents\\Lib\\site-packages\\google\\api_core\\retry\\retry_unary.py:294\u001b[39m, in \u001b[36mRetry.__call__..retry_wrapped_func\u001b[39m\u001b[34m(*args, **kwargs)\u001b[39m\n\u001b[32m 290\u001b[39m target = functools.partial(func, *args, **kwargs)\n\u001b[32m 291\u001b[39m sleep_generator = exponential_sleep_generator(\n\u001b[32m 292\u001b[39m \u001b[38;5;28mself\u001b[39m._initial, \u001b[38;5;28mself\u001b[39m._maximum, multiplier=\u001b[38;5;28mself\u001b[39m._multiplier\n\u001b[32m 293\u001b[39m )\n\u001b[32m--> \u001b[39m\u001b[32m294\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mretry_target\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 295\u001b[39m \u001b[43m \u001b[49m\u001b[43mtarget\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 296\u001b[39m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_predicate\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 297\u001b[39m \u001b[43m \u001b[49m\u001b[43msleep_generator\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 298\u001b[39m \u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_timeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 299\u001b[39m \u001b[43m \u001b[49m\u001b[43mon_error\u001b[49m\u001b[43m=\u001b[49m\u001b[43mon_error\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 300\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", "\u001b[36mFile \u001b[39m\u001b[32md:\\Anaconda\\envs\\hello_agents\\Lib\\site-packages\\google\\api_core\\retry\\retry_unary.py:156\u001b[39m, in \u001b[36mretry_target\u001b[39m\u001b[34m(target, predicate, sleep_generator, timeout, on_error, exception_factory, **kwargs)\u001b[39m\n\u001b[32m 152\u001b[39m \u001b[38;5;66;03m# pylint: disable=broad-except\u001b[39;00m\n\u001b[32m 153\u001b[39m \u001b[38;5;66;03m# This function explicitly must deal with broad exceptions.\u001b[39;00m\n\u001b[32m 154\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[32m 155\u001b[39m \u001b[38;5;66;03m# defer to shared logic for handling errors\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m156\u001b[39m next_sleep = \u001b[43m_retry_error_helper\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 157\u001b[39m \u001b[43m \u001b[49m\u001b[43mexc\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 158\u001b[39m \u001b[43m \u001b[49m\u001b[43mdeadline\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 159\u001b[39m \u001b[43m \u001b[49m\u001b[43msleep_iter\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 160\u001b[39m \u001b[43m \u001b[49m\u001b[43merror_list\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 161\u001b[39m \u001b[43m \u001b[49m\u001b[43mpredicate\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 162\u001b[39m \u001b[43m \u001b[49m\u001b[43mon_error\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 163\u001b[39m \u001b[43m \u001b[49m\u001b[43mexception_factory\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 164\u001b[39m \u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 165\u001b[39m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 166\u001b[39m \u001b[38;5;66;03m# if exception not raised, sleep before next attempt\u001b[39;00m\n\u001b[32m 167\u001b[39m time.sleep(next_sleep)\n", "\u001b[36mFile \u001b[39m\u001b[32md:\\Anaconda\\envs\\hello_agents\\Lib\\site-packages\\google\\api_core\\retry\\retry_base.py:214\u001b[39m, in \u001b[36m_retry_error_helper\u001b[39m\u001b[34m(exc, deadline, sleep_iterator, error_list, predicate_fn, on_error_fn, exc_factory_fn, original_timeout)\u001b[39m\n\u001b[32m 208\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m predicate_fn(exc):\n\u001b[32m 209\u001b[39m final_exc, source_exc = exc_factory_fn(\n\u001b[32m 210\u001b[39m error_list,\n\u001b[32m 211\u001b[39m RetryFailureReason.NON_RETRYABLE_ERROR,\n\u001b[32m 212\u001b[39m original_timeout,\n\u001b[32m 213\u001b[39m )\n\u001b[32m--> \u001b[39m\u001b[32m214\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m final_exc \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01msource_exc\u001b[39;00m\n\u001b[32m 215\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m on_error_fn \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m 216\u001b[39m on_error_fn(exc)\n", "\u001b[36mFile \u001b[39m\u001b[32md:\\Anaconda\\envs\\hello_agents\\Lib\\site-packages\\google\\api_core\\retry\\retry_unary.py:147\u001b[39m, in \u001b[36mretry_target\u001b[39m\u001b[34m(target, predicate, sleep_generator, timeout, on_error, exception_factory, **kwargs)\u001b[39m\n\u001b[32m 145\u001b[39m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[32m 146\u001b[39m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[32m--> \u001b[39m\u001b[32m147\u001b[39m result = \u001b[43mtarget\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 148\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m inspect.isawaitable(result):\n\u001b[32m 149\u001b[39m warnings.warn(_ASYNC_RETRY_WARNING)\n", "\u001b[36mFile \u001b[39m\u001b[32md:\\Anaconda\\envs\\hello_agents\\Lib\\site-packages\\google\\api_core\\timeout.py:130\u001b[39m, in \u001b[36mTimeToDeadlineTimeout.__call__..func_with_timeout\u001b[39m\u001b[34m(*args, **kwargs)\u001b[39m\n\u001b[32m 126\u001b[39m remaining_timeout = \u001b[38;5;28mself\u001b[39m._timeout\n\u001b[32m 128\u001b[39m kwargs[\u001b[33m\"\u001b[39m\u001b[33mtimeout\u001b[39m\u001b[33m\"\u001b[39m] = remaining_timeout\n\u001b[32m--> \u001b[39m\u001b[32m130\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[43m*\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43m*\u001b[49m\u001b[43m*\u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", "\u001b[36mFile \u001b[39m\u001b[32md:\\Anaconda\\envs\\hello_agents\\Lib\\site-packages\\google\\api_core\\grpc_helpers.py:77\u001b[39m, in \u001b[36m_wrap_unary_errors..error_remapped_callable\u001b[39m\u001b[34m(*args, **kwargs)\u001b[39m\n\u001b[32m 75\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m callable_(*args, **kwargs)\n\u001b[32m 76\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m grpc.RpcError \u001b[38;5;28;01mas\u001b[39;00m exc:\n\u001b[32m---> \u001b[39m\u001b[32m77\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m exceptions.from_grpc_error(exc) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mexc\u001b[39;00m\n", "\u001b[31mInvalidArgument\u001b[39m: 400 API key not valid. Please pass a valid API key. [reason: \"API_KEY_INVALID\"\ndomain: \"googleapis.com\"\nmetadata {\n key: \"service\"\n value: \"generativelanguage.googleapis.com\"\n}\n, locale: \"en-US\"\nmessage: \"API key not valid. Please pass a valid API key.\"\n]" ] } ], "source": [ "# 单元块 6: 运行示例\n", "user_input = \"你好,请帮我查询一下今天北京的天气,然后根据天气推荐一个合适的旅游景点\"\n", "result = run_assistant(user_input)" ] }, { "cell_type": "code", "execution_count": 40, "id": "68c735c1-eb3e-40e7-8b70-2be941798187", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "✅ 交互式对话功能已加载!\n", "运行 'interactive_travel_assistant()' 开始对话\n" ] } ], "source": [ "# 单元块 7: 实现交互式对话功能\n", "def interactive_travel_assistant():\n", " \"\"\"交互式旅行助手\"\"\"\n", " print(\"🌍 欢迎使用智能旅行助手!\")\n", " print(\"=\" * 50)\n", " print(\"我可以帮您查询任何城市的天气,并根据天气推荐合适的旅游景点。\")\n", " print(\"您只需输入城市名称,我将为您提供完整的旅行建议。\")\n", " print(\"输入 '退出'、'quit' 或 'exit' 可以结束对话。\")\n", " print(\"=\" * 50)\n", " \n", " conversation_count = 0\n", " \n", " while True:\n", " # 获取用户输入\n", " user_input = input(f\"\\n🏙️ 请输入城市名称 (对话 {conversation_count + 1}): \").strip()\n", " \n", " # 检查退出条件\n", " if user_input.lower() in ['退出', 'quit', 'exit']:\n", " print(\"\\n\" + \"=\" * 50)\n", " print(\"👋 感谢使用智能旅行助手,期待下次为您服务!\")\n", " print(\"=\" * 50)\n", " break\n", " \n", " # 检查空输入\n", " if not user_input:\n", " print(\"⚠️ 请输入有效的城市名称。\")\n", " continue\n", " \n", " # 构建查询\n", " query = f\"请帮我查询{user_input}的天气,然后根据天气推荐合适的旅游景点\"\n", " \n", " print(f\"\\n📡 处理您的请求: {query}\")\n", " print(\"-\" * 50)\n", " \n", " # 运行助手\n", " result = run_assistant(query)\n", " \n", " # 增加对话计数\n", " conversation_count += 1\n", " \n", " print(\"\\n\" + \"=\" * 50)\n", " print(f\"💫 已完成 {conversation_count} 次对话\")\n", " print(\"=\" * 50)\n", "\n", "# 启动交互式助手\n", "print(\"✅ 交互式对话功能已加载!\")\n", "print(\"运行 'interactive_travel_assistant()' 开始对话\")" ] }, { "cell_type": "code", "execution_count": 41, "id": "bc58c911-8502-4cf5-aa3f-a9f57a94b679", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "🌍 欢迎使用智能旅行助手!\n", "==================================================\n", "我可以帮您查询任何城市的天气,并根据天气推荐合适的旅游景点。\n", "您只需输入城市名称,我将为您提供完整的旅行建议。\n", "输入 '退出'、'quit' 或 'exit' 可以结束对话。\n", "==================================================\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "🏙️ 请输入城市名称 (对话 1): 伦敦\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "📡 处理您的请求: 请帮我查询伦敦的天气,然后根据天气推荐合适的旅游景点\n", "--------------------------------------------------\n" ] }, { "data": { "text/html": [ "\n", "
\n", "
👤 用户:
\n", "
请帮我查询伦敦的天气,然后根据天气推荐合适的旅游景点
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " 🔄 循环 1:\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
🧠 智能体响应:
\n", "
Thought: 用户请求查询伦敦的天气,并根据天气推荐景点。第一步是获取伦敦的天气。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " ⚡ 执行工具: get_weather(city=\"伦敦\")\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
👁️ 观察结果:
\n", "
伦敦当前天气:Clear,气温9°C,湿度93%,风速12km/h
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " 🔄 循环 2:\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
🧠 智能体响应:
\n", "
Thought: 我已经查询到伦敦的天气是\"Clear\"。现在我需要根据这个天气信息来推荐伦敦的旅游景点。我可以使用 `get_attraction` 工具,将城市设置为\"伦敦\",天气设置为\"Clear\"。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " ⚡ 执行工具: get_attraction(city=\"伦敦\", weather=\"Clear\")\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
👁️ 观察结果:
\n", "
在伦敦天气晴朗时,乘船游览泰晤士河是最佳选择,欣赏国会大厦和伦敦眼。白天参观西敏寺和大本钟。格林威治天文台也是不错的景点。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " 🔄 循环 3:\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
🧠 智能体响应:
\n", "
Thought: 我已经查询到伦敦的天气信息,并且根据晴朗的天气推荐了合适的旅游景点。现在我拥有了所有必要的信息来回答用户的请求。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
✅ 任务完成!
\n", "
伦敦目前天气晴朗,气温9°C。在伦敦天气晴朗时,乘船游览泰晤士河是最佳选择,可以欣赏国会大厦和伦敦眼。白天还可以参观西敏寺、大本钟和格林威治天文台。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "==================================================\n", "💫 已完成 1 次对话\n", "==================================================\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "🏙️ 请输入城市名称 (对话 2): 郑州\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "📡 处理您的请求: 请帮我查询郑州的天气,然后根据天气推荐合适的旅游景点\n", "--------------------------------------------------\n" ] }, { "data": { "text/html": [ "\n", "
\n", "
👤 用户:
\n", "
请帮我查询郑州的天气,然后根据天气推荐合适的旅游景点
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " 🔄 循环 1:\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
🧠 智能体响应:
\n", "
Thought: 用户请求包含两个步骤:首先查询郑州的天气,然后根据天气推荐景点。我需要先调用 `get_weather` 工具获取郑州的天气信息。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " ⚡ 执行工具: get_weather(city=\"郑州\")\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
👁️ 观察结果:
\n", "
郑州当前天气:Mist,气温10°C,湿度94%,风速4km/h
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " 🔄 循环 2:\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
🧠 智能体响应:
\n", "
Thought: 我已经查询到了郑州的天气是 \"Mist\"。现在我需要根据这个天气信息,调用 `get_attraction` 工具来推荐旅游景点。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " ⚡ 执行工具: get_attraction(city=\"郑州\", weather=\"Mist\")\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
👁️ 观察结果:
\n", "
在雾霾天气下,郑州的二七纪念塔和新稀伏羲山景区是最值得去的旅游景点。这些地方空气质量较好,景色优美。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " 🔄 循环 3:\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
🧠 智能体响应:
\n", "
Thought: 我已经获取了郑州的天气信息和根据该天气推荐的旅游景点。现在我可以将这些信息整合起来,回答用户的请求。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
✅ 任务完成!
\n", "
郑州当前天气:Mist,气温10°C,湿度94%,风速4km/h。根据当前雾蒙蒙的天气,推荐您前往二七纪念塔和新稀伏羲山景区,这些地方空气质量较好,景色优美。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "==================================================\n", "💫 已完成 2 次对话\n", "==================================================\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "🏙️ 请输入城市名称 (对话 3): 莆田\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "📡 处理您的请求: 请帮我查询莆田的天气,然后根据天气推荐合适的旅游景点\n", "--------------------------------------------------\n" ] }, { "data": { "text/html": [ "\n", "
\n", "
👤 用户:
\n", "
请帮我查询莆田的天气,然后根据天气推荐合适的旅游景点
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " 🔄 循环 1:\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
🧠 智能体响应:
\n", "
Thought: 用户请求包含两个步骤:首先查询莆田的天气,然后根据天气推荐景点。我需要先使用 `get_weather` 工具获取莆田的天气信息。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " ⚡ 执行工具: get_weather(city=\"莆田\")\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
👁️ 观察结果:
\n", "
莆田当前天气:Partly cloudy,气温19°C,湿度77%,风速10km/h
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " 🔄 循环 2:\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
🧠 智能体响应:
\n", "
Thought: 我已经获取了莆田的天气信息是 \"Partly cloudy\"。现在我需要根据这个天气信息,使用 `get_attraction` 工具来推荐合适的旅游景点。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " ⚡ 执行工具: get_attraction(city=\"莆田\", weather=\"Partly cloudy\")\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
👁️ 观察结果:
\n", "
莆田在多云天气下,莆田市博物馆和莆田古城是最值得去的景点。这些地方风景宜人,适合观光。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", " 🔄 循环 3:\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
🧠 智能体响应:
\n", "
Thought: 我已经获取了莆田的天气信息和根据天气推荐的旅游景点。现在我可以将这些信息整合成最终答案。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "
✅ 任务完成!
\n", "
莆田当前天气:Partly cloudy,气温19°C,湿度77%,风速10km/h。在多云天气下,莆田市博物馆和莆田古城是最值得去的景点,这些地方风景宜人,适合观光。
\n", "
\n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stdout", "output_type": "stream", "text": [ "\n", "==================================================\n", "💫 已完成 3 次对话\n", "==================================================\n" ] }, { "ename": "KeyboardInterrupt", "evalue": "Interrupted by user", "output_type": "error", "traceback": [ "\u001b[31m---------------------------------------------------------------------------\u001b[39m", "\u001b[31mKeyboardInterrupt\u001b[39m Traceback (most recent call last)", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[41]\u001b[39m\u001b[32m, line 2\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m# 启动交互式对话\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m2\u001b[39m \u001b[43minteractive_travel_assistant\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[40]\u001b[39m\u001b[32m, line 15\u001b[39m, in \u001b[36minteractive_travel_assistant\u001b[39m\u001b[34m()\u001b[39m\n\u001b[32m 11\u001b[39m conversation_count = \u001b[32m0\u001b[39m\n\u001b[32m 13\u001b[39m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28;01mTrue\u001b[39;00m:\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# 获取用户输入\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m15\u001b[39m user_input = \u001b[38;5;28;43minput\u001b[39;49m\u001b[43m(\u001b[49m\u001b[33;43mf\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[38;5;130;43;01m\\n\u001b[39;49;00m\u001b[33;43m🏙️ 请输入城市名称 (对话 \u001b[39;49m\u001b[38;5;132;43;01m{\u001b[39;49;00m\u001b[43mconversation_count\u001b[49m\u001b[38;5;250;43m \u001b[39;49m\u001b[43m+\u001b[49m\u001b[38;5;250;43m \u001b[39;49m\u001b[32;43m1\u001b[39;49m\u001b[38;5;132;43;01m}\u001b[39;49;00m\u001b[33;43m): \u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m)\u001b[49m.strip()\n\u001b[32m 17\u001b[39m \u001b[38;5;66;03m# 检查退出条件\u001b[39;00m\n\u001b[32m 18\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m user_input.lower() \u001b[38;5;129;01min\u001b[39;00m [\u001b[33m'\u001b[39m\u001b[33m退出\u001b[39m\u001b[33m'\u001b[39m, \u001b[33m'\u001b[39m\u001b[33mquit\u001b[39m\u001b[33m'\u001b[39m, \u001b[33m'\u001b[39m\u001b[33mexit\u001b[39m\u001b[33m'\u001b[39m]:\n", "\u001b[36mFile \u001b[39m\u001b[32mD:\\Anaconda\\envs\\hello_agents\\Lib\\site-packages\\ipykernel\\kernelbase.py:1275\u001b[39m, in \u001b[36mKernel.raw_input\u001b[39m\u001b[34m(self, prompt)\u001b[39m\n\u001b[32m 1273\u001b[39m msg = \u001b[33m\"\u001b[39m\u001b[33mraw_input was called, but this frontend does not support input requests.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 1274\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m StdinNotImplementedError(msg)\n\u001b[32m-> \u001b[39m\u001b[32m1275\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_input_request\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 1276\u001b[39m \u001b[43m \u001b[49m\u001b[38;5;28;43mstr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 1277\u001b[39m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_parent_ident\u001b[49m\u001b[43m[\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mshell\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 1278\u001b[39m \u001b[43m \u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mget_parent\u001b[49m\u001b[43m(\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mshell\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 1279\u001b[39m \u001b[43m \u001b[49m\u001b[43mpassword\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mFalse\u001b[39;49;00m\u001b[43m,\u001b[49m\n\u001b[32m 1280\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n", "\u001b[36mFile \u001b[39m\u001b[32mD:\\Anaconda\\envs\\hello_agents\\Lib\\site-packages\\ipykernel\\kernelbase.py:1320\u001b[39m, in \u001b[36mKernel._input_request\u001b[39m\u001b[34m(self, prompt, ident, parent, password)\u001b[39m\n\u001b[32m 1317\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyboardInterrupt\u001b[39;00m:\n\u001b[32m 1318\u001b[39m \u001b[38;5;66;03m# re-raise KeyboardInterrupt, to truncate traceback\u001b[39;00m\n\u001b[32m 1319\u001b[39m msg = \u001b[33m\"\u001b[39m\u001b[33mInterrupted by user\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m-> \u001b[39m\u001b[32m1320\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyboardInterrupt\u001b[39;00m(msg) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m 1321\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m:\n\u001b[32m 1322\u001b[39m \u001b[38;5;28mself\u001b[39m.log.warning(\u001b[33m\"\u001b[39m\u001b[33mInvalid Message:\u001b[39m\u001b[33m\"\u001b[39m, exc_info=\u001b[38;5;28;01mTrue\u001b[39;00m)\n", "\u001b[31mKeyboardInterrupt\u001b[39m: Interrupted by user" ] } ], "source": [ "# 启动交互式对话\n", "interactive_travel_assistant()" ] }, { "cell_type": "code", "execution_count": null, "id": "b84ad2cf-d240-4322-9e91-5da2af51f53f", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "hello_agents", "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.14" } }, "nbformat": 4, "nbformat_minor": 5 }