fix(models): gemini-2.5-flash (light) + gemini-2.5-pro (heavy), LOCATION=global for modellkall
This commit is contained in:
parent
f711f7be74
commit
7585a485e0
|
|
@ -1,16 +1,17 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
agent.py — Cloud Run entrypoint for OSVauco OPAX agent.
|
agent.py — OSVauco OPAX agent.
|
||||||
|
|
||||||
Modes:
|
Modes:
|
||||||
light (standard) — gemini-2.0-flash-001, $1/task hard stop
|
light — gemini-2.5-flash, $1/task
|
||||||
heavy (audit+) — gemini-2.5-pro-001, $3/task hard stop
|
heavy — gemini-2.5-pro, $3/task
|
||||||
|
|
||||||
Legacy values 'A' and 'A+' are accepted and normalized.
|
Legacy 'A' / 'A+' normaliseres automatisk.
|
||||||
Authorized users for heavy: opax, admin
|
Authoriserte brukere for heavy: opax, admin
|
||||||
|
|
||||||
Requires: google-adk >= 1.0.0,<2.0.0
|
Gjeldende modell-tilgjengelighet (mai 2026):
|
||||||
google-cloud-aiplatform >= 1.112.0
|
gemini-2.0-flash-001 kun for eksisterende kunder — bruk IKKE.
|
||||||
|
gemini-2.5-flash / gemini-2.5-pro krever GOOGLE_CLOUD_LOCATION=global.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
|
@ -26,18 +27,18 @@ from google.genai import types
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
PROJECT_ID = os.environ.get("GOOGLE_CLOUD_PROJECT", "propane-will-491900-m5")
|
PROJECT_ID = os.environ.get("GOOGLE_CLOUD_PROJECT", "propane-will-491900-m5")
|
||||||
LOCATION = os.environ.get("GOOGLE_CLOUD_LOCATION", "us-central1")
|
LOCATION = os.environ.get("GOOGLE_CLOUD_LOCATION", "global")
|
||||||
RAG_CORPUS = os.environ.get("RAG_CORPUS", "")
|
RAG_CORPUS = os.environ.get("RAG_CORPUS", "")
|
||||||
|
|
||||||
# Light mode — pinned to stable versioned alias
|
# Light mode — gemini-2.5-flash (GA, global)
|
||||||
ORCHESTRATOR_MODEL = os.environ.get("ORCHESTRATOR_MODEL", "gemini-2.0-flash-001")
|
ORCHESTRATOR_MODEL = os.environ.get("ORCHESTRATOR_MODEL", "gemini-2.5-flash")
|
||||||
SUBAGENT_MODEL = os.environ.get("SUBAGENT_MODEL", "gemini-2.0-flash-001")
|
SUBAGENT_MODEL = os.environ.get("SUBAGENT_MODEL", "gemini-2.5-flash")
|
||||||
REASONING_MODEL = os.environ.get("REASONING_MODEL", "gemini-2.0-flash-001")
|
REASONING_MODEL = os.environ.get("REASONING_MODEL", "gemini-2.5-flash")
|
||||||
|
|
||||||
# Heavy mode
|
# Heavy mode — gemini-2.5-pro (GA, global)
|
||||||
HEAVY_ORCHESTRATOR = os.environ.get("HEAVY_ORCHESTRATOR_MODEL", "gemini-2.5-pro-001")
|
HEAVY_ORCHESTRATOR = os.environ.get("HEAVY_ORCHESTRATOR_MODEL", "gemini-2.5-pro")
|
||||||
HEAVY_SUBAGENT = os.environ.get("HEAVY_SUBAGENT_MODEL", "gemini-2.5-pro-001")
|
HEAVY_SUBAGENT = os.environ.get("HEAVY_SUBAGENT_MODEL", "gemini-2.5-pro")
|
||||||
HEAVY_REASONING = os.environ.get("HEAVY_REASONING_MODEL", "gemini-2.5-flash-001")
|
HEAVY_REASONING = os.environ.get("HEAVY_REASONING_MODEL", "gemini-2.5-flash")
|
||||||
|
|
||||||
BUDGET_LIGHT = float(os.environ.get("BUDGET_A_USD_PER_TASK", "1.0"))
|
BUDGET_LIGHT = float(os.environ.get("BUDGET_A_USD_PER_TASK", "1.0"))
|
||||||
BUDGET_HEAVY = float(os.environ.get("HEAVY_MODE_BUDGET_USD_PER_DAY", "3.0"))
|
BUDGET_HEAVY = float(os.environ.get("HEAVY_MODE_BUDGET_USD_PER_DAY", "3.0"))
|
||||||
|
|
@ -59,8 +60,7 @@ def _normalize_mode(mode: str) -> str:
|
||||||
|
|
||||||
|
|
||||||
def authorize_mode(user_id: str, mode: str) -> None:
|
def authorize_mode(user_id: str, mode: str) -> None:
|
||||||
"""Normalize mode first, then check authorization. Raises ValueError or PermissionError."""
|
mode = _normalize_mode(mode)
|
||||||
mode = _normalize_mode(mode) # raises ValueError for unknown modes
|
|
||||||
if mode == "heavy" and user_id not in HEAVY_MODE_ALLOWED_USERS:
|
if mode == "heavy" and user_id not in HEAVY_MODE_ALLOWED_USERS:
|
||||||
raise PermissionError(
|
raise PermissionError(
|
||||||
f"User '{user_id}' is not authorized for heavy mode. "
|
f"User '{user_id}' is not authorized for heavy mode. "
|
||||||
|
|
@ -80,11 +80,11 @@ if RAG_CORPUS:
|
||||||
similarity_top_k=10,
|
similarity_top_k=10,
|
||||||
vector_distance_threshold=0.6,
|
vector_distance_threshold=0.6,
|
||||||
)
|
)
|
||||||
logger.info(f"RAG tool initialised with corpus: {RAG_CORPUS}")
|
logger.info(f"RAG tool initialised: {RAG_CORPUS}")
|
||||||
except ImportError as e:
|
except ImportError as e:
|
||||||
logger.warning(f"VertexAiRagRetrieval not available — running without RAG: {e}")
|
logger.warning(f"VertexAiRagRetrieval ikke tilgjengelig: {e}")
|
||||||
else:
|
else:
|
||||||
logger.warning("RAG_CORPUS env var not set — running without RAG retrieval")
|
logger.warning("RAG_CORPUS ikke satt — kjører uten RAG")
|
||||||
|
|
||||||
|
|
||||||
def get_models_for_mode(mode: Mode) -> dict:
|
def get_models_for_mode(mode: Mode) -> dict:
|
||||||
|
|
@ -108,18 +108,16 @@ def get_models_for_mode(mode: Mode) -> dict:
|
||||||
def build_agent(mode: str = "light") -> Agent:
|
def build_agent(mode: str = "light") -> Agent:
|
||||||
mode = _normalize_mode(mode)
|
mode = _normalize_mode(mode)
|
||||||
models = get_models_for_mode(mode)
|
models = get_models_for_mode(mode)
|
||||||
mode_label = "heavy" if mode == "heavy" else "light"
|
|
||||||
instruction = (
|
instruction = (
|
||||||
f"Du er OPAX — OSVauco AI-agent. "
|
f"Du er OPAX — OSVauco AI-agent. Modus: {mode}. "
|
||||||
f"Modus: {mode_label}. Budsjettgrense per oppgave: ${models['budget_usd']}. "
|
f"Budsjettgrense per oppgave: ${models['budget_usd']}. "
|
||||||
"Bruk retrieve_knowledge-verktøyet for å hente dokumentasjon og kontekst. "
|
"Bruk retrieve_knowledge for å hente dokumentasjon. "
|
||||||
"Foretrekk alltid dokumenterte svar fremfor spekulasjon. "
|
"Svar på norsk (bokmål) med mindre annet er bedt om."
|
||||||
"Svar alltid på norsk (bokmål) med mindre brukeren eksplisitt ber om et annet språk."
|
|
||||||
)
|
)
|
||||||
return Agent(
|
return Agent(
|
||||||
model=models["orchestrator"],
|
model=models["orchestrator"],
|
||||||
name="opax_agent",
|
name="opax_agent",
|
||||||
description=f"OPAX — OSVauco enterprise agent [{mode_label}]",
|
description=f"OPAX — OSVauco enterprise agent [{mode}]",
|
||||||
instruction=instruction,
|
instruction=instruction,
|
||||||
tools=[rag_tool] if rag_tool else [],
|
tools=[rag_tool] if rag_tool else [],
|
||||||
)
|
)
|
||||||
|
|
@ -162,9 +160,8 @@ def run(
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import sys
|
import sys
|
||||||
logging.basicConfig(level=logging.WARNING)
|
logging.basicConfig(level=logging.WARNING)
|
||||||
query = sys.argv[1] if len(sys.argv) > 1 else "Hva er OPAX heavy mode?"
|
query = sys.argv[1] if len(sys.argv) > 1 else "Hva er OPAX?"
|
||||||
requested_mode = sys.argv[2] if len(sys.argv) > 2 else "light"
|
mode = sys.argv[2] if len(sys.argv) > 2 else "light"
|
||||||
print(f"Mode : {requested_mode}")
|
print(f"Mode: {mode} | Query: {query}")
|
||||||
print(f"Query: {query}")
|
|
||||||
print("-" * 60)
|
print("-" * 60)
|
||||||
print(run(message=query, user_id="opax", mode=requested_mode))
|
print(run(message=query, user_id="opax", mode=mode))
|
||||||
|
|
|
||||||
11
main.py
11
main.py
|
|
@ -1,8 +1,8 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
main.py — Cloud Run entrypoint for OSVauco OPAX agent.
|
main.py — Cloud Run entrypoint, OSVauco OPAX.
|
||||||
Modes: light (default, gemini-2.0-flash-001) | heavy (gemini-2.5-pro-001)
|
Modes: light (gemini-2.5-flash) | heavy (gemini-2.5-pro)
|
||||||
ML-1: telemetri, state store, DAG-endepunkter.
|
ML-1: telemetri, state store, DAG.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
@ -31,7 +31,7 @@ class RunRequest(BaseModel):
|
||||||
|
|
||||||
|
|
||||||
class DagRequest(BaseModel):
|
class DagRequest(BaseModel):
|
||||||
messages: List[str] = Field(..., description="Liste av meldinger som kjøres parallelt")
|
messages: List[str] = Field(...)
|
||||||
user_id: str = "opax"
|
user_id: str = "opax"
|
||||||
session_id: str = "default"
|
session_id: str = "default"
|
||||||
mode: str = "light"
|
mode: str = "light"
|
||||||
|
|
@ -45,7 +45,6 @@ def health():
|
||||||
|
|
||||||
@app.post("/run")
|
@app.post("/run")
|
||||||
def run_agent(req: RunRequest):
|
def run_agent(req: RunRequest):
|
||||||
# Validate mode and authorization before any work — returns 400/403 on bad input
|
|
||||||
try:
|
try:
|
||||||
authorize_mode(req.user_id, req.mode)
|
authorize_mode(req.user_id, req.mode)
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
|
|
@ -71,7 +70,7 @@ def run_agent(req: RunRequest):
|
||||||
finally:
|
finally:
|
||||||
duration = round(time.monotonic() - start, 3)
|
duration = round(time.monotonic() - start, 3)
|
||||||
success = error_msg is None
|
success = error_msg is None
|
||||||
model = "gemini-2.0-flash-001" if req.mode in ("light", "A") else "gemini-2.5-pro-001"
|
model = "gemini-2.5-flash" if req.mode in ("light", "A") else "gemini-2.5-pro"
|
||||||
log_agent_call(
|
log_agent_call(
|
||||||
agent_id=AGENT_ID,
|
agent_id=AGENT_ID,
|
||||||
input_payload={"message": req.message, "mode": req.mode},
|
input_payload={"message": req.message, "mode": req.mode},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user