本地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
相关产品推荐
相关产品推荐

