2016judea/vertical-market-agent

Construisez un agent conversationnel qui maîtrise un seul secteur et une seule métropole, en s’appuyant sur un résumé précalculé de données publiques réelles (ou d’un corpus d’avis miné) et en pouvant interroger des enregistrements en direct pendant la conversation — trouver le fossé, construire un substrat stable en octets, énumérer ce que les enregistrements ne peuvent pas fournir, les pièges de données qui produisent des chiffres erronés plausibles, les mathématiques déterministes dans les outils, le coût mesuré des invites et la durée de vie du cache TTL, le déploiement en tant que destination publicitaire, une conclusion hors secteur et une couche spatiale précalculée « qu’est-ce qui est à côté ». À utiliser lors de la construction d’un agent IA vertical ancré dans des enregistrements plutôt que dans des connaissances générales.

Qu'est-ce que vertical-market-agent ?

Ce guide détaille la construction d'un agent chat IA vertical, conçu pour exceller dans un secteur et une métropole spécifiques grâce à un substrat de données précalculé et la capacité d'interroger des enregistrements en direct. Il est particulièrement utile pour les développeurs d'agents IA qui souhaitent dépasser les limites des modèles généralistes en s'ancrant dans des données publiques réelles, comme les avis minés ou les registres fonciers et fiscaux. La méthode comprend neuf étapes, allant de la sélection de la métropole et du « fossé » concurrentiel, à la construction d'un substrat JSON stable en octets, en passant par la gestion des pièges de données (où les bugs produisent des chiffres plausibles mais faux), l'implémentation de mathématiques déterministes via des outils, et la mesure des coûts d'invite. Le déploiement inclut des options avancées comme les destinations publicitaires avec des URL éphémères, une couche spatiale précalculée, et un mécanisme de « sortie hors secteur » pour recueillir des retours des visiteurs. Le guide insiste sur des règles strictes pour l'invite : ne jamais inventer de nombre, ne pas présenter une valeur de registre public comme une valeur de marché, et toujours vérifier les données avec des tests de validation. Il est compatible avec les plateformes d'agents utilisant des outils et des flux de conversation, et s'applique particulièrement aux secteurs comme l'immobilier, les services locaux, ou la restauration.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/2016judea/brick-mortar-skills/tree/HEAD/skills/vertical-market-agent

Installed? Explore more Recherche et analyse de données skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Construction d'un agent de marché vertical

Un agent conversationnel qui bat un modèle général dans un secteur et une métropole, car il transporte un résumé précalculé de données réelles et peut interroger des enregistrements en direct pendant qu'il parle. Terminé = en ligne sur une URL, répondant avec des chiffres qui remontent au substrat, refusant d'inventer ceux qu'il n'a pas, et vérifié en production avec des sondes réelles (pas un test local).

Étape 0 : deux questions auxquelles le propriétaire répond

  1. Quelle métropole, et pourquoi celle-ci ? Choisissez là où vous avez déjà du travail de terrain ou des données littéralement vraies. Minez une métropole, puis faites de la publicité là-bas.
  2. Sera-t-il annoncé, et est-il lié ? Quatre décisions d'ingénierie en dépendent (pixel, durée de vie du cache, URL personnalisées, attribution). Voir l'étape 7.

Étape 1 : trouver le fossé avant d'écrire du code

Deux sortes : un corpus que vous avez miné et possédez (par exemple, des dizaines de milliers d'avis), ou une jointure (un flux d'annonces en direct contre les registres fonciers, d'évaluation et fiscaux d'un comté : deux sources gratuites que personne ne prend la peine de combiner). L'énumération groupée payante échoue souvent (crédits épuisés, recherche de propriétaire absente).

Lorsque l'énumération groupée est verrouillée, le point d'entrée est la contrainte, pas les données. Une application de comté qui répond pour n'importe quelle adresse mais n'en liste aucune est acceptable une fois que vous énumérez les adresses ailleurs (étape 3).

Les États sans divulgation sont une opportunité : personne n'a de comparables de vente, y compris les concurrents, donc l'arithmétique du comté elle-même, bien organisée, devient le meilleur ancrage.

Étape 2 : construire le substrat

Un résumé JSON figé injecté côté serveur dans l'invite système à chaque message.

  • Vérifiez d'abord la taille du panel sur un agent basé sur un corpus d'avis. « Où vous vous classez parmi les endroits comme le vôtre » nécessite ~50+ entreprises avec 50+ avis chacune. En dessous, ne déployez pas de classement.
  • Un profil sectoriel écrit par un modèle n'est pas un substrat. Charger de la prose écrite par un modèle lui dit ce qu'il sait déjà et ne crée aucun fossé. Le substrat est mesuré.
  • Les données manquantes sont un retard, pas un obstacle : si vous possédez les moyens de miner un panel, minez-le.
  • Vérifiez la licence avant de miner. Les données de certaines sources ne peuvent pas être redistribuées, ce qui détermine si un panel miné peut jamais être un téléchargement.
  • Chaque bloc porte une _interprétation : 2 à 4 phrases sur ce qu'il signifie et comment un professionnel l'utilise. La valeur la plus élevée par octet ; c'est la différence entre réciter et raisonner.
  • Sortie stable en octets : sort_keys=True, tris totaux avec égalités départagées sur un champ unique, pas d'horodatage sauf generated_on. Un seul octet variable refacture le préfixe mis en cache à chaque message.
  • Superposez, et laissez les meilleures couches remplacer les plus anciennes ; deux blocs donnant des nombres différents pour une même question obligent le modèle à arbitrer en pleine réponse. Remplacez au niveau de la sous-clé lorsqu'un bloc est mixte.
  • Archivez complet, expédiez compact (doubles .compact.json), en revenant à l'archive si un double manque.
  • Supprimez les e-mails personnels des recherches fusionnées : à l'échelle publicitaire, le modèle transforme la boîte de réception d'un fonctionnaire en votre canal sortant. Département + téléphone dit la même chose.

Étape 3 : énumérer ce que les enregistrements ne peuvent pas

Un flux de listes mince ne voit presque rien. Cherchez les lieux « à proximité » sur une grille de petits cercles, puis joignez chaque résultat aux registres du comté (une exécution : 307 complexes -> 208 parcelles correspondantes -> 9 736 unités).

  • Petits cercles (~3,5 km sur une grille ~3,9 km) : l'API plafonne les résultats par appel, donc une requête à l'échelle de la métropole ne renvoie silencieusement que les endroits les plus connus.
  • Laissez le registre public décider ce qu'est quelque chose, pas la source à partir de laquelle vous avez énuméré (un « appartement » d'annuaire que le comté enregistre comme un établissement de soins ; un lot de voitures d'occasion étiqueté multifamilial).
  • Dans un marché où rien n'est listé, les personnes qui valent la peine d'être contactées sont celles qui ne vendent pas.

Étape 4 : les pièges de données (à lire deux fois)

Chaque bug ici a produit un chiffre erroné plausible, jamais une erreur. Budgetisez du temps de QA par rapport à un correctif connu.

  1. Re-interrogez la source avant de planifier autour de sa description. Un nom de couche dans un document est une hypothèse. Lisez les métadonnées du service (pour ArcGIS ?f=json, editingInfo.dataLastEditDate) et les valeurs réelles des champs avant de faire confiance à un nom de champ.
  2. Vérifiez contre quelque chose que vous connaissez. Un bâtiment connu pour avoir 36 unités analysé comme 10 : un seul correctif a attrapé le pire bug. Mieux encore, renvoyez un échantillon de votre sortie à la propre API de l'éditeur dans un cadre de coordonnées différent et comparez.
  3. Surveillez les inversions, pas seulement les valeurs aberrantes : de petites propriétés s'évaluant plus cher par porte que les grandes signifie que l'analyseur est faux, pas le marché.
  4. Faites en sorte que les données se vérifient elles-mêmes. Là où une contre-vérification existe (m² par unité), calculez les deux lectures d'un champ ambigu et laissez la bande plausible choisir ; si aucun ne correspond, signalez et excluez.
  5. Dédoublez avant d'agréger. Un flux listant une propriété sous chaque type d'actif qu'elle correspond : 623 lignes étaient 206 propriétés.
  6. Mettez en cache BRUT, jamais analysé, sinon une correction de l'analyseur signifie re-crawler le serveur d'un petit comté.
  7. Les formats d'adresse diffèrent de l'index des registres. Abrégez les directions et supprimez le suffixe ; une échelle de variantes a récupéré environ la moitié des manques.
  8. Étiquetez les petits échantillons avec leur n ; parfois la minceur est la découverte.
  9. Sur un corpus d'avis, lisez les CORRESPONDANCES, jamais la part. Exécutez chaque expression régulière de taxonomie contre du texte réel de 1 à 3 étoiles et lisez ce qu'elle a correspondu. Le verbe de service du secteur est souvent un verbe de préjudice : un motif « blessure » sur couper (moi|mon) correspondait à 10,7 % des plaintes de salon, principalement « payé 40 $ pour me couper les cheveux moi-même ». Vérifiez percer (dentaire), remorquer (dépannage), décaper (détaillage), casser (verre), raser / tondre (barbiers, toilettage), coller (phlébotomie). Et un thème que personne ne soulève reste caché.
  10. Le vocabulaire de l'éditeur n'est pas celui de l'acheteur. La classe « artérielle » d'un comté peut être le réseau autoroutier, où rien ne fait face, tandis que les rues commerciales qu'un courtier entend sont des « collectrices ». Listez le contenu de chaque seau avant de mapper, et nommez les champs d'après ce qu'ils contiennent.
  11. Un schéma partagé partage les noms de colonnes, pas les conventions. À travers les comtés, un champ peut porter quatre systèmes de classification, -9999 vs 0, une troisième valeur de résidence. Recensez chaque champ par comté ; traitez un zéro d'un comté comme un bug de requête jusqu'à preuve du contraire ; préférez les tests dérivés (valeur du bâtiment = 0 et valeur du terrain > 0 pour vacance).
  12. Un nom est plusieurs choses (une autoroute et sa route de desserte partagent un nom). Renvoyez les alternatives et faites dire au modèle laquelle il a utilisée.
  13. Les choses qui « devraient » se rencontrer une fois se rencontrent plusieurs fois (deux routes se croisant à six endroits). La moyenne des points atterrit dans un champ ; regroupez, conservez chaque emplacement, choisissez selon une règle énoncée.
  14. Un total dérivé supprime silencieusement des lignes que vous n'avez jamais calculées. Expédiez le nombre de couverture à côté de tout total avec des entrées partielles, et faites-le lire comme un minimum.

Étape 5 : les mathématiques déterministes vont dans un outil, jamais dans l'invite

DSCR, IRR, cash-on-cash, dosages, impôts : un outil, calculé, renvoyant ses hypothèses et avertissements. L'arithmétique d'un modèle est plausiblement fausse (un DSCR de 1,19 qui est en réalité 1,09 va à un prêteur). Cela force une vraie boucle d'agent (flux -> exécuter des outils -> retour d'information -> flux), y compris la gestion de pause_turn et max_tokens.

Étape 6 : coût des invites, mesuré

  • Comptez les tokens avec l'API. Un JSON dense tourne à ~2,4 octets/token, pas ~4.
  • Imposez un plafond octets/token dans un test : expédier l'archive au lieu du double compact n'a aucun symptôme sauf la facture.
  • La durée de vie du cache suit le trafic. Peu fréquent, partagé à la main : le défaut de 5 minutes (une écriture d'une heure est une surcharge que personne ne réutilise). Trafic payant continu : 1 heure, car les visiteurs partagent le préfixe.

Étape 7 : déploiement

  • Dérivez la page d'un seul générateur ; chaque remplacement affirme que son ancre existe, et les gardes vérifient dans les deux directions (le contenu supprimé est parti et la fonctionnalité a survécu).
  • S'il s'agit d'une destination publicitaire : URL personnalisées en tant que redirections temporaires (les permanentes sont mises en cache par la plateforme publicitaire), en vérifiant que la chaîne de requête survit ; un nom d'événement pixel par campagne ; durée de vie du cache 1 h ; et attribution épinglée à sessionStorage sur le hit d'atterrissage et portée à chaque tour (pas localStorage, sinon la visite organique de la semaine prochaine sera créditée à l'annonce d'aujourd'hui).
  • Vérifiez l'état de déploiement, pas le journal de build ; un plafond de fonction serverless ou un fichier non tracé peut échouer derrière un journal vert. Importez les fichiers de données statiquement pour que le bundler les inclue.

Règles strictes pour l'invite

  1. N'inventez jamais un nombre. Substrat, un appel d'outil réellement exécuté, ou une estimation signalée.
  2. Ne présentez jamais une valeur de registre public comme une valeur de marché. Dites laquelle vous donnez.
  3. Énoncez la limite de couverture dans la description de l'outil ET l'invite (quels comtés). Une règle à un seul endroit est contournée.
  4. Registre public un à la fois, pas sous forme de liste. La recherche de propriétaire pour la propriété demandée est acceptable ; les listes groupées de noms et adresses peuvent enfreindre la loi sur les dossiers ouverts des États pour un usage commercial.
  5. Revérifiez ce que l'invite qualifie d'impossible. Un mensonge confiant sur ce qui ne peut pas être connu est pire que le vide.

Agents de recherche pour les couches de contexte

Donnez aux agents de recherche parallèles un budget de tokens (et le rapport 2,4 octets/token), dites-leur de couper le chiffre plutôt que l'avertissement, et attendez-vous à ce qu'ils corrigent votre travail antérieur.

Étape 8 : la conclusion hors secteur

Certains visiteurs ne sont pas son utilisateur (un magasin d'occasion dans un agent de restaurant). Le défaut « Je n'ai pas cela » perd le meilleur signal que vous obtiendrez : un vrai propriétaire nommant le secteur à construire ensuite.

  • Un outil flag_out_of_scope(sector) : le client rend trois options tactiles ; un outil submit_feature_request enregistre l'appui.
  • Tout dans la première réponse : la profondeur médiane de session est d'un tour.
  • N'inventoriez pas ce que l'agent porte à la place (une coupe a fait passer une réponse de 1 275 à 124 caractères).
  • Les options sont rendues par le client, jamais une liste numérotée en prose (un simple « 2 » peut déclencher la compétence 2).
  • Dites au modèle où les options sont rendues ; il ne peut pas voir le client.
  • Mappez les options à des capacités universelles afin qu'une demande déposée nomme une capacité pour un secteur.

Étape 9 : la couche spatiale (« qu'est-ce qui est à côté »)

  • Trouvez l'organisation ArcGIS Online du comté, pas son hôte GIS bloqué par WAF ; les services hébergés servent souvent de manière anonyme. Demandez la géométrie dans la référence spatiale native de la couche.
  • Lorsque deux sources se rencontrent, demandez la seconde dans le cadre de la première (outSR), et affirmez que les étendues se chevauchent avant d'émettre des lignes : un décalage de cadre n'intersecte rien et signale « chaque parcelle non zonée ». Dans DuckDB, ST_Transform nécessite always_xy := true ou renvoie silencieusement POINT(inf inf).
  • Zonage par centroïde ; le zonage fractionné nécessite un seuil de part (>5 % du lot), en comparant les districts, pas les polygones. Une simple intersection a appelé 37 % des parcelles fractionnées ; le seuil a donné ~4 %.
  • Les codes de zonage d'une ville sont ceux de cette ville. Le même code signifie des districts différents à côté ; expédiez la ville et le nom publié avec chaque code.
  • Précalculez hors ligne, expédiez un index sans géométrie, n'ajoutez pas de route API : GIS du comté -> miroir spatial DuckDB -> un index JSON validé ; l'exécution ne fait que des recherches et du haversine. Une dépendance spatiale défaillante dégrade en une liste de voisins vide, une réponse erronée confiante. Validez l'index au chargement et levez une exception.
  • Une inégalité n'importe où dans une jointure spatiale rétrograde le prédicat spatial en post-filtre (ON a.id < b.id AND ST_Intersects(...) testé ~29 milliards de paires). Laissez le prédicat seul, EXPLAIN pour SPATIAL_JOIN, émettez les clés, puis dédoublez : 7 minutes non terminées sont devenues 19 secondes.
  • Limitez l'index expédié à ce dans quoi l'acheteur transacte plus les voisins immédiats, et signalez les parcelles de « contexte » qui portent moins de données.

Individual skills in this repo

This repo contains 7 individual skills — each has its own dedicated page.

2016judea/ascii-charts

Build charts as plain Unicode-block text — bar, range, bullet, gap-bracket, star-histogram, heatmap, line, Venn, pie, donut and scatter — with a dependency-free Python script, for anywhere only monospace text survives (newsletter code blocks, Markdown, terminals, plain-text email, chat). Use when a chart has to embed as literal text instead of an image or a third-party chart service, or when you want a hand-made terminal look with no branding footer.

2016judea/buffett-checklist

Apply Warren Buffett's investment framework as a discipline lens when weighing a buy, hold, or sell decision — circle of competence, economic moat, owner earnings & intrinsic value, margin of safety, management/capital-allocation quality, and market psychology (Mr. Market, fear vs greed, temperament). Use when asked to "run this through Buffett", "what would Buffett say", "does this pass the moat test", "is this cheap enough", or for a second, more skeptical read on a name being evaluated or already held. This is a discipline overlay, not a replacement for a strategy — it applies the Buffett lens to how someone actually invests, rather than issuing generic advice.

2016judea/image-riff

Turn one or more reference images into original art in that reference's own visual language, then cut it to whatever surface it's for. Use when you paste or point at art and say "use this as the base image", "generate art from this", "riff on this", "some creative ideation with these images", "make me a channel banner / avatar / cover / plate", "wilder version of this", or want a spread of options off one piece of reference. This is the TASK skill; the engine is the `make-art` tool skill.

2016judea/leonardo

Draw the way Leonardo da Vinci drew — a study sheet, a notebook folio, a red-chalk or silverpoint study, a machine cutaway, a storm of vortices — in his real materials and page-logic, generated with the make-art engine and anchored on fifteen of his actual (public-domain) sheets. Use when you say "Leonardo", "da Vinci", "like his notebooks", "a codex page of X", "draw this as one of his study sheets", "sanguine", "silverpoint", or wants a design, diagram, or illustration in that hand. Also a reading guide to his notebooks (Richter's 1883 public-domain translation) for "what did Leonardo say about shadow / trees / water". This is a TASK skill; the engine is `make-art`.

2016judea/mcp-stack

Which free MCP server or framework to reach for, and its traps — finance/gov data (SEC EDGAR, Yahoo, SAM.gov, USAspending), web research (Exa, Firecrawl, Crawl4AI, Jina reader), design/art/brand (Canva, Inkscape, Penpot, Figma, Orshot, Hugging Face image gen, vectorizing, charts), data/spatial (DuckDB spatial, live ArcGIS layers, OpenStreetMap/Overpass, Census, MapLibre), and ops (PostHog, iMessage, context7 docs). Use when making a social post, OG card, poster, logo/vector, chart, map, or brand asset; when querying parquet/geojson/duckdb or a city's open-data layer; when an MCP "needs authentication" or fails; or when asked "what tools do we have", "is there an MCP for X", "should we add X".

2016judea/records-request

Get a specific record out of a US government office by public-records request — "request the assessor's model", "file a data practices request", "FOIA this", "open records request", "can we just ask the county for it", "who do I write to at <county>", "chase that request", "did they ever answer". Covers checking the website first, finding the right office and statute, the carve-out paragraph that makes a request answerable instead of refused, web-form traps (hidden character caps, WAFs that reject apostrophes), chasing (there is usually no deadline), whether what comes back may be republished, and parsing multi-year tables without silent errors.

2016judea/sms-native-product

Build a product whose interface is text messages rather than an app or a website — "no app, no website", "they just text a number", "chat with our agent natively in Text Messages", "can we do this over text", "an SMS bot", "a Telegram bot", "make it a group chat", "minimum viable friction". Fires equally when it has already gone wrong — "my campaign got rejected", "our number is blocked", "the texts aren't arriving", "why do I need to register". Covers the gate that decides whether such a product can send at all (US A2P 10DLC registration, SHAFT content rules, permanent rejection codes), group MMS from code, what each channel can't do, an architecture that survives losing the channel, and guarding model-rewritten user content.

Skills associés