Fuentes de Datos para Sofía
Sofía puede responder preguntas usando contenido real de los tres programas de FIA. El sistema usa routing semántico en dos pasos: primero encuentra la fuente más relevante, luego busca el contenido dentro de esa fuente.
Arquitectura de dos pasos
Pregunta del usuario
↓
match_data_sources(embedding) → ¿cuál fuente tiene la respuesta?
↓
match_capsule_chunks(embedding, p_path_id)
o match_knowledge_base(embedding) → chunks de contenido real
↓
Contexto para el prompt de Sofía
Por qué dos pasos
Con un solo paso (buscar en todos los chunks directamente) Sofía podría traer contenido de cualquier programa sin saber de cuál habla el alumno. Con dos pasos:
- El paso 1 es liviano: compara con 5 filas de descripción
- El paso 2 busca solo en la fuente correcta: miles de chunks, pero filtrados
- Agregar un track nuevo = 1 INSERT + 1 embedding, sin redeployar el engine
Tabla sofia_data_sources
Cada fila describe una fuente de conocimiento en lenguaje natural. El engine la fetchea para saber qué puede buscar y cuándo.
| Campo | Tipo | Para qué sirve |
|---|---|---|
source_key |
TEXT (único) | Identificador interno: fia_ventas_transcripts |
name |
TEXT | Nombre legible: "FIA Ventas — Clases y Cápsulas" |
description |
TEXT | Qué hay aquí y cuándo buscar — lo que Sofía "lee" |
query_method |
TEXT | match_capsule_chunks o match_knowledge_base |
rpc_name |
TEXT | Nombre exacto del RPC en Supabase |
default_params |
JSONB | Parámetros por defecto: threshold, count, p_path_id |
covers_topics |
TEXT[] | Temas que cubre |
example_questions |
TEXT[] | Preguntas de ejemplo (también usadas para el embedding) |
embedding |
vector(1536) | Embedding sobre name+description+topics+questions |
Fuentes activas
| source_key | Programa | Contenido |
|---|---|---|
fia_agentica_transcripts |
FIA Agéntica | 16 cápsulas: clases 1-4 + Primeros Pasos |
fia_ventas_transcripts |
FIA Ventas | 22 cápsulas: clases 1-10 + bonus |
fia_empresas_transcripts |
FIA Empresas | 17 cápsulas del programa |
knowledge_base_frameworks |
KB | Frameworks: RoLoCoDePre, WorkIA, RICA, Método FIA |
knowledge_base_casos |
KB | Casos de éxito con números reales |
RPCs disponibles
match_data_sources — Paso 1: routing
Dada la pregunta embebida, devuelve las fuentes más relevantes.
SELECT * FROM match_data_sources(
query_embedding := '<vector>',
match_threshold := 0.4, -- default
match_count := 3 -- default
);
-- Devuelve: source_key, name, description, query_method, rpc_name, default_params, similarity
match_capsule_chunks — Paso 2a: contenido de clases
SELECT * FROM match_capsule_chunks(
query_embedding := '<vector>',
match_threshold := 0.4,
match_count := 5,
p_path_id := 'b2c3d4e5-f6a7-8901-bcde-f12345678901' -- FIA Ventas
);
-- Devuelve: capsule_slug, capsule_title, chunk_index, content, similarity
p_path_id = null busca en todos los tracks.
match_knowledge_base — Paso 2b: frameworks y casos
SELECT * FROM match_knowledge_base(
query_embedding := '<vector>',
match_threshold := 0.5,
match_count := 4,
p_category := 'caso' -- opcional
);
-- Devuelve: slug, category, title, summary, content, voice_notes, similarity
Helpers TypeScript
En src/lib/sofia-data-sources.ts:
import { matchDataSources, getSofiaDataSources, matchCapsules, formatDataSourcesForPrompt } from '@/lib/sofia-data-sources'
// Paso 1: routing semántico
const fuentes = await matchDataSources("¿cómo uso ChatGPT para vender?")
// → [{ source_key: 'fia_ventas_transcripts', similarity: 0.62, default_params: { p_path_id: '...' } }]
// Paso 2: contenido de la fuente ganadora
const chunks = await matchCapsules("¿cómo uso ChatGPT para vender?", {
pathId: 'b2c3d4e5-f6a7-8901-bcde-f12345678901'
})
// → [{ capsule_title: 'Clase 1 FV', content: '...', similarity: 0.71 }]
// Fallback: todas las fuentes como texto para el system prompt
const todas = await getSofiaDataSources()
const texto = formatDataSourcesForPrompt(todas)
Path IDs de los tracks
// src/lib/agentica.ts
FIA_AGENTICA_PATH_ID = 'd4e5f6a7-b8c9-0123-defa-234567890123'
// src/lib/static-ventas.ts
FIA_VENTAS_PATH_ID = 'b2c3d4e5-f6a7-8901-bcde-f12345678901'
// src/lib/static-empresas.ts
FIA_EMPRESAS_PATH_ID = 'c3d4e5f6-a7b8-9012-cdef-123456789012'
Agregar una fuente nueva
- INSERT en
sofia_data_sourcesconembedding = null - Generar el embedding sobre:
name + '\n' + description + '\n' + covers_topics.join(', ') + '\n' + example_questions.join(' | ') - PATCH con el embedding → la fuente es inmediatamente visible para el engine
- No hace falta redeployar nada