Introduzione agli SDK per Agenti
La crescita degli agenti autonomi potenziati dall’IA ha trasformato il nostro modo di pensare alle applicazioni software. Questi agenti, capaci di comprendere, ragionare e agire in modo indipendente o semi-indipendente, promettono un futuro di sistemi altamente intelligenti e automatizzati. Al cuore della costruzione di tali agenti ci sono i Kit di Sviluppo Software per Agenti (SDK). Un SDK per Agenti fornisce gli strumenti fondamentali, le librerie e i framework necessari per progettare, sviluppare, distribuire e gestire agenti IA. Questa guida avanzata esplorerà un’analisi comparativa dei popolari SDK per Agenti, concentrandosi sulla loro architettura, caratteristiche avanzate, casi d’uso pratici e fornendo esempi di codice per illustrare i loro punti di forza e di debolezza. Esploreremo SDK prominenti come LangChain, AutoGen, LlamaIndex, e discuteremo delle alternative emergenti.
Componenti Fondamentali di un SDK per Agenti
Prima di esplorare specifici SDK, è cruciale comprendere i componenti architetturali comuni che forniscono:
- Integrazione LLM: Facilita la connessione fluida con vari Modelli di Lingua Grande (LLM) (es. OpenAI, Anthropic, modelli Hugging Face).
- Gestione dei Prompt: Strumenti per la costruzione, il templating e la gestione dei prompt per un’interazione ottimale con i LLM.
- Chiamata a Strumenti/Funzioni: Meccanismi per consentire agli agenti di interagire con API esterne, database o funzioni personalizzate per estendere le loro capacità.
- Gestione della Memoria: Sistemi per consentire agli agenti di mantenere il contesto, la cronologia delle conversazioni e le informazioni apprese attraverso le interazioni.
- Pianificazione e Ragionamento: Framework per consentire agli agenti di suddividere compiti complessi, pianificare i passi di esecuzione e ragionare sui risultati (es. ReAct, CoT).
- Orchestrazione degli Agenti: Strumenti per definire sistemi multi-agente, gestire la comunicazione e coordinare i compiti tra gli agenti.
- Osservabilità e Debugging: Funzionalità per il monitoraggio del comportamento degli agenti, il tracciamento dei percorsi di esecuzione e la risoluzione di problemi.
- Distribuzione e Scalabilità: Considerazioni e strumenti per distribuire agenti in ambienti di produzione e scalare le loro operazioni.
LangChain: Il Coltellino Svizzero dello Sviluppo Agenti
LangChain è senza dubbio lo SDK per Agenti più utilizzato e completo. È noto per la sua modularità e le ampie integrazioni, rendendolo una scelta potente per flussi di lavoro agentici complessi.
Architettura e Concetti Fondamentali
L’architettura di LangChain è costruita attorno a diverse astrazioni fondamentali:
- LLMs/ChatModels: Interfacce per interagire con vari fornitori di LLM.
- Prompts: Modelli per generare input per LLM.
- Chains: Sequenze di chiamate a LLM o ad altre utilità.
- Agenti: LLM potenziati con strumenti per interagire con il loro ambiente. Utilizzano un ‘ciclo di ragionamento’ (es. ReAct) per decidere quale strumento utilizzare.
- Tools: Funzioni che un agente può chiamare per eseguire azioni specifiche.
- Memory: Memorizza le interazioni passate per fornire contesto.
- Retrievers: Componenti per recuperare documenti da una base di conoscenza.
- VectorStores: Database per memorizzare embedding vettoriali.
Caratteristiche Avanzate e Esempio Pratico (Agente ReAct con Strumento Personalizzato)
LangChain eccelle nella creazione di agenti sofisticati con utilizzo di strumenti personalizzati e ragionamento complesso. Creiamo un agente LangChain in grado di rispondere a domande sui prezzi delle azioni attuali utilizzando uno strumento personalizzato e poi riassumere le notizie relative all’azienda.
Esempio: Agente Prezzo Azioni e Notizie
Per prima cosa, definiamo uno strumento personalizzato per recuperare i prezzi delle azioni:
from langchain.tools import BaseTool
from typing import Type
from pydantic import BaseModel, Field
import yfinance as yf
class StockPriceInput(BaseModel):
ticker: str = Field(description="Il simbolo del ticker azionario (es. MSFT per Microsoft).")
class StockPriceTool(BaseTool):
name = "get_stock_price"
description = "Utile per ottenere il prezzo attuale delle azioni di un'azienda."
args_schema: Type[BaseModel] = StockPriceInput
def _run(self, ticker: str) -> str:
try:
stock = yf.Ticker(ticker)
current_price = stock.history(period="1d")["Close"].iloc[-1]
return f"Il prezzo attuale di {ticker} è ${current_price:.2f}"
except Exception as e:
return f"Impossibile recuperare il prezzo delle azioni per {ticker}: {e}"
async def _arun(self, ticker: str) -> str:
raise NotImplementedError("Async non implementato per StockPriceTool")
Successivamente, ci integriamo con un’API di notizie (es. NewsAPI.org – assicurati di avere una chiave API) come altro strumento. Per brevità, utilizzeremo una funzione segnaposto per il recupero delle notizie:
from langchain.tools import tool
@tool
def get_company_news(company_name: str) -> str:
"""Utile per ottenere i titoli delle notizie recenti per un dato nome aziendale."""
# In uno scenario reale, questo chiamerebbe un'API di notizie
if "Microsoft" in company_name:
return "Notizie recenti su Microsoft: Annuncia una nuova partnership con l'IA, gli utili superano le aspettative."
elif "Apple" in company_name:
return "Notizie recenti su Apple: Vendite forti del Vision Pro, si vocifera del lancio di un nuovo iPhone."
else:
return f"Nessuna notizia recente trovata per {company_name}."
Ora, creiamo l’agente:
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_react_agent
from langchain import hub
# Inizializza LLM
llm = ChatOpenAI(temperature=0, model="gpt-4-turbo-preview") # o gpt-3.5-turbo
# Definisci gli strumenti che l'agente può utilizzare
tools = [StockPriceTool(), get_company_news]
# Ottieni il template del prompt ReAct dall'Hub di LangChain
prompt = hub.pull("hwchase17/react")
# Crea l'agente ReAct
agent = create_react_agent(llm, tools, prompt)
# Crea l'Executor dell'Agente
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, handle_parsing_errors=True)
# Esegui l'agente
print(agent_executor.invoke({"input": "Qual è il prezzo attuale delle azioni di Apple e quali sono le ultime notizie su di loro?"}))
# Output atteso (troncato per brevità):
# > Entrando nella nuova catena AgentExecutor...
# Pensiero: Devo prima trovare il prezzo delle azioni di Apple, poi cercare notizie su di loro.
# Azione: get_stock_price
# Input Azione: AAPL
# Osservazione: Il prezzo attuale di AAPL è $xxx.xx
# Pensiero: Ora ho il prezzo delle azioni. Devo ottenere le notizie per Apple.
# Azione: get_company_news
# Input Azione: Apple
# Osservazione: Notizie recenti su Apple: Vendite forti del Vision Pro, si vocifera del lancio di un nuovo iPhone.
# Pensiero: Ho sia il prezzo delle azioni che le notizie su Apple. Posso ora fornire una risposta completa.
# Risposta Finale: Il prezzo attuale delle azioni di Apple è $xxx.xx. Le notizie recenti su Apple includono forti vendite del Vision Pro e voci su un nuovo lancio dell'iPhone.
Questo esempio dimostra la capacità di LangChain di orchestrare più strumenti all’interno di un ciclo di ragionamento sofisticato (ReAct), rendendolo ideale per compiti che richiedono decisioni dinamiche.
Punti di Forza e Debolezza
- Punti di Forza: Estremamente flessibile e modulare, vasto ecosistema di integrazioni (LLM, vector stores, strumenti), forte supporto della comunità, eccellente per ragionamenti complessi e multi-step.
- Punti di Debolezza: Può avere una curva di apprendimento ripida, il codice boilerplate può accumularsi, il debugging delle prestazioni può essere difficile in catene complesse.
AutoGen: Conversazioni Multi-Agente e Orchestrazione
AutoGen di Microsoft si concentra sulle conversazioni multi-agente, consentendo agli sviluppatori di costruire sistemi in cui più agenti collaborano per risolvere compiti. Si enfatizza la flessibilità nel definire i ruoli degli agenti e i modelli di comunicazione.
Architettura e Concetti Fondamentali
I concetti fondamentali di AutoGen ruotano attorno a:
- Agenti: I mattoni fondamentali. Possono essere alimentati da LLM (
ConversableAgent) o agire come proxy umani (UserProxyAgent). - Conversazioni: Gli agenti comunicano inviando messaggi tra loro.
- GroupChat: Facilita le conversazioni tra più agenti in modo strutturato.
- Esecuzione del Codice: Gli agenti possono eseguire codice localmente o in un contenitore Docker.
Caratteristiche Avanzate e Esempio Pratico (Generazione e Revisione del Codice)
AutoGen eccelle in scenari in cui un compito si suddivide naturalmente in sotto-compiti che richiedono diverse competenze, simulati da diversi agenti. Creiamo un semplice sistema multi-agente per la generazione e revisione del codice.
Esempio: Generatore e Revisore di Codice Python
import autogen
# Configura LLM (assicurati di avere OPENAI_API_KEY impostato nelle variabili ambiente)
config_list = autogen.config_list_openai_aoai(exclude="aoai")
# Crea un UserProxyAgent per fungere da interfaccia umana
user_proxy = autogen.UserProxyAgent(
name="User_Proxy",
human_input_mode="NEVER", # Imposta su "ALWAYS" per il debug interattivo
max_consecutive_auto_reply=10,
is_termination_msg=lambda x: x.get("content", "").rstrip().endswith("TERMINATE"),
code_execution_config={
"work_dir": "coding",
"use_docker": False # Imposta su True per esecuzione isolata
},
)
# Crea un AssistantAgent per la generazione di codice
coder = autogen.AssistantAgent(
name="Coder",
llm_config={"config_list": config_list},
system_message="Sei un programmatore Python utile. Scrivi codice Python pulito ed efficiente."
)
# Crea un altro AssistantAgent per la revisione e il testing del codice
reviewer = autogen.AssistantAgent(
name="Reviewer",
llm_config={"config_list": config_list},
system_message="Sei un revisore di codice. Esamina il codice Python fornito per correttezza, efficienza e bug. Suggerisci miglioramenti e scrivi test se necessario."
)
# Crea un GroupChat per orchestrare la conversazione
groupchat = autogen.GroupChat(
agents=[user_proxy, coder, reviewer],
messages=[],
max_round=15,
speaker_selection_method="auto" # Lascia che AutoGen decida chi parla dopo
)
# Crea un GroupChatManager per gestire la chat di gruppo
manager = autogen.GroupChatManager(groupchat=groupchat, llm_config={"config_list": config_list})
# Inizia la conversazione
user_proxy.initiate_chat(
manager,
message="Scrivi una funzione Python che calcola efficientemente il n-esimo numero di Fibonacci. Il revisore lo controllerà e suggerirà dei test."
)
# Output previsto (semplificato e troncato):
# User_Proxy (al manager): Scrivi una funzione Python...
# Coder (al manager): Ecco il codice:
# ```python
# def fibonacci(n):
# if n <= 0: return 0
# elif n == 1: return 1
# else:
# a, b = 0, 1
# for _ in range(2, n + 1):
# a, b = b, a + b
# return b
# ```
# Reviewer (al manager): Sembra buono, efficiente usando l'approccio iterativo. Ecco un caso di test:
# ```python
# # test_fibonacci.py
# import pytest
# from your_module import fibonacci # Supponendo che il codice sia salvato in un modulo
# def test_fibonacci_zero(): assert fibonacci(0) == 0
# def test_fibonacci_one(): assert fibonacci(1) == 1
# def test_fibonacci_small_numbers():
# assert fibonacci(2) == 1
# assert fibonacci(3) == 2
# assert fibonacci(5) == 5
# def test_fibonacci_large_number():
# assert fibonacci(10) == 55
# ```
# User_Proxy (al manager): TERMINATE
Questo esempio dimostra come AutoGen faciliti un flusso di lavoro collaborativo, con agenti che assumono ruoli distinti e scambiano messaggi per raggiungere un obiettivo comune. Il UserProxyAgent può persino eseguire il codice generato se configurato per farlo.
Forze e Debolezze
- Forze: Eccellente per la collaborazione multi-agente, orchestrazione delle attività guidata dal linguaggio naturale, solide capacità di esecuzione del codice, intuitivo per costruire agenti conversazionali.
- Debolezze: Meno enfasi sul ragionamento interno complesso degli agenti (come ReAct per un singolo agente), può essere meno diretto per flussi di lavoro profondamente annidati e sequenziali rispetto alle catene di LangChain, gestire flussi di conversazione complessi può diventare complicato.
LlamaIndex: Integrazione Dati per LLM
Seppur non sia strettamente un 'Agent SDK' nel senso di LangChain o AutoGen, LlamaIndex è indispensabile per costruire agenti che devono interagire con e ragionare su vasti volumi di dati privati o specifici per un dominio. Si concentra su 'R' in RAG (Retrieval Augmented Generation).
Architettura e Concetti Chiave
L'architettura di LlamaIndex è incentrata sull'ingestione dei dati, l'indicizzazione e le interrogazioni:
- Loaders: Connettori a varie fonti di dati (PDF, database, API, ecc.).
- Nodes: Pezzi di dati ingeriti, spesso con metadati.
- Indexes: Rappresentazioni strutturate dei tuoi dati, ottimizzate per il recupero (es. VectorStoreIndex, KeywordTableIndex).
- Query Engines: Interfacce per interrogare gli indici, spesso utilizzando LLM per la sintesi.
- Retrievers: Componenti che recuperano nodi rilevanti da un indice basato su una query.
- Agents: LlamaIndex ha anche la propria astrazione di agente, spesso costruita attorno a un motore di query e strumenti, progettata per interagire con le fonti di dati.
Caratteristiche Avanzate & Esempio Pratico (Interrogazione di Dati Non Strutturati)
LlamaIndex eccelle nella costruzione di agenti che possono 'parlare' con i tuoi dati. Creiamo un agente in grado di rispondere a domande basandosi su una raccolta di documenti.
Esempio: Agente Q&A per Documenti
Assumiamo di avere una directory data/ contenente diversi file di testo (ad esempio, note di riunioni, descrizioni di prodotti).
import os
from llama_index.readers.simple import SimpleDirectoryReader
from llama_index.core import VectorStoreIndex, Settings
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core.agent import AgentRunner
from llama_index.core.tools import QueryEngineTool, ToolMetadata
# 1. Carica documenti da una directory
# Crea file di dati fittizi per la dimostrazione
if not os.path.exists("data"): os.makedirs("data")
with open("data/product_info.txt", "w") as f: f.write("Il nuovo prodotto XYZ presenta una fotocamera da 12MP, display OLED da 6.1 pollici e 256GB di memoria. Costa $999.")
with open("data/company_policy.txt", "w") as f: f.write("I dipendenti hanno diritto a 20 giorni di ferie pagate all'anno. Tutte le spese di viaggio devono essere approvate in anticipo.")
documents = SimpleDirectoryReader("data").load_data()
# 2. Configura LLM e Modello di Embedding (assicurati che OPENAI_API_KEY sia impostato)
Settings.llm = OpenAI(model="gpt-3.5-turbo", temperature=0)
Settings.embed_model = OpenAIEmbedding(model="text-embedding-ada-002")
# 3. Crea un VectorStoreIndex dai documenti
index = VectorStoreIndex.from_documents(documents)
# 4. Crea un motore di query dall'indice
query_engine = index.as_query_engine()
# 5. Definisci il motore di query come strumento per l'agente
query_engine_tool = QueryEngineTool(
query_engine=query_engine,
metadata=ToolMetadata(
name="document_qa_tool",
description="Può rispondere a domande sui documenti aziendali, informazioni sui prodotti e politiche."
),
)
# 6. Crea l'Agente LlamaIndex (utilizza OpenAI LLM di default se configurato)
agent = AgentRunner(tools=[query_engine_tool], llm=Settings.llm, verbose=True)
# 7. Esegui l'agente
response = agent.chat("Quali sono le specifiche del nuovo prodotto XYZ?")
print(response)
# Output previsto:
# > Ingresso nel ciclo dell'agente.
# Pensiero: L'utente sta chiedendo informazioni sulle specifiche del prodotto. Dovrei usare il `document_qa_tool` per interrogare i documenti caricati.
# Chiamata Strumento: document_qa_tool con argomenti: {"query": "specifiche del nuovo prodotto XYZ"}
# Risposta: Il nuovo prodotto XYZ presenta una fotocamera da 12MP, display OLED da 6.1 pollici e 256GB di memoria.
# > Ciclo dell'agente terminato.
# Il nuovo prodotto XYZ presenta una fotocamera da 12MP, display OLED da 6.1 pollici e 256GB di memoria.
response = agent.chat("Quanti giorni di ferie pagate hanno diritto i dipendenti?")
print(response)
# Output previsto:
# > Ingresso nel ciclo dell'agente.
# Pensiero: L'utente sta chiedendo informazioni sulle politiche aziendali riguardo alle ferie pagate. Dovrei usare il `document_qa_tool` per interrogare i documenti caricati.
# Chiamata Strumento: document_qa_tool con argomenti: {"query": "politica sulle ferie pagate"}
# Risposta: I dipendenti hanno diritto a 20 giorni di ferie pagate all'anno.
# > Ciclo dell'agente terminato.
# I dipendenti hanno diritto a 20 giorni di ferie pagate all'anno.
Questo esempio mette in evidenza la forza di LlamaIndex nel rendere i dati non strutturati interrogabili da LLM. L'agente decide dinamicamente di utilizzare il document_qa_tool quando si trova di fronte a domande che possono essere risposte dai documenti ingeriti.
Forze e Debolezze
- Forze: Senza pari per RAG, solide capacità di ingestione e indicizzazione dei dati, forte supporto per varie fonti di dati e magazzini vettoriali, buono per costruire agenti arricchiti dalla conoscenza.
- Debolezze: Meno focalizzato sulle conversazioni complesse multi-agente o su catene di ragionamento profonde e multi-fase rispetto a LangChain/AutoGen (anche se può integrarsi con essi), la sua astrazione di agente è principalmente per l'interazione con i dati.
Alternative Emergenti e SDK di Nicchia
Lo spazio degli agenti è in rapida evoluzione, con nuovi SDK e framework che emergono costantemente:
- CrewAI: Si basa su concetti di LangChain e AutoGen, fornendo un framework più strutturato per definire ruoli, attività e processi per team multi-agente. Semplifica l'orchestrazione di flussi di lavoro complessi con un focus su chiare responsabilità degli agenti.
- Haystack (Deepset): Sebbene sia principalmente un framework per costruire sistemi di ricerca, Haystack supporta anche RAG e capacità agentiche. È noto per il suo approccio modulare e il forte focus sulla prontezza per la produzione.
- Semantic Kernel (Microsoft): Un SDK leggero che consente agli sviluppatori di integrare LLM con linguaggi di programmazione tradizionali. Si concentra su 'plugin' e 'abilità' per estendere le capacità degli LLM, offrendo un approccio più incentrato sul codice per lo sviluppo di agenti.
Scegliere il Giusto Agent SDK per il Tuo Progetto
Il miglior Agent SDK dipende fortemente dai requisiti specifici del tuo progetto:
- Per il ragionamento complesso con un singolo agente utilizzando strumenti personalizzati e flussi di lavoro flessibili: LangChain è un'ottima scelta grazie alla sua modularità e alle ampie integrazioni. È il punto di riferimento per costruire agenti autonomi e sofisticati.
- Per la collaborazione multi-agente, interfacce conversazionali e l'esecuzione automatizzata di compiti (soprattutto quando coinvolgono codice): AutoGen brilla. Se il tuo problema si decompone naturalmente in ruoli che possono conversare e agire, AutoGen fornisce un framework potente.
- Per agenti che devono interrogare e sintetizzare informazioni in modo efficiente da vasti set di dati proprietari o non strutturati: LlamaIndex è indispensabile. È il tuo strumento principale per costruire agenti alimentati da RAG. Spesso, LlamaIndex viene utilizzato insieme a LangChain o AutoGen per fornire capacità di recupero dati ai loro agenti.
- Per flussi di lavoro multi-agente con ruoli e compiti chiari: Considera CrewAI per un approccio più strutturato agli agenti basati su team.
- Per integrare le capacità LLM in applicazioni esistenti con un focus su 'abilità' e plugin: Semantic Kernel potrebbe essere una scelta migliore, specialmente per gli sviluppatori .NET.
Conclusione
Lo spazio SDK per agenti è dinamico e potente, offrendo un insieme diversificato di strumenti per dare vita agli agenti AI. LangChain, AutoGen e LlamaIndex rappresentano la punta di diamante, ciascuno con punti di forza distinti adattati a diversi aspetti dello sviluppo degli agenti. Comprendendo le loro architetture fondamentali, le funzionalità avanzate e le applicazioni pratiche, gli sviluppatori possono prendere decisioni informate, combinare i loro punti di forza e costruire sistemi di agenti AI altamente intelligenti, solidi e scalabili capaci di affrontare sfide complesse del mondo reale. Il futuro dell'AI è sempre più agentico e padroneggiare questi SDK è fondamentale per sbloccare il suo pieno potenziale.
🕒 Published: