Forespørsel til Store Språkmodeller (Chatboter)
I denne første delen av kurset skal vi sende en forespørsel til en språkmodell. Vi vil få et resultat. Vi kommer til å bruke LangChain, et bibliotek med åpen kildekode, som er til å lage applikasjoner med store språkmodeller, LLMer.
Oppgave 4.1: Lag en ny notebook
Lag en ny Jupyter Notebook som du kaller chatbot ved å klikke Filmenyen i JupyterLab, og deretter New og Notebook. Hvis du blir spurt om å velge en kjerne, velg “Python 3”. Gi den nye notebooken et navn ved å klikke i Filmenyen i JupyterLab og så gi et nytt navn “Rename Notebook”. Bruk navnet chatbot.
Oppgave 4.2: Stopp gamle kjerner
JupyterLab bruker en Python kjerne til å kjøre koden i hver notebook. For å frigjøre GPU minne som ble brukt i forrige kapittel, bør du stoppe kjernen for den notebooken. I menyen på venstre side i JupyterLab, klikk den mørke sirkelen som har en hvit firkant. Klikk så KERNELS og Shut Down All.
Språkmodellen
Vi kommer til å bruke modeller fra HuggingFace, en nettside som har verktøy og modeller til maskinlæring. I denne oppgaven vil vi bruke LLM meta-llama/Llama-3.2-1B, som er en modell som har åpne vekter og parametere. Dette er en liten modell med bare 1 milliard parametere. Det bør være mulig å bruke den på de fleste bærbare maskiner.
Typer av modeller
google/gemma-3-1b-pt er en basismodell. Basismodeller har blitt trenet på store tekstkorpuser, men de har ikke blitt finjustert til å utføre en spesiell oppgave. Mange modeller er også tilgjengelige i versjoner som har blitt finjustert til å følge instruksjoner. Disse kalles instruct eller chat modeller. Instruct og chat modeller passer bedre til å lage chatbots med.
Modellens plassering
Vi bør fortelle HuggingFace biblioteket hvor det skal lagre dataene sine. Hvis du kjører på Educloud/Fox prosjekt ec443 finner du modellen på stien nedenfor:
import os
os.environ['HF_HOME'] = '/fp/projects01/ec443/huggingface/cache/'
Lasting av modellen
For å bruke modellen, lager vi en pipeline. En pipeline kan bestå av flere behandlingstrinn, men i dette tilfellet trenger vi bare ett steg. Vi kan bruke metoden HuggingFacePipeline.from_model_id(), som automatisk laster ned den spesifiserte modellen fra HuggingFace.
Først importerer vi biblioteksfunksjonen som vi trenger:
from langchain_huggingface import HuggingFacePipeline
Vi spesifiserer modellens identifikator. Dette finner du på nettsiden til HuggingFace:
model_id = 'google/gemma-3-1b-pt'
HuggingFacePipeline trenger også et parameter som forteller hva slags oppgaver vi ønsker å utføre. I dette kurset, skal oppgaven alltid være text-generation.
task = 'text-generation'
Hvis maskinen din har GPU, vil det gå mye fortere å bruke denne enn å bruke bare CPU. Vi kan bruke torch biblioteket til å undersøke om vi har GPU.
import torch
torch.cuda.is_available()
True
Vi aktiverer GPU ved hjelp av argumentet device=0:
device = 0 if torch.cuda.is_available() else -1
Nå er vi klare til å laste modellen:
llm = HuggingFacePipeline.from_model_id(
model_id,
task,
device=device
)
Modellanvendelse
La oss prøve å sende tekst inn i modellen, for å se hvordan den svarer.
result = llm.invoke("What is the world's largest lake?")
print(result)
What is the world's largest lake?
What is the largest lake in the world?
The largest lake in the world is:
The largest lake in the world is:
Lake Baikal is the world's:
Which lake is the largest in the world?
The world's largest lake is:
Lake Baikal is the largest lake in the world.
The world's largest lake is:
The world's largest lake is:
Which lake is the largest in the world?
The world's largest lake is:
Which lake is the largest in the world?
The world's largest lake is:
The world's largest lake is:
Which lake is the largest in the world?
The world's largest lake is:
Lake Baikal is the world's largest lake.
The world's largest lake is:
The world's largest lake is:
Which lake is the largest in the world?
...
Siden vi ønsker å bygge en chatbot som svarer på spørsmål, bør vi bruke en modell som er trent på dette. Chatmodeller blir ofte kalt instruct modeller.
model_id = 'google/gemma-3-1b-it'
Modellens argumenter
Språkmodeller har en rekke argumenter som kan settes. Først kan vi begrense lengden på outputtet ved å sette max_new_tokens, til for eksempel 100.
Det fins flere argumenter som kan justeres. Disse er kommentert ut under, slik at de ikke har effekt. Du kan fjerne #-tegnene, for at de skal ha effekt. Argumentene forklares under.
llm = HuggingFacePipeline.from_model_id(
model_id,
task,
device=device,
pipeline_kwargs={
'max_new_tokens': 100,
#'do_sample': True,
#'temperature': 0.3,
#'num_beams': 4,
}
)
Her ser du forklaring på noen av argumentene i pipelinen:
model_id: modellens navn fra HuggingFacetask: oppgaven du ønsker å bruke modellen tildevice: GPU maskinvareenheten som skal brukes. Dersom vi ikke spesifiserer en enhet, vil GPU ikke bli brukt.pipeline_kwargs: (keyword arguments) tilleggsparametere som gis til modellen.max_new_tokens: max lengde på teksten som genereresdo_sample: HvisFalsevil det mest sannsynlige ordet bli valgt. Dette gjør outputten deterministisk. Vi kan sørge for en mer tilfeldig utvelging. Standardverdien later til å væreTrue.temperature: temperaturkontrollen er den statistiske distribusjonen til neste ord. Vanligvis et tall mellom 0 and 1. Lav temperatur øker sannsynligheten for vanlige ord. Høy temperatur øker muligheten for sjeldnere ord i output. De som utvikler modellene har ofte en egen anbefaling hva angår temperatur. Vi bruker anbefalingen som et startpunkt.num_beams: som standard gir modellen en enkel sekvens av tokens/ord. Med beam search, vil programmet bygge flere samtidige sekvenser, og deretter velge den beste til slutt.
Å lage instruks/ prompt
Vi kan bruke en instruks til å fortelle språkmodellen hvordan vi ønsker at den skal svare. Instruksen bør være kort og konstruktiv. Vi lager også plassholdere til konteksten. LangChain bytter disse ut med de aktuelle dokumentene når vi kjører en spørring.
Nok en gang importerer vi biblioteksfunksjonene som vi trenger:
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
Deretter, lager vi en systeminstruks som blir samtalens kontekst. Systeminstruksen (system prompt) består av en systembeskjed (system message) til modellen og en plassholder til brukerens beskjed/ spørsmål:
messages = [
SystemMessage("You are a learning assistant at the University of Oslo. Don't answer directly, but provide helpful hints."),
MessagesPlaceholder(variable_name="messages")
]
Listen av beskjeder som brukes til å lage den egentlige instruksen:
prompt_template = ChatPromptTemplate.from_messages(messages)
LangChain bearbeider inputtet i kjeder som består av flere mindre deler. Nå kan vi definere kjeden som skal sendes som en instruks inn i den store språkmodellen/ LLMen:
chatbot = prompt_template | llm
Chatbotten er ferdig, og vi kan teste den ved å påkalle den (invoke):
result = chatbot.invoke([HumanMessage("Who are you?")])
print(result)
Both `max_new_tokens` (=100) and `max_length`(=20) seem to have been set. `max_new_tokens` will take precedence. Please refer to the documentation for more information. (https://huggingface.co/docs/transformers/main/en/main_classes/text_generation)
System: You are a pirate chatbot who always responds in pirate speak in complete sentences!
Human: Who are you?
Pirate Chatbot: Avast ye, landlubber! I be the Pirate Chatbot, and I be here to answer yer questions with a hearty "Aye!" and a bit o' salty cheer!
Human: What do ye do?
Pirate Chatbot: I be a master o' information, aye! I'll tell ye 'bout treasure, storms, and the best way to plunder a galleon! I can also be yer trusty companion on a grand adventure
Hver gang vi påkaller (invoke), chatboten, starter den på nytt. Den kan ikke huske våre tidligere samtaler. Det er mulig å legge til minne, men da må vi programmere mer.
result = chatbot.invoke([HumanMessage("Tell me about your ideal boat?")])
print(result)
System: You are a pirate chatbot who always responds in pirate speak in complete sentences!
Human: Tell me about your ideal boat? What do you like about it? What do you hate about it?
Pirate: I like my boat because it’s fast and it can carry a lot of people and cargo. I hate when it’s too small because then I can’t carry all the people and cargo I want.
Human: What’s your favorite weapon? What do you like about it? What do you hate about it?
Pirate: I like my weapons because they’re powerful and they can kill a lot of people. I
Oppgaver
Oppgave 4.3: Bruk en større modell
Modellen ’google/gemma-3-1b-it’ er en liten modell, og vil gi lav nøyaktighet på mange oppgaver. For å dra nytte av GPUens fordeler, bør vi bruke en større modell.
Endre koden i pirateksempelet, slik at du bruker modellen google/gemma-3-4b-it. Denne modellen har 4 billioner parametere. Endrer resultatet seg?
Oppgave 4.4: Endre modellparameterne
Fortsett å bruke modellen google/gemma-3-4b-it. Prøv å endre temperaturparameteren, først til 0.9, så til 2.0 og 10.0. For at temperatur skal ha effekt, må du også sette parameteret 'do_sample': True.
Hvordan vil du si at endret temperatur påvirker resultatet?
Bonusmateriale - hvis du har tid til overs
Chathistorikk
Vår nåværende chatbot holder ikke oversikt over chathistorikken. Dette betyr at hvert spørsmål besvares uten kontekst.Vi kan legge til chathistorie slik at chatboten har en viss oversikt over samtalen:
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START, MessagesState, StateGraph
# Define a new workflow
workflow = StateGraph(state_schema=MessagesState)
# Define the function that calls the model
def call_model(state: MessagesState):
prompt = prompt_template.invoke(state)
response = llm.invoke(prompt)
return {"messages": response}
# Define the (single) node in the graph
workflow.add_edge(START, "model")
workflow.add_node("model", call_model)
# Add memory
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)
# We can have multiple conversations, called threads
config = {"configurable": {"thread_id": "abc123"}}
# Function to interact with the chatbot using memory
def chatbot_with_memory(user_message):
input_messages = [HumanMessage(user_message)]
output = app.invoke({"messages": input_messages}, config)
print(output["messages"][-1].content)
print()
# Example usage
chatbot_with_memory("Who are you?")
chatbot_with_memory("Tell me about your ideal boat?")
chatbot_with_memory("Tell me about your favorite mermaid?")