Spaces:
Sleeping
Sleeping
Alessandro Tomassini
deploy(hf): overlay README/Dockerfile da huggingface/, senza docs/binari/model
c42a5a1 | """Costruzione del verificatore LLM (giudice a valle). | |
| Estratta dal `ServiceRegistry` perché è una factory autonoma: dipende solo dalle | |
| `Settings` e da un hook `on_before` (fornito dal registry per liberare la VRAM | |
| prima di caricare l'LLM). Ritorna `None`, con degradazione controllata, quando | |
| l'ML è disabilitato o il modello-giudice non è disponibile. | |
| """ | |
| from __future__ import annotations | |
| from collections.abc import Callable | |
| from config.runtime.settings import Settings | |
| from core.support.logging_utils import get_logger | |
| logger = get_logger("registry") | |
| def build_verifier( | |
| settings: Settings, | |
| on_before: Callable[[], None], | |
| approver: str | None = None, | |
| simulate: bool = False, | |
| ): | |
| """Costruisce il verificatore LLM (giudice a valle) o None se indisponibile. | |
| Il modello-giudice è scelto tramite la chiave `approver` (default da | |
| Settings, fallback al predefinito del registry): un plugin in | |
| `layers/llm/llm_approver/` fornisce client (llama.cpp locale) e prompt. | |
| Richiede ENABLE_ML come il layer LLM. `on_before` è l'hook (eseguito una sola | |
| volta prima della prima chiamata al modello) che libera la VRAM dei modelli di | |
| detection prima di caricare l'LLM. | |
| `simulate=True` (debug): il verificatore costruisce i prompt per ogni span ma | |
| NON chiama l'LLM (nessun load del modello, nessuna valutazione). Serve a | |
| ispezionare in debug i prompt che verrebbero inviati. | |
| """ | |
| if not settings.enable_ml: | |
| logger.info("Verifica LLM richiesta ma ENABLE_ML=False: ignorata.") | |
| return None | |
| try: | |
| from layers.llm.backends.base import LlmGenerationParams | |
| from layers.llm.llm_approver import provider as approver_provider | |
| from layers.llm.verifier import LlmSpanVerifier | |
| key = approver or settings.approver | |
| plugin = approver_provider.resolve_approver(key) | |
| logger.info( | |
| "[giudice] modello selezionato: '%s' (%s)", | |
| plugin.spec.key, plugin.spec.repo, | |
| ) | |
| # Batch moderato: dare al modello il contesto di una lista lo fa | |
| # "ingaggiare" meglio (a entità singola tende a rispondere []), ma | |
| # piccolo per limitare troncamenti/omissioni dei modelli più deboli. | |
| verifier_batch = 8 | |
| # Token di output PROPORZIONATI al batch: ogni oggetto JSON pesa ~32 | |
| # token, quindi bastano ~32/entità + margine. Tetto basso = niente | |
| # generazioni runaway = molto più veloce (prima era 768, lentissimo). | |
| # La repetition_penalty effettiva è quella dello spec del giudice | |
| # (tarata per modello), applicata in BaseApprover.build_client. | |
| params = LlmGenerationParams( | |
| max_new_tokens=48 * verifier_batch, # ~384 per 8 entità | |
| temperature=settings.llm_temperature, | |
| timeout=settings.llm_timeout, | |
| repetition_penalty=settings.verifier_repetition_penalty, | |
| ) | |
| client = plugin.build_client(settings, params) | |
| prompt = plugin.prompt() | |
| except Exception as exc: # noqa: BLE001 - degradazione controllata | |
| logger.warning("Verificatore LLM non disponibile: %s", exc) | |
| return None | |
| # Hook eseguito UNA volta prima della prima chiamata al giudice: libera | |
| # dalla VRAM TUTTI gli altri modelli (sempre, non solo su cuda: su CPU è | |
| # un no-op innocuo che comunque libera RAM e cache engine). | |
| return LlmSpanVerifier( | |
| client, weight=settings.verifier_weight, | |
| batch_size=verifier_batch, on_before=on_before, | |
| prompt=prompt, simulate=simulate, | |
| ) | |