17장. 세션, 메모리, 대화 상태 관리
17장. 세션, 메모리, 대화 상태 관리
LLM 서비스 데모를 처음 만들면 종종 이런 착각을 한다. 채팅창이 있으니 대화형 서비스가 이미 완성된 것처럼 보인다는 착각이다. 사용자가 질문을 보내고 모델이 답하면 얼핏 그럴듯하다. 하지만 두세 번만 말을 주고받아도 금세 이상한 점이 드러난다. 방금 한 이야기를 잊고, 같은 설명을 다시 하고, 사용자의 취향도 기억하지 못한다. 브라우저를 새로고침하면 대화가 사라지기도 한다.
이유는 단순하다. LLM은 기본적으로 상태가 없다. 모델은 매 요청마다 그 순간 전달된 입력만 보고 답을 만든다. 어제 나눈 대화도, 10초 전에 말한 조건도, 사용자가 어떤 고객인지도 스스로 보관하지 않는다. 우리가 "기억한다"고 느끼는 경험은 사실 모델의 능력이라기보다 애플리케이션이 문맥을 다시 넣어준 결과다.
그래서 대화형 서비스의 품질은 프롬프트 문장력만으로 결정되지 않는다. 세션을 어떻게 저장할지, 얼마나 긴 문맥을 유지할지, 무엇을 요약하고 무엇을 오래 보관할지, 여러 기기와 여러 탭에서 상태를 어떻게 맞출지가 더 중요해진다. 이 장의 핵심은 한 문장으로 정리할 수 있다. 대화 경험은 결국 애플리케이션이 책임진다.

대화 상태를 세 가지로 나눠서 생각하라
대화형 LLM 서비스를 설계할 때 가장 먼저 해야 할 일은 "기억"이라는 말을 쪼개는 것이다. 기억을 한 덩어리로 생각하면 설계가 금방 엉킨다. 실무에서는 대개 세 가지 층으로 나누면 훨씬 명확해진다.
첫 번째는 세션이다. 지금 열려 있는 대화방, 현재 요청이 어떤 사용자와 어떤 대화 흐름에 속하는지 구분해주는 단위다. 채팅방 번호표에 가깝다.
두 번째는 문맥이다. 이번 응답을 만들기 위해 모델에 실제로 넣는 대화 내용이다. 최근 몇 개의 메시지, 요약본, 참고 문서, 현재 작업 상태가 여기에 들어간다. 세션 전체가 아니라, 그중 지금 필요한 부분만 골라서 모델에 제공하는 층이다.
세 번째는 메모리다. 세션을 넘어 비교적 오래 유지하고 싶은 정보다. 예를 들어 사용자의 선호 언어, 회사명, 자주 쓰는 보고서 형식, 반복되는 업무 규칙 같은 것들이다.
이 셋은 비슷해 보이지만 역할이 다르다. 세션은 경계를 정의하고, 문맥은 현재 답변의 재료가 되며, 메모리는 장기 경험을 만든다. 이 구분이 되면 "무엇을 DB에 저장할까"보다 먼저 "무엇이 지금 필요하고 무엇이 나중에도 필요할까"를 판단할 수 있다.
세션은 채팅방이 아니라 작업의 경계다
세션을 단순히 대화 UI의 방 번호로만 생각하면 놓치는 것이 많다. 실무에서 세션은 사용자의 말 몇 줄을 저장하는 상자가 아니라, 하나의 상호작용 흐름을 묶는 경계다.
예를 들어 고객지원 챗봇이라면 세션 하나가 문의 한 건일 수 있다. 문서 작성 도우미라면 세션 하나가 특정 문서 초안 작업일 수 있다. 회의록 서비스라면 하나의 회의가 세션이 될 수 있다. 중요한 것은 "이 맥락은 어디까지 이어져야 하는가"를 제품 기준으로 먼저 정하는 것이다.
세션 설계에서 자주 필요한 필드는 생각보다 단순하다. session_id, user_id, tenant_id, 생성 시각, 마지막 활동 시각, 현재 상태, 제목, 연결된 작업 객체 정도만 있어도 출발할 수 있다. 여기에 대화 모드, 사용 중인 모델, 언어, 권한 범위 같은 메타데이터를 붙이면 운영이 한결 편해진다.
세션 수명도 중요하다. 모든 세션을 영원히 살려둘 필요는 없다. 어떤 서비스는 30분 동안 활동이 없으면 세션을 닫아도 되고, 어떤 서비스는 몇 달 뒤에도 다시 이어서 봐야 한다. 이 기준은 기술보다 제품 경험에서 나온다. 세금 신고 도우미와 일상 잡담 챗봇의 세션 수명이 같을 이유는 없다.
여기서 한 가지 실수가 자주 나온다. 사용자가 로그인만 되어 있으면 세션을 하나만 두는 것이다. 그러면 여러 작업이 뒤섞인다. 오전에 계약서를 검토하다가 오후에 마케팅 카피를 쓰면, 서로 다른 문맥이 같은 통에 들어간다. 결국 모델은 이상한 친절함을 발휘한다. 계약서 얘기하다가 갑자기 광고 문구를 섞어 말하는 식이다. 사람도 메신저 방을 나누는데, 시스템이 그 정도 배려는 해줘야 한다.
메시지 저장은 '전부 넣기'가 아니라 '재구성 가능성'이 핵심이다
많은 초기에선 대화 메시지를 순서대로 저장하고, 요청이 오면 전부 다시 모델에 넣는다. 사용자가 적고 대화가 짧을 때는 이 방식도 된다. 하지만 대화가 길어지면 곧바로 한계가 온다. 토큰 비용이 늘고, 지연이 길어지고, 중요한 정보가 긴 대화 속에 묻힌다.
그래서 메시지 저장의 목적을 다시 생각해야 한다. 저장의 목적은 단순 보관이 아니라 재구성 가능성이다. 나중에 필요한 문맥을 적절한 형태로 다시 만들 수 있어야 한다.
실무에서는 메시지를 보통 다음 단위로 다룬다.
사용자 메시지
어시스턴트 응답
시스템 지시나 대화 정책
툴 호출 요청과 결과
상태 변화 이벤트
특히 툴 호출이 들어가는 서비스에서는 단순한 채팅 로그만으로는 부족하다. 모델이 어떤 도구를 왜 호출했는지, 외부 시스템에서 어떤 결과를 받았는지, 그 결과가 사용자에게 어떻게 반영되었는지를 함께 남겨야 한다. 그래야 나중에 같은 세션을 재생하거나 디버깅할 수 있다.
중요한 것은 원본 로그와 모델 입력용 문맥을 분리하는 것이다. 원본 로그는 사실 그대로 보관한다. 반면 모델에 넣는 문맥은 목적에 맞게 압축하고 선택한다. 이 둘을 같은 것으로 취급하면 저장도 비싸지고 응답도 둔해진다.
문맥 창은 넓을수록 좋은 것이 아니다
LLM 서비스에서 자주 듣는 말이 있다. "컨텍스트 윈도우가 커졌으니 이제 대화 전체를 다 넣어도 되지 않나요?" 이 말은 절반만 맞다. 큰 문맥 창은 확실히 도움이 된다. 하지만 크다고 해서 항상 좋은 것은 아니다.
첫째, 비용이 늘어난다. 긴 대화를 매번 다시 넣으면 사용자 한 명의 채팅도 조용히 비싸진다.
둘째, 속도가 느려진다. 입력이 길수록 처리 시간이 늘어나는 경우가 많다.
셋째, 집중력이 흐려진다. 모델에게 너무 많은 내용을 한꺼번에 주면 정말 중요한 제약 조건이 오히려 묻히기도 한다.
넷째, 불필요한 과거가 현재를 오염시킨다. 예전의 임시 요구사항, 이미 바뀐 결론, 취소된 작업 상태가 계속 따라오면 현재 답변의 정확도가 떨어진다.
그래서 좋은 대화 서비스는 "얼마나 많이 넣을까"보다 "무엇을 남기고 무엇을 덜어낼까"를 더 잘한다. 사람도 회의할 때 녹취록 전부를 읽고 답하지 않는다. 최근 논의와 핵심 결정만 챙긴다.
최근 대화, 요약, 핵심 사실을 분리하라
문맥 관리에서 가장 실용적인 패턴은 최근 대화와 축약 요약을 함께 쓰는 방식이다. 흔히 롤링 서머리라고 부르는 접근이다.
예를 들어 최근 8개 메시지는 원문 그대로 넣고, 그 이전 내용은 짧은 요약으로 대체할 수 있다. 이렇게 하면 방금 오간 말의 뉘앙스는 유지하면서도 긴 세션의 핵심을 잃지 않을 수 있다.
좋은 요약은 단순 줄거리 요약이 아니다. 대화 서비스에서 유용한 요약은 보통 이런 정보를 담는다.
사용자의 현재 목표
지금까지 확정된 조건
아직 해결되지 않은 질문
모델이 수행한 작업과 그 결과
다음 응답에서 지켜야 할 작성 규칙
예를 들어 문서 작성 서비스라면 "사용자는 투자자 보고용 요약 문서를 원하며, 분량은 A4 1장, 톤은 공식적, 숫자는 보수적으로 표현, 아직 시장 규모 문단은 미완성" 같은 정보가 요약에 들어가야 한다. 반대로 잡담이나 이미 끝난 논의는 굳이 남길 필요가 없다.
요약은 한 번 크게 만들고 끝내는 것보다, 일정 길이를 넘을 때마다 갱신하는 편이 낫다. 다만 매 메시지마다 새로 요약하면 또 비용이 든다. 그래서 보통은 메시지 수, 토큰 수, 세션 길이, 상태 변화 여부를 기준으로 요약 시점을 정한다.
무엇을 요약하고 무엇을 그대로 둘 것인가
문맥 축약에서 어려운 점은 모두 중요해 보인다는 것이다. 하지만 실무에서는 우선순위를 정해야 한다. 좋은 기준은 "다음 응답의 품질에 직접 영향을 주는가"이다.
그대로 유지할 가치가 큰 것은 최근 질문, 현재 작업 지시, 형식 제약, 툴 실행 결과, 아직 확정되지 않은 쟁점이다. 이런 것은 모델이 바로 다음 답을 만드는 데 직접 필요하다.
반면 요약해도 되는 것은 이미 합의된 배경 설명, 반복된 표현, 끝난 작업의 세부 과정, 감탄사처럼 의미가 약한 대화들이다.
아예 버려도 되는 정보도 있다. 예를 들어 사용자가 "잠깐만", "다시", "이건 아니고"처럼 흐름 조정용으로 남긴 짧은 말 중 일부는 상태 업데이트 후 원문 중요도가 떨어질 수 있다. 물론 감사 로그나 원본 보관은 따로 필요하지만, 매번 모델에 넣을 이유는 없다.
문맥 관리는 도서관 운영과 비슷하다. 책을 버리자는 뜻이 아니라, 당장 읽을 책상 위에는 필요한 책만 올리자는 뜻이다.
메모리는 대화 로그가 아니라 정제된 사실이어야 한다
대화형 서비스에서 "메모리"를 도입하고 싶어지는 순간이 온다. 사용자가 늘 같은 업종이고, 늘 같은 형식을 선호하며, 늘 비슷한 작업을 반복하기 때문이다. 문제는 무엇을 메모리로 저장할지다.
여기서 가장 흔한 실수는 긴 대화 전체를 장기 기억으로 취급하는 것이다. 그렇게 하면 기억이 아니라 잡동사니 창고가 된다. 메모리는 대화 로그의 복사본이 아니라, 장기적으로 유용한 사실의 정제본이어야 한다.
실무에서는 메모리를 보통 세 종류로 나누면 관리하기 쉽다.
첫 번째는 프로필 메모리다. 사용자의 기본 선호와 정적 정보다. 예를 들면 선호 언어, 직무, 회사명, 자주 쓰는 출력 형식, 금지하고 싶은 표현 스타일 같은 것들이다.
두 번째는 작업 메모리다. 특정 프로젝트나 문서, 티켓, 케이스에 묶여 있는 지속 정보다. 예를 들어 "이번 제안서는 20대 직장인을 타깃으로 한다", "이 고객사는 민감한 가격 정보 공개를 꺼린다" 같은 사실이 여기에 속한다.
세 번째는 상호작용 메모리다. 반복적으로 드러난 선호나 습관을 추출한 것이다. 사용자가 늘 표 형식을 원한다거나, 답변 앞에 결론을 먼저 달라고 한다거나, 코드는 Python 예제를 선호한다는 정보가 여기에 들어갈 수 있다.
중요한 점은, 메모리는 대체로 사람이 읽어도 이해 가능한 문장이나 구조화된 속성 형태여야 한다는 것이다. 나중에 왜 이런 기억이 생겼는지 설명 가능해야 하고, 수정하거나 삭제하기도 쉬워야 한다.
메모리는 자동 수집보다 검증이 더 중요하다
메모리를 만들 때 모델에게 "중요한 사실을 알아서 기억해"라고 맡기고 싶어진다. 어느 정도는 가능하다. 하지만 자동 수집만 믿으면 곧 이상한 일이 생긴다. 사용자가 한번 농담으로 말한 별명을 본명처럼 기억하거나, 일시적 요구사항을 영구 선호로 저장할 수 있다.
그래서 메모리에는 최소한의 검증 규칙이 필요하다. 예를 들어 한 번 나온 정보는 바로 영구 저장하지 않고, 반복 등장하거나 사용자가 명시적으로 확인했을 때만 승격하는 식이다. 또는 "항상", "매번", "선호한다"처럼 장기 성향으로 해석될 표현만 후보로 삼는 방법도 있다.
민감한 정보의 경계도 분명해야 한다. 개인식별정보, 결제 정보, 건강 정보, 법적 민감 정보는 메모리 자동 저장 대상에서 제외해야 하는 경우가 많다. 잘 기억하는 서비스보다, 함부로 기억하지 않는 서비스가 더 신뢰받는다.
좋은 메모리는 똑똑함보다 절제가 중요하다. 상대의 취향을 잘 기억하는 바리스타는 멋지지만, 주민등록번호까지 외우고 있으면 무섭다.
단기 메모리와 장기 메모리를 섞지 마라
대화형 시스템에서 상태 관리가 꼬이는 이유 중 하나는 단기 정보와 장기 정보를 한 통에 넣기 때문이다. 예를 들어 "이번 요청에서는 300자 이내로 써줘" 같은 조건은 단기 지시다. 반면 "나는 평소에 간결한 요약을 선호해"는 장기 선호일 수 있다.
이 둘을 구분하지 않으면 문제가 생긴다. 단기 조건이 영구 선호로 남아버리거나, 오래 유지되어야 할 취향이 세션이 끝나면서 사라진다.
실전에서는 보통 이렇게 나누는 편이 안전하다. 현재 세션 안에서만 유효한 상태는 session state에 둔다. 예를 들어 현재 문서의 제목, 지금 선택한 언어, 이번 대화에서의 길이 제한이 여기에 들어간다. 여러 세션에 걸쳐 유지할 가치가 있는 것은 durable memory에 둔다. 예를 들어 사용자의 기본 언어, 자주 쓰는 톤, 팀의 공통 서식 규칙 같은 것들이다.
이 구분이 명확하면 모델 입력도 쉬워진다. "지금 당장 지켜야 할 것"과 "평소 참고하면 좋은 것"을 분리해서 전달할 수 있기 때문이다.
상태 동기화는 백엔드만의 문제가 아니다
대화 상태는 서버에만 저장하면 끝날 것 같지만, 실제 서비스에서는 프론트엔드와의 동기화가 매우 중요하다. 같은 사용자가 브라우저 두 탭을 열어두거나, 모바일과 데스크톱에서 동시에 작업하거나, 스트리밍 응답 도중 새 요청을 보내는 일이 흔하기 때문이다.
이때 흔히 생기는 문제가 순서 꼬임이다. 먼저 보낸 요청보다 나중 요청의 응답이 먼저 도착하거나, 한 탭에서 제목을 바꿨는데 다른 탭에는 옛 상태가 남거나, 툴 실행 결과가 늦게 반영되어 대화 흐름이 어색해지는 식이다.
이 문제를 줄이려면 상태를 이벤트 관점으로 보는 것이 좋다. "최종 화면 상태"만 덮어쓰는 방식보다, 메시지 추가, 응답 시작, 응답 토큰 수신, 툴 호출 시작, 툴 결과 반영, 응답 완료 같은 이벤트를 순서대로 관리하는 편이 안전하다.
특히 스트리밍 채팅에서는 다음 원칙이 유용하다. 서버는 각 응답 단위를 식별 가능한 ID로 보내고, 클라이언트는 그 ID 기준으로 화면을 업데이트한다. 응답이 완전히 끝나기 전에는 임시 상태와 확정 상태를 구분한다. 사용자가 중간에 취소하면 해당 응답을 중단된 상태로 마감한다. 이런 작은 규칙들이 모여 대화 경험의 부드러움을 만든다.
여러 기기와 여러 탭에서 같은 대화를 맞추는 법
멀티 디바이스 환경에서는 "누가 진짜 최신 상태인가"가 중요하다. 가장 쉬운 원칙은 서버를 단일 진실 원천으로 두는 것이다. 즉, 세션과 메시지의 최종 상태는 서버가 결정하고, 클라이언트는 이를 구독하거나 주기적으로 동기화한다.
사용자가 메시지를 보내면 클라이언트는 즉시 화면에 임시 메시지를 띄울 수 있다. 하지만 서버가 접수하고 message_id를 발급하면 그 시점의 상태를 기준으로 정렬과 확정을 해야 한다. 그래야 네트워크가 느릴 때도 메시지가 중복되거나 순서가 꼬이지 않는다.
여러 탭 동기화에서는 다음 요소가 특히 중요하다.
세션 버전 또는 마지막 업데이트 시각
메시지별 고유 ID
낙관적 UI와 서버 확정 상태의 구분
취소, 재생성, 편집 같은 액션의 충돌 처리
예를 들어 한 탭에서 "다시 생성"을 눌렀는데 다른 탭에서는 이전 답변이 아직 유효하다고 생각하면 혼란이 생긴다. 이런 경우 응답 계보를 남기는 방식이 유용하다. 원본 응답, 재생성 응답, 선택된 응답을 구분하면 사용자는 대화가 왜 바뀌었는지 이해할 수 있다.
문서형 서비스와 채팅형 서비스는 상태 구조가 다르다
모든 대화 서비스가 똑같은 상태 모델을 쓰지는 않는다. 채팅형 서비스는 메시지 순서가 중심이다. 반면 문서형 서비스는 결과물 객체가 중심이 되는 경우가 많다.
예를 들어 블로그 초안 작성 서비스에서는 사용자가 여러 차례 대화하더라도 진짜 중요한 상태는 "현재 초안의 최신 버전", "선택한 톤", "목차 구조", "승인 여부"일 수 있다. 이 경우 메시지 로그만 저장해서는 부족하다. 대화와 별도로 문서 상태를 버전 관리해야 한다.
반대로 고객 상담 챗봇이라면 세션의 핵심 상태가 티켓 정보, 현재 문의 카테고리, 상담 단계, 필요한 인증 여부일 수 있다. 즉, 대화 상태는 서비스 도메인 상태와 연결되어야 한다.
이 점이 중요하다. 대화 로그만 잘 저장한다고 상태 관리가 끝나는 것이 아니다. 제품이 진짜로 다루는 객체가 무엇인지 찾아야 한다. 대화는 그 객체를 조작하기 위한 인터페이스일 뿐인 경우가 많다.
상태 모델은 사람이 이해할 수 있어야 한다
운영 단계로 갈수록 중요한 것은 설명 가능성이다. 사용자가 "왜 갑자기 이전 이야기를 잊었나요?"라고 물었을 때, 운영자가 상태를 추적할 수 있어야 한다. 그러려면 내부 상태 모델이 사람에게도 읽혀야 한다.
예를 들어 다음 정도는 쉽게 확인 가능해야 한다. 현재 세션에 최근 몇 개 메시지가 문맥으로 들어갔는지, 마지막 요약이 언제 생성됐는지, 어떤 메모리가 적용됐는지, 어떤 툴 결과가 아직 반영 대기 중인지 말이다.
상태가 전부 블랙박스처럼 섞여 있으면 디버깅이 매우 힘들다. 사용자는 모델이 멍청하다고 느끼지만, 실제 원인은 오래된 요약이 갱신되지 않았거나 다른 탭의 상태가 덮어쓴 것일 수 있다. 결국 좋은 상태 관리는 사용자 경험과 운영 경험을 동시에 좋게 만든다.
대화가 길어질수록 필요한 것은 더 많은 기억이 아니라 더 좋은 편집이다
긴 대화를 다루다 보면 "더 많이 저장하자"는 방향으로 가기 쉽다. 하지만 서비스 품질은 저장량보다 편집 품질에서 갈린다. 어떤 정보를 살리고, 어떤 정보를 접고, 어떤 기억을 승격하고, 어떤 상태를 잊게 할지 결정하는 능력이 중요하다.
이 편집 감각이 없으면 대화는 점점 무거워진다. 비용은 늘고, 응답은 느려지고, 모델은 산만해진다. 반대로 편집이 잘되면 세션이 길어도 가볍게 움직인다. 사용자는 "나를 기억한다"고 느끼지만, 실제로는 시스템이 중요한 것만 잘 추려서 다시 보여주고 있는 셈이다.
이 점에서 대화 상태 관리는 단순 저장 문제가 아니다. 작게는 토큰 최적화이고, 크게는 제품 경험의 편집 설계다.
실무에서 추천하는 기본 전략
처음부터 거대한 메모리 시스템을 만들 필요는 없다. 다만 최소한의 질서는 있어야 한다. 실무에서는 다음 흐름으로 시작하면 안정적이다.
세션 단위를 제품 기준으로 명확히 정의한다.
원본 메시지 로그와 모델 입력용 문맥을 분리한다.
최근 메시지 몇 개는 원문으로, 그 이전은 요약으로 유지한다.
장기 메모리는 명시적이거나 반복적으로 확인된 정보만 저장한다.
서버를 상태의 기준점으로 두고, 클라이언트는 이벤트 기반으로 동기화한다.
세션 상태와 도메인 객체 상태를 따로 관리하되 연결 가능하게 설계한다.
이 정도만 지켜도 대화형 서비스의 체감 품질은 크게 달라진다. 사용자는 같은 모델을 써도 어떤 서비스는 자연스럽고 어떤 서비스는 금방 멍해진다고 느낀다. 그 차이의 상당 부분은 모델 선택이 아니라 상태 관리에서 나온다.
자주 생기는 실패 패턴
상태 관리가 약한 서비스에는 비슷한 증상이 반복된다. 처음에는 사소해 보여도 사용자 신뢰를 빠르게 깎아먹는다.
첫째, 모든 메시지를 매번 통째로 넣는 방식이다. 초반엔 단순하지만, 길어질수록 느리고 비싸며 산만해진다.
둘째, 요약을 너무 늦게 하거나 너무 자주 하는 방식이다. 너무 늦으면 문맥이 비대해지고, 너무 자주 하면 요약 비용과 오류가 쌓인다.
셋째, 장기 메모리 기준이 없는 방식이다. 사용자의 일시적 요구가 영구 취향처럼 남아버린다.
넷째, 프론트 상태와 서버 상태가 따로 노는 방식이다. 한쪽에서는 완료로 보이는데 다른 쪽에서는 아직 생성 중인 일이 생긴다.
다섯째, 대화 상태와 제품 상태를 분리하지 않는 방식이다. 문서 작성 서비스인데 문서 버전은 없고 채팅 로그만 남는 식이다.
이런 실수는 특별히 복잡한 AI 때문이 아니라, 대화 서비스를 일반 채팅창 정도로 가볍게 본 데서 나온다.
마무리
대화형 LLM 서비스의 본질은 모델이 말을 잘하는가에만 있지 않다. 사용자가 지금 누구인지, 무슨 작업을 하고 있는지, 방금 어떤 결정을 내렸는지, 무엇을 오래 기억하고 무엇을 잊어야 하는지를 애플리케이션이 얼마나 잘 관리하느냐에 달려 있다.
세션은 경계를 만들고, 문맥은 현재 답변을 가능하게 하며, 메모리는 장기 경험을 만든다. 그리고 이 셋은 자동으로 생기지 않는다. 저장 전략, 요약 규칙, 메모리 정책, 동기화 구조를 통해 애플리케이션이 만들어내야 한다.
결국 사용자가 "이 서비스는 내 말을 이해하고 이어서 일한다"고 느끼는 순간은, 모델이 갑자기 의식을 얻어서가 아니다. 상태 없는 모델 위에 상태 있는 제품을 잘 올려놓았기 때문이다.
다음 장에서는 이 상태 구조 위에서 한 단계 더 나아가, 여러 사용자와 조직이 함께 쓰는 환경에서 인증, 권한, 테넌시를 어떻게 설계해야 하는지 살펴보겠다.
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.