He explorado diversas formas de integrar modelos de lenguaje en C#, con especial interés en LangChain. Nuestro objetivo inicial era utilizar LangChain con C#, pero a medida que avanzamos en la investigación y pruebas, nos encontramos con varias limitaciones que nos llevaron a reconsiderar nuestro enfoque. En este artículo, repasaremos los intentos realizados, las dificultades encontradas y la solución alternativa implementada con Mistral en local.

Primeros intentos: LangChain en C

LangChain es una biblioteca diseñada para estructurar y facilitar interacciones con modelos de lenguaje de gran tamaño (LLMs), proporcionando herramientas para manejar prompts, memoria, agentes y herramientas externas. Sin embargo, LangChain solo tiene implementaciones oficiales en Python y JavaScript (Node.js), lo que ya presentaba un primer obstáculo para nuestro objetivo de integrarlo en un entorno basado en C#.

A pesar de esta limitación, consideramos diferentes estrategias para incorporar LangChain en C#:

  1. Utilizar una API de LangChain Server: Se podría haber ejecutado LangChain en Python y exponerlo como una API REST, permitiendo que C# se comunique con él mediante peticiones HTTP.
  2. Crear bindings de Python en C#: Otra posibilidad era utilizar interacciones entre C# y Python mediante IronPython o Python.NET, lo que permitiría llamar a funciones de LangChain desde C#.
  3. Recrear las funcionalidades de LangChain en C#: Aunque más complejo, podríamos haber implementado una arquitectura similar a LangChain dentro de C#, reutilizando conceptos como herramientas, cadenas de ejecución y agentes.

Tras evaluar estas opciones, encontramos que ninguna de ellas era ideal para nuestro caso, ya que todas requerían una dependencia fuerte con Python o una reimplementación costosa y propensa a errores. Además, mantener un sistema en dos lenguajes distintos habría agregado más complejidad al proyecto.

Problema con el uso de herramientas en LangChain

Durante las pruebas iniciales con LangChain, notamos que aunque el modelo de lenguaje respondía a las consultas en C#, realmente no estaba ejecutando herramientas (Tools) dentro del entorno C#. En los casos en los que LangChain intentaba utilizar herramientas, el procesamiento ocurría en Python, lo que contradecía nuestro objetivo de mantener todo dentro del ecosistema C#.

Este comportamiento se debía a que LangChain fue diseñado para ejecutarse de manera nativa en Python, lo que hacía que la integración en C# dependiera de un backend externo que gestionara las herramientas. No había una forma directa y eficiente de ejecutar herramientas dentro de C# sin recurrir a un servidor externo en Python.

Alternativa: Uso de Ollama y Mistral en local

Dado que la conexión con LangChain en C# presentaba demasiadas barreras, decidimos cambiar el enfoque y utilizar Ollama en local con Mistral. Esta decisión nos permitió evitar depender de LangChain y seguir trabajando con modelos de lenguaje dentro de un ecosistema puramente C#.

Ollama es un servidor local para ejecutar modelos de lenguaje como Mistral, Llama 3, Gemma, entre otros, sin necesidad de acceder a APIs externas. Esto ofrecía varias ventajas clave:

  • Independencia de LangChain: No era necesario ejecutar servidores adicionales ni depender de Python.
  • Funcionamiento en local: Sin necesidad de conectarse a la nube, lo que mejora la privacidad y el rendimiento.
  • Compatibilidad con C#: Se podía interactuar con la API de Ollama mediante HttpClient, sin modificar significativamente la arquitectura del proyecto.

Implementación en C

Con esta nueva estrategia, implementamos una nueva clase MistralLocalToolUse.cs, que reemplaza LlamaGroqToolUse.cs. Este cambio permitió que la aplicación enviara solicitudes a un servidor Ollama local, obteniendo respuestas directamente de Mistral.

El código actualizado se diseñó para:

  • Enviar peticiones HTTP a Ollama con el modelo Mistral.
  • Interpretar la respuesta JSON para manejar la información adecuadamente.
  • Ejecutar herramientas (Tools) de manera similar a LangChain, manteniendo la arquitectura original.

Sin embargo, en las primeras pruebas, notamos que Mistral aún no ejecutaba herramientas como se esperaba. Si bien el modelo respondía, no hacía uso de las herramientas definidas en la configuración. Esto nos llevó a investigar más a fondo y descubrimos que, aunque Ollama permite definir herramientas, no siempre las activa de manera eficiente.

Para solucionar esto, se reestructuró la forma en que se envían las solicitudes a Ollama, asegurándonos de incluir correctamente la selección de herramientas en el request. Finalmente, logramos hacer que Mistral procesara y ejecutara herramientas de manera adecuada dentro del ecosistema C#.

LangChain no está diseñado para C#, y aunque hay formas indirectas de integrarlo, ninguna de ellas era práctica o eficiente para nuestro caso. En lugar de intentar forzar la compatibilidad, encontramos una alternativa viable utilizando Ollama y Mistral en local, logrando un resultado funcional dentro de un entorno completamente basado en C#.

Este caso demuestra la importancia de la flexibilidad en el desarrollo de software: en ocasiones, la mejor solución no es insistir en una tecnología específica, sino buscar alternativas que se adapten mejor a las limitaciones y necesidades del proyecto. Al final, conseguimos implementar una arquitectura sólida y eficiente sin necesidad de recurrir a LangChain, aunque el proceso nos llevó a replantear la forma en que los modelos ejecutan herramientas en C#.