MVP desplegado: nef-bot-pilot (Widget de chat RAG para negocio)

Fecha: 2026-09-17. Stack: Cloudflare Workers + Workers AI + Vectorize + D1 + KV + Turnstile.

Producción

  • URL: https://nef-bot-pilot.nef.workers.dev (chat público) /admin (ingesta)
  • Widget Turnstile: nef-bot-pilot-widget (managed), sitekey 0x4AAAAAAE5wlYi026UKdjtW, dominios nef-bot-pilot.nef.workers.dev + localhost/[IP]
  • Secrets en Worker: TURNSTILE_SECRET, ADMIN_KEY
  • Copia local de secrets (gitignored): .env.local y .dev.vars en ~//llm-test-cf
  • Recursos: D1 nef-bot-pilot (id 052be1fb-…), KV NEF_BOT_KV (id 839883cb…), Vectorize nef-bot-vectors (1024d cosine)

Pitfalls aprendidos (evitar re-depurar)

  1. run_worker_first:true exige assets.binding — sin él, env.ASSETS no existe → 500.
  2. Workers AI requiere binding explícito "ai":{"binding":"AI"} en wrangler.jsonc — sin él, env.AI es undefined → excepción 1101.
  3. Assets resuelve pretty URLs: no reescribir / ni /admin; pasar el request tal cual a env.ASSETS.fetch(request).
  4. Streaming de chat (vía binding o REST): eventos SSE data: con chat.completion.chunk; el delta es choices[0].delta.content; [DONE] al final; usage aparece en el último evento. NO usar response (acumulado/ausente).
  5. El token OAuth de wrangler login no trae challenge-widgets.write; re-loguear con wrangler >=4.109 para wrangler turnstile widget create/get.
  6. wrangler con subcomando turnstile = el del proyecto (devDep 4.133.0); el global Homebrew (4.99.0) no lo trae.

Seguridad v1 (fail closed)

Turnstile siteverify server-side (action+hostname) · rate limit KV/IP/10min · presupuesto diario de tokens en D1 (~500k ≈ U$S 1/día) · score-gate retrieval >=0.45 → “no tengo info” sin gastar generación · contexto como datos no confiables en el prompt (anti injerencia) · ingesta solo con ADMIN_KEY (timing-safe) · CSP estricta, sin inline JS · sin fetching de URLs (cero SSRF) · CORS same-origin.

Pendiente

  • Prueba en navegador: Turnstile → ingest → chat RAG end-to-end.
  • Vars ajustables desde wrangler.jsonc: DAILY_TOKEN_BUDGET, RATE_LIMIT_PER_WINDOW, RETRIEVAL_MIN_SCORE, TOPK, BUSINESS_NAME, MAX_OUTPUT_TOKENS.

Guía de preparación de datos (añadida al /admin como details plegable)

Principios que dictan la guía (acordes a chunking ~900 chars + similitud coseno bge-m3 + “solo responde con contexto”):

  1. Respuestas completas y autocontenidas: cada frase se sostiene sola.
  2. Una idea por párrafo (3-6 líneas); el corte respeta párrafos.
  3. Escribir la pregunta como la diría el cliente, respuesta directa primero, luego detalle.
  4. Números completos en dígitos; sin “después/arriba”; el contexto no tiene orden.
  5. Evitar: contradicciones, fechas que caducan, “ver sección”/enlaces, jerga sin definir, tablas gigantes.
  6. Checklist previo + prueba rápida en chat tras subir. Nota: el dedupe es por hash del contenido — re-subir un doc editado cuenta como nuevo y deja cohabitando versiones.