{
  "cells": [
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "# Vanna Agent Test - 基于 create_react_agent 的实现\n",
        "\n",
        "## 目标\n",
        "使用 LangGraph 的 `create_react_agent()` 创建一个包含四个工具的智能Agent：\n",
        "1. generate_sql - 生成SQL\n",
        "2. valid_sql - 验证SQL\n",
        "3. run_sql - 执行SQL\n",
        "4. generate_summary - 生成摘要\n",
        "\n",
        "## 架构\n",
        "- 三节点结构：Agent节点 → Tools节点 → END节点\n",
        "- Agent自主决策是否需要查询数据库\n",
        "- 对于常识问题直接用LLM回答"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "## 1. 环境准备和导入"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "项目根目录: c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\n",
            "common目录存在: True\n",
            "Python路径已更新: True\n",
            "✅ 导入完成\n"
          ]
        }
      ],
      "source": [
        "# 添加项目根目录到Python路径\n",
        "import sys\n",
        "import os\n",
        "\n",
        "# 方法1: 基于当前notebook文件位置计算项目根目录\n",
        "current_dir = os.path.dirname(os.path.abspath(__file__)) if '__file__' in globals() else os.getcwd()\n",
        "project_root = os.path.dirname(current_dir)  # test/ 的上一级就是项目根目录\n",
        "\n",
        "# 方法2: 备用方案，如果方法1失败\n",
        "if not os.path.exists(os.path.join(project_root, 'common')):\n",
        "    # 尝试当前工作目录的上一级\n",
        "    project_root = os.path.dirname(os.getcwd())\n",
        "\n",
        "# 添加到Python路径\n",
        "if project_root not in sys.path:\n",
        "    sys.path.insert(0, project_root)\n",
        "\n",
        "print(f\"项目根目录: {project_root}\")\n",
        "print(f\"common目录存在: {os.path.exists(os.path.join(project_root, 'common'))}\")\n",
        "print(f\"Python路径已更新: {project_root in sys.path}\")\n",
        "\n",
        "# 基础导入\n",
        "from typing import Dict, Any, List, Optional\n",
        "import pandas as pd\n",
        "import re\n",
        "import json\n",
        "from datetime import datetime\n",
        "\n",
        "# LangChain/LangGraph 导入\n",
        "from langchain.tools import tool\n",
        "from langchain_core.messages import HumanMessage, AIMessage, SystemMessage\n",
        "from langgraph.prebuilt import create_react_agent\n",
        "\n",
        "# 项目导入\n",
        "from common.vanna_instance import get_vanna_instance\n",
        "from common.utils import get_current_llm_config\n",
        "\n",
        "print(\"✅ 导入完成\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "✅ 配置参数已设置\n",
            "最大工具调用次数: 10\n",
            "最大返回行数: 200\n"
          ]
        }
      ],
      "source": [
        "# ========== 可配置参数 ==========\n",
        "\n",
        "# 最大工具调用次数（防止无限循环）\n",
        "MAX_TOOL_CALLS = 10\n",
        "\n",
        "# 最大返回行数\n",
        "MAX_RETURN_ROWS = 200\n",
        "\n",
        "# 是否启用详细日志\n",
        "VERBOSE = True\n",
        "\n",
        "# 数据库业务范围描述（请根据实际情况修改）\n",
        "DATABASE_SCOPE = \"\"\"\n",
        "=== 数据库业务范围 ===\n",
        "本系统是高速公路服务区商业管理系统，包含以下业务数据：\n",
        "\n",
        "核心业务实体：\n",
        "- 服务区(bss_service_area)：服务区基础信息、位置、状态\n",
        "- 档口/商铺(bss_business_day_data)：档口信息、品类、营业数据\n",
        "- 车流量(bss_car_day_count)：按车型统计的日流量数据\n",
        "- 公司信息(bss_company)：服务区管理公司\n",
        "\n",
        "关键业务指标：\n",
        "- 支付方式：微信支付、支付宝支付、现金支付等\n",
        "- 营业数据：支付金额、订单数量、营业额、收入统计\n",
        "- 车流统计：按车型的流量分析\n",
        "- 经营分析：餐饮、小吃、便利店等品类收入\n",
        "\n",
        "时间范围：\n",
        "- 数据更新到最近的营业日\n",
        "- 历史数据可追溯到系统上线时间\n",
        "\"\"\"\n",
        "\n",
        "print(\"✅ 配置参数已设置\")\n",
        "print(f\"最大工具调用次数: {MAX_TOOL_CALLS}\")\n",
        "print(f\"最大返回行数: {MAX_RETURN_ROWS}\")\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "## 3. 获取LLM实例\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔧 检测到模型: qwen-plus\n",
            "🔧 为模型 qwen-plus 设置 enable_thinking=False\n",
            "✅ 使用OpenAI兼容API（方法1：model_kwargs）\n"
          ]
        }
      ],
      "source": [
        "def get_llm():\n",
        "    \"\"\"获取兼容的LLM实例\"\"\"\n",
        "    try:\n",
        "        # 尝试使用OpenAI兼容的API\n",
        "        from langchain_openai import ChatOpenAI\n",
        "        from common.utils import get_current_llm_config\n",
        "        \n",
        "        llm_config = get_current_llm_config()\n",
        "        \n",
        "        if llm_config.get(\"base_url\") and llm_config.get(\"api_key\"):\n",
        "            # 构建参数，确保thinking功能正确设置\n",
        "            model_name = llm_config.get(\"model\", \"\").lower()\n",
        "            print(f\"🔧 检测到模型: {model_name}\")\n",
        "            \n",
        "            # 方法1：尝试使用model_kwargs传递参数\n",
        "            model_kwargs = {}\n",
        "            if \"deepseek\" in model_name or \"qianwen\" in model_name or \"qwen\" in model_name:\n",
        "                model_kwargs[\"enable_thinking\"] = False\n",
        "                print(f\"🔧 为模型 {model_name} 设置 enable_thinking=False\")\n",
        "            \n",
        "            llm = ChatOpenAI(\n",
        "                base_url=llm_config.get(\"base_url\"),\n",
        "                api_key=llm_config.get(\"api_key\"),\n",
        "                model=llm_config.get(\"model\"),\n",
        "                temperature=llm_config.get(\"temperature\", 0.7),\n",
        "                model_kwargs=model_kwargs\n",
        "            )\n",
        "            print(\"✅ 使用OpenAI兼容API（方法1：model_kwargs）\")\n",
        "            return llm\n",
        "    except Exception as e:\n",
        "        print(f\"⚠️ OpenAI API方法1失败: {e}\")\n",
        "        \n",
        "        # 方法2：尝试使用extra_body\n",
        "        try:\n",
        "            from langchain_openai import ChatOpenAI\n",
        "            from common.utils import get_current_llm_config\n",
        "            \n",
        "            llm_config = get_current_llm_config()\n",
        "            \n",
        "            if llm_config.get(\"base_url\") and llm_config.get(\"api_key\"):\n",
        "                model_name = llm_config.get(\"model\", \"\").lower()\n",
        "                \n",
        "                llm = ChatOpenAI(\n",
        "                    base_url=llm_config.get(\"base_url\"),\n",
        "                    api_key=llm_config.get(\"api_key\"),\n",
        "                    model=llm_config.get(\"model\"),\n",
        "                    temperature=llm_config.get(\"temperature\", 0.7),\n",
        "                    extra_body={\"enable_thinking\": False}\n",
        "                )\n",
        "                print(\"✅ 使用OpenAI兼容API（方法2：extra_body）\")\n",
        "                return llm\n",
        "        except Exception as e2:\n",
        "            print(f\"⚠️ OpenAI API方法2失败: {e2}\")\n",
        "    \n",
        "    # 回退方案：创建一个简单的包装器\n",
        "    from langchain_core.language_models import BaseChatModel\n",
        "    from langchain_core.messages import BaseMessage, AIMessage\n",
        "    from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "    \n",
        "    class VannaLLMWrapper(BaseChatModel):\n",
        "        \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "        \n",
        "        def __init__(self):\n",
        "            super().__init__()\n",
        "            self.vn = get_vanna_instance()\n",
        "        \n",
        "        def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "            # 构建提示词\n",
        "            prompt = \"\"\n",
        "            for msg in messages:\n",
        "                if isinstance(msg, SystemMessage):\n",
        "                    prompt = msg.content + \"\\n\\n\"\n",
        "                elif isinstance(msg, HumanMessage):\n",
        "                    prompt += f\"用户: {msg.content}\\n\"\n",
        "                elif isinstance(msg, AIMessage):\n",
        "                    prompt += f\"助手: {msg.content}\\n\"\n",
        "            \n",
        "            # 调用Vanna，确保禁用thinking\n",
        "            try:\n",
        "                # 直接调用项目中的LLM实例，它应该已经正确配置了thinking参数\n",
        "                response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            except TypeError:\n",
        "                # 如果不支持enable_thinking参数，使用默认调用\n",
        "                try:\n",
        "                    response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                except TypeError:\n",
        "                    # 最后的备用方案\n",
        "                    response = self.vn.chat_with_llm(question=prompt)\n",
        "            \n",
        "            # 返回结果\n",
        "            message = AIMessage(content=response)\n",
        "            generation = ChatGeneration(message=message)\n",
        "            return ChatResult(generations=[generation])\n",
        "        \n",
        "        @property\n",
        "        def _llm_type(self) -> str:\n",
        "            return \"vanna_wrapper\"\n",
        "    \n",
        "    print(\"✅ 使用Vanna LLM包装器\")\n",
        "    return VannaLLMWrapper()\n",
        "\n",
        "# 获取LLM实例\n",
        "llm = get_llm()\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 4,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:40:13,350 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:40:23,136 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:40:23,137 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:40:23,138 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:40:23,139 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:40:23,139 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:40:23,140 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:40:23,142 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:40:23,142 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:40:23,143 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:40:23,144 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:40:23,393 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:40:23,394 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:40:23,395 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:40:23,396 - vanna.BaseLLMChat - INFO -   model: qwen-plus\n",
            "2025-07-08 09:40:23,397 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:40:23,398 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:40:23,398 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:40:23,399 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:40:23,399 - vanna.BaseLLMChat - INFO -   stream: False\n",
            "2025-07-08 09:40:23,399 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:40:23,400 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:40:23,400 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000024E2E5135C0>\n",
            "2025-07-08 09:40:23,401 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:40:23,402 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:40:24,662 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:40:24,663 - app.VannaSingleton - INFO - Vanna 实例创建成功\n",
            "2025-07-08 09:40:24,668 - vanna.BaseLLMChat - INFO - \n",
            "Using model qwen-plus for 18.5 tokens (approx)\n",
            "2025-07-08 09:40:24,668 - vanna.BaseLLMChat - INFO - Enable thinking: False, Stream mode: False\n",
            "2025-07-08 09:40:24,669 - vanna.BaseLLMChat - INFO - 使用非流式处理模式\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "✅ 使用Vanna LLM包装器\n",
            "\n",
            "🧪 测试LLM基础功能...\n",
            "🔧 成功禁用thinking和stream\n",
            "✅ LLM测试成功: 测试成功\n"
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    # 使用类配置允许额外字段\n",
        "    model_config = {\"extra\": \"allow\"}\n",
        "    \n",
        "    def __init__(self, **kwargs):\n",
        "        super().__init__(**kwargs)\n",
        "        # 在初始化后设置vn实例\n",
        "        object.__setattr__(self, 'vn', get_vanna_instance())\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 5,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[5]\u001b[39m\u001b[32m, line 55\u001b[39m\n\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[5]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:28:50,209 - app.VannaSingleton - INFO - 创建 Vanna 实例...\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "⚠️  检测到thinking参数问题，直接使用Vanna包装器...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "2025-07-08 09:29:00,759 - app.ConfigUtils - INFO - === 当前模型配置 ===\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM提供商: api\n",
            "2025-07-08 09:29:00,762 - app.ConfigUtils - INFO - LLM模型: qianwen\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding提供商: api\n",
            "2025-07-08 09:29:00,763 - app.ConfigUtils - INFO - Embedding模型: text-embedding-v4\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - 向量数据库: pgvector\n",
            "2025-07-08 09:29:00,764 - app.ConfigUtils - INFO - ==================\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 创建QIANWEN+PGVECTOR实例\n",
            "2025-07-08 09:29:00,765 - vanna.VannaFactory - INFO - 已配置使用PgVector，连接字符串: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:00,766 - vanna.VannaFactory - INFO - 已配置使用API嵌入模型: text-embedding-v4\n",
            "2025-07-08 09:29:01,087 - vanna.BaseLLMChat - INFO - 传入的 config 参数如下：\n",
            "2025-07-08 09:29:01,088 - vanna.BaseLLMChat - INFO -   api_key: sk-db68e37f00974031935395315bfe07f0\n",
            "2025-07-08 09:29:01,089 - vanna.BaseLLMChat - INFO -   base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
            "2025-07-08 09:29:01,090 - vanna.BaseLLMChat - INFO -   model: qwen3-235b-a22b\n",
            "2025-07-08 09:29:01,091 - vanna.BaseLLMChat - INFO -   allow_llm_to_see_data: True\n",
            "2025-07-08 09:29:01,092 - vanna.BaseLLMChat - INFO -   temperature: 0.6\n",
            "2025-07-08 09:29:01,093 - vanna.BaseLLMChat - INFO -   n_results: 6\n",
            "2025-07-08 09:29:01,094 - vanna.BaseLLMChat - INFO -   language: Chinese\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   stream: True\n",
            "2025-07-08 09:29:01,095 - vanna.BaseLLMChat - INFO -   enable_thinking: False\n",
            "2025-07-08 09:29:01,096 - vanna.BaseLLMChat - INFO -   connection_string: postgresql://postgres:postgres@192.168.67.1:5432/highway_pgvector_db\n",
            "2025-07-08 09:29:01,097 - vanna.BaseLLMChat - INFO -   embedding_function: <core.embedding_function.EmbeddingFunction object at 0x0000018A8D2376B0>\n",
            "2025-07-08 09:29:01,098 - vanna.BaseLLMChat - INFO - temperature is changed to: 0.6\n",
            "2025-07-08 09:29:01,099 - vanna.BaseLLMChat - INFO - QianWenChat init\n",
            "2025-07-08 09:29:02,512 - vanna.VannaFactory - INFO - 已连接到业务数据库: 192.168.67.1:6432/highway_db\n",
            "2025-07-08 09:29:02,513 - app.VannaSingleton - INFO - Vanna 实例创建成功\n"
          ]
        },
        {
          "ename": "ValueError",
          "evalue": "\"VannaLLMWrapper\" object has no field \"vn\"",
          "output_type": "error",
          "traceback": [
            "\u001b[31m---------------------------------------------------------------------------\u001b[39m\n",
            "\u001b[31mValueError\u001b[39m                                Traceback (most recent call last)\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 55\u001b[39m\n",
            "\u001b[32m     52\u001b[39m         \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[33m\"\u001b[39m\u001b[33mvanna_wrapper\u001b[39m\u001b[33m\"\u001b[39m\n",
            "\u001b[32m     54\u001b[39m \u001b[38;5;66;03m# 创建LLM实例\u001b[39;00m\n",
            "\u001b[32m---> \u001b[39m\u001b[32m55\u001b[39m llm = \u001b[43mVannaLLMWrapper\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n",
            "\u001b[32m     56\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33m\"\u001b[39m\u001b[33m✅ 使用Vanna LLM包装器\u001b[39m\u001b[33m\"\u001b[39m)\n",
            "\u001b[32m     58\u001b[39m \u001b[38;5;66;03m# 测试LLM基础功能\u001b[39;00m\n",
            "\n",
            "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[26]\u001b[39m\u001b[32m, line 17\u001b[39m, in \u001b[36mVannaLLMWrapper.__init__\u001b[39m\u001b[34m(self)\u001b[39m\n",
            "\u001b[32m     15\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m__init__\u001b[39m(\u001b[38;5;28mself\u001b[39m):\n",
            "\u001b[32m     16\u001b[39m     \u001b[38;5;28msuper\u001b[39m().\u001b[34m__init__\u001b[39m()\n",
            "\u001b[32m---> \u001b[39m\u001b[32m17\u001b[39m     \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mvn\u001b[49m = get_vanna_instance()\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:997\u001b[39m, in \u001b[36mBaseModel.__setattr__\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m    995\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)\n",
            "\u001b[32m    996\u001b[39m \u001b[38;5;66;03m# if None is returned from _setattr_handler, the attribute was set directly\u001b[39;00m\n",
            "\u001b[32m--> \u001b[39m\u001b[32m997\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m (setattr_handler := \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_setattr_handler\u001b[49m\u001b[43m(\u001b[49m\u001b[43mname\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mvalue\u001b[49m\u001b[43m)\u001b[49m) \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    998\u001b[39m     setattr_handler(\u001b[38;5;28mself\u001b[39m, name, value)  \u001b[38;5;66;03m# call here to not memo on possibly unknown fields\u001b[39;00m\n",
            "\u001b[32m    999\u001b[39m     \u001b[38;5;28mself\u001b[39m.__pydantic_setattr_handlers__[name] = setattr_handler\n",
            "\n",
            "\u001b[36mFile \u001b[39m\u001b[32mc:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\pydantic\\main.py:1044\u001b[39m, in \u001b[36mBaseModel._setattr_handler\u001b[39m\u001b[34m(self, name, value)\u001b[39m\n",
            "\u001b[32m   1041\u001b[39m \u001b[38;5;28;01melif\u001b[39;00m name \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.__pydantic_fields__:\n",
            "\u001b[32m   1042\u001b[39m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mcls\u001b[39m.model_config.get(\u001b[33m'\u001b[39m\u001b[33mextra\u001b[39m\u001b[33m'\u001b[39m) != \u001b[33m'\u001b[39m\u001b[33mallow\u001b[39m\u001b[33m'\u001b[39m:\n",
            "\u001b[32m   1043\u001b[39m         \u001b[38;5;66;03m# TODO - matching error\u001b[39;00m\n",
            "\u001b[32m-> \u001b[39m\u001b[32m1044\u001b[39m         \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[33mf\u001b[39m\u001b[33m'\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mcls\u001b[39m.\u001b[34m__name__\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m object has no field \u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\u001b[33m'\u001b[39m)\n",
            "\u001b[32m   1045\u001b[39m     \u001b[38;5;28;01melif\u001b[39;00m attr \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n",
            "\u001b[32m   1046\u001b[39m         \u001b[38;5;66;03m# attribute does not exist, so put it in extra\u001b[39;00m\n",
            "\u001b[32m   1047\u001b[39m         \u001b[38;5;28mself\u001b[39m.__pydantic_extra__[name] = value\n",
            "\n",
            "\u001b[31mValueError\u001b[39m: \"VannaLLMWrapper\" object has no field \"vn\""
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 由于ChatOpenAI不支持enable_thinking参数，直接使用Vanna包装器\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "print(\"⚠️  检测到thinking参数问题，直接使用Vanna包装器...\")\n",
        "\n",
        "# 直接创建Vanna包装器\n",
        "from langchain_core.language_models import BaseChatModel\n",
        "from langchain_core.messages import BaseMessage, AIMessage, SystemMessage, HumanMessage\n",
        "from langchain_core.outputs import ChatResult, ChatGeneration\n",
        "\n",
        "class VannaLLMWrapper(BaseChatModel):\n",
        "    \"\"\"Vanna LLM的LangChain包装器\"\"\"\n",
        "    \n",
        "    def __init__(self):\n",
        "        super().__init__()\n",
        "        self.vn = get_vanna_instance()\n",
        "    \n",
        "    def _generate(self, messages: List[BaseMessage], **kwargs) -> ChatResult:\n",
        "        # 构建提示词\n",
        "        prompt = \"\"\n",
        "        for msg in messages:\n",
        "            if isinstance(msg, SystemMessage):\n",
        "                prompt = msg.content + \"\\n\\n\"\n",
        "            elif isinstance(msg, HumanMessage):\n",
        "                prompt += f\"用户: {msg.content}\\n\"\n",
        "            elif isinstance(msg, AIMessage):\n",
        "                prompt += f\"助手: {msg.content}\\n\"\n",
        "        \n",
        "        # 调用Vanna，确保禁用thinking和stream\n",
        "        try:\n",
        "            # 尝试禁用thinking和stream\n",
        "            response = self.vn.chat_with_llm(question=prompt, enable_thinking=False, stream=False)\n",
        "            print(\"🔧 成功禁用thinking和stream\")\n",
        "        except TypeError:\n",
        "            try:\n",
        "                # 尝试只禁用stream\n",
        "                response = self.vn.chat_with_llm(question=prompt, stream=False)\n",
        "                print(\"🔧 成功禁用stream\")\n",
        "            except TypeError:\n",
        "                # 最后的备用方案\n",
        "                response = self.vn.chat_with_llm(question=prompt)\n",
        "                print(\"🔧 使用默认调用\")\n",
        "        \n",
        "        # 返回结果\n",
        "        message = AIMessage(content=response)\n",
        "        generation = ChatGeneration(message=message)\n",
        "        return ChatResult(generations=[generation])\n",
        "    \n",
        "    @property\n",
        "    def _llm_type(self) -> str:\n",
        "        return \"vanna_wrapper\"\n",
        "\n",
        "# 创建LLM实例\n",
        "llm = VannaLLMWrapper()\n",
        "print(\"✅ 使用Vanna LLM包装器\")\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"检查Vanna实例是否正常工作...\")\n",
        "    \n",
        "    # 直接测试Vanna实例\n",
        "    try:\n",
        "        vn = get_vanna_instance()\n",
        "        direct_response = vn.chat_with_llm(question=\"测试\", stream=False)\n",
        "        print(f\"✅ Vanna直接调用成功: {direct_response}\")\n",
        "    except Exception as e2:\n",
        "        print(f\"❌ Vanna直接调用也失败: {e2}\")\n",
        "        print(\"请检查您的LLM配置和网络连接\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "🔧 检测到模型: qwen3-235b-a22b\n",
            "🔧 为模型 qwen3-235b-a22b 设置 enable_thinking=False\n",
            "✅ 使用OpenAI兼容API（方法1：model_kwargs）\n",
            "\n",
            "🧪 测试LLM基础功能...\n",
            "❌ LLM测试失败: Completions.create() got an unexpected keyword argument 'enable_thinking'\n",
            "如果仍然有thinking错误，请检查您的app_config.py中的LLM配置\n"
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 重新获取LLM实例\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "llm = get_llm()\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    from langchain_core.messages import HumanMessage\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"如果仍然有thinking错误，请检查您的app_config.py中的LLM配置\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "🔧 检测到模型: qwen3-235b-a22b\n",
            "🔧 为模型 qwen3-235b-a22b 设置 enable_thinking=False\n",
            "✅ 使用OpenAI兼容API（方法1：model_kwargs）\n",
            "\n",
            "🧪 测试LLM基础功能...\n",
            "❌ LLM测试失败: Completions.create() got an unexpected keyword argument 'enable_thinking'\n",
            "如果仍然有thinking错误，请检查您的app_config.py中的LLM配置\n"
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 重新获取LLM实例\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "llm = get_llm()\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    from langchain_core.messages import HumanMessage\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"如果仍然有thinking错误，请检查您的app_config.py中的LLM配置\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "🔧 检测到模型: qwen3-235b-a22b\n",
            "🔧 为模型 qwen3-235b-a22b 设置 enable_thinking=False\n",
            "✅ 使用OpenAI兼容API（方法1：model_kwargs）\n",
            "\n",
            "🧪 测试LLM基础功能...\n",
            "❌ LLM测试失败: Completions.create() got an unexpected keyword argument 'enable_thinking'\n",
            "如果仍然有thinking错误，请检查您的app_config.py中的LLM配置\n"
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 重新获取LLM实例\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "llm = get_llm()\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    from langchain_core.messages import HumanMessage\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"如果仍然有thinking错误，请检查您的app_config.py中的LLM配置\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "🔧 检测到模型: qwen3-235b-a22b\n",
            "🔧 为模型 qwen3-235b-a22b 设置 enable_thinking=False\n",
            "✅ 使用OpenAI兼容API（方法1：model_kwargs）\n",
            "\n",
            "🧪 测试LLM基础功能...\n",
            "❌ LLM测试失败: Completions.create() got an unexpected keyword argument 'enable_thinking'\n",
            "如果仍然有thinking错误，请检查您的app_config.py中的LLM配置\n"
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 重新获取LLM实例\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "llm = get_llm()\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    from langchain_core.messages import HumanMessage\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"如果仍然有thinking错误，请检查您的app_config.py中的LLM配置\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "🔧 检测到模型: qwen3-235b-a22b\n",
            "🔧 为模型 qwen3-235b-a22b 设置 enable_thinking=False\n",
            "✅ 使用OpenAI兼容API（方法1：model_kwargs）\n",
            "\n",
            "🧪 测试LLM基础功能...\n",
            "❌ LLM测试失败: Completions.create() got an unexpected keyword argument 'enable_thinking'\n",
            "如果仍然有thinking错误，请检查您的app_config.py中的LLM配置\n"
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 重新获取LLM实例\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "llm = get_llm()\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    from langchain_core.messages import HumanMessage\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"如果仍然有thinking错误，请检查您的app_config.py中的LLM配置\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔄 重新创建LLM实例...\n",
            "🔧 检测到模型: qwen3-235b-a22b\n",
            "🔧 为模型 qwen3-235b-a22b 设置 enable_thinking=False\n",
            "✅ 使用OpenAI兼容API（方法1：model_kwargs）\n",
            "\n",
            "🧪 测试LLM基础功能...\n",
            "❌ LLM测试失败: Completions.create() got an unexpected keyword argument 'enable_thinking'\n",
            "如果仍然有thinking错误，请检查您的app_config.py中的LLM配置\n"
          ]
        }
      ],
      "source": [
        "## 3.1 重新创建LLM实例（解决thinking参数问题）\n",
        "\n",
        "# 重新获取LLM实例\n",
        "print(\"🔄 重新创建LLM实例...\")\n",
        "llm = get_llm()\n",
        "\n",
        "# 测试LLM基础功能\n",
        "print(\"\\n🧪 测试LLM基础功能...\")\n",
        "try:\n",
        "    from langchain_core.messages import HumanMessage\n",
        "    test_response = llm.invoke([HumanMessage(content=\"请回复'测试成功'\")])\n",
        "    print(f\"✅ LLM测试成功: {test_response.content}\")\n",
        "except Exception as e:\n",
        "    print(f\"❌ LLM测试失败: {e}\")\n",
        "    print(\"如果仍然有thinking错误，请检查您的app_config.py中的LLM配置\")\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "## 4. 定义工具函数\n",
        "### 4.1 generate_sql 工具"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 11,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "✅ generate_sql 工具已定义\n"
          ]
        }
      ],
      "source": [
        "@tool\n",
        "def generate_sql(question: str) -> Dict[str, Any]:\n",
        "    \"\"\"\n",
        "    将自然语言问题转换为SQL查询。\n",
        "    \n",
        "    Args:\n",
        "        question: 需要转换为SQL的自然语言问题\n",
        "    \n",
        "    Returns:\n",
        "        包含SQL生成结果的字典\n",
        "    \"\"\"\n",
        "    try:\n",
        "        if VERBOSE:\n",
        "            print(f\"🔧 [generate_sql] 输入问题: {question}\")\n",
        "        \n",
        "        vn = get_vanna_instance()\n",
        "        sql = vn.generate_sql(question=question, allow_llm_to_see_data=True)\n",
        "        \n",
        "        if sql is None:\n",
        "            # 检查是否有解释性文本\n",
        "            explanation = getattr(vn, 'last_llm_explanation', None)\n",
        "            if explanation:\n",
        "                return {\n",
        "                    \"success\": False,\n",
        "                    \"sql\": None,\n",
        "                    \"error\": explanation,\n",
        "                    \"error_type\": \"no_relevant_data\"\n",
        "                }\n",
        "            else:\n",
        "                return {\n",
        "                    \"success\": False,\n",
        "                    \"sql\": None,\n",
        "                    \"error\": \"无法生成SQL查询，可能是问题描述不够明确或数据表结构不匹配\",\n",
        "                    \"error_type\": \"generation_failed\"\n",
        "                }\n",
        "        \n",
        "        if VERBOSE:\n",
        "            print(f\"✅ [generate_sql] 生成的SQL: {sql}\")\n",
        "        \n",
        "        return {\n",
        "            \"success\": True,\n",
        "            \"sql\": sql,\n",
        "            \"error\": None\n",
        "        }\n",
        "        \n",
        "    except Exception as e:\n",
        "        return {\n",
        "            \"success\": False,\n",
        "            \"sql\": None,\n",
        "            \"error\": f\"SQL生成异常: {str(e)}\",\n",
        "            \"error_type\": \"exception\"\n",
        "        }\n",
        "\n",
        "print(\"✅ generate_sql 工具已定义\")\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "### 4.2 valid_sql 工具"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 12,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "✅ valid_sql 工具已定义\n"
          ]
        }
      ],
      "source": [
        "@tool\n",
        "def valid_sql(sql: str) -> Dict[str, Any]:\n",
        "    \"\"\"\n",
        "    验证SQL语句的正确性。\n",
        "    \n",
        "    Args:\n",
        "        sql: 要验证的SQL语句\n",
        "    \n",
        "    Returns:\n",
        "        包含验证结果的字典\n",
        "    \"\"\"\n",
        "    try:\n",
        "        if VERBOSE:\n",
        "            print(f\"🔧 [valid_sql] 验证SQL: {sql[:100]}...\")\n",
        "        \n",
        "        # 1. 基础格式检查\n",
        "        if not sql or not sql.strip():\n",
        "            return {\n",
        "                \"success\": True,\n",
        "                \"valid\": False,\n",
        "                \"error\": \"SQL语句为空\"\n",
        "            }\n",
        "        \n",
        "        # 2. 禁止词检查\n",
        "        forbidden_operations = ['UPDATE', 'DELETE', 'DROP', 'ALTER', 'INSERT']\n",
        "        sql_upper = sql.upper().strip()\n",
        "        \n",
        "        for operation in forbidden_operations:\n",
        "            if sql_upper.startswith(operation):\n",
        "                return {\n",
        "                    \"success\": True,\n",
        "                    \"valid\": False,\n",
        "                    \"error\": f\"不允许的操作: {operation}。本系统只支持查询操作(SELECT)。\"\n",
        "                }\n",
        "        \n",
        "        # 3. 语法验证（使用EXPLAIN）\n",
        "        vn = get_vanna_instance()\n",
        "        explain_sql = f\"EXPLAIN {sql}\"\n",
        "        \n",
        "        try:\n",
        "            result = vn.run_sql(explain_sql)\n",
        "            if result is not None:\n",
        "                if VERBOSE:\n",
        "                    print(\"✅ [valid_sql] SQL验证通过\")\n",
        "                return {\n",
        "                    \"success\": True,\n",
        "                    \"valid\": True,\n",
        "                    \"error\": None\n",
        "                }\n",
        "            else:\n",
        "                return {\n",
        "                    \"success\": True,\n",
        "                    \"valid\": False,\n",
        "                    \"error\": \"SQL语法验证失败\"\n",
        "                }\n",
        "        except Exception as e:\n",
        "            error_msg = str(e)\n",
        "            if VERBOSE:\n",
        "                print(f\"❌ [valid_sql] 验证失败: {error_msg}\")\n",
        "            return {\n",
        "                \"success\": True,\n",
        "                \"valid\": False,\n",
        "                \"error\": f\"SQL语法错误: {error_msg}\"\n",
        "            }\n",
        "            \n",
        "    except Exception as e:\n",
        "        return {\n",
        "            \"success\": False,\n",
        "            \"valid\": False,\n",
        "            \"error\": f\"验证过程异常: {str(e)}\"\n",
        "        }\n",
        "\n",
        "print(\"✅ valid_sql 工具已定义\")\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "### 4.3 run_sql 工具\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 13,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "✅ run_sql 工具已定义\n"
          ]
        }
      ],
      "source": [
        "@tool\n",
        "def run_sql(sql: str) -> Dict[str, Any]:\n",
        "    \"\"\"\n",
        "    执行SQL查询并返回结果。\n",
        "    \n",
        "    Args:\n",
        "        sql: 要执行的SQL查询语句\n",
        "    \n",
        "    Returns:\n",
        "        包含查询结果的字典\n",
        "    \"\"\"\n",
        "    try:\n",
        "        if VERBOSE:\n",
        "            print(f\"🔧 [run_sql] 执行SQL: {sql[:100]}...\")\n",
        "        \n",
        "        vn = get_vanna_instance()\n",
        "        df = vn.run_sql(sql)\n",
        "        \n",
        "        if df is None:\n",
        "            return {\n",
        "                \"success\": False,\n",
        "                \"data\": None,\n",
        "                \"error\": \"SQL执行返回空结果\",\n",
        "                \"row_count\": 0\n",
        "            }\n",
        "        \n",
        "        if not isinstance(df, pd.DataFrame):\n",
        "            return {\n",
        "                \"success\": False,\n",
        "                \"data\": None,\n",
        "                \"error\": f\"SQL执行返回非DataFrame类型: {type(df)}\",\n",
        "                \"row_count\": 0\n",
        "            }\n",
        "        \n",
        "        if df.empty:\n",
        "            return {\n",
        "                \"success\": True,\n",
        "                \"data\": [],\n",
        "                \"columns\": list(df.columns),\n",
        "                \"row_count\": 0,\n",
        "                \"message\": \"查询执行成功，但没有找到符合条件的数据\"\n",
        "            }\n",
        "        \n",
        "        # 处理数据结果\n",
        "        total_rows = len(df)\n",
        "        limited_df = df.head(MAX_RETURN_ROWS)\n",
        "        \n",
        "        # 转换为字典格式\n",
        "        rows = limited_df.to_dict(orient=\"records\")\n",
        "        columns = list(df.columns)\n",
        "        \n",
        "        if VERBOSE:\n",
        "            print(f\"✅ [run_sql] 查询成功，返回 {total_rows} 行数据\")\n",
        "        \n",
        "        result = {\n",
        "            \"success\": True,\n",
        "            \"data\": rows,\n",
        "            \"columns\": columns,\n",
        "            \"row_count\": len(rows),\n",
        "            \"total_row_count\": total_rows,\n",
        "            \"is_limited\": total_rows > MAX_RETURN_ROWS\n",
        "        }\n",
        "        \n",
        "        if total_rows > MAX_RETURN_ROWS:\n",
        "            result[\"message\"] = f\"共 {total_rows} 行数据，已限制显示前 {MAX_RETURN_ROWS} 行\"\n",
        "        \n",
        "        return result\n",
        "        \n",
        "    except Exception as e:\n",
        "        error_msg = str(e)\n",
        "        if VERBOSE:\n",
        "            print(f\"❌ [run_sql] 执行失败: {error_msg}\")\n",
        "        \n",
        "        return {\n",
        "            \"success\": False,\n",
        "            \"data\": None,\n",
        "            \"error\": f\"SQL执行失败: {error_msg}\",\n",
        "            \"row_count\": 0\n",
        "        }\n",
        "\n",
        "print(\"✅ run_sql 工具已定义\")\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "### 4.4 generate_summary 工具\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "✅ generate_summary 工具已定义\n"
          ]
        }
      ],
      "source": [
        "@tool\n",
        "def generate_summary(question: str, query_result: str) -> Dict[str, Any]:\n",
        "    \"\"\"\n",
        "    为查询结果生成自然语言摘要。\n",
        "    \n",
        "    Args:\n",
        "        question: 原始问题\n",
        "        query_result: 查询结果的JSON字符串\n",
        "    \n",
        "    Returns:\n",
        "        包含摘要结果的字典\n",
        "    \"\"\"\n",
        "    try:\n",
        "        if VERBOSE:\n",
        "            print(f\"🔧 [generate_summary] 为问题生成摘要: {question}\")\n",
        "        \n",
        "        # 解析查询结果\n",
        "        try:\n",
        "            result_data = json.loads(query_result) if isinstance(query_result, str) else query_result\n",
        "        except:\n",
        "            result_data = {\"error\": \"无法解析查询结果\"}\n",
        "        \n",
        "        # 检查是否有数据\n",
        "        if not result_data.get(\"success\") or not result_data.get(\"data\"):\n",
        "            return {\n",
        "                \"success\": True,\n",
        "                \"summary\": \"查询执行完成，但没有找到符合条件的数据。\"\n",
        "            }\n",
        "        \n",
        "        # 重构DataFrame用于摘要生成\n",
        "        rows = result_data.get(\"data\", [])\n",
        "        columns = result_data.get(\"columns\", [])\n",
        "        \n",
        "        if rows and columns:\n",
        "            df = pd.DataFrame(rows, columns=columns)\n",
        "            \n",
        "            # 调用Vanna生成摘要\n",
        "            vn = get_vanna_instance()\n",
        "            summary = vn.generate_summary(question=question, df=df)\n",
        "            \n",
        "            if summary:\n",
        "                if VERBOSE:\n",
        "                    print(f\"✅ [generate_summary] 摘要生成成功\")\n",
        "                return {\n",
        "                    \"success\": True,\n",
        "                    \"summary\": summary\n",
        "                }\n",
        "        \n",
        "        # 生成默认摘要\n",
        "        row_count = result_data.get(\"row_count\", 0)\n",
        "        summary = f\"根据您的问题『{question}』，查询返回了 {row_count} 条记录。\"\n",
        "        \n",
        "        if columns:\n",
        "            summary += f\"数据包含以下字段：{', '.join(columns[:5])}\" \n",
        "            if len(columns) > 5:\n",
        "                summary += f\"等{len(columns)}个字段。\"\n",
        "            else:\n",
        "                summary += \"。\"\n",
        "        \n",
        "        return {\n",
        "            \"success\": True,\n",
        "            \"summary\": summary\n",
        "        }\n",
        "        \n",
        "    except Exception as e:\n",
        "        if VERBOSE:\n",
        "            print(f\"❌ [generate_summary] 生成摘要失败: {str(e)}\")\n",
        "        \n",
        "        return {\n",
        "            \"success\": True,\n",
        "            \"summary\": f\"查询执行完成，共返回数据。\"\n",
        "        }\n",
        "\n",
        "print(\"✅ generate_summary 工具已定义\")\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "## 5. 创建 ReAct Agent\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 15,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "✅ 工具列表已准备\n",
            "可用工具: ['generate_sql', 'valid_sql', 'run_sql', 'generate_summary']\n"
          ]
        }
      ],
      "source": [
        "# 系统提示词\n",
        "SYSTEM_MESSAGE = f\"\"\"\n",
        "你是一个智能数据查询助手，可以帮助用户查询数据库信息，也可以回答一般性问题。\n",
        "\n",
        "{DATABASE_SCOPE}\n",
        "\n",
        "=== 工作流程 ===\n",
        "1. 判断问题类型：\n",
        "   - 如果问题涉及上述业务数据，使用工具查询数据库\n",
        "   - 如果是常识性问题（如\"荔枝几月上市\"），直接用你的知识回答\n",
        "\n",
        "2. 数据库查询流程：\n",
        "   a) 使用 generate_sql 生成SQL\n",
        "   b) 使用 valid_sql 验证SQL\n",
        "   c) 如果验证通过，使用 run_sql 执行SQL\n",
        "   d) 使用 generate_summary 生成结果摘要\n",
        "\n",
        "3. 错误处理：\n",
        "   - 如果无法生成SQL，说明数据库中可能没有相关数据\n",
        "   - 对于边界问题，可以先尝试查询，如果失败则用常识回答\n",
        "\n",
        "4. 注意事项：\n",
        "   - 每个工具调用都要检查返回的 success 字段\n",
        "   - 如果工具调用失败，根据 error 信息决定下一步\n",
        "   - 避免重复调用相同的工具超过2次\n",
        "\n",
        "请根据用户问题，智能选择合适的处理方式。\n",
        "\"\"\"\n",
        "\n",
        "# 创建工具列表\n",
        "tools = [generate_sql, valid_sql, run_sql, generate_summary]\n",
        "\n",
        "print(\"✅ 工具列表已准备\")\n",
        "print(f\"可用工具: {[tool.name for tool in tools]}\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "## 5.0 重新创建Agent（使用修复后的LLM）\n",
        "\n",
        "# 重新创建Agent\n",
        "print(\"🔄 重新创建Agent...\")\n",
        "\n",
        "agent = None\n",
        "success_method = None\n",
        "\n",
        "# 基础创建（系统消息将在调用时处理）\n",
        "try:\n",
        "    agent = create_react_agent(\n",
        "        llm,\n",
        "        tools=tools\n",
        "    )\n",
        "    success_method = \"基础创建（系统消息将在调用时处理）\"\n",
        "    print(\"✅ ReAct Agent 重新创建成功\")\n",
        "    print(\"⚠️  注意：系统消息将在每次调用时手动添加\")\n",
        "except Exception as e3:\n",
        "    print(f\"❌ Agent创建失败: {e3}\")\n",
        "    raise Exception(\"无法创建 ReAct Agent\")\n",
        "\n",
        "print(f\"🎯 成功方法: {success_method}\")\n",
        "print(f\"📋 Agent 类型: {type(agent)}\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "方法1失败: create_react_agent() got an unexpected keyword argument 'system_message'\n",
            "方法2失败: create_react_agent() got an unexpected keyword argument 'state_modifier'\n",
            "✅ ReAct Agent 创建成功（方法3：基础创建）\n",
            "⚠️  注意：系统消息将在每次调用时手动添加\n",
            "🎯 成功方法: 基础创建（系统消息将在调用时处理）\n",
            "📋 Agent 类型: <class 'langgraph.graph.state.CompiledStateGraph'>\n"
          ]
        }
      ],
      "source": [
        "# 创建 ReAct Agent\n",
        "# 尝试多种兼容的方式来设置系统消息\n",
        "\n",
        "agent = None\n",
        "success_method = None\n",
        "\n",
        "# 方法1：尝试使用 system_message 参数\n",
        "try:\n",
        "    agent = create_react_agent(\n",
        "        llm,\n",
        "        tools=tools,\n",
        "        system_message=SYSTEM_MESSAGE\n",
        "    )\n",
        "    success_method = \"system_message 参数\"\n",
        "    print(\"✅ ReAct Agent 创建成功（方法1：system_message 参数）\")\n",
        "except Exception as e:\n",
        "    if VERBOSE:\n",
        "        print(f\"方法1失败: {e}\")\n",
        "    \n",
        "    # 方法2：尝试使用 state_modifier 参数\n",
        "    try:\n",
        "        agent = create_react_agent(\n",
        "            llm,\n",
        "            tools=tools,\n",
        "            state_modifier=SYSTEM_MESSAGE\n",
        "        )\n",
        "        success_method = \"state_modifier 参数\"\n",
        "        print(\"✅ ReAct Agent 创建成功（方法2：state_modifier 参数）\")\n",
        "    except Exception as e2:\n",
        "        if VERBOSE:\n",
        "            print(f\"方法2失败: {e2}\")\n",
        "        \n",
        "        # 方法3：基础创建（将在调用时处理系统消息）\n",
        "        try:\n",
        "            agent = create_react_agent(\n",
        "                llm,\n",
        "                tools=tools\n",
        "            )\n",
        "            success_method = \"基础创建（系统消息将在调用时处理）\"\n",
        "            print(\"✅ ReAct Agent 创建成功（方法3：基础创建）\")\n",
        "            print(\"⚠️  注意：系统消息将在每次调用时手动添加\")\n",
        "        except Exception as e3:\n",
        "            print(f\"❌ 所有方法都失败了:\")\n",
        "            print(f\"  方法1: {e}\")\n",
        "            print(f\"  方法2: {e2}\")\n",
        "            print(f\"  方法3: {e3}\")\n",
        "            raise Exception(\"无法创建 ReAct Agent\")\n",
        "\n",
        "print(f\"🎯 成功方法: {success_method}\")\n",
        "print(f\"📋 Agent 类型: {type(agent)}\")\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 18,
      "metadata": {},
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "🔍 Agent 状态验证:\n",
            "   - Agent 实例: True\n",
            "   - Agent 类型: <class 'langgraph.graph.state.CompiledStateGraph'>\n",
            "   - 创建方法: 基础创建（系统消息将在调用时处理）\n",
            "   - 可用工具: 4 个\n",
            "   - 工具列表: ['generate_sql', 'valid_sql', 'run_sql', 'generate_summary']\n",
            "   - 基础调用测试: 尝试中...\n",
            "   - 基础调用测试: ❌ 失败 (Error code: 400 - {'error': {'code': 'invalid_parameter_error', 'param': None, 'message': 'parameter.enable_thinking must be set to false for non-streaming calls', 'type': 'invalid_request_error'}, 'id': 'chatcmpl-9f3d39f8-df01-9096-a0ce-c11c829b0b24', 'request_id': '9f3d39f8-df01-9096-a0ce-c11c829b0b24'})\n",
            "   - 详细错误:\n",
            "\n",
            "==================================================\n",
            "⚠️  Agent 验证失败，请检查配置\n",
            "==================================================\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Traceback (most recent call last):\n",
            "  File \"C:\\Users\\PaulWang\\AppData\\Local\\Temp\\ipykernel_40896\\2734479170.py\", line 24, in verify_agent\n",
            "    result = agent.invoke({\"messages\": simple_messages}, test_config)\n",
            "             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langgraph\\pregel\\__init__.py\", line 2719, in invoke\n",
            "    for chunk in self.stream(\n",
            "                 ^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langgraph\\pregel\\__init__.py\", line 2436, in stream\n",
            "    for _ in runner.tick(\n",
            "             ^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langgraph\\pregel\\runner.py\", line 161, in tick\n",
            "    run_with_retry(\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langgraph\\pregel\\retry.py\", line 40, in run_with_retry\n",
            "    return task.proc.invoke(task.input, config)\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langgraph\\utils\\runnable.py\", line 623, in invoke\n",
            "    input = context.run(step.invoke, input, config, **kwargs)\n",
            "            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langgraph\\utils\\runnable.py\", line 370, in invoke\n",
            "    ret = context.run(self.func, *args, **kwargs)\n",
            "          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langgraph\\prebuilt\\chat_agent_executor.py\", line 505, in call_model\n",
            "    response = cast(AIMessage, model_runnable.invoke(state, config))\n",
            "                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langchain_core\\runnables\\base.py\", line 3047, in invoke\n",
            "    input_ = context.run(step.invoke, input_, config)\n",
            "             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langchain_core\\runnables\\base.py\", line 5431, in invoke\n",
            "    return self.bound.invoke(\n",
            "           ^^^^^^^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langchain_core\\language_models\\chat_models.py\", line 372, in invoke\n",
            "    self.generate_prompt(\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langchain_core\\language_models\\chat_models.py\", line 957, in generate_prompt\n",
            "    return self.generate(prompt_messages, stop=stop, callbacks=callbacks, **kwargs)\n",
            "           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langchain_core\\language_models\\chat_models.py\", line 776, in generate\n",
            "    self._generate_with_cache(\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langchain_core\\language_models\\chat_models.py\", line 1022, in _generate_with_cache\n",
            "    result = self._generate(\n",
            "             ^^^^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\langchain_openai\\chat_models\\base.py\", line 790, in _generate\n",
            "    response = self.client.create(**payload)\n",
            "               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\openai\\_utils\\_utils.py\", line 287, in wrapper\n",
            "    return func(*args, **kwargs)\n",
            "           ^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\openai\\resources\\chat\\completions\\completions.py\", line 925, in create\n",
            "    return self._post(\n",
            "           ^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\openai\\_base_client.py\", line 1239, in post\n",
            "    return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))\n",
            "                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n",
            "  File \"c:\\Projects\\cursor_projects\\Vanna-Chainlit-Chromadb\\.venv\\Lib\\site-packages\\openai\\_base_client.py\", line 1034, in request\n",
            "    raise self._make_status_error_from_response(err.response) from None\n",
            "openai.BadRequestError: Error code: 400 - {'error': {'code': 'invalid_parameter_error', 'param': None, 'message': 'parameter.enable_thinking must be set to false for non-streaming calls', 'type': 'invalid_request_error'}, 'id': 'chatcmpl-9f3d39f8-df01-9096-a0ce-c11c829b0b24', 'request_id': '9f3d39f8-df01-9096-a0ce-c11c829b0b24'}\n",
            "During task with name 'agent' and id 'e3744fa2-a8df-45fa-2e57-f0e5dec4feb4'\n"
          ]
        }
      ],
      "source": [
        "## 5.1 Agent 状态验证\n",
        "\n",
        "# 验证Agent是否正常创建\n",
        "def verify_agent():\n",
        "    \"\"\"验证Agent状态\"\"\"\n",
        "    print(\"🔍 Agent 状态验证:\")\n",
        "    print(f\"   - Agent 实例: {agent is not None}\")\n",
        "    print(f\"   - Agent 类型: {type(agent)}\")\n",
        "    print(f\"   - 创建方法: {success_method}\")\n",
        "    print(f\"   - 可用工具: {len(tools)} 个\")\n",
        "    print(f\"   - 工具列表: {[tool.name for tool in tools]}\")\n",
        "    \n",
        "    # 测试基础功能\n",
        "    try:\n",
        "        # 创建一个最简单的消息（包含系统消息，因为我们用的是基础创建）\n",
        "        simple_messages = [\n",
        "            SystemMessage(content=\"你是一个有用的助手。\"),\n",
        "            HumanMessage(content=\"你好，请简单回复。\")\n",
        "        ]\n",
        "        test_config = {\"recursion_limit\": 3}\n",
        "        \n",
        "        # 尝试调用\n",
        "        print(\"   - 基础调用测试: 尝试中...\")\n",
        "        result = agent.invoke({\"messages\": simple_messages}, test_config)\n",
        "        \n",
        "        # 检查返回结果\n",
        "        if result and \"messages\" in result:\n",
        "            final_message = result[\"messages\"][-1]\n",
        "            print(f\"   - 基础调用测试: ✅ 成功\")\n",
        "            print(f\"   - 返回消息类型: {type(final_message).__name__}\")\n",
        "            print(f\"   - 消息内容预览: {final_message.content[:50]}...\")\n",
        "            return True\n",
        "        else:\n",
        "            print(f\"   - 基础调用测试: ❌ 返回格式异常\")\n",
        "            return False\n",
        "            \n",
        "    except Exception as e:\n",
        "        print(f\"   - 基础调用测试: ❌ 失败 ({e})\")\n",
        "        if VERBOSE:\n",
        "            import traceback\n",
        "            print(\"   - 详细错误:\")\n",
        "            traceback.print_exc()\n",
        "        return False\n",
        "\n",
        "# 执行验证\n",
        "verify_success = verify_agent()\n",
        "print(f\"\\n{'='*50}\")\n",
        "if verify_success:\n",
        "    print(\"🎉 Agent 验证通过，可以开始测试！\")\n",
        "    print(\"💡 提示：由于使用基础创建方式，每次调用都会包含完整的系统消息\")\n",
        "else:\n",
        "    print(\"⚠️  Agent 验证失败，请检查配置\")\n",
        "print(f\"{'='*50}\")\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "## 6. 测试函数\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def test_agent(question: str, max_iterations: int = None) -> Dict[str, Any]:\n",
        "    \"\"\"\n",
        "    测试Agent处理问题\n",
        "    \n",
        "    Args:\n",
        "        question: 用户问题\n",
        "        max_iterations: 最大迭代次数，默认使用MAX_TOOL_CALLS\n",
        "    \n",
        "    Returns:\n",
        "        处理结果\n",
        "    \"\"\"\n",
        "    if max_iterations is None:\n",
        "        max_iterations = MAX_TOOL_CALLS\n",
        "    \n",
        "    print(f\"\\n{'='*60}\")\n",
        "    print(f\"🤔 问题: {question}\")\n",
        "    print(f\"⚙️  最大工具调用次数: {max_iterations}\")\n",
        "    print(f\"⚙️  Agent 创建方法: {success_method}\")\n",
        "    print(f\"{'='*60}\\n\")\n",
        "    \n",
        "    try:\n",
        "        # 构建消息 - 根据Agent创建方式决定是否包含系统消息\n",
        "        if success_method == \"基础创建（系统消息将在调用时处理）\":\n",
        "            # 如果Agent创建时没有系统消息，需要手动添加\n",
        "            messages = [\n",
        "                SystemMessage(content=SYSTEM_MESSAGE),\n",
        "                HumanMessage(content=question)\n",
        "            ]\n",
        "        else:\n",
        "            # 如果Agent创建时已包含系统消息，只需要用户消息\n",
        "            messages = [\n",
        "                HumanMessage(content=question)\n",
        "            ]\n",
        "        \n",
        "        # 设置配置，包括递归限制\n",
        "        config = {\n",
        "            \"recursion_limit\": max_iterations + 5,  # 额外的缓冲\n",
        "            \"configurable\": {\n",
        "                \"thread_id\": f\"test_{datetime.now().strftime('%Y%m%d_%H%M%S')}\"\n",
        "            }\n",
        "        }\n",
        "        \n",
        "        if VERBOSE:\n",
        "            print(f\"📝 发送消息数量: {len(messages)}\")\n",
        "            print(f\"📝 消息类型: {[type(msg).__name__ for msg in messages]}\")\n",
        "        \n",
        "        # 调用Agent\n",
        "        start_time = datetime.now()\n",
        "        result = agent.invoke({\"messages\": messages}, config=config)\n",
        "        end_time = datetime.now()\n",
        "        \n",
        "        # 提取最终响应\n",
        "        final_message = result[\"messages\"][-1]\n",
        "        \n",
        "        print(f\"\\n{'='*60}\")\n",
        "        print(f\"✅ 最终答案:\")\n",
        "        print(f\"{final_message.content}\")\n",
        "        print(f\"\\n⏱️  处理时间: {(end_time - start_time).total_seconds():.2f} 秒\")\n",
        "        print(f\"📊 消息数量: {len(result['messages'])}\")\n",
        "        print(f\"{'='*60}\\n\")\n",
        "        \n",
        "        return {\n",
        "            \"success\": True,\n",
        "            \"question\": question,\n",
        "            \"answer\": final_message.content,\n",
        "            \"messages\": result[\"messages\"],\n",
        "            \"duration\": (end_time - start_time).total_seconds()\n",
        "        }\n",
        "        \n",
        "    except Exception as e:\n",
        "        print(f\"\\n❌ 处理失败: {e}\")\n",
        "        if VERBOSE:\n",
        "            import traceback\n",
        "            print(f\"🔍 详细错误信息:\")\n",
        "            traceback.print_exc()\n",
        "        return {\n",
        "            \"success\": False,\n",
        "            \"question\": question,\n",
        "            \"error\": str(e)\n",
        "        }\n",
        "\n",
        "print(\"✅ 测试函数已定义\")\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "## 7. 执行测试\n",
        "### 7.1 测试数据库查询"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 测试数据库查询问题\n",
        "test_questions_db = [\n",
        "    \"查询所有服务区的名称\",\n",
        "    \"统计今天的营业额\",\n",
        "    \"哪个档口的收入最高？\",\n",
        "    \"昨天的车流量是多少？\"\n",
        "]\n",
        "\n",
        "# 选择一个问题测试（可以修改索引）\n",
        "result = test_agent(test_questions_db[0], max_iterations=8)\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "### 7.2 测试常识问题\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 测试常识性问题\n",
        "test_questions_common = [\n",
        "    \"荔枝几月份上市？\",\n",
        "    \"今天天气怎么样？\",\n",
        "    \"Python是什么？\",\n",
        "    \"如何做番茄炒蛋？\"\n",
        "]\n",
        "\n",
        "# 选择一个问题测试\n",
        "result = test_agent(test_questions_common[0], max_iterations=5)\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "### 7.3 测试边界问题\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 测试边界问题（可能在数据库中，也可能需要常识）\n",
        "test_questions_boundary = [\n",
        "    \"服务区有卖荔枝吗？\",  # 可能需要查询商品表\n",
        "    \"高速公路什么时候建成的？\",  # 可能没有这个数据\n",
        "    \"如何联系客服？\",  # 系统相关但可能不在数据库\n",
        "]\n",
        "\n",
        "# 选择一个问题测试\n",
        "result = test_agent(test_questions_boundary[0], max_iterations=10)\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "### 7.4 批量测试\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 批量测试多个问题\n",
        "def batch_test(questions: List[str], max_iterations: int = None):\n",
        "    \"\"\"批量测试问题\"\"\"\n",
        "    results = []\n",
        "    \n",
        "    for i, question in enumerate(questions, 1):\n",
        "        print(f\"\\n🔄 测试 {i}/{len(questions)}: {question}\")\n",
        "        result = test_agent(question, max_iterations)\n",
        "        results.append(result)\n",
        "        \n",
        "        # 简短总结\n",
        "        if result[\"success\"]:\n",
        "            print(f\"✅ 成功，耗时 {result['duration']:.2f} 秒\")\n",
        "        else:\n",
        "            print(f\"❌ 失败: {result.get('error', 'Unknown error')}\")\n",
        "    \n",
        "    # 统计\n",
        "    success_count = sum(1 for r in results if r[\"success\"])\n",
        "    total_time = sum(r.get(\"duration\", 0) for r in results)\n",
        "    \n",
        "    print(f\"\\n📊 批量测试完成:\")\n",
        "    print(f\"   - 成功率: {success_count}/{len(questions)} ({success_count/len(questions)*100:.1f}%)\")\n",
        "    print(f\"   - 总耗时: {total_time:.2f} 秒\")\n",
        "    print(f\"   - 平均耗时: {total_time/len(questions):.2f} 秒/问题\")\n",
        "    \n",
        "    return results\n",
        "\n",
        "# 执行批量测试\n",
        "all_test_questions = [\n",
        "    \"查询所有服务区\",\n",
        "    \"荔枝几月份上市？\",\n",
        "    \"今天的营业额是多少？\",\n",
        "    \"Python是什么编程语言？\"\n",
        "]\n",
        "\n",
        "# batch_results = batch_test(all_test_questions, max_iterations=8)\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "## 8. 调试工具\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def analyze_agent_execution(result: Dict[str, Any]):\n",
        "    \"\"\"分析Agent执行过程\"\"\"\n",
        "    if not result.get(\"success\"):\n",
        "        print(\"❌ 执行失败，无法分析\")\n",
        "        return\n",
        "    \n",
        "    messages = result.get(\"messages\", [])\n",
        "    \n",
        "    print(f\"\\n📝 执行过程分析:\")\n",
        "    print(f\"总消息数: {len(messages)}\")\n",
        "    \n",
        "    tool_calls = []\n",
        "    for i, msg in enumerate(messages):\n",
        "        if hasattr(msg, 'tool_calls') and msg.tool_calls:\n",
        "            for tool_call in msg.tool_calls:\n",
        "                tool_calls.append({\n",
        "                    \"index\": i,\n",
        "                    \"tool\": tool_call[\"name\"],\n",
        "                    \"args\": tool_call.get(\"args\", {})\n",
        "                })\n",
        "    \n",
        "    print(f\"\\n🔧 工具调用序列 (共 {len(tool_calls)} 次):\")\n",
        "    for tc in tool_calls:\n",
        "        print(f\"   {tc['index']}. {tc['tool']} - 参数: {tc['args']}\")\n",
        "    \n",
        "    # 统计工具使用\n",
        "    from collections import Counter\n",
        "    tool_counter = Counter(tc['tool'] for tc in tool_calls)\n",
        "    \n",
        "    print(f\"\\n📊 工具使用统计:\")\n",
        "    for tool, count in tool_counter.items():\n",
        "        print(f\"   - {tool}: {count} 次\")\n",
        "\n",
        "# 使用示例（需要先运行测试）\n",
        "# analyze_agent_execution(result)\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "## 9. 自定义测试\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# 在这里输入您的自定义问题进行测试\n",
        "custom_question = \"查询今天营业额最高的前3个档口\"\n",
        "\n",
        "# 可以调整最大工具调用次数\n",
        "custom_max_iterations = 10\n",
        "\n",
        "# 执行测试\n",
        "custom_result = test_agent(custom_question, max_iterations=custom_max_iterations)\n",
        "\n",
        "# 分析执行过程\n",
        "if custom_result[\"success\"]:\n",
        "    analyze_agent_execution(custom_result)\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "## 10. 总结\n",
        "\n",
        "### 实现的功能：\n",
        "1. ✅ 使用 `create_react_agent()` 创建智能Agent\n",
        "2. ✅ 实现四个工具：generate_sql, valid_sql, run_sql, generate_summary\n",
        "3. ✅ Agent能够自主判断是查询数据库还是用常识回答\n",
        "4. ✅ 支持配置最大工具调用次数，防止无限循环\n",
        "5. ✅ 对边界问题的处理：先尝试查询，失败则用常识\n",
        "\n",
        "### 使用说明：\n",
        "1. 修改 `DATABASE_SCOPE` 变量来更新数据库业务范围描述\n",
        "2. 调整 `MAX_TOOL_CALLS` 来控制最大工具调用次数\n",
        "3. 使用 `test_agent()` 函数测试单个问题\n",
        "4. 使用 `batch_test()` 批量测试多个问题\n",
        "5. 使用 `analyze_agent_execution()` 分析执行过程\n",
        "\n",
        "### 注意事项：\n",
        "- 所有代码都在这个notebook中，不影响项目其他部分\n",
        "- valid_sql 工具是新创建的，从现有代码中提取了验证逻辑\n",
        "- Agent会根据工具返回的success和error信息智能决策下一步\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "## 11. 依赖包说明\n",
        "\n",
        "### 运行此 notebook 需要的包：\n",
        "\n",
        "如果运行时遇到缺包错误，请在您的 `.venv` 环境中安装以下包：\n",
        "\n",
        "```bash\n",
        "# LangChain 和 LangGraph 相关\n",
        "pip install langchain==0.3.7\n",
        "pip install langgraph==0.2.53\n",
        "pip install langchain-openai==0.2.9  # 如果使用OpenAI兼容API\n",
        "\n",
        "# 其他可能需要的依赖\n",
        "pip install pandas  # 如果还没安装\n",
        "pip install asyncio  # 通常已内置\n",
        "```\n",
        "\n",
        "### 版本兼容性说明：\n",
        "- 本 notebook 基于 LangChain/LangGraph v0.3.x 开发\n",
        "- `create_react_agent` 函数在 `langgraph.prebuilt` 模块中\n",
        "- 如果版本不匹配，可能需要调整导入路径或API用法\n",
        "\n",
        "### 常见问题：\n",
        "1. **ImportError: cannot import name 'create_react_agent'**\n",
        "   - 确保 langgraph 版本 >= 0.2.0\n",
        "   - 检查导入路径是否正确\n",
        "\n",
        "2. **找不到 Vanna 实例**\n",
        "   - 确保项目根目录的 common/vanna_instance.py 可以正常导入\n",
        "   - 检查数据库连接配置\n",
        "\n",
        "3. **LLM 调用失败**\n",
        "   - 检查 app_config.py 中的 LLM 配置\n",
        "   - 确保 API key 和 endpoint 正确\n"
      ]
    },
    {
      "cell_type": "raw",
      "metadata": {
        "vscode": {
          "languageId": "raw"
        }
      },
      "source": [
        "## 12. 开始使用\n",
        "\n",
        "### 快速开始：\n",
        "1. 确保已激活 `.venv` 环境\n",
        "2. 运行 Cell 1-5 进行初始化设置\n",
        "3. 运行 Cell 6-16 创建工具和Agent\n",
        "4. 运行 Cell 19 定义测试函数\n",
        "5. 然后可以测试各种问题：\n",
        "\n",
        "```python\n",
        "# 测试示例\n",
        "test_agent(\"查询今天的营业额\")\n",
        "test_agent(\"荔枝几月份上市？\")\n",
        "test_agent(\"哪个服务区车流量最大？\")\n",
        "```\n",
        "\n",
        "祝您测试愉快！🚀\n"
      ]
    }
  ],
  "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.12.6"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}
