Llama 3 Groq Das Paradies Fuer Ki Llama 3 Groq Das Paradies Fuer Ki

Llama 3 + Groq: Das Paradies für KI

In diesem Blog werden wir eine Backend für eine generative KI-Nachrichtensuche erstellen. Dabei werden wir das Llama-3 8B-Modell von Meta über Groqs LPU verwenden.

Über Groq

Falls Sie noch nichts von Groq gehört haben, möchte ich Sie aufklären. Groq setzt neue Maßstäbe für die Inferenzgeschwindigkeit bei der Texterstellung in großen Sprachmodellen (LLMs). Groq bietet eine LPU (Language Processing Unit) Schnittstellenmotor, der eine neue Art von End-to-End-Verarbeitungssystem ist, das die schnellste Inferenz für rechenintensive Anwendungen mit einem sequenziellen Komponenten, wie in LLMs, bietet.

Wir werden nicht näher darauf eingehen, wie die Inferenz auf Groq im Vergleich zu GPUs schneller ist. Wir möchten die Geschwindigkeitssteigerung von Groq und die Textgenerierungsfähigkeiten von Llama 3 nutzen, um eine Generative AI News Search zu erstellen. Dies wird der Bing AI Suche, Google AI Suche oder PPLX ähneln.

Warum Llama 3?

Die kürzliche Veröffentlichung der Llama 3 Modelle von Meta war ein großer Erfolg. Das größere 70B Llama 3 Modell ist derzeit auf Platz fünf in der LMSys LLM Rangliste. Bei Aufgaben in der englischen Sprache ist dasselbe Modell auf Platz zwei hinter GPT-4.

Laut Meta’s Llama 3 Veröffentlichungsblog ist das 8B Modell das beste in seiner Kategorie und das 70B Modell ist besser als Gemini Pro 1.5 und Claude 3 Sonnet.

Llama 3 + Groq: Das Paradies für KI

Benchmark-Bild aus dem Meta Llama 3 Veröffentlichungsblog

Um das Verständnis des Modells für reale Szenarien und Probleme zu zeigen, hat Meta ein hochwertiges Evaluierungssatz erstellt. Der Evaluierungssatz enthält 1800 Prompts, die 12 Hauptanwendungsfälle abdecken:

  • Nach Rat fragen
  • Brainstorming
  • Klassifizierung
  • Beantwortung geschlossener Fragen
  • Coding
  • Kreatives Schreiben
  • Extraktion
  • Einnehmen einer Rolle/Persona
  • Beantwortung offener Fragen
  • Schlussfolgern
  • Umschreiben
  • Zusammenfassung

Dieser Satz wurde vor der Modellentwicklungsteam geheim gehalten, um eine zufällige Überanpassung ihrer Modelle an diese Daten zu vermeiden. Sie testeten Llama 3 70B gegen Claude Sonnet, Mistral Medium, GPT-3.5 und Llama 2. Das folgende Diagramm zeigt die Gewinnrate von Llama 3 gegenüber allen oben genannten Modellen.

Llama 3 + Groq: Das Paradies für KI

Human Evaluation aus dem Meta Llama 3 Veröffentlichungsblog

Mit all diesen Benchmarks zugunsten von Llama 3 können wir uns entscheiden, es für unsere Generative AI News Search zu verwenden.

Im Allgemeinen bieten die kleineren Modelle eine schnellere Inferenz, da sie nicht so viel VRAM verbrauchen und aufgrund der geringeren Parameterberechnung die Token-Generierung schneller ist. Daher können wir uns entscheiden, das kleinere Llama 3 Modell zu verwenden, d.h. das Llama 3 8B Modell.

Lasst uns das Ganze codieren.

News API

Wir werden die kostenlose News-API von Newsdata.io verwenden, um Nachrichteninhalte basierend auf der Suchanfrage abzurufen. Wir können auch RSS-Feeds von Google verwenden, um dies zu erreichen, oder es kann jede andere News-API sein.

Sie können auf die Newsdata News-API über einen API-Token zugreifen, der nach der Registrierung auf der Newsdata-Plattform generiert werden kann. Sobald wir den API-Token haben, geht es nur darum, einen GET-Aufruf mit der Suchanfrage durchzuführen, die Ergebnisse abzurufen und sie an das LLM weiterzugeben.

Wir werden den folgenden Code verwenden, um Nachrichten mit der Newsdata.io API abzurufen.

# news.py
import os
import httpx
from configs import NEWS_API_KEY, NEWS_BASE_URL
async def getNews(query: str, max_size: int = 8):
async with httpx.AsyncClient(timeout=60) as client:
response = await client.get(
os.path.join(NEWS_BASE_URL, "news") +
f"?apiKey={NEWS_API_KEY}&q={query}&size={max_size}")
try:
response.raise_for_status()
return response.json()
except httpx.HTTPStatusError as e:
print(
f"Error response {e.response.status_code} while requesting {e.request.url!r}"
)
return None

Oben verwenden wir die httpx Bibliothek, um einen asynchronen Aufruf an die API mit dem API-Token und dem Suchbegriff durchzuführen. Wenn der Antwortstatuscode 200 ist, geben wir die Antwort zurück, andernfalls geben wir None zurück und drucken die Ausnahme.

Groq Schnittstelle

Groq stellt das Llama 3 8B Modell über eine REST-API bereit, die über einen API-Schlüssel authentifiziert wird. Wir können auch über die offizielle Groq Python Bibliothek mit dem Llama 3 8B Modell interagieren.

Die folgende ist die Art und Weise, wie wir mit Groq interagieren werden.

# llms/groq.py
from groq import Groq, AsyncGroq
import traceback
from typing import List, Dict, Union
from llms.base import BaseLLM
from llms.ctx import ContextManagement
from groq import RateLimitError
import backoff
manageContext = ContextManagement()
class GroqLLM(BaseLLM):
def __init__(self, api_key: Union[str, None] = None):
super().__init__(api_key)
self.client = AsyncGroq(api_key=api_key)
@backoff.on_exception(backoff.expo, RateLimitError, max_tries=3)
async def __call__(self, model: str, messages: List[Dict], **kwargs):
try:
if "system" in kwargs:
messages = [{
"role": "system",
"content": kwargs.get("system")
}] + messages
del kwargs["system"]
if "ctx_length" in kwargs:
del kwargs["ctx_length"]
messages = manageContext(messages, kwargs.get("ctx_length", 7_000))
output = await self.client.chat.completions.create(
messages=messages, model=model, **kwargs)
return output.choices[0].message.content
except RateLimitError:
raise RateLimitError
except Exception as err:
print(f"ERROR: {str(err)}")
print(f"{traceback.format_exc()}")
return ""
class GroqLLMStream(BaseLLM):
def __init__(self, api_key: Union[str, None] = None):
super().__init__(api_key)
self.client = AsyncGroq(api_key=api_key)
async def __call__(self, model: str, messages: List[Dict], **kwargs):
if "system" in kwargs:
messages = [{
"role": "system",
"content": kwargs.get("system")
}] + messages
del kwargs["system"]
messages = manageContext(messages, kwargs.get("ctx_length", 7_000))
if "ctx_length" in kwargs:
del kwargs["ctx_length"]
output = await self.client.chat.completions.create(messages=messages,
model=model,
stream=True,
**kwargs)
async for chunk in output:
yield chunk.choices[0].delta.content or ""

Ich bevorzuge im Allgemeinen die Vererbung von LLM-Klassen von einer BaseLLM, damit ich alle gemeinsamen Dienstprogramme über die Basis steuern kann. Das folgende ist die BaseLLM.

# llms/base.py
from abc import ABC, abstractmethod
from typing import List, Dict, Union
class BaseLLM(ABC):
def __init__(self, api_key: Union[str, None] = None, **kwargs):
self.api_key = api_key
self.client = None
self.extra_args = kwargs
@abstractmethod
async def __call__(self, model: str, messages: List[Dict], **kwargs):
pass

Mit Llama 3 8B haben wir die Möglichkeit, 8192 Token in unserer Kontextlänge zu verwenden. Davon behalten wir 7000 Token für den Eingabekontext und den Rest für die Ausgabe oder Generierung.

Wenn der Eingabekontext größer als 7000 Token ist, müssen wir diesen Kontext verwalten, damit wir eine gute Anzahl von Tokens für die Ausgabegenerierung im Kontext übrig haben. Dafür haben wir die ContextManagement-Dienstprogramm geschrieben, das unten bereitgestellt wird.

# llms/ctx.py
from typing import List, Dict, Literal, Union
from transformers import AutoTokenizer
class ContextManagement:
def __init__(self):
self.tokenizer = AutoTokenizer.from_pretrained(
"meta-llama/Meta-Llama-3-8B")
def __count_tokens__(self, content: str):
tokens = self.tokenizer.tokenize(content)
return len(tokens) + 2
def __pad_content__(self, content: str, num_tokens: int):
return self.tokenizer.decode(
self.tokenizer.encode(content, max_length=num_tokens))
def __call__(self, messages: List[Dict], max_length: int = 28_000):
managed_messages = []
current_length = 0
current_message_role = None
for ix, message in enumerate(messages[::-1]):
content = message.get("content")
message_tokens = self.__count_tokens__(message.get("content"))
if ix > 0:
if current_length + message_tokens >= max_length:
tokens_to_keep = max_length - current_length
if tokens_to_keep > 0:
content = self.__pad_content__(content, tokens_to_keep)
current_length += tokens_to_keep
else:
break
if message.get("role") == current_message_role:
managed_messages[-1]["content"] += f"\n\n{content}"
else:
managed_messages.append({
"role": message.get("role"),
"content": content
})
current_message_role = message.get("role")
current_length += message_tokens
else:
if current_length + message_tokens >= max_length:
tokens_to_keep = max_length - current_length
if tokens_to_keep > 0:
content = self.__pad_content__(content, tokens_to_keep)
current_length += tokens_to_keep
managed_messages.append({
"role": message.get("role"),
"content": content
})
else:
break
else:
managed_messages.append({
"role": message.get("role"),
"content": content
})
current_length += message_tokens
current_message_role = message.get("role")
print(f"TOTAL TOKENS: ", current_length)
return managed_messages[::-1]

Oben verwenden wir die HuggingFace tokenizers Bibliothek, um unsere Nachrichten zu tokenisieren und die Token zu zählen und nur Nachrichten und Nachrichteninhalte beizubehalten, die in die maximale Tokenlänge passen, auf die wir uns oben geeinigt haben, d.h. 7000.

Um den meta-llama/Meta-Llama-3–8B Tokenizer zu verwenden, müssen wir zunächst unsere Daten angeben und die Nutzungsbedingungen von Meta auf HuggingFace akzeptieren und unseren HuggingFace Token unserem Computer hinzufügen, indem wir den Befehl huggingface-cli login verwenden oder den Token in der from_pretrained Methode des AutoTokenizer angeben.

Einfacher Prompt

Wir werden einen sehr einfachen Prompt für unsere Generative AI News Search Anwendung verwenden. Der Prompt wird unten bereitgestellt.

# prompts.py
SYSTEM_PROMPT = """You are a news summary bot. When a user provides a query, you will receive several news items related to that query. Your task is to assess the relevance of these news items to the query and retain only the ones that are pertinent.
If there are relevant news items, you should summarize them in a concise, professional, and respectful manner. The summary should be delivered in the first person, and you must provide citations for the news articles in markdown format. Do not inform the user about the number of news items reviewed or found; focus solely on delivering a succinct summary of the relevant articles.
In cases where no relevant news items can be found for the user's query, respond politely stating that you cannot provide an answer at this time. Remember, your responses should directly address the user's interest without revealing the backend process or the specifics of the data retrieval.
For example, if the query is about "Lok Sabha elections 2024" and relevant articles are found, provide a summary of these articles. If the articles are unrelated or not useful, inform the user respectfully that you cannot provide the required information.
"""

Der Prompt ist sehr einfach zu verstehen.

Der Agent

Lasst uns alles zusammenbringen und unseren Generative AI News Search Agent abschließen.

# agent.py
from llms.groq import GroqLLMStream
from configs import GROQ_API_KEY, GROQ_MODEL_NAME
from news import getNews
from prompts import SYSTEM_PROMPT
llm = GroqLLMStream(GROQ_API_KEY)
async def newsAgent(query: str):
retrieved_news_items = await getNews(query)
if not retrieved_news_items:
yield "\n_Cannot fetch any relevant news related to the search query._"
return
retrieved_news_items = retrieved_news_items.get("results")
useful_meta_keys = [
"title", "link", "keywords", "creator", "description", "country",
"category"
]
news_items = [{
k: d[k]
for k in useful_meta_keys
} for d in retrieved_news_items]
messages = [{
"role": "user",
"content": f"Query: {query}\n\nNews Items: {news_items}"
}]
async for chunk in llm(GROQ_MODEL_NAME,
messages,
system=SYSTEM_PROMPT,
max_tokens=1024,
temperature=0.2):
yield chunk

Oben importieren wir alle notwendigen Module, die wir zum Interagieren mit Llama 3 auf Groq, zur Kontextverwaltung, zum System-Prompt und zur Nachrichtenabrufung geschrieben haben. Anschließend definieren wir die newsAgent-Funktion, die die Benutzerabfrage oder Suchabfrage als einziges Argument akzeptiert.

In newsAgent rufen wir zunächst unsere Nachrichten über die Newsdata.io API ab und sammeln dann die relevanten Schlüssel, die wir an das LLM weitergeben möchten. Anschließend geben wir die Abfrage, die abgerufenen Nachrichtenartikel und den System-Prompt zusammen mit dem Modellnamen an unsere Groq Streaming-Schnittstelle weiter und geben die Chunks aus, während sie generiert und empfangen werden.

Umgebungsvariablen und Konfigurationen

Wir müssen die folgenden Umgebungsvariablen festlegen, um unsere GenerativeAI News Search Anwendung auszuführen.

  • Umgebungsvariablen
GROQ_API_KEY="YOUR_GROQ_API_KEY"
GROQ_MODEL_NAME="llama3-8b-8192"
NEWS_API_KEY="YOUR_NEWS_API_KEY"
NEWS_BASE_URL="https://newsdata.io/api/1/"

Wir benötigen den Groq API Key und den API-Schlüssel von Newsdata.io, um Nachrichten abzurufen.

  • Laden von Umgebungsvariablen
import os
from dotenv import load_dotenv
load_dotenv()
GROQ_API_KEY = os.environ.get("GROQ_API_KEY")
GROQ_MODEL_NAME = os.environ.get("GROQ_MODEL_NAME")
NEWS_API_KEY = os.environ.get("NEWS_API_KEY")
NEWS_BASE_URL = os.environ.get("NEWS_BASE_URL")

API bereitstellen

Unser GenerativeAI News Search Agent ist fast fertig. Wir müssen ihn nur noch über eine Streaming-API bereitstellen. Dafür werden wir FastAPI und Uvicorn verwenden, wie im folgenden Code gezeigt.

# app.py
from fastapi import FastAPI
from fastapi.responses import StreamingResponse
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
from agent import newsAgent
app = FastAPI()
origins = ["*"]
app.add_middleware(
CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
async def index():
return {"ok": True}
@app.get("/api/news")
async def api_news(query: str):
return StreamingResponse(newsAgent(query), media_type="text/event-stream")
if __name__ == "__main__":
uvicorn.run("app:app", host="0.0.0.0", port=8899, reload=True)

Oben importieren wir unseren newsAgent zusammen mit den erforderlichen FastAPI und Uvicorn Modulen und richten die FastAPI Anwendung ein.

Wir erstellen einen Index-Endpoint nur für Health-Checks. Unser News Search Agent wird über die Route /api/news bereitgestellt, die eine Streaming-Antwort zurückgibt.

Sobald wir mit der app.py Datei fertig sind, können wir den Server mit dem folgenden Befehl starten.

python app.py

Der Server wird auf Portnummer 8899 gestartet.

Wir können uns nun in unserem Browser auf http://localhost:8899/api/news?query=searchtext bewegen und unsere Nachrichten in der folgenden Art und Weise erhalten.

Llama 3 + Groq: Das Paradies für KI

GIF vom Autor

Der gesamte Code ist in dem unten angegebenen Link verfügbar.

Fazit

In diesem Blog haben wir gesehen, wie wir mit der schnelleren LPU-Schnittstelle, die über Groq verfügbar ist, eine nahezu Echtzeit-Inferenz erhalten können. Wir haben auch einen Blick auf die Benchmark-Ergebnisse von Llama 3 geworfen und das kleinere Llama 3 8B Modell für die Nachrichtenzusammenfassung integriert.

Das war’s von diesem Blog, ich hoffe, Sie hatten eine gute Zeit beim Lesen.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert