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.