You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

本地Flask调用微调Gemini模型遇400无效参数错误求助

排查Flask应用调用微调Gemini模型时的400无效参数错误

问题背景

本地Flask应用调用Vertex AI上微调后的Gemini模型时,触发Error processing request: 400 Request contains an invalid argument错误,已配置.env文件包含PROJECT_ID、LOCATION(美国区域)、MODEL_NAME和GOOGLE_APPLICATION_CREDENTIALS,相关代码如下:

app.py

from flask import Flask, render_template, request, jsonify
from dotenv import load_dotenv
import os

import utils  # Import utility functions
import vertexai
from vertexai.generative_models import GenerativeModel

app = Flask(__name__)

load_dotenv()  # Load environment variables from .env file
print(f"GOOGLE_APPLICATION_CREDENTIALS: {os.environ.get('GOOGLE_APPLICATION_CREDENTIALS')}")

# Load the model and environment variables
PROJECT_ID = os.getenv('PROJECT_ID')
LOCATION = os.getenv('LOCATION')
MODEL_NAME = os.getenv('MODEL_NAME')  # Load from .env

# Initialize Vertex AI
vertexai.init(project=PROJECT_ID, location=LOCATION)

# Load the fine-tuned model - adjust this part
model = GenerativeModel(MODEL_NAME)

UPLOAD_FOLDER = 'D:/University of Law/Courses/MSc CS Final Project/AI_Powered_Blueprint_Analyzer/uploads'
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER

@app.route("/", methods=["GET", "POST"])
def index():
    if request.method == "POST":
        try:
            analysis_name = request.form.get("analysis_name")
            blueprint_file = request.files.get("blueprint")
            additional_data = {
                "persona": request.files.get("persona"),
                "kpis": request.files.get("kpis"),
                "stakeholder_maps": request.files.get("stakeholder_maps"),
                "system_map": request.files.get("system_map"),
                "user_journey_map": request.files.get("user_journey_map"),
                "project_roadmap": request.files.get("project_roadmap"),
            }

        # validate required files 
            if not blueprint_file:
                return render_template("index.html", error="Blueprint file is required")

            prompt = utils.construct_prompt(analysis_name, blueprint_file, additional_data, app.config['UPLOAD_FOLDER'])
            print("Generated Prompt:", prompt)  # Debug print

            response = model.generate_content(
                contents=prompt,
                generation_config={
                    "max_output_tokens": 2048,
                    "temperature": 0.7,
                    "top_p": 0.8,
                }
            )
            
            if response and response.text:
                swot_analysis, improvements = utils.parse_gemini_response(response.text)
                return render_template("results.html", 
                                    analysis_name=analysis_name, 
                                    swot=swot_analysis, 
                                    improvements=improvements)
            else:
                return render_template("index.html", 
                                    error="No response generated from the model")

        except Exception as e:
            print(f"Full error details: {str(e)}")  # Debug print
            return render_template("index.html", 
                                error=f"Error processing request: {str(e)}")

    return render_template("index.html")

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

utils.py

import os
import re
from werkzeug.utils import secure_filename

def allowed_file(filename):
    allowed_extensions = {'png', 'jpg', 'jpeg', 'pdf', 'txt'}
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in allowed_extensions

def construct_prompt(analysis_name, blueprint_file, additional_data, upload_folder):
    prompt = f"Analysis Name: {analysis_name}\n\n"

    def read_file_content(file):
        file_content = file.read()
        file.seek(0)  # Reset file pointer
        try:
            return file_content.decode('utf-8')
        except UnicodeDecodeError:
            return "[Binary file content not included in analysis]"

    if blueprint_file:
        filename = secure_filename(blueprint_file.filename)
        filepath = os.path.join(upload_folder, filename)
        blueprint_file.save(filepath)
        prompt += f"Blueprint File: {filename}\n"
        prompt += read_file_content(blueprint_file) + "\n\n"

    for data_type, file in additional_data.items():
        if file:
            filename = secure_filename(file.filename)
            filepath = os.path.join(upload_folder, filename)
            file.save(filepath)
            prompt += f"{data_type.capitalize()} Content:\n" # Process file content if needed
            prompt += read_file_content(file) + "\n\n"

    prompt += """
Please analyze the provided service blueprint and additional materials. Structure your response as follows:

SWOT Analysis:
- Strengths:
[List key strengths identified in the blueprint]
- Weaknesses:
[List key weaknesses identified in the blueprint]
- Opportunities:
[List key opportunities identified in the blueprint]
- Threats:
[List key threats identified in the blueprint]

Improvements:
1. [First improvement with detailed steps]
2. [Second improvement with detailed steps]
[Continue with numbered improvements as needed]

"""
    return prompt

def parse_gemini_response(response_text):
    #Improved parsing logic using regex
    swot_match = re.search(r"SWOT Analysis:\n(.*?)\nImprovements:", response_text, re.DOTALL)
    improvements_match = re.search(r"Improvements:\n(.*?)$", response_text, re.DOTALL)

    swot_analysis = swot_match.group(1).strip() if swot_match else "SWOT analysis not found."
    improvements = improvements_match.group(1).strip() if improvements_match else "Improvements not found."
    return swot_analysis, improvements

核心排查点

1. 微调模型引用格式错误

Vertex AI中微调后的模型必须使用完整资源ID引用,而非仅模型名称。修改模型初始化代码:

model = GenerativeModel(f"projects/{PROJECT_ID}/locations/{LOCATION}/models/{MODEL_NAME}")

仅传入MODEL_NAME会导致API无法识别模型资源,这是触发400错误的最常见原因。

2. 生成配置参数不兼容

部分微调后的Gemini模型对generation_config参数有特殊限制:

  • 检查max_output_tokens是否超出模型允许上限(部分微调模型限制为1024以内)
  • 确认temperature(0-1)和top_p(0-1)的取值在模型支持区间内

3. 输入Prompt格式无效

当前construct_prompt函数尝试读取二进制文件(PNG/JPG/PDF)并转成文本,会引入大量乱码,导致API判定输入无效:

  • 仅读取TXT文件内容,二进制文件仅保留文件名标识
  • 若需分析图片/PDF,需使用Gemini多模态能力,将文件作为图像/文档输入,而非文本拼接

修改read_file_content函数示例:

def read_file_content(file):
    if file.filename.lower().endswith('.txt'):
        file_content = file.read()
        file.seek(0)
        try:
            return file_content.decode('utf-8')
        except UnicodeDecodeError:
            return "[Text file encoding error]"
    else:
        return "[Non-text file - content not included in prompt]"

4. 权限与区域验证

  • 确认GOOGLE_APPLICATION_CREDENTIALS指向的服务账号密钥有效,且拥有Vertex AI User或更高权限
  • 验证LOCATION配置的美国区域(如us-central1)与模型部署区域完全一致,跨区域调用会触发无效参数错误

5. 请求内容长度超限

检查生成的Prompt总长度是否超过模型上下文窗口限制,过长内容会触发400错误。可在construct_prompt末尾添加长度校验:

if len(prompt) > 8192:  # 根据模型实际上下文窗口调整
    prompt = prompt[:8192] + "\n[Prompt truncated due to length limit]"

内容的提问来源于stack exchange,提问作者Mehrdad Atariani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 12:28:23