Simulazione di un ristorante multi-agente utilizzando modelli linguistici di grandi dimensioni (LLM) in pratica, con Python e OpenAI
Ecco come ho utilizzato Large Language Model Agents per simulare l'attività end-to-end di un ristorante, utilizzando Python.
La scorsa settimana OpenAI ha pubblicato un file PDF di cui tutti parlano. Si tratta di una guida di 34 pagine che spiega cosa sono gli agenti LLM (Large Language Model Agents) e come utilizzarli.
Il PDF è relativamente breve e facile da leggere (non è necessario essere un ingegnere informatico o un mentore per capirlo), ma in poche parole spiega tre cose:

1. Gli agenti LLM (Large Language Model Agents) sono "sistemi che svolgono compiti in modo indipendente per conto dell'utente".
Quindi, non si tratta semplicemente di prompt del Big Language Model (LLM) richiamati tramite un'API? Beh, sì e no. Si utilizza lo stesso modello (o gli stessi modelli) di completamento della conversazione, quindi è un po' la stessa cosa, ma il punto è creare un'azione specifica. Con questo intendo dire che l'output del proxy deve essere tradotto in un output eseguibile nel sistema. Ad esempio, se l'output LLM dice "spaghetti", allora "spaghetti" verrà aggiunto al percorso dati e, alla fine, qualcuno lo vedrà e cucinerà gli spaghetti (avviso).
2. Gli agenti Large Language Model (LLM) sono particolarmente integrati con funzioni (strumenti).
Mi riferisco allo scenario in cui si pone una domanda a ChatGPT, che a sua volta richiama il proprio generatore di immagini/strumento di ricerca web/snippet di codice. Internamente, ChatGPT utilizza una funzione chiamata widget, che viene attivata dalla domanda. Il generatore di immagini è una funzione integrata, ma ChatGPT può anche richiamare un widget personalizzato , che l'utente può specificare per la propria attività. Questa capacità di integrare widget e funzioni esterne è ciò che conferisce agli agenti LLM (Large Language Model Agents) una tale flessibilità e potenza nell'esecuzione di un'ampia varietà di compiti.
3. È possibile combinare in sequenza numerosi agenti di modelli linguistici di grandi dimensioni (agenti LLM).
È possibile combinare un singolo agente e dotarlo di più strumenti oppure suddividere gli strumenti in agenti specializzati, che è ciò che faremo in questo articolo (un altro suggerimento!).
I dettagli tecnici possono essere di interesse per gli ingegneri del software, ma perché questo argomento degli agenti è così importante per tutti gli altri?
Bene, perché questo rappresenta un cambio di paradigma che contribuisce a rendere utili i modelli di intelligenza artificiale aperta. Pensateci: ora i grandi modelli linguistici (LLM) forniscono Risultati attuabili. Quindi, non si tratta di utilizzare i prompt LLM nell'ultimo passaggio del flusso di lavoro per migliorare il risultato finale; Piuttosto, si tratta di Integrazione dell'intero flusso di lavoro con agenti Large Language Model (agenti LLM) Per migliorare la qualità dell'intero flusso di lavoro.
Anche se sto cercando di spiegarlo a parole, penso sia più facile illustrarlo con un esempio pratico. Diciamo che stiamo parlando di un ristorante, per esempio.
In genere, un ristorante segue uno svolgimento molto normale e chiaro: si fa la fila, si ordina il cibo, si aspetta che arrivi, si mangia e si va via. Ora, se traduciamo questo usando l’approccio “agente”, possiamo identificare almeno tre agenti:
- agente Cliente Si tratta di un agente LLM (Large Language Model) che ordina cibo o chiede suggerimenti al cameriere.
- agente cameriere Si tratta di un modello linguistico di grandi dimensioni (LLM) che raccoglie le richieste e, quando necessario, fornisce suggerimenti.
- agente Divertimento Si tratta di un modello linguistico di grandi dimensioni (LLM) finalizzato alla gestione dei reclami dei clienti.
Ora, OpenAI ti spiega esattamente come costruire queste entità, ma questa è la parte relativamente semplice; C'è molto di più da scoprire, non è vero?
Dobbiamo implementare il ristorante , dobbiamo creare un sistema di code in cui le persone si siedono in base all'affluenza, dobbiamo creare il menu , simulare i tempi di attesa e assicurarci che tutto funzioni. Solo allora potremo collegare gli agenti. Come sempre:
L'intelligenza artificiale generativa è potente, ma solo se utilizzata nel contesto giusto.
Quindi, prima di passare alla parte interessante degli agenti, in questo articolo vedrai:
- Progettazione del sistema Per l'LLM come agente di ristorazione. Un'idea senza codice, solo uno schizzo del progetto fatto con carta e penna (o meglio, mouse e PowerPoint).
- Implementazione del ristorante senza agenti. Semplice e diretto, basta creare la struttura di base del codice.
- Implementazione dell'agente Restaurant. Oltre a un'interfaccia utente grafica semplice per visualizzarlo bene.
- Considerazioni e osservazioni finali.
Sembra che abbiamo molto da trattare. Al laboratorio! 🧪
1. Progettazione del sistema di ristorazione: una guida per esperti
Nota: se hai svolto alcune esercitazioni tecniche, troverai la progettazione di questo sistema molto semplice. L'obiettivo di questo progetto non è dimostrare in modo esaustivo ogni parte di un sistema di apprendimento automatico (come ti chiedono in un'intervista di 15 minuti 🙃), ma semplicemente fornire alcune indicazioni su cosa faremo in seguito.
Il modo in cui possiamo visualizzare il processo di ristorazione, integrato con un modello linguistico di grandi dimensioni (LLM), è riassunto in questa immagine:

Lasciatemi spiegare:
- Ristorante() e Menu() Sono due classi. Li definiamo e tutte le tabelle, gli ordini e le informazioni di sistema all'interno delle classi verranno definiti e aggiornati dinamicamente.
- dovrà Nuovo cliente Passare attraverso un meccanismo di seduta. Se possono sedersi (ci sono abbastanza tavoli liberi), va bene, possiamo lasciarli sedere; Altrimenti il cliente dovrà attendere in coda.
- Per il cliente il sedutoCi sarà un cameriere che permetterà loro di ordinare il cibo. Possono "lamentarsi" e chiedere quanto tempo ci vorrà per ricevere il cibo dopo averlo ordinato.
- Le persone non possono in attesa in fila Fanno tante cose, ma possono anche "lamentarsi" e chiedere quanto tempo dovranno aspettare in fila prima di potersi sedere.
Ora, se ci pensate bene, non serve un modello linguistico complesso (LLM) per questo. Ad esempio, potremmo calcolare il tempo di attesa in anticipo e poi collegarlo a una stringa strutturata predefinita. Potremmo anche usare una semplice lista di raccolta ordini (come un chiosco automatico di McDonald's) e finire lì. Certo, potremmo farlo, ma pensateci un attimo.
Cosa succede se un cliente , mentre aspetta, chiede informazioni sul menù ? E se è indeciso su cosa ordinare? E se vuole sapere qual è la migliore opzione vegetariana ? E se desidera un buon vino a un prezzo ragionevole ? Potremmo iniziare a definire metodi basati su regole per ciascuno di questi scenari, sprecando tempo e denaro, oppure potremmo iniziare a utilizzare l'intelligenza artificiale. Questo articolo si propone proprio di questo. Utilizzando i Large Language Model Agents (LLM Agents), avremo la possibilità di gestire tutti questi scenari in un colpo solo.
Ora, se avete imparato qualcosa, è che l'ingegneria del software va fatta passo dopo passo . È meglio avere la struttura di base del modello e poi aggiungere i tocchi finali e i miglioramenti. Per questo motivo, costruiremo una versione senza agenti del prodotto descritto sopra. Questa versione semplificata avrà un sistema di accodamento che calcola i tempi di attesa ed esegue il menu, in modo che tutto funzioni senza intoppi senza alcuna intelligenza artificiale. Dopo questo passaggio, possiamo assegnare agli agenti i ruoli che abbiamo discusso e dimostrato in precedenza (cliente, host e cameriere).
2. Implementazione senza agente
È sempre meglio semplificare il più possibile tutto nello script principale e lasciare le operazioni complesse in secondo piano. La nostra implementazione Agent Free può essere eseguita in questo codice.
importa casuale importa tempo importa matematica importa sys da utils importa * da costanti importa * da naive_models importa * se __name__ == "__main__": random.seed(42) menu = preprocess_menu(MENU_FILE, eat_time_factor=0.5) R = Restaurant( num_tables=2, arrival_prob=0.7, tick_length=1, real_pause=5.0, query_prob=0.4, menu=menu ) R.run(total_time=60)
Come possiamo vedere, possiamo modificare:
- num_tabelle; Numero di tavoli nel nostro ristorante.
- arrivo_probabile; Rappresenta la probabilità che un cliente arrivi a ogni intervallo temporale.
- zecca; È il passo temporale della nostra simulazione.
- pausa; Implementa la funzione time.sleep(), che viene utilizzata per simulare il flusso di lavoro di un vero ristorante.
Tutta questa implementazione viene effettuata nel file naive_models.py , che si trova qui.
import random
import time
import math
import sys
from utils import *
from constants import *
class Table:
def __init__(self, id, capacity=1):
self.id = id
self.capacity = capacity
self.is_free = True
self.cust_id = None
self.plate = None
self.cooking_complete_at = None
self.leave_at = None
def seat(self, cust_id, clock, plate, cook_time, eat_time):
self.is_free = False
self.cust_id = cust_id
self.plate = plate
self.cooking_complete_at = clock + cook_time
self._scheduled_eat_time = eat_time
msg = (
f"[{clock:04}m] 🪑 Seated customer {cust_id} at T{self.id} "
f"ordering {plate!r} (cook {cook_time}m, eat {eat_time}m)"
)
print(msg); sys.stdout.flush()
def start_eating(self, clock):
self.leave_at = clock + self._scheduled_eat_time
msg = (
f"[{clock:04}m] 🍽️ Customer {self.cust_id} at T{self.id} "
f"starts eating their {self.plate!r} (leaves at {self.leave_at}m)"
)
print(msg); sys.stdout.flush()
def depart(self, clock):
msg = (
f"[{clock:04}m] 💸 Customer {self.cust_id} finished their "
f"{self.plate!r} and left T{self.id}"
)
print(msg); sys.stdout.flush()
self.is_free = True
self.cust_id = None
self.plate = None
self.cooking_complete_at = None
self.leave_at = None
class Restaurant:
def __init__(self, num_tables, arrival_prob=0.33,
tick_length=1, real_pause=0.5, menu=None,
query_prob=0.0):
self.tables = [Table(i) for i in range(num_tables)]
# queue holds only customer IDs
self.queue = []
self.clock = 0
self.next_cust_id = 1
self.arrival_prob = arrival_prob
self.tick = tick_length
self.pause = real_pause
self.menu = menu or [
("Burger", 2, 4),
("Pasta", 3, 5),
("Salad", 1, 2),
("Steak", 4, 6),
("Soup", 1, 3),
]
self.query_prob = query_prob
total = sum(c + e for _, c, e in self.menu)
self.avg_service_time = total / len(self.menu)
def open_tables(self):
return [t for t in self.tables if t.is_free]
def _pick_dish(self):
return random.choice(self.menu)
def arrive(self):
if random.random() < self.arrival_prob:
cid = self.next_cust_id
self.next_cust_id += 1
free = self.open_tables()
if free:
# pick dish only when seating immediately
plate, cook_time, eat_time = self._pick_dish()
table = min(free, key=lambda t: t.capacity)
table.seat(cid, self.clock, plate, cook_time, eat_time)
else:
self.queue.append(cid)
print(f"[{self.clock:04}m] ⏳ Queued customer {cid} (waiting)")
def process_cooking(self):
for t in self.tables:
if (not t.is_free
and t.cooking_complete_at is not None
and t.cooking_complete_at <= self.clock
and t.leave_at is None):
t.start_eating(self.clock)
def process_departures(self):
for t in self.tables:
if (not t.is_free
and t.leave_at is not None
and t.leave_at <= self.clock):
t.depart(self.clock)
def seat_from_queue(self):
while self.queue and self.open_tables():
cid = self.queue.pop(0)
# pick dish at seating time
plate, cook_time, eat_time = self._pick_dish()
table = min(self.open_tables(), key=lambda t: t.capacity)
table.seat(cid, self.clock, plate, cook_time, eat_time)
def estimate_queue_time(self, cid):
positions = list(self.queue)
idx = positions.index(cid)
raw_wait = (idx + 1) * self.avg_service_time / len(self.tables)
return math.ceil(raw_wait)
def estimate_food_time(self, cid):
for t in self.tables:
if t.cust_id == cid:
if t.cooking_complete_at > self.clock:
return t.cooking_complete_at - self.clock
return max(0, t.leave_at - self.clock)
return None
def handle_random_query(self):
queue_ids = list(self.queue)
seated_ids = [t.cust_id for t in self.tables if not t.is_free]
if queue_ids and (not seated_ids or random.random() < 0.7):
cid = random.choice(queue_ids)
wait = self.estimate_queue_time(cid)
print(f"[{self.clock:04}m] ❓ Customer {cid}: How long will I be in line?")
print(f"[{self.clock:04}m] ➡️ Estimated wait for customer {cid}: {wait}m")
elif seated_ids:
cid = random.choice(seated_ids)
wait = self.estimate_food_time(cid)
table = next(t for t in self.tables if t.cust_id == cid)
food = table.plate
print(f"[{self.clock:04}m] ❓ Customer {cid}: How long will the {food} take me?")
if wait is None:
print(f"[{self.clock:04}m] ➡️ Ready now!")
else:
print(f"[{self.clock:04}m] ➡️ Estimated food wait for customer {cid}: {wait}m")
def tick_once(self):
self.arrive()
self.process_cooking()
self.process_departures()
self.seat_from_queue()
if self.query_prob and random.random() < self.query_prob:
self.handle_random_query()
self.clock += self.tick
time.sleep(self.pause)
def run(self, total_time):
while self.clock < total_time:
self.tick_once()
print("n--- END OF SHIFT ---")
free = sum(t.is_free for t in self.tables)
print(f"{free}/{len(self.tables)} tables free at {self.clock}m.")
if __name__ == "__main__":
random.seed(42)
menu = preprocess_menu(MENU_FILE, eat_time_factor=0.5)
R = Restaurant(
num_tables=2,
arrival_prob=0.7,
tick_length=1,
real_pause=5.0,
query_prob=0.4,
menu=menu
)
R.run(total_time=60)
Bene, è un discorso lungo, lasciatemi spiegarvi alcuni passaggi.
L'intero script viene eseguito su naive_sim utilizzando il comando .run() con le seguenti funzioni:
- arrivare, che rappresenta l'arrivo e la richiesta dei clienti, oppure il loro arrivo e il loro posizionamento in una coda.
- processo_di_cottura, che simula la cottura di ogni tavolo.
- processi_partenze, che simula la partenza del cliente.
- posto_dalla_coda, che simula i clienti seduti in coda.
- gestire_query_casuale, che viene chiamato in modo casuale, dove un cliente in coda o in attesa del suo cibo può chiedere informazioni sul tempo di attesa.
Se eseguiamo naive_sim.py, otterremo questo dal terminale.

Ora, questo è di per sé un prodotto di scienza dei dati. Con questo si può gestire una catena di ristoranti di Monte Carlo, si può vedere il potenziale per la creazione di una lunga coda, i ristoranti possono usare questo "gemello digitale" del loro ristorante e vedere quando potrebbero verificarsi situazioni critiche. Ora che abbiamo un prodotto funzionante, rendiamolo più bello e potente utilizzando l'intelligenza artificiale (IA).
3. Implementazione del ristorante dell'agente
Come possiamo vedere sopra, i clienti sono già in grado di porre domande e noi abbiamo la risposta sotto forma di numero. Il cliente sceglie anche un alimento casuale nel nostro sistema. Ora proviamo ad aggiungere agenti a questo sistema. L'attivazione di un sistema di agenti di ristorazione è un passo avanti nell'automazione del servizio clienti e nel miglioramento dell'esperienza utente. Gli agenti qualificati sanno rispondere in modo efficiente alle richieste dei clienti e fornire consigli personalizzati.
3.1 Implementazione di agenti dedicati
Sarà necessario installare il modulo “Agenti”:
Di seguito è riportata l'implementazione dell'agente del servizio clienti, dell'agente di intrattenimento e del gestore dei reclami.
# custom_agents.py import os, json da openai import OpenAI da agents import Agent da newtools import * client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), default_headers={"OpenAI-Beta":"assistants=v2"}) menu_agent = Agent(name = "Chef_suggester", instructions = "Sei un cameriere disponibile che conosce tutto del nostro ristorante e aiuta i clienti a scegliere il cibo. Inizierai presentandoti educatamente come assistente virtuale per il cibo e salutando educatamente il cliente. Il nome del cliente si trova nel file json msg" "Leggerai il menu e, in base a ciò che il cliente ti chiede, nella chiave di richiesta del file json, fornirai il miglior consiglio dal menu." "Se il cliente ti pone domande inappropriate, invia semplicemente un messaggio in formato json 'unsuccessfull' '{food: , stato: }'", tools = [get_menu]) entertainer_agent = Agent(name = "Entertainer", instructions = ("Sei un cameriere disponibile che tiene occupati i clienti mentre aspettano." "Non puoi offrire sconti o offerte, ma possono fare domande sul menu, che puoi ottenere dalle" "funzioni get_menu. Possono anche chiederti quanto tempo ci sarà per entrare. Le loro informazioni sono in waiting_time" "Se user_status è 'queue', fornisci semplicemente l'orario con gentilezza, in base alla durata dell'attesa. Altrimenti, se user_status è 'food', significa che stanno aspettando il cibo. Seleziona 'order' e fornisci un riferimento divertente al loro tempo di attesa. Ad esempio 'il tuo tempo di attesa per la pasta è di 1 minuti, sembra che lo chef ci stia mettendo il sugo!'", tools = [get_menu]) customer_agent = Agent(name = "Customer", instructions = ("Sei un cliente e stai mangiando in un ristorante italiano. Guarda il menu utilizzando Funzione get_menu. Se sai già cosa vuoi, dillo al cameriere. " "In caso contrario, fornisci loro un'indicazione generale o chiedi una guida in base ai tuoi gusti generali e sceglieranno il meglio per te."), tools = [get_menu]) def call_agent(runner, msg, class_agent = "wait"): if class_agent == "entertainer": return runner.run_sync(entertainer_agent, msg) elif class_agent == "waiter": return runner.run_sync(menu_agent, msg) elif class_agent == "customer": return runner.run_sync(customer_agent, '')
Abbiamo la definizione del client , che è la chiamata al client OpenAI, newtools.py , che recupera l'elenco, e call_agent , che chiama ed esegue il singolo agente tramite un runner . Questi componenti sono essenziali per creare un sistema di agenti efficace.
È esattamente ciò di cui abbiamo parlato nell'introduzione. Definiamo diversi agenti da connettere, i quali utilizzano strumenti specificati dal mio codice. Questi strumenti e agenti consentono l'automazione delle attività di assistenza clienti e un'esperienza utente migliorata.
da agenti importa function_tool da costanti importa * importa pandas come pd @function_tool def get_menu(): df = pd.read_csv(MENU_FILE) # converti in un elenco di dizionari (o struttura serializzabile JSON) restituisci df.to_dict(orient="records")
3.2 Implementazione di agenti dedicati
L'implementazione di Table e Restaurant, insieme agli agenti, è integrata nel seguente codice:
importa casuale importa tempo importa matematica importa sys da utilità importa * da costanti importa * importa tempo, casuale, json da agenti_personalizzati importa * da utilità importa * da costanti importa * da agenti importa Runner # elenco di nomi dalla tua costante NOMI # presumi che NOMI = [ ... ] is defined in constants.py
import logging
# Set up logging
def log(msg):
logging.info(msg)
class Table:
def __init__(self, id, capacity=1):
self.id = id
self.capacity = capacity
self.is_free = True
self.cust_id = None
self.orders = [] # list of (plate, cook_time, eat_time)
self.current_phase = None # "cooking" or "eating"
self.cooking_complete_at = None
self.leave_at = None
def seat(self, cust_id, cust_name, clock, orders):
self.is_free = False
self.cust_id = cust_id
self.orders = list(orders) # copy the list of tuples
# start first dish cooking immediately
plate, cook_time, eat_time = self.orders.pop(0)
self.current_phase = "cooking"
self._scheduled_eat_time = eat_time
self._remaining_orders = self.orders # save the tail
self.cooking_complete_at = clock + cook_time
self.leave_at = None
msg = (f"[{clock:04}m] 🪑 Seated {cust_name} (#{cust_id}) at T{self.id} "
f"ordering {len(orders)} dishes; first: {plate!r} "
f"(cook {cook_time}m, eat {eat_time}m)")
print(msg); sys.stdout.flush()
def start_eating(self, clock):
self.current_phase = "eating"
self.leave_at = clock + self._scheduled_eat_time
plate = self.plate if hasattr(self, 'plate') else "dish"
msg = (f"[{clock:04}m] 🍽️ {plate!r} ready for {self.cust_name} "
f"(#{self.cust_id}) at T{self.id}, eating until {self.leave_at}m")
print(msg); sys.stdout.flush()
def finish_phase(self, clock):
"""Called when eating of current dish finishes."""
if self._remaining_orders:
# move to next dish
plate, cook_time, eat_time = self._remaining_orders.pop(0)
self.current_phase = "cooking"
self._scheduled_eat_time = eat_time
self.cooking_complete_at = clock + cook_time
self.leave_at = None
self.plate = plate
msg = (f"[{clock:04}m] 🔄 Next dish for {self.cust_name} (#{self.cust_id}) "
f"at T{self.id}: {plate!r} (cook {cook_time}m, eat {eat_time}m)")
print(msg); sys.stdout.flush()
else:
# no more dishes: depart
msg = (f"[{clock:04}m] 💸 {self.cust_name} (#{self.cust_id}) "
f"finished all dishes and left T{self.id}")
print(msg); sys.stdout.flush()
self.is_free = True
self.cust_id = None
self.orders = []
self.current_phase = None
self.cooking_complete_at = None
self.leave_at = None
class Restaurant:
def __init__(self, num_tables, arrival_prob=0.33,
tick_length=1, real_pause=0.5, menu=None,
query_prob=0.0):
self.tables = [Table(i) for i in range(num_tables)]
self.queue = [] # just customer IDs
self.clock = 0
self.next_cust_id = 1
self.arrival_prob = arrival_prob
self.tick = tick_length
self.pause = real_pause
self.menu = menu or [
("Burger", 2, 4),
("Pasta", 3, 5),
("Salad", 1, 2),
("Steak", 4, 6),
("Soup", 1, 3),
]
self.runner = Runner()
self.query_prob = query_prob
self.names = {}
self.load_logging()
def load_logging(self):
logging.getLogger("httpx").setLevel(logging.WARNING)
logging.getLogger("openai").setLevel(logging.WARNING)
logging.getLogger("urllib3").setLevel(logging.WARNING)
logging.basicConfig(level=logging.INFO, format='[%(asctime)s] %(message)s',
datefmt='%H:%M:%S', handlers=[
logging.FileHandler("restaurant_log.txt", mode='w'),
logging.StreamHandler(sys.stdout)])
def log_to_msg(self,msg):
logging.info(msg)
def open_tables(self):
return [t for t in self.tables if t.is_free]
def _pick_orders(self, cname):
"""Choose between 1–3 random menu items as a list."""
#n = random.randint(1, 3)
#return random.sample(self.menu, n)
customer_text = call_agent(runner = self.runner, msg= '', class_agent="customer").final_output
msg = f'The customer {cname} is talking to the waiter, saying this {customer_text}'
print(msg)
self.log_to_msg(msg)
menu_asker_output = call_agent(runner = self.runner, msg = json.dumps(customer_text), class_agent="waiter").final_output
output = extract_json_dict(menu_asker_output)
msg = f'The processed response from our LLM is {output}'
print(msg)
self.log_to_msg(msg)
if output['status'] == 'successfull':
return filter_menu_items(output['food'])
else:
n = random.randint(1, 3)
return random.sample(self.menu, n)
def _assign_name(self, cid):
name = random.choice(NAMES)
self.names[cid] = name
return name
def arrive(self):
if random.random() < self.arrival_prob:
cid = self.next_cust_id
self.next_cust_id += 1
cname = self._assign_name(cid)
free = self.open_tables()
if free:
orders = self._pick_orders(cname)
table = min(free, key=lambda t: t.capacity)
table.cust_name = cname
plate, cook_time, eat_time = orders[0]
table.plate = plate
table.seat(cid, cname, self.clock, orders)
else:
self.queue.append(cid)
msg = f"[{self.clock:04}m] ⏳ Queued {cname} (#{cid}) – waiting"
print(msg)
self.log_to_msg(msg)
def process_cooking(self):
for t in self.tables:
if (not t.is_free and
t.current_phase=="cooking" and
t.cooking_complete_at <= self.clock):
# cooking done → start eating
t.cust_name = self.names[t.cust_id]
t.start_eating(self.clock)
def process_departures(self):
for t in self.tables:
if (not t.is_free and
t.current_phase=="eating" and
t.leave_at <= self.clock):
t.cust_name = self.names[t.cust_id]
t.finish_phase(self.clock)
def seat_from_queue(self):
while self.queue and self.open_tables():
cid = self.queue.pop(0)
cname = self.names[cid]
orders = self._pick_orders(cname=cname)
table = min(self.open_tables(), key=lambda t: t.capacity)
table.cust_name = cname
plate, cook_time, eat_time = orders[0]
table.plate = plate
table.seat(cid, cname, self.clock, orders)
def estimate_queue_time(self, cid):
# same logic as before: position in queue × avg service
avg = sum(c+e for _,c,e in self.menu) / len(self.menu)
idx = self.queue.index(cid)
return math.ceil((idx+1)*avg/len(self.tables))
def estimate_food_time(self, cid):
for t in self.tables:
if t.cust_id == cid:
# if they’re still cooking, time until cook‐done
if t.current_phase == "cooking":
return max(0, t.cooking_complete_at - self.clock)
# if they’re eating, time until they finish eating
if t.current_phase == "eating":
return max(0, t.leave_at - self.clock)
return None
def handle_random_query(self):
queue_ids = list(self.queue)
seated_ids = [t.cust_id for t in self.tables if not t.is_free]
if queue_ids and (not seated_ids or random.random() < 0.7):
cid = random.choice(queue_ids)
wait = self.estimate_queue_time(cid)
cname = self.names[cid]
msg = f"[{self.clock:04}m] ❓ Customer {cid}: How long will I be in line?"
print(msg) self.log_to_msg(msg) msg = f"[{self.clock:04}m] ➡️ Tempo di attesa stimato per il cliente {cid}: {wait}m" print(msg) self.log_to_msg(msg) waiting_message = { "customer_id": cid, "customer_name": cname, "type": "line", "wait_min": wait, "next_food": None } output_llm = call_agent(class_agent="entertainer", runner = self.runner, msg = json.dumps(waiting_message)) msg = f"Il nostro LLM si è preso cura di {cname} con questo: {output_llm}" print(msg) self.log_to_msg(msg) elif seated_ids: cid = random.choice(seated_ids) wait = self.estimate_food_time(cid) table = next(t for t in self.tables if t.cust_id == cid) food = table.plate cname = self.names[cid] msg = f"[{self.clock:04}m] ❓ Cliente {cid}: Quanto tempo mi ci vorrà per ordinare il cibo?"
print(msg) self.log_to_msg(msg) se wait è None: msg = f"[{self.clock:04}m] ➡️ Pronto ora!"
print(msg) self.log_to_msg(msg) else: msg = f"[{self.clock:04}m] ➡️ Tempo di attesa stimato per il cibo per il cliente {cid}: {wait}m" print(msg) self.log_to_msg(msg) waiting_message = { "customer_id": cid, "customer_name": cname, "type": "line", "wait_min": wait, "next_food": food } output_llm = call_agent(class_agent="entertainer", runner = self.runner, msg = json.dumps(waiting_message)) msg = f"Il nostro LLM si è preso cura di {cname} con questo: {output_llm}" print(msg) self.log_to_msg(msg) def tick_once(self): self.arrive() self.process_cooking() self.process_departures() self.seat_from_queue() if self.query_prob and random.random() < self.query_prob: self.handle_random_query() self.clock += self.tick time.sleep(self.pause) def run(self, total_time): while self.clock < total_time: self.tick_once() free = sum(t.is_free for t in self.tables) msg = f"n--- FINE TURNO ---n{free}/{len(self.tables)} tavoli liberi a {self.clock}m."
print(msg) self.log_to_msg(msg) if __name__ == "__main__": random.seed(42) menu = preprocess_menu(MENU_FILE, eat_time_factor=0.5) R = Restaurant( num_tables=5, arrival_prob=0.7, tick_length=1, real_pause=5.0, query_prob=0.8, menu=menu ) R.run(total_time=60)
3.3 Implementazione di un'interfaccia utente grafica (GUI) per un ristorante utilizzando un modello linguistico di grandi dimensioni (LLM)
Per visualizzare le prestazioni del ristorante con un'applicazione LLM (Large Language Model), utilizzeremo una semplice interfaccia utente grafica (GUI).
da llm_models_gui importa RestaurantGUI da utils importa * importa casuale da llm_models importa Restaurant se __name__ == "__main__": random.seed(42) menu = preprocess_menu(MENU_FILE, eat_time_factor=0.5) R = Restaurant( num_tables=5, arrival_prob=0.7, tick_length=1, real_pause=1.0, # più fluido per GUI query_prob=0.8, menu=menu ) app = RestaurantGUI(R)

L'interfaccia utente grafica (GUI) fornisce informazioni sulla persona (Emma), sulla tabella, sull'ora e sull'output del modello linguistico completo (LLM). Viene creato automaticamente anche un record .txt.
Vi mostro un esempio dell'output:
[12:31:23] La cliente Emma sta parlando con il cameriere, dicendo: “Vorrei iniziare con la bruschetta come antipasto. Poi ordinerò gli spaghetti alla carbonara come primo piatto. Per dessert, vorrei il tiramisù. Potrebbe anche consigliarmi un vino da abbinare a questo pasto?” [12:31:25] La risposta elaborata del nostro studente di master è: {'cibo': ['Bruschetta', 'Spaghetti alla Carbonara', 'Tiramisù', 'Chianti Classico'], 'stato': 'riuscito'} [12:31:25] [0000m] ❓ Cliente 1: Quanto tempo ci vorrà per preparare il cibo? [12:31:25] [00:00] ➡️ Tempo di attesa previsto per il cibo per cliente: 1:15 minuti [12:31:26] Lo studente MBA ha preso in carico il caso di Emma con questo: Ultimo cliente: Agente(nome="Intrattenitore", …) Risultato finale (catena): Ciao Emma! Grazie per la tua pazienza. Il tempo di attesa per entrare è di circa 15 minuti. Quasi fatto – giusto il tempo per iniziare a sognare quella deliziosa bruschetta! 🍽️
Possiamo offrire:
- Il cliente crea il proprio menù tramite l'agente.e chiede una raccomandazione all'agente del cameriere.
- Il cameriere consiglia un vino Chianti e lo aggiunge alla lista.
- L'addetto alla gestione dei reclami informa il cliente del tempo di attesa.
Ora non solo possiamo simulare il flusso di lavoro, come facevamo prima, ma disponiamo di un flusso di lavoro intelligente , potenziato dalla stessa tecnologia ChatGPT. Non è fantastico?
4. Conclusione
Grazie mille per essere venuti, significa molto per me ❤️.
Torniamo indietro e vediamo cosa abbiamo fatto in questo articolo.
- Progettazione del sistema di ristorazione:
Abbiamo creato un progetto rapido per un sistema di ristorazione utilizzando PowerPoint con l'aggiunta di agenti di intelligenza artificiale. - Senza agenti:
Per prima cosa abbiamo realizzato una simulazione deterministica, in modo da poter codificare la logica della coda, dei tempi di cottura e della rotazione del tavolo. Questo è il nostro scheletro prima di realizzare qualsiasi IA. - Ristorante basato su agente:
In questa fase, abbiamo utilizzato agenti di intelligenza artificiale per popolare il nostro caso di reclamo + azione con gli agenti. Abbiamo anche creato un'interfaccia utente grafica per visualizzare chiaramente i risultati.
Ora, a questo punto, voglio essere molto chiaro. So che sembra un po' come in Black Mirror. Simulazione del cliente? Simulazione di ristorante e cameriere? Sì, è strano, ma il problema non è mai lo strumento di intelligenza artificiale in sé, bensì il modo in cui viene utilizzato. Credo che sostituire i camerieri umani con l'IA sia una strategia perdente.
Essere un cameriere non significa semplicemente prendere le ordinazioni e consigliare il vino numero N in base agli N-1 vini ordinati in precedenza. Si tratta di essere abbastanza cordiali da far sentire l'ospite benvenuto, ma abbastanza distanti da non interferire nella sua conversazione, abbastanza gentili da farlo sentire a casa, ma abbastanza forti da fargli rispettare i propri limiti. È una combinazione di qualità che, a mio avviso, richiedono tocco umano, pazienza ed empatia.
Tuttavia, ritengo che l'uso corretto di questa tecnologia possa essere duplice:
- Aiutare persone reali che sono in lista d'attesa. I camerieri all'interno sono molto impegnati e i ristoranti mettono già a disposizione un menù da consultare mentre si aspetta il tavolo; non è realistico pensare che altri camerieri intrattengano persone che aspettano senza tavolo. A questo punto, potrebbe essere utile avere un compagno AI con cui chattare.
- Simulazione di ristorante. Lo scenario che ho scritto simula Comportamento Clienti Anche. Ciò significa che, potenzialmente, puoi utilizzare le simulazioni per testare diversi scenari, vedere quando si formano le code, ipotizzare reazioni diverse da parte delle persone, risposte diverse da parte dei camerieri, ecc. In altre parole, questo può essere il tuo "gemello digitale" su cui eseguire i test.
I commenti sono chiusi.