Docs
Cómo Georadar extrae qué marcas aparecen, con qué sentimiento y en qué posición. Detección de entidades y atributos con los prompts reales del sistema.
La respuesta cruda de ChatGPT o Claude es un texto largo. Para convertir ese texto en métricas comparables hace falta responder, por cada respuesta:
- ¿Qué marcas se mencionan? ¿Son las que teníamos catalogadas o aparecen nuevas?
- ¿En qué posición aparece cada una (primera, segunda, enterrada al final)?
- ¿Con qué sentimiento se las trata (positivo, neutral, negativo)?
- ¿En qué rol aparecen: como tema principal, como comparativa, como ejemplo, como referencia al pasar?
- ¿Qué atributos se les asocian (cómodas, duraderas, caras, sostenibles) y con qué intensidad?
Nada de esto se deja al azar ni a regex. Georadar hace dos llamadas más al LLM por cada respuesta, con prompts muy específicos.
1. Entity detection
La primera llamada extrae menciones de entidades. El system prompt es largo y detallado — el LLM detector recibe el contexto completo del proyecto y las entidades conocidas, y devuelve un JSON estructurado.
Lo que el detector sabe
Cuando Georadar le pasa una respuesta al detector, le da también:
- Contexto del proyecto — nombre, industria, descripción
- Contexto del study (si lo hay) — descripción, instrucciones específicas de detección
- Entidades canónicas — las entidades que tienes en tu proyecto, con su identifier, type, relación (
own,competitor,neutral,ignored) y aliases - Entidades de referencia (contextuales) — entidades útiles para desambiguar aunque no estén en el proyecto
- Scope constraints (si hay) — tipos de entidad permitidos o prohibidos para este study
El prompt real
Fragmento del system prompt (packages/ai/src/templates/entity-detection.ts):
## Detection Rules
1. Find ALL relevant entity mentions in the text
2. The seed set is a strong prior, not a closed universe
3. When a mention clearly matches a known entity, set `matchedIdentifier`
to that exact existing identifier
4. Prefer the most specific known entity that clearly fits, but do not
force weak matches
5. If the mention is relevant and clearly named but does not match any
known entity, leave `matchedIdentifier` as `null`
6. Do not invent identifiers for new discoveries
### What is NOT an Entity
- URLs and domain names (e.g., "cincodias.elpais.com", "bbva.es",
"wikipedia.org") are SOURCE CITATIONS, not entities. NEVER detect
them as entities, even if they contain a brand name.
- Generic category words (e.g., "banco", "marca", "salud", "tecnología",
"neobancos") are NOT entities. Only detect named, specific
brands/products/organizations.
### Brand vs. Sub-product Matching
- If "BBVA Spark" is mentioned but only "bbva" exists in the known list
→ match to "bbva" with exactText="BBVA Spark"
- If both "bbva" AND "bbva-spark" exist in the known list → match to
the MOST SPECIFIC one: "bbva-spark"
- Do NOT create separate detections for both parent and sub-product
from the same mention
El prompt incluye además:
- Clasificación de sentiment con criterios explícitos:
very-negative/negative/neutral(default) /positive/very-positive. El default es neutral: un LLM que simplemente lista marcas no está siendo positivo, está describiendo. Esto se subraya expresamente en el prompt: “Words like ‘revolutionary’ or ‘incredible’ in marketing contexts are ‘positive’, NOT ‘very-positive’.” - Clasificación de
mentionRole:subject(la marca es el tema) ·comparison(aparece junto a otras competidoras) ·example(caso ilustrativo) ·reference(mención de pasada). Con una aclaración crítica: “When a response lists several entities with their features, ALL of them are ‘comparison’, not ‘subject’.” - Discovery rules para marcas nuevas: solo si están mencionadas por nombre, son claramente una marca/empresa/producto, centrales al texto, y NO son una categoría genérica.
Qué devuelve el detector
Para cada respuesta, el LLM devuelve un JSON con dos arrays:
{
"mentions": [
{
"name": "BBVA",
"type": "brand",
"matchedIdentifier": "bbva",
"discoveryName": null,
"confidence": 0.95,
"sentiment": "positive",
"mentionRole": "subject",
"position": 0,
"exactText": "BBVA"
},
{
"name": "Some Unknown Bank",
"type": "brand",
"matchedIdentifier": null,
"discoveryName": "SomeUnknownBank",
"confidence": 0.7,
"sentiment": "neutral",
"mentionRole": "comparison",
"position": 1,
"exactText": "Some Unknown Bank"
}
],
"discoveries": [
{
"name": "SomeUnknownBank",
"type": "brand",
"aliases": ["Unknown Bank", "SUB"],
"reason": "Explicitly named, compared against BBVA",
"confidence": 0.7
}
]
}
Georadar post-procesa:
- El sentiment string (
"positive") se convierte a número 1–5 (positive = 4) — lo que vive en la base de datos. - Se calculan
startIndex/endIndexdentro del texto original. - Se extrae
fullSentence— la oración completa que contiene la mención.
Scope enforcement
Si hay un study con scope definido:
- Los
disallowedEntityTypesdescartan menciones de ese tipo (ej. ignorar todas las menciones de tipoperson). - La
blocklistdescarta menciones de identifiers concretos. - La
allowlistrestringe a solo ciertos identifiers.
El sistema no filtra después: el filtrado se le pide al propio detector vía el prompt. El detector directamente no incluye las menciones fuera de scope.
Discoveries (candidatos)
Las entradas en discoveries son marcas nuevas que el detector encontró pero no estaban en tu catálogo. Se guardan como candidatos (en la tabla entity_candidates) y aparecen en la UI para promoción manual o descarte.
2. Attribute detection
Con las menciones de entidad ya resueltas, se hace una segunda pasada sobre la misma respuesta para extraer atributos asociados a cada entidad.
Lo que ve el detector de atributos
- Las mismas respuesta del LLM
- La lista de entidades ya detectadas con su posición
- El catálogo de atributos conocidos del proyecto (“Calidad”, “Servicio al cliente”, “Precio”, “Sostenibilidad”) con sus aliases
Reglas relevantes del prompt real
Fragmento (packages/ai/src/templates/attribute-detection.ts):
## Detection Rules
1. Find attribute mentions related to the detected entities
2. Each attribute must be associated with a specific entity
3. CRITICAL: Use the EXACT identifier from the known list - if
"durability" exists, use that identifier even if text says
"durable" or "built to last"
4. IMPORTANT: Use the EXACT attribute name from the known list
(e.g., "Quality" not "quality", "Customer Service" not
"customer service")
5. Match attributes by name OR aliases
### Sentiment Classification (be conservative)
- very-negative: Severe criticism, complete failure, disaster
- negative: Problems, needs improvement, criticism
- neutral: Factual description without positive/negative judgment
- positive: Good, beneficial, praised (DEFAULT for mildly positive)
- very-positive: ONLY for exceptional, outstanding, best-in-class
### Intensity Classification (be conservative)
- very-low: Barely mentioned, implied
- low: Mentioned briefly without emphasis
- moderate: Clear mention with some emphasis (DEFAULT)
- high: Strong emphasis, multiple descriptors
- very-high: Only for extreme emphasis with stacked qualifiers
(e.g., "absolutely exceptional", "unprecedented")
### What to Detect
- Only detect attributes from the KNOWN list that are EXPLICITLY mentioned
- Do NOT infer attributes that aren't clearly stated
- ONE attribute per concept: combine repetitions into one detection
- Skip neutral factual mentions that don't carry evaluation
Qué devuelve
{
"detectedAttributes": [
{
"entityIdentifier": "bbva",
"attributeIdentifier": "customer-service",
"attributeName": "Customer Service",
"confidence": 0.88,
"sentiment": "positive",
"intensity": "high",
"evidence": "excellent customer support",
"reasoning": "The text explicitly praises BBVA's customer support.",
"exactText": "excellent customer support"
}
],
"suggestedNewAttributes": [
{
"identifier": "sustainability",
"name": "Sustainability",
"category": "Environmental",
"reason": "BBVA's green banking initiatives are mentioned.",
"entityIdentifiers": ["bbva"]
}
]
}
suggestedNewAttributes son los candidatos a ampliar el catálogo de atributos del proyecto. Igual que con entidades, no se añaden automáticamente — quedan pendientes de revisión.
Y después: métricas
Con entidades y atributos detectados, Georadar corre un cálculo de métricas por respuesta (pesos combinados de sentimiento, posición, conteo y ranking competitivo) que produce los scores precalculados. Esos scores viajan a ClickHouse junto a las menciones y son los que el dashboard agrega.
El detalle completo del cómputo vive en Métricas · Computation.
Por qué el detector es un modelo distinto
Tres razones:
- Especialización: un modelo preparado para devolver JSON estructurado con reglas estrictas hace el trabajo mejor que uno generalista. Gemini 2.5 Flash Lite es el default — barato, rápido, fiable en JSON.
- Consistencia: si el detector cambiase según qué engine respondió al prompt original, las métricas no serían comparables entre engines. El mismo detector para todas las respuestas garantiza comparabilidad.
- Coste: la detección se hace N veces por run (una por respuesta). Tiene que ser barata o el coste explota.
Siguiente
Con entidades, atributos y métricas calculadas, toca Leer los resultados — las cinco vistas del dashboard.
