Curs 1 — Primul apel către un LLM¶
LLM-uri, API-uri și parametri de generare¶
În acest notebook facem primul apel către un model Gemini folosind Python. Scopul nu este să construim încă un agent, ci să înțelegem structura minimă a unui apel către un LLM:
- modelul folosit
- mesajele trimise către model
- parametrii de generare
- outputul primit La finalul notebook-ului trebuie să avem:
- API key configurată corect în
.env - un prim apel funcțional către Gemini
- un rezumat neutru generat de model
- un mic experiment cu
temperature - un output salvat împreună cu parametrii folosiți
0. Instalare pachete¶
# Rulează o singură dată. Dacă ești în Google Colab, sari peste acest pas.
#%pip install -q openai python-dotenv requests
1. Instalare biblioteci¶
Folosim biblioteca openai, dar nu folosim un model OpenAI.
Folosim Gemini prin endpoint-ul compatibil cu formatul OpenAI.
- sintaxa
messages = [{"role": "...", "content": "..."}]este foarte răspândită și ne va ajuta mai târziu să lucrăm și cu OpenRouter, DeepSeek sau alte modele compatibile.
2. Configurarea cheii API¶
https://aistudio.google.com/api-keys
Cheia API nu se scrie direct în notebook.
O salvăm într-un fișier local numit .env.
Fișierul .env trebuie să conțină:
GEMINI_API_KEY=cheia_ta_aici
!Important:
nu urca niciodată .env pe GitHub
în repository trebuie să existe doar .env.example
dacă ai publicat cheia accidental, șterge cheia din Google AI Studio și generează alta
import os
from dotenv import load_dotenv
from openai import OpenAI
from google import genai
3. Creăm clientul API¶
Clientul este obiectul prin care trimitem cereri către model. Aici avem trei lucruri importante:
api_key: cheia personalăbase_url: adresa endpoint-ului Gemini compatibil cu formatul OpenAImodel: modelul pe care îl vom folosi în apel
from dotenv import load_dotenv
import os
load_dotenv()
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
if not GEMINI_API_KEY:
raise ValueError("Missing GEMINI_API_KEY. Add it to your .env file.")
from openai import OpenAI
client = OpenAI(
api_key=GEMINI_API_KEY,
base_url="https://generativelanguage.googleapis.com/v1beta/openai/"
)
MODEL = "gemini-2.5-flash"
print("Client configurat.")
print("Model selectat:", MODEL)
Client configurat. Model selectat: gemini-2.5-flash
4. Primul apel minimal¶
Începem cu cel mai simplu caz: trimitem o singură întrebare către model și primim un răspuns.
Aici nu folosim încă system message, nu definim un rol special și nu construim o conversație.
Vrem doar să verificăm că:
- cheia API funcționează
- modelul răspunde
- înțelegem forma minimă a unui apel
response = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "user", "content": "Say hello."}
]
)
print(response.choices[0].message.content)
Hello!
# raspunsul modelului
response.choices[0].message.content
'Hello!'
response
ChatCompletion(id='JRvvaaXoMueynsEPusrdsQM', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='Hello!', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None))], created=1777277734, model='gemini-2.5-flash', object='chat.completion', service_tier=None, system_fingerprint=None, usage=CompletionUsage(completion_tokens=2, prompt_tokens=4, total_tokens=31, completion_tokens_details=None, prompt_tokens_details=None))
- ChatCompletion(...) = obiectul complet returnat de API. Nu este doar textul, ci răspunsul + metadata.
- id='JRvvaaXoMueynsEPusrdsQM' = identificator unic al apelului. Util pentru debugging/loguri.
- object='chat.completion' = tipul obiectului returnat. Confirmă că este un răspuns de tip chat completion.
- created=1777277734 = timestamp intern al momentului când a fost creat răspunsul.
- model='gemini-2.5-flash' = modelul care a generat răspunsul.
- choices=[...] = lista de răspunsuri generate. De obicei folosim primul răspuns: choices[0].
- index=0 = poziția răspunsului în lista choices. Aici este primul și singurul răspuns.
- message=ChatCompletionMessage(...) = mesajul generat de model.
- message.content='Hello!' = textul efectiv al răspunsului. Îl accesezi cu:
- response.choices[0].message.content
- message.role='assistant' = rolul mesajului generat. Modelul răspunde ca assistant.
- finish_reason='stop' = modelul s-a oprit normal. Nu a fost tăiat de limită.
- logprobs=None = nu ai cerut probabilități pentru tokeni.
- refusal=None = modelul nu a refuzat cererea.
- annotations=None = nu există adnotări suplimentare returnate.
- audio=None = nu există output audio.
- function_call=None = modelul nu a cerut apelarea unei funcții vechi-style.
- tool_calls=None = modelul nu a cerut folosirea unui tool.
- service_tier=None = nu apare un nivel special de serviciu raportat.
- system_fingerprint=None = providerul nu a returnat o amprentă internă a sistemului.
- usage=CompletionUsage(...) = informații despre tokeni consumați.
- prompt_tokens=4 = tokenii trimiși către model în cerere.
- completion_tokens=2 = tokenii generați de model în răspuns.
- total_tokens=31 = totalul raportat de provider. La Gemini prin compatibilitate OpenAI poate include overhead intern, deci nu trebuie tratat mereu ca simpla sumă prompt + completion.
- completion_tokens_details=None și prompt_tokens_details=None = nu există detalii suplimentare despre tokeni.
response = client.chat.completions.create(
model=MODEL,
messages=[
{
"role": "system",
"content": ""
"You are a clear teacher explaining AI to sociology students."
},
{
"role": "user",
"content": "Explain what a large language model is in 3 simple sentences."
}
],
temperature=0.3
)
print(response.choices[0].message.content)
A Large Language Model (LLM) is a type of artificial intelligence trained on massive amounts of text data, like books and websites. It learns to understand, generate, and translate human language by recognizing complex patterns in words and sentences. Essentially, an LLM predicts the most probable next word in a sequence, allowing it to create coherent and contextually relevant text.
5. Mai multe modele¶
models_to_test = [
"gemini-2.5-flash",
"gemini-2.5-flash-lite",
]
for model_name in models_to_test:
response = client.chat.completions.create(
model=model_name,
messages=[
{"role": "user", "content": "Explain what an LLM is in one simple sentence."}
]
)
print("=" * 60)
print("MODEL:", model_name)
print(response.choices[0].message.content)
============================================================ MODEL: gemini-2.5-flash An LLM is a large artificial intelligence system trained to understand and generate human-like text. ============================================================ MODEL: gemini-2.5-flash-lite An LLM is a powerful computer program trained on vast amounts of text and code that can understand, generate, and manipulate human-like language.
response
ChatCompletion(id='kBzvaamLMsSNkdUPte3qgAM', choices=[Choice(finish_reason='length', index=0, logprobs=None, message=ChatCompletionMessage(content='A Large Language Model (', refusal=None, role='assistant', annotations=None, audio=None, function_call=None, tool_calls=None))], created=1777278099, model='gemini-2.5-flash', object='chat.completion', service_tier=None, system_fingerprint=None, usage=CompletionUsage(completion_tokens=5, prompt_tokens=26, total_tokens=222, completion_tokens_details=None, prompt_tokens_details=None))
6. Exercițiu: rezumat neutru al unei știri¶
Vom da modelului un text scurt și îi cerem să producă un rezumat neutru. Regulă:
- maximum 60 de cuvinte
- fără opinie personală
- fără exagerări
- fără informații care nu apar în text
news_text = """
Guvernul a anunțat un nou program de finanțare pentru modernizarea transportului public în orașele mari.
Programul include achiziția de autobuze electrice, modernizarea stațiilor și extinderea sistemelor de ticketing digital.
Reprezentanții ministerului spun că scopul este reducerea poluării și creșterea accesului la transport public.
Unele organizații civice au cerut criterii clare de alocare a fondurilor și transparență în implementare.
"""
prompt = f"""
Rezuma textul de mai jos în maximum 60 de cuvinte.
Rezumatul trebuie să fie neutru, clar și factual.
Nu adăuga informații care nu apar în text.
TEXT:
{news_text}
"""
response = client.chat.completions.create(
model=MODEL,
messages=[
{
"role": "system",
"content": "You summarize public-interest texts in a neutral and factual way."
},
{
"role": "user",
"content": prompt
}
],
temperature=0.2,
)
summary = response.choices[0].message.content
print(summary)
Guvernul a anunțat un program de finanțare pentru modernizarea transportului public în orașele mari. Acesta include achiziția de autobuze electrice, modernizarea stațiilor și extinderea sistemelor de ticketing digital. Scopul declarat este reducerea poluării și creșterea accesului. Organizațiile civice au cerut criterii clare de alocare a fondurilor și transparență în implementare.
7. Ce face temperature?¶
temperature controlează cât de variat este răspunsul.
- valori mici: răspunsuri mai stabile, mai previzibile
- valori mari: răspunsuri mai creative, dar uneori mai puțin precise
Pentru analiză socială, clasificare și rezumate factuale, începem de obicei cu valori mici:
0,0.2,0.3. Pentru generare creativă putem folosi valori mai mari.
test_prompt = """
Descrie în două propoziții ce este un model lingvistic mare.
Explică pentru studenți de sociologie, fără jargon tehnic.
"""
temperatures = [0.0, 0.7, 1.5]
for temp in temperatures:
response = client.chat.completions.create(
model="gemini-2.5-flash-lite",
messages=[
{
"role": "system",
"content": "You explain AI concepts clearly and briefly."
},
{
"role": "user",
"content": test_prompt
}
],
temperature=temp,
max_tokens=120
)
print("=" * 80)
print("TEMPERATURE:", temp)
print(response.choices[0].message.content)
================================================================================ TEMPERATURE: 0.0 Un model lingvistic mare este ca un asistent super inteligent care a citit o cantitate uriașă de texte, de la cărți la articole de pe internet. Datorită acestei "lecturi" extinse, el poate înțelege și genera limbaj uman, ajutându-ne să scriem, să rezumăm informații sau chiar să purtăm conversații. ================================================================================ TEMPERATURE: 0.7 Un model lingvistic mare este un program de calculator antrenat pe o cantitate uriașă de text, învățând astfel să înțeleagă și să genereze limbaj uman. Gândește-te la el ca la cineva care a citit o bibliotecă imensă și poate acum să vorbească, să scrie și să răspundă la întrebări pe baza a tot ce a învățat despre cum comunicăm noi. ================================================================================ TEMPERATURE: 1.5 Imaginează-ți un model lingvistic mare ca pe un student extrem de studios, care a citit o cantitate imensă de texte de pe internet, inclusiv cărți, articole și conversații. Datorită acestui antrenament extensiv, el a învățat cum funcționează limbajul, care cuvinte se potrivesc cel mai bine împreună și chiar poate înțelege subtilitățile sensurilor, asemănător modului în care noi, oamenii, ne formăm înțelegerea lumii prin expunere și
8. Mini-interpretare¶
Completați după rulare:
- Care răspuns a fost cel mai stabil?
- Care răspuns a fost cel mai creativ?
- Care răspuns este mai potrivit pentru cercetare academică?
- Ce valoare de
temperatureați folosi pentru rezumate neutre? TODO: Scrieți aici observațiile voastre.
9. Funcție simplă pentru apeluri repetate¶
MODEL = "gemini-2.5-flash-lite"
def ask_model(
user_message,
system_message="You are a helpful assistant.",
model=MODEL,
temperature=0.3,
max_tokens=300
):
response = client.chat.completions.create(
model=model,
messages=[
{
"role": "system",
"content": system_message
},
{
"role": "user",
"content": user_message
}
],
temperature=temperature,
max_tokens=max_tokens
)
return response.choices[0].message.content
answer = ask_model(
user_message="Explain the difference between an LLM and an AI agent in 4 bullet points.",
system_message="You explain AI concepts to sociology students using simple language.",
temperature=0.3,
max_tokens=250
)
print(answer)
Here's the difference between an LLM and an AI agent, explained simply for sociology students: * **LLM (Large Language Model): The "Brain" for Talking.** Think of an LLM like a super-smart, incredibly well-read person who's really good at understanding and generating human language. It can write essays, answer questions, summarize text, and even translate, but it mostly just *talks* or *writes*. * **AI Agent: The "Brain" with a "Body" and "Goals."** An AI agent is like that same smart person, but now they can also *do things* in the world (even a digital world). They have a goal, can perceive their surroundings (like seeing a webpage or reading an email), and can take actions to achieve that goal. * **LLM is a Tool, Agent is a Doer.** An LLM is a powerful tool that an agent can *use*. For example, an agent might use an LLM to understand a customer's complaint (the LLM does the understanding) and then use that understanding to send a specific reply or take another action (the agent does the doing). * **
10. Salvăm outputul și parametrii¶
Trebuie să știm:
- ce model am folosit
- ce prompt am trimis
- ce parametri am setat
- ce răspuns am primit
import json
from datetime import datetime
from pathlib import Path
output_dir = Path("outputs")
output_dir.mkdir(exist_ok=True)
experiment = {
"timestamp": datetime.now().isoformat(),
"model": MODEL,
"temperature": 0.2,
"max_tokens": 120,
"task": "neutral_news_summary",
"input_text": news_text,
"output_text": summary
}
output_path = output_dir / "c1_first_summary.json"
with open(output_path, "w", encoding="utf-8") as f:
json.dump(experiment, f, ensure_ascii=False, indent=2)
print("Experiment salvat în:", output_path)
11. Verificăm fișierul salvat¶
Acum citim fișierul înapoi, ca să vedem că rezultatul a fost salvat corect.
with open(output_path, "r", encoding="utf-8") as f:
saved_experiment = json.load(f)
saved_experiment
12. Exercițiu scurt pentru studenți¶
Alegeți un text scurt, de 5–8 rânduri, dintr-o sursă publică. Poate fi despre transport, sănătate, educație, mediu sau costul vieții. Completați variabila de mai jos și generați un rezumat neutru. Apoi salvați rezultatul.
student_text = """
TODO: Lipiți aici un text scurt dintr-o sursă publică.
"""
student_prompt = f"""
Rezuma textul de mai jos în maximum 60 de cuvinte.
Rezumatul trebuie să fie neutru, clar și factual.
Nu adăuga informații care nu apar în text.
TEXT:
{student_text}
"""
student_summary = ask_model(
user_message=student_prompt,
system_message="You summarize public-interest texts in a neutral and factual way.",
temperature=0.2,
max_tokens=120
)
print(student_summary)
Vă rog să lipiți textul pe care doriți să îl rezum. Voi aștepta textul pentru a
student_experiment = {
"timestamp": datetime.now().isoformat(),
"model": MODEL,
"temperature": 0.2,
"max_tokens": 120,
"task": "student_neutral_summary",
"input_text": student_text,
"output_text": student_summary
}
student_output_path = output_dir / "c1_student_summary.json"
with open(student_output_path, "w", encoding="utf-8") as f:
json.dump(student_experiment, f, ensure_ascii=False, indent=2)
print("Experiment salvat în:", student_output_path)
13. Checklist pentru finalul Cursului 1¶
La finalul acestui notebook trebuie să aveți:
- API key funcțională
.envlocal configurat- primul apel către Gemini rulat cu succes
- un rezumat neutru generat
- experimentul cu
temperaturerulat - output salvat în
outputs/ .envadăugat în.gitignorePentru repository:README.md.env.example.gitignore- notebook-ul de Curs 1
- fără cheia API în GitHub
14. Ce luăm mai departe în Cursul 2¶
Acum știm să apelăm un model și să controlăm minim răspunsul. În Cursul 2 vom compara modele:
- același prompt
- modele diferite
- criterii simple de evaluare: claritate, factualitate, neutralitate, viteză Întrebarea următoare nu mai este „cum chemăm modelul?”, ci „ce model alegem pentru proiect?”.