close guardrail gaps and fix the scoring pipeline top to bottom
Constraint resolver: aggregate mass/footprint across a combo instead of pairwise-only checks, treat medium/atmosphere as agreement not supply/demand, reduce multi-provider checks by best/sum instead of AND-ing every provider, fail closed on unrecognized mutex values, add a propulsion-viability (thrust-to-weight) rule. Seed data updated to match (nuclear/solar-sail footprint floors, water-medium exclusions, explicit ground/gravity providers). Domain metric units were stored globally per metric name instead of per-domain, silently corrupting cost_efficiency for every domain but the first one seeded — fixed with a schema migration. Stub estimator's cost_efficiency/safety/availability/reliability were a backwards formula and flat constants; replaced with heuristics grounded in each entity's thrust_profile/energy_form/infrastructure. LLM estimate_physics() now receives each metric's unit and expected range instead of a bare name, fixing wildly miscalibrated estimates traced back to the prompt's own hardcoded example anchoring the model to the wrong order of magnitude. Sharpened the safety-estimation and plausibility-review prompts. Deduped provider parsing logic into llm/parsing.py. Web pipeline form can now pick an LLM provider per run instead of only via server env var. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,32 +7,40 @@ import os
|
||||
from physcom.llm.base import LLMProvider
|
||||
|
||||
|
||||
def build_llm_provider() -> LLMProvider | None:
|
||||
"""Return an LLMProvider based on env vars, or None if not configured.
|
||||
def build_llm_provider(
|
||||
provider: str | None = None,
|
||||
model: str | None = None,
|
||||
host: str | None = None,
|
||||
) -> LLMProvider | None:
|
||||
"""Return an LLMProvider, or None if not configured.
|
||||
|
||||
Explicit args (e.g. from a per-request web form) override env vars;
|
||||
passing nothing falls back to the env-var-only behavior below.
|
||||
|
||||
LLM_PROVIDER — provider name ('gemini', 'ollama'; more can be added)
|
||||
GEMINI_API_KEY — required when LLM_PROVIDER=gemini
|
||||
GEMINI_API_KEY — required when provider is 'gemini' (server env only,
|
||||
never accepted as a request param)
|
||||
GEMINI_MODEL — optional Gemini model name (default: gemini-2.0-flash)
|
||||
OLLAMA_MODEL — optional Ollama model name (default: qwen2.5:7b)
|
||||
OLLAMA_HOST — optional Ollama server URL (default: http://localhost:11434)
|
||||
"""
|
||||
provider = os.environ.get("LLM_PROVIDER", "").lower().strip()
|
||||
provider = (provider or os.environ.get("LLM_PROVIDER", "")).lower().strip()
|
||||
|
||||
if not provider:
|
||||
if not provider or provider == "stub":
|
||||
return None
|
||||
|
||||
if provider == "gemini":
|
||||
api_key = os.environ.get("GEMINI_API_KEY", "")
|
||||
if not api_key:
|
||||
raise ValueError("LLM_PROVIDER=gemini requires GEMINI_API_KEY to be set")
|
||||
model = os.environ.get("GEMINI_MODEL", "gemini-2.0-flash")
|
||||
raise ValueError("Gemini requires GEMINI_API_KEY to be set in the server environment")
|
||||
model = model or os.environ.get("GEMINI_MODEL", "gemini-2.0-flash")
|
||||
from physcom.llm.providers.gemini import GeminiLLMProvider
|
||||
return GeminiLLMProvider(api_key=api_key, model=model)
|
||||
|
||||
if provider == "ollama":
|
||||
model = os.environ.get("OLLAMA_MODEL", "qwen2.5:7b")
|
||||
host = os.environ.get("OLLAMA_HOST", "http://localhost:11434")
|
||||
model = model or os.environ.get("OLLAMA_MODEL", "qwen2.5:7b")
|
||||
host = host or os.environ.get("OLLAMA_HOST", "http://localhost:11434")
|
||||
from physcom.llm.providers.ollama import OllamaLLMProvider
|
||||
return OllamaLLMProvider(model=model, host=host)
|
||||
|
||||
raise ValueError(f"Unknown LLM_PROVIDER: {provider!r}. Supported: gemini, ollama")
|
||||
raise ValueError(f"Unknown LLM provider: {provider!r}. Supported: gemini, ollama, stub")
|
||||
|
||||
Reference in New Issue
Block a user