{"id":225,"date":"2026-01-30T20:27:29","date_gmt":"2026-01-30T20:27:29","guid":{"rendered":"https:\/\/elbrinner.com\/?p=225"},"modified":"2026-02-05T16:41:37","modified_gmt":"2026-02-05T16:41:37","slug":"bri-flow","status":"publish","type":"post","link":"https:\/\/elbrinner.com\/index.php\/2026\/01\/30\/bri-flow\/","title":{"rendered":"Bri Flow"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-large wp-image-226\" src=\"https:\/\/elbrinner.com\/wp-content\/uploads\/2026\/02\/briflow-1024x456.png\" alt=\"\" width=\"1024\" height=\"456\" srcset=\"https:\/\/elbrinner.com\/wp-content\/uploads\/2026\/02\/briflow-1024x456.png 1024w, https:\/\/elbrinner.com\/wp-content\/uploads\/2026\/02\/briflow-300x134.png 300w, https:\/\/elbrinner.com\/wp-content\/uploads\/2026\/02\/briflow-768x342.png 768w, https:\/\/elbrinner.com\/wp-content\/uploads\/2026\/02\/briflow-1536x684.png 1536w, https:\/\/elbrinner.com\/wp-content\/uploads\/2026\/02\/briflow-2048x912.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>Con la llegada de la IA, proyectos que antes eran inalcanzables a nivel individual hoy son posibles gracias a herramientas como github copilot. <strong>Bri Flow<\/strong> nace de una necesidad concreta: <strong>dise\u00f1ar flujos conversacionales fijos con l\u00f3gica compleja<\/strong>, integrables con agentes, formularios y sistemas RAG, manteniendo control, seguridad y extensibilidad. En este art\u00edculo explico c\u00f3mo lo hice, qu\u00e9 decisiones t\u00e9cnicas tom\u00e9<\/p>\n<h3>Motivaci\u00f3n y enfoque general<\/h3>\n<p><strong>Problema inicial<\/strong> Las herramientas cerradas que prob\u00e9 no encajaban: poca flexibilidad para l\u00f3gica avanzada, dif\u00edcil integraci\u00f3n con LLMs y RAG, y escasa capacidad para reutilizar subflujos. Adem\u00e1s, necesitaba que los flujos fueran <strong>deterministas y auditables<\/strong>.<\/p>\n<p><strong>Decisi\u00f3n clave<\/strong> Representar el flujo como <strong>JSON estructurado<\/strong>. Con ese contrato claro, cualquier backend puede interpretar y ejecutar la l\u00f3gica. Arquitectura y flujo de ejecuci\u00f3n<\/p>\n<p><strong>Componentes principales<\/strong><\/p>\n<ul>\n<li><strong>Editor visual<\/strong>: interfaz para crear nodos y conexiones; exporta JSON con la estructura del flujo.<\/li>\n<li><strong>Backend (.NET)<\/strong>: int\u00e9rprete del JSON, <em>expression engine<\/em>, funciones nativas, ejecuci\u00f3n de llamadas REST, integraci\u00f3n con agentes\/LLMs y gesti\u00f3n de sesiones.<\/li>\n<li><strong>Frontend<\/strong>: consume la API del backend; recibe JSON procesado que indica qu\u00e9 componente renderizar (bot\u00f3n, formulario, carrusel, mensaje, etc.).<\/li>\n<\/ul>\n<p><strong>Flujo de datos (conceptual)<\/strong> Editor \u2192 JSON \u2192 Backend (.NET interpreta y ejecuta) \u2192 Frontend (renderiza seg\u00fan JSON procesado) \u2192 Usuario. El backend mantiene la sesi\u00f3n del usuario, el estado del flujo y filtra contenido por idioma cuando procede.<\/p>\n<div><\/div>\n<h3>Idea central<\/h3>\n<p>Las <strong>expresiones no son c\u00f3digo externo<\/strong>: son cadenas definidas dentro del JSON que exporta el editor. El backend recibe ese JSON, extrae las expresiones y las <strong>eval\u00faa en tiempo de ejecuci\u00f3n<\/strong> contra el contexto de la sesi\u00f3n y las variables del flujo. Por eso fue necesario dise\u00f1ar un lenguaje\/expression engine propio: las expresiones deben ser <strong>flexibles<\/strong>, <strong>seguras<\/strong>, <strong>deterministas<\/strong> y <strong>controlables<\/strong> desde el backend.<\/p>\n<p><strong>Beneficios pr\u00e1cticos<\/strong><\/p>\n<ul>\n<li>Procesar listas devueltas por servicios REST directamente en el flujo.<\/li>\n<li>Evitar c\u00f3digo ad-hoc en cada integraci\u00f3n: la l\u00f3gica se define en expresiones dentro del JSON.<\/li>\n<li>Reutilizaci\u00f3n y trazabilidad: toda la l\u00f3gica queda en el flujo exportado.<\/li>\n<\/ul>\n<div><\/div>\n<h3>Ejemplos pr\u00e1cticos y fragmento JSON<\/h3>\n<p>A continuaci\u00f3n un ejemplo simplificado que ilustra c\u00f3mo se modela un flujo en JSON y c\u00f3mo se usan expresiones para controlar la ejecuci\u00f3n.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\">{\r\n    \"schema_version\": 2,\r\n    \"flow_id\": \"principal\",\r\n    \"version\": \"1.0.223\",\r\n    \"name\": \"principal\",\r\n    \"description\": \"Flujo  ejemplo\",\r\n   \"locales\":  [\"es\",\"pt\",\"en\"],\r\n   \"start_node\":  \"start\",\r\n   \"nodes\":  {\r\n       \"start\":  {\r\n          \"id\":  \"start\",\r\n          \"type\":  \"start\",\r\n          \"next\":  { \"flow_id\":  \"principal\",  \"node_id\":  \"response_1\" },\r\n           \"variables\": [\r\n              {  \"name\":  \"selected_button_button_1\", \"defaultValue\":  \"\",  \"isList\":  false }\r\n           ]\r\n      },\r\n       \"response_1\":  {\r\n          \"id\":  \"response_1\",\r\n          \"type\":  \"response\",\r\n          \"next\":  {  \"flow_id\": \"principal\",  \"node_id\":  \"agent_call_1\"  },\r\n          \"i18n\":  {\r\n             \"es\":  {  \"text\":  [\"hola\"] },\r\n              \"pt\":  {  \"text\": [\"oi\"]  },\r\n              \"en\":  { \"text\":  [\"hi\"]  }\r\n          }\r\n       },\r\n       \"agent_call_1\": {\r\n           \"id\": \"agent_call_1\",\r\n           \"type\": \"agent_call\",\r\n           \"next\": {  \"flow_id\":  \"principal\",  \"node_id\": \"button_1\"  },\r\n          \"save_as\":  \"agent_agent_call_1\",\r\n          \"model\":  {\r\n              \"provider\":  \"azure-openai\",\r\n             \"deployment\":  \"gpt-4o-mini\",\r\n              \"temperature\":  0.2,\r\n             \"max_tokens\":  800\r\n          }\r\n       },\r\n       \"button_1\":  {\r\n          \"id\":  \"button_1\",\r\n          \"type\":  \"button\",\r\n          \"save_as\":  \"selected_button_button_1\",\r\n          \"options\":  [\r\n             {  \"target\":  {  \"flow_id\": \"\",  \"node_id\":  \"end_1\"  }, \"label\":  \"Opci\u00f3n  1\",  \"value\": \"Opci\u00f3n  1\"  },\r\n              { \"target\":  {  \"flow_id\":  \"\", \"node_id\":  \"end_1\"  },  \"label\": \"Opci\u00f3n  2\",  \"value\":  \"Opcion 2\"  }\r\n          ]\r\n       },\r\n       \"end_1\":  { \"id\":  \"end_1\",  \"type\":  \"end\", \"next\":  null  }\r\n   }\r\n}\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p><strong>Ejemplo LINQ-like<\/strong> (expresi\u00f3n dentro del engine)<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\">itemsVar.where(x =&gt; x.active).select(x =&gt; x.id).orderBy(x =&gt; x)<\/pre>\n<p>&nbsp;<\/p>\n<p>La pieza final es el frontend: llama a la API y renderiza los componentes seg\u00fan la estructura del JSON recibido; el backend se encarga de procesar la informaci\u00f3n y devolverla lista para pintar, adaptando la respuesta a la sesi\u00f3n del usuario y al idioma seleccionado al iniciar el flujo.<\/p>\n<ul>\n<li><strong>Editor Bri Flow<\/strong>: <a href=\"https:\/\/elbrinner.com\/flow\/\"><span tabindex=\"0\" role=\"button\" data-url=\"https:\/\/elbrinner.com\/flow\/\" aria-label=\"https:\/\/elbrinner.com\/flow\/, esto le llevar\u00e1 a elbrinner.com\">https:\/\/elbrinner.com\/flow\/<\/span><\/a><\/li>\n<li><strong>C\u00f3digo fuente del editor<\/strong>: <a href=\"https:\/\/github.com\/elbrinner\/BRI-FLOW\"><span tabindex=\"0\" role=\"button\" data-url=\"https:\/\/github.com\/elbrinner\/BRI-FLOW\" aria-label=\"https:\/\/github.com\/elbrinner\/BRI-FLOW, esto le llevar\u00e1 a github.com\">https:\/\/github.com\/elbrinner\/BRI-FLOW<\/span><\/a><\/li>\n<\/ul>\n<div><\/div>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Con la llegada de la IA, proyectos que antes eran inalcanzables a nivel individual hoy son posibles gracias a herramientas como github copilot. Bri Flow nace de una necesidad concreta: dise\u00f1ar flujos conversacionales fijos con l\u00f3gica compleja, integrables con agentes, formularios y sistemas RAG, manteniendo control, seguridad y extensibilidad. En este art\u00edculo explico c\u00f3mo lo &#8230; <a title=\"Bri Flow\" class=\"read-more\" href=\"https:\/\/elbrinner.com\/index.php\/2026\/01\/30\/bri-flow\/\" aria-label=\"Leer m\u00e1s sobre Bri Flow\">Leer m\u00e1s<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[10],"tags":[83],"class_list":["post-225","post","type-post","status-publish","format-standard","hentry","category-net","tag-github-copilot"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/posts\/225","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/comments?post=225"}],"version-history":[{"count":6,"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/posts\/225\/revisions"}],"predecessor-version":[{"id":232,"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/posts\/225\/revisions\/232"}],"wp:attachment":[{"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/media?parent=225"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/categories?post=225"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/elbrinner.com\/index.php\/wp-json\/wp\/v2\/tags?post=225"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}