<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Reserhub Engineering]]></title><description><![CDATA[Reserhub Engineering]]></description><link>https://engineering.reservamos.tech</link><generator>RSS for Node</generator><lastBuildDate>Tue, 07 Apr 2026 20:03:13 GMT</lastBuildDate><atom:link href="https://engineering.reservamos.tech/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Mastering Architecture Decision Records for Software Teams]]></title><description><![CDATA[Mastering Architecture Decision Records for Software Teams
Introduction to Architecture Decision Records (ADRs)
In the fast-paced world of software development, making informed architectural decisions is crucial. How do teams track these decisions an...]]></description><link>https://engineering.reservamos.tech/mastering-architecture-decision-records-for-software-teams</link><guid isPermaLink="true">https://engineering.reservamos.tech/mastering-architecture-decision-records-for-software-teams</guid><category><![CDATA[ADRs]]></category><category><![CDATA[architecture]]></category><category><![CDATA[decision making]]></category><category><![CDATA[General Programming]]></category><category><![CDATA[software development]]></category><dc:creator><![CDATA[Raul Vega]]></dc:creator><pubDate>Fri, 05 Dec 2025 15:50:50 GMT</pubDate><content:encoded><![CDATA[<h1 id="heading-mastering-architecture-decision-records-for-software-teams">Mastering Architecture Decision Records for Software Teams</h1>
<h2 id="heading-introduction-to-architecture-decision-records-adrs">Introduction to Architecture Decision Records (ADRs)</h2>
<p>In the fast-paced world of software development, making informed architectural decisions is crucial. How do teams track these decisions and their long-term implications? Architecture Decision Records (ADRs) are the answer. Serving as a structured method for capturing significant decisions, ADRs help teams maintain a clear historical record of why certain architectural choices were made, who made them, and the consequences of those decisions. Originally popularized by Michael Nygard, ADRs not only aid in maintaining consistency and understanding architectural evolution but also enhance the onboarding process for new team members.</p>
<h2 id="heading-the-importance-of-adrs-in-software-development">The Importance of ADRs in Software Development</h2>
<p>ADRs play a pivotal role in software development by ensuring transparency and facilitating improved communication among team members and stakeholders. By documenting the context, decision, status, and consequences of architectural choices, ADRs help break down complex decisions into understandable components. This clarity is particularly beneficial when onboarding new team members, as it provides them with documented insights into past decisions, allowing them to quickly get up to speed with the project's architecture.</p>
<p>Furthermore, ADRs compel teams to explicitly consider the implications of their choices, leading to more informed decision-making. This practice is especially valuable for distributed teams, as ADRs serve as a communication tool that ensures everyone is aligned and informed about key architectural choices.</p>
<h2 id="heading-how-to-implement-adrs-effectively">How to Implement ADRs Effectively</h2>
<p>Implementing ADRs effectively requires understanding their key components and adhering to best practices for documentation. A typical ADR includes:</p>
<ul>
<li><p><strong>Context</strong>: The background information and circumstances leading to the decision.</p>
</li>
<li><p><strong>Decision</strong>: The actual choice made.</p>
</li>
<li><p><strong>Status</strong>: The current status of the decision (e.g., proposed, accepted, deprecated).</p>
</li>
<li><p><strong>Consequences</strong>: The outcomes, both positive and negative, of the decision.</p>
</li>
</ul>
<p>To maximize the benefits of ADRs, teams should ensure that the documentation is clear, concise, and consistently updated. It's also essential to involve all relevant stakeholders in the decision-making process and to document not just the decisions made, but also the alternatives considered.</p>
<h2 id="heading-tools-and-frameworks-supporting-adrs">Tools and Frameworks Supporting ADRs</h2>
<p>Several tools and frameworks are available to support the creation and management of ADRs. One popular option is MADR (Markdown Architecture Decision Records), which provides a straightforward template for documenting decisions. These tools streamline the ADR process, making it more efficient and less error-prone. By leveraging such tools, teams can ensure that their ADRs are well-organized and easily accessible, thereby enhancing their utility as a communication and documentation tool.</p>
<h2 id="heading-practical-examples-of-adr-implementation">Practical Examples of ADR Implementation</h2>
<p>To understand ADRs in action, consider a scenario where a software development team must decide between two database technologies. By using an ADR, the team documents the context of needing a scalable database solution, explores the decision to choose a NoSQL database over a traditional SQL database, and outlines the consequences, such as improved scalability but increased complexity. These records not only capture the rationale behind the decision but also guide future projects facing similar challenges.</p>
<p>Another example is the decision-making process for adopting a microservices architecture. An ADR can document the team's reasons for transitioning from a monolithic architecture, the expected benefits such as enhanced modularity, and the trade-offs like potential integration challenges. These documented decisions help clarify the team's strategic direction and provide insights for future architectural planning.</p>
<h2 id="heading-case-study-adr-usage-at-spotify">Case Study: ADR Usage at Spotify</h2>
<p>Spotify is an excellent example of a company that has successfully implemented ADRs to align their architectural decisions with business goals and technical constraints. By documenting their decisions in a structured manner, Spotify fosters a culture of well-informed decision-making and continuous learning. This approach not only ensures that architectural choices support business objectives but also improves team communication and collaboration.</p>
<h2 id="heading-challenges-and-considerations">Challenges and Considerations</h2>
<p>While ADRs offer numerous benefits, there are also challenges to consider. Common pitfalls include inadequate documentation, inconsistent updates, and lack of stakeholder involvement. To overcome these challenges, teams should establish clear guidelines for creating and maintaining ADRs. Regular reviews and updates can help keep the documentation relevant and useful, while stakeholder engagement ensures that all perspectives are considered.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In conclusion, Architecture Decision Records are an invaluable tool for software development teams looking to maintain a clear and detailed record of their architectural decisions. By providing transparency and facilitating better communication, ADRs help teams align their architectural choices with business goals and technical constraints. As more companies recognize the value of ADRs, they are likely to become a standard practice in software development, ensuring that architectural decisions are well-documented and easily accessible for future reference. To get started with ADRs, consider adopting a framework like MADR and involve your entire team in the documentation process. This proactive approach will set the foundation for a more informed and cohesive decision-making culture.</p>
<h3 id="heading-references">References</h3>
<p><a target="_blank" href="https://github.com/joelparkerhenderson/architecture-decision-record">Architecture Decision Record - Joel Parker Henderson</a></p>
<p><a target="_blank" href="https://adr.github.io/madr/">MADR - Markdown Architectural Decision Records</a></p>
<p><a target="_blank" href="https://www.ozimmer.ch/practices/2023/04/03/ADRCreation.html">How to create ADRs — and how not to - Olaf Zimmermann</a></p>
<p><a target="_blank" href="https://engineering.atspotify.com/2020/04/when-should-i-write-an-architecture-decision-record">When Should I Write an Architecture Decision Record - Spotify Engineering</a></p>
]]></content:encoded></item><item><title><![CDATA[Git Integration Techniques]]></title><description><![CDATA[Git, the widely used version control system, offers several powerful tools for managing code changes and collaboration within a project. Among the most commonly used features are merge, rebase, and squash. Understanding these operations is essential ...]]></description><link>https://engineering.reservamos.tech/git-integration-techniques</link><guid isPermaLink="true">https://engineering.reservamos.tech/git-integration-techniques</guid><category><![CDATA[Git]]></category><category><![CDATA[integration]]></category><dc:creator><![CDATA[Diego Bugs]]></dc:creator><pubDate>Thu, 13 Jun 2024 15:00:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1718056005981/ef66c51c-359d-4576-81bd-519772920987.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Git, the widely used version control system, offers several powerful tools for managing code changes and collaboration within a project. Among the most commonly used features are merge, rebase, and squash. Understanding these operations is essential for maintaining a clean and efficient Git workflow.</p>
<h2 id="heading-git-merge-integrating-changes"><strong>Git Merge: Integrating changes</strong></h2>
<p>When you merge a branch into another, Git combines the changes made in the source branch into the target branch. This creates a new commit in the target branch, representing the merge. Merge commits are often visible in the commit history, which can make the history a bit more cluttered but also more accurately reflects the history of changes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718054826355/aa37cf66-883f-4b21-9483-21c59e7eb850.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-git-rebase-streamlining-commit-history"><strong>Git Rebase</strong>: Streamlining commit history</h2>
<p>When you rebase a branch onto another branch, Git takes the changes in the source branch and reapplies them on top of the target branch. This essentially rewrites the commit history of the source branch to appear as if the changes were made directly on top of the target branch. Rebase results in a cleaner and linear commit history, but it can rewrite history, which can cause issues if the branch is shared or already pushed to a remote repository.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718054845666/a0835a26-9dbf-4a47-8cb1-25c73ae53dfe.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-git-squash-consolidating-commits"><strong>Git Squash</strong>: Consolidating commits</h2>
<p>Squashing commits is a technique to combine multiple commits into a single commit. This is often used before merging or rebasing to tidy up the commit history and make it more cohesive. Squashing can be useful to keep the commit history clean and concise, especially for feature branches where multiple small commits might not be necessary or desirable in the main branch's history.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1718054861120/d8616d4e-5c4e-405e-86fa-52998dd5336b.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-choosing-the-right-approach">Choosing the right approach</h2>
<p>The choice between merge, rebase, and squash depends on various factors, including project workflow, collaboration practices, and personal preferences. While merge is straightforward and preserves the original commit history, rebase and squash offer ways to create a cleaner, more streamlined history. However, it's crucial to consider the potential impact on collaboration and repository history when deciding which approach to use.</p>
<p>One common problem with rebase is the potential to rewrite commit history. When developers rebase their branches onto a common base branch, it alters the commit IDs and effectively creates new commits. While this can result in a cleaner commit history, it can also introduce confusion and conflicts, especially if other team members have already based their work on the original commits. Mismanaged rebases can lead to divergent branches and difficulties in reconciling changes.</p>
<p>Similarly, squash commits, while useful for tidying up a feature branch's history, can also obscure important details about the development process. When multiple commits are squashed into one, the individual changes and their respective messages are lost. This can make it harder to track down specific changes or understand the rationale behind them, especially when reviewing code or diagnosing issues in the future.</p>
<p>Ultimately, the key to avoiding these common problems lies in communication and collaboration within the development team. Developers should be transparent about their intentions when using Git operations like rebase and squash, and they should be mindful of the potential impact on shared branches and commit history. By following best practices and coordinating effectively, teams can harness the full power of Git while minimizing the risk of introducing unnecessary complexity or confusion.</p>
]]></content:encoded></item><item><title><![CDATA[Taking advantage of Flow State]]></title><description><![CDATA[The first software company I worked for had a space where any team member could give a talk about any topic they wanted.
One day, someone gave a talk about The 5AM Club book, in which the idea is to help you create a 1-hour morning routine that enabl...]]></description><link>https://engineering.reservamos.tech/taking-advantage-of-flow-state</link><guid isPermaLink="true">https://engineering.reservamos.tech/taking-advantage-of-flow-state</guid><category><![CDATA[lifestyle]]></category><category><![CDATA[flow]]></category><category><![CDATA[Inspiration]]></category><category><![CDATA[mentalhealth]]></category><category><![CDATA[translation]]></category><dc:creator><![CDATA[Alan Morales]]></dc:creator><pubDate>Thu, 25 Apr 2024 17:50:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1714068032805/9039d5b8-b37e-4955-88aa-faf3811e56f9.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The first software company I worked for had a space where any team member could give a talk about any topic they wanted.</p>
<p>One day, someone gave a talk about The 5AM Club book, in which the idea is to help you create a 1-hour morning routine that enables you to be more productive during your day. The suggested routine is:</p>
<ul>
<li><p>Do 20 minutes of exercise.</p>
</li>
<li><p>Do 20 minutes of meditation.</p>
</li>
<li><p>Take the last 20 minutes to learn something.</p>
</li>
</ul>
<p>I was curious, so I decided to try it out.</p>
<p>After a week, I was finding myself being more productive, but not only that, I was also enjoying more my work.</p>
<p>I got a certain feeling of <em>being present</em> that reminded me of the times when I'm outside taking pictures and get so focus, that I eventually end up forgetting about the <em>real world</em>, and I would just observe everything, thinking about what my next photo should be and how I was going to compose it.</p>
<p>To give you an example, I can tell you about the time I went to the beach with some friends, I remember being on the seashore, and in the matter of seconds, I turned left and saw the sun, the shadows, and as I began to feel the light, the time began to slowdown, I could only hear the waves, a seagull, and a kid running into the sea. All I saw was silhouettes, and a clear image taking shape in my head. Finally, I raised my phone, and took the picture.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1703395289648/3b3de78c-f923-482d-848f-49641e30a811.jpeg?auto=compress,format&amp;format=webp" alt="https://cdn.hashnode.com/res/hashnode/image/upload/v1703395289648/3b3de78c-f923-482d-848f-49641e30a811.jpeg?auto=compress,format&amp;format=webp" /></p>
<p>I used to call this phenomenon <em>photography mood</em>. However, I discovered a term that describes exactly what that <em>being present</em> feeling is.</p>
<h2 id="heading-the-flow-state"><strong>The Flow State</strong></h2>
<p>I read about this term in Sarah Drasner's article <a target="_blank" href="https://leaddev.com/culture-engagement-motivation/why-flow-matters-more-passion"><strong><em>Why flow matters more than passion</em></strong></a> where she describes it as follow:</p>
<blockquote>
<p>The phenomenon in which a person is fully immersed in an activity that leads to focus, energized involvement, and enjoyment. A person in flow state is no longer thinking of multiple things, or even their sense of self, but is singularly focused on a task or challenge.</p>
</blockquote>
<p>In my journey into the tech world, I've learnt to take advantage of the flow state, I see a lot of benefits in it.</p>
<ul>
<li><p><strong>Solve complex problems</strong>: When in <em>flow</em>, complex problems seem easier than they really are.</p>
</li>
<li><p><strong>Keep myself motivated</strong>: There is something about the <em>flow state</em> that generates motivation when the <em>flow</em> is consistent. Better yet, this motivation last longer, it is intrinsic motivation.</p>
</li>
<li><p><strong>Work Smarter</strong>: When in <em>flow</em>, I might end a task that would normally take me a whole day in three or four hours. This allows me to use the remaining time to:</p>
<ul>
<li><p>Rest from work.</p>
</li>
<li><p>Learn.</p>
</li>
<li><p>Improve the result of my task.</p>
</li>
<li><p>Work on contributions outside my role.</p>
</li>
</ul>
</li>
</ul>
<p>This, far from seeing it as stolen time from my company, I see it in a way in which I can generate more impact and improve the way people in the company see me.</p>
<p>Although this <em>flow</em> thing sounds good, it's not a switch you can get on and off whenever you want, but I think you can train your mind in a way that you can get into <em>flow state</em> in a more consistent way.</p>
<h3 id="heading-generative-mental-spaces"><strong>Generative Mental Spaces</strong></h3>
<p><em>Flow state</em> happens when the subconscious mind takes over. If we want to enter <em>flow state</em> more often, we need to practice turning off our conscious mind and we need to do this consistently.</p>
<p>One way to do this is to create spaces in your day/week where you have no agenda, no pressure of accomplish something. These spaces are called <em>Generative Mental Spaces,</em> and they need to meet certain characteristics:</p>
<ul>
<li><p>They have no agenda, no pressure of accomplish something.</p>
</li>
<li><p>It needs to be an activity in which your subconscious mind works more than your conscious mind.</p>
</li>
<li><p>You need to do this consistently (make it a habit).</p>
</li>
</ul>
<p>For example, my go to space is to take pictures. This space is normally me walking around observing and taking pictures without a goal and I tend to do it once a week.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1709416006150/8691cc2a-e80c-4302-b7cc-d21a2fd292bf.png?auto=compress,format&amp;format=webp" alt="https://cdn.hashnode.com/res/hashnode/image/upload/v1709416006150/8691cc2a-e80c-4302-b7cc-d21a2fd292bf.png?auto=compress,format&amp;format=webp" /></p>
<h3 id="heading-transitions"><strong>Transitions</strong></h3>
<p>It is important that you let your mind and body know that you're entering an activity that requires you to be present. We need a way to transition from the world into our activity, this will help us to be present, and (hopefully) trick your mind into <em>flow</em>.</p>
<p>These transitions are little activities that you do before your main activity, and they have the following characteristics:</p>
<ul>
<li><p>They take no more than, let's say 20 minutes.</p>
</li>
<li><p>They help you being present and clean the noise in your mind.</p>
</li>
<li><p>You do them before your main activity, every time.</p>
</li>
</ul>
<p>For example, before starting a drama class we do an exercise called <a target="_blank" href="https://bbbpress.com/2013/02/exploring-the-space/"><strong><em>exploring the space</em></strong></a><em>(</em><a target="_blank" href="https://www.artemanteatro.com/post/por-qu%C3%A9-y-para-qu%C3%A9-caminar-por-el-espacio"><strong><em>caminar por el espacio</em></strong></a><em>)</em>, which consist of the group walking around the classroom while trying to have a balanced space between each person. During this exercise, the teacher instructs us to relax, breath and walk at different paces and levels. This transition allows us to leave the world behind and be present for the rest of the class.</p>
<p>In my day to day, a common <em>transition</em> activity is to clean my house/room/desk, depending on the day. After cleaning, I take a shower and then I start working.</p>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>I see the <em>Flow State</em> as a powerful tool to be better in my job. Unfortunately, is not a switch I can get on and off whenever I need it. This is why I've identified two strategies that help me get into Flow State more often:</p>
<ul>
<li><p>Generative Mental Spaces</p>
</li>
<li><p>Transitions</p>
</li>
</ul>
<p>By applying those strategies in my life, I'v been able get good results in my work. I'm still generating more ideas around this, so these are just my conclusions until now.</p>
<p>However, I hope you find these ideas useful, and if you do, let me know. :)</p>
]]></content:encoded></item><item><title><![CDATA[LangGraph con Multi-Agente]]></title><description><![CDATA[Durante el desarrollo de nuestro chatbot, hemos añadido varias funcionalidades. Inicialmente, solo generaba una URL para que el usuario pudiera visualizar los viajes disponibles según sus necesidades (a lo que nos referiremos como URL de viaje). Ahor...]]></description><link>https://engineering.reservamos.tech/langgraph-con-multi-agente</link><guid isPermaLink="true">https://engineering.reservamos.tech/langgraph-con-multi-agente</guid><category><![CDATA[langchain]]></category><category><![CDATA[chatbot]]></category><category><![CDATA[Developer]]></category><category><![CDATA[AI]]></category><dc:creator><![CDATA[Edgar Aguilar]]></dc:creator><pubDate>Thu, 11 Apr 2024 15:00:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1713192462101/73e6d07f-f828-4af0-9b17-cbdef8b37a7c.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Durante el desarrollo de nuestro chatbot, hemos añadido varias funcionalidades. Inicialmente, solo generaba una URL para que el usuario pudiera visualizar los viajes disponibles según sus necesidades (a lo que nos referiremos como URL de viaje). Ahora, también puede responder preguntas sobre los viajes disponibles, atender consultas sobre reservamos utilizando la información de la página web y generar una URL de información sobre cualquier compra realizada por el usuario.</p>
<p>Para lograr lo anterior, utilizamos un <strong>Agente</strong> de <a target="_blank" href="https://python.langchain.com/docs/get_started/introduction"><strong>Langchain</strong></a> que nos facilita la implementación y el uso de los modelos de <strong>OpenAI</strong>, así como los que estén disponibles. Este es muy útil para aplicaciones muy sencillas. Sin embargo, existen algunas problemáticas cuando se implementan más funcionalidades y el proyecto crece.</p>
<p>La problemática principal es que ahora el chatbot tiene varias funcionalidades y tiene que decidir cómo actuar dependiendo de lo que el usuario pide, disminuyendo su eficiencia al momento de responder. Nosotros, como desarrolladores, no podemos involucrarnos mucho en la manera en la que el agente toma decisiones.</p>
<p>Para intentar solucionar este problema, utilizamos <strong>LangGraph</strong>, una nueva herramienta que el equipo de <strong>LangChain</strong> desarrolló.</p>
<h1 id="heading-que-es-langgraph">¿Qué es LangGraph?</h1>
<p>Hace unos días, el equipo de LangChain anunció <a target="_blank" href="https://blog.langchain.dev/langgraph/">LangGraph</a>. El <strong>objetivo</strong> de este es brindar al desarrollador un mayor <strong>control sobre el ciclo de ejecución de un Agente,</strong> pero con el uso de un grafo. Para lograrlo, se utilizan 3 elementos principales: <strong>stateGraph, Nodes</strong> y <strong>Edges.</strong></p>
<p>Donde en el <strong>StateGraph</strong> se define el estado del grafo que va a viajar y mutar durante el ciclo de ejecución. Los <strong>Nodes</strong> se definen con un nombre y su función a ejecutar, y los <strong>Edges</strong> se encargan de conectar los nodos.</p>
<p>Los <strong>Edges</strong> se dividen en 3 grupos:</p>
<ul>
<li><p><strong>The Starting Edge:</strong> Edge que conecta el inicio del grafo con un nodo en particular.</p>
</li>
<li><p><strong>Normal Edges:</strong> Edges donde un nodo siempre se ejecuta después de otro.</p>
</li>
<li><p><strong>Conditional Edges:</strong> Edge donde se utiliza una función para determinar qué nodo será el siguiente en ejecutarse cuando existen varias conexiones.</p>
</li>
</ul>
<p>Existen diferencias entre un <strong>Agente</strong> de <strong>LangChain</strong> y una <strong>implementación</strong> de <strong>LangGraph</strong>. La principal diferencia es que <strong>LangGraph</strong> expone parte de la lógica interna de un <strong>AgentExecutor</strong>. Una funcionalidad notable es que se puede definir un <strong>nodoprincipal</strong> que siempre se va a ejecutar al inicio del proceso. Esto hace que el <strong>Agente</strong> ya no sea 100% autónomo, por lo que el equipo de <strong>LangChain</strong> decidió nombrar la implementación del grafo como una <strong>State Machine</strong>. Donde se combina la autonomía del <strong>Agente</strong> con instrucciones específicas que el <strong>desarrollador</strong> puede definir.</p>
<p>Por ejemplo, tal vez quieras:</p>
<ul>
<li><p>Forzar al <strong>agente</strong> a que ejecute una <strong>tool</strong> en específico primero.</p>
</li>
<li><p>Tener mas control en como se van a ejecutar las <strong>tools</strong>.</p>
</li>
<li><p>Tener diferentes <strong>prompts</strong> para el <strong>agente</strong>, dependiendo en el estado en que se encuente.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710957391131/4833a0c3-621d-4e6e-ac2e-02489dbb2e64.png" alt class="image--center mx-auto" /></p>
<h1 id="heading-implementacion">Implementación</h1>
<h2 id="heading-single-agent">Single Agent</h2>
<h3 id="heading-replicando-el-funcionamiento-del-chatbot-de-langchain">Replicando el funcionamiento del <strong>chatbot</strong> de <strong>LangChain</strong></h3>
<p>Traduciendo la lógica de nuestro <strong>chatbot</strong> usando un <strong>AgentExecutor</strong> de <strong>LangChain</strong> a <strong>LangGraph</strong>, la implementación queda de la siguiente manera:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710957483363/b6b80f12-11ec-4be9-92a5-b45ce9587bd5.png" alt class="image--center mx-auto" /></p>
<p>En el diagrama podemos observar los siguientes elementos:</p>
<p><strong>Nodos:</strong><code>Agent</code>, <code>action</code>, <code>last_agent</code> y <code>END</code></p>
<p>El nodo <code>Agent</code> recibe el input del usuario y decide si necesita ejecutar alguna <strong>tool</strong> para realizar la tarea o si debe finalizar el proceso.</p>
<p>El nodo <code>action</code> se encarga de ejecutar las <strong>tools</strong> y devolver el <strong>output</strong> las veces que sean necesarias.</p>
<p>El nodo <code>last_agent</code> guarda la respuesta final en la base de datos antes de finalizar el proceso. Es importante mencionar que sin este nodo, el agente enviaría el mensaje directamente al nodo <code>END</code> para terminar el proceso y responder al usuario.</p>
<h3 id="heading-modificaciones-al-proceso-de-ejecucion">Modificaciones al proceso de ejecución</h3>
<p>Un reto al que nos enfrentamos utilizando un <strong>agente</strong> de <strong>LangChain</strong> es indicar qué tools se deben ejecutar al momento de recibir la petición del usuario. Por ejemplo:</p>
<p><strong>Input del usuario:</strong> Quiero viajar de Mérida a CDMX el 22 de febrero de 2024.</p>
<p>Para esta petición necesitamos varios elementos para generar la URL de viaje con las especificaciones del usuario. Necesitamos: origen, destino, fecha de salida, fecha de regreso y número de pasajeros.</p>
<p>La manera en que obtenemos estos parámetros es con una <strong>tool</strong> llamada <strong>params_extractor</strong> y esta debe ejecutarse al principio del ciclo. El problema es que el <strong>agente</strong>, al ser 100% <strong>autónomo,</strong> únicamente delimitado por el prompt del sistema, no siempre ejecuta esta <strong>tool</strong> y puede ocurrir un error al consultar los viajes y generar la URL.</p>
<p>Aprovechando que <strong>LangGraph</strong> te permite involucrarte en el proceso de ejecución, una modificación interesante, como antes se mencionó, es forzar al <strong>agente</strong> a primero ejecutar una <strong>tool</strong> al principio del proceso. Quedando de la siguiente manera:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710957557184/09a705d3-1f13-4f76-bb12-d31e72ce6229.png" alt class="image--center mx-auto" /></p>
<p>En el diagrama se puede observar que hay un nuevo <strong>nodo,first_agent,</strong> que se comunica directamente con <strong>action</strong> para forzar la ejecución de la <strong>tool params_extractor</strong> y después seguir con el proceso. Con esto resolvemos el problema. Esta solución es ideal en el caso de que el chatbot solo sea capaz de consultar viajes disponibles y armar la URL de viaje.</p>
<h3 id="heading-que-pasaria-si-el-chatbot-tuviera-mas-funcionalidades">¿Que pasaría si el chatbot tuviera mas funcionalidades?</h3>
<p>Actualmente, el chatbot tiene varias funcionalidades:</p>
<ul>
<li><p>Generar una URL para viajes disponibles.</p>
</li>
<li><p>Responder preguntas relacionadas al contenido que se encuentra en el sitio de <a target="_blank" href="http://reservamos.com/">Reservamos.com</a>. Ej. ¿Qué es un boleto flexible?</p>
</li>
<li><p>Proporcionar detalles de una compra previa (soporte al cliente).</p>
</li>
</ul>
<p>A medida que se agregan nuevas funcionalidades, la lista de <strong>tools</strong> va creciendo, reduciendo la eficiencia del chatbot. Esto se debe a que, cuanto más funcionalidades tenga, aumenta el margen de error al momento de decidir qué <strong>tools</strong> ejecutar.</p>
<p>Un enfoque interesante es utilizar <strong>LangGraph Multi-Agent</strong>.</p>
<h2 id="heading-multi-agent">Multi-Agent</h2>
<p>Un Chatbot con el enfoque <strong>Single Agent</strong> puede funcionar de manera efectiva usualmente utilizando un grupo de <strong>tools</strong> dentro de un único dominio, pero incluso utilizando modelos poderosos como <strong>gpt-4,</strong> puede ser menos efectivo al usar muchas <strong>tools</strong>.</p>
<p>Una manera de abordar tareas complicadas es a través de un enfoque de "divide y vencerás": crear un <strong>agente especializado</strong> para cada tarea o dominio y dirigir las tareas al <strong>"experto"</strong> correcto.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1710957665360/056ffbe6-7ff7-4ade-a0eb-feca81d4716e.png" alt class="image--center mx-auto" /></p>
<p>Ahora cada <strong>nodo</strong> es un <strong>agente</strong> con sus propias <strong>tools</strong> y se definen utilizando la clase <strong>AgentExecutor.</strong> Al seguir con este enfoque, nos podemos encontrar nuevamente con las limitantes de un <strong>Agente</strong> de <strong>LangChain</strong>. ¿Cómo puedo involucrarme en el proceso de cada agente? Para lograr esto, sería necesario que cada agente sea un <strong>subgrafo</strong> con sus propios flujos de ejecución en lugar de utilizar un <strong>AgentExecutor</strong>. Lo que genera nuevos puntos a considerar. Por ejemplo:</p>
<ul>
<li><p>¿Cuántos <strong>tokens</strong> va a consumir?</p>
</li>
<li><p>¿Cuánto <strong>tiempo</strong> va a tardar en responder?</p>
</li>
<li><p>¿Qué tan <strong>preciso</strong> es?</p>
</li>
</ul>
<p>Es importante tomar en cuenta las preguntas anteriores, ya que tenemos que asegurar que la eficiencia del chatbot se mantenga o mejore, mientras que el tiempo y costo de procesamiento no aumenten drásticamente.</p>
<p>Al ejecutar pruebas manuales, podemos notar un comportamiento interesante. Iniciamos estas pruebas con peticiones sencillas como: "Quiero viajar de <em>&lt;origen&gt;</em> a <em>&lt;destino&gt;</em> el 23 de marzo". Resultando en una respuesta correcta con un tiempo de ejecución dentro de un rango aceptable.</p>
<h3 id="heading-mensaje-inicial-hola">Mensaje inicial - <em>Hola!</em></h3>
<p>Recordemos que tenemos un chatbot y sabemos que normalmente los usuarios inician con un <strong><em>Hola</em></strong> y no con la petición que quieren. Entonces, el siguiente paso es observar el comportamiento del <strong>supervisor</strong> con un primer input saludando al chatbot. Resulta que no contesta a esos mensajes. Ya que, la responsabilidad del <strong>supervisor</strong> es delegar la tarea a uno de sus <strong>expertos</strong> y al no coincidir ninguno con el input, este decide terminar la ejecución.</p>
<p>Un primer enfoque para resolver esta situación puede ser agregar un <strong>agente</strong> nuevo que se encargue de contestar conversaciones casuales hasta que el usuario ingrese la información suficiente para ejecutar otro <strong>agente</strong> y dar una respuesta final. Lo cual parece la opción ideal, pero el supervisor no entiende que la respuesta que devuelve el nuevo <strong>agente</strong> no es un mensaje del usuario y la ejecución termina en un bucle.</p>
<p>Una forma de evitar esto es modificar manualmente el <strong>nodo</strong> responsable de llamar de nuevo al <strong>supervisor</strong> o terminar el proceso. Cuando recibe una respuesta de uno de sus <strong>agentes</strong>, devuelve la respuesta al usuario. Esto no es ideal ya que el propósito de este enfoque es que los <strong>agentes</strong> puedan interactuar entre ellos para generar una respuesta más precisa. Sin embargo, por ahora, esto solo es posible para peticiones específicas y no para mantener una conversación.</p>
<p>Aún así, podemos aprovechar esta idea de tener varios "<strong>expertos</strong>", dividir las responsabilidades y al mismo tiempo, mantener una conversación casual. ¿Cómo? Regresando al primer enfoque <strong><em>SingleAgent Chatbot Graph</em></strong> con algunas modificaciones. La idea es mantener la estructura de un <strong>Agente</strong> que tiene una lista de <strong>tools</strong> para ejecutar dependiendo del input del usuario. Pero ahora, estas <strong>tools</strong> las vamos a ver como "<strong>expertos</strong>", cada uno de ellos con un nombre y descripción de lo que pueden hacer. Cuando se invoquen, estas se encargarán de inicializar un <strong>Agente</strong> siendo un subgrafo con sus propios nodos y tools a ejecutar.</p>
<p>Con este nuevo enfoque logramos lo siguiente:</p>
<ul>
<li><p>El grafo principal puede mantener conversaciones casuales.</p>
</li>
<li><p>Cada subgrafo tiene su propio flujo, sus nodos y hasta podemos utilizar diferentes modelos de IA para realizar sus tareas.</p>
</li>
</ul>
<p>Con estos resultados, podemos afirmar que hemos logrado nuestro objetivo.</p>
<ol>
<li><p>Como desarrolladores, podemos involucrarnos en el proceso de ejecución del <strong>Agente</strong>.</p>
</li>
<li><p>El chatbot es capaz de mantener una conversación casual sin consumir más memoria.</p>
</li>
<li><p>Los tiempos de respuesta y el consumo de tokens son similares a nuestro Agente de <strong>LangChain</strong>.</p>
</li>
<li><p>Implementamos la arquitectura multi-agente, lo que nos ofrece flexibilidad para implementar varios modelos de IA simultáneamente y experimentar con ellos.</p>
</li>
</ol>
<h2 id="heading-puntos-a-considerar">Puntos a considerar</h2>
<p>Para saber si es viable implementar <strong>LangGraph</strong> con <strong>Multi-Agent</strong>, hay una serie de puntos a considerar con sus respectivos criterios:</p>
<ol>
<li><p><strong>Asegurar que el chatbot responde de manera correcta a la petición del usuario.</strong></p>
<ol>
<li>Ejecutando pruebas unitarias donde definimos una serie de preguntas que nos ayudan a validar el comportamiento del chatbot.</li>
</ol>
</li>
<li><p><strong>Mantener el tiempo de respuesta promedio del chatbot.</strong></p>
<ol>
<li>Ejecutando las pruebas unitarias múltiples veces para calcular el promedio de tiempo de respuesta y compararlo.</li>
</ol>
</li>
<li><p><strong>Mantener el consumo de tokens por request.</strong></p>
<ol>
<li>Ejecutando las pruebas unitarias múltiples veces para calcular el promedio de consumo de tokens por request y compararlo.</li>
</ol>
</li>
<li><p><strong>Analizar si mejora la escalabilidad del proyecto.</strong></p>
<ol>
<li>Es importante mencionar que la complejidad del proyecto puede aumentar con el uso de <strong>LangGraph</strong>, ya que cada <strong>nodo</strong> puede tener su propio flujo de ejecución. Por lo tanto, un buen diseño y documentación son cruciales para mantener el proyecto manejable y escalable.</li>
</ol>
</li>
</ol>
]]></content:encoded></item></channel></rss>