Integrare l’IA negli IDE

Integrare l'IA negli IDE' - 'Integrating AI in IDEs

L’IA ha dimostrato il suo immenso potenziale nell’aiutare le attività di codifica, come rispondere alle domande, generare frammenti di codice, spiegare il codice e rilevare problemi. Tuttavia, l’approccio attuale che utilizza interfacce utente Web come ChatGPT e si basa pesantemente sui metodi di copia e incolla può essere complicato e meno efficiente. Per massimizzare i benefici dell’IA nella codifica, è essenziale un’integrazione più stretta delle capacità dell’IA all’interno degli ambienti di sviluppo integrati (IDE) moderni. Sono possibili diverse idee per raggiungere questa integrazione senza soluzione di continuità, alcune delle quali sono già state implementate negli IDE come IntelliJ IDEA, mentre altre rappresentano opportunità inespresse.

Ci sono due concetti principali di tale integrazione: Azioni AI e Assistente AI (interfaccia utente di chat).

Azioni AI

Le Azioni AI sono attività che sfruttano l’IA per ottenere risultati desiderati. Ogni Azione AI dovrebbe:

  1. Preparare un prompt e un contesto, coinvolgere l’IA per elaborare i dati, raccogliere i risultati e presentarli all’utente nella forma più conveniente o apportare modifiche al codice.
  2. Preparare un prompt e un contesto, chiamare l’Assistente AI e consentire all’utente di completare il lavoro.
  3. Eseguire una combinazione complicata degli scenari 1 e 2.

Le Azioni AI possono essere eseguite in modi diversi:

  • Scatenate dalle richieste degli utenti (ad esempio, come refactoring)
  • Iniziate dai servizi di sistema su un programma, in background o quando appropriato (ad esempio, azioni di analisi del codice)

Intenzioni di codice AI

Nel mondo degli IDE moderni, una potente funzionalità che sta diventando sempre più diffusa è il concetto di “Intenzioni”. Queste Intenzioni offrono agli utenti la possibilità di eseguire azioni predefinite sul proprio codice in base al contesto specifico. Immagina, ad esempio, di lavorare con un’istruzione “for” e in quel contesto avere a disposizione varie Intenzioni come “Converti in while”, “Inverti l’ordine” o “Usa Streams”, tra le altre. L’utilizzo delle Intenzioni si rivela estremamente vantaggioso in quanto consente un rapido refactoring e manipolazione del codice, semplificando il processo di sviluppo.

Sviluppare Intenzioni, tuttavia, non è un compito facile e, pertanto, i fornitori di IDE le codificano e le includono nei rispettivi IDE. Sebbene alcuni IDE consentano agli sviluppatori di creare le proprie Intenzioni, questa impresa è piuttosto impegnativa e richiede una conoscenza approfondita della piattaforma IDE, una programmazione estensiva e la creazione di plugin per distribuire le nuove Intenzioni sviluppate.

Fortunatamente, con l’avvento di modelli di linguaggio basati sull’IA come ChatGPT, richiedere azioni legate al codice è diventato significativamente più semplice. Fornendo semplicemente un frammento di codice e un prompt a ChatGPT, il modello può eseguire facilmente l’azione desiderata. Ad esempio, se fornisci un ciclo a ChatGPT con il prompt “Inverti la direzione di un ciclo”, eseguirà facilmente la trasformazione specificata sul frammento di codice fornito.

E otterrai lo stesso risultato dell’Intenzione codificata:

È quindi abbastanza naturale introdurre Intenzioni AI, che sono essenzialmente prompt AI denominati legati a un determinato contesto. Il contesto può essere un file, una classe, un’istruzione, un metodo specifico, ecc. Quindi, un’Intenzione AI dovrebbe fornire un prompt, chiedere all’IDE un contesto, coinvolgere l’IA per elaborare i dati, raccogliere i risultati e presentarli all’utente nella forma più conveniente o apportare modifiche al codice.

Vantaggi delle Intenzioni AI:

  1. Quasi ogni refactoring può essere fatto utilizzando il linguaggio comune. I prompt possono essere semplici come “Sostituisci usando il formato” per API ben note (come PrintStream.println(String) in Java) o possono essere più complessi con istruzioni aggiuntive per API meno conosciute.
  2. Non è necessario codificare tali Intenzioni
  3. Non è necessario scrivere plugin per distribuire tali Intenzioni
  4. Tali Intenzioni possono essere facilmente configurate dall’utente.
  5. Non è necessario utilizzare un’interfaccia di chat, specialmente per azioni ripetitive
  6. Menor traffico di token LLM per risparmiare costi

Definire Intenzioni di Codice AI Con Annotazioni

Una caratteristica interessante e innovativa da considerare è l’integrazione delle intenzioni AI direttamente nell’API utilizzando le annotazioni. Introducendo intenzioni AI dichiarative, gli sviluppatori possono istruire l’IDE sulle intenzioni disponibili per ogni classe, campo o metodo e specificare i prompt appropriati per eseguire intenzioni specifiche attraverso l’assistenza di un modello di linguaggio come LLM. Queste intenzioni AI dichiarative possono essere fornite dagli autori di framework/librerie e sono accessibili in modo trasparente a tutti gli sviluppatori che utilizzano IDE che le supportano.

Come esempio illustrativo, diamo un’occhiata all’Intenzione AI “Sostituisci usando il formato”, che consente agli sviluppatori di sostituire le chiamate println(String) con chiamate più efficienti printls() che prendono formato e lista di argomenti come input:

Applicando tali Intenzioni a una chiamata:

System.out.println("i = " + i);

Risultati:

System.out.printf("i = %d%n", i);

Se l’IDE può fornire visualizzazioni renderizzate per alcuni elementi di testo nell’editor, un’Intenzione AI annotata può essere renderizzata nel codice solo con il titolo, nascondendo la lunga descrizione. Inoltre, tale rendering può contenere il pulsante inlaid Play che consente di eseguire quell’azione in un solo clic.

Azione di Correzione delle Deprecazioni

Un altro ottimo utilizzo delle Intenzioni AI dichiarative è affrontare le API deprecate. Quindi ogni metodo deprecato può includere annotazioni che definiscono Intenzioni AI speciali per consentire il refactoring di quel metodo in una versione moderna. Tali intenzioni AI possono essere invocate esplicitamente durante la modifica/esplorazione del codice. Oppure può esserci un’altra azione di livello superiore che raccoglierebbe tutti i metodi deprecati e correttamente annotati e chiederebbe allo sviluppatore di correggerne alcuni/tutti.

I vantaggi dell’utilizzo delle Intenzioni AI dichiarative per la gestione delle API deprecate sono numerosi. Riduce significativamente il tempo e lo sforzo necessari per mantenere e aggiornare il codice legacy, favorisce una transizione più fluida alle ultime tecnologie e pratiche migliori. Inoltre, migliora la collaborazione tra gli sviluppatori fornendo un approccio unificato per la gestione dei metodi deprecati in tutto il codice.

Azione TODO

In molti casi i commenti TODO (come // TODO:) forniscono istruzioni sufficienti per consentire a LLM di generare correttamente il codice richiesto per completare tali TODO. Ad esempio, il seguente codice:

sarà correttamente refattorizzato da LLM utilizzando la prompt “Completa TODO nel codice seguente” per diventare:

Quindi è abbastanza naturale raccogliere i commenti TODO e offrirli nell’elenco delle Azioni AI da eseguire. I TODO a livello di classe dovrebbero essere offerti ovunque nella classe, i TODO a livello di metodo dovrebbero essere offerti nello scope del metodo, ecc. Certamente, alcuni/molti TODO non possono essere completati utilizzando solo LLM e prompt generici, ma sarebbe a discrezione di uno sviluppatore specifico se invocarli o meno.

Se l’IDE può fornire visualizzazioni renderizzate per alcuni elementi di testo nell’editor, un TODO può essere renderizzato nel codice con un pulsante inlaid (come Play) che consente di completare quel TODO in un solo clic.

Azione Crea Metodo

Sarebbe bello permettere all’AI di generare la firma del metodo utilizzando il nome del metodo digitato e indovinando il tipo di ritorno e i parametri. Ad esempio, una prompt “Proporre firma per un metodo (con corpo vuoto): splitStringUsingRegex” produce abbastanza correttamente il seguente metodo:

Opzionalmente, includerebbe anche la generazione del corpo del metodo.

L’azione “Crea Metodo” deve essere invocata direttamente nell’editor di codice digitando il nome del metodo e premendo il tasto Tab (o un altro tasto di scelta rapida adatto) o scegliendo esplicitamente l’azione “Crea Metodo”.

Azione Suggerisci Dipendenze

LLM è competente nella generazione di codice basato sulle esigenze degli utenti. Tuttavia, il codice generato spesso si basa su librerie o framework di terze parti. Ciò può causare errori di compilazione se le dipendenze necessarie non sono già state aggiunte al progetto. Di conseguenza, trovare manualmente e aggiungere le dipendenze necessarie può richiedere più tempo rispetto all’ottenimento del codice stesso.

Per affrontare questo problema, un’aggiunta utile sarebbe un’azione “Suggerisci Dipendenze”. Questa azione consentirebbe agli utenti di richiedere a LLM (o a un modello specificamente addestrato) informazioni su determinati tipi di dipendenze, come librerie, Maven, Gradle, ecc. Se le dipendenze vengono trovate, possono essere applicate automaticamente al progetto, semplificando il processo e risparmiando tempo.

Ad esempio, coinvolgendo LLM per trovare la dipendenza Maven “org.json.JSONObject” potrebbe produrre il seguente suggerimento:

Questo può essere utilizzato per modificare le dipendenze di un progetto.

Azione Suggerisci Nome

Ci sono molte rifattorizzazioni del codice esistenti che introducono nuovi metodi di classe, parametri o variabili come “Estrai Metodo”, “Introduce Parametro”, ecc. Tutte le nuove cose, create durante tali rifattorizzazioni, dovrebbero essere correttamente denominate. Quindi è abbastanza naturale utilizzare LLM per trovare possibili nomi suggeriti in base al codice che viene rifattorizzato e mostrare quei nomi in un popup. Il recupero dei nomi richiederebbe tempo, quindi non dovrebbe essere invasivo e quindi dovrebbe essere eseguito in background.

Suggerisci l’azione di implementazione

Questa azione permetterebbe di generare l’implementazione dei metodi che hanno un corpo vuoto. LLM può essere molto preciso se il nome del metodo e i suoi argomenti definiscono chiaramente (come dovrebbero) lo scopo del metodo. Ad esempio, per il seguente metodo vuoto:

LLM suggerisce correttamente il suo corpo come:

Questa azione dovrebbe essere eseguita in background e il risultato dovrebbe essere applicato direttamente nell’editor di codice senza mostrare ulteriori interfacce utente e senza interrompere lo sviluppatore nel continuare a lavorare con l’IDE.

Probabilmente, dovrebbe esserci un’opzione per avviare l’azione “Suggerisci implementazione” nell’interfaccia utente della chat per avere un maggiore controllo, se necessario.

Suggerisci l’azione Regex

L’azione “Suggerisci Regex” dovrebbe essere disponibile per tutti i letterali di stringhe e dovrebbe prendere un letterale di stringa e utilizzarlo per interrogare l’IA per una Regex. Successivamente, il letterale di stringa dovrebbe essere sostituito da una Regex generata.

Forse questa azione dovrebbe essere disponibile solo per i letterali di stringa che iniziano con “Regex”.

Ad esempio, dopo aver invocato l’azione “Suggerisci regex” per un letterale di stringa nel seguente codice:

Il codice verrebbe modificato per includere una Regex generata:

Spiega l’azione del codice

L’azione “Spiega codice” dovrebbe utilizzare LLM con un prompt adeguato per ottenere una descrizione di cosa fa il codice. Per impostazione predefinita, tale spiegazione dovrebbe essere mostrata in un popup con la possibilità di passare tra la versione breve e la versione completa della spiegazione. Inoltre, dovrebbe esserci un’opzione per avviare l’azione “Spiega codice” nell’interfaccia utente della chat per avere un maggiore controllo, se necessario.

Commenta l’azione del codice

L’azione “Commenta codice” dovrebbe utilizzare LLM con una sorta di prompt “Spiega codice” e inserire una breve spiegazione del codice come commento proprio accanto al codice. Questa azione dovrebbe essere eseguita in background e il risultato dovrebbe essere applicato direttamente nell’editor di codice senza mostrare ulteriori interfacce utente e senza interrompere lo sviluppatore nel continuare a lavorare con il codice.

Spiega l’azione della stringa

Questa azione dovrebbe essere disponibile per i letterali di stringhe e dovrebbe mostrare una spiegazione in un popup. Dovrebbe esserci un’opzione per aprire questa spiegazione nell’interfaccia utente della chat se sono necessarie ulteriori spiegazioni o test.

LLM è molto bravo nel riconoscere ciò che è incorporato nella stringa, quindi questa azione funzionerà con un prompt piuttosto semplice. Ad esempio, LLM riconosce facilmente:

  • Regex più o meno complessi
  • Istruzioni SQL
  • Stringhe di formato Printf
  • Stringhe di formato MessageFormat
  • Ecc.

Quando LLM non riesce a rilevare il formato della stringa, dovrebbe esserci un prompt per descrivere un formato.

Trova l’azione dei problemi potenziali

La maggior parte degli IDE moderni include strumenti in grado di rilevare ed evidenziare tutti gli errori e gli avvisi di codice trovati da un compilatore e da strumenti di analisi del codice specifici dell’IDE.

Tuttavia, LLM può fornire una rilevazione aggiuntiva di problemi potenziali, specialmente in alcune situazioni molto complesse. Con un prompt adeguato, LLM può produrre rapporti strutturati sui problemi in forma testuale o in formato JSON. Quindi, il parsing e l’utilizzo di quel rapporto sarebbe piuttosto facile.

Quindi l’azione “Trova problemi potenziali” può utilizzare LLM con un prompt adeguato “Trova problemi nel codice” e nel contesto, analizzare i risultati e presentarli nella solita visualizzazione elenco dei messaggi, fornendo un’esperienza utente comune con navigazione del codice, ecc.

Suggerisci l’azione di refactoring

L’azione “Suggerisci refactoring” dovrebbe utilizzare LLM per ottenere una versione ottimizzata, corretta o leggermente migliorata del tuo codice.

Per impostazione predefinita, questa azione dovrebbe essere eseguita in background e il risultato dovrebbe essere applicato direttamente nell’editor di codice senza mostrare ulteriori interfacce utente intrusive. Dovrebbe esserci un’opzione per aprire questo refactoring nell’interfaccia utente della chat se sono necessari ulteriori passaggi, spiegazioni o test.

Se l’IDE può fornire viste renderizzate per alcuni elementi di testo nell’editor, un metodo refattorizzato può essere temporaneamente visualizzato con pulsanti Precedente/Successivo a destra che consentono di cambiare rapidamente le varianti del codice refattorizzato (se presenti).

Suggerisci l’azione del messaggio di commit

L’azione “Suggest Commit Message” dovrebbe utilizzare LLM per comporre un messaggio di commit VCS basato su un elenco curato delle modifiche effettuate nel progetto. Dovrebbe esserci un’opzione per passare tra diversi stili di messaggi come liste monolitiche o elenchi puntati.

Azione Genera Documentazione

L’azione “Genera Documentazione” dovrebbe utilizzare LLM per comporre la documentazione dello sviluppatore per metodi e classi in un formato specifico del linguaggio, ad esempio JavaDoc.

AI Assistant

AI Assistant fornisce un’interfaccia utente universale per la chat simile a quella offerta da ChatGPT, in modo che gli sviluppatori possano interagire con LLM, ottenere risposte e codice e commettere i risultati indietro se desiderato.

AI Assistant dovrebbe tenere traccia del contesto della chat e dovrebbe essere consapevole di dove si trova il punto di modifica. Ciò ci consente di:

  • Generare codice basato sul codice esistente (se la dimensione della finestra di contesto lo consente).
  • Controllare e modificare il codice da inserire per produrre risultati compilabili validi. Ad esempio:
    • Se AI Assistant ha prodotto un metodo, dovrebbe essere inserito correttamente a livello di classe, ignorando la posizione del cursore o posizionandolo nel posto più vicino valido.
    • Se AI Assistant produce un frammento di codice e il punto di inserimento non è nel metodo, può essere incluso in un metodo con il nome del metodo suggerito dall’AI.
    • Eccetera.
  • Evitare la generazione di una classe e un metodo main() fino a quando non viene esplicitamente richiesto di farlo.
  • Controllare i nomi per impedire la produzione di elementi con nomi duplicati.
  • Riutilizzare metodi già esistenti senza la necessità di generare duplicati (forse con una richiesta).

Dovrebbe esserci un playground integrato direttamente in AI Assistant. Quindi il codice generato può essere testato e debuggato sul posto senza la necessità di incollarlo nuovamente, aggiungere il metodo main(), compilare un progetto, ecc. Può essere fatto sia nell’AI Assistant stesso che in una finestra/vista correlata. Eventuali dipendenze mancanti ma necessarie dovrebbero essere risolte automaticamente (vedi l’azione “Suggest Dependencies” per ulteriori dettagli).

Nota: Sarebbe opportuno evitare di utilizzare AI Assistant nella maggior parte dei casi in cui si possono ottenere risultati sufficientemente buoni tramite una singola transazione LLM utilizzando un prompt adeguatamente progettato. AI Assistant dovrebbe essere utilizzato solo quando viene esplicitamente richiamato dall’utente o per azioni che RICHIEDONO diverse transazioni con il coinvolgimento diretto dell’utente necessario per ottenere i risultati desiderati ed è difficile progettare un’interfaccia utente dedicata.