Ga naar hoofdinhoud

GPT-OSS lokaal instellen en uitvoeren met Ollama

Leer hoe je GPT-OSS lokaal installeert, instelt en uitvoert met Ollama en een eenvoudige Streamlit-applicatie bouwt.
· 12 min lezen

Verken met AI

GPT-OSS is OpenAI’s eerste open-weight modelserie, en je kunt het rechtstreeks op je eigen computer draaien. Ontworpen voor krachtig redeneren, agentachtige taken en flexibele ontwikkelaarscenario’s, valt GPT-OSS op door de instelbare denk-inspanning en transparante chain-of-thought-mogelijkheden.

In deze tutorial laat ik je zien hoe je de GPT-OSS-modellen van OpenAI lokaal instelt met Ollama en demonstreer ik hoe je een interactieve demo bouwt die de unieke redeneercapaciteiten van het model laat zien. We verkennen de instelbare chain-of-thought-functies van het model en bouwen een Streamlit-applicatie die het denkproces van het model visualiseert.

We houden onze lezers op de hoogte van het laatste AI-nieuws via The Median, onze gratis vrijdagse nieuwsbrief die de belangrijkste verhalen van de week samenvat. Abonneer je en blijf scherp in slechts een paar minuten per week:

Wat is OpenAI’s GPT-OSS?

De GPT-OSS-serie van OpenAI is hun eerste open-weight release sinds GPT-2, waarmee je toegang krijgt tot high-performance redeneermodellen onder de Apache 2.0-licentie. Deze state-of-the-art taalmodellen leveren sterke prestaties tegen lage kosten en overtreffen open modellen van vergelijkbare grootte op redeneertaken.

Er zijn twee varianten: gpt-oss-120b en gpt-oss-20b.

GPT OSS Variants

Bron: OpenAI

gpt-oss-120b

gpt-oss-120b is OpenAI’s vlaggenschip open-weight model, met prestaties die kunnen wedijveren met propriëtaire systemen zoals o4‑mini op lastige redeneerbenchmarks. Ondanks de omvang van 117 miljard parameters is het geoptimaliseerd om op één 80 GB‑GPU te draaien. Dit maakt het een realistische optie voor onderzoekslabs en enterprise-teams die krachtige taalmodellen lokaal willen hosten.

Het model is ontworpen om complexe workflows te ondersteunen, zoals toolgebruik, redeneren in meerdere stappen en fijnmazige controle over hoeveel “denk”-inspanning het aan elke taak besteedt. Door het open-weight karakter en de Apache 2.0-licentie is het een flexibele keuze voor teams die het model diepgaand willen inspecteren, aanpassen of fine-tunen.

gpt-oss-20b

gpt-oss-20b biedt verrassend sterke redeneerprestaties in een footprint die past op consumentenlaptops. Met slechts 21 miljard parameters presteert het op sommige benchmarks nog steeds beter dan OpenAI’s o3-mini en draait het efficiënt op apparaten met 16 GB geheugen. Het is gekwantiseerd en klaargemaakt voor snelle lokale uitrol, en compatibel met tools zoals Ollama, vLLM en zelfs Apple’s Metal‑platform.

Dit model is ideaal voor developers die responsieve, private AI‑apps willen bouwen zonder afhankelijk te zijn van cloudinfrastructuur. Net als de grotere variant ondersteunt het een instelbare redeneerdiepte en duidelijke tussenstappen—perfect voor experimenten, lichtgewicht assistenten en edge‑device‑applicaties.

Waarom GPT-OSS lokaal draaien?

GPT-OSS lokaal draaien biedt een aantal overtuigende voordelen ten opzichte van cloudalternatieven:

  • Privacy en controle: Alle inferentie gebeurt op je eigen hardware, dus geen externe afhankelijkheden, storingen of API-wijzigingen, en je krijgt volledige toegang tot het interne redeneren van het model, niet alleen de eindantwoorden.
  • Prestaties: Lokale modellen elimineren netwerkvertragingen voor directe reacties, met onbeperkt gebruik (geen rate‑limits of tokenplafonds) en garanderen 24/7‑beschikbaarheid.
  • Kostenbesparing: Het model vereist eenmalig downloaden en instellen zonder abonnementskosten, en je kunt je bestaande compute‑resources gebruiken zonder doorlopende API‑kosten.
  • Transparant redeneren: Je kunt schakelen tussen lage, middelhoge en hoge “inspanning” om snelheid af te stemmen op diepgang, en de volledige chain‑of‑thought inspecteren.
  • Aanpasbaarheid en uitbreidbaarheid: We kunnen de open-weight modellen fine-tunen voor onze specifieke taken, samplingparameters bijstellen en agentachtige tools naadloos integreren.

GPT-OSS lokaal instellen met Ollama

Ollama maakt het lokaal draaien van large language models opvallend eenvoudig door downloads, kwantisatie en uitvoering te verzorgen. Ik neem je stap voor stap mee in het instellen van GPT-OSS op je systeem. Aan het eind ziet onze app er zo uit:

Streamlit app powered by gpt-oss and ollama

Stap 1: Installeer Ollama

Download en installeer eerst Ollama via de officiële website.

Download ollama

Na installatie kun je deze verifiëren door een terminal te openen en te typen:

ollama --version

Dit geeft de nieuwste versie van Ollama terug die op je systeem is geïnstalleerd.

Stap 2: Download de GPT-OSS‑modellen

OpenAI levert twee GPT-OSS‑varianten die zijn geoptimaliseerd voor verschillende use‑cases, maar voor deze demo halen we alleen de gpt-oss-20b‑variant binnen:

# Voor productie en zware redeneertaken 
ollama pull gpt-oss:120b
# Voor lagere latentie en lokale uitrol 
ollama pull gpt-oss:20b

Het 20B‑model is perfect voor lokale ontwikkeling en kan draaien op systemen met 16GB+ geheugen, terwijl het 120B‑model meer mogelijkheden biedt maar 80GB+ geheugen vereist.

Stap 3: Test de installatie

Laten we controleren of alles correct werkt:

ollama run gpt-oss:20b

Je zou een prompt moeten zien waarin je direct met het model kunt interageren. Probeer te vragen: "Bewijs dat √2 irrationaal is."

GPT-OSS lokaal gebruiken: interactieve chatbot

Laten we nu snel een eenvoudige app bouwen die de redeneercapaciteiten van GPT-OSS laat zien. Onze applicatie bevat:

  • Interactieve regelaars voor redeneren
  • Visualisatie van chain‑of‑thought
  • Prestatiemonitoring
  • Gespreksgeschiedenis

Stap 1: Installeer dependencies

Voer de volgende commando’s uit om de benodigde dependencies te installeren:

pip install streamlit ollama

De bovenstaande snippet installeert Streamlit voor de webinterface en de Ollama‑Pythonclient voor lokale interactie met het GPT-OSS‑model.

Stap 2: Libraries importeren en de pagina opzetten

Voordat we in de kernlogica van de chat duiken, halen we alle tools binnen en zetten we onze gebruikersinterface op.

import streamlit as st
import json
import ollama
import time
from typing import Dict, Any, List
import re
from datetime import datetime

# Configure page
st.set_page_config(
    page_title="GPT-OSS Chat Demo", 
    layout="wide",
    page_icon="💬"
)
# Custom CSS for UI
st.markdown("""
<style>
.reasoning-box {
    background-
    
    
    border-radius: 10px;
    border-left: 4px solid #00d4aa;
    
}
.answer-box {
    background-
    
    border-radius: 10px;
    border-left: 4px solid #007bff;
    
}
.metric-card {
    background-
    
    border-radius: 10px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
    text-align: center;
    
}
.chat-message {
    
    
    border-radius: 10px;
}
.user-message {
    background-
    border-left: 4px solid #2196f3;
}
.assistant-message {
    background-
    border-left: 4px solid #9c27b0;
}
</style>
""", unsafe_allow_html=True)

We importeren een paar kernpakketten zoals Streamlit voor onze webinterface, Ollama om het lokale GPT-OSS‑model aan te roepen, plus hulmodules zoals json, time, typing en re. Vervolgens gebruiken we st.set_page_config() om de pagina een titel, brede layout en een icoon te geven, en injecteren we lichte CSS zodat denkstappen en antwoorden in aparte panelen verschijnen.

Stap 3: Kernintegratie van het model

Met onze UI‑basis op z’n plek bouwen we nu onze kernfunctie voor modelintegratie, call_model():

def call_model(messages: List[Dict], model_name: str = "gpt-oss:20b", temperature: float = 1.0) -> Dict[str, Any]:
    try:
        start_time = time.time()        
        # Prepare options for Ollama
        options = {
            'temperature': temperature,
            'top_p': 1.0,
        }        
        response = ollama.chat(
            model=model_name, 
            messages=messages,
            options=options
        )
        end_time = time.time()        
        if isinstance(response, dict) and 'message' in response:
            content = response['message'].get('content', '')
        elif hasattr(response, 'message'):
            content = getattr(response.message, 'content', '')
        else:
            content = str(response)         
        return {
            'content': content, 
            'response_time': end_time - start_time, 
            'success': True
        }
    except Exception as e:
        return {
            'content': f"Error: {e}", 
            'response_time': 0, 
            'success': False
        }

De bovenstaande code:

  • Accepteert een lijst met chatberichten (systeem + gebruiker), zodat we eenvoudig context over meerdere beurten kunnen behouden.
  • Noteert vervolgens start_time en end_time rond de aanroep van ollama.chat() om de responstijd aan de gebruiker te tonen.
  • Normaliseert ook de responses van de Ollama‑client door de ruwe tekstoutput te extraheren.
  • Tot slot wikkelt de functie call_model() de hele aanroep in een try/except om fouten op te vangen.

Stap 4: Chain‑of‑thought‑parser

Om onze demo echt transparant te maken, moeten we de “innerlijke monoloog” van het model scheiden van het eindoordeel. De functie parse_reasoning_response() doet precies dat:

def parse_reasoning_response(content: str) -> Dict[str, str]:
    patterns = [
        r"<thinking>(.*?)</thinking>",
        r"Let me think.*?:(.*?)(?=\n\n|\nFinal|Answer:)",
        r"Reasoning:(.*?)(?=\n\n|\nAnswer:|\nConclusion:)",
    ]
    reasoning = ""
    answer = content    
    for pat in patterns:
        m = re.search(pat, content, re.DOTALL | re.IGNORECASE)
        if m:
            reasoning = m.group(1).strip()
            answer = content.replace(m.group(0), "").strip()
            break    
    if not reasoning and len(content.split('\n')) > 3:
        lines = content.split('\n')
        for i, l in enumerate(lines):
            if any(k in l.lower() for k in ['therefore', 'in conclusion', 'final answer', 'answer:']):
                reasoning = '\n'.join(lines[:i]).strip()
                answer = '\n'.join(lines[i:]).strip()
                break
    return {
        'reasoning': reasoning or "No explicit reasoning detected.", 
        'answer': answer or content
    }

We scheiden het verborgen “denken” van het model van het eindoordeel zodat gebruikers desgewenst elke redeneerstap kunnen bekijken. Zo wordt de response geparseerd:

  • Zoeken naar expliciete markeringen: Eerst zoekt het model naar <thinking>…</thinking>-tags of zinnen als “Reasoning:” en “Let me think through” met reguliere expressies.
  • Extractie en opschoning: Als er een match is, wordt dat segment het redeneren, en de rest wordt als antwoord beschouwd.
  • Heuristische fallback: Als er geen tags zijn maar de output uit meerdere regels bestaat, scant het op conclusie‑trefwoorden (“therefore”, “in conclusion”, “final answer” of “Answer:”) en splitst daar.
  • Output: Ongeacht de vorm geeft parse_reasoning_response() altijd een antwoord terug.

Stap 5: Volledige Streamlit‑applicatie

Nu we alle bouwstenen hebben gemaakt, zetten we ze samen tot een interactieve chatapp.

# Initialize history
if 'history' not in st.session_state:
    st.session_state.history = []
# Sidebar for settings
with st.sidebar:
    st.header("Configuration")    
    model_choice = st.selectbox(
        "Model", 
        ["gpt-oss:20b", "gpt-oss:120b"],
        help="Choose between 20B (faster) or 120B (more capable)"
    )    
    effort = st.selectbox(
        "Reasoning Effort", 
        ["low", "medium", "high"], 
        index=1,
        help="Controls depth of reasoning shown"
    )    
    temperature = st.slider(
        "Temperature", 
        0.0, 2.0, 1.0, 0.1,
        help="Controls response randomness"
    )    
    show_reasoning = st.checkbox(
        "Show Chain-of-Thought", 
        True,
        help="Display model's thinking process"
    )    
    show_metrics = st.checkbox(
        "Show Performance Metrics",
        True,
        help="Display response time and model info"
    )    
    st.markdown("---")        
    if st.button("Clear Conversation"):
        st.session_state.history = []
        st.rerun()  
# Main Chat Interface
st.title("💬 GPT-OSS Interactive Chat")
examples = [
    "",
    "If a train travels 120km in 1.5 hours, then 80km in 45 minutes, what's its average speed?",
    "Prove that √2 is irrational.",
    "Write a function to find the longest palindromic substring.",
    "Explain quantum entanglement in simple terms.",
    "How would you design a recommendation system?",
]
selected_from_dropdown = st.selectbox("Choose from examples:", examples)
# Get the question text
question_value = ""
if hasattr(st.session_state, 'selected_example'):
    question_value = st.session_state.selected_example
    del st.session_state.selected_example
elif selected_from_dropdown:
    question_value = selected_from_dropdown
question = st.text_area(
    "Or Enter your question:", 
    value=question_value, 
    height=100,
    placeholder="Ask anything! Try different reasoning effort levels to see how the model's thinking changes..."
)
# Submit button
col1, col2 = st.columns([1, 4])
with col1:
    submit_button = st.button("Ask GPT-OSS", type="primary")
if submit_button and question.strip():
    # System prompts 
    system_prompts = {
        'low': 'You are a helpful assistant. Provide concise, direct answers.',
        'medium': f'You are a helpful assistant. Show brief reasoning before your answer. Reasoning effort: {effort}',
        'high': f'You are a helpful assistant. Show complete chain-of-thought reasoning step by step. Think through the problem carefully before providing your final answer. Reasoning effort: {effort}'
    }    
    # Message history
    msgs = [{'role': 'system', 'content': system_prompts[effort]}]    
    msgs.extend(st.session_state.history[-6:])
    msgs.append({'role': 'user', 'content': question})    
    with st.spinner(f"GPT-OSS thinking ({effort} effort)..."):
        res = call_model(msgs, model_choice, temperature)
    if res['success']:
        parsed = parse_reasoning_response(res['content'])        
        st.session_state.history.append({'role': 'user', 'content': question})
        st.session_state.history.append({'role': 'assistant', 'content': res['content']})        
        col1, col2 = st.columns([3, 1] if show_metrics else [1])        
        with col1:
            if show_reasoning and parsed['reasoning'] != 'No explicit reasoning detected.':
                st.markdown("### Chain-of-Thought Reasoning")
                st.markdown(f"<div class='reasoning-box'>{parsed['reasoning']}</div>", unsafe_allow_html=True)            
            st.markdown("### Answer")
            st.markdown(f"<div class='answer-box'>{parsed['answer']}</div>", unsafe_allow_html=True)       
        if show_metrics:
            with col2:
                st.markdown(f"""
                <div class="metric-card">
                    <h4> Metrics</h4>
                    <p><strong>Time:</strong><br>{res['response_time']:.2f}s</p>
                    <p><strong>Model:</strong><br>{model_choice}</p>
                    <p><strong>Effort:</strong><br>{effort.title()}</p>
                </div>
                """, unsafe_allow_html=True)
    else:
        st.error(f"{res['content']}")
if st.session_state.history:
    st.markdown("---")
    st.subheader("Conversation History")    
    recent_history = st.session_state.history[-8:]  # Last 8 messages (4 exchanges)    
    for i, msg in enumerate(recent_history):
        if msg['role'] == 'user':
            st.markdown(f"""
            <div class="chat-message user-message">
                <strong>You:</strong> {msg['content']}
            </div>
            """, unsafe_allow_html=True)
        else:
            parsed_hist = parse_reasoning_response(msg['content'])
            with st.expander(f"GPT-OSS Response", expanded=False):
                if parsed_hist['reasoning'] != 'No explicit reasoning detected.':
                    st.markdown("**Reasoning Process:**")
                    st.code(parsed_hist['reasoning'], language='text')
                st.markdown("**Final Answer:**")
                st.markdown(parsed_hist['answer'])
# Footer
st.markdown("---")
st.markdown("""
<div style='text-align: center;'>
    <p><strong>Powered by GPT-OSS-20B via Ollama</strong></p>
</div>
""", unsafe_allow_html=True)

In deze laatste stap brengen we alle onderdelen van onze app samen—session state, zijbalkinstellingen, voorbeeldprompts, berichtopbouw, modelaanroep, parsing en weergave—tot één geheel:

  1. Initialisatie van session state: We gebruiken st.session_state.history om elke uitwisseling tussen gebruiker en assistent over reruns heen te onthouden.
  2. Zijbalkconfiguratie: Deze configuratie laat gebruikers het volgende kiezen
    • Model: gpt-oss:20b of gpt-oss:120b
    • Redeneerinspanning: laag/middel/hoog
    • Temperatuur: van 0 tot 2,0, wat de willekeur van het model regelt
    • Chain‑of‑Thought‑schakelaar: Om het interne redeneren van het model te tonen of te verbergen
    • Gesprek wissen: Hiermee wis je de geschiedenis en start je de app opnieuw
  3. Voorbeeldprompts en invoer: Een dropdown met startvragen helpt nieuwe gebruikers op weg, en wat de gebruiker selecteert (of typt) wordt de vraag in het tekstvak.
  4. Het verzoek opbouwen: Wanneer Ask GPT-OSS wordt geklikt, dan:
    • Maken we een systeemprompt op basis van het gekozen inspanningsniveau.
    • Voegen we de laatste zes berichten uit de geschiedenis toe om context te behouden.
    • Voegen we de nieuwe vraag van de gebruiker toe.
  5. Modelaanroep: We gebruiken de functie call_model(), die:
    • De samengestelde berichten naar Ollama stuurt
    • De responstijd meet
    • Een genormaliseerde contentstring teruggeeft
  6. Parsing en weergave: Met de functie parse_reasoning_response() splitsen we de output van het model in een chain‑of‑thought‑gedeelte (“reasoning”) en een opgeschoond gedeelte (“answer”).
  7. Beheer van geschiedenis: Elk paar van vraag en antwoord wordt toegevoegd aan de lijst st.session_state.history, zodat de volgende run ze voor context meeneemt.

Wil je het zelf proberen? Sla de code op als gpt_oss_demo.py en start:

streamlit run gpt_oss_demo.py

Conclusie

GPT-OSS van OpenAI is een van de beste open-weight modellen die je vandaag kunt draaien. Door Ollama’s vereenvoudigde uitrol te combineren met de interactieve mogelijkheden van Streamlit, hebben we een platform gemaakt dat het volgende laat zien:

  • Instelbare redeneerdiepte
  • Volledige lokale controle
  • Transparant denkproces

GPT-OSS, in combinatie met tools zoals Ollama, maakt geavanceerde AI‑mogelijkheden toegankelijk voor developers, onderzoekers en organisaties die privacy, controle en begrip vooropstellen.

Onderwerpen

Gerelateerd