Corso
Kimi K2.6 è l’ultimo modello open-source di Moonshot AI, pensato per il coding, l’esecuzione a lungo raggio, l’uso di tool e i workflow agentici. Il modello è disponibile tramite Kimi.com, l’app Kimi, Kimi Code e l’API, risultando utile per creare applicazioni AI pratiche che richiedono ragionamento, chiamate a strumenti e output strutturati.
In questo tutorial creerai JobFit AI, un assistente alla ricerca di lavoro basato su AI che legge il CV di un candidato, cerca annunci attivi, controlla le pagine selezionate e genera un report con punteggio di compatibilità. Kimi K2.6 è adatto a questo progetto perché supporta workflow a lungo contesto, chiamate a strumenti e modalità sia con ragionamento che senza attraverso la piattaforma API di Kimi.
Il progetto usa:
- Kimi K2.6 come modello di ragionamento
- Olostep per la ricerca web in tempo reale e lo scraping delle pagine di lavoro
- pypdf per estrarre testo dal CV del candidato
- OpenAI Agents SDK per costruire l’agente che usa tool
- Gradio per trasformare il workflow in una semplice web app
Alla fine del tutorial avrai un’app funzionante che consente agli utenti di caricare un CV, descrivere le preferenze di lavoro e generare in meno di un minuto un report con punteggio dei ruoli pertinenti.
Se stai appena iniziando con l’AI agentica, ti consiglio vivamente di iscriverti al percorso di competenze AI Agents Fundamentals. Copre tutte le basi dei pattern di progettazione, MCP e dei sistemi multi-agente.
Prerequisiti del tutorial
Prima di iniziare, assicurati di avere:
- Python 3.11+
- Una chiave API Kimi
- Almeno 5 $ di credito nel tuo account Moonshot AI
- Una chiave API Olostep
- Un CV in PDF
- Conoscenze di base di Python
1. Configura l’ambiente Python
Crea una nuova cartella di progetto:
mkdir JobFit-AI
cd JobFit-AI
Poi installa i pacchetti richiesti:
pip install gradio openai pypdf openai-agents
I principali pacchetti sono:
-
gradio: crea l’interfaccia web -
openai: si connette ad API compatibili con OpenAI -
pypdf: estrae testo dai file PDF -
openai-agents: crea l’agente AI che usa tool
Poi crea gli account e genera le tue chiavi API:
- Crea un account Olostep gratuito e genera una chiave API dalla dashboard di Olostep. Puoi anche iscriverti allo Starter plan a 9 $/mese, che include 5.000 richieste. Ti dà abbastanza richieste per testare e distribuire la tua app.
- Vai alla piattaforma Kimi, aggiungi almeno 5 $ di credito e genera la tua chiave API.
Imposta le chiavi API Kimi e Olostep come variabili d’ambiente. La MOONSHOT_API_KEY viene usata per accedere all’API di Kimi K2.6, mentre la OLOSTEP_API_KEY serve per cercare e fare scraping delle pagine di lavoro attive.
2. Definisci la configurazione del progetto
Avvia Jupyter Notebook, crea una nuova cella e aggiungi gli import necessari e la configurazione del progetto.
import json
import os
import requests
from agents import Agent, AsyncOpenAI, ModelSettings, OpenAIChatCompletionsModel, RunConfig, Runner, function_tool, set_tracing_disabled
from IPython.display import Markdown, display
from pypdf import PdfReader
Ora definisci il nome del modello, gli endpoint API, il numero massimo di turni dell’agente, il percorso del CV e le preferenze di lavoro.
KIMI_MODEL = "kimi-k2.6"
KIMI_BASE_URL = "https://api.moonshot.ai/v1"
OLOSTEP_SEARCH_URL = "https://api.olostep.com/v1/searches"
OLOSTEP_SCRAPE_URL = "https://api.olostep.com/v1/scrapes"
MAX_AGENT_TURNS = 25
cv_path = "abid-resume.pdf"
preferences = """
Remote data science, AI writer, or technical writer roles in AI, machine learning, data science, or cloud.
Prefer technical content, tutorials, developer education, research writing, and AI product storytelling.
""".strip()
set_tracing_disabled(True)
I valori di KIMI_MODEL e KIMI_BASE_URL indicano all’app di usare Kimi K2.6 tramite l’endpoint compatibile con OpenAI di Moonshot AI. Gli URL di Olostep sono usati per la ricerca di offerte attive e per lo scraping delle pagine.
La variabile cv_path punta al PDF del curriculum del candidato. Assicurati che il PDF sia salvato nella stessa cartella del progetto, oppure aggiorna il percorso se è altrove.
La variabile preferences indica all’agente che tipo di lavori cercare. Puoi aggiornarla in base al ruolo target, al settore, alla località, al livello di seniority o allo stile di lavoro preferito.
Disabilitiamo il tracing con set_tracing_disabled(True) perché è una funzionalità dell’OpenAI Agents SDK abilitata di default. Dato che questo progetto usa Kimi tramite un endpoint compatibile con OpenAI, disabilitarlo semplifica la configurazione locale ed evita problemi legati al tracing con un provider di modelli di terze parti.
3. Connettiti all’API Kimi K2.6
Quindi, configura il client Kimi usando la chiave API che hai salvato prima come variabile d’ambiente.
kimi_client = AsyncOpenAI(
api_key=os.environ["MOONSHOT_API_KEY"],
base_url=KIMI_BASE_URL,
)
Questo crea il client API per Kimi. La api_key è caricata da MOONSHOT_API_KEY e la base_url punta all’endpoint compatibile con OpenAI di Moonshot AI.
Poi, incapsula il modello Kimi in modo che possa essere usato nell’OpenAI Agents SDK:
kimi_model = OpenAIChatCompletionsModel(
model=KIMI_MODEL,
openai_client=kimi_client,
)
Ora definisci le impostazioni del modello:
model_settings = ModelSettings(
tool_choice="auto",
parallel_tool_calls=True,
extra_body={"thinking": {"type": "disabled"}},
)
L’impostazione tool_choice="auto" permette all’agente di decidere quando chiamare i tool. Con parallel_tool_calls=True l’agente può eseguire più chiamate a tool in parallelo quando serve.
Disabilitiamo anche la modalità “thinking” di Kimi con extra_body={"thinking": {"type": "disabled"}}. Mantiene l’output più pulito e adatto a un report di compatibilità strutturato.
Infine, crea la configurazione di esecuzione:
run_config = RunConfig(
workflow_name="JobFit AI Kimi Search",
tracing_disabled=True,
)
Il workflow_name assegna un’etichetta chiara a questa esecuzione. Manteniamo il tracing disabilitato perché questo progetto usa Kimi tramite un endpoint compatibile con OpenAI, non il backend di tracing di OpenAI.
4. Estrai il testo dal CV del candidato
Ora usa PdfReader per caricare il CV del candidato ed estrarre il testo da ogni pagina.
reader = PdfReader(cv_path)
cv_text = "\n".join(page.extract_text() or "" for page in reader.pages)[:12000]
print(f"Loaded {len(cv_text):,} characters from {cv_path}")
Questo codice legge il file PDF definito in cv_path, estrae il testo da ogni pagina e lo unisce in un’unica stringa.
Il limite [:12000] mantiene il testo del CV abbastanza corto da rientrare comodamente nel prompt dell’agente, fornendo al tempo stesso al modello contesto sufficiente su esperienza, competenze e preferenze del candidato.
L’output sarà simile a questo, a seconda del nome e della lunghezza del tuo file CV:
Loaded 2,946 characters from abid-resume.pdf
Questo conferma che il CV è stato caricato correttamente e mostra quante battute sono state estratte dal PDF.
5. Crea le istruzioni per l’agente
Ora definisci le istruzioni che controllano come l’agente deve cercare, usare i tool e formattare il report finale.
AGENT_INSTRUCTIONS = """
You are JobFit AI, a focused job-search agent.
Tool plan:
- Call search_jobs exactly once with limit 8.
- Read at most 3 direct job pages with read_job_page.
- After reading up to 3 pages, stop using tools and write the report.
- Search again only if the first search returns zero usable jobs.
- Avoid broad search pages, expired jobs, and LinkedIn unless no better source exists.
Report rules:
- Keep the report simple, clear, and practical.
- Use short bullets.
- Do not use em dashes.
- Do not use contractions.
- Do not add text before or after the report.
- End after the final Job Notes entry.
- Include at least 5 ranked jobs if the search results contain at least 5 usable jobs.
- If only 3 pages were scraped, use backup jobs from search results when they look usable.
- Every job must include a clickable Markdown link.
- Every job must have one apply decision: Apply, Maybe, or Do not apply.
Use exactly this Markdown structure:
# JobFit AI Report
## Best Match
- **Role:** <job title>
- **Company:** <company>
- **Apply decision:** Apply / Maybe / Do not apply
- **Fit score:** <score>/100
- **Link:** [Apply here](<job url>)
**Why this is the best match:**
- <specific reason>
- <specific reason>
- <specific reason>
## Ranked Jobs
| Rank | Role | Company | Apply? | Fit | Link |
| --- | --- | --- | --- | --- | --- |
| 1 | <role> | <company> | Apply / Maybe / Do not apply | <score>/100 | [Apply here](<url>) |
## Job Notes
### 1. <Role> at <Company>
- **Apply decision:** Apply / Maybe / Do not apply
- **Fit score:** <score>/100
- **Link:** [Apply here](<job url>)
**Why it fits:**
- <bullet>
- <bullet>
**Concerns:**
- <bullet>
- <bullet>
**Application angle:**
- <how the person should position their CV/application>
""".strip()
Queste istruzioni mantengono l’agente focalizzato. Limitano il workflow a una ricerca, fino a tre letture di pagine e una struttura di report Markdown fissa.
Le regole del report rendono anche l’output più rapido da scansionare, richiedendo punti elenco brevi, link cliccabili, punteggi di compatibilità e una chiara decisione di candidatura per ciascun ruolo.
6. Crea il prompt di runtime
Dopo aver definito le istruzioni dell’agente, crea il template di prompt che verrà passato all’agente durante ogni esecuzione.
RUN_PROMPT_TEMPLATE = """
Find current job postings for this candidate and rank them by fit.
Keep the run simple:
- one search
- up to three page reads
- final report
The final report must follow AGENT_INSTRUCTIONS exactly.
Use simple wording. Do not use em dashes. Do not use contractions.
Candidate CV:
{cv_text}
Preferences:
{preferences}
""".strip()
Questo prompt combina il testo del CV del candidato e le preferenze di lavoro a runtime.
Il segnaposto cv_text viene riempito con il contenuto estratto dal CV, mentre preferences con le preferenze di ruolo definite prima. Insieme forniscono all’agente abbastanza contesto per cercare ruoli pertinenti e classificarli per compatibilità.
7. Aggiungi la ricerca web live con Olostep
Ora che le istruzioni e il prompt di runtime sono pronti, aggiungi due strumenti che permettono all’agente di cercare sul web e leggere pagine di lavoro usando Olostep.
Il primo tool cerca sul web offerte di lavoro e restituisce un elenco compatto di risultati.
@function_tool
def search_jobs(query: str, limit: int = 8) -> str:
"""Search the web for job listings and return compact JSON results."""
response = requests.post(
OLOSTEP_SEARCH_URL,
headers={"Authorization": f"Bearer {os.environ['OLOSTEP_API_KEY']}", "Content-Type": "application/json"},
json={"query": query},
timeout=60,
)
response.raise_for_status()
links = response.json().get("result", {}).get("links", [])[:limit]
results = [
{"title": item.get("title", "Untitled"), "url": item.get("url"), "description": item.get("description", "")}
for item in links
if isinstance(item, dict) and item.get("url")
]
return json.dumps(results, ensure_ascii=False)
Il decorator @function_tool rende questa funzione Python disponibile all’agente come tool richiamabile.
Quando l’agente ha bisogno di offerte, chiama search_jobs con una query di ricerca. La funzione invia la query all’endpoint di ricerca Olostep, raccoglie i risultati principali e li restituisce in JSON.
Ogni risultato include:
- titolo del ruolo
- URL dell’offerta
- breve descrizione
Il secondo tool consente all’agente di aprire e leggere una specifica pagina di lavoro.
@function_tool
def read_job_page(url: str) -> str:
"""Scrape one job listing URL and return markdown text."""
response = requests.post(
OLOSTEP_SCRAPE_URL,
headers={"Authorization": f"Bearer {os.environ['OLOSTEP_API_KEY']}", "Content-Type": "application/json"},
json={"url_to_scrape": url, "formats": ["markdown"]},
timeout=120,
)
response.raise_for_status()
markdown = response.json().get("result", {}).get("markdown_content") or ""
return markdown[:8000]
Questa funzione invia un URL di un’offerta all’endpoint di scraping di Olostep e restituisce il contenuto della pagina in formato Markdown.
Il limite [:8000] mantiene la pagina estratta abbastanza breve da essere gestita dall’agente, preservando i dettagli più utili come responsabilità, requisiti e informazioni sull’azienda.
8. Crea l’agente JobFit AI
Ora crea l’agente e collega tutti i componenti definiti prima: il modello Kimi, le impostazioni del modello, gli strumenti Olostep e le istruzioni dell’agente.
agent = Agent(
name="JobFit AI",
model=kimi_model,
model_settings=model_settings,
tools=[search_jobs, read_job_page],
instructions=AGENT_INSTRUCTIONS,
)
L’oggetto Agent è il controller principale di questo workflow.
Usa:
kimi_modelcome modello di ragionamentomodel_settingsper controllare l’uso dei tool e il comportamento dell’outputsearch_jobsper trovare offerte attiveread_job_pageper fare scraping delle pagine selezionateAGENT_INSTRUCTIONSper seguire regole di ricerca e report esatte
A questo punto, l’agente è pronto per cercare lavori, confrontarli con il CV del candidato e generare un report JobFit AI strutturato.
9. Esegui il workflow dell’agente
Ora esegui l’agente JobFit AI usando il testo del CV estratto e le preferenze definite.
Per prima cosa, formatta il prompt di runtime:
prompt = RUN_PROMPT_TEMPLATE.format(cv_text=cv_text, preferences=preferences)
Questo riempie il template con il CV del candidato e le preferenze di ruolo target.
Poi avvia l’esecuzione in streaming dell’agente:
print("Starting agent run")
result = Runner.run_streamed(
agent,
prompt,
max_turns=MAX_AGENT_TURNS,
run_config=run_config,
)
Il metodo Runner.run_streamed() avvia il workflow e trasmette gli eventi in tempo reale. È più facile vedere quando l’agente chiama un tool, riceve l’output e crea il messaggio finale.
Ora aggiungi il loop di streaming:
async for event in result.stream_events():
if event.type == "agent_updated_stream_event":
print(f"Agent: {event.new_agent.name}")
elif event.type == "run_item_stream_event":
item = event.item
if event.name == "tool_called":
raw = item.raw_item
tool_name = raw.get("name") if isinstance(raw, dict) else getattr(raw, "name", "tool")
arguments = raw.get("arguments") if isinstance(raw, dict) else getattr(raw, "arguments", "")
arguments = str(arguments).replace(chr(10), " ")[:500]
print(f"Tool call: {tool_name}")
if arguments:
print(f"Parameters: {arguments}")
elif event.name == "tool_output":
print(f"Tool output: {len(str(item.output)):,} chars")
elif event.name == "message_output_created":
print("Final message ready")
Questo loop stampa aggiornamenti utili durante l’esecuzione. Per esempio, mostra quando l’agente cerca lavori, legge una pagina o conclude la generazione del report.
Infine, salva l’output finale in una variabile chiamata report:
report = result.final_output
globals()["report"] = report
print("Run complete")
print(f"Model responses: {len(result.raw_responses)}")
print(f"Run items: {len(result.new_items)}")
print(f"Final output: {len(str(report)):,} chars")
La variabile report contiene il report finale di JobFit AI, che puoi visualizzare, salvare o usare nella web app Gradio.
L’output sarà più o meno così:
Starting agent run
Agent: JobFit AI
Tool call: search_jobs
Parameters: {"query":"remote data science writer technical writer AI machine learning content editor","limit":8}
Tool output: 2,445 chars
Tool call: read_job_page
Parameters: {"url":"https://www.indeed.com/q-data-science-writer-jobs.html"}
Tool output: 8,000 chars
Tool call: read_job_page
Parameters: {"url":"https://www.builtinnyc.com/jobs/remote/data-analytics/data-science"}
Tool output: 8,000 chars
Tool call: read_job_page
Parameters: {"url":"https://www.virtualvocations.com/jobs/q-data+scientist+remote+jobs/c-writing/d-336"}
Tool output: 5,075 chars
Final message ready
Run complete
Model responses: 5
Run items: 13
Final output: 5,931 chars
Questo output conferma che l’agente ha cercato lavori, letto pagine selezionate e generato correttamente il report finale.
10. Visualizza il report JobFit generato
Dopo il completamento dell’esecuzione, visualizza il report finale in formato Markdown.
display(Markdown(report))
Questo rende il report JobFit AI direttamente nel notebook, più leggibile del semplice testo.
Il report include il miglior match, i ruoli classificati, i punteggi di compatibilità, le decisioni di candidatura, le criticità e gli spunti per l’applicazione.

11. Trasforma il workflow in una web app Gradio
Dopo aver testato il workflow nel notebook, puoi trasformarlo in una semplice web app Gradio. Crea un file app.py, poi copia il codice dal file JobFit-AI/app.py in GitHub e incollalo nel tuo file locale.
Esegui l’app con:
python app.py

Poi apri l’app locale nel browser all’URL mostrato (in questo caso, http://127.0.0.1:7860/):

La web app Gradio offre un’interfaccia semplice per generare report di compatibilità. Include:
- Un campo di upload del PDF del CV in cui caricare il curriculum.
- Una casella di testo per le preferenze, dove descrivere i ruoli desiderati, compresi tipo di ruolo, settore, località, seniority e argomenti preferiti.
- Un pulsante Generate JobFit Report per avviare il workflow dell’agente.
- Un log di avanzamento nascosto che appare durante l’esecuzione e mostra cosa sta facendo l’app, come leggere il CV, chiamare i tool e ricevere gli output.
- Un’area finale in Markdown che mostra il report classificato quando l’agente ha finito.
Dietro le quinte, l’app legge il CV caricato, estrae il testo, invia CV e preferenze all’agente JobFit AI e cerca offerte attive con Olostep. Legge fino a tre pagine di lavoro e restituisce un report Markdown strutturato con ruoli classificati, punteggi di compatibilità, decisioni di candidatura, criticità e spunti per l’applicazione.
12. Carica un CV e genera un report
Ora testa la web app caricando un PDF di CV o resume e cliccando Generate JobFit Report.
In questo esempio ho caricato un CV con circa tre anni di esperienza per verificare se l’app trovasse ruoli pertinenti in base al profilo e alle preferenze del candidato. Il report è stato generato in meno di un minuto.
Durante l’esecuzione, il log di avanzamento mostra ogni fase del workflow, tra cui:
- lettura del CV
- estrazione del testo da ogni pagina
- avvio dell’esecuzione dell’agente
- chiamata allo strumento di ricerca lavori
- ritorno dell’output dello strumento

Una volta conclusa l’esecuzione, l’app mostra il report finale in formato Markdown.
Il report inizia con il miglior match, seguito da una tabella di ruoli classificati. Poi fornisce note dettagliate per ciascun ruolo, incluso punteggio di compatibilità, decisione di candidatura, motivi della compatibilità, possibili criticità e un angolo di applicazione.

In questo esempio, il risultato principale era un ruolo di Senior Data Science Writer presso NannyML. Poiché il ruolo combaciava con il background del candidato in data science, scrittura tecnica e contenuti AI, sembrava un’ottima corrispondenza.
Puoi cliccare sul link Apply here nel report per aprire la pagina dell’offerta e rivedere l’annuncio completo prima di decidere se candidarti.

Nota: se riscontri problemi nell’eseguire il progetto in locale, consulta il repository GitHub: kingabzpro/JobFit-AI. Include il notebook, il file app.py e le istruzioni per l’installazione delle dipendenze e l’esecuzione locale.
Considerazioni finali
JobFit AI usa Kimi K2.6, Olostep e l’OpenAI Agent SDK per risolvere due problemi comuni per chi sta cambiando ruolo o sta attivamente cercando lavoro.
Il primo problema è sapere dove candidarsi. Esistono tanti job board, piattaforme e pagine “Careers”, ma non è sempre chiaro quali ruoli valgano il tuo tempo. Questa app aiuta a restringere il campo usando CV e preferenze del candidato per trovare ruoli più rilevanti per la sua esperienza.
Il secondo problema è filtrare troppi annunci. Invece di controllare manualmente ogni bacheca, l’agente cerca annunci attivi, legge pagine selezionate e crea un report strutturato con miglior match, ruoli classificati, punteggi, criticità e angoli di applicazione. È più facile concentrarsi sui ruoli che meritano davvero una candidatura.
L’API Kimi K2.6 si è comportata bene in questo workflow agentico. È stata veloce, affidabile ed efficace nel seguire istruzioni strutturate. Durante i test, consentendo fino a 25 turni, ha cercato e fatto scraping di più pagine in maggiore profondità, ma l’esecuzione ha richiesto circa cinque minuti. Per bilanciare qualità e velocità, ho ristretto il workflow a una ricerca e fino a tre letture di pagina, ottenendo il report in meno di un minuto.
Puoi migliorare la qualità del report aumentando il numero di passaggi, di risultati di ricerca o di pagine lette. Ad esempio, se aumenti il limite dell’agente a 30 turni e gli permetti di leggere più pagine, può produrre un report più approfondito con più ruoli e raccomandazioni più solide. Tuttavia, aumenteranno anche tempi di esecuzione e uso dell’API.
Se sei interessato a creare strumenti agentici simili, dai un’occhiata agli altri tutorial API su come costruire:
FAQ su Kimi K2.6
What is Kimi K2.6?
Kimi K2.6 è l’ultimo modello agentico open-weight di Moonshot AI, rilasciato ad aprile 2026. Si basa su un’architettura Mixture-of-Experts (MoE) con ~1 trilione di parametri totali, ne attiva 32 miliardi per forward pass, ed è ottimizzato per coding, uso di tool e task agentici a lungo orizzonte.
What is Kimi K2.6's context window?
Kimi K2.6 supporta una finestra di contesto da 262.144 token (256K). È quindi adatto a elaborare interi codebase, documenti lunghi o run agentiche multi-step in un’unica sessione.
How much does Kimi K2.6 cost via API?
Direttamente tramite l’API di Kimi, i token di input costano 0,95 $/1M (cache miss) e 0,16 $/1M (cache hit), con output a 4,00 $/1M token. Alcuni provider di terze parti offrono in parte tariffe più basse, a partire da circa 0,60 $/1M input e 2,80 $/1M output.
Does Kimi K2.6 support a thinking mode?
Sì, Kimi K2.6 supporta sia la modalità thinking (ragionamento esteso) sia la modalità instant (risposte più rapide, senza thinking). Nel tutorial, la modalità thinking è esplicitamente disabilitata tramite extra_body={"thinking": {"type": "disabled"}} per mantenere gli output più puliti e veloci.
How does Kimi K2.6 perform on agentic coding benchmarks?
Kimi K2.6 ottiene 80,2 su SWE-Bench Verified, risultando il modello open-source più forte a quel livello, con performance appena dietro a modelli chiusi come Claude Opus 4.6 (80,8%) e Gemini 3.1 Pro (80,6%). Su BrowseComp, segna 83,2, che sale a 86,3 con la modalità Agent Swarm, posizionandosi subito dietro GPT-5.5 Pro (90,1) e il non pubblicato Claude Mythos Preview (86,9).
In quanto data scientist certificato, sono appassionato di sfruttare tecnologie all’avanguardia per creare applicazioni di machine learning innovative. Con una solida esperienza in riconoscimento vocale, analisi e reportistica dei dati, MLOps, AI conversazionale e NLP, ho affinato le mie competenze nello sviluppo di sistemi intelligenti in grado di avere un impatto concreto. Oltre alla mia expertise tecnica, sono anche un comunicatore efficace, con il talento di rendere chiari e sintetici concetti complessi. Di conseguenza, sono diventato un blogger molto seguito in ambito data science, condividendo idee ed esperienze con una community in crescita di professionisti dei dati. Attualmente mi concentro sulla creazione e sull’editing di contenuti, lavorando con large language model per sviluppare contenuti potenti e coinvolgenti che possano aiutare aziende e singoli a valorizzare al meglio i propri dati.


