diff --git a/CHANGELOG.md b/CHANGELOG.md index fbdf810f..ef74d1a8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ # Changelog +## Sprint 215 Grounded assistant cross-domain reliability (2026-07-16) + +- Raised the bounded local Ollama answer budget from 700 to 1,200 tokens after + a live Mol profile exhausted the smaller limit; `done_reason=length` remains + a hard error and incomplete text is still never returned. +- Required listed themes to be covered without adding unrelated themes and + kept cross-domain answers compact without weakening source, unit, estimate, + chronology or unsupported-metric rules. +- Exposed the output limit in the Unraid DockerMan template and aligned all + Compose, runtime, example and operator documentation defaults. + ## Sprint 213-214 Cross-domain area profile (2026-07-16) - Implemented one allowlisted MercatorNet WCS registry for official Flemish diff --git a/backend/README.md b/backend/README.md index dc28c5df..9d320bcb 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1114,7 +1114,7 @@ OLLAMA_ENABLED=true OLLAMA_BASE_URL=http://host.docker.internal:11434 OLLAMA_DEFAULT_MODEL=qwen3.5:9b OLLAMA_TIMEOUT_SECONDS=120 -OLLAMA_MAX_OUTPUT_TOKENS=700 +OLLAMA_MAX_OUTPUT_TOKENS=1200 OLLAMA_CONTEXT_TOKENS=16384 ``` @@ -1125,7 +1125,9 @@ models with `GET /api/v1/assistant/models` and ask a grounded question through present in Ollama `/api/tags`. Missing water depth/bathymetry remains explicit; the assistant cannot turn 2D water geometry into volume. GeoIntel rejects an answer when Ollama reports `done_reason=length`, so a visibly truncated sentence -is never presented as a complete result. +is never presented as a complete result. The 1,200-token default leaves enough +room for a compact cross-domain profile while the system prompt requires every +explicitly requested theme and excludes unrelated themes. ## Agricultural-use parcel history diff --git a/backend/app/core/config.py b/backend/app/core/config.py index 24e258d4..b33e9a87 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -82,7 +82,7 @@ class Settings(BaseSettings): ollama_base_url: str = Field(default="http://127.0.0.1:11434", validation_alias="OLLAMA_BASE_URL") ollama_default_model: str = Field(default="qwen3.5:9b", validation_alias="OLLAMA_DEFAULT_MODEL") ollama_timeout_seconds: int = Field(default=120, ge=5, le=600, validation_alias="OLLAMA_TIMEOUT_SECONDS") - ollama_max_output_tokens: int = Field(default=700, ge=100, le=4_000, validation_alias="OLLAMA_MAX_OUTPUT_TOKENS") + ollama_max_output_tokens: int = Field(default=1_200, ge=100, le=4_000, validation_alias="OLLAMA_MAX_OUTPUT_TOKENS") ollama_context_tokens: int = Field(default=16_384, ge=4_096, le=131_072, validation_alias="OLLAMA_CONTEXT_TOKENS") cors_origins: list[str] | str = Field( default=["http://localhost:5173", "http://127.0.0.1:5173"], diff --git a/backend/app/services/geo_assistant_service.py b/backend/app/services/geo_assistant_service.py index 36a328e7..8ee45cc4 100644 --- a/backend/app/services/geo_assistant_service.py +++ b/backend/app/services/geo_assistant_service.py @@ -525,6 +525,8 @@ class GeoAssistantService: "Noem bij cijfers de bron en eenheid. Maak duidelijk onderscheid tussen exacte metingen en schattingen. " "Als is_estimate true is, noem de waarde verplicht een schatting en nooit exact. " "Objectaantallen zijn ondersteunend; geef betekenisvolle oppervlakte-, lengte- of bevolkingsmetriek voorrang. " + "Wanneer de gebruiker meerdere thema's opsomt, behandel elk gevraagd thema en voeg geen ongevraagd thema toe. " + "Houd het antwoord beknopt: groepeer de kernmetrieken per gevraagd thema en herhaal geen beperkingen. " "Beschrijf alleen waargenomen verschillen; verzin geen oorzaak, voorspelling, verzadiging of andere verklaring. " "Neem waarden en jaren letterlijk over en bereken zelf geen gemiddelde, tempo, oorzaak of afgeleide trend. " "Gebruik platte tekst met korte alinea's en opsommingen, zonder Markdown-symbolen. " diff --git a/backend/tests/test_sprint202_temporal_metrics_and_ollama.py b/backend/tests/test_sprint202_temporal_metrics_and_ollama.py index 525597fa..ff0bd41f 100644 --- a/backend/tests/test_sprint202_temporal_metrics_and_ollama.py +++ b/backend/tests/test_sprint202_temporal_metrics_and_ollama.py @@ -202,12 +202,15 @@ def test_geo_assistant_sends_grounded_context_without_thinking_trace(monkeypatch assert captured["payload"]["think"] is False assert captured["payload"]["options"]["temperature"] == 0.0 assert captured["payload"]["options"]["num_ctx"] == 16_384 + assert captured["payload"]["options"]["num_predict"] == 1_200 assert "Gebruik uitsluitend feiten en cijfers uit CONTEXT_JSON" in captured["payload"]["messages"][0]["content"] assert "scope.label is het exact geanalyseerde gebied" in captured["payload"]["messages"][0]["content"] assert "noem de waarde verplicht een schatting" in captured["payload"]["messages"][0]["content"] assert "verzin geen oorzaak, voorspelling, verzadiging" in captured["payload"]["messages"][0]["content"] assert "bereken zelf geen gemiddelde, tempo, oorzaak of afgeleide trend" in captured["payload"]["messages"][0]["content"] assert "zonder Markdown-symbolen" in captured["payload"]["messages"][0]["content"] + assert "behandel elk gevraagd thema en voeg geen ongevraagd thema toe" in captured["payload"]["messages"][0]["content"] + assert "Houd het antwoord beknopt" in captured["payload"]["messages"][0]["content"] assert "water_volume_available" in captured["payload"]["messages"][0]["content"] @@ -254,6 +257,9 @@ def test_unraid_ollama_context_window_is_configurable() -> None: assert "OLLAMA_CONTEXT_TOKENS: ${OLLAMA_CONTEXT_TOKENS:-16384}" in compose assert 'Target="OLLAMA_CONTEXT_TOKENS"' in template assert "OLLAMA_CONTEXT_TOKENS=16384" in env_example + assert "OLLAMA_MAX_OUTPUT_TOKENS: ${OLLAMA_MAX_OUTPUT_TOKENS:-1200}" in compose + assert 'Target="OLLAMA_MAX_OUTPUT_TOKENS"' in template + assert "OLLAMA_MAX_OUTPUT_TOKENS=1200" in env_example def test_temporal_comparison_preserves_all_compatible_semantic_metrics() -> None: diff --git a/deploy/unraid/README.md b/deploy/unraid/README.md index c442ddfe..574a9fde 100644 --- a/deploy/unraid/README.md +++ b/deploy/unraid/README.md @@ -200,7 +200,7 @@ OLLAMA_ENABLED=true OLLAMA_BASE_URL=http://host.docker.internal:11434 OLLAMA_DEFAULT_MODEL=qwen3.5:9b OLLAMA_TIMEOUT_SECONDS=120 -OLLAMA_MAX_OUTPUT_TOKENS=700 +OLLAMA_MAX_OUTPUT_TOKENS=1200 OLLAMA_CONTEXT_TOKENS=16384 ``` diff --git a/deploy/unraid/geointel-unraid-template.xml b/deploy/unraid/geointel-unraid-template.xml index 62168241..8600f1b5 100644 --- a/deploy/unraid/geointel-unraid-template.xml +++ b/deploy/unraid/geointel-unraid-template.xml @@ -51,5 +51,6 @@ http://host.docker.internal:11434 qwen3.5:9b 120 + 1200 16384 diff --git a/deploy/unraid/geointel.env.example b/deploy/unraid/geointel.env.example index 3a01072f..226a9192 100644 --- a/deploy/unraid/geointel.env.example +++ b/deploy/unraid/geointel.env.example @@ -71,5 +71,5 @@ OLLAMA_ENABLED=true OLLAMA_BASE_URL=http://host.docker.internal:11434 OLLAMA_DEFAULT_MODEL=qwen3.5:9b OLLAMA_TIMEOUT_SECONDS=120 -OLLAMA_MAX_OUTPUT_TOKENS=700 +OLLAMA_MAX_OUTPUT_TOKENS=1200 OLLAMA_CONTEXT_TOKENS=16384 diff --git a/deploy/unraid/run-dockerman-container.sh b/deploy/unraid/run-dockerman-container.sh index f70695b8..9e61ec1c 100644 --- a/deploy/unraid/run-dockerman-container.sh +++ b/deploy/unraid/run-dockerman-container.sh @@ -67,7 +67,7 @@ OLLAMA_ENABLED="${OLLAMA_ENABLED:-true}" OLLAMA_BASE_URL="${OLLAMA_BASE_URL:-http://host.docker.internal:11434}" OLLAMA_DEFAULT_MODEL="${OLLAMA_DEFAULT_MODEL:-qwen3.5:9b}" OLLAMA_TIMEOUT_SECONDS="${OLLAMA_TIMEOUT_SECONDS:-120}" -OLLAMA_MAX_OUTPUT_TOKENS="${OLLAMA_MAX_OUTPUT_TOKENS:-700}" +OLLAMA_MAX_OUTPUT_TOKENS="${OLLAMA_MAX_OUTPUT_TOKENS:-1200}" OLLAMA_CONTEXT_TOKENS="${OLLAMA_CONTEXT_TOKENS:-16384}" install_dockerman_metadata() { diff --git a/docker-compose.unraid.yml b/docker-compose.unraid.yml index 342eff25..ac820c14 100644 --- a/docker-compose.unraid.yml +++ b/docker-compose.unraid.yml @@ -65,7 +65,7 @@ services: OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://host.docker.internal:11434} OLLAMA_DEFAULT_MODEL: ${OLLAMA_DEFAULT_MODEL:-qwen3.5:9b} OLLAMA_TIMEOUT_SECONDS: ${OLLAMA_TIMEOUT_SECONDS:-120} - OLLAMA_MAX_OUTPUT_TOKENS: ${OLLAMA_MAX_OUTPUT_TOKENS:-700} + OLLAMA_MAX_OUTPUT_TOKENS: ${OLLAMA_MAX_OUTPUT_TOKENS:-1200} OLLAMA_CONTEXT_TOKENS: ${OLLAMA_CONTEXT_TOKENS:-16384} ports: - "${GEOINTEL_FRONTEND_PORT:-1202}:80" diff --git a/docker-compose.yml b/docker-compose.yml index 64879ad8..f4eb2071 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -70,7 +70,7 @@ services: OLLAMA_BASE_URL: ${OLLAMA_BASE_URL:-http://host.docker.internal:11434} OLLAMA_DEFAULT_MODEL: ${OLLAMA_DEFAULT_MODEL:-qwen3.5:9b} OLLAMA_TIMEOUT_SECONDS: ${OLLAMA_TIMEOUT_SECONDS:-120} - OLLAMA_MAX_OUTPUT_TOKENS: ${OLLAMA_MAX_OUTPUT_TOKENS:-700} + OLLAMA_MAX_OUTPUT_TOKENS: ${OLLAMA_MAX_OUTPUT_TOKENS:-1200} OLLAMA_CONTEXT_TOKENS: ${OLLAMA_CONTEXT_TOKENS:-16384} ports: - "${GEOINTEL_BACKEND_PORT:-8000}:8000" diff --git a/docs/CODEX_EXECUTION_LOG.md b/docs/CODEX_EXECUTION_LOG.md index 73ae4997..bcef9dad 100644 --- a/docs/CODEX_EXECUTION_LOG.md +++ b/docs/CODEX_EXECUTION_LOG.md @@ -1,3 +1,29 @@ +## Sprint 215 Grounded assistant cross-domain reliability (2026-07-16) + +Changed: +- Measured the exact live Mol assistant context at 12 current themes, 36 + semantic metrics, six temporal series and 17,302 compact JSON characters. +- Increased the bounded output allowance to 1,200 tokens and instructed the + local model to cover every explicitly listed theme, omit unrelated themes + and avoid repeated limitations. +- Kept `think=false`, deterministic temperature, the 16,384-token context and + fail-closed rejection of `done_reason=length` unchanged. +- Added the output limit to the editable Unraid template and aligned all + deployment defaults and documentation. + +Validation evidence: +- A read-only live production-chain probe with the 1,200-token setting + completed without truncation against the full persisted Mol context. +- The focused assistant suite passed 14 tests. +- The complete readiness gate passed 713 backend tests, backend compilation, + 105 documented API routes with three explicit binary/non-envelope routes, + one Alembic head and the frontend TypeScript and production build. +- Tower deployment and browser verification follow in this pass. + +Next: +- Deploy, rerun the exact six-theme Dutch question and verify the end-user + response and responsive assistant UI in the browser. + ## Sprint 213-214 Cross-domain thematic rasters and DOV soil map (2026-07-16) Changed: