Personal project · 2025 · Designer and engineer · Independent
Stack: Python, FastAPI, Google Earth Engine, FAISS, Redis, Azure Container Apps, Next.js, MapLibre
Geospatial analysis is powerful and unfriendly. The data is public, but the path from a question — how has vegetation changed around this reservoir? — to a defensible answer runs through band selection, cloud masking, reducers, geometry and a vocabulary of indices. GeoLLM is an attempt to put a conversational interface on that work without hiding the measurement.
The user asks a question. An LLM planner decomposes it, chooses from a registry of typed geospatial tools, and assembles a response from what those tools return. Retrieval and web search provide context the model cannot infer; Earth Engine provides the numbers.
Planner, not oracle
The central design decision was to make the model a planner rather than an answer generator. It does not describe what vegetation is probably doing. It selects an analysis, calls it, and interprets the result. If no tool can answer the question, it should say so.
| Capability | Backed by |
|---|---|
| Vegetation condition | Sentinel-2 NDVI, masked composites |
| Land cover | Classification over a defined area and period |
| Surface water | Water indices and extent comparison |
| Land surface temperature | Thermal band retrieval and scaling |
| Context and definitions | Retrieved corpus, plus web search |
The API behind it
A FastAPI service routes each query to Earth Engine, retrieval or search. Retrieval is per-session RAG over FAISS with SentenceTransformer embeddings and a Redis TTL, so a follow-up question retains context without keeping every session forever. Answers stream over SSE. The service runs as a Docker container on Azure Container Apps, with a Next.js and MapLibre frontend that draws the analysed layer rather than a decorative map.
Making it usable
A correct answer that takes several minutes is not an interface. Land-cover analysis originally took hundreds of seconds; by restructuring the Earth Engine work and caching reusable products, the common path now returns in about 4.73 seconds. The map, the index legend and the underlying parameters are returned together, so the user can see what was measured rather than only what was concluded.
- Typed tool schemas with explicit units, date ranges and geometry parameters.
- A retrieval layer for method definitions and place context, kept separate from measurement tools.
- Web search for conditions the static corpus cannot cover, clearly labelled as external context.
- Cached, precomputed products for repeatable analyses; live computation only when the question requires it.
- A visible trace of the chosen tool and its inputs, so an answer can be checked.
What it taught me
Tool-calling agents fail in ordinary, unglamorous ways: ambiguous units, a date range that returns an empty collection, a geometry that crosses the antimeridian. Most of the engineering was making those failures legible and recoverable. The model is good at choosing a path; the system has to make each step honest.
The project also clarified what I want from an AI product: not a chat window over a black box, but a narrow interface that makes a difficult capability accessible while keeping its evidence in view.