Harvest: de la liste de courses aux producteurs locaux
Résumé
Harvest inverse la recherche du circuit court: au lieu de parcourir des annuaires producteur par producteur, l'utilisateur donne sa liste de courses en langage naturel, sa position et un rayon. Un agent identifie les produits demandés, une requête géospatiale trouve les producteurs locaux qui les vendent, et la réponse arrive en cartes prêtes à l'action: adresse, distance, horaires, contact. Conçu, développé et opéré par Myelink.
01Le problème
Acheter en circuit court demande aujourd'hui de parcourir des annuaires: producteur par producteur, page par page, en espérant que l'un d'eux vende ce qu'on cherche. Harvest prend le problème dans l'autre sens, celui du consommateur: on part de la liste de courses ("oeufs, boeuf, blé", ou même "je veux des protéines et des glucides"), et c'est aux producteurs d'apparaître.
02L'approche
Trois entrées: la liste en langage naturel, la position du navigateur, un rayon de recherche réglable. Un agent traduit les termes libres de l'utilisateur en produits réels du catalogue, en écrivant lui-même ses requêtes SQL sur un ensemble de tables en liste blanche. La recherche des producteurs, elle, est entièrement déterministe: une requête géospatiale PostGIS filtre par distance réelle, agrège les produits couverts par marchand et classe du plus proche au plus lointain.
La réponse est rendue en cartes producteurs: adresse, distance, horaires, téléphone, site, itinéraire. Le tout dans la langue détectée de la question. La base s'enrichit par contribution: les producteurs proposés passent par une file de modération avant publication.
03L'architecture
Deux services: un front Django qui gère comptes, sessions de chat et rendu, et un service FastAPI qui héberge le graphe LangGraph. Ils communiquent en REST authentifié et partagent une base PostgreSQL/PostGIS dont le schéma appartient au front. Les conversations gardent leur mémoire entre les tours via des checkpoints Redis.
04Le choix de conception
La partie la plus lente d'un pipeline LLM est le décodage, token par token. Le formatter de Harvest ne génère donc que ce qui a besoin d'être généré: la langue détectée, un message d'accueil, et une courte description par producteur. Tout le reste, coordonnées, adresses, contacts, listes de produits, est ré-attaché en Python depuis la base, à l'octet près. Le modèle produit quelques pour cent de la réponse; le code garantit les 95 autres.
Même discipline sur les garde-fous: l'agent ne peut lire que des tables en liste blanche, les demandes hors sujet court-circuitent le graphe par des tags sentinelles filtrés de l'affichage, et le texte issu du modèle est échappé avant tout rendu, le scénario de l'injection par un contenu malveillant étant traité comme un cas nominal.
05La stack
| Couche | Choix |
|---|---|
| Front | Django, modules ES vanilla, SSE, géolocalisation navigateur |
| Agent | FastAPI + LangGraph, sorties structurées Pydantic |
| Géospatial | PostgreSQL + PostGIS: distance réelle, agrégats par marchand |
| Mémoire | checkpoints Redis, conversation persistante entre les tours |
| Inférence | modèles via passerelle OpenAI-compatible, température 0 pour le matching |
| Observabilité | Langfuse: traces et gestion versionnée des prompts |
| Qualité | une centaine de tests Python et JavaScript, CI sur chaque branche |
06État
Harvest est en production, opéré par Myelink, avec une couverture de producteurs qui s'étend région par région, alimentée par les contributions modérées.
@software{harvest,
author = {Vinceslas, Medhy},
title = {Harvest: de la liste de courses aux producteurs locaux},
note = {En production, Myelink EURL}
}