Memoria del bot
El agente IA recuerda tres cosas: el historial de la conversación, los atributos del contacto y la memoria de la organización: una biblioteca de documentos que tú alimentas con archivos, notas escritas a mano y páginas web. Cada agente elige qué parte de esa biblioteca consulta, y antes de responder busca en ella los fragmentos que hablan de lo que preguntó el cliente.
Referencia completa de endpoints en Bot · Knowledge. Permisos: bot:read para consultar y buscar, bot:write para crear, editar o borrar fuentes, bot:ai-config para decidir qué documentos usa cada agente.
Cómo funciona (RAG en un minuto)
- Registras una fuente: un archivo, una nota o la URL de una página pública.
- Un worker extrae el texto, lo parte en fragmentos de ~700 tokens con solapamiento y genera un embedding por fragmento (
text-embedding-3-small, 1536 dimensiones). Los fragmentos también se indexan a texto completo en español. - El documento pasa de
PENDINGaREADY(oFAILEDcon un mensaje que dice qué corregir). - Cuando un cliente escribe, el agente busca los top-K fragmentos más relevantes entre los documentos que tiene asignados y se los pasa al modelo como contexto del negocio.
- Si lo que el cliente pregunta no está en la memoria, la consulta queda registrada como vacío de conocimiento para que lo cubras después.
Fuentes
| Fuente | Endpoint | Notas |
|---|---|---|
FILE | POST /organizations/{orgId}/bot/knowledge | Multipart: file + opcional title y tags (separados por coma). PDF, DOCX, TXT, MD y CSV, hasta 25 MiB. |
NOTE | POST …/bot/knowledge/notes PATCH …/bot/knowledge/notes/{id} | Texto escrito en el panel o por API (title, content en Markdown, tags). Al editar el contenido se vuelve a procesar. resolvesQuestionKey marca qué vacío cierra. |
URL | POST …/bot/knowledge/url | Página web pública (url, title, tags). Con syncEveryHours (1–720) se vuelve a leer sola; sin él, solo cuando la reproceses. |
# Archivo (multipart)
curl -X POST "https://api.mosend.dev/organizations/${ORG_ID}/bot/knowledge" \
-H "X-Api-Key: ${API_KEY}" \
-F "file=@politica-de-devoluciones.pdf" \
-F "title=Política de devoluciones" \
-F "tags=soporte,devoluciones"
# Nota escrita a mano
curl -X POST "https://api.mosend.dev/organizations/${ORG_ID}/bot/knowledge/notes" \
-H "X-Api-Key: ${API_KEY}" -H "Content-Type: application/json" \
-d '{
"title": "Horario de despachos",
"content": "Despachamos de lunes a viernes antes de las 3 p. m. Los pedidos del fin de semana salen el lunes.",
"tags": ["envios"]
}'
# Página web que se relee cada 24 horas
curl -X POST "https://api.mosend.dev/organizations/${ORG_ID}/bot/knowledge/url" \
-H "X-Api-Key: ${API_KEY}" -H "Content-Type: application/json" \
-d '{ "url": "https://tutienda.com/preguntas-frecuentes", "title": "FAQ del sitio", "syncEveryHours": 24 }'Los tres responden con el documento recién creado (status: "PENDING"). El procesamiento corre en segundo plano; consulta GET …/bot/knowledge/{id} hasta verlo en READY.
Estado de procesamiento y resincronización
PENDING→ en cola o procesándose.READY→ indexado y en uso (chunkCountdice cuántos fragmentos).FAILED→ no se pudo; el campoerrorexplica qué corregir (PDF escaneado, URL que no responde, tipo no permitido…).POST …/bot/knowledge/{id}/reprocessvuelve a extraer el texto y regenera los embeddings. Sirve para archivos y páginas por igual.- Las páginas con
syncEveryHourslas revisa un proceso cada hora: la que ya cumplió su intervalo se descarga de nuevo y solo se reprocesa si cambió el contenido (se compara un hash del texto). Si la página no cambió, no gasta embeddings. PATCH …/{id}/titleyPATCH …/{id}/tagsrenombran y re-etiquetan sin reprocesar.DELETE …/{id}borra fragmentos, vectores y el archivo.
Qué agente consulta qué
La biblioteca es de la organización; cada agente decide qué parte lee con knowledgeDocIds en POST/PATCH /organizations/{orgId}/bot/agents — en el panel son casillas por documento.
- Vacío → el agente consulta toda la biblioteca.
- Con ids → solo esos documentos, sin importar sus etiquetas.
knowledgeTags(el mecanismo anterior, por etiqueta) sigue funcionando, pero con menor precedencia: si el agente tieneknowledgeDocIds, las etiquetas no se miran.
curl -X PATCH "https://api.mosend.dev/organizations/${ORG_ID}/bot/agents/${AGENT_ID}" \
-H "X-Api-Key: ${API_KEY}" -H "Content-Type: application/json" \
-d '{ "knowledgeDocIds": ["<docId-devoluciones>", "<docId-faq>"], "knowledgeTopK": 5, "knowledgeMinSimilarity": 0.3 }'knowledgeTopK (default 5) es cuántos fragmentos entran al contexto por turno; knowledgeMinSimilarity (default 0.3) el parecido mínimo para usar uno. Ambos se fijan por agente.
Cómo recupera: búsqueda híbrida
La recuperación combina dos rankings sobre los mismos fragmentos y los fusiona con Reciprocal Rank Fusion:
- Parecido semántico: distancia coseno entre el embedding de la pregunta y el de cada fragmento (pgvector). Entiende sinónimos y paráfrasis.
- Palabras exactas: texto completo en español (
tsvector). Encuentra un código de producto, un nombre propio o una sigla que el embedding diluye.
Un fragmento hallado por palabra exacta (porTexto: true) se usa aunque su parecido quede por debajo de knowledgeMinSimilarity: si el cliente escribe la referencia exacta, el bot la encuentra aunque el resto de la frase no se parezca a nada del documento.
Probar la búsqueda
POST /organizations/{orgId}/bot/knowledge/searchejecuta exactamente la misma consulta que hace el bot antes de responder. Úsalo para comprobar qué vería el agente ante una pregunta, o como "buscar en el conocimiento de la empresa" desde tu propio sistema.
curl -X POST "https://api.mosend.dev/organizations/${ORG_ID}/bot/knowledge/search" \
-H "X-Api-Key: ${API_KEY}" -H "Content-Type: application/json" \
-d '{ "query": "¿cuánto tarda una devolución?", "topK": 5, "tags": ["soporte"], "minSimilarity": 0.3 }'
# Respuesta (200)
{
"data": {
"results": [
{
"docId": "…",
"title": "Política de devoluciones",
"content": "El reembolso se procesa en 5 a 8 días hábiles desde que recibimos el producto…",
"similarity": 0.61,
"porTexto": true
}
]
}
}topK1–20 (default 5).tagslimita a documentos con alguna de esas etiquetas.minSimilarity0–1 (default 0.3).- Sin documentos en
READYdevuelveresults: []sin gastar embedding. Cada búsqueda con documentos cuesta un embedding de la pregunta (se registra enAiUsage).
Vacíos de conocimiento (insights)
Cada vez que el bot busca en la memoria queda registrado qué preguntó, si encontró algo y qué documentos usó. GET /organizations/{orgId}/bot/knowledge/insights?dias=30 lo resume:
{
"data": {
"desde": "2026-08-08T…", "dias": 30,
"resumen": { "consultas": 412, "respondidas": 371, "sinRespuesta": 41, "tasa": 90, "documentos": 12, "documentosListos": 11 },
"vacios": [
{ "questionKey": "garantia-extendida", "question": "¿tienen garantía extendida?", "veces": 9,
"ultimaVez": "2026-09-06T…", "agentIds": ["…"], "agentes": ["Ventas"] }
],
"porAgente": [ { "agentId": "…", "nombre": "Ventas", "consultas": 300, "respondidas": 281 } ],
"documentos": [ { "id": "…", "title": "FAQ del sitio", "sourceType": "URL", "status": "READY", "useCount": 140, "lastUsedAt": "…", "usosEnPeriodo": 88 } ]
}
}vaciosagrupa las preguntas que se quedaron sin respuesta por su forma normalizada (questionKey), con cuántas veces se repitió y qué agentes la recibieron.- Para cerrar un vacío, crea una nota con ese
resolvesQuestionKey: el grupo deja de aparecer y la próxima vez el bot ya tiene el dato. documentosordena la biblioteca por uso en el período: lo que nunca se usa es candidato a revisar o borrar.
Flujo típico
- Carga las fuentes base: el PDF de políticas, una nota con horarios y datos que cambian seguido, y la FAQ pública como URL con
syncEveryHours: 24. - Espera a que queden en
READY(GET …/bot/knowledge). Si alguna cae enFAILED, leeerrory corrígela. - Asigna documentos por agente con
knowledgeDocIds: soporte lee políticas y FAQ; ventas lee el catálogo. - Prueba con
POST …/bot/knowledge/searchlas 5 preguntas que más recibes. Si el fragmento correcto no aparece, reescribe esa parte del documento en lenguaje natural. - Cada semana revisa
GET …/bot/knowledge/insights?dias=7y cierra los vacíos con notas.
Formatos, límites y buenas prácticas
- PDF con texto seleccionable (no escaneado), DOCX, TXT/MD y CSV (cada fila se convierte en "Columna: valor · Columna: valor", ideal para listas de precios). Máximo 25 MiB por archivo.
- Páginas web: solo URLs públicas; se guarda el texto visible, sin menús ni scripts.
- Documentos cortos y temáticos funcionan mejor que un manual gigante: la recuperación es por fragmento, no por archivo.
- Una pregunta, una sección, en lenguaje natural: "El plazo de devolución es de 30 días" se recupera mejor que "Devol: 30d".
- Lo que cambia seguido va en notas: se editan sin volver a subir un archivo, y una nota con
resolvesQuestionKeycierra un vacío de una vez.
Errores típicos
- El PDF parece una imagen escaneada: no tiene texto seleccionable. Pásalo por OCR y vuelve a subirlo.
- El bot no usa mi documento: confirma que el agente tenga ese documento en
knowledgeDocIds(o la lista vacía), que el documento esté enREADY, y que el número esté en un modo con IA (AI_AGENToRULES_PLUS_AI_FALLBACK). Luego reproduce la pregunta con/search. - El bot dice cosas viejas: reprocesa el documento o, si es una página, revisa que tenga
syncEveryHours. - Quiero sacar un documento de un agente sin borrarlo: quítalo de sus
knowledgeDocIds; sigue disponible para los demás.
Costos
Procesar usa embeddings (text-embedding-3-small, USD 0.02 por millón de tokens); cada turno del bot y cada llamada a /search suman un embedding de la pregunta. Todo se cobra del saldo de la organización con el margen configurado y queda en AiUsage. Como referencia: 50 PDF de 10 páginas rondan USD 0.03 en total, una sola vez.