Fix: Gemini API modernization, dynamic model selection, and config path corrections
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
# Migration Guide: Google AI Builder Apps -> Local Docker Stack
|
||||
|
||||
> **WICHTIGER HINWEIS:** Der Gemini-Agent führt Code **innerhalb** dieses Docker-Containers aus. Er hat keinen Zugriff auf den Docker-Daemon des Host-Systems. Daher kann und wird der Agent **NIEMALS** in der Lage sein, Befehle wie `docker build`, `docker-compose up` oder andere Docker-Management-Aufgaben auszuführen. Diese Befehle müssen immer vom Benutzer auf dem Host-System ausgeführt werden.
|
||||
|
||||
**Ziel:** Standardisierter Prozess, um eine von Google AI Studio generierte React-App schnell, robust und fehlerfrei in die lokale Docker/Python-Architektur zu integrieren.
|
||||
|
||||
**Grundsatz:** "Minimalset & Robustheit". Wir bauen keine aufgeblähten Container, und wir verhindern Timeouts und fehlende Abhängigkeiten proaktiv.
|
||||
@@ -93,6 +95,17 @@ Multi-Line Prompts können in Docker-Umgebungen zu **sehr hartnäckigen Syntaxfe
|
||||
* **Signaturen prüfen:** Shared Libraries (`helpers.py`) haben oft ältere Signaturen. Immer die tatsächliche Definition prüfen!
|
||||
* Beispiel: `call_openai_chat` unterstützt oft kein `system_message` Argument. Stattdessen Prompt manuell zusammenbauen (`sys_instr + "\n\n" + prompt`).
|
||||
|
||||
### 1.6 Pitfall: Veraltete API-Nutzung & Bibliotheksnamen
|
||||
**ACHTUNG:** Dies ist eine der häufigsten Fehlerquellen bei der Migration älterer KI-Skripte.
|
||||
|
||||
* **Das Problem 1 (Name):** Der Name des Pakets (`google-generativeai`) stimmt nicht mit dem Import (`import google.genai`) überein, den neuere Versionen erwarten. In unserem Fall bleiben wir vorerst beim Import von `google.generativeai`.
|
||||
* **Installation (`requirements.txt`):** `google-generativeai`
|
||||
* **Import (z.B. in `helpers.py`):** `import google.generativeai as genai`
|
||||
|
||||
* **Das Problem 2 (API-Nutzung):** Älterer Code verwendet eine `genai.Client`-Klasse, die **nicht mehr existiert**. Dies führt zu einem Absturz.
|
||||
* **Fehlerbild im Log:** `AttributeError: module 'google.generativeai' has no attribute 'Client'`
|
||||
* **Lösung:** Der Code MUSS auf die moderne `GenerativeModel`-API umgestellt werden. Siehe **Appendix A.4** für ein Code-Beispiel.
|
||||
|
||||
---
|
||||
|
||||
## 2. Die Backend-Bridge (`server.cjs`)
|
||||
@@ -277,5 +290,104 @@ Achtung beim Routing. Wenn die App unter `/app/` laufen soll, muss der Trailing
|
||||
### A.2 Neuer Standard für KI-Apps
|
||||
Für zukünftige Apps gilt:
|
||||
1. **Prompts in JSON/Text-Files:** Niemals riesige Strings im Python-Code hardcoden.
|
||||
2. **`helpers.call_gemini_flash` nutzen:** Diese Funktion ist nun der Gold-Standard für einfache, stateless Calls.
|
||||
2. **`helpers.call_gemini_flash` nutzen:** Diese Funktion ist nun der Gold-Standard für einfache, stateless Calls. Siehe **Appendix A.4** für die korrekte Implementierung.
|
||||
3. **JSON im Dockerfile:** Vergesst nicht, die externen Prompt-Files mit `COPY` in den Container zu holen!
|
||||
|
||||
### A.3 Kritisches Problem & Lösung: `AttributeError` bei Gemini API (Jan 2026)
|
||||
- **Problem:** Nach der Migration auf die `google-generativeai` Bibliothek schlugen alle API-Aufrufe mit einem `AttributeError: module 'google.generativeai' has no attribute 'Client'` Fehler fehl.
|
||||
- **Log-Analyse:**
|
||||
```
|
||||
ERROR:helpers:Fehler beim Gemini-Flash-Aufruf: module 'google.generativeai' has no attribute 'Client'
|
||||
```
|
||||
- **Untersuchung:**
|
||||
1. Die erste Annahme, es handle sich um einen falschen Modellnamen (`404 NOT_FOUND`), erwies sich als irreführend.
|
||||
2. Die Analyse des `helpers.py`-Skripts zeigte, dass der Code versuchte, eine `genai.Client`-Klasse zu verwenden.
|
||||
- **Schlussfolgerung & Lösung:**
|
||||
Der Fehler lag in der Verwendung einer **veralteten API-Initialisierungsmethode**. Die `google-generativeai`-Bibliothek hat die `Client`-Klasse entfernt und erfordert nun einen modernen Ansatz.
|
||||
|
||||
**Die Korrektur (implementiert in `helpers.py`):**
|
||||
1. **Konfigurieren des API-Schlüssels:** `genai.configure(api_key="IHR_KEY")`
|
||||
2. **Instanziieren des Modells:** `model = genai.GenerativeModel('gemini-1.5-flash-latest')`
|
||||
3. **Aufrufen der Generierung:** `response = model.generate_content(...)`
|
||||
|
||||
Dieser Fix wurde in `helpers.py` umgesetzt und hat die Funktionalität des GTM Architect wiederhergestellt. Alle neuen KI-Anwendungen müssen diesem Muster folgen.
|
||||
|
||||
### A.4 Gold-Standard: Gemini API Wrapper (Robust & Dynamic)
|
||||
Um 404-Fehler durch sich ändernde Modellnamen oder regionale Unterschiede zu vermeiden, nutzt der neue Standard eine **dynamische Modell-Ermittlung**.
|
||||
|
||||
```python
|
||||
import google.generativeai as genai
|
||||
import logging
|
||||
|
||||
# Cache für den Modellnamen
|
||||
_CACHED_MODEL_NAME = None
|
||||
|
||||
def _get_best_flash_model(api_key):
|
||||
"""
|
||||
Ermittelt dynamisch das beste verfügbare Flash-Modell via list_models().
|
||||
"""
|
||||
global _CACHED_MODEL_NAME
|
||||
if _CACHED_MODEL_NAME:
|
||||
return _CACHED_MODEL_NAME
|
||||
|
||||
default_model = "gemini-1.5-flash"
|
||||
try:
|
||||
genai.configure(api_key=api_key)
|
||||
# Suche nach Modellen mit 'flash' und 'generateContent' Support
|
||||
models = list(genai.list_models())
|
||||
flash_models = [
|
||||
m.name.replace('models/', '')
|
||||
for m in models
|
||||
if 'flash' in m.name.lower() and 'generateContent' in m.supported_generation_methods
|
||||
]
|
||||
|
||||
# Priorisierung
|
||||
if "gemini-1.5-flash" in flash_models:
|
||||
_CACHED_MODEL_NAME = "gemini-1.5-flash"
|
||||
elif flash_models:
|
||||
_CACHED_MODEL_NAME = flash_models[0]
|
||||
else:
|
||||
_CACHED_MODEL_NAME = default_model
|
||||
|
||||
return _CACHED_MODEL_NAME
|
||||
except Exception:
|
||||
return default_model
|
||||
|
||||
@retry_on_failure
|
||||
def call_gemini_flash(prompt, system_instruction=None, temperature=0.3, json_mode=False):
|
||||
"""
|
||||
Robuster Wrapper mit dynamischer Modellwahl.
|
||||
"""
|
||||
logger = logging.getLogger(__name__)
|
||||
api_key = _get_gemini_api_key()
|
||||
|
||||
try:
|
||||
genai.configure(api_key=api_key)
|
||||
|
||||
generation_config = {
|
||||
"temperature": temperature,
|
||||
"top_p": 0.95,
|
||||
"top_k": 40,
|
||||
"max_output_tokens": 8192,
|
||||
}
|
||||
if json_mode:
|
||||
generation_config["response_mime_type"] = "application/json"
|
||||
|
||||
# Dynamisch das richtige Modell wählen
|
||||
model_name = _get_best_flash_model(api_key)
|
||||
|
||||
model = genai.GenerativeModel(
|
||||
model_name=model_name,
|
||||
generation_config=generation_config,
|
||||
system_instruction=system_instruction
|
||||
)
|
||||
|
||||
contents = [prompt] if isinstance(prompt, str) else prompt
|
||||
response = model.generate_content(contents)
|
||||
|
||||
return response.text.strip()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Fehler beim Gemini-Flash-Aufruf: {e}")
|
||||
raise e
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user