Capacidades de un Agente Analítico AI-Parrot (PandasAgent)¶
Documento de capacidades para agentes tipo Porygon (
agents/porygon.py) y TROC Finance (agents/troc.py), construidos sobrePandasAgentcon todo el stack analítico de AI-Parrot: DatasetManager, sistema de Skills, memoria episódica, Working Memory, WhatIf Toolkit, Infographic Toolkit y Knowledge Base local con FAISS.
Índice¶
- Anatomía de un agente analítico
- DatasetManager: el catálogo de datos
- El principio "in our end": los datos no salen a la nube
- Tipos de datasets / fuentes soportadas
- Incorporar nuevos datasets en caliente
- Columnas calculadas y datasets compuestos
- Sistema de Skills
- Memoria episódica
- Infographic Toolkit
- Working Memory Toolkit
- WhatIf Toolkit
- Knowledge Base local con FAISS
- Resumen general de capacidades y potencial
1. Anatomía de un agente analítico¶
Tanto Porygon como TROC Finance se declaran con la misma composición de mixins
sobre PandasAgent:
@register_agent(name="porygon", at_startup=True)
class Porygon(SkillRegistryMixin, EpisodicMemoryMixin, PandasAgent):
agent_id: str = "porygon"
model = 'gemini-3.1-pro-preview'
enable_episodic_memory: bool = True
episodic_backend: str = "faiss"
enable_skill_registry: bool = True
...
Esta jerarquía aporta cuatro grandes bloques de capacidad:
| Bloque | De dónde viene | Qué aporta |
|---|---|---|
| Ejecución analítica | PandasAgent (parrot.bots.data) |
REPL de pandas (python_repl_pandas), forecasting con Prophet, gestión de DataFrames |
| Catálogo de datos | DatasetManager (_dataset_manager) |
Registro, materialización perezosa y manipulación local de fuentes de datos |
| Aprendizaje y procedimientos | SkillRegistryMixin + EpisodicMemoryMixin |
Skills reutilizables + memoria de experiencias pasadas |
| Toolkits especializados | WorkingMemoryToolkit, WhatIfToolkit, InfographicToolkit, DatabaseToolkit |
Memoria de trabajo, simulación de escenarios, infografías HTML, SQL multi-driver |
El PandasAgent es el núcleo: expone un REPL de pandas (PythonPandasTool)
donde los datasets registrados aparecen como variables Python listas para usar.
Cada DataFrame se inyecta con:
- Su nombre original (p. ej.
kiosks_daily_summary). - Un alias estable (
df1,df2, …) coherente con lo que reportalist_datasets. - Metadatos auxiliares (
kiosks_daily_summary_row_count,_columns,_shape, …).
# Dentro del REPL del agente, todo esto está disponible:
result = kiosks_daily_summary[kiosks_daily_summary['is_empty'] == True]
print(kiosks_daily_summary_columns) # ['kiosk_id', 'warehouse_id', ...]
El flag use_tool_llm (Porygon lo deja en False) controla si la elección de
herramientas se delega a un LLM auxiliar; por defecto el propio modelo principal
razona sobre qué herramienta invocar.
2. DatasetManager: el catálogo de datos¶
DatasetManager (parrot/tools/dataset_manager/tool.py, clase DatasetManager(AbstractToolkit))
es la pieza central de datos. Funciona como un catálogo + toolkit: registra
fuentes, las describe al LLM, las materializa bajo demanda y mantiene los datos
crudos en local.
Cada fuente registrada queda envuelta en un DatasetEntry, que guarda el estado
de ciclo de vida (_df, _column_types, cargado/no cargado, protegido) y los
metadatos seguros para el LLM, modelados por DatasetInfo.
2.1 El principio "in our end": los datos no salen a la nube¶
Este es el punto arquitectónico más importante para análisis sobre datos sensibles: el LLM nunca recibe filas crudas de las tablas. Solo recibe metadatos y, opcionalmente, resúmenes o muestras pequeñas.
El modelo DatasetInfo define exactamente qué se expone al modelo:
class DatasetInfo(BaseModel):
name, alias, description, source_type, source_description
# ✓ Esto SÍ se envía al LLM (metadatos, no datos):
columns: List[str] # solo nombres de columnas
column_types: Optional[Dict[str, str]] # tipos (integer, text, ...)
row_count_estimate: Optional[int] # tamaño, para decidir estrategia
table_size_warning: str # "tabla grande → usa GROUP BY"
usage_do, usage_dont: List[str] # guías de uso
# ✗ Solo presente si loaded=True (los datos viven en memoria local):
shape, loaded, memory_usage_mb, null_count
Cómo se garantiza el aislamiento:
- Carga perezosa con prefetch de esquema. Una
TableSourceejecuta una consulta aINFORMATION_SCHEMAal registrarse para conocer columnas y tipos. No se trae ni una fila para exponer el esquema. - Materialización local.
fetch_dataset(...)ejecuta la consulta (idealmente agregada conGROUP BY/SUM/AVGempujadas a la base de datos) y guarda el resultado en un DataFrame en memoria del proceso, con caché opcional en Redis. Ese DataFrame se queda local. - Respuestas acotadas.
fetch_datasetdevuelve los datos completos solo si el resultado es pequeño; para resultados grandes devuelve unsample_rows(vista previa de ~20-50 filas) y marca"complete": False, indicando que el dataset completo está en memoria como variable de Python (python_variable) para que el REPL lo manipule. - Manipulación en el REPL. Toda transformación pesada (joins, agregaciones, pivots, correlaciones, forecasting) ocurre en pandas, localmente. El LLM solo ve el código que escribe y los resúmenes/tablas que decide devolver.
Consecuencia práctica: a la nube del LLM solo viajan descripciones de esquema, guías de uso (
usage_guidance), el código pandas generado y los resúmenes finales que el agente elige mostrar. Los datos crudos se procesan íntegramente en nuestra infraestructura.
2.2 Tipos de datasets / fuentes soportadas¶
Todas las fuentes heredan de DataSource (sources/base.py). Hay dos grandes
modos: perezoso (solo esquema, filas bajo demanda) y eager (DataFrame
cargado en el arranque).
Fuentes perezosas (esquema precargado, sin filas)¶
| Tipo | Método de registro | Descripción |
|---|---|---|
| TableSource | add_table_source(name, table, driver, ...) |
Tabla de BD (BigQuery, Postgres, MySQL). Hace prefetch del esquema vía INFORMATION_SCHEMA. El LLM debe pasar un SELECT dirigido; valida columnas y rechaza SELECT * en tablas grandes (>10k filas). |
| QuerySlugSource | add_query(name, query_slug, ...) |
Envuelve un slug de QuerySource. Infiere tipos con 1 fila; gestiona su propia caché. |
| MultiQuerySlugSource | (interno) | Varios slugs concatenados, unión de esquemas. |
| SQLQuerySource | add_sql_source(name, sql, driver, ...) |
Plantilla SQL con marcadores {param}. fetch(conditions={...}) sustituye y ejecuta. |
| IcebergSource | add_iceberg_source(name, table_id, catalog_params, ...) |
Tabla Apache Iceberg. |
| DeltaTableSource | add_deltatable_source(name, path, ...) |
Tabla Delta Lake (local, s3://, gs://). |
| MongoSource | add_mongo_source(name, collection, database, ...) |
Colección MongoDB/DocumentDB; requiere filter y projection. |
| AirtableSource | add_airtable_source(name, base_id, table, ...) |
Base/tabla de Airtable. |
| SmartsheetSource | add_smartsheet_source(name, sheet_id, ...) |
Hoja de Smartsheet. |
Fuentes eager (DataFrame cargado de inmediato)¶
| Tipo | Método de registro | Descripción |
|---|---|---|
| InMemorySource | add_dataframe(name, df, ...) |
Envuelve un DataFrame de pandas ya en memoria. |
add_dataframe_from_file(name, path, ...) |
Lee CSV/Excel con pandas y lo registra. | |
add_dataset(name, table/query/dataframe/query_slug, ...) |
Ejecuta la fuente al instante y cachea el resultado como DataFrame. |
Fuentes compuestas¶
| Tipo | Método de registro | Descripción |
|---|---|---|
| CompositeDataSource | add_composite_dataset(name, joins, ...) |
Dataset virtual que une dos o más datasets ya registrados mediante JoinSpec (left/right/on/how/suffixes). |
Carga de ficheros para análisis estructural¶
load_file(name, path, max_rows_per_table=200, output_format='markdown') carga un
CSV/Excel y produce un resumen estructural en markdown (tablas, tipos), pensado
para que el agente entienda un fichero subido sin convertirlo aún en DataFrame.
Parámetros clave de los métodos de registro¶
add_table_source, add_dataset y add_query comparten un vocabulario común:
await dm.add_table_source(
name="active_employees", # identificador del dataset
table="troc.troc_employees", # nombre cualificado en la BD
driver="pg", # "pg" | "bigquery" | "mysql"
description="Lista de empleados...", # descripción para el LLM
query_filter={"region": "POKEMON HIERARCHY"}, # filtro permanente siempre aplicado
usage_guidance={ # guías do/don't para el LLM
"do": [
"Análisis de headcount, cálculos FTE",
"Filtrado por estado activo, departamento, rol",
],
"dont": [
"No usar para datos financieros (revenue, expenses, EBITDA)",
],
},
)
descriptionyusage_guidance(do/dont) son la forma de enseñar al LLM cuándo y cómo usar cada dataset, sin exponer datos.permanent_filter/query_filter: filtro de igualdad siempre aplicado (escalar →=, lista →IN). Útil para multi-tenancy o recortar el alcance.allowed_columns: restringe el acceso a un subconjunto de columnas.cache_ttl/no_cache: control de la caché en Redis (Parquet).metadata,query_slug,computed_columns: metadatos extra, slug de QuerySource y columnas calculadas (ver abajo).
Ejemplo real de Porygon registrando 8 fuentes perezosas (BigQuery + Postgres) y 2
eager, y de TROC Finance registrando proyecciones, presupuesto y chart_of_accounts.
2.3 Incorporar nuevos datasets en caliente¶
El agente puede ampliar su catálogo durante la conversación, no solo en el arranque:
fetch_dataset(name, sql=..., conditions=..., force_refresh=...)— herramienta principal: materializa una fuente registrada. ParaTableSourceexige unSELECTexplícito (preferiblemente agregado); para fuentes compuestas o SQL aceptaconditions. Devuelve forma, columnas, esquema y datos/muestra + la variable Python disponible en el REPL.add_source(source, ...)— punto de entrada genérico para registrar cualquier subclase deDataSourcedinámicamente.add_dataframe_from_file(...)/load_file(...)— incorporar ficheros subidos (CSV/Excel) como dataset o como resumen estructural.store_dataframe/add_dataframe— guardar en el catálogo un DataFrame calculado en el REPL para reutilizarlo en pasos posteriores.- Gestión del ciclo de vida:
activate_datasets,deactivate_datasets,remove_dataset,evict_dataset(libera memoria sin perder la definición),check_data_quality,list_datasets,get_metadata,get_source_schema.
2.4 Columnas calculadas y datasets compuestos¶
Columnas calculadas (ComputedColumnDef): columnas virtuales aplicadas después
de materializar, en local:
ComputedColumnDef(
name="margin",
func="math_operation", # add | subtract | multiply | divide
columns=["revenue", "cost"],
kwargs={"operation": "subtract"},
)
Funciones integradas: operaciones matemáticas y concatenación de strings; si está
disponible QuerySource, se cargan funciones adicionales. Se pueden añadir en
caliente con add_computed_column(...).
Datasets compuestos (CompositeDataSource + JoinSpec): joins declarativos
entre datasets registrados, materializados con pd.merge() secuencial y filtros por
componente. Cada componente se cachea de forma individual.
3. Sistema de Skills¶
El SkillRegistryMixin (parrot/skills/) dota al agente de un registro de
skills versionables tipo Git: instrucciones de comportamiento reutilizables,
escritas como markdown con frontmatter YAML.
Qué es una skill¶
Una skill es un fichero markdown con metadatos y un cuerpo de instrucciones:
---
name: ebitda_breakdown
description: Procedimiento estándar de desglose de EBITDA por proyecto/programa/mes
triggers:
- /ebitda
- /ebitda_breakdown
source: authored # authored | learned
category: workflow # tool_usage | workflow | domain | error_handling | ...
priority: 90
version: 1.0
---
# Cuerpo de la skill
Pasos, fórmulas, datasets a usar, contrato de salida, "qué NO hacer"...
Existen dos formatos:
- Skill de fichero único (
agents/<agente>/skills/*.md). - Skill compuesta (directorio con
SKILL.md+ activos). Por ejemplo,agents/troc_finance/skills/daily_financial_projection/contiene unSKILL.mdque instruye al agente a leer y ejecutarcompute.pyverbatim enpython_repl_pandas. Esto es la ejecución de skills: la skill transporta código Python real que el agente carga y ejecuta para generar DataFrames y bloques de salida deterministas.
Configuración (flags vistos en los agentes)¶
| Flag | Default | Significado |
|---|---|---|
enable_skill_registry |
True |
Interruptor maestro del registro de skills. |
skill_registry_expose_tools |
True |
Registra las herramientas de skills (buscar, documentar, listar, cargar). |
skill_registry_inject_context |
True |
Inyecta automáticamente las skills relevantes en el system prompt antes de cada consulta. |
skill_registry_auto_extract |
False |
Extrae skills nuevas de las conversaciones (costoso → opt-in). |
skill_registry_max_context_skills |
3 |
Máximo de skills inyectadas por consulta. |
Cómo funcionan (carga, contexto, ejecución)¶
- Descubrimiento al arrancar (
SkillsDirectoryLoader+SkillFileRegistry): escaneaagents/<agente>/skills/(incluidolearned/), parsea cada.mdy los indexa por nombre y por trigger. - Inyección de contexto en dos niveles:
- Capa estática
<available_skills>: bloque XML inyectado una vez al configurar, que lista todas las skills con su nombre, descripción y triggers. - Carga bajo demanda: el LLM detecta una skill relevante y llama a
load_skill(name="..."), que devuelve el cuerpo completo + manifiesto de activos. - Activación por trigger (
SkillTriggerMiddleware): si el mensaje del usuario empieza con/ebitda_breakdown, el middleware activa esa skill y la coloca en el contexto./skillsy/helplistan las disponibles. - Almacenamiento y búsqueda semántica (
SkillRegistry,store.py): registro versionado (v0 completo + deltas en diff unificado), con embeddings (all-mpnet-base-v2) e índice FAISS parasearch_skills. La relevancia combina0.7 * similitud + 0.3 * utilidad. - Auto-extracción (si
auto_extract=True): un LLM analiza la conversación y, si la confianza ≥ 0.5, guarda automáticamente una skill nueva.
Herramientas de skills expuestas¶
document_skill, update_skill, search_skills, read_skill, list_skills,
save_learned_skill (la guarda como .md y la activa al instante) y load_skill.
4. Memoria episódica¶
El EpisodicMemoryMixin (parrot/memory/episodic/) permite al agente recordar y
aprender de interacciones pasadas. Cada unidad de memoria es un episodio.
Qué se almacena¶
El modelo EpisodicMemory captura situación, acción, resultado y la lección
aprendida:
class EpisodicMemory(BaseModel):
situation: str # qué se le pidió
action_taken: str # qué hizo el agente
outcome: EpisodeOutcome # SUCCESS | FAILURE | PARTIAL | TIMEOUT
error_type, error_message # clasificación del error
reflection, lesson_learned, suggested_action # reflexión (LLM o heurística)
category: EpisodeCategory # TOOL_EXECUTION | QUERY_RESOLUTION | ERROR_RECOVERY | ...
importance: int # 1-10
related_tools, related_entities
embedding: list[float] # vector para búsqueda semántica
# + scoping multi-tenant: tenant_id, agent_id, user_id, session_id, room_id, crew_id
Configuración (flags vistos en los agentes)¶
| Flag | Default | Significado |
|---|---|---|
enable_episodic_memory |
False (los agentes lo activan a True) |
Interruptor maestro. |
episodic_backend |
"faiss" |
Backend de almacenamiento: faiss (local/dev), pgvector (producción), redis_vector (experimental). |
episodic_reflection_enabled |
True |
Genera reflexión (lección + acción sugerida) tras cada episodio. |
episodic_inject_warnings |
True |
Inyecta avisos de fallos pasados en el system prompt. |
episodic_max_warnings |
3 |
Máximo de avisos inyectados. |
Cómo funciona¶
- Almacenamiento FAISS (
FAISSBackend): índiceIndexFlatIP(producto interno = coseno sobre vectores normalizados), con persistencia a disco (episodes.faiss+episodes.jsonl+id_order.json), tope de episodios y auto-guardado periódico. Caché caliente opcional en Redis. - Embeddings (
all-MiniLM-L6-v2, 384 dim): se embebe el textosituación | acción | lección. - Recall (
recall.py): búsqueda semántica (SemanticOnlyStrategy) o híbrida léxica+semántica (HybridBM25Strategy, fusión0.4*BM25 + 0.6*semántico). - Reflexión (
ReflectionEngine): genera la lección con LLM (Gemini flash) y, si falla, con patrones heurísticos por regex (timeout, rate limit, permisos, etc.). - Scoring de importancia (
HeuristicScorer/ValueScorer): los fallos puntúan alto (importantes de recordar), los éxitos triviales bajo. - Inyección de avisos: antes de cada respuesta,
get_failure_warningsbusca fallos similares al query actual y los inyecta como:
MISTAKES TO AVOID:
- Consulta a API sin comprobar rate limit (tool: fetch_api) — Añade delay entre llamadas
SUGGESTED APPROACHES:
- Implementa backoff o reduce la frecuencia de peticiones.
- Grabación automática (fire-and-forget): cada
ask()y cada ejecución de herramienta se graban como episodios sin bloquear la respuesta.
Herramientas episódicas¶
search_episodic_memory(query, failures_only), record_lesson(situation, lesson, ...)
y get_warnings(context) (prefijo ep_).
5. Infographic Toolkit¶
El InfographicToolkit (parrot/tools/infographic_toolkit.py, FEAT-197) genera
infografías HTML autocontenidas a partir de los DataFrames que el agente tiene en
el REPL. Se enlaza al agente con set_bot(self) y persiste los artefactos en el
ArtifactStore de la app.
En TROC Finance se registra así:
artifact_store = app.get("artifact_store")
if artifact_store is not None:
infographic_toolkit = InfographicToolkit(artifact_store=artifact_store)
infographic_toolkit.set_bot(self) # lee los locals del REPL pandas
self.tool_manager.register_toolkit(infographic_toolkit)
Herramientas expuestas¶
| Herramienta | Propósito |
|---|---|
infographic_render(template_name, theme, mode, blocks, data_variables, enhance_brief) |
Valida, renderiza y persiste la infografía. Devuelve artifact_id + URL. |
infographic_list_templates() |
Lista las plantillas disponibles. |
infographic_get_template_contract(template_name) |
Devuelve el contrato (orden y tipos de bloques, constraints, bundles JS). |
infographic_validate_blocks(template_name, blocks) |
Validación en seco; devuelve {"ok": ...} sin lanzar excepción. |
El agente indica en data_variables qué DataFrames del REPL alimentan la infografía;
el toolkit los lee vía bot._get_repl_locals() y valida que existan y no estén vacíos.
Tipos de infografía que puede generar¶
Plantillas integradas (registro extensible):
| Plantilla | Uso |
|---|---|
basic |
Infografía simple: título + tarjetas hero + resumen + gráfico + bullets. |
executive |
Briefing ejecutivo: KPIs + tendencias + tabla + recomendaciones. |
dashboard |
Dashboard denso: 6-8 KPIs + línea + tarta + tabla + progreso. |
comparison |
Comparativa lado a lado + tabla + barras + ganador. |
timeline |
Informe cronológico con eventos + área. |
minimal |
Mínima: título + resumen + 3 bullets. |
multi_tab |
Informe con pestañas (3-7 tabs, cada una con sus propios bloques). |
financial_variance |
Dashboard de varianza financiera (4 hero cards, barras DoD, línea acumulada). |
financial_projection_variance |
Varianza de proyección financiera (incluye bundle de ECharts vía CDN). |
Bloques disponibles (15): title, hero_card (KPI con tendencia), summary,
chart, bullet_list, table, image, quote, callout, divider, timeline,
progress, accordion, checklist, tab_view.
Tipos de gráfico (12): bar, line, pie, donut, area, scatter, radar,
heatmap, treemap, funnel, gauge, waterfall — renderizados con ECharts.
Temas (4): light, dark, corporate, midnight.
Modos y "enhance pass"¶
deterministic: HTML esqueleto generado solo a partir de los bloques validados (rápido, predecible).enhance: pasada opcional con LLM que añade interactividad JavaScript a partir de unenhance_brief. Por seguridad, solo se permiten bundles JS declarados en la plantilla (whitelist con SRI). Si la validación falla, hace fallback al esqueleto.
El resultado se devuelve con return_direct=True, de modo que no se re-resume por
el LLM: la infografía persistida es el output. El artefacto se guarda en el
ArtifactStore (con HTML + envelope de bloques + bundles JS) y se sirve por URL
(/api/v1/artifacts/{id}?format=html).
6. Working Memory Toolkit¶
El WorkingMemoryToolkit (parrot/tools/working_memory/) es un almacén de
resultados intermedios para análisis de varios pasos. Resuelve un problema clave:
durante una cadena de razonamiento, el agente necesita guardar DataFrames y objetos
intermedios entre llamadas a herramientas sin devolver datos crudos al LLM
(ahorra tokens y mantiene contexto). El LLM solo ve resúmenes compactos (forma,
dtypes, estadísticas, vista previa pequeña).
Se registra de forma sencilla:
wm_toolkit = WorkingMemoryToolkit()
self.tool_manager.register_toolkit(wm_toolkit) # prefijo de herramientas: "wm"
Herramientas principales¶
| Herramienta | Propósito |
|---|---|
store(key, df, ...) |
Guardar un DataFrame bajo una clave. |
store_result(key, data, data_type="auto", ...) |
Guardar cualquier objeto (texto, dict, list, bytes, Message, objeto). |
get_stored(key, ...) / get_result(key, ...) |
Recuperar el resumen compacto del elemento. |
list_stored(turn_id=None) / search_stored(query, ...) |
Listar/buscar elementos guardados. |
drop_stored(key) |
Eliminar un elemento. |
compute_and_store(spec, ...) |
Ejecutar una operación declarativa (DSL) y guardar el resultado. |
merge_stored(keys, store_as, ...) / summarize_stored(keys, store_as, agg_rules, ...) |
Unir / unir+agregar varios DataFrames. |
import_from_tool(tool_name, variable_name, store_as, ...) |
Puente: importar un DataFrame desde el namespace del REPL pandas. |
save_interaction / recall_interaction |
Puente con AnswerMemory (pares pregunta-respuesta por turn_id). |
El compute_and_store usa un DSL declarativo (OperationSpecInput) con 13
operaciones (filter, aggregate, join, merge, correlate, pivot, rank, window, sort,
select, rename, fillna, drop_duplicates, describe). El agente nunca ejecuta código
arbitrario por esta vía: solo specs validados por Pydantic, lo que lo hace seguro y
auditable. Internamente, WorkingMemoryCatalog guarda CatalogEntry (DataFrames con
linaje: parent_keys, source_operation) y GenericEntry (otros objetos).
7. WhatIf Toolkit¶
El WhatIfToolkit (parrot_tools/whatif_toolkit.py) realiza análisis de
escenarios "qué pasaría si" de forma descompuesta: aplica cambios hipotéticos sobre
los datasets y mide su impacto, todo en pandas, en local.
Se construye enlazándolo al DatasetManager y al REPL pandas, y se activa con el flag
enable_scenarios=True en el agente:
whatif_toolkit = WhatIfToolkit(
dataset_manager=dm,
pandas_tool=getattr(self, 'pandas_tool', None),
)
self.tool_manager.register_toolkit(whatif_toolkit)
Conceptos¶
- Métricas derivadas (
DerivedMetric): campos calculados por fórmula (revenue_per_visit = revenue / visits) que se recalculan al cambiar las columnas base. - Acciones (
Action): operaciones hipotéticas — excluir filas, escalar columnas, ajustar por porcentaje, escalar por entidad, escalado proporcional. - Restricciones (
Constraint): límites duros (cambio máximo %, mín/máx, ratio). - Objetivos (
Objective): minimizar, maximizar o alcanzar un valor objetivo, con pesos. - Optimización: algoritmo
greedy(mejora iterativa) ogenetic(búsqueda exhaustiva de combinaciones).
Herramientas (flujo descompuesto)¶
| Herramienta | Propósito |
|---|---|
describe_scenario(df_name, scenario_description, derived_metrics) |
Crea y valida un escenario; devuelve scenario_id + inventario de columnas. |
add_actions(scenario_id, actions) |
Añade acciones posibles, validadas contra el esquema. |
set_constraints(scenario_id, objectives, constraints) |
Define objetivos y restricciones. |
simulate(scenario_id, algorithm, max_actions) |
Ejecuta la optimización; registra el DataFrame resultado en el DatasetManager (whatif_<id>_result). |
compare_scenarios(scenario_ids) |
Compara varios escenarios resueltos lado a lado. |
quick_impact(df_name, action_description, action_type, target, parameters) |
Atajo de un solo paso para preguntas simples ("¿y si quitamos X?"). |
El resultado se presenta como tabla comparativa baseline vs escenario (cambio absoluto y %), acciones aplicadas y veredicto. Como el resultado se registra en el DatasetManager, encadena con pandas y nuevas simulaciones.
8. Knowledge Base local con FAISS¶
El flag local_kb=True dota al agente de una base de conocimiento en memoria,
respaldada por FAISS, que indexa documentos propios del agente y los recupera por
similitud durante el razonamiento (patrón RAG sobre su propio conocimiento).
super().__init__(
*args,
local_kb=True,
kb_embedding_model="sentence-transformers/all-mpnet-base-v2",
kb_dimension=768, # Porygon usa 768; el default del framework es 384
...
)
Qué indexa y cómo¶
- Origen: ficheros markdown/texto en
AGENTS_DIR/<agent_id>/kb/. Por ejemplo, Porygon tieneagents/porygon/kb/forecasting.md; TROC Finance,agents/troc_finance/kb/con guías de marca, etc. Son guías de consultas, ejemplos de uso de herramientas y procedimientos de dominio. - Carga (
LocalKB.load_documents): trocea cada fichero respetando los encabezados markdown y los bloques de código (chunk_size=4096,overlap=100), genera embeddings y los indexa. - Índice FAISS:
LocalKBusa por defecto un índice HNSW con distancia coseno (vectores normalizados). ElFAISSStoresoportaFlat,IVFyHNSW. El índice se cachea a disco (.kb_cache.faiss) y se detecta el cambio de ficheros por fecha de modificación. - Configuración:
local_kb(bool),kb_embedding_model(modelo HuggingFace),kb_dimension(384 o 768).
Cómo se usa en el razonamiento¶
Durante ask(), _build_kb_context(question, ...) activa las KBs elegibles (la KB
local es always_active=True), ejecuta kb.search(query, k=5, score_threshold=0.5),
formatea los fragmentos relevantes y los inyecta en el system prompt. Así el
agente razona con su conocimiento de dominio sin latencia de servicios externos y de
forma consistente.
Nota: el
local_kb(KB de markdown del agente) es distinto del backend FAISS de la memoria episódica y del índice FAISS del registro de skills, aunque los tres usan FAISS + sentence-transformers. Son tres almacenes vectoriales con propósitos diferentes: conocimiento de dominio, experiencias pasadas y procedimientos reutilizables.
9. Resumen general de capacidades y potencial¶
Un agente tipo PandasAgent con todo el stack de AI-Parrot integrado se comporta como un analista de datos autónomo y con memoria, que opera sobre datos sensibles sin sacarlos a la nube. Resumen de capacidades:
Datos y análisis (DatasetManager + PandasAgent)¶
- Catálogo unificado sobre BigQuery, Postgres, MySQL, Mongo, Iceberg, Delta Lake, Airtable, Smartsheet, QuerySource, SQL parametrizado, ficheros y DataFrames.
- Carga perezosa: el LLM ve esquemas, tipos, estimaciones de tamaño y guías
do/dont, pero nunca filas crudas. - Toda la transformación pesada ocurre localmente en pandas (REPL); a la nube solo viajan código y resúmenes finales.
- Datasets nuevos en caliente, columnas calculadas, joins compuestos, forecasting con Prophet, controles de calidad de datos.
Procedimientos y aprendizaje (Skills + Memoria episódica)¶
- Skills: procedimientos reutilizables en markdown, con triggers
/comando, versionado tipo Git, búsqueda semántica, e incluso ejecución de código (skills compuestas concompute.py). El agente puede aprender skills nuevas. - Memoria episódica: recuerda éxitos y fallos, reflexiona sobre ellos e inyecta avisos ("errores a evitar") en futuras respuestas, mejorando con el uso.
Trabajo de varios pasos (Working Memory + WhatIf)¶
- Working Memory: almacena resultados intermedios entre pasos sin saturar el contexto, con un DSL declarativo y seguro de 13 operaciones.
- WhatIf: simula escenarios hipotéticos (excluir, escalar, ajustar) con objetivos y restricciones, optimización greedy/genética, y compara escenarios — todo local.
Comunicación de resultados (Infographic Toolkit)¶
- Genera infografías HTML (9 plantillas, 15 bloques, 12 tipos de gráfico, 4 temas, pestañas multi-tab) directamente desde los DataFrames del agente, con persistencia como artefactos y modo enhance opcional con interactividad JS segura.
Conocimiento de dominio (Local KB con FAISS)¶
- RAG sobre el conocimiento propio del agente (markdown indexado en FAISS), inyectado en el prompt para respuestas consistentes y con baja latencia.
Potencial combinado¶
| Escenario | Cómo lo resuelve el agente |
|---|---|
| "¿Cómo está Phoenix?" (Porygon) | DatasetManager materializa KPIs agregados → pandas los cruza → memoria episódica avisa de errores previos → infografía dashboard. |
| "Compara presupuesto vs real de EBITDA" (TROC) | Skill /ebitda_breakdown guía el cálculo → Working Memory guarda intermedios → WhatIf simula recortes → infografía financial_variance. |
| "¿Y si cerramos 2 almacenes?" | WhatIf aplica acciones de exclusión/escalado sobre datos locales, respeta restricciones y devuelve impacto comparado. |
| Análisis recurrente | Las skills capturan el procedimiento; la memoria episódica retiene lecciones; la KB local fija el conocimiento de dominio. |
Principio rector: capacidad analítica de nivel experto + privacidad por diseño — los datos crudos se procesan in our end, y solo descripciones, código y resúmenes agregados llegan al LLM en la nube.