Python 및 OpenAI를 활용한 실제 대규모 언어 모델(LLM)을 활용한 다중 에이전트 레스토랑 시뮬레이션
Python을 사용하여 대규모 언어 모델 에이전트를 사용하여 종단 간 레스토랑 운영을 시뮬레이션한 방법은 다음과 같습니다.
지난주 OpenAI는 파일을 공개했습니다. PDF그리고 모두가 이에 대해 이야기하고 있습니다. 이 문서는 대규모 언어 모델 에이전트(LLM 에이전트)가 무엇이고 어떻게 사용하는지 설명하는 34페이지 분량의 가이드입니다.
PDF는 비교적 짧고 읽기 쉽습니다(소프트웨어 엔지니어나 멘토가 아니어도 이해할 수 있습니다). 하지만 간단히 말해서 세 가지 내용을 설명합니다.

1. 대규모 언어 모델 에이전트(LLM 에이전트) "이것은 당신을 대신하여 독립적으로 작업을 완료하는 시스템입니다."
그럼 이건 그냥 API를 통해 호출되는 간단한 LLM(대규모 언어 모델) 프롬프트 아닌가요? 네, 맞기도 하고 아니기도 합니다. 같은 대화 완성 모델을 사용하고 있으니, 어느 정도는 맞는 것 같습니다. 그러나 특정 작업을 생성하기 위한 것입니다. 즉, 에이전트의 출력은 이는 실행 가능한 결과로 번역되어야 합니다. 시스템에서 예를 들어, 대규모 언어 모델(LLM)의 출력이 "스파게티"라고 나오면 "스파게티"가 데이터 경로에 추가되고, 결국 누군가 이를 보고 스파게티를 요리하게 됩니다(알림).
2. LLM 에이전트(대규모 언어 모델 에이전트)는 특별히 통합되어 있습니다. 기능(도구)
ChatGPT에 질문을 하면 ChatGPT가 이미지 생성기/웹 검색기/코드 조각을 호출하는 시나리오에 대해 이야기하고 있습니다. 내부적으로는 사용자의 프롬프트에 따라 실행되는 '도구'라는 함수를 사용합니다. 이미지 생성기는 내장 함수이지만, ChatGPT가 호출할 수도 있습니다. 당신의 일(당신의 도구)작업에 맞게 사용자 정의할 수 있습니다. 외부 도구와 기능을 통합할 수 있는 이러한 기능 덕분에 대규모 언어 모델 에이전트(LLM 에이전트)는 다양한 작업을 수행하는 데 있어 뛰어난 유연성과 성능을 제공합니다.
3. 여러 개의 대형 언어 모델 에이전트(LLM 에이전트)를 통합할 수 있습니다. 연이은
단일 에이전트를 통합하여 여러 도구를 제공할 수도 있습니다. أو 도구를 특수 에이전트로 나누는 것이 바로 이 글에서 할 일입니다(또 다른 힌트!).
기술적인 세부 사항은 소프트웨어 엔지니어에게 흥미로울 수 있지만, 에이전트라는 주제가 다른 사람들에게도 왜 그렇게 중요할까요?
음, 이는 오픈 AI 모델에 가치를 제공하는 패러다임 전환을 의미하기 때문입니다. 생각해 보세요. 대규모 언어 모델(LLM)은 이제 실행 가능한 결과. 따라서 최종 출력을 개선하기 위해 워크플로의 마지막 단계에서 LLM 프롬프트를 사용하는 것이 아닙니다. 대규모 언어 모델 에이전트(LLM 에이전트)를 사용하여 전체 워크플로 통합 전체 워크플로의 품질을 개선합니다.
말로 설명하려고 하지만, 실제로 보여드리는 게 더 쉬울 것 같아요. 예를 들어, 식당, 예를 들면.
일반적인 레스토랑은 매우 자연스럽고 간단한 행동 방침을 따릅니다. 줄을 서서 음식을 주문하고, 음식을 기다리고, 식사를 하고, 떠납니다. 이제 이를 "에이전트" 방식으로 해석하면, 최소 세 가지의 에이전트를 파악할 수 있습니다.
- 에이전트 고객 음식을 주문하거나 웨이터에게 제안을 요청하는 것은 대규모 언어 모델(LLM) 에이전트입니다.
- 에이전트 웨이터 필요할 때 요청을 수집하고 제안을 하는 대규모 언어 모델(LLM)입니다.
- 에이전트 환대 이는 고객 불만을 처리하는 것을 목표로 하는 대규모 언어 모델(LLM)입니다.
OpenAI는 이러한 엔티티를 만드는 방법을 정확히 알려주지만, 상대적으로 쉬운 부분입니다. 그 외에도 해야 할 일이 많이 있죠?
우리는 구현해야합니다 음식점, 그리고 우리는 만들어야 합니다 대기 목록 방법, 레스토랑이 얼마나 혼잡한지에 따라 사람들이 앉을 곳을 결정해야 하며, 알타암의 지도, 시뮬레이션 대기 시간그리고 모든 것이 제대로 작동하는지 확인하세요. 그때 그때서야 상담원을 연결해 드릴 수 있습니다. 언제나처럼:
생성적 AI는 강력하지만, 올바른 맥락에서 사용해야만 그렇습니다.
그럼, 에이전트에 대한 흥미로운 부분을 살펴보기 전에 이 기사에서 다음 내용을 살펴보겠습니다.
- 시스템 설계 레스토랑 에이전트 LLM을 위한 과정입니다. 코드는 필요 없고, 펜과 종이(아니면 마우스와 파워포인트)로만 구성된 프로젝트 개요만 있으면 됩니다.
- 에이전트 없는 레스토랑 구현. 간단하고 직관적이며, 코드의 기본 구조만 만들면 됩니다.
- 에이전트 레스토랑 구현. 그리고 이를 잘 표시하기 위한 간단한 그래픽 사용자 인터페이스도 있습니다.
- 마지막 고려사항 및 관찰.
다룰 게 많은 것 같네. 연구실로 가자! 🧪
1. 레스토랑 시스템 설계: 전문가 가이드
참고: 기술적인 부분을 몇 번 살펴보셨다면 이 시스템 설계가 꽤 간단하다는 것을 아실 겁니다. 이 설계의 목표는 머신 러닝 시스템의 모든 부분을 포괄적으로 설명하는 것이 아니라(15분짜리 인터뷰에서 기대하시는 것처럼요 🙃), 다음에 무엇을 해야 할지에 대한 지침을 제공하는 것입니다.
대규모 언어 모델(LLM)과 통합된 레스토랑 프로세스를 시각화하는 방법은 다음 그림으로 요약됩니다.

설명해드리죠:
- 식당() 그리고 메뉴() 두 개의 클래스가 있습니다. 이 두 클래스를 정의하면 클래스 내의 모든 테이블, 주문, 시스템 정보가 동적으로 정의되고 업데이트됩니다.
- 해야 할 것이다 신규 고객 좌석 시스템을 통과하세요. 앉을 수 있다면 (빈 테이블이 충분하다면) 좋습니다. 앉게 해 드리겠습니다. 그렇지 않으면 고객은 줄을 서게 됩니다.
- 고객을 위해 좌석음식을 주문할 수 있는 웨이터가 있을 겁니다. 주문 후 음식이 얼마나 걸리는지 "불만"을 제기할 수 있습니다.
- 사람들은 할 수 없습니다 줄을 서서 기다리다 그들은 많은 일을 하지만, "불평"을 하고 앉을 수 있을 때까지 얼마나 줄을 서야 하는지 물을 수도 있습니다.
이제 생각해 보면, 당신은 그렇지 않습니다. 필요 이 목적을 위해서는 대규모 언어 모델(LLM)이 필요합니다. 예를 들어, 대기 시간을 미리 계산한 다음 미리 정의된 형식화된 문자열에 연결할 수 있습니다. 또한 간단한 메뉴(맥도날드 자동 키오스크처럼)를 사용하여 주문을 수집하고 처리할 수도 있습니다. 물론 그렇게 할 수도 있지만, 한번 생각해 보세요.
고객이 메뉴에 대한 정보를 묻고 싶어한다면 어떻게 해야 하나요? 기다리는 동안만약 그랬다면? 주저하다 음식에 대해서요? 그들이 궁금해하면 어쩌죠? 가장 맛있는 채식 옵션 메뉴에 있다고? 그들이 원한다면 어떨까? 합리적인 가격에 좋은 와인이러한 각 시나리오에 대해 규칙 기반 방법을 정의하여 시간과 비용을 낭비할 수도 있고, 아니면 인공지능을 사용할 수도 있습니다. 이 글에서는 바로 이러한 내용을 다룹니다. 대규모 언어 모델 에이전트(LLM 에이전트)를 사용하면 이러한 모든 시나리오를 한 번에 처리할 수 있습니다.
제가 배운 게 있다면, 소프트웨어 엔지니어링을 해야 한다는 것입니다. 단계별로하나쯤 갖는 게 낫죠. 해골 모델에 장식과 액세서리를 추가하세요. 이러한 이유로 위 제품의 에이전트 없는 버전을 구축할 것입니다. 이 간소화된 버전에는 대기 시간을 계산하고 메뉴를 실행하는 대기열 시스템이 포함되어 인공 지능 없이도 모든 것이 원활하게 실행됩니다. 이 단계가 끝나면 위에서 논의하고 시연했던 위치(고객, 호스트, 웨이터)에 에이전트를 배치할 수 있습니다.
2. 에이전트 없는 구현
메인 스크립트에서는 모든 것을 최대한 단순하게 유지하고 복잡한 작업은 백그라운드에 남겨두는 것이 가장 좋습니다. 에이전트 없는 구현은 이 코드에서 실행할 수 있습니다.
random 가져오기 time 가져오기 math 가져오기 sys 가져오기 utils에서 import * from constants import * from naive_models import * 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)
보시다시피, 우리는 다음을 변경할 수 있습니다.
- 테이블 수우리 식당의 테이블 수.
- 도착 확률;는 각 시간 단계에 고객이 도착할 확률입니다.
- 진드기;는 시뮬레이션의 시간 단계입니다.
- 중지; 실제 레스토랑의 작업 흐름을 시뮬레이션하는 데 사용되는 time.sleep() 함수를 구현합니다.
이제 이 모든 구현은 파일에서 수행됩니다. naive_models.py, 기존의 여기.
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)
내용이 길어요. 몇 가지 단계를 설명해 드리겠습니다.
전체 스크립트는 다음 명령을 사용하여 naive_sim에서 실행됩니다. .달리다() 다음 기능을 갖추고 있습니다:
- 도착하다고객의 도착과 요청, 또는 고객이 도착하여 대기열에 배치되는 것을 나타냅니다.
- 조리 과정각 테이블에서 요리하는 모습을 시뮬레이션합니다.
- 프로세스_출발고객 이탈을 시뮬레이션합니다.
- 대기열에서 좌석고객이 줄을 서서 기다리는 상황을 시뮬레이션합니다.
- 핸들_랜덤_쿼리이는 무작위로 불리는데, 줄을 서 있거나 음식을 기다리는 고객이 대기 시간에 대해 문의할 수 있는 곳입니다.
naive_sim.py를 실행하면 터미널에서 다음 결과를 얻을 수 있습니다.

자, 이건 그 자체로 데이터 과학 제품입니다. 이걸로 몬테카를로 체인을 운영하면 긴 대기열의 잠재력을 확인할 수 있습니다. 레스토랑은 이 "디지털 트윈"을 활용하여 중요한 상황이 언제 발생할지 예측할 수 있습니다. 이제 제대로 작동하는 제품이 있으니, 인공지능(AI)을 활용하여 더욱 아름답고 강력하게 만들어 보겠습니다.
3. 에이전트 레스토랑 구현
위에서 볼 수 있듯이, 고객은 이미 질문을 할 수 있고, 답변은 숫자로 제공됩니다. 고객은 또한 시스템에서 음식을 무작위로 선택합니다. 이제 이 시스템에 상담원을 추가해 보겠습니다. 레스토랑 상담원 시스템을 구현하는 것은 고객 서비스를 자동화하고 사용자 경험을 개선하는 데 있어 매우 중요한 단계입니다. 숙련된 상담원이 고객 문의에 효율적으로 답변하고 개인 맞춤형 추천을 제공할 수 있기 때문입니다.
3.1 전담 에이전트 구현
"에이전트" 모듈을 설치해야 합니다.
고객 서비스 담당자, 엔터테인먼트 담당자, 불만 처리 담당자의 구현은 다음과 같습니다.
# custom_agents.py import os, json from openai import OpenAI from agents import Agent from newtools import * client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"), default_headers={"OpenAI-Beta":"assistants=v2"}) menu_agent = Agent(name = "Chef_suggester", instructions = "당신은 저희 레스토랑에 대한 모든 것을 알고 고객이 음식을 고르는 것을 돕는 친절한 서버입니다. 먼저 정중하게" "음식 가상 비서라고 소개하고 고객에게 정중하게 인사를 건네세요. 고객의 이름은 msg json 파일에서 확인할 수 있습니다." "메뉴를 읽고 고객이 묻는 내용을 바탕으로 json 파일의 요청 키에 메뉴에서 가장 적합한 추천을 제공하세요." "고객이 부적절한 질문을 하는 경우 'unsuccessfull'을 출력하세요. json 형식 '{food: , 상태: }'", tools = [get_menu]) entertainer_agent = Agent(name = "Entertainer", instructions = ("고객이 기다리는 동안 바쁘게 지내도록 도와주는 친절한 서버입니다." "할인이나 혜택을 제공할 수는 없지만, 메뉴에 대한 질문을 할 수 있으며, 이는 get_menu 함수에서 얻을 수 있습니다." "또한 줄을 서서 기다리는 시간이 얼마나 될지 물어볼 수도 있습니다. 해당 정보는 waiting_time에 있습니다." "user_status가 'queue'인 경우 대기 시간을 기준으로 친절하게 시간을 제공하십시오. 그렇지 않은 경우, user_status가 'food'인 경우 음식을 기다리고 있다는 의미입니다. 'order'를 선택하고 대기 시간에 대한 재미있는 언급을 제공하십시오." "예를 들어 '파스타 대기 시간이 5분인데, 셰프가 소스를 뿌리는 것 같습니다!'", tools = [get_menu]) customer_agent = Agent(name = "Customer", instructions = ("당신은 고객이고 이탈리아 레스토랑에서 식사하고 있습니다. get_menu 함수를 사용하여 메뉴를 선택하세요. 이미 원하는 메뉴를 알고 있다면 웨이터에게 말씀하세요. " "그렇지 않으면 대략적인 정보를 알려주거나, 취향에 따라 안내를 요청하세요. 웨이터가 가장 적합한 메뉴를 골라줄 것입니다.") 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, '')
우리는 정의를 가지고 있습니다 고객이는 OpenAI의 클라이언트 호출이며 newtools.py, 목록을 끌어올리고 콜_에이전트 개별 에이전트를 호출하고 이를 통해 운영합니다. 러너이러한 구성 요소는 효과적인 에이전트 시스템을 만드는 데 필수적입니다.
이것이 바로 서론에서 우리가 이야기했던 내용입니다. 우리는 여러 가지를 식별합니다. 자치령 대표 그들은 연결될 것이고, 그들은 사용하고 있습니다 도구 제 코드에 의해 정의됩니다. 이러한 도구와 에이전트를 사용하면 고객 서비스 작업을 자동화하고 사용자 경험을 개선할 수 있습니다.
에이전트에서 function_tool 가져오기 상수에서 * 가져오기 pandas를 pd로 가져오기 @function_tool def get_menu(): df = pd.read_csv(MENU_FILE) # 사전 목록(또는 JSON 직렬화 가능 구조)으로 변환 return df.to_dict(orient="records")
3.2 전담 에이전트 구현
구현이 통합되었습니다 작업대 그리고 레스토랑 다음 코드의 에이전트를 사용합니다.
import random import time import math import sys from utils import * from constants import * import time, random, json from custom_agents import * from utils import * from constants import * from agents import Runner # NAMES 상수에서 가져온 이름 목록 # NAMES = [ ...로 가정 ] 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] ➡️ 고객 {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"저희 LLM은 {cname}을 다음과 같이 처리했습니다: {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] ❓ 고객 {cid}: 음식이 나오는 데 얼마나 걸리나요?”
wait이 None인 경우: msg = f"[{self.clock:04}m] ➡️ 지금 준비되었습니다!"
print(msg) self.log_to_msg(msg) else: msg = f"[{self.clock:04}m] ➡️ 고객 {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"저희 LLM은 {cname}을 다음과 같이 처리했습니다: {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() self.query_prob이고 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--- 교대 종료 ---n{free}/{len(self.tables)}개의 테이블이 {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 대규모 언어 모델(LLM)을 사용하여 레스토랑을 위한 그래픽 사용자 인터페이스(GUI) 구현
대규모 언어 모델(LLM) 애플리케이션으로 레스토랑의 성과를 표시하기 위해 간단한 그래픽 사용자 인터페이스(GUI)를 사용합니다.
llm_models_gui에서 RestaurantGUI 가져오기 utils에서 * 가져오기 random에서 llm_models 가져오기 Restaurant 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=1.0, # GUI에 대한 더 매끄러운 query_prob=0.8, menu=menu ) app = RestaurantGUI(R)

그래픽 사용자 인터페이스(GUI)는 해당 인물(엠마), 테이블, 시간, 그리고 대규모 언어 모델(LLM)의 출력에 대한 정보를 제공합니다. .txt 파일도 자동으로 생성됩니다.
출력의 예를 보여드리겠습니다.
[12:31:23] 고객 Emma가 서버에게 말합니다. "전채로 브루스케타를 주문하고 싶습니다. 그다음 스파게티 카르보나라를 첫 번째 코스로 주문하겠습니다. 디저트로는 티라미수를 주문하겠습니다. 이 요리와 어울리는 와인도 추천해 주시겠습니까?" [12:31:25] 석사과정 학생의 처리된 답변은 다음과 같습니다. {'food': ['Bruschetta', 'Spaghetti Carbonara', 'Tiramisu', 'Chianti Classico'], 'status': 'successful'} [12:31:25] [0000M] ❓ 고객 1: 음식을 준비하는 데 얼마나 걸리나요? [12:31:25] [0000M] ➡️ 고객의 예상 음식 대기 시간 1:15분 [12:31:26] LLM 학생이 Emma의 주문을 처리했습니다. 마지막 고객: Agent(name="Entertainer", …) 최종 결과(문자열): 안녕하세요 Emma! 귀하의 인내심에 감사드립니다. 입장 대기시간은 약 15분 정도입니다. 이제 거의 다 왔어요. 맛있는 브루스케타를 꿈꾸기에 충분한 시간이에요! 🍽️
우리는 다음을 제공할 수 있습니다:
- 고객은 에이전트를 통해 자신만의 메뉴를 만듭니다.그리고 웨이터의 에이전트에게 추천을 요청합니다.
- 웨이터가 키안티 와인을 추천해 주고 목록에 추가해 준다.
- 불만 처리 담당자는 고객에게 대기 기간을 알려줍니다.
이제 이전처럼 워크플로를 시뮬레이션할 수 없게 되었고, 워크플로가 생겼습니다. 영리한동일한 ChatGPT 기술로 구동됩니다. 정말 멋지지 않나요?
4. 결론
와주셔서 정말 감사합니다. 저에게는 정말 큰 의미가 있어요 ❤️.
이 기사에서 우리가 무엇을 했는지 다시 살펴보겠습니다.
- 레스토랑 시스템 설계:
우리는 AI 에이전트를 추가한 PowerPoint를 사용하여 레스토랑 시스템에 대한 간단한 디자인을 만들었습니다. - 에이전트 없는 기준:
먼저 대기열, 조리 시간, 테이블 회전에 대한 로직을 코딩할 수 있도록 결정론적 시뮬레이션을 구축했습니다. 이는 AI가 구현되기 전의 뼈대였습니다. - 에이전트 기반 레스토랑:
이 단계에서는 AI 에이전트를 활용하여 불만 사항 및 조치 사례를 에이전트에게 전달했습니다. 또한 결과를 명확하게 표시하기 위해 그래픽 사용자 인터페이스(GUI)도 개발했습니다.
자, 이쯤에서 분명히 말씀드리고 싶습니다. 블랙미러처럼 들릴 수도 있겠지만요. 손님을 비춘다고요? 식당과 웨이터를 비춘다고요? 네, 이상하죠. 그러나 문제는 AI 도구 자체가 아니라, 어떻게 사용되느냐입니다. 저는 인간 웨이터를 AI로 대체하는 것은 지는 게임이라고 생각합니다.
웨이터는 단순히 주문을 받고 이전에 주문한 1번 와인을 바탕으로 XNUMX번 와인을 추천하는 것이 아닙니다. 손님이 환영받는 기분을 느낄 만큼 따뜻하면서도 대화에 끼어들지 않을 만큼 거리를 두는 것, 손님이 편안하게 느낄 만큼 부드러우면서도 자신의 경계를 존중할 만큼 강인한 자세를 갖는 것입니다. 저는 이러한 자질들이 인간적인 손길, 인내심, 그리고 공감을 필요로 한다고 생각합니다.
하지만 저는 이 기술을 올바르게 사용하는 데에는 두 가지 목적이 있다고 믿습니다.
- 대기자 명단에 있는 실제 사람들을 돕습니다. 매장 안의 웨이터들은 매우 바쁘고, 식당들은 이미 기다리는 동안 메뉴를 살펴볼 수 있도록 메뉴를 제공하고 있습니다. 다른 웨이터들이 테이블 없이 기다리는 사람들을 응대하고 있다고 생각하는 것은 비현실적입니다. 이 시점에서 AI와 채팅하는 것이 도움이 될 수 있습니다.
- 레스토랑 시뮬레이션내가 쓴 시나리오는 시뮬레이션입니다 행동 고객 또한, 이는 시뮬레이션을 사용하여 다양한 시나리오를 테스트하고, 대기열이 형성되는 시점을 확인하고, 사람들의 다양한 반응과 웨이터의 다양한 대응을 가정하는 등의 작업을 수행할 수 있음을 의미합니다. 다시 말해, 테스트를 수행하는 자체 "디지털 트윈"이 될 수 있습니다.
댓글이 닫혔습니다.