Initial Release
A PyProd (InterSystems IRIS Interoperability, pure Python) production that recommends a
trip’s best departure time/fare given an arrival deadline (e.g. “I need to be there
by 14:00”) and, when that recommendation means leaving much earlier or later than a rider
would naively expect, suggests a nearby café or coworking space to wait at.
Full spec/plan/research: https://github.com/Guspex/smartdepart/blob/main/specs/001-uber-route-coffee-agent/.
This file documents the RAG architecture per the project’s deliverables requirement
(“Documentação explicativa sobre a estratégia de Chunking, escolha do Modelo de
Embeddings e arquitetura de componentes”).
production/wsgi/static/index.html — a single self-contained page (no build step, no
framework) served by the same WSGI app at GET /. Origin, destination, and “what time do
you need to arrive” go in; the page calls POST /api/uber-route/recommend and renders three
comparable departure options — leave now, leave 30 minutes early, or leave 60 minutes early —
each with its own fare, and a nearby waiting-place suggestion for the two earlier options
(research.md §20). See tasks.md’s “Post-MVP Addition” sections for what was and wasn’t
verified live.
Accessing it live: the frontend is registered as an IRIS Web Application at /uberapp
(see deploy/UberRouteSetup.cls, run once with do ##class(UberRoute.Setup).CreateWebApp()
from %SYS). Open http://<host>:<mapped-52773-port>/uberapp/ in a browser — it will prompt
for HTTP Basic Auth (any valid IRIS account, e.g. SuperUser); unauthenticated access is
enabled but currently rejected by IRIS itself for WSGI-type applications on this build before
the request reaches the app (a confirmed platform bug, not an app bug — see research.md §15).
POST /api/uber-route/recommend (WSGI, production/wsgi/app.py)
│
▼
BsUberRouteService (validates payload, adapterless — fed by the WSGI app)
│ send_request_sync
▼
BpRouteOrchestrator (candidate-time scan, 30-min Business Rule, persistence)
│ │
│ SendRequestSync │ SendRequestSync (only if rule fires)
▼ ▼
BoIntegratedMlPredictor BoHybridRagEngine
(FarePredictor via SQL) (vector + keyword search over WaitingPlace)
│ │
▼ ▼
└──────────── InterSystems IRIS (relational + JSON + Vector Store) ──────────┘
All four hosts are pure Python (intersystems-pyprod), per the project constitution’s
PyProd-First Interoperability principle — see https://github.com/Guspex/smartdepart/blob/main/.specify/memory/constitution.md.
Ingestion (ingestion/load_waiting_places.py): reads data/waiting_places_seed.json
— name, address, category, lat/lng, rating, and a free-text description per place.
Chunking: sentence/semantic chunking, 256–512 tokens (word count as a proxy) per
chunk with 50-token overlap. Every chunk keeps the place’s address and category attached
as a header, so a retrieved chunk is never missing the “where” and “what kind of place”
context. In practice, most place descriptions are short single-paragraph blurbs and fit
in one chunk — the chunker only splits when a description exceeds ~512 tokens. Rationale
and alternatives: research.md §4.
Embedding model: sentence-transformers/all-MiniLM-L6-v2, run locally via Python (no
external API call, no API key) — 384-dimension vectors, loaded with backend="onnx" rather
than the library’s default PyTorch backend, which reliably segfaulted IRIS’s embedded-Python
worker process (research.md §22). Chosen over text-embedding-3-small specifically to avoid
an external network/API-key dependency for a Community Edition demo; the embedding call is
isolated in production/hosts/bo_hybrid_rag_engine.py:_embed(), so swapping providers later is a
contained change. Full rationale: research.md §3.
Indexing: UberRoute.WaitingPlace.Embedding is VECTOR(DOUBLE, 384) with an
AS HNSW(Distance='Cosine') index (IRIS 2025.1+; falls back to an unindexed
VECTOR_COSINE scan on older 2024.1.x images — the dataset is small enough that this is
a performance-only difference). SearchableText has an %iFind.Index.Basic index for
keyword search. Both verified live against IRIS 2026.1 Community — see
research.md §5–6.
Retrieval (BO_HybridRAGEngine): hybrid search — a VECTOR_COSINE top-10 semantic
search combined with an iFind keyword search
(WHERE %ID %FIND search_index(SearchableTextIdx, ?) — not %CONTAINS(col, word),
which does not work against a DDL-created iFind index, corrected after live testing), each
candidate filtered to within ~1 km of the rider’s origin (haversine distance), then ranked
by 0.6 * vector_score + 0.4 * keyword_score.
Response/“generation”: rather than an LLM prompt/generation step, the top-ranked
candidate’s structured fields (name, address, category, rating, distance) are returned
directly, plus a short templated rationale explaining why it was chosen over the other
candidates (distance, rating, which signal — semantic or keyword — dominated the match).
This keeps the “prompt → generation” step deterministic and explainable rather than
introducing an LLM call as a fifth dependency for a feature that doesn’t need free-form
text generation.
TRAIN MODEL FarePredictor crashes (segfault in the AutoML provider) on the testedsentence-transformers’s default backend (PyTorch) reliably segfaults the IRISencode() on this platform (confirmed via caught signal 11 inmessages.log, 6/6 reproductions) — fixed by loading it with backend="onnx" insteadproduction/adapters/overpass_adapter.py) rather than a fixed seed dataset.intersystems_pyprod production.py) must be run inside IRIS’s ownpip install; seeSee quickstart.md for the full,
step-by-step validation guide. Local unit/integration/contract tests (no live IRIS
required — IRIS/pyprod calls are mocked):
pip install -r production/requirements.txt
pytest tests/