{ "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: \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: \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: \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: \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: \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: \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: \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: \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: \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: \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: \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: \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: \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: \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: \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 类型: \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 类型: \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 }