TC$mC$ on erinomainen kysymys, ja olet aivan oikeilla jC$ljillC$: pidetC$C$n
kokonaisuus yksinkertaisena. YlimC$C$rC$inen LLM-analyysi vain pidentC$isi
viivettC$, kuluttaisi resursseja ja lisC$isi vikaantumispisteitC$.
Kuten koodistasi nC$kyy, Valvomo on jo nyt tietoinen siitC$, onko promptissa
kuva (`has_vision`) ja tukeeko valittu malli konenC$kC6C$ (`is_vision_model`).
Voimme ratkaista tC$mC$n rakentamalla koodiin **automaattisen
varajC$rjestelmC$n (Graceful Degradation)** suoraan `process_prompt_to_llm`
-funktioon.
Ideana on seuraava sC$C$ntC6:
*Jos promptissa on kuva, mutta yhtC$C$n konenC$kC6mallia ei ole saatavilla,
Valvomo kuorii raskaat kuvadatat automaattisesti pois, lisC$C$ promptin
loppuun "Failover"-ohjeistuksen ja yrittC$C$ reitittC$C$ kyselyn uudelleen
pelkkC$nC$ tekstinC$ tavalliselle LLM:lle.*
NC$in sinun ei tarvitse muuttaa kC$yttC6liittymC$C$ tai lisC$tC$ uusia
asetuksia, vaan Orkestraattori hoitaa homman taustalla.
### Miten tC$mC$ lisC$tC$C$n koodiin
Etsi tiedostosta `valvomo_proxy.py` funktio `process_prompt_to_llm` ja sieltC$
kohta, jossa tarkistetaan `valid_keys`. Korvaa alkuperC$inen `if not
valid_keys:` -blokki tC$llC$ laajennetulla versiolla:
```python
valid_keys = []
for k, v in llm_endpoints.items():
if not v.get("enabled", True): continue
if has_vision and not v.get("is_vision_model", True): continue
if payload_size_mb > v.get("max_payload_mb", 10.0): continue
valid_keys.append(k)
# UUSI FAILOVER-LOGIIKKA ALKAA TCSTC
if not valid_keys:
if has_vision:
print(f"[!] Ei aktiivisia Vision-malleja promptille {prompt_id}.
YritetC$C$n teksti-failoveria...")
# EtsitC$C$n tekstimalleja, joille kelpaa tavallinen teksti (koko
pienenee, kun kuva poistetaan)
fallback_keys = [k for k, v in llm_endpoints.items() if
v.get("enabled", True)]
if fallback_keys:
valid_target = fallback_keys[0] # Valitaan ensimmC$inen vapaa
testimalli
# Kuoritaan kuvaobjektit pois viesteistC$
for m in p["request"].get("messages", []):
if isinstance(m.get("content"), list):
text_parts = [c for c in m["content"] if c.get("type")
== "text"]
# LisC$tC$C$n failover-ohjeistus viimeiseen
user-viestiin
if m["role"] == "user" and text_parts:
text_parts[0]["text"] += "
[SYSTEM: FAILOVER] Kuvadatan kC$sittely ei ole juuri nyt mahdollista. YritC$
ratkaista tehtC$vC$ parhaasi mukaan pelkC$n yllC$ olevan rikastusdatan ja
semanttisen kartan avulla."
m["content"] = text_parts
print(f"[*] Kuva poistettu ja failover-ohje injektoitu.
ReititetC$C$n mallille: {valid_target}")
has_vision = False # KC$C$nnetC$C$n lippu pois
valid_keys = [valid_target]
# Jos ei onnistunut failover tai tekstimalliakaan ei ole olemassa
if not valid_keys:
state["responses"][prompt_id] = {
"id": prompt_id, "status": "pending_response_approval",
"content": f"[VIRHE]: Ei soveltuvia LLM-pC$C$tepisteitC$ edes
failoverin jC$lkeen. Reititys epC$onnistui.",
"source": "system"
}
p["status"] = "failed_routing"
save_state(state)
return
```
### Miksi tC$mC$ on tehokas ratkaisu?
1. **Ei ylimC$C$rC$istC$ API-liikennettC$:** Valvomo tekee reitityspC$C$tC6ksen
heti muistissa olevien mallien perusteella.
2. **Kevyempi Payload:** Base64-kuvan (joka voi olla satoja kilotavuja tai
jopa megatavuja) poistaminen varmistaa, ettC$ failover-kysely mahtuu lokaalin
(esim. Gemma) mallin konteksti-ikkunaan ja maksimikohtaan (`max_payload_mb`)
heittC$mC$llC$.
3. **HyC6dyntC$C$ olemassa olevan rikastuksen:** Koska sinun UI Vision
Extractorisi jo teki tyC6n ja muutti nC$ytC6n elementit tekstimuotoiseksi
ID-listaksi, lokaali tekstipohjainen Gemma todennC$kC6isesti ratkaisee
PDF-napin sijainnin suoraan `[SYSTEM: FAILOVER]` -tekstin ylC$puolelta
lC6ytyvC$stC$ ID-listasta aivan yhtC$ hyvin kuin kallis visio-malli.