Leerpad
OpenAI’s o4-mini is de nieuwste toevoeging aan de o-serie van redeneergerichte AI-modellen. In deze tutorial laat ik je stap voor stap zien hoe je een beoordelaar voor wetenschappelijke artikelen bouwt met OpenAI’s o4-mini API. De tool zal:
- Inhoud uit wetenschappelijke artikelen (PDF’s) extraheren.
- Zwakke argumenten, onbewezen claims of gebrekkige methodologie uitlichten.
- Verbeteringen voorstellen en een conclusie geven.
We breiden onze review-assistent ook uit met ondersteuning voor statistische tools, zodat het model op aanvraag p-waardes, effectgroottes en betrouwbaarheidsintervallen kan berekenen.
We houden onze lezers op de hoogte van het laatste AI-nieuws met The Median, onze gratis nieuwsbrief op vrijdag die de belangrijkste verhalen van de week samenvat. Abonneer je en blijf scherp in een paar minuten per week:
Waarom O4-Mini gebruiken?
OpenAI’s o4-mini is een kostenefficiënt, high-performance redeneermodel dat diepgaande analyses kan uitvoeren voor taken zoals programmeren, wiskunde en wetenschappelijke redeneringen. Ondanks dat het kleiner is dan het o3-model, behaalt het consistent state-of-the-art resultaten op benchmarks zoals AIME 2024/2025 en GPQA.
Dankzij de snelheid en betaalbaarheid is het ideaal voor taken zoals het beoordelen van wetenschappelijke artikelen, het genereren van codeuitleg of hulp bij competitieve wiskundevragen. De belangrijkste sterke punten zijn:
- Topprestaties in wiskunde en codering voor zijn grootte.
- Lage latentie, geschikt voor taken met hoog volume.
- Efficiënt qua geheugen en kosten, perfect voor demo’s, experimenten en onderzoekstools.
Wil je meer weten? Lees dan deze introductieblog over o4-mini.
Projectoverzicht: Beoordelaar voor wetenschappelijke artikelen met O4-Mini
We bouwen een Python-gebaseerde beoordelaar voor wetenschappelijke artikelen die het volgende kan:
- Een door de gebruiker geüpload artikel accepteren (PDF of tekst).
- Inhoud uit het artikel extraheren.
- O4-mini’s redeneervermogen gebruiken om te analyseren op logische fouten of zwakke argumenten.
- Een gestructureerde review van zwaktes en suggesties tonen.
Dit project draait volledig lokaal en gebruikt de API van OpenAI.
Stap 1: Toegang krijgen tot O4-Mini via de OpenAI API
Om o4-mini te gebruiken, heb je een API-sleutel van OpenAI nodig. Zo doe je dat:
- Ga naar https://platform.openai.com/account/api-keys
- Log in en klik op Create new secret key.
- Geef het een naam (bijv. "o4-mini-key") en bewaar het veilig.
- Zorg dat je tegoed toevoegt aan je account via de billing-sectie.
Nu kun je authenticeren en de API vanuit Python aanroepen.
Stap 2: Installeer afhankelijkheden
Laten we beginnen met het installeren van een paar afhankelijkheden en het instellen van een omgevingsvariabele voor onze API-sleutel.
pip install openai PyMuPDF tiktoken numpy
export OPENAI_API_KEY =” YOUR_KEY”
Stap 3: Hulpcode voor statistiek
Nu de afhankelijkheden geregeld zijn, gaan we naar onze helperfuncties. Deze functies worden door het LLM aangeroepen via tool calls wanneer dat nodig is.
Stap 3.1: Imports
Deze imports worden gebruikt om t-toetsen, standaardfouten en betrouwbaarheidsintervallen te berekenen.
from scipy.stats import ttest_ind, sem, t
import numpy as np
Stap 3.2: p-waarde opnieuw berekenen
Deze functie voert een t-toets van Welch uit tussen twee onafhankelijke steekproefgroepen. Ze test de hypothese dat de gemiddelden van de twee groepen statistisch van elkaar verschillen.
def recalculate_p_value(group1, group2):
t_stat, p_value = ttest_ind(group1, group2, equal_var=False)
return {"p_value": round(p_value, 4)}
De functie recalculate_p_value() retourneert de p-waarde, afgerond op vier decimalen, die aangeeft hoe waarschijnlijk het is dat het waargenomen verschil op toeval berust. Dit helpt het LLM claims over statistische significantie in het artikel te valideren.
Stap 3.3: Cohen’s d berekenen
Cohen’s d is een gestandaardiseerde maat voor effectgrootte tussen twee groepen. Eerst worden de gemiddelden en standaarddeviaties van elke groep berekend. Vervolgens wordt de gepoolde standaarddeviatie gebruikt om het verschil tussen gemiddelden te normaliseren.
def compute_cohens_d(group1, group2):
mean1, mean2 = np.mean(group1), np.mean(group2)
std1, std2 = np.std(group1, ddof=1), np.std(group2, ddof=1)
pooled_std = np.sqrt((std1**2 + std2**2) / 2)
d = (mean1 - mean2) / pooled_std
return {"cohens_d": round(d, 4)}
De functie retourneert de Cohen’s d-waarde, afgerond op vier decimalen. Dit helpt het LLM de praktische significantie (niet alleen statistische) van groepsverschillen te begrijpen. Dat is vooral waardevol wanneer de steekproefgrootte groot is en p-waardes op zichzelf niet veelzeggend zijn.
Stap 3.4: Betrouwbaarheidsinterval berekenen
We definiëren nu een helper om het betrouwbaarheidsinterval voor één steekproefgroep te berekenen. Betrouwbaarheidsintervallen zijn nuttig om de betrouwbaarheid van een geschat gemiddelde te begrijpen—met andere woorden, hoeveel onzekerheid er rond de gemiddelde waarde zit.
def compute_confidence_interval(data, confidence=0.95):
data = np.array(data)
n = len(data)
mean = np.mean(data)
margin = sem(data) * t.ppf((1 + confidence) / 2., n-1)
return {
"mean": round(mean, 4),
"confidence_interval": [round(mean - margin, 4), round(mean + margin, 4)],
"confidence": confidence
}
Dit is wat deze functie retourneert:
mean: De gemiddelde waarde van de invoergegevens.confidence_interval: Een lijst met de onder- en bovengrens waarbinnen het ware gemiddelde waarschijnlijk valt, op basis van het opgegeven betrouwbaarheidsniveau.confidence: Het gebruikte betrouwbaarheidsniveau voor het interval.
Stap 3.5: Groepsstatistieken
We sluiten de helperfuncties af met een eenvoudige helper die het gemiddelde, de standaarddeviatie en de steekproefgrootte samenvat.
def describe_group(data):
data = np.array(data)
return {
"mean": round(np.mean(data), 4),
"std_dev": round(np.std(data, ddof=1), 4),
"n": len(data)
}
Dit helpt het LLM de onderliggende dataverdeling te interpreteren en biedt essentiële context voor het beoordelen van resultaten. Door statistische beschrijvingen zoals gemiddelde, standaarddeviatie en aantal bloot te leggen, versterken onze tools het redeneervermogen van het model bij experimenten en claims in artikelen.
Stap 4: Beoordelaar voor wetenschappelijke artikelen met toolondersteuning
In deze sectie bouwen we de Python-gebaseerde beoordelaar die OpenAI’s o4-mini API gebruikt en toolondersteuning voor statistische analyses bevat, zodat het model strenge evaluaties en onderbouwde kritieken kan leveren.
Stap 4.1: Imports
We beginnen onze hoofdcode met een paar essentiële libraries om PDF-inhoud te extraheren, te tokenizen en met de OpenAI API te communiceren.
import os
import fitz
import openai
import json
import tiktoken
from statistics_helper import (
recalculate_p_value,
compute_cohens_d,
compute_confidence_interval,
describe_group
)
openai.api_key = os.getenv("OPENAI_API_KEY")
Laten we nu stap voor stap de volledige pijplijn bouwen.
Stap 4.2: Tekst uit PDF extraheren
We beginnen met het uitlezen van ruwe tekst uit het artikel. Met de fitz-library kunnen we over alle pagina’s itereren en de geëxtraheerde tekst samenvoegen tot één string.
def extract_text_from_pdf(path):
doc = fitz.open(path)
full_text = "\n".join(page.get_text() for page in doc)
return full_text
Dit legt de basis. We gaan de ruwe tekst nu tokenizen en in stukken opdelen voordat we die naar het model sturen.
Let op: ik heb een nep-wetenschappelijk artikel gegenereerd voor demodoeleinden, met opzet voorzien van fouten in logica en experimenteel ontwerp.
Stap 4.3: Chunken
LLM’s hebben contextlimieten, dus we delen lange documenten op in behapbare stukken. We gebruiken Tiktoken om de tekst te tokenizen op basis van het coderingsschema van het model.
def chunk_text(text, max_tokens=12000, model="o4-mini"):
encoding = tiktoken.get_encoding("cl100k_base")
tokens = encoding.encode(text)
chunks = []
for i in range(0, len(tokens), max_tokens):
chunk = tokens[i:i + max_tokens]
chunk_text = encoding.decode(chunk)
chunks.append(chunk_text)
return chunks
Zo werkt het:
- Eerst gebruiken we
tiktokenom de volledige documenttekst te tokenizen met decl100k_base tokenizer, die compatibel is met moderne OpenAI-modellen zoals GPT-4, GPT-4o en o4-mini. - De getokenizeerde tekst wordt vervolgens opgesplitst in segmenten van
max_tokenslengte. Dit zorgt ervoor dat elk stuk binnen de maximale invoergrootte van het model blijft, wat essentieel is om token-overflowfouten tijdens inferentie te voorkomen. - Vervolgens wordt elk tokensstuk terug gedecodeerd naar leesbare tekst met
encoding.decode(). Dit behoudt natuurlijke formuleringen en opmaak, zodat het model tijdens de verwerking samenhangende context krijgt. - Tot slot worden alle gedecodeerde stukken verzameld in een lijst en geretourneerd. Deze chunks kunnen vervolgens één voor één naar het LLM worden gestuurd voor review, analyse of generatie.
Deze chunkstap is essentieel om afkappingsfouten tijdens inferentie te voorkomen en garandeert dat er geen belangrijke tekst wegvalt door overflow.
Stap 4.4: Toolmapping
Voordat het model externe functies kan aanroepen, moeten we een mapping definiëren tussen functienamen (zoals het model ze ziet) en de daadwerkelijke Python-functies die worden uitgevoerd. Deze mapping vormt de brug tussen de tool calls van het model en onze lokale codebase.
tool_function_map = {
"recalculate_p_value": recalculate_p_value,
"compute_cohens_d": compute_cohens_d,
"compute_confidence_interval": compute_confidence_interval,
"describe_group": describe_group,
}
Elke sleutel in dit woordenboek komt overeen met een functienaam waarnaar het model kan verwijzen tijdens een toolaanroep, en elke waarde is de daadwerkelijke Python-functie die is geïmporteerd uit de module statistics_helper.
Stap 4.5: Toolfuncties definiëren
Om het redeneervermogen van het model te verbeteren, registreren we tools die het LLM kan aanroepen via function calling. Deze tools behandelen statistische analyses zoals p-waardeherberekening, betrouwbaarheidsintervallen en effectgroottes.
tools = [
{
"type": "function",
"name": "recalculate_p_value",
"description": "Calculate p-value between two sample groups",
"parameters": {
"type": "object",
"properties": {
"group1": {"type": "array", "items": {"type": "number"}},
"group2": {"type": "array", "items": {"type": "number"}}
},
"required": ["group1", "group2"]
}
},
{
"type": "function",
"name": "compute_cohens_d",
"description": "Compute effect size (Cohen's d) between two groups",
"parameters": {
"type": "object",
"properties": {
"group1": {"type": "array", "items": {"type": "number"}},
"group2": {"type": "array", "items": {"type": "number"}}
},
"required": ["group1", "group2"]
}
},
{
"type": "function",
"name": "compute_confidence_interval",
"description": "Compute confidence interval for a sample group",
"parameters": {
"type": "object",
"properties": {
"data": {"type": "array", "items": {"type": "number"}},
"confidence": {"type": "number", "default": 0.95}
},
"required": ["data"]
}
},
{
"type": "function",
"name": "describe_group",
"description": "Summarize sample mean, std deviation, and count",
"parameters": {
"type": "object",
"properties": {
"data": {"type": "array", "items": {"type": "number"}}
},
"required": ["data"]
}
}
]
Met bovenstaande tooldefinitie kan het LLM begrijpen:
- Wat de tool doet (
description) - Hoe de tool wordt aangeroepen (
name) - Welke input wordt verwacht, inclusief verplichte velden en types (arrays van getallen in dit geval)
Het LLM beslist intelligent wanneer een tool moet worden aangeroepen, zoals het opnieuw berekenen van een p-waarde, op basis van de context van de review. Wanneer het een statistische claim of twijfelachtig resultaat tegenkomt, kan het de juiste helperfunctie aanroepen, de output ontvangen en zijn redenering met dat resultaat voortzetten. Dit maakt een grondigere en beter onderbouwde analyse mogelijk, waarbij het model niet alleen bekritiseert maar ook de onderliggende data verifieert.
Stap 4.6: De chunk reviewen
We definiëren nu de kernlogica die elke tekstchunk naar het o4-mini-model stuurt. Als het een tool aanroept, handelen we de functieaanroep af en zetten we het gesprek voort.
def review_text_chunk(chunk):
try:
response = client.responses.create(
model="o4-mini",
reasoning={"effort": "high"},
input=[
{
"role": "system",
"content": (
"You are an expert AI research reviewer. Read the given chunk of a research paper and highlight weak arguments."
"unsupported claims, or flawed methodology. You can request tools to: Recalculate p-values, Compute confidence intervals, "
"Estimate effect size (Cohen's d), Describe sample statistics. Be rigorous and explain your reasoning. "
"Conclude with suggestions and a verdict."
)
},
{
"role": "user",
"content": chunk
}
],
tools = tools,
)
# Check for tool calls
for item in response.output:
if getattr(item, "type", None) == "function_call":
fn_call = getattr(item, "function_call", {})
fn_name = getattr(fn_call, "name", "")
args = getattr(fn_call, "arguments", {})
if fn_name in tool_function_map:
tool_result = tool_function_map[fn_name](**args)
# Send back tool result as continuation input
tool_response = client.responses.create(
model="o4-mini",
reasoning={"effort": "high"},
input=[
*response.output,
{
"role": "tool",
"name": fn_name,
"content": str(tool_result)
}
],
max_output_tokens=3000
)
if hasattr(tool_response, "output_text") and tool_response.output_text:
return tool_response.output_text.strip()
# If no tool was called, return original response
if hasattr(response, "output_text") and response.output_text:
return response.output_text.strip()
if response.status == "incomplete":
reason = getattr(response.incomplete_details, "reason", "unknown")
return f" Incomplete response: {reason}"
return " No valid output returned by the model."
except Exception as e:
return f" Error during chunk review: {e}"
De functie review_text_chunk is verantwoordelijk voor het sturen van elke chunk van het artikel naar het LLM, samen met een systeemprompt en toolregister. Zo werkt het stap voor stap:
- Systeempromptdefinitie: een systeemprompt instrueert het model om zich te gedragen als een expert-beoordelaar van AI-onderzoek. Het vertelt het model om:
- De chunk van het artikel te analyseren op logische fouten, onbewezen claims en methodologische problemen.
- Het moedigt het model ook aan om tools te gebruiken zoals gedefinieerd in de vorige sectie. Deze prompt bepaalt de rol van het LLM en stuurt aan op analytische diepgang.
- Eerste redeneeraanroep van het model: de chunk en de systeemprompt worden naar het model gestuurd met de functie
client.responses.create()die deResponses APIgebruikt voor redeneren. In deze aanroep:- Het model staat op
"o4-mini", en de vlagreasoning={"effort": "high"}staat op hoog, wat gedetailleerde meerstapsinterne redenering stimuleert. Deze instelling geeft het model aan hoe diep het moet “nadenken” voordat het een eindantwoord genereert. Het bepaalt het aantal interne redeneertokens dat het model mag gebruiken. - De parameter tools geeft een lijst door met beschikbare functietools die het model kan aanroepen.
- Er is geen expliciete
tool_choice="auto"nodig, omdat de Responses API automatisch beslist over toolgebruik.
- Het model staat op
- Afhandeling van toolgebruik: als het model besluit een tool aan te roepen, dan:
- Halen we de functienaam en argumenten uit de toolaanroep door het gestructureerde responseobject te inspecteren.
- Roept de corresponderende lokale Python-functie aan met die argumenten.
- Geven we de tooloutput terug aan het model via een tweede aanroep van de methode
responses.create, waarbij we het toolresultaat als een bericht met de rol "tool" toevoegen. Dit simuleert een voortzetting van het redeneerproces.
- Interpretatie van het resultaat: als er een tool is aangeroepen, gebruikt het model het teruggegeven resultaat om de analyse te verfijnen en een beter onderbouwde kritiek te produceren. Als er geen tool nodig is, geeft het zijn oordeel direct terug uit de eerste aanroep.
Dit meerstaps redeneer- en verificatiemechanisme geeft het model een strenge reviewcapaciteit. Het bootst na hoe een menselijke reviewer een probleem zou signaleren, een snelle berekening zou doen en vervolgens de feedback zou bijstellen
Stap 4.7: Volledige papierreview
Als alle componenten klaar zijn, gebruiken we deze functie om een hele PDF te verwerken. Dit brengt alles samen.
def review_full_pdf(pdf_path):
raw_text = extract_text_from_pdf(pdf_path)
chunks = chunk_text(raw_text)
print(f"\n Extracted {len(chunks)} chunks from PDF\n")
all_reviews = []
for idx, chunk in enumerate(chunks):
print(f"\n Reviewing Chunk {idx + 1}/{len(chunks)}...")
review = review_text_chunk(chunk)
all_reviews.append(f"### Chunk {idx + 1} Review\n{review}")
full_review = "\n\n".join(all_reviews)
return full_review
Deze functie fungeert als wrapper om een volledig artikel te reviewen:
- Eerst wordt de inhoud geëxtraheerd en gechunkt.
- Vervolgens wordt elke chunk achtereenvolgens door het reviewproces gestuurd.
- Tot slot worden alle outputs samengevoegd tot één rapport.
Stap 4.8: De main-functie
We definiëren nu het toegangspunt van het script. Dit maakt het mogelijk om het programma direct vanuit de terminal te draaien met een PDF-bestandspad als input.
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Review an academic paper PDF for weak arguments.")
parser.add_argument("pdf_path", type=str, help="Path to the research paper PDF")
args = parser.parse_args()
review_output = review_full_pdf(args.pdf_path)
print("\n Final Aggregated Review:\n")
print(review_output)
with open("paper_review_output.md", "w") as f:
f.write(review_output)
print("\n Review saved to paper_review_output.md")
Dit blok doet het volgende:
- Het gebruikt
argparseom het pad naar een PDF te accepteren als command line-argument. - Vervolgens roept het de functie
review_full_pdf()aan om de volledige review te genereren. - Print het eindresultaat naar de console.
- Slaat de review tot slot op in Markdown-formaat (
paper_review_output.md) voor later gebruik of integratie.
Om deze code te draaien, typ je de volgende opdracht in de terminal:
python pdf_reviewer_assistant.py Fake_paper.pdf


Conclusie
In dit project hebben we een beoordelaar voor wetenschappelijke artikelen gemaakt met de o4-mini model-API van OpenAI. We hebben het vermogen van het model uitgebreid met realtime statistische tools, zodat het p-waardes, betrouwbaarheidsintervallen en effectgroottes opnieuw kan analyseren.
Deze demo legt de basis voor toekomstige integraties met PDF-interfaces, citatiecheckers of zelfs multimodale onderzoeksassistenten.
Wil je meer weten over recente OpenAI-releases? Bekijk dan deze blogs:
Ik ben een Google Developers Expert in ML (Gen AI), een Kaggle 3x Expert en een Women Techmakers Ambassador met meer dan 3 jaar ervaring in tech. In 2020 heb ik een healthtech-startup mee opgericht en ik volg een master computer science aan Georgia Tech, met als specialisatie machine learning.

