项目目标

  1. 满足自己筛选基金经理;
  2. 写一个跟AI相关的项目;
  3. 学习与锻炼Python编程;
  4. 学习与使用开源框架 Qwen-agent。  

项目背景

        早在2020年底就尝试过爬取网上的基金数据用来解决自己的问题了,从网上学到一些筛选基金经理的理论,想着去实践,但是专业网站、APP都不能满足。
        因此,就想着自己来写一个工具,从数据采集到最后数据分析结果呈现,尽可能地让整个过程自动化。可是,一直未去实践,仅是有想法而已,画画流程图而已。
        2020年,随着 GPT-3火爆全球,AI正式进入科技领域的热门。而我是在近一年多才慢慢主动去关注这个领域,去学习一些应用层技术。之后,了解到有chan2SQL,觉得挺有意思的。很快就和自己以前构想的基金经理筛选项目结合到一起了。         

        好了,大概就这样,接下来就是实现的过程了。整个过程,基本上靠LLM chat工具来写代码,而我主要负责出想法,调试代码。  

想法 + 使用AI工具实现过程

工具与技术框架介绍

工具:

  • Windows 笔记本
  •  PyCharm 2025.1 (原IDE PyCharm 2024.3.4 (Community Edition)  已不合适使用)

技术框架:

  • Qwen-agen 0.0.24;
  • Python 3.12;
  • flask  3.1.0;
  • flask-cors  3.0.10;
  • vue.js

Python解释器里关键包:

  • mysql 0.0.3
  • mysql-connector-python    8.4.0     
  • mysqlclient    2.2.7    

为了方便阅读,此系列文章,每一篇开头都保持上述【项目目标】和【项目背景】,以及【想法 + 使用AI工具实现过程】中的“工具与技术框架介绍”。


上一篇文章说到,最后得到的SQL语句中有换行等其他格式的字符,导致得到的SQL无法直接复制粘贴,运行。也谈及了问题可能是出现在 prompt上。

而经过验证,确实可通过修改 system prompt来解决这个问题。

新的 system prompt 定义如下:(只是修改了第4点)

# 构建 system_prompt
system_prompt = f'''
你是一个数据库助手,能将自然语言转换为 SQL。请遵循以下规则:
1. 始终参考以下表结构:
{get_table_schema()}
2. 生成的 SQL 必须严格符合表结构和字段名。
3. 如果问题涉及未提及的表或字段,请直接告知用户。
4. 你只需输出 SQL 语句,不要存在格式化的内容,不要执行它,也不要解释。
'''

基于初版代码优化过程

本次主要优化内容

  1. 实现 Vue + Flask 前后端分离;
  2. 探索 Qwen-agent 是否支持其他 LLM

初始代码如下

主程序 app.py

from flask import Flask, render_template, request
import mysql.connector
from mysql.connector import Error
import os
from dotenv import load_dotenv
from qwen_agent.agents import Assistant

app = Flask(__name__)

# 加载环境变量(用于数据库配置)
load_dotenv()

# 数据库连接配置(从 .env 文件读取)
def get_db_connection():
    try:
        connection = mysql.connector.connect(
            host=os.getenv('DB_HOST'),
            user=os.getenv('DB_USER'),
            password=os.getenv('DB_PASSWORD'),
            database=os.getenv('DB_NAME')
        )
        return connection
    except Error as e:
        print(f"数据库连接失败: {e}")
        return None

# 获取表结构信息(供 LLM 使用)
def get_table_schema():
    return """
    表结构如下:
    - 表名: fund_list
      字段(字段注释 | 字段类型): fund_id (基金ID | varchar), fund_name (基金名称 | varchar), company_id (基金公司编码 | varchar), 
        company_name (基金公司名称 | varchar), manager_ids (当前管理人ID | varchar), manager_names (当前管理人名称 | varchar), 
        fund_type (基金类型 | varchar), fund_size (基金规模(元) | decimal), create_user (创建人 | varchar), create_time (创建时间 | datetime), update_time (更新时间 | datetime)
    - 表名: fund_manager
      字段(字段注释 | 字段类型): manager_id (基金经理ID | varchar), manager_name (基金经理名称 | varchar), company_id (基金公司编码 | varchar), 
        company_name (基金公司名称 | varchar), work_duration (从业时长 | varchar), work_years (从业年份 | decimal), 
        manager_link (基金经理详情链接 | varchar), create_user (创建人 | varchar), create_time (创建时间 | datetime), update_time (更新时间 | datetime)
    - 表名: manager_fund_rel
      字段(字段注释 | 字段类型): id (主键 | int), manager_id (基金经理ID | varchar), manager_name (基金经理名称 | varchar), 
        company_id (基金公司编码 | varchar), company_name (基金公司名称 | varchar), fund_id (基金ID | varchar), fund_name (基金名称 | varchar), 
        fund_type (基金类型 | varchar), fund_size (基金规模(元) | decimal), fund_managing_time (基金管理时间 | varchar), 
        fund_managing_duration (管理时长 | varchar), fund_managing_years (管理年份 | decimal), term_return_rate (任期回报率(保留4位小数存储) | decimal),
        year_return_rate (年化收益率(保留4位小数存储) | decimal), create_user (创建人 | varchar), create_time (创建时间 | datetime), update_time (更新时间 | datetime)
    """

import re
# 正则表达式提取 SQL
def extract_sql(text):
    # 匹配以 SELECT/INSERT/UPDATE/DELETE 开头的 SQL
    match = re.search(r'(SELECT\s+.*?;|INSERT\s+.*?;|UPDATE\s+.*?;|DELETE\s+.*?;)', text, re.DOTALL | re.IGNORECASE)
    if match:
        return match.group(0).strip()
    return ''

# 构建 system_prompt,强调只生成 SQL 不执行
system_prompt = f'''
你是一个数据库助手,能将自然语言转换为 SQL。请遵循以下规则:
1. 始终参考以下表结构:
{get_table_schema()}
2. 生成的 SQL 必须严格符合表结构和字段名。
3. 如果问题涉及未提及的表或字段,请直接告知用户。
4. 你只需输出 SQL 语句,不要存在格式化的内容,不要执行它,也不要解释。
'''

# 初始化 Qwen 助手(不注册任何工具)
llm_cfg = {
    'model': 'qwen-plus', #'qwen-max',
    'model_server': 'dashscope'
}

bot = Assistant(
    llm=llm_cfg,
    system_message=system_prompt
)

messages = []

@app.route('/', methods=['GET', 'POST'])
def index():
    global messages
    execution_result = None

    if request.method == 'POST':
        user_input = request.form.get('query', '')
        execute_sql = request.form.get('execute_sql')  # 是否点击了执行按钮

        if user_input.lower() in ['exit', 'quit']:
            return render_template('index.html', history=messages, sql="")

        if not execute_sql:
            # 用户输入自然语言,让 AI 生成 SQL
            messages.append({'role': 'user', 'content': user_input})

            # 获取 AI 最终生成的 SQL
            final_content = ''
            for r in bot.run(messages=messages):
                if isinstance(r, dict):
                    content = r.get('content', '')
                else:
                    content = str(r)
                final_content = content.strip()  # 保留最后一次的内容

            # 提取SQL
            extract_sql_str = extract_sql(final_content)

            messages.append({'role': 'assistant', 'content': final_content})
            messages.append({'role': 'assistant_sql', 'content': extract_sql_str})
        else:
            # 用户点击“执行 SQL”,使用后端手动执行
            sql_to_run = request.form.get('sql_to_execute', '').strip()
            conn = get_db_connection()
            if conn and conn.is_connected():
                cursor = conn.cursor(dictionary=True)
                try:
                    cursor.execute(sql_to_run)
                    execution_result = cursor.fetchall()
                except Error as e:
                    execution_result = f"执行错误:{str(e)}"
                finally:
                    cursor.close()
                    conn.close()
            else:
                execution_result = "数据库连接失败"

    return render_template(
        'index.html',
        history=messages,
        execution_result=execution_result
    )

if __name__ == '__main__':
    app.run(debug=True)

前端页面 \templates\index.html

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>SQL 生成助手</title>
    <!-- 引入 CodeMirror 样式 -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0/codemirror.min.css">
    <style>
        .CodeMirror {
            border: 1px solid #ccc;
            height: auto;
        }
    </style>
</head>
<body>
    <h1>AI SQL 生成助手</h1>

    {% for msg in history %}
        <div style="margin-bottom: 10px;">
            <strong>{{ msg.role }}:</strong>
            <pre>{{ msg.user_custom_content }}</pre>
            <pre>{{ msg.content }}</pre>
        </div>
    {% endfor %}

    <form method="post">
        <textarea name="query" rows="4" cols="50" placeholder="请输入你的自然语言查询..."></textarea><br/>
        <input type="submit" value="生成 SQL">
    </form>

    {% if formatted_sql %}
        <h2>格式化后的 SQL:</h2>
        <textarea id="sqlEditor" rows="10" cols="80">{{ formatted_sql }}</textarea>
        <button onclick="copyToClipboard()">复制 SQL 到剪贴板</button>
    {% endif %}

    <!-- 引入 CodeMirror JS -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0/codemirror.min.js"></script>
    <script>
        // 初始化 CodeMirror 编辑器
        var editor = CodeMirror.fromTextArea(document.getElementById('sqlEditor'), {
            lineNumbers: true,
            mode: 'text/x-mysql',
            theme: 'dracula'
        });

        // 复制到剪贴板功能
        function copyToClipboard() {
            const sqlText = editor.getValue();
            navigator.clipboard.writeText(sqlText).then(() => {
                alert("SQL 已复制到剪贴板!");
            }, () => {
                alert("复制失败,请手动复制。");
            });
        }
    </script>
</body>
</html>

优化1:实现 Vue + Flask前后端分离

一、前言:

为啥要实现前后端分离架构呢,是为了更好地调试与使用吧,在技术开发上来说,这是实现了前端工程师与后端开发工程的分工。而为啥前端选择了vue,选择了这样一套前后端分离架构呢?

Python后端选择 Flask 的理由如下截图所示,何况前面一直 app.py 就是在使用 Flask。

而之所以选择 vue.js,是因为不想倒腾其他前端框架了,没用过,也不在项目目标中。其他较不错的前端框架,比如 React、Angular等。

二、过程:

回到优化内容来,怎么实现这么一个目标呢,直接让 LLM Chat 给写一份初始代码。

prompt:

app.py 代码内容如下:

复制粘贴 app.py 的全部代码,将上述初始代码粘贴下来,这里就不重复粘贴了

前端 \templates\index.html 代码如下:

复制粘贴 index.html 的全部代码,将上述初始代码粘贴下来,这里就不重复粘贴了

****

请根据上述代码,将其架构改为前后端分离,前端使用 vue,后端继续使用 flash,请给出完整且可运行的项目代码

这里建议大家新创建一个项目。

(1)更换 IDE

本次的代码涉及到 vue.js 的使用,原来使用 IDE PyCharm 2024.3.4 (Community Edition)  是不支持的,PyCharm 的专业版才支持,这个大家看情况解决吧。

我的办法是下载了 PyCharm 2025.1版本,下载地址:Other Versions - PyCharm

然后某宝买了一个好东西,就可没烦恼的长期使用了。

(2)安装 node.js、npm

在处理代码前,请大家确保已安装了 node.js、npm。

这里给大家一个 npm 安装教程,NPM安装与配置全流程详解(2025最新版)-CSDN博客

避免用到哪些点赞与阅读量都不少,而质量有待商榷的文章,自己就是在上面浪费了近一个小时。只要按照如下截图部分操作即可:

搞完上述准备工作,就到代码编译运行了……

        LLM 给出来的代码版本,在结构上来说,是不错的。但是一运行起来,就遇到了各种各样的问题,主要问题点如下:

  • 前端生成未使用到的引用,致使发生编译错误,无法运行;
  • 前后端分离常见问题,404(路由、代理)、跨域;
  • 前端还出现了 vue 加载语法错误的代码,致使代码无法像预期一样执行,属于运行时错误。
三、最终代码:

项目结构

app.py

from flask import Flask, jsonify, request
from flask_cors import CORS
import mysql.connector
from mysql.connector import Error
import os
from dotenv import load_dotenv
from qwen_agent.agents import Assistant

# 加载环境变量
load_dotenv()

app = Flask(__name__)
CORS(app)  # 启用跨域请求

import sys
print(sys.executable)

# 数据库连接配置(从 .env 文件读取)
def get_db_connection():
    try:
        connection = mysql.connector.connect(
            host=os.getenv('DB_HOST'),
            user=os.getenv('DB_USER'),
            password=os.getenv('DB_PASSWORD'),
            database=os.getenv('DB_NAME')
        )
        return connection
    except Error as e:
        print(f"数据库连接失败: {e}")
        return None


# 获取表结构信息(供 LLM 使用)
def get_table_schema():
    return """
    表结构如下:
    - 表名: fund_list
      字段(字段注释 | 字段类型): fund_id (基金ID | varchar), fund_name (基金名称 | varchar), company_id (基金公司编码 | varchar), 
        company_name (基金公司名称 | varchar), manager_ids (当前管理人ID | varchar), manager_names (当前管理人名称 | varchar), 
        fund_type (基金类型 | varchar), fund_size (基金规模(亿元) | decimal), create_user (创建人 | varchar), create_time (创建时间 | datetime), update_time (更新时间 | datetime)
    - 表名: fund_manager
      字段(字段注释 | 字段类型): manager_id (基金经理ID | varchar), manager_name (基金经理名称 | varchar), company_id (基金公司编码 | varchar), 
        company_name (基金公司名称 | varchar), work_duration (从业时长 | varchar), work_years (从业年份 | decimal), 
        manager_link (基金经理详情链接 | varchar), create_user (创建人 | varchar), create_time (创建时间 | datetime), update_time (更新时间 | datetime)
    - 表名: manager_fund_rel
      字段(字段注释 | 字段类型): id (主键 | int), manager_id (基金经理ID | varchar), manager_name (基金经理名称 | varchar), 
        company_id (基金公司编码 | varchar), company_name (基金公司名称 | varchar), fund_id (基金ID | varchar), fund_name (基金名称 | varchar), 
        fund_type (基金类型 | varchar), fund_size (基金规模(亿元) | decimal), fund_managing_time (基金管理时间 | varchar), 
        fund_managing_duration (管理时长 | varchar), fund_managing_years (管理年份 | decimal), term_return_rate (任期回报率(保留4位小数存储) | decimal),
        year_return_rate (年化收益率(保留4位小数存储) | decimal), create_user (创建人 | varchar), create_time (创建时间 | datetime), update_time (更新时间 | datetime)
    """

import re


# 正则表达式提取 SQL
def extract_sql(text):
    # 匹配以 SELECT/INSERT/UPDATE/DELETE 开头的 SQL
    match = re.search(r'(SELECT\s+.*?;|INSERT\s+.*?;|UPDATE\s+.*?;|DELETE\s+.*?;)', text, re.DOTALL | re.IGNORECASE)
    if match:
        return match.group(0).strip()
    return ''


# 构建 system_prompt
system_prompt = f'''
你是一个数据库助手,能将自然语言转换为 SQL。请遵循以下规则:
1. 始终参考以下表结构:
{get_table_schema()}
2. 生成的 SQL 必须严格符合表结构和字段名。
3. 如果问题涉及未提及的表或字段,请直接告知用户。
4. 你只需输出 SQL 语句,不要存在格式化的内容(比如换行符\n等),不要执行它,也不要解释。
'''

# 初始化 Qwen 助手(不注册任何工具)
llm_cfg = {
    'model': 'qwen-max',  # 'qwen-plus',
    'model_server': 'dashscope'
}

bot = Assistant(
    llm=llm_cfg,
    system_message=system_prompt
)

messages = []


@app.route('/api/generate-sql', methods=['POST'])
def generate_sql():
    global messages
    data = request.json
    user_input = data.get('query', '')

    if not user_input:
        return jsonify({'error': '缺少查询内容'}), 400

    if user_input.lower() in ['exit', 'quit']:
        return jsonify({'sql': ''})

    # 用户输入自然语言,让 AI 生成 SQL
    messages.append({'role': 'user', 'content': user_input})

    # 获取 AI 最终生成的 SQL
    final_content = ''
    for r in bot.run(messages=messages):
        if isinstance(r, dict):
            content = r.get('content', '')
        else:
            content = str(r)
        final_content = content.strip()  # 保留最后一次的内容

    # 提取SQL
    extract_sql_str = extract_sql(final_content)

    messages.append({'role': 'assistant', 'content': final_content})

    return jsonify({'sql': extract_sql_str})


@app.route('/api/execute-sql', methods=['POST'])
def execute_sql():
    data = request.json
    sql_to_run = data.get('sql', '').strip()
    if not sql_to_run:
        return jsonify({'error': '缺少 SQL 语句'}), 400
    conn = get_db_connection()
    if not conn or not conn.is_connected():
        return jsonify({'error': '数据库连接失败'}), 500

    cursor = conn.cursor(dictionary=True)

    try:
        # 判断是否是 SELECT 查询
        if sql_to_run.strip().lower().startswith('select'):
            result = cursor.fetchall()
            return jsonify({'result': result})
        else:
            conn.commit()  # 提交事务
            return jsonify({'message': 'SQL 执行成功', 'rows_affected': cursor.rowcount})
    except Error as e:
        return jsonify({'error': str(e)}), 400
    finally:
        cursor.close()
        conn.close()

if __name__ == '__main__':
    app.run(debug=True)

config.py

class Config:
    DEBUG = False
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class DevelopmentConfig(Config):
    DEBUG = True

class ProductionConfig(Config):
    DEBUG = False

config = {
    'development': DevelopmentConfig,
    'production': ProductionConfig
}

index.html

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>SQL 生成助手</title>
    <!-- 引入 CodeMirror 样式 -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.0/codemirror.min.css">
</head>
<body>
    <div id="app"></div>
</body>
</html>
SqlAssistant.vue
<template>
  <div class="sql-assistant">
    <h1>SQL 生成智能助手</h1>

    <div class="chat-container">
      <div v-for="(message, index) in chatMessages" :key="index" class="message">
        <strong>{{ message.role }}:</strong>
        <pre v-if="message.content">{{ message.content }}</pre>
      </div>
    </div>

    <form @submit.prevent="generateSql" class="query-form">
      <textarea v-model="userQuery" rows="4" placeholder="请输入你的自然语言查询..."></textarea>
      <button type="submit">生成 SQL</button>
    </form>

    <div v-if="generatedSql" class="sql-output">
      <h2>生成的 SQL:</h2>
      <textarea id="sqlEditor" v-model="generatedSql" rows="10" cols="80"></textarea>
      <div class="sql-actions">
        <button @click="copyToClipboard">复制 SQL 到剪贴板</button>
        <button @click="executeSql">执行 SQL</button>
      </div>
    </div>

    <div v-if="executionResult" class="execution-result">
      <h2>执行结果:</h2>
      <pre>{{ JSON.stringify(executionResult, null, 2) }}</pre>
    </div>

    <div v-if="errorMessage" class="error-message">
      {{ errorMessage }}
    </div>
  </div>
</template>

<script>
import axios from 'axios'
import CodeMirror from 'codemirror'
import 'codemirror/mode/sql/sql'
import 'codemirror/theme/dracula.css'

export default {
  name: 'SqlAssistant',
  data() {
    return {
      userQuery: '',
      generatedSql: '',
      chatMessages: [],
      executionResult: null,
      errorMessage: '',
      editor: null
    }
  },
  mounted() {
    // 初始化 CodeMirror 编辑器
    this.$nextTick(() => {
      const editorElement = document.getElementById('sqlEditor');
      if (editorElement) {
        CodeMirror.fromTextArea(editorElement, {
          lineNumbers: true,
          mode: 'sql',
          readOnly: true
        });
      } else {
        console.error("未能找到 ID 为 'sqlEditor' 的元素");
      }
    });
  },
  methods: {
    async generateSql() {
      this.errorMessage = '';
      this.executionResult = null;

      if (!this.userQuery.trim()) {
        this.errorMessage = '请输入查询内容';
        return;
      }

      try {
        // 添加用户消息到聊天记录
        this.chatMessages.push({ role: 'User', content: this.userQuery });
        // 调用 API 生成 SQL
        const response = await axios.post('/api/generate-sql', { query: this.userQuery });
        console.log('resp -------- ', response)
        // 更新生成的 SQL
        this.generatedSql = response.data.sql || '';
        // 更新编辑器内容
        if (this.editor && this.generatedSql) {
          this.editor.setValue(this.generatedSql);
        }
        // 添加 AI 回复到聊天记录
        this.chatMessages.push({ role: 'Assistant', content: `生成的 SQL:\n${this.generatedSql}` });
        // 清空输入框
        this.userQuery = '';
      } catch (error) {
        this.errorMessage = `生成 SQL 失败: ${error.message}`;
        console.error('生成 SQL 错误:', error);
      }
    },
    async executeSql() {
      this.errorMessage = '';
      this.executionResult = null;
      if (!this.generatedSql.trim()) {
        this.errorMessage = '没有可执行的 SQL 语句';
        return;
      }
      try {
        // 执行 SQL
        const response = await axios.post('/api/execute-sql', { sql: this.generatedSql });
        if (response.data.error) {
          throw new Error(response.data.error);
        }
        this.executionResult = response.data.result;
      } catch (error) {
        this.errorMessage = `执行 SQL 失败: ${error.message}`;
        console.error('执行 SQL 错误:', error);
      }
    },
    copyToClipboard() {
      const sqlText = this.editor ? this.editor.getValue() : this.generatedSql;
      if (!sqlText) {
        this.errorMessage = '没有可复制的 SQL 语句';
        return;
      }
      navigator.clipboard.writeText(sqlText).then(() => {
        alert("SQL 已复制到剪贴板!");
      }, () => {
        this.errorMessage = "复制失败,请手动复制。";
      });
    }
  }
}
</script>

<style scoped>
.sql-assistant {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
  font-family: Arial, sans-serif;
}

h1, h2 {
  color: #333;
}

.chat-container {
  border: 1px solid #ddd;
  padding: 15px;
  margin-bottom: 20px;
  max-height: 400px;
  overflow-y: auto;
}

.message {
  margin-bottom: 10px;
}

.query-form {
  margin-bottom: 20px;
}

textarea {
  width: 100%;
  padding: 10px;
  font-size: 16px;
  box-sizing: border-box;
  margin-bottom: 10px;
}

button {
  background-color: #4CAF50;
  color: white;
  border: none;
  padding: 10px 15px;
  margin-right: 10px;
  cursor: pointer;
  font-size: 16px;
}

button:hover {
  background-color: #45a049;
}

.sql-output {
  margin-top: 20px;
}

.sql-actions {
  margin-top: 10px;
}

.execution-result {
  margin-top: 20px;
  background-color: #f8f8f8;
  padding: 15px;
  border: 1px solid #ddd;
}

.error-message {
  margin-top: 20px;
  color: red;
  background-color: #fff0f0;
  padding: 15px;
  border: 1px solid #ffcccc;
}
</style>

index.js

import { createRouter, createWebHistory } from 'vue-router'
import SqlAssistant from '../components/SqlAssistant.vue'

const routes = [
  { path: '/', component: SqlAssistant }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

App.vue

<template>
  <router-view />
</template>

<script>
export default {
  name: 'App'
}
</script>

main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

const app = createApp(App)
app.use(router)
app.mount('#app')

pakage.json

{
  "name": "sql-assistant",
  "version": "1.0.0",
  "description": "AI SQL Assistant",
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "eslint ."
  },
  "dependencies": {
    "axios": "^1.6.7",
    "codemirror": "^5.65.0",
    "vue": "^3.4.21",
    "vue-router": "^4.3.0"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "^5.0.8",
    "@vue/cli-plugin-eslint": "^5.0.8",
    "@vue/cli-service": "^5.0.8",
    "eslint": "^8.56.0",
    "eslint-config-prettier": "^9.0.0",
    "eslint-plugin-vue": "^9.23.0"
  }
}
package-lock.json,上面截图忘记说明了,这个也是运行过程生成的,不需理会。

vue.config.js
module.exports = {
  lintOnSave: false, // 关闭 ESLint 校验

  devServer: {
    proxy: {
      '/api': {
        target: 'http://localhost:5000', // 后端地址
        changeOrigin: true,              // 允许跨域
        pathRewrite: {
          // '^/api': ''                    // 把请求路径中的 /api 替换为空
        }
      }
    },
    port: 8080                           // 可选:指定前端开发端口
  }
}

至此,代码都在上面了,整个项目完整代码:夸克网盘分享

运行 app.py 启动后端服务,在PyCharm 终端,项目路径\frontend> 执行命令:npm run serve,启动前端。

启动成功后,浏览器访问:http://localhost:8080/ 

优化2:探索 Qwen-agent 是否支持其他 LLM

大家,可以从上述的运行效果来看,都没能生成想要的SQL,我猜想是 api_key 的问题,是受到了使用限制,也还不知在那里充值,在阿里云百炼上没找到,找到的朋友麻烦评论区留言告知一声,谢谢。

        然后呢,也怀疑会不会是模型 qwen-max 在自然语言生成SQL上能力不够。于是,就想着能不能实现动态配置 llm。经过查询资料,查看Qwen-agent,得知目前官方是不支持的,需要修改 Qwen-agent 框架底层代码,太技术了,暂时不倒腾了。

未完待续…

        回看项目目标,接下来最关键的就是要实现“筛选基金经理”,也就是要能按自然语言描述的需求,生成SQL,这里就会涉及到复杂查询SQL的问题。经过了解,要解决这个问题并非易事,这就是要学习之所在吧。对此的优化思路如下:

  1. 优化 prompt;
  2. 考证 DeepSeek 给出的思路:(先验证给出的解决方案是否是 Qwen-Agent 真的支持的,然后结合其他 LLM Chat给出的方案,综合考虑。再而,编码测试验证)
  • 采用 Qwen-Agent 的 三级代理架构;
  • Qwen-Agent 的逐步推理(Stepwise Reasoning)通过工具链实现多跳决策:将复杂问题分解为原子化子查询;
  • 工具增强:领域专属工具包(解决知识盲区);
  • 验证反馈闭环(降低错误率)。

这里放一下之前文章的链接吧,方便大家阅读。

AI编程实战:Python + Qwen-agent 实现chat2SQL智能助手系统-CSDN博客

AI编程实战:Python + Qwen-agent 实现chat2SQL智能助手系统(二)-CSDN博客

Logo

电影级数字人,免显卡端渲染SDK,十行代码即可调用,工业级demo免费开源下载!

更多推荐