Django et IA locale : connecter Langchain

5 juin 2023 10:19 dans data-pipelines / publications
Slider Image

Comment exploiter la puissance de l'IA ? La question se pose aux acteurs de la tech et aux entreprises. Un début de réponse semble émerger, du moins les outils pour la bâtir. Nous introduirons sommairement dans cet article la librairie Langchain, qui propose des outils pour programmer avec les language models.

Note : le code présenté dans cet article est disponible dans le repository django-local-ai.
Dans cet article, nous allons nous baser sur la configuration décrite dans l'article Utiliser une IA locale dans Django.

Installons la librairie :


        pip install langchain
      

Testons Langchain dans un terminal avec un language model local pour vérifier que tout fonctionne :

from langchain.llms import LlamaCpp
        from langchain import PromptTemplate, LLMChain
        from langchain.callbacks.manager import CallbackManager
        from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler

        template = """Question: {question}

        Answer: Let's think step by step."""

        prompt = PromptTemplate(template=template, input_variables=["question"])

        callback_manager = CallbackManager([StreamingStdOutCallbackHandler()])

        llm = LlamaCpp(
            # le path doit être absolu
            model_path="/home/mes/models/GPT4All-13B-snoozy.ggmlv3.q5_0.bin",
            callback_manager=callback_manager,
            verbose=True,
        )

        llm_chain = LLMChain(prompt=prompt, llm=llm)

        question = "Name the planets in the solar system with their diameter in kilometers"

        llm_chain.run(question)
      

Le modèle doit émettre une réponse dans le terminal, indiquant ainsi que tout fonctionne correctement. Nous pouvons brancher cela sur Django pour l'utiliser dans une interface web.

Créer une task Langchain

Sur le même principe que dans le premier article, nous allons devoir créer une task qui sera chargée de l'inférence, cette fois en utilisant Langchain. Commençons par créer un fichier langchain.py avec une fonction pour charger le language model.

Connecter les websockets

La première étape est de brancher l'output de Langchain sur notre channel websockets pour qu'il soit streamé au frontend. Ecrivons un handler spécifique pour notre cas :

from typing importAnyfrom langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
        from instant.producers import publish

        TOKS = 0classWsCallbackHandler(StreamingStdOutCallbackHandler):"""Callback handler for websockets. Only works with LLMs that support streaming."""defon_llm_new_token(self, token: str, **kwargs: Any) -> None:"""Run on new LLM token. Only available when streaming is enabled."""
                TOKS += 1if TOKS == 1:
                    publish("$llm", "#STARTSTREAM#")
                publish("$llm", token)
      

Charger le language model

Ajoutons maintenant une helper function pour charger le language model quand nécessaire :

from langchain.llms import LlamaCpp
        from langchain.callbacks.manager import CallbackManager
        from django.conf import settings

        LLM: LlamaCpp | None = None
        TOKS = 0defload_langchain(*args, **kwargs) -> LlamaCpp:
            TOKS = 0if LLM isNone:
                LLM = LlamaCpp(
                    model_path=settings.MODEL_PATH,
                    # on branche ici le callback custom précédemment élaboré
                    callback_manager=CallbackManager([WsCallbackHandler()]),
                    verbose=True,
                    **kwargs,
                )
            return LLM
      

La task d'inférence

Sur la base de ces éléments nous pouvons maintenant écrire la task d'inférence elle-même. Dans un fichier tasks.py :

from django.conf import settings
        from langchain import LLMChain, PromptTemplate
        from instant.producers import publish
        
        from myapp.langchain import load_langchain

        @huey.task()definfertemplate(question: str, template: str):
            LLM = load_langchain(n_ctx=1024)
            prompt = PromptTemplate(template=template, input_variables=["question"])
            llm_chain = LLMChain(prompt=prompt, llm=LLM)
            llm_chain.run(question)
            publish("$llm", "#ENDSTREAM#")
            return

Tout est prêt pour brancher un endpoint.

Le endpoint

Créons un api endpoint simple, avec d'abord un schéma Pydantic pour spécifier les données requises depuis le frontend: prompt et template :

classInferContract(Schema):
            prompt: strclassInferTemplateContract(InferContract):
            template: str

Branchons le endpoint en utilisant ce schéma pour les données d'entrée requises :

from myapp.schemas import InferTemplateContract
        from myapp.tasks import infertemplate

        @router.post("/inferlc",
            response={ 200: None },
        )definferlc(request: HttpRequest, data: InferTemplateContract):
            prompt: str = data.dict()["prompt"]
            template: str = data.dict()["template"]
            print("Calling Langchain infer task with template", template)
            print("For prompt", prompt)
            infertemplate(prompt, template)
            return200, None

Et voilà ! Le frontend va poster ses template et prompt et écouter la réponse du language model en websockets. Maintenant que la librairie est branchée, il reste à explorer les nombreuses possibilités de Langchain, en parcourant la doc ou en lisant le code Python. La pratique et l'imagination de chaque développeur doit faire le reste.

Le code présenté dans cet article est disponible dans le repository django-local-ai.

Articles associés

Utiliser une IA locale dans Django

Ceci est une introduction l'IA prend de plus en plus de place, de plus en plus vite. Depuis quelques temps a émergé un mouvement open source autour notamment de Llama.cpp.