De erizo a telaraña: rediseñar un cerebro de notas para agentes


22 de junio de 2026

Tengo un "tercer cerebro": una base de conocimiento en org-roam, replicada entre varias máquinas, donde voy guardando lo que aprendo. Nació como un Zettelkasten humano —nota larga, enlaces a mano—. Pero ha pasado una cosa: ya casi solo lo alimenta y lo recorre una IA. El humano mete cuatro notas; el agente vive ahí.

Así que toca rediseñarlo para lo que de verdad es ahora: un sustrato para agentes. Este es el plan, en tres partes —lo que tenemos, lo que queremos, y cómo llegar—. Lo escribo antes de tocar nada, a propósito.

Lo que tenemos

Una auditoría honesta del grafo, hoy:

¿Conclusión? Funciona para un humano que mete cuatro notas y tira de la memoria. No funciona para una IA, que necesita recorrer conexiones para que el conocimiento aflore solo. La disciplina de re-enlazar cada nota nueva con las viejas es justo lo que mata a todos los segundos cerebros humanos: nadie la mantiene. Pero un agente sí puede.

Lo que queremos

Dos capas

La síntesis de la IA es interpretativa y puede equivocarse; por eso la fuente no se tira nunca. El humano navega la fuente; el agente recorre los átomos. Nada se pierde.

Una telaraña, no un erizo

Enlaces nota↔︎nota de verdad, no solo índice→nota. La conectividad que una máquina puede mantener al día y un humano no.

Un vault privado, sin muros internos

El cerebro entero es privado por naturaleza. Así que dentro no hay distinción "público vs privado" —fuera esa etiqueta, una capa de complejidad menos—. Los dominios (áreas, sesiones) se quedan, pero solo como organización, no como muros: eso libera el enlazado cruzado, que es justo lo que le falta al grafo.

La única frontera de verdad se mueve fuera del cerebro: al acto de publicar (manual, con doble revisión, y cerrado por defecto). Y un eje aparte que no se relaja nunca: los secretos no entran jamás —un cerebro que se replica a varias máquinas no es sitio para credenciales; "privado" no es "seguro para secretos"—.

Ramas por sesión

Cada agente/sesión tiene su nodo raíz y su área, y enlaza libremente con las demás cuando un concepto hace de puente. Organización para que cada uno aflore lo suyo sin ruido del resto.

El motor: deduplicación por embeddings (local)

Esta es la pieza clave, y conviene entender qué es un embedding: convertir un texto en una lista de números (un vector) que captura su significado. Textos que significan lo parecido caen cerca en ese espacio; los distintos, lejos. Como coordenadas de sentido.

¿Para qué? Para no duplicar. Un buscador normal busca palabras: "el límite de 64KB" y "el tope del buffer" no se emparejan, aunque signifiquen lo mismo. Sus embeddings, sí. Así que antes de crear un átomo nuevo: lo paso a vector, busco si ya hay uno casi idéntico en el grafo, y si lo hay, enlazo en vez de duplicar. Sin esto, un grafo granular se pudre en mil casi-duplicados —el problema, no la solución—.

Y corre en casa: un modelo pequeño de embeddings sobre el hardware local, gratis y sin que el cerebro salga de la red. El mismo motor mejora el aflorado: recuerdas por significado, no por palabra clave.

El plan

Fase 1 — El motor de dedup (embeddings)

Modelo de embeddings local + un índice vectorial sobre los nodos + búsqueda semántica. Primero esto, porque atomizar sin deduplicar es construir el problema.

Fase 2 — El pipeline de ingesta (dos capas)

Entra un texto → la IA lo analiza y lo atomiza → cada átomo pasa por el dedup → se crean/actualizan nodo fuente + átomos concepto + sus enlaces. Granularidad con criterio: un nodo = una idea que querrías recordar o enlazar por separado.

Fase 3 — Migrar el grafo viejo (sin bulldozer)

Re-enlazar las hojas sueltas del erizo a sus hubs y entre sí, fusionar duplicados. Control de versiones como red de seguridad. Borrar solo basura real, y revisada antes. Un nodo suelto casi nunca es basura: es una buena nota que nadie enlazó. Se cura, no se arrasa.

Fase 4 — Aflorado por dominio + ramas

Recuperación filtrada por rama y por significado. Cada sesión, su raíz.

Por qué

La apuesta es simple: un cerebro que una máquina mantiene coherente. La disciplina que los humanos no sostienen —re-enlazar, deduplicar, destilar— una IA sí. Y a cambio, el conocimiento aflora en el momento justo, en el contexto, sin que se lo pidas. Eso es lo que separa un cajón de notas de un cerebro.

Esto es el plan. Lo revisamos, y le damos.

Fase 1, en directo: eligiendo el motor

(Este post crece mientras lo construyo. Aquí van las pruebas reales, no el cuento.)

Primer paso de la Fase 1: ¿qué modelo de embeddings usamos? Tenía Ollama corriendo, pero ninguno de embeddings instalado. Bajé el sospechoso habitual, nomic-embed-text, y le hice la prueba de fuego: ¿reconoce que dos frases distintas significan lo mismo, frente a una ajena?

La métrica es la separación: cuánto más cerca cae el "mismo concepto" que el "concepto distinto" (una frase de recetas de tortilla, de control). Cuanto mayor la separación, mejor discrimina el modelo.

modelo mismo concepto distinto (tortilla) separación
nomic-embed-text 0.567 0.552 +0.015
nomic-embed-text + prefijo 0.653 0.619 +0.035
bge-m3 (multilingüe) 0.502 0.257 +0.245

El resultado es contundente, y esconde una trampa que casi me como: nomic apenas distingue. +0.015 es ruido puro; con su prefijo de tarea recomendado sube a +0.035, y sigue siendo malo. ¿Por qué? Porque nomic está entrenado en inglés, y el cerebro está en español. Le pides distinguir conceptos en castellano y se encoge de hombros.

bge-m3, multilingüe, separa siete veces mejor: el mismo concepto a 0.50, la tortilla a 0.25, un abismo limpio entre medias. Ese es el motor.

La lección, anotada con sangre: el modelo de embeddings tiene que hablar tu idioma. El que sale por defecto en todos los tutoriales es una trampa si no escribes en inglés. Una hora de pruebas te ahorra un cerebro que no sabe deduplicar.

Siguiente paso: indexar los ~150 nodos reales con bge-m3 y sacar los clusters de casi-duplicados de verdad. Sigo.

Fase 1: el motor, sobre datos reales

Indexados los ~150 nodos del grafo con bge-m3 y comparados todos contra todos (un vector por nodo, coseno de cada par). El motor encontró los duplicados reales él solo:

par coseno qué es
alacritty ↔︎ alacritty 0.974 duplicado casi exacto, a fusionar
haskell ↔︎ Haskell 0.849 variante de mayús/minús, a unir
LLM ↔︎ "IA / LLM (índice)" 0.768 una hoja que debe colgar de su índice

Y dos hallazgos que no esperaba:

  1. Los nodos índice se parecen entre sí (0.85–0.89 entre ellos): comparten el "esto es un mapa de contenido", así que el motor los ve casi gemelos. Lección: el dedup debe excluir los índices — son hubs distintos a propósito.
  2. Los nodos-stub finos se agrupan por genéricos: notas de una línea sobre temas técnicos caen juntas porque tienen poco contenido propio que las distinga. Es, gratis, un detector de nodos demasiado delgados — justo los que la capa atómica va a engordar.

O sea: el motor no solo deduplica, es un diagnóstico del grafo. Una hora de trabajo y ya sé qué fusionar, qué enlazar y qué nodos están anémicos. Siguiente: convertirlo en un comando que toda sesión use antes de crear un nodo, para que el grafo deje de duplicar en origen.

Fase 1, cerrada: el motor ya es un comando

El motor está cableado en la herramienta del cerebro: similar "<texto>" (¿ya existe esto?), dups (pares casi-duplicados) y reindex (incremental — solo re-embebe lo nuevo o cambiado, los 150 nodos en 54 segundos la primera vez, y cero las siguientes). Cada sesión lo usa antes de crear un nodo.

Y al probarlo en serio, una sorpresa que vale doble. similar "el daemon de emacs colgado al 100% de CPU" encontró el nodo exacto a 0.70. Pero similar "lenguaje funcional con mónadas" NO encontró el nodo «haskell», y «terminal por GPU» no encontró «alacritty». ¿Bug? No: esos nodos son stubs —solo el título, sin cuerpo—. Una nota que es la palabra "haskell" a secas no tiene significado que agarrar, así que embebe débil.

O sea: el motor no solo deduplica y aflora — delata los nodos anémicos. Sin quererlo, similar es un test de calidad: si una búsqueda descriptiva no encuentra un nodo que existe, ese nodo está demasiado flaco. Justo los que la Fase 2 va a engordar. El erizo tiene púas finas; toca darles carne.

Fase 1: hecha. El cerebro ya sabe decir "esto ya lo tienes". Siguiente: la capa de átomos.

Fase 3: barrido de duplicados

Con dups en la mano, la limpieza fue quirúrgica. El grafo escondía cuatro nodos redundantes: dos alacritty idénticos creados con un minuto de diferencia, un dropbox vacío junto al bueno, una copia accidental de un tutorial, y un stub de haskell sin enlazar al lado del que tenía cinco referencias. Todos eran stubs vacíos sin un solo enlace entrante — borrarlos no rompió nada. Cada borrado se revisó antes; cada cambio es un commit en git, por si acaso.

Grafo: 150 → 146 nodos, cero duplicados reales. Y lo elegante: los "duplicados" que quedan (wsl ↔︎ nix, =mysql=…) ya no son duplicados — son nodos anémicos que se parecen por flacos. El dedup terminó; lo que queda es darles carne. Y eso, darle cuerpo a lo que es solo un título, es justo la Fase 2.

Comparte este post:

Es tu post

Estas seguro? Esto no se puede deshacer.

Comentarios (0)

Sin comentarios todavia. Se el primero!

Deja un comentario