Modele Či platforme AI
Apeluri API LLM Asincrone ÃŪn Python: O Ghid CuprinzÄtor
Ca dezvoltatori Či oameni de ČtiinČÄ, adesea ne gÄsim ÃŪn situaČia de a interacČiona cu aceste modele puternice prin intermediul API-urilor. Cu toate acestea, pe mÄsurÄ ce aplicaČiile noastre cresc ÃŪn complexitate Či dimensiune, nevoia de interacČiuni eficiente Či performante cu API-urile devine crucialÄ. Aici, programarea asincronÄ strÄluceČte, permiČÃĒndu-ne sÄ maximizÄm debitul Či sÄ minimizÄm ÃŪntÃĒrzierea atunci cÃĒnd lucrÄm cu API-urile LLM.
Ãn acest ghid cuprinzÄtor, vom explora lumea apelurilor API LLM asincrone ÃŪn Python. Vom acoperi totul, de la conceptele de bazÄ ale programÄrii asincrone pÃĒnÄ la tehnici avansate pentru gestionarea fluxurilor de lucru complexe. La sfÃĒrČitul acestui articol, veČi avea o ÃŪnČelegere solidÄ a modului de a utiliza programarea asincronÄ pentru a ÃŪmbunÄtÄČi aplicaČiile dvs. LLM.
Ãnainte de a intra ÃŪn detalii despre apelurile API LLM asincrone, sÄ stabilim o bazÄ solidÄ ÃŪn conceptele de programare asincronÄ.
Programarea asincronÄ permite executarea mai multor operaČii ÃŪn paralel, fÄrÄ a bloca firul principal de execuČie. Ãn Python, acest lucru se realizeazÄ ÃŪn principal prin intermediul modulului asyncio, care oferÄ un cadru pentru scrierea de cod concurent utilizÃĒnd corutine, bucle de evenimente Či obiecte viitoare.
Concepte cheie:
- Corutine: FuncČii definite cu async def care pot fi oprite Či reluate.
- BuclÄ de evenimente: Mecanismul central de execuČie care gestioneazÄ Či ruleazÄ sarcinile asincrone.
- Obiecte aČteptate: Obiecte care pot fi utilizate cu cuvÃĒntul cheie await (corutine, sarcini, obiecte viitoare).
IatÄ un exemplu simplu pentru a ilustra aceste concepte:
import asyncio
<p>async def salut(nume):</p>
<p>await asyncio.sleep(1) # SimuleazÄ o operaČie I/O</p>
<p>print(f"Salut, {nume}!")</p>
<p>async def main():</p>
<p>await asyncio.gather(</p>
<p>salut("Alice"),</p>
<p>salut("Bob"),</p>
<p>salut("Charlie")</p>
<p>)</p>
asyncio.run(main())
Ãn acest exemplu, definim o funcČie asincronÄ salut care simuleazÄ o operaČie I/O cu asyncio.sleep(). FuncČia main utilizeazÄ asyncio.gather() pentru a rula mai multe saluturi ÃŪn paralel. Ãn ciuda ÃŪntÃĒrzierii de somn, toate trei saluturi vor fi tipÄrite dupÄ aproximativ 1 secundÄ, demonstrÃĒnd puterea execuČiei asincrone.
Nevoia de asincronism ÃŪn apelurile API LLM
Atunci cÃĒnd lucrÄm cu API-urile LLM, adesea ne confruntÄm cu scenarii ÃŪn care trebuie sÄ facem mai multe apeluri API, fie ÃŪn secvenČÄ, fie ÃŪn paralel. Codul sincron tradiČional poate duce la blocaje semnificative de performanČÄ, ÃŪn special atunci cÃĒnd avem de-a face cu operaČii cu latenČÄ ridicatÄ, cum ar fi solicitÄrile de reČea cÄtre serviciile LLM.
SÄ considerÄm un scenariu ÃŪn care trebuie sÄ generÄm rezumate pentru 100 de articole diferite utilizÃĒnd un API LLM. Cu o abordare sincronÄ, fiecare apel API ar bloca pÃĒnÄ primeČte un rÄspuns, posibil necesitÃĒnd cÃĒteva minute pentru a finaliza toate solicitÄrile. O abordare asincronÄ, pe de altÄ parte, ne permite sÄ iniČiem mai multe apeluri API ÃŪn paralel, reducÃĒnd semnificativ timpul de execuČie total.
Configurarea mediului
Pentru a ÃŪncepe cu apelurile API LLM asincrone, trebuie sÄ configuraČi mediul Python cu bibliotecile necesare. IatÄ ce aveČi nevoie:
- Python 3.7 sau superior (pentru suport nativ asyncio)
- aiohttp: O bibliotecÄ client HTTP asincronÄ
- openai: Clientul oficial OpenAI pentru Python (dacÄ utilizaČi modelele GPT ale OpenAI)
- langchain: Un cadru pentru construirea de aplicaČii cu LLM (opČional, dar recomandat pentru fluxuri de lucru complexe)
PuteČi instala aceste dependenČe utilizÃĒnd pip:
<p>pip install aiohttp openai langchain <div class="relative flex flex-col rounded-lg">
Apeluri API LLM asincrone de bazÄ cu asyncio Či aiohttp
SÄ ÃŪncepem prin a face un apel asincron simplu cÄtre un API LLM utilizÃĒnd aiohttp. Vom utiliza API-ul GPT-3.5 al OpenAI ca exemplu, dar conceptele se aplicÄ Či altor API-uri LLM.
import asyncio
import aiohttp
from openai import AsyncOpenAI
<p>async def genereaza_text(prompt, client):</p>
<p>rÄspuns = await client.chat.completions.create(</p>
<p>model="gpt-3.5-turbo",</p>
<p>mesaje=[{"rol": "utilizator", "conČinut": prompt}]</p>
<p>)</p>
<p>return rÄspuns.alegeri[0].mesaj.conČinut</p>
<p>async def main():</p>
<p>prompturi = [</p>
<p>"ExplicaČi calculul cuantic ÃŪn termeni simpli.",</p>
<p>"ScrieČi un haiku despre inteligenČa artificialÄ.",</p>
<p>"DescrieČi procesul de fotosintezÄ."</p>
<p>]</p>
<p>async with AsyncOpenAI() as client:</p>
<p>sarcini = [genereaza_text(prompt, client) for prompt in prompturi]</p>
<p>rezultate = await asyncio.gather(*sarcini)</p>
<p>for prompt, rezultat in zip(prompturi, rezultate):</p>
<p>print(f"Prompt: {prompt}\nRÄspuns: {rezultat}\n")</p>
asyncio.run(main())
Ãn acest exemplu, definim o funcČie asincronÄ genereaza_text care face un apel cÄtre API-ul OpenAI utilizÃĒnd clientul AsyncOpenAI. FuncČia main creeazÄ mai multe sarcini pentru diferite prompturi Či utilizeazÄ asyncio.gather() pentru a rula aceste sarcini ÃŪn paralel.
AceastÄ abordare ne permite sÄ trimitem mai multe solicitÄri cÄtre API-ul LLM simultan, reducÃĒnd semnificativ timpul total de execuČie.
Tehnici avansate: Ãmpachetarea Či controlul concurenČei
Ãn timp ce exemplul anterior demonstreazÄ conceptele de bazÄ ale apelurilor API LLM asincrone, aplicaČiile din lumea realÄ adesea necesitÄ abordÄri mai sofisticate. SÄ explorÄm douÄ tehnici importante: ÃŪmpachetarea solicitÄrilor Či controlul concurenČei.
Ãmpachetarea solicitÄrilor: Atunci cÃĒnd avem de-a face cu un numÄr mare de prompturi, este adesea mai eficient sÄ le ÃŪmpachetÄm ÃŪn grupuri decÃĒt sÄ trimitem solicitÄri individuale pentru fiecare prompt. Acest lucru reduce suprasarcina multiplelor apeluri API Či poate duce la o performanČÄ mai bunÄ.
import asyncio
from openai import AsyncOpenAI
<p>async def proceseaza_pachet(pachet, client):</p>
<p>rÄspunsuri = await asyncio.gather([</p>
<p>client.chat.completions.create(</p>
<p>model="gpt-3.5-turbo",</p>
<p>mesaje=[{"rol": "utilizator", "conČinut": prompt}]</p>
<p>) for prompt in pachet</p>
<p>])</p>
<p>return [rÄspuns.alegeri[0].mesaj.conČinut for rÄspuns in rÄspunsuri]</p>
<p>async def main():</p>
<p>prompturi = [f"SpuneČi-mi un fapt despre numÄrul {i}" for i in range(100)]</p>
<p>dimensiunea_pachetului = 10</p>
<p>async with AsyncOpenAI() as client:</p>
<p>rezultate = []</p>
<p>for i in range(0, len(prompturi), dimensiunea_pachetului):</p>
<p>pachet = prompturi[i:i+dimensiunea_pachetului]</p>
<p>rezultate_pachet = await proceseaza_pachet(pachet, client)</p>
<p>rezultate.extend(rezultate_pachet)</p>
<p>for prompt, rezultat in zip(prompturi, rezultate):</p>
<p>print(f"Prompt: {prompt}\nRÄspuns: {rezultat}\n")</p>
asyncio.run(main())
Controlul concurenČei: DeČi programarea asincronÄ permite execuČia concurentÄ, este important sÄ controlaČi nivelul de concurenČÄ pentru a evita supraÃŪncÄrcarea serverului API sau depÄČirea limitelor de ratÄ. Putem utiliza asyncio.Semaphore pentru acest scop.
import asyncio
from openai import AsyncOpenAI
<p>async def genereaza_text(prompt, client, semafor):</p>
<p>async with semafor:</p>
<p>rÄspuns = await client.chat.completions.create(</p>
<p>model="gpt-3.5-turbo",</p>
<p>mesaje=[{"rol": "utilizator", "conČinut": prompt}]</p>
<p>)</p>
<p>return rÄspuns.alegeri[0].mesaj.conČinut</p>
<p>async def main():</p>
<p>prompturi = [f"SpuneČi-mi un fapt despre numÄrul {i}" for i in range(100)]</p>
<p>numÄr_solicitarilor_concurente = 5</p>
<p>semafor = asyncio.Semaphore(numÄr_solicitarilor_concurente)</p>
<p>async with AsyncOpenAI() as client:</p>
<p>sarcini = [genereaza_text(prompt, client, semafor) for prompt in prompturi]</p>
<p>rezultate = await asyncio.gather(*sarcini)</p>
<p>for prompt, rezultat in zip(prompturi, rezultate):</p>
<p>print(f"Prompt: {prompt}\nRÄspuns: {rezultat}\n")</p>
asyncio.run(main())
Ãn acest exemplu, utilizÄm un semafor pentru a limita numÄrul de solicitÄri concurente la 5, asigurÃĒndu-ne cÄ nu supraÃŪncÄrcÄm serverul API.
Gestionarea erorilor Či reÃŪncercÄrile ÃŪn apelurile LLM asincrone
Atunci cÃĒnd lucrÄm cu API-uri externe, este crucial sÄ implementÄm o gestionare robustÄ a erorilor Či mecanisme de reÃŪncercare. SÄ ÃŪmbunÄtÄČim codul nostru pentru a gestiona erorile comune Či pentru a implementa o reÃŪncercare cu ÃŪntÃĒrziere exponenČialÄ.
import asyncio
import random
from openai import AsyncOpenAI
from tenacity import retry, stop_after_attempt, wait_exponential
class EroareAPI(Exception):
pass
<p>@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10))</p>
<p>async def genereaza_text_cu_reÃŪncercare(prompt, client):</p>
<p>try:</p>
<p>rÄspuns = await client.chat.completions.create(</p>
<p>model="gpt-3.5-turbo",</p>
<p>mesaje=[{"rol": "utilizator", "conČinut": prompt}]</p>
<p>)</p>
<p>return rÄspuns.alegeri[0].mesaj.conČinut</p>
<p>except Exception as e:</p>
<p>print(f"Eroare apÄrutÄ: {e}")</p>
<p>raise EroareAPI("Nu am putut genera text")</p>
<p>async def proceseaza_prompt(prompt, client, semafor):</p>
<p>async with semafor:</p>
<p>try:</p>
<p>rezultat = await genereaza_text_cu_reÃŪncercare(prompt, client)</p>
<p>return prompt, rezultat</p>
<p>except EroareAPI:</p>
<p>return prompt, "Nu am putut genera rÄspuns dupÄ mai multe ÃŪncercÄri."</p>
<p>async def main():</p>
<p>prompturi = [f"SpuneČi-mi un fapt despre numÄrul {i}" for i in range(20)]</p>
<p>numÄr_solicitarilor_concurente = 5</p>
<p>semafor = asyncio.Semaphore(numÄr_solicitarilor_concurente)</p>
<p>async with AsyncOpenAI() as client:</p>
<p>sarcini = [proceseaza_prompt(prompt, client, semafor) for prompt in prompturi]</p>
<p>rezultate = await asyncio.gather(*sarcini)</p>
<p>for prompt, rezultat in rezultate:</p>
<p>print(f"Prompt: {prompt}\nRÄspuns: {rezultat}\n")</p>
asyncio.run(main())
AceastÄ versiune ÃŪmbunÄtÄČitÄ include:
- O excepČie personalizatÄ
EroareAPIpentru erori legate de API. - O funcČie
genereaza_text_cu_reÃŪncercaredecoratÄ cu@retrydin biblioteca tenacity, care implementeazÄ o reÃŪncercare cu ÃŪntÃĒrziere exponenČialÄ. - Gestionarea erorilor ÃŪn funcČia
proceseaza_promptpentru a prinde Či raporta eČecurile.
Optimizarea performanČei: RÄspunsuri ÃŪn flux
Pentru generarea de conČinut de lungÄ duratÄ, rÄspunsurile ÃŪn flux pot ÃŪmbunÄtÄČi semnificativ performanČa perceputÄ a aplicaČiei dvs. Ãn loc de a aČtepta ÃŪntregul rÄspuns, puteČi prelucra Či afiČa bucÄČi de text pe mÄsurÄ ce devin disponibile.
import asyncio
from openai import AsyncOpenAI
<p>async def flux_text(prompt, client):</p>
<p>flux = await client.chat.completions.create(</p>
<p>model="gpt-3.5-turbo",</p>
<p>mesaje=[{"rol": "utilizator", "conČinut": prompt}],</p>
<p>flux=True</p>
<p>)</p>
<p>rÄspuns_complet = ""</p>
<p>async for bucÄČicÄ in flux:</p>
<p>if bucÄČicÄ.alegeri[0].delta.conČinut is not None:</p>
<p>conČinut = bucÄČicÄ.alegeri[0].delta.conČinut</p>
<p>rÄspuns_complet += conČinut</p>
<p>print(conČinut, end='', flush=True)</p>
<p>print("\n")</p>
<p>return rÄspuns_complet</p>
<p>async def main():</p>
<p>prompt = "ScrieČi o poveste scurtÄ despre un om de ČtiinČÄ care cÄlÄtoreČte ÃŪn timp."</p>
<p>async with AsyncOpenAI() as client:</p>
<p>rezultat = await flux_text(prompt, client)</p>
<p>print(f"RÄspuns complet:\n{rezultat}")</p>
asyncio.run(main())
Acest exemplu demonstreazÄ cum sÄ fluxaČi rÄspunsul de la API, tipÄrind fiecare bucÄČicÄ pe mÄsurÄ ce soseČte. AceastÄ abordare este deosebit de utilÄ pentru aplicaČii de chat sau orice scenariu ÃŪn care doriČi sÄ oferiČi feedback ÃŪn timp real utilizatorului.
Construirea fluxurilor de lucru asincrone cu LangChain
Pentru aplicaČii LLM mai complexe, cadru LangChain oferÄ o abstracČie de nivel ÃŪnalt care simplificÄ procesul de ÃŪnlÄnČuire a mai multor apeluri LLM Či integrarea altor instrumente. SÄ explorÄm un exemplu de utilizare a LangChain cu capacitÄČi asincrone:
Acest exemplu aratÄ cum LangChain poate fi utilizat pentru a crea fluxuri de lucru mai complexe cu fluxare Či execuČie asincronÄ. AsyncCallbackManager Či StreamingStdOutCallbackHandler permit fluxarea ÃŪn timp real a conČinutului generat.
import asyncio
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.callbacks.manager import AsyncCallbackManager
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
<p>async def genereaza_poveste(subiect):</p>
<p>llm = OpenAI(temperatura=0.7, flux=True, manager_callback=AsyncCallbackManager([StreamingStdOutCallbackHandler()]))</p>
<p>prompt = PromptTemplate(</p>
<p>variabile_de_intrare=["subiect"],</p>
<p>Čablon="ScrieČi o poveste scurtÄ despre {subiect}."</p>
<p>)</p>
<p>lanČ = LLMChain(llm=llm, prompt=prompt)</p>
<p>return await lanČ.arun(subiect=subiect)</p>
<p>async def main():</p>
<p>subiecte = ["o pÄdure magicÄ", "un oraČ futurist", "o civilizaČie subacvaticÄ"]</p>
<p>sarcini = [genereaza_poveste(subiect) for subiect in subiecte]</p>
<p>poveČti = await asyncio.gather(*sarcini)</p>
<p>for subiect, poveste in zip(subiecte, poveČti):</p>
<p>print(f"\nSubiect: {subiect}\nPoveste: {poveste}\n{'='*50}\n")</p>
asyncio.run(main())
Servirea aplicaČiilor LLM asincrone cu FastAPI
Pentru a face aplicaČia dvs. LLM asincronÄ disponibilÄ ca serviciu web, FastAPI este o alegere excelentÄ datoritÄ suportului sÄu nativ pentru operaČii asincrone. IatÄ un exemplu de creare a unui punct de terminare API simplu pentru generarea de text:
from fastapi import FastAPI, BackgroundTasks
from pydantic import BaseModel
from openai import AsyncOpenAI
app = FastAPI()
client = AsyncOpenAI()
class CerereDeGenerare(BaseModel):
prompt: str
class RÄspunsDeGenerare(BaseModel):
text_generat: str
@app.post("/genereazÄ", model_rÄspuns=RÄspunsDeGenerare)
async def genereazÄ_text(cerere: CerereDeGenerare, sarcini_in_background: BackgroundTasks):
rÄspuns = await client.chat.completions.create(
model="gpt-3.5-turbo",
mesaje=[{"rol": "utilizator", "conČinut": cerere.prompt}]
)
text_generat = rÄspuns.alegeri[0].mesaj.conČinut
# SimulaČi o prelucrare suplimentarÄ ÃŪn background
sarcini_in_background.add_task(log_genereare, cerere.prompt, text_generat)
return RÄspunsDeGenerare(text_generat=text_generat)
async def log_genereare(prompt: str, text_generat: str):
# SimulaČi ÃŪnregistrarea sau o prelucrare suplimentarÄ
await asyncio.sleep(2)
print(f"Ãnregistrat: Prompt '{prompt}' a generat text de lungime {len(text_generat)}")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
AcestÄ aplicaČie FastAPI creeazÄ un punct de terminare /genereazÄ care acceptÄ un prompt Či returneazÄ text generat. De asemenea, demonstreazÄ cum sÄ utilizaČi sarcini ÃŪn background pentru prelucrÄri suplimentare fÄrÄ a bloca rÄspunsul.
Practici recomandate Či capcane comune
Pe mÄsurÄ ce lucraČi cu apelurile API LLM asincrone, ČineČi cont de aceste practici recomandate:
- FolosiČi pool-uri de conexiuni: Atunci cÃĒnd faceČi mai multe solicitÄri, reutilizaČi conexiunile pentru a reduce suprasarcina.
- ImplementaČi o gestionare corespunzÄtoare a erorilor: LuaČi ÃŪntotdeauna ÃŪn considerare problemele de reČea, erorile API Či rÄspunsurile neaČteptate.
- RespectaČi limitele de ratÄ: UtilizaČi semafoare sau alte mecanisme de control al concurenČei pentru a evita supraÃŪncÄrcarea serverului API.
- MonitorizaČi Či ÃŪnregistraČi: ImplementaČi o ÃŪnregistrare cuprinzÄtoare pentru a urmÄri performanČa Či a identifica problemele.
- FolosiČi fluxarea pentru conČinut de lungÄ duratÄ: ÃmbunÄtÄČeČte experienČa utilizatorului Či permite prelucrarea timpurie a rezultatelor parČiale.












