🎯 2026년 목표 분야 목표 ☁️ Cloud 클라우드 환경 운영 경험 쌓기 (상세 내용 추후 작성) 🔐 Security 보안관제 자동화 경험 ✍️ Blog 블로그 꾸준히 작성 📚 자격증 정보처리기사 / 정보보안기사 / AWS-SAA 🏆 장기 자격증 CISA / CISSP (정보보안 관련 경력 요건 충족 후 도전) 💻 Development 개발 공부 꾸준히 진행 🇺🇸 English 영어 공부 🏃 Exercise 꾸준한 운동 🔄 Review 리팩토링 과정 복습 및 Velog 재작성 ☁️ Cloud Security 클라우드 보안 복습 및 Velog 작성 🎓 Next Year 석사 과정 예정 🗺️ 공부 로드맵 - Version 10월 🟢 완료 | 🟡 진행중 | 🔴 미완료 | ⚪ 시작 전 순서 공부 상태 / 목표 진행률 1 🐍 파이썬 🟢 점프 투 파이썬 완강 → 지속적인 복습 + 개인 프로젝트 100% 2 📘 정보처리기사 실기 🟡 10월 25일 시험 / 합격 목표 50% 3 🔐 모의해킹 - 노말틱 ⚪ 정보처리기사 실기 끝나고 11월 시작 0% 4 🇺🇸 영어 ⚪ 11월부터 시작 0% 5 🌐 혼자 공부하는 네트워크 🟢 완강 → 지속적인 복습 100% 6 🔄 리팩토링 과정 ⚪ 복습 + 실습 + 블로그 재작성 0% 7 🐳 Docker ⚪ 모의해킹 완료 후 시작 0% 8 ☁️ AWS 보안 가이드 ⚪ Docker 강의 완료 후 시작 0% 9 ☕ JAVA ⚪ 파이썬 활용 능력이 어느 정도 자리 잡은 후 시작 0% 📅 금주 목표 - 10/05(월) ~ 10/11(일) 🟢 완료 | 🟡 진행중 | 🔴 미완료 | ⚪ 시작 전 분야 목표 진행 상황 진행률 🌐 Network 혼자 공부하는 네트워크 복습 🟡 30% 🐍 Python Project Nmap과 유사한 기능 직접 구현 🟡 50% 📘 정보처리기사 개념 정리 🟡 40% 📘 정보처리기사 2020년도 기출 3회차 풀이 ⚪ 0% 📘 정보처리기사 2021년도 기출 2회차 풀이 ⚪ 0% 📘 정보처리기사 2022년도 기출 2회차 풀이 ⚪ 0% 📘 정보처리기사 2023년도 기출 1회차 풀이 ⚪ 0% 📘 정보처리기사 2024년도 기출 1회차 풀이 ⚪ 0% 📘 정보처리기사 2025년도 기출 1회차 풀이 ⚪ 0% 📘 정보처리기사 2026년도 기출 1회차 풀이 ⚪ 0% ✅ 오늘의 목표 🟢 완료 | 🟡 진행중 | 🔴 미완료 | ⚪ 시작 전 상태 할 일 ⚪ 💰 Household Account 작성 - 23:50 ⚪ 📘 **정보처리기사 개념 정리 + 블로그 정리 ⚪ 📘 정보처리기사 DAY 6 - 문제풀이 ⚪ 🌐 혼자 공부하는 네트워크 복습 DAY 6 🟡 🐍 Python Security Scanner DAY 6 - Nmap 기능 구현 + 블로그 정리 🟡 🐍 Python Security Scanner DAY 6 - 지금까지 작성 한 코드 복기 💻 오늘 완료한 일 상태 완료 내역 ✅ ✅ ✅ ✅ ✅ ✅
무슨 일이 있었나 오픈AI가 2026년 10월 6일 'Sharing AI progress in mathematics'라는 글을 통해 자사 내부 AI 모델이 수학계의 장기 미해결 난제 100개 이상을 풀어냈다고 공식 발표했다. 지난 8월 28일부터 학습을 시작한 내부 모델이, 앞서 공개된 나비에-스토크스 밀레니엄 상 문제 해결에 더해 수학 거의 모든 분야에 걸쳐 10년 이상 풀리지 않은 문제 100여 개를 추가로 해결했다는 내용이다. 오픈AI는 이 같은 주장을 독립적으로 검증하기 위해 '수학과 인공지능 자문단(Advisory Group on Mathematics and Artificial Intelligence)'을 꾸렸다고 밝혔다. 자문단 구성원은 오픈AI로부터 급여를 받지 않는 독립적 지위라는 점을 강조했다. 오픈AI 소속 수학자들조차 AI의 진행 속도에 놀라 내부적으로 '이 결과를 어떻게 공개할지'를 논의했다고 전해진다. 이번 발표는 이번 주 출시된 신형 모델 GPT-6 아스트라(Astra)가 추가로 여러 장기 미해결 수학 문제에서 새로운 결과를 냈다는 내용과도 맞물려 있다. 오픈AI는 아스트라가 수십 년간 풀리지 않은 수학·이론 컴퓨터과학 문제들을 '해결했거나 본질적인 진전을 이뤘다'고 설명했다. 앞서 올여름에는 내부 시스템이 10년 이상 미해결 상태였던 문제 10개를 풀었다고 밝힌 바 있고, 5월에는 미공개 모델이 에르되시 단위거리 추측(Erdős unit-distance conjecture)의 반증을 내놓기도 했다. 다만 이 발표를 둘러싼 논란도 있다. 오픈AI의 초기 발표문에는 "핵심 결과에 대해 최소 10년 이상, 많은 경우 그보다 훨씬 오래 진전이 없었던 미해결 문제들의 답을 공유한다"는 문구가 있었는데, 이후 별다른 설명 없이 조용히 수정됐다. 매체 더버지에 따르면 케임브리지대학의 한 수학자는 오픈AI의 초기 발표가 안드레아스 톰(Andreas Thom)과 가보르 쿤(Gábor Kun) 등 기존 연구자들의 핵심적인 선행 기여를 충분히 밝히지 않았다고 지적했다. 왜 중요한가 이번 사안은 'AI가 정말 독창적인 추론으로 난제를 풀었는가, 아니면 기존 문헌의 결과를 재구성·결합한 것에 가까운가'라는 신뢰성·공로 인정 문제를 정면으로 제기한다. AI 모델이 이미 존재하는 인간 연구자의 성과를 디딤돌로 삼았다면, 그 공로를 어떻게 분배할 것인가는 간단치 않은 문제다. 주요 AI 랩들이 '유명 미해결 문제를 풀었다'는 성과를 역량 과시·마케팅 수단으로 점점 더 많이 활용하는 흐름 속에서, 독립적 검증 기구의 필요성이 커지고 있다. 오픈AI가 자문단을 꾸린 것도 이런 맥락이지만, 급여 지급 구조나 실제 독립성 수준은 앞으로도 검증 대상이 될 전망이다. 보도에 따르면 앤스로픽의 미공개 클로드 연구 모델도 별도로 리만 가설과 관련된 수십 년 묵은 연구에서 주요한 진전을 이뤘다고 알려져, 오픈AI·앤스로픽·구글 딥마인드 등 프런티어 랩들이 유명 수학 난제 해결을 'AGI에 가까운 역량'의 증거로 경쟁적으로 내세우는 더 큰 흐름의 일부임을 보여준다. 이러한 성과가 사실이라면 AI가 순수수학 연구의 협력자로서 빠르게 유용해지고 있다는 신호지만, 과장된 주장은 수학계의 신뢰를 해치고 톰·쿤 공로 논란처럼 반발을 부를 수 있다는 점에서 균형 잡힌 검증이 중요해지고 있다. 원문: https://openai.com/index/sharing-ai-progress-in-mathematics
무슨 일이 있었나 앤스로픽이 2026년 10월 7일 신형 소형 모델 '클로드 하이쿠 5.5(Claude Haiku 5.5)'를 공식 출시했다. API 식별자는 claude-haiku-5-5 이며, 클로드 플랫폼은 물론 AWS·구글 클라우드·마이크로소프트 애저에서도 바로 이용할 수 있다. 앤스로픽은 이 모델을 "지금까지 내놓은 소형 모델 중 가장 저렴하고 가장 빠르며 가장 성능이 뛰어난 모델"이라고 소개했다. 요약, 컨텍스트 압축, 데이터베이스 질의, 분류 같은 대량·저비용 작업에 적합하고, 오퍼스 5.5·소네트 5.5와 함께 서브에이전트로 활용하거나 실시간 고객지원·브라우저 자동화처럼 속도가 중요한 작업에도 쓰도록 설계됐다. 특히 하이쿠 계열 최초로 '조정 가능한 추론 강도(effort)' 설정이 도입돼, 비용과 성능 사이의 균형을 사용자가 직접 조절할 수 있게 됐다. 하이쿠 4.5 대비 벤치마크 향상폭도 상당하다. OSWorld 2.1(오프라인 서브셋) 점수는 15.7%에서 72.4%로, 'Humanity's Last Exam'(도구 미사용)은 10.2%에서 45.9%로, Terminal-Bench 4.0은 0.0%에서 39.2%로 뛰었다. 가격은 100만 토큰당(10만 토큰 이하/초과 기준) 입력 0.10달러/0.50달러, 출력 0.50달러/2.50달러, 캐시 읽기 0.01달러/0.05달러, 캐시 쓰기 0.125달러/0.625달러로 책정됐다. 앤스로픽에 따르면 평균적으로 하이쿠 4.5보다 운영 비용이 약 75% 저렴하다. 함께 발표된 내용으로 소네트 5.5의 캐시 읽기 가격도 100만 토큰당 0.10달러로 절반 인하돼 에이전트 작업 비용을 약 20% 낮췄고, 맥스·팀 구독자에겐 매달 API 크레딧이 제공되며 파이썬·타입스크립트 SDK에는 컴퓨터·브라우저 사용 베타 기능이 추가됐다. 안전성 면에서는 하이쿠 4.5보다 정렬 수준이 개선됐고, 사이버보안 안전장치는 더 엄격해졌으며 생물 안전장치는 다른 최신 모델과 동일한 수준이라고 밝혔다. 왜 중요한가 '소형' 모델임에도 벤치마크가 큰 폭으로 뛴 것은, 한때 플래그십 모델만 가능했던 성능이 빠르게 저가 모델로 내려오고 있음을 보여준다. 이는 AI 성능-비용 경쟁의 최전선이 계속 이동하고 있다는 신호다. 시점도 주목할 만하다. 오픈AI가 GPT-6와 '인텔리전트 UI'를 챗GPT 전체에 적용한 날과 같은 날 발표되면서, 플래그십·보급형 모델 양쪽에서 동시에 벌어지는 오픈AI·앤스로픽·구글의 3각 경쟁 구도가 한층 뚜렷해졌다. 기업 입장에서는 분류·서브에이전트 같은 대량 작업의 비용이 낮아지면 AI 도입의 총비용(TCO)이 줄어 생산 환경 적용이 가속화될 수 있다. 또한 '조정 가능한 추론 강도'는 추론 비용 관리가 전략적 레버가 되는 흐름을 보여준다. 최근 마이크로소프트 CEO 사티아 나델라가 "토큰맥싱(tokenmaxxing)"의 비용 부담을 언급하며 "프런티어 문제가 아니면 프런티어 모델을 쓰지 말라"고 한 발언과 맞닿아 있는 대목으로, 업계 전반이 '모델 크기·비용에 맞는 최적 배치' 전략으로 옮겨가고 있음을 시사한다. 원문: https://www.anthropic.com/claude-haiku-5-5
AI가 코드를 쓰기 시작하자, 제품을 만드는 사람의 일이 바뀌었다 얼마 전 「 개발자는 안 뽑습니다 」라는 글을 읽었다. 제목만 보면 개발자의 시대가 끝난다는 이야기처럼 보이지만, 글의 핵심은 조금 다르다. 개발자가 필요 없어지는 것이 아니라, 제품을 만드는 사람에게 요구되는 능력이 달라지고 있다는 이야기다. 과거에는 아이디어를 실제 제품으로 만드는 일이 쉽지 않았다. 문제를 발견한 사람이 기획서를 작성하면 디자이너가 화면을 만들고, 개발자가 코드를 작성하고, 다시 QA를 거쳐 제품을 출시했다. 아이디어와 실제 제품 사이에는 많은 사람이 필요했고, 상당한 시간이 필요했다. 그 과정에서 가장 희소한 능력 중 하나는 ‘구현할 수 있는 능력’이었다. 그런데 AI가 이 구조를 빠르게 바꾸고 있다. 이제는 기획자나 디자이너, 창업자처럼 직접 개발을 하지 않던 사람도 AI를 이용하면 실제 작동하는 제품을 만들 수 있다. 완벽한 제품은 아니더라도 아이디어를 화면으로 만들고, 데이터를 연결하고, 사용자에게 보여주고, 반응을 확인하는 것까지 가능해졌다. 그래서 제품 개발의 흐름도 조금씩 달라지고 있다. 예전에는 아이디어 → 기획서 → 디자인 → 개발 → 테스트 → 출시 였다면, 앞으로는 문제 발견 → 프로토타입 → 사용자 반응 → 수정 이라는 훨씬 짧은 반복이 가능해진다. 중요한 변화는 개발 속도만 빨라지는 것이 아니다. 제품을 만드는 사람의 역할 자체가 바뀐다는 점이다. 구현 능력보다 중요한 것이 생기기 시작했다 AI 이전에는 “어떻게 만들 것인가”가 중요한 문제였다. 서비스를 만들고 싶어도 개발할 사람이 없으면 시작하기 어려웠다. 하지만 AI가 구현 비용을 빠르게 낮추면서 질문이 달라지고 있다. 무엇을 만들 것인가. 왜 만들어야 하는가. 누구의 어떤 문제를 해결할 것인가. 어떤 기능을 만들지 않을 것인가. 그리고 실제로 만든 것이 효과가 있었는가. 이런 질문의 중요성이 훨씬 커진다. 코딩이 중요하지 않아지는 것이 아니다. 코딩이라는 생산 수단에 접근하기 위해 필요했던 진입장벽이 낮아지고 있는 것이다. 이 차이는 꽤 크다. 과거에는 아이디어가 있어도 구현 능력이 없으면 제품을 만들기 어려웠지만, 이제는 아이디어와 판단력이 있는 사람이 AI의 도움을 받아 직접 실험할 수 있다. 그렇다면 자연스럽게 희소성도 이동한다. ‘만드는 방법을 아는 사람’에서 ‘무엇을 만들어야 하는지 아는 사람’으로. AI Builder라는 새로운 형태의 사람 최근 이런 사람을 ‘AI Builder’라고 부르기 시작한다. AI Builder를 단순히 AI로 코딩하는 사람이라고 생각하면 조금 부족하다. 중요한 것은 AI 도구를 얼마나 많이 사용할 줄 아느냐가 아니다. 현실의 문제를 발견하고, 그것을 제품으로 바꾸고, 실제 사용자에게 전달하고, 결과를 확인할 때까지 전체 과정을 움직일 수 있는 사람이 AI Builder에 가깝다. 그래서 출신 직군도 크게 중요하지 않다. 개발자일 수도 있고, 기획자일 수도 있고, 디자이너일 수도 있고, 마케터나 창업자일 수도 있다. 중요한 것은 자신의 전문 영역을 넘어 제품 전체를 바라볼 수 있는가다. 문제를 발견하고, 가설을 세우고, AI를 이용해 빠르게 구현하고, 사용자에게 보여주고, 결과를 측정하고, 다시 수정한다. 이 과정 전체를 반복할 수 있는 사람이 점점 강해질 것이다. 오히려 ‘현장 경험’의 가치가 커진다 AI 시대에 역설적으로 더 중요해지는 것이 있다. 바로 도메인 지식과 현장 경험이다. AI는 많은 것을 알고 있다. 코드도 작성하고, 화면도 만들고, 문서도 정리한다. 하지만 어떤 문제가 정말 중요한지는 여전히 현실 속에 있다. 고객이 어디에서 불편함을 느끼는지, 어떤 절차 때문에 포기하는지, 사람들이 말로 표현하지 않는 불만은 무엇인지, 업계에서 당연하게 받아들이지만 사실은 비효율적인 것이 무엇인지. 이런 것은 현장에 있는 사람이 훨씬 잘 알 수 있다. 그래서 AI가 강해질수록 인간의 전문성이 필요 없어지는 것이 아니라 전문성의 종류가 달라질 가능성이 높다. 과거에는 특정 도구를 다루는 전문성이 중요했다면, 앞으로는 문제와 사람을 이해하는 전문성이 더 중요해질 수 있다. 무엇을 만들지보다 무엇을 만들지 않는지가 중요해진다 또 하나의 변화가 있다. AI를 이용하면 기능을 만드는 것이 너무 쉬워진다. 몇 년 전이라면 개발 비용 때문에 포기했을 기능도 이제는 며칠, 경우에 따라 몇 시간 안에 프로토타입으로 만들 수 있다. 그런데 이건 좋은 일만은 아니다. 쉽게 만들 수 있다는 것은 쉽게 불필요한 것도 만들 수 있다는 뜻이기 때문이다. 기능을 하나 더 추가하는 비용이 낮아질수록 제품은 오히려 복잡해질 위험이 있다. 그래서 앞으로 좋은 제품을 만드는 사람에게 중요한 능력 중 하나는 ‘만들지 않는 능력’이 될 것이다. 이 기능이 정말 필요한가. 이 문제가 실제로 존재하는가. 사용자가 원하는 것인가, 아니면 우리가 만들고 싶은 것인가. 지금 만들어야 하는가. 이 질문에 계속 답해야 한다. AI 시대에는 제작 능력보다 선택 능력이 더 중요해질 수 있다. Build보다 Measure가 중요해진다 제품을 만드는 비용이 내려가면 자연스럽게 병목도 이동한다. 과거에는 ‘만드는 것’이 병목이었다. 앞으로는 ‘무엇이 효과가 있었는지 알아내는 것’이 병목이 될 가능성이 크다. 제품을 출시했다고 끝나는 것이 아니다. 사람들이 실제로 사용하는가. 처음 방문한 사람이 가입하는가. 가입한 사람이 계속 사용하는가. 어디에서 이탈하는가. 어떤 기능은 사용하지 않는가. 우리가 해결했다고 생각했던 문제가 정말 해결됐는가. 이 데이터를 보고 다시 제품을 바꿔야 한다. 그래서 앞으로의 제품 개발 과정은 단순한 Think → Build → Deploy 가 아니라, Think → Build → Deploy → Measure → Learn → Build 이라는 반복에 가까워질 것이다. AI가 Build를 빠르게 해줄수록 Measure와 Learn의 중요성은 더욱 커진다. AI가 모든 전문가를 대체하는 것은 아니다 여기에는 반드시 주의해야 할 부분도 있다. AI가 만들어낸 제품이 화면에서 정상적으로 작동한다고 해서 좋은 제품인 것은 아니다. 보안, 개인정보, 데이터베이스 구조, 결제, 권한 관리, 대규모 트래픽, 장애 대응, 법률과 규제 같은 문제는 여전히 높은 전문성이 필요하다. AI Builder가 모든 것을 혼자 해야 한다는 의미도 아니다. 오히려 좋은 Builder에게 중요한 능력은 자신이 어디까지 판단할 수 있고 어디부터 전문가가 필요한지를 구분하는 것이다. AI는 전문가를 없애기보다는 전문가가 개입하는 지점을 바꿀 가능성이 크다. 반복적인 구현은 AI가 맡고, 복잡한 판단과 높은 위험이 존재하는 영역에는 더 높은 수준의 전문가가 집중하는 식이다. 결국 회사의 최소 단위도 달라질 수 있다 이 변화가 계속된다면 단순히 개인의 업무 방식만 달라지는 것이 아닐 수 있다. 회사의 형태도 달라질 것이다. 과거에는 하나의 인터넷 서비스를 만들기 위해 기획자, 디자이너, 프론트엔드 개발자, 백엔드 개발자, QA, 데이터 분석가 등 여러 역할이 필요했다. 앞으로는 한 사람이 AI를 통해 이 능력들의 상당 부분을 호출할 수 있다. 그렇다고 여덟 명이 필요했던 회사가 무조건 한 명의 회사가 된다는 뜻은 아니다. 좀 더 정확히 말하면, 한 사람이 여덟 가지 능력에 접근할 수 있게 된다는 것이다. 그리고 필요할 때 전문가와 협업한다. 조직에서 중요한 것은 사람 수가 아니라 판단과 실행의 밀도가 된다. 앞으로 경쟁력이 되는 것은 무엇일까 AI가 더 발전한다고 가정하면 제품을 만드는 사람에게 필요한 능력은 대략 다섯 가지로 정리할 수 있을 것 같다. 첫 번째는 문제를 발견하는 능력이다. 두 번째는 무엇을 만들고 무엇을 만들지 않을지 결정하는 제품 판단력이다. 세 번째는 AI를 단순히 사용하는 것이 아니라 여러 작업을 연결하고 검증하는 능력이다. 네 번째는 특정 분야에 대한 깊은 현장 지식이다. 마지막은 결과에 대한 책임이다. 기능을 만들었다는 것으로 끝나는 것이 아니라 그것이 실제로 사람들의 행동을 바꾸고 문제를 해결했는지 확인하는 것이다. 결국 앞으로 제품을 만드는 사람의 경쟁력은 얼마나 많은 코드를 작성했느냐보다, 얼마나 정확하게 문제를 발견하고, 얼마나 빠르게 실험하고, 얼마나 제대로 결과를 측정하며, 얼마나 집요하게 개선할 수 있는가에 가까워질 것이다. AI가 강해질수록 인간의 판단력이 중요해진다 AI 시대를 이야기할 때 우리는 자꾸 AI가 무엇을 할 수 있는지를 이야기한다. 코드를 작성한다. 디자인을 만든다. 문서를 작성한다. 데이터를 분석한다. 하지만 어쩌면 더 중요한 질문은 반대편에 있을지도 모른다. AI가 많은 일을 할 수 있게 되었을 때 인간은 무엇을 해야 하는가. 나는 그 답이 ‘판단’에 가까워지고 있다고 생각한다. 어떤 문제를 해결할 것인지. 누구를 위해 만들 것인지. 무엇을 중요하게 생각할 것인지. 무엇을 하지 않을 것인지. 그리고 결과에 책임질 것인지. AI가 구현 비용을 낮출수록 이런 질문들의 가치는 오히려 올라간다. 그래서 앞으로 좋은 제품을 만드는 사람은 AI보다 더 많은 것을 아는 사람이 아닐지도 모른다. AI에게 무엇을 맡기고, 자신은 어떤 판단을 해야 하는지를 아는 사람. 그리고 현실의 문제를 끝까지 바라보는 사람. 그런 사람이 앞으로의 Builder가 아닐까.
🧩 GoF 디자인 패턴 정리 정보처리기사 실기에서 자주 출제되는 GoF 디자인 패턴 을 문제 중심으로 정리한다. GoF 디자인 패턴은 목적에 따라 크게 다음 세 종류로 구분한다. 생성 패턴(Creational) 구조 패턴(Structural) 행위 패턴(Behavioral) 📌 연습 문제 1. 생성 패턴 구분 다음 설명에 해당하는 생성 패턴을 순서대로 쓰시오. ᄀ. 서로 어울리는 버튼, 창, 메뉴 같은 제품군을 구체 클래스 없이 한 세트로 만든다. ᄂ. 같은 조립 절차를 사용해 서로 다른 형태의 복잡한 결과물을 만든다. ᄃ. 이미 존재하는 원형 객체를 복제해 새 객체를 얻는다. ᄅ. 클래스의 인스턴스를 하나만 만들고 여러 사용자가 같은 인스턴스에 접근한다. 풀이 ᄀ. 관련 객체들을 한 세트로 생성 서로 관련되거나 의존적인 객체들을 구체적인 클래스를 직접 지정하지 않고 제품군 단위로 생성 한다. 관련 객체 제품군 버튼 + 창 + 메뉴 한 세트로 생성 → Abstract Factory ᄂ. 조립 과정을 이용해 복잡한 객체 생성 같은 생성 절차를 사용하면서 최종 결과물은 다르게 만들 수 있다. 복잡한 객체 단계별 조립 같은 과정 → 다른 결과 → Builder ᄃ. 기존 객체 복제 새로운 객체를 처음부터 만드는 대신 기존 객체를 복사하여 생성한다. 원형 객체 복제 Clone → Prototype ᄅ. 인스턴스를 하나만 생성 프로그램 전체에서 객체를 하나만 생성하고 같은 객체를 공유한다. 인스턴스 1개 공유 전역 접근 → Singleton ✅ 답 ᄀ : Abstract Factory ᄂ : Builder ᄃ : Prototype ᄅ : Singleton 2. Adapter · Bridge 다음 두 상황에 해당하는 구조 패턴을 순서대로 쓰시오. ᄀ. 이미 만들어진 결제 모듈의 인터페이스가 새 서비스의 규격과 맞지 않아 중간 변환 객체를 끼웠다. ᄂ. 리모컨 종류와 가전제품 종류가 앞으로 각각 늘어날 수 있어 두 계층을 분리하고 연결 객체를 뒀다. 풀이 ᄀ. 인터페이스 변환 기존 클래스 자체를 수정하지 않고 중간 객체를 이용하여 원하는 인터페이스로 변환한다. 기존 인터페이스 ↓ 변환 ↓ 새 인터페이스 → Adapter ᄂ. 추상화와 구현 분리 기능을 담당하는 계층과 실제 구현을 담당하는 계층을 분리하여 각각 독립적으로 확장할 수 있게 한다. 추상화 계층 ↔ 구현 계층 서로 독립적으로 확장 → Bridge ✅ 답 ᄀ : Adapter ᄂ : Bridge 3. Proxy · Decorator · Facade 다음 역할에 해당하는 패턴을 순서대로 쓰시오. ᄀ. 실제 객체 앞에서 권한을 검사하고 필요할 때만 실제 객체를 만든다. ᄂ. 기존 인터페이스를 유지하면서 감싼 객체에 기능을 겹쳐 더한다. ᄃ. 복잡한 여러 하위 시스템을 단순한 하나의 진입 창구로 감춘다. 풀이 ᄀ. 실제 객체 대신 대리 객체 사용 클라이언트가 실제 객체에 직접 접근하지 않고 대리 객체를 거치게 한다. 접근 제어 권한 검사 지연 생성 대리 객체 → Proxy ᄂ. 객체를 감싸 기능 추가 기존 객체의 인터페이스는 유지하면서 객체를 감싸 새로운 기능을 추가한다. 기존 객체 ↓ Decorator로 감싸기 ↓ 기능 추가 → Decorator ᄃ. 복잡한 시스템에 단순한 창구 제공 여러 개의 복잡한 하위 시스템을 직접 호출하는 대신 하나의 단순한 인터페이스를 제공한다. 복잡한 여러 시스템 ↓ 하나의 단순한 창구 → Facade ✅ 답 ᄀ : Proxy ᄂ : Decorator ᄃ : Facade 4. Observer · Mediator 한 뉴스 채널의 새 소식이 등록된 구독자 모두에게 자동 전송되는 방식과, 여러 항공기의 요청을 관제탑 하나가 받아 충돌 없이 조정하는 방식에 해당하는 패턴을 순서대로 쓰시오. 풀이 뉴스 채널과 구독자 한 객체의 상태가 변경되면 해당 객체를 구독하고 있는 여러 객체에 자동으로 알린다. Publisher ↓ Observer 1 Observer 2 Observer 3 상태 변화 구독자에게 자동 알림 1 : N → Observer 항공기와 관제탑 객체들이 서로 직접 통신하지 않고 중간의 중재 객체를 통해 통신한다. 항공기 A ─┐ 항공기 B ─┼→ 관제탑 → 조정 항공기 C ─┘ 중앙 중재자 객체 간 직접 통신 감소 → Mediator ✅ 답 Observer, Mediator 5. Strategy · State 내비게이션 사용자가 최소 거리와 최단 시간 계산법 가운데 하나를 선택하는 경우와, 주문 객체가 결제 대기, 결제 완료, 취소라는 내부 상태에 따라 같은 요청에 다르게 반응하는 경우의 패턴을 순서대로 쓰시오. 풀이 알고리즘을 선택 여러 알고리즘을 각각 객체로 만들어 필요에 따라 교체한다. 최단 거리 알고리즘 최단 시간 알고리즘 사용자가 선택 → Strategy 객체 상태에 따라 행동 변화 같은 객체라도 내부 상태가 달라지면 행동이 달라진다. 결제 대기 결제 완료 취소 상태에 따라 행동 변경 → State ✅ 답 Strategy, State 6. 행위 패턴 구분 다음 설명에 해당하는 행위 패턴을 순서대로 쓰시오. ᄀ. 요청을 객체로 만들어 저장, 대기열 처리, 취소를 가능하게 한다. ᄂ. 요청을 처리할 객체를 만날 때까지 처리자 사슬을 따라 넘긴다. ᄃ. 컬렉션 내부 표현을 노출하지 않고 원소에 차례로 접근한다. ᄅ. 객체 구조를 바꾸지 않고 원소에 적용할 새 연산을 별도 객체로 추가한다. ᄆ. 상위 클래스가 알고리즘 골격을 정하고 하위 클래스가 일부 단계를 재정의한다. 풀이 ᄀ. 요청을 객체로 캡슐화 실행할 요청 자체를 하나의 객체로 만든다. 요청 객체화 저장 Queue Undo → Command ᄂ. 처리자에게 계속 전달 현재 객체가 처리할 수 없으면 다음 처리자에게 요청을 넘긴다. 요청 ↓ 처리자 A ↓ 처리자 B ↓ 처리자 C → Chain of Responsibility ᄃ. 컬렉션 순회 컬렉션의 내부 구조를 직접 노출하지 않고 요소를 하나씩 접근한다. hasNext() next() → Iterator ᄅ. 객체 구조는 그대로 두고 연산 추가 기존 객체 구조를 수정하지 않으면서 새로운 연산을 추가한다. 객체 구조 유지 새로운 연산 추가 각 객체 방문 → Visitor ᄆ. 알고리즘의 전체 틀 제공 상위 클래스에서 알고리즘의 전체 흐름을 정의하고 세부 단계만 하위 클래스에서 구현한다. 전체 흐름 → 부모 클래스 일부 단계 → 자식 클래스 → Template Method ✅ 답 ᄀ : Command ᄂ : Chain of Responsibility ᄃ : Iterator ᄅ : Visitor ᄆ : Template Method 📚 2020~2026년 관련 기출문제 📌 2020년 2회 10번 다음 보기가 설명하는 패턴을 쓰시오. 영문 Full-Name으로 작성하시오. 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들에게 연락이 가고 자동으로 내용이 갱신되는 방법으로 일대 다의 의존성을 가지며 상호작용하는 객체 사이에서는 가능하면 느슨하게 결합하는 디자인을 사용해야 한다. 풀이 핵심 키워드는 한 객체의 상태 변화 다른 객체들에게 자동 전달 1 : N 느슨한 결합 이다. 이는 Observer Pattern 의 특징이다. ✅ 답 Observer Pattern 📌 2020년 4회 2번 목적에 따른 디자인 패턴의 유형에는 생성, 구조, ( ) 이/가 있다. 괄호 ( ) 안에 알맞은 유형을 쓰시오. 풀이 GoF 디자인 패턴은 목적에 따라 세 가지로 분류한다. 생성 패턴 구조 패턴 행위 패턴 ✅ 답 행위 📌 2021년 2회 13번 괄호 ( ) 안에 알맞은 단어를 쓰시오. 디자인 패턴 중에서 ( ) 패턴은 반복적으로 사용되는 객체들의 상호작용을 패턴화한 것으로, 클래스나 객체들이 상호작용하는 방법이다. 알고리즘의 패턴에는 Interpreter, Observer, Command가 있다. 풀이 문제에서 객체들의 상호작용 책임 분배 Observer Command Interpreter 가 등장한다. 이들은 모두 행위 패턴 에 속한다. ✅ 답 행위(Behavioral) 📌 2021년 3회 16번 다음 설명에 해당하는 디자인 패턴을 쓰시오. ( ) 패턴은 객체지향 디자인 패턴이다. 부모(상위) 클래스에 알려지지 않은 구체 클래스를 생성하는 패턴이며, 자식(하위) 클래스가 어떤 객체를 생성할지를 결정하도록 하는 패턴이기도 하다. 부모(상위) 클래스 코드에 구체 클래스 이름을 감추기 위한 방법으로도 사용한다. 풀이 객체 생성 자체는 상위 클래스에서 정의하지만 어떤 객체를 만들 것인가? 는 하위 클래스에서 결정한다. 객체 생성 ↓ 하위 클래스가 결정 → Factory Method ✅ 답 Factory Method 📌 2022년 3회 3번 다음은 디자인 패턴에 대한 설명이다. 괄호 안에 알맞은 답을 작성하시오. (1)은/는 기능을 처리하는 추상화 계층과 실제 구현을 담당하는 구현 계층을 분리하여, 두 계층이 독립적으로 변경될 수 있도록 하는 패턴이다. 구현뿐 아니라 추상화도 독립적인 확장이 필요할 때 사용한다. 기능 계층과 구현 계층을 연결하는 다리 역할을 하며, 기능 확장과 구현 변경을 서로 분리할 수 있다. (2)은/는 한 객체의 상태가 변화하면 그 객체에 의존하는 다른 객체들에게 변화된 상태를 전달해주는 패턴이다. 일대다 관계를 가지며, 주로 분산된 시스템 간에 이벤트를 생성, 발행(Publish)하고 이를 수신(Subscribe)해야 할 때 이용한다. 풀이 1 추상화와 구현 분리 추상화 계층 ↕ 구현 계층 독립적 확장 → Bridge 2 상태 변화 자동 전달 상태 변화 Publish / Subscribe 1 : N → Observer ✅ 답 (1) Bridge (2) Observer Pattern 📌 2023년 1회 11번 다음 설명에 해당하는 디자인 패턴을 쓰시오. 실제 객체를 직접 참조하는 대신 대리 객체를 앞에 둔다. 대리 객체는 접근 제어, 지연 생성, 로깅 같은 부가 작업을 처리한 뒤 실제 객체에 요청을 전달한다. 풀이 핵심 키워드는 대리 객체 접근 제어 지연 생성 로깅 이다. 이는 Proxy 패턴 이다. ✅ 답 Proxy 📌 2023년 2회 11번 디자인 패턴 설명을 읽고 1과 2에 들어갈 패턴을 쓰시오. 1 클래스의 인스턴스를 하나만 만들고 어디서든 그 인스턴스에 접근하게 한다. 2 객체 구조의 원소를 바꾸지 않고 새로운 연산을 추가하며, 각 원소를 방문해 작업을 수행한다. 풀이 1 인스턴스 하나 객체 1개 공유 전역 접근 → Singleton 2 구조를 바꾸지 않고 연산 추가 객체 구조 유지 새로운 연산 추가 원소 방문 → Visitor ✅ 답 1 Singleton 2 Visitor 📌 2024년 1회 20번 다음 설명에 해당하는 GoF 디자인 패턴을 쓰시오. 구체적인 클래스를 지정하지 않고 서로 관련되거나 의존적인 객체들의 제품군을 생성하는 인터페이스를 제공한다. 제품군 전체를 일관되게 교체해야 할 때 사용한다. 풀이 핵심은 구체 클래스 지정 X 관련 객체 제품군 제품군 전체 생성 이다. 이는 Abstract Factory 이다. ✅ 답 Abstract Factory 📌 2024년 2회 10번 다음 설명에 해당하는 GoF 디자인 패턴을 쓰시오. 컬렉션의 내부 표현을 노출하지 않고 원소를 차례대로 접근할 수 있게 한다. hasNext와 next 같은 동작으로 순회 책임을 별도 객체에 맡긴다. 풀이 컬렉션 순차 접근 hasNext() next() 가 핵심이다. 이는 Iterator 패턴 이다. ✅ 답 Iterator 📌 2024년 3회 6번 괄호에 공통으로 들어갈 GoF 디자인 패턴 분류를 쓰시오. ( ) 패턴은 객체들이 상호작용하는 방법과 책임 분배를 정의한다. 객체 사이의 통신 방법을 다루고 알고리즘을 캡슐화해 결합도를 낮춘다. Chain of Responsibility, Command, Observer가 여기에 속한다. 풀이 Chain of Responsibility Command Observer 는 모두 행위 패턴 이다. ✅ 답 행위 📌 2025년 1회 14번 다음 설명에 해당하는 디자인 패턴을 쓰시오. 호환되지 않는 인터페이스를 가진 기존 객체를 감싸 클라이언트가 원하는 인터페이스로 바꿔 준다. 기존 클래스의 내부 코드는 수정하지 않는다. 풀이 기존 객체 수정 X 호환되지 않는 인터페이스 원하는 인터페이스로 변환 따라서 Adapter 이다. ✅ 답 Adapter 📌 2025년 2회 7번 다음 설명에 해당하는 디자인 패턴을 쓰시오. 실제 객체를 바로 사용하지 않는다. 그 객체를 대신하는 대리 객체가 접근을 제어하고 부가 기능도 맡는다. 실제 객체의 생성을 늦추거나 접근 권한을 확인할 때 쓴다. 풀이 대리 객체 접근 권한 지연 생성 이 나오면 Proxy 이다. ✅ 답 Proxy 📌 2026년 1회 2번 다음 설명에 해당하는 디자인 패턴을 각각 쓰시오. 1 기능의 클래스 계층과 구현의 클래스 계층을 분리하고, 두 계층을 연결하여 서로 독립적으로 확장할 수 있게 한다. 2 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들에게 상태 변화를 자동으로 알린다. 풀이 1 기능과 구현 분리 추상화 ↔ 구현 독립적 확장 → Bridge 2 상태 변화 자동 알림 한 객체의 상태 변화 ↓ 여러 객체에 알림 → Observer ✅ 답 1 Bridge 2 Observer 📌 2026년 2회 17번 다음 설명에 해당하는 디자인 패턴을 보기에서 골라 쓰시오. 구체적인 클래스를 명시하지 않고 서로 관련되거나 의존적인 객체들의 집합을 생성하기 위한 인터페이스를 제공한다. Kit 라고도 한다. ᄀ. Builder ᄂ. Factory Method ᄃ. Abstract Factory ᄅ. Prototype 풀이 관련 객체들의 집합 제품군 구체 클래스 명시 X Kit 이 나오면 Abstract Factory 이다. ✅ 답 ᄃ. Abstract Factory 📌 GoF 디자인 패턴 분류 GoF 디자인 패턴은 총 23개 이며 크게 세 종류로 나눈다. 분류 목적 생성 패턴 객체를 어떻게 생성할 것인가 구조 패턴 객체와 클래스를 어떻게 구성할 것인가 행위 패턴 객체들이 어떻게 동작하고 협력할 것인가 🏗️ 생성 패턴 객체의 생성 방식 과 관련된 패턴이다. 패턴 핵심 키워드 Abstract Factory 관련 객체 제품군 생성 Builder 단계별 조립 Factory Method 객체 생성을 하위 클래스가 결정 Prototype 기존 객체 복제 Singleton 인스턴스 하나만 생성 생성 = 객체를 어떻게 만들까? 🧱 구조 패턴 클래스나 객체를 어떻게 조합하고 연결할 것인가 와 관련된다. 패턴 핵심 키워드 Adapter 인터페이스 변환 Bridge 추상화와 구현 분리 Composite 부분과 전체를 동일하게 처리 Decorator 객체를 감싸 기능 추가 Facade 복잡한 시스템의 단순 창구 Flyweight 객체 공유로 메모리 절약 Proxy 대리 객체 🎮 행위 패턴 객체 간의 책임 분배와 상호작용 을 다룬다. 패턴 핵심 키워드 Chain of Responsibility 처리자 사슬 Command 요청 객체화 Interpreter 문법 해석 Iterator 컬렉션 순회 Mediator 중재자 Memento 상태 저장·복원 Observer 상태 변화 자동 알림 State 상태에 따라 행동 변경 Strategy 알고리즘 선택·교체 Template Method 알고리즘 골격 정의 Visitor 구조 변경 없이 연산 추가 🧠 생성 패턴 암기 생성 패턴 5개는 추빌팩프싱 처럼 묶어서 기억할 수 있다. 추 → Abstract Factory 빌 → Builder 팩 → Factory Method 프 → Prototype 싱 → Singleton 시험에서는 이름 자체보다 키워드 연결 이 더 중요하다. 제품군 → Abstract Factory 조립 → Builder 하위 클래스 → Factory Method 복제 → Prototype 하나만 → Singleton 🧠 헷갈리기 쉬운 구조 패턴 Adapter vs Bridge Adapter 이미 존재하는 두 인터페이스가 서로 맞지 않을 때 사용한다. 기존 인터페이스 → 변환 → 원하는 인터페이스 Adapter = 변환기 Bridge 처음부터 기능과 구현을 분리해서 둘 다 독립적으로 확장한다. 추상화 ↔ 구현 Bridge = 두 계층을 연결하는 다리 Proxy vs Decorator 둘 다 객체를 감싼다 는 점 때문에 헷갈리기 쉽다. Proxy 목적은 접근 제어 이다. 권한 검사 지연 생성 접근 제어 대리 객체 Decorator 목적은 기능 추가 이다. 기존 객체 + 기능 + 기능 + 기능 따라서 Proxy = 대신 접근 Decorator = 기능 추가 라고 기억하면 된다. Facade Facade는 여러 복잡한 기능을 하나의 단순한 창구로 제공한다. 복잡한 시스템 여러 개 ↓ Facade ↓ 사용자 Facade = 안내 데스크 라고 생각하면 쉽다. 🧠 Observer vs Mediator Observer 한 객체의 변화가 여러 객체에게 자동 전파 된다. 1 → N 유튜브 채널 → 구독자 뉴스 채널 → 구독자 Mediator 여러 객체가 서로 직접 통신하지 않고 중앙 중재자 를 거친다. A ─┐ B ─┼→ Mediator C ─┘ 관제탑 채팅방 서버 중앙 조정자 🧠 Strategy vs State 둘 다 동작이 바뀐다는 점에서 헷갈릴 수 있다. Strategy 사용할 알고리즘을 선택한다. 최단 거리 최단 시간 통행료 최소 → Strategy 즉 Strategy = 어떤 방법을 사용할까? State 객체의 현재 상태 때문에 행동이 달라진다. 대기 결제 완료 취소 즉 State = 지금 상태가 무엇인가? 🧠 행위 패턴 핵심 키워드 시험에서는 설명 속 단어를 보고 바로 패턴을 떠올리는 것이 중요하다. 요청 객체화 저장 / 취소 / Queue → Command 처리할 때까지 다음 객체로 전달 → Chain of Responsibility hasNext / next 컬렉션 순회 → Iterator 중앙에서 객체들을 조정 → Mediator 상태 변화 자동 알림 1 : N Publish / Subscribe → Observer 상태에 따라 행동 변경 → State 알고리즘 선택 / 교체 → Strategy 알고리즘 골격은 부모 세부 단계는 자식 → Template Method 객체 구조 변경 X 새로운 연산 추가 → Visitor 🔥 시험 직전 최종 암기 생성 Abstract Factory → 관련 객체 제품군 Builder → 단계별 조립 Factory Method → 하위 클래스가 생성 결정 Prototype → 복제 Singleton → 인스턴스 하나 구조 Adapter → 인터페이스 변환 Bridge → 추상화 / 구현 분리 Decorator → 기능 추가 Facade → 단순한 통합 창구 Proxy → 대리 객체 / 접근 제어 행위 Observer → 상태 변화 자동 알림 Mediator → 중앙 중재자 Strategy → 알고리즘 선택 State → 상태에 따라 행동 변경 Command → 요청 객체화 Chain of Responsibility → 처리자 사슬 Iterator → 순차 접근 Visitor → 구조 변경 없이 연산 추가 Template Method → 부모가 골격, 자식이 세부 구현 🔥 한 줄로 기억하기 객체를 만든다 → 생성 패턴 객체를 연결하고 조립한다 → 구조 패턴 객체가 서로 행동하고 협력한다 → 행위 패턴
지난 글에서는 플레이어가 무엇을 반복해서 하는지 알아보기 위해 행동의 횟수보다 행동 사이의 관계를 기록하기 시작했다 는 이야기를 했다. 공격한 뒤 물체를 던지는지. 던진 뒤 다른 물체를 집는지. 대시한 뒤 다시 공격을 이어가는지. 이런 반복되는 관계를 어느 정도 구분할 수 있게 되면서 다음 문제가 생겼다. 그럼 이 습관을 실제 게임의 능력으로 어떻게 바꿀까? 분석 결과를 보여주는 것만으로는 게임이 달라지지 않는다. 플레이어가 계속 비슷한 방식으로 싸우고 있다면, 그 행동 자체가 새로운 전투 규칙으로 돌아오게 만들고 싶었다. 처음에는 이 부분도 생각보다 단순하게 해결할 수 있을 것 같았다. 처음에는 패턴 하나에 스킬 하나를 만들었다 예를 들어 이런 플레이어가 있다고 해보자. 물체를 던진다 ↓ 다른 물체를 집는다 ↓ 다시 근접 공격한다 이 행동을 반복한다면 그 흐름을 그대로 이용하는 능력을 만들 수 있다. 실제로 처음 만든 능력도 비슷했다. 물체를 던져 적에게 충격을 준 뒤 잠시 그 충격을 기억한다. 그다음 새로운 물체를 집거나 받아내면 기억해둔 충격을 그 물체에 연결한다. 그리고 그 물체로 다음 근접 공격을 성공시키면 이전 투척의 힘 일부가 같이 전달된다. 투척 적중 ↓ 충격을 기억 ↓ 새로운 물체 획득 ↓ 다음 근접 공격 강화 처음 이게 실제로 동작했을 때는 꽤 만족스러웠다. 단순히 투척을 많이 했다 → 투척 공격력 +20% 가 아니라, 플레이어가 원래 하던 행동은 그대로 남아 있으면서 그 행동 사이에 새로운 연결 하나가 생겼기 때문 이다. 다른 방식도 만들어봤다. 한 적을 때린 뒤 별개의 공격으로 다른 적을 때리면, 두 적의 위치 관계를 기억해서 둘 사이에 새로운 효과가 생기게 했다. 적 A 공격 ↓ 적 B 공격 ↓ 두 위치 사이에 효과 발생 여기까지는 꽤 괜찮았다. 그런데 세 번째, 네 번째 패턴을 생각하기 시작하면서 이상한 점이 보였다. AI 게임을 만들고 있는데, 내가 모든 답을 만들고 있었다 플레이어가 공격 후 투척을 자주 한다면 그에 맞는 스킬을 만든다. 대시 후 공격을 자주 한다면 또 다른 스킬을 만든다. 여러 적 사이를 오가며 싸운다면 또 하나를 만든다. 몇 개 정도는 충분히 할 수 있다. 문제는 계속 늘어날 때다. 행동이 늘고, 물체가 늘고, 대상이 늘고, 시간 조건이 늘고, 공간 관계까지 들어오기 시작하면 가능한 조합도 빠르게 많아진다. 그리고 그때마다 내가 “이 패턴에는 이 스킬.” 이라고 완성된 답을 하나씩 추가하고 있었다. 생각해보니 조금 이상했다. AI가 플레이어를 읽고 새로운 능력을 만들어주는 게임을 만들겠다고 시작했는데, 정작 가능한 플레이 스타일과 그 결과는 내가 전부 미리 만들고 있었다. 이 구조라면 나중에 AI가 들어오더라도 결국 내가 만들어둔 답안 중 하나를 고르는 역할밖에 하지 못한다. 그래서 완성된 스킬을 계속 추가하는 대신, 스킬 자체를 표현할 수 있는 작은 언어를 만들어보기로 했다. 스킬 대신 ‘스킬을 만드는 문법’을 만든다 하나의 능력을 잘게 나눠보면 생각보다 몇 가지 질문으로 정리할 수 있었다. 무슨 행동에서 시작되는가? ↓ 무엇을 기억하는가? ↓ 무엇과 연결하는가? ↓ 어디에 적용하는가? ↓ 어떤 효과가 생기는가? 예를 들어, “물체를 던져 맞힌 충격을 기억했다가 다음에 집은 물체의 공격으로 전달한다” 라는 능력도 이렇게 쪼개볼 수 있다. 투척 적중 ↓ 이전 충격 기억 ↓ 다음 물체와 연결 ↓ 다음 성공 공격까지 유지 ↓ 기억한 힘을 전달 다른 능력은 같은 재료를 전혀 다르게 사용할 수 있다. 대시 ↓ 대시 시작 위치 기억 ↓ 다음 근접 공격 위치와 연결 ↓ 두 위치 사이 ↓ 새로운 효과 발생 또는 적 A 공격 ↓ 적 B 공격 ↓ 다시 적 A 공격 ↓ 기억한 적 B의 위치 ↓ 효과 발생 각각만 보면 전혀 다른 스킬처럼 보인다. 하지만 내부적으로는 행동을 감지하고, 무언가를 기억하고, 다른 대상이나 위치와 연결하고, 그 결과를 새로운 효과로 바꾼다 는 비슷한 언어로 표현할 수 있다. 내가 원했던 건 바로 이쪽이었다. 완성된 스킬을 계속 만드는 대신, 여러 스킬을 표현할 수 있는 언어를 만드는 것. 그리고 언젠가 AI가 스킬을 만든다면, 아무것도 없는 곳에서 게임 규칙을 마음대로 발명하는 게 아니라 이 언어 안에서 의미 있는 조합을 찾게 하고 싶었다. 그렇다고 AI에게 모든 걸 자유롭게 만들게 할 수는 없었다 처음부터 LLM에게 이렇게 요청할 수도 있다. “이 플레이어에게 어울리는 재미있는 스킬 하나 만들어줘.” 아마 그럴듯한 아이디어는 꽤 잘 나올 것이다. 하지만 아이디어와 실제 게임 규칙은 다르다. 모델이 존재하지 않는 기능을 사용할 수도 있다. 앞에서 기억하지 않은 대상을 뒤에서 참조할 수도 있다. 서로 연결할 수 없는 두 효과를 붙일 수도 있다. A가 B를 부르고, B가 다시 A를 불러서 효과가 끝없이 반복될 수도 있다. 무언가를 기억하게 해놓고 언제 그 기억을 지워야 하는지 정의하지 않을 수도 있다. 게임에서는 이런 문제가 단순한 문장 오류로 끝나지 않는다. 잘못하면 실제 전투 상태가 망가지거나, 한 번의 행동에서 끝없이 효과가 발생할 수도 있다. 그래서 한 가지 경계를 만들었다. AI가 무언가를 제안할 수는 있지만, 그 제안이 곧 게임의 규칙이 되지는 않는다. 조합할 수 있다는 것과, 실행할 수 있다는 것은 달랐다 그래서 스킬 문법 뒤에 Compiler 를 두었다. 스킬 조합이 들어오면 바로 실행하지 않고 먼저 검사한다. 실제로 존재하는 기능들로 이루어져 있는지. 앞 단계에서 나온 결과를 다음 단계가 받을 수 있는지. 기억해야 하는 상태가 있다면 언제 생성되고 언제 사라지는지. 효과가 자기 자신을 다시 부르는 구조는 없는지. 한 번의 행동에서 너무 많은 효과를 만들어내지는 않는지. 그리고 마지막으로, 실제로 플레이어에게 설명할 수 있는 능력인지 까지 확인한다. 개념적으로는 이런 흐름에 가깝다. Skill 조합 ↓ 게임 규칙과 맞는가? ↓ 상태와 연결이 유효한가? ↓ 끝없이 반복되지 않는가? ↓ 실제로 실행 가능한가? ↓ 플레이어에게 설명 가능한가? ↓ 게임에 적용 이 과정을 만들면서 생각보다 중요했던 게 하나 더 있었다. 게임에서 실제로 일어나는 것과 플레이어가 읽는 설명이 서로 달라지면 안 된다는 점 이다. 예를 들어 실제 효과는 3초 동안 유지되는데 스킬 설명에는 4초라고 적혀 있다면, Adaptive System을 플레이어가 믿기 어렵다. 그래서 지금은 실제 능력과 UI 설명이 따로 존재하지 않는다. 같은 검증된 결과에서 실제 효과도 만들고, 플레이어가 읽는 설명도 만든다. 스킬 이름이나 설명 역시 LLM이 즉석에서 자유롭게 작성하도록 하지 않았다. 게임의 문체와 실제 동작을 사람이 통제할 수 있도록 미리 만들어둔 표현을 사용한다. 결국 사람이 만드는 것과 AI가 고르는 것을 나누게 됐다 여기까지 만들고 나니 AI에게 어디까지 맡기고 싶은지도 조금 명확해졌다. 사람이 해야 하는 일은 게임에서 가능한 것의 경계를 만드는 것 이다. 어떤 행동이 존재하는지. 무엇을 기억할 수 있는지. 어떤 관계가 가능한지. 어떤 효과를 실제 게임에서 지원하는지. 그리고 그 조합이 안전한지. 반대로 AI에게 기대했던 건, 그 가능한 조합들 중 지금 이 플레이어의 행동과 의미 있게 연결되는 것을 찾는 일 이었다. 즉 내가 만들고 싶었던 건 AI가 게임의 법칙을 마음대로 쓰는 구조가 아니었다. 사람이 게임의 언어를 만들고, AI는 그 언어 안에서 플레이어에게 맞는 문장을 찾는다. 이쪽에 더 가까웠다. 이제야 Local LLM을 시험할 준비가 됐다 여기까지 오고 나서야 처음 생각했던 실험을 제대로 해볼 수 있게 됐다. 플레이어가 무엇을 반복하고 있는지는 게임이 계산한다. 그 행동을 능력으로 표현할 수 있는 문법도 있다. 잘못된 조합을 막을 수 있는 Compiler도 있다. 실제 효과와 UI 설명도 같은 결과에서 나온다. 즉 모델이 실수하더라도 게임 자체가 무너지지 않도록 필요한 경계는 어느 정도 만들어졌다. 그리고 이제 남은 질문은 하나였다. 이 조합 문제를 정말 Local LLM이 규칙 기반 방식보다 더 잘 풀 수 있을까? 다음 글에서는 실제 Local LLM을 게임에 넣고, 처음에는 완성된 능력 중 하나를 고르게 해보고, 그다음에는 능력 자체를 조합하게 해보고, 마지막에는 내부적인 복잡함까지 최대한 걷어낸 뒤 다시 시험해본 이야기를 적어보려고 한다. 결과는 처음 기대했던 방향과는 꽤 달랐다.
무슨 일이 있었나 오픈AI가 2026년 10월 7일, 챗GPT의 일반 대화창(Chat 탭)에 GPT-6와 '인텔리전트 UI(Intelligent UI)'를 전격 적용했다. 플러스·프로·비즈니스·엔터프라이즈 이용자는 오늘부터, 무료·Go 이용자는 내일부터 순차 적용된다(엔터프라이즈는 관리자 설정에 따라 달라질 수 있다). 인텔리전트 UI는 챗GPT가 텍스트만 내놓던 방식에서 벗어나 질문 맥락에 맞춰 텍스트·이미지·인터랙티브 요소를 조합해 응답을 구성하는 기능이다. 예컨대 숫자 계산 질문에는 채팅창 안에서 바로 값을 조정할 수 있는 '대화형 계산기'가 나타나는 식이다. 그래프나 차트로 복잡한 개념을 설명하거나, 누를 수 있는 버튼·입력 폼 같은 상호작용 도구도 답변에 바로 포함된다. 이번에 적용되는 모델은 유료 등급엔 GPT-6 Sol, 무료·Go 등급엔 GPT-6 Luna다. 모델이 '생각'을 마치기 전부터 단계적으로 유용한 정보를 먼저 보여주는 응답 방식도 함께 도입됐다. 다만 이번 변경은 Chat 탭에만 적용되며, 업무용 'Work'나 코딩 도구 'Codex'를 구동하는 모델에는 영향이 없다. GPT-6 계열은 지난 9월 3일 아스트라(Astra)가 먼저 출시됐고, 9월 22일 Sol·Luna가 챗GPT Work·Codex·API에 추가됐다. 이번 발표는 그 연장선에서 일반 대화 인터페이스까지 GPT-6 체제로 전환을 완료했다는 의미를 갖는다. 왜 중요한가 이는 오픈AI가 챗봇을 순수 텍스트 대화창에서 '생성형 인터페이스'로 전환하려는 신호로 읽힌다. 구글의 AI 플레이그라운드, 앤스로픽의 아티팩트 기능처럼 경쟁사들도 이미 텍스트를 넘어선 상호작용형 결과물 제공 경쟁에 뛰어든 상태라, 이번 발표는 '챗봇 UI 전쟁'을 한층 가속화할 전망이다. 우려의 목소리도 있다. 매체 기즈모도는 시각 요소가 추가되면 토큰 소모가 빨라지고, 그림이나 차트 자체가 새로운 환각(hallucination) 발생 지점이 될 수 있다고 지적했다. 서치엔진저널은 차트나 비교표 형태로 제시되는 답변에서 출처 표기가 어떻게 이뤄질지 오픈AI가 명확히 밝히지 않았다는 점도 짚었다. 일반 이용자에게는 질문에 대한 답이 훨씬 시각적이고 직관적으로 바뀐다는 장점이 있지만, 기업 환경에서는 관리자 정책에 따라 접근 여부가 갈리는 만큼 당장 모든 조직이 혜택을 보긴 어렵다. 결국 이번 변화는 LLM과의 상호작용 방식 자체를 '대화'에서 '즉석 생성 인터페이스'로 넓히려는 시도로, 구글 제미나이·앤스로픽 클로드와의 사용자 경험 경쟁에도 직접적인 영향을 줄 것으로 보인다. 원문: https://openai.com/index/gpt-6-for-everyone
RSI 구간 일반적인 해석 매매 관점 0 10 극단적 과매도 투매에 가까운 상태 기술적 반등 가능성 매우 높음 10 20 강한 과매도 매도세가 매우 강함 반등 후보 구간 20 30 과매도 매도세 우위 반등 여부 관찰 30 40 약한 과매도/약세 아직 약세 성격 섣부른 매수 주의 40 50 중립 약세 매수·매도 힘의 균형 추세 확인 필요 50 중립 방향성 기준점 상승/하락 추세 판단에 중요 50 60 중립 강세 매수세가 조금씩 우위 상승 추세 초기 확인 60 70 강한 상승 모멘텀 매수세 강함 상승 추세 지속 가능성 70 80 과매수 매수세가 상당히 강함 단기 조정 가능성 80 90 강한 과매수 매우 강한 상승 과열 주의 90 100 극단적 과매수 비정상적으로 강한 상승 급락·조정 위험 크게 증가 레인보우로보틱스 차트를 보면서 앞으로의 주가방향 및 흐름을 추적해 보도록 하겠습니다. 3일간 양봉이 나오면서, 이전 영상에서 말씀드렸던, 46만원을 10월 6일 뚫고, 10월 7일 조정을 받는 모습입니다. 10월 2일 20일 이평선 위로 올라선 모습으로, 방향성이 하락에서, 상승으로 전환하는 모습으로 보여 집니다. 10월 7일 기준 RSI 51.64로 중립~강세 구간이며, 볼랜져밴드 0.72로 상단에 위치하고 있습니다. 여기서 2가지 흐름이 나올 수 있는데, 첫번째로, 하루, 이틀 조정이 나오면서 20일 이평선에서 지지 받고 올라가는 흐름입니다. 두번째로, 10월 7일 하락 분을 금일 회복하는 양봉이 나오고 바로 반등하는 흐름입니다. 두 흐름 다 반등 흐름으로, 대응 전략으로, 10월 8일 부터 20일 이평선 43,700원 평단가를 목표로 분할 매수 추천드립니다. 추가로, 20일 이평선을 이탈할 경우, 2번 지지 받았던 41만이 강한 지지선이며, 해당 흐름은 앞, 두 흐름보다 확률이 낮아 보입니다. 요약하자면, 하락 후 반등 흐름으로, 10월 8일 부터 20일 이평선 43,700원 평단가를 목표로 분할 매수 추천 매도 시점으로 피보나치 0.5 구간인 52만~53만에 매도 추천드립니다. 감사합니다. 이상 골든 엉클이었습니다!
네. 이 경우에는 처음부터 LiteLLM/자동 전환까지 한꺼번에 검증하기보다, “각 모델의 B300 최적 vLLM 설정을 찾는 Stage 1 → 실제 주/야간 모델 세트를 검증하는 Stage 2 → 전환 자동화를 검증하는 Stage 3” 순서가 좋습니다. 특히 지금 가장 먼저 알아야 하는 것은 각 모델에 대해 몇 GPU가 필요한지, TP/DP/EP를 어떻게 잡아야 하는지, HBM 중 weight와 KV에 각각 얼마를 쓰는지가 최적인지 입니다. vLLM도 single-node에서는 모델이 1 GPU에 들어가면 single GPU, 그렇지 않으면 TP를 늘리는 접근을 기본 가이드로 제시하고 있습니다. MoE에서는 EP를 별도로 실험할 가치가 있습니다. vLLM 1. 전체 테스트를 이렇게 나누겠습니다 Stage 1 모델별 단독 Characterization │ │ GPU / TP / EP / KV 최적값 탐색 ▼ Stage 2 주간/야간 Model-set 동시 구동 │ │ GPU allocation / 간섭 / capacity 검증 ▼ Stage 3 AIStor → NVMe → HBM 전환 테스트 │ │ cold/warm start 측정 ▼ Stage 4 Day ↔ Night 자동 전환 │ │ prefetch → load → warmup → switch → drain ▼ Stage 5 LiteLLM + multi-user 부하 │ ▼ Production baseline 처음부터 LiteLLM을 넣지 않는 것이 포인트입니다. Stage 1~3에서는 vLLM endpoint를 직접 때려서 GPU serving 자체를 먼저 검증 하는 편이 원인 분석이 쉽습니다. 2. Stage 1 — 모델별 단독 테스트 우선 모델 하나만 B300 node에 올립니다. 예를 들어 Qwen 계열 MoE라면 다음과 같은 matrix를 만들겠습니다. Test GPU TP DP EP 목적 Q1 1 1 1 OFF 1 GPU 수용 가능 여부 Q2 2 2 1 OFF TP baseline Q3 2 1 2 ON EP 효과 Q4 4 1 4 ON EP scaling Q5 4 2 2 ON TP+EP 조합 Q6 8 1 8 ON full-node EP 중요한 점은 최신 vLLM에서 --enable-expert-parallel 을 켠 경우 expert layer의 EP size가 TP×DP로 구성 된다는 것입니다. 예를 들어 TP=2, DP=4이면 8 GPU에서 expert layer는 EP=8이고 attention layer는 각 DP group 안에서 TP=2가 됩니다. vLLM 따라서 앞에서 이야기했던 TP/DP/EP 를 완전히 독립적인 세 숫자로 생각하기보다는 실제 사용하는 vLLM 버전의 구현에 맞춰 test matrix를 작성 해야 합니다. 3. 각 모델에서 찾고 싶은 최종 결과 모델마다 결국 아래 한 줄을 만드는 것이 목표입니다. Qwen3.x-35B-A3B GPU 2 TP 1 DP 2 EP enabled (effective EP=2) max-model-len 32K KV HBM xx GiB/GPU GPU memory xx % CPU 24 cores NUMA 0 Throughput xxxx tok/s TTFT P50/P95 xx / xx ms TPOT P50/P95 xx / xx ms Max concurrency xx NVMe→HBM load xx sec 이게 만들어지면 나중에 Kubernetes Deployment YAML을 만드는 것은 상대적으로 쉽습니다. 4. 테스트 지표는 tokens/sec만 보면 안 됩니다 LLM serving은 최소한 다음을 같이 봐야 합니다. Performance ──────────────────── Request throughput Input tokens/sec Output tokens/sec Latency ──────────────────── TTFT Time To First Token TPOT Time Per Output Token E2E latency P50 / P95 / P99 Capacity ──────────────────── Concurrent requests Queue depth KV cache usage Prefix cache hit GPU ──────────────────── GPU utilization HBM usage NVLink traffic Power PCIe traffic System ──────────────────── CPU utilization NUMA remote access RAM NVMe read throughput Network vLLM은 /metrics 에서 production metrics를 노출하므로 Prometheus로 수집하는 게 좋습니다. vLLM 그리고 online benchmark에는 vllm bench serve 를 사용할 수 있습니다. request rate, input/output length, prompt 수 등을 바꿔 serving throughput을 측정할 수 있습니다. vLLM vLLM Benchmark CLI 문서 5. Context length를 반드시 여러 개 테스트 이 workload에서는 이게 상당히 중요합니다. 제가 baseline을 잡는다면: Short input 1K output 256 Medium input 8K output 1K Long input 32K output 2K Very Long input 64K+ output 2K 정도로 나눕니다. Wizard/문서 처리에서 생성되는 context가 DeepSeek/GLM으로 넘어간다면 32K~64K 이상 workload가 실제로 나올 가능성 도 고려해야 합니다. 그리고 concurrency: 1 2 4 8 16 32 64 ... 를 올립니다. 즉 한 모델당: GPU topology × context length × concurrency matrix입니다. 6. 중요한 것은 Saturation point를 찾는 것 예를 들어 결과가: Concurrency tok/s P95 TTFT 1 150 80 ms 2 290 90 ms 4 550 110 ms 8 980 180 ms 16 1300 350 ms 32 1400 1200 ms 64 1420 4000 ms 라면 throughput만 보면 64가 가장 좋아 보입니다. 하지만 실제 서비스라면: 16 → 32 throughput +8% TTFT +243% 같은 상태일 수 있습니다. 따라서 16 정도를 serving capacity로 잡는 식입니다. 이걸 각 모델마다 찾아야 합니다. 7. MoE 모델은 EP ON/OFF를 반드시 비교 현재 목록은 MoE 모델 비중이 높으므로 중요합니다. 예를 들어 같은 8 GPU에서: Test A TP=8 EP=OFF vs Test B TP=1 DP=8 EP=ON vs Test C TP=2 DP=4 EP=ON 을 비교해볼 가치가 있습니다. vLLM은 MoE에서 EP를 지원하고, 현재는 --all2all-backend 로 여러 communication backend도 선택할 수 있습니다. EP workload는 expert token 분포가 치우칠 수 있어서 EPLB(Expert Parallel Load Balancer)도 제공합니다. vLLM 처음부터 EPLB까지 튜닝하지 말고 : EP OFF ↓ EP ON ↓ all-to-all backend 비교 ↓ 필요 시 EPLB 순서가 좋습니다. 8. Stage 2 — 실제 “주간 세트”를 동시에 올려보기 개별 모델 최적값을 찾았으면 그다음부터가 진짜 중요한 테스트입니다. 첨부하신 주간 workload를 그대로 재현합니다. DAY DeepSeek-V4.1-Flash GLM-5.3-Flash PaddleOCR-VL Docling layout Docling models Figure classifier 예를 들어 B300 node 여러 대가 있다면 실제 production 후보 배치 그대로 올립니다. GPU Node 01 ┌──────────────────────────┐ │ DeepSeek Flash │ │ GPU 0~7 │ └──────────────────────────┘ GPU Node 02 ┌──────────────────────────┐ │ GLM Flash │ │ GPU 0~7 │ └──────────────────────────┘ Compute / Small GPU ┌──────────────────────────┐ │ PaddleOCR / Docling │ └──────────────────────────┘ 실제 Stage 1 결과에 따라 4 GPU씩 들어간다면: GPU Node GPU0 ─┐ GPU1 │ DeepSeek GPU2 │ GPU3 ─┘ GPU4 ─┐ GPU5 │ GLM GPU6 │ GPU7 ─┘ 도 테스트합니다. Stage 1 결과를 보기 전에는 어느 쪽이 맞다고 고정하지 않는 게 좋습니다. 9. OCR/Docling → LLM까지 실제 pipeline test도 필요 각 모델을 독립적으로 때리는 것만으로는 부족합니다. 실제 주간 workflow가: PDF/Image │ ▼ PaddleOCR │ ▼ Docling │ ├── layout ├── figure └── context extraction │ ▼ DeepSeek / GLM │ ▼ response 라면 end-to-end workload 도 만들어야 합니다. 그래야 GPU serving benchmark에는 안 나타나는: OCR bottleneck CPU preprocessing object download context serialization network tokenization LLM queue 등을 찾을 수 있습니다. 10. Stage 3 — AIStor/local NVMe까지 포함 그다음에는 model loading을 별도 테스트합니다. 세 가지 시간을 측정합니다. Case A — Cold AIStor │ │ S3 ▼ NVMe │ ▼ RAM │ ▼ HBM T_cold = ? 두 번째는: Case B — Warm NVMe NVMe │ ▼ RAM │ ▼ HBM T_warm = ? 세 번째: Case C — Already loaded HBM │ ▼ ready T_ready = ? 이 결과가 주간↔야간 전환 시간을 결정 합니다. 예를 들어: AIStor → NVMe 6 min NVMe → model ready 2 min warmup 1 min total cold 9 min 이면 22:00 전환을 위해 21:30부터 준비하는 게 충분한지 판단할 수 있습니다. 11. Stage 4 — 실제 Day → Night 전환 야간에는 첨부하신 세 모델을 실제로 올립니다. DAY ────────────────────────── DeepSeek-V4.1-Flash GLM-5.3-Flash PaddleOCR/Docling │ │ prefetch ▼ 21:xx AIStor → NVMe │ ▼ NIGHT LOAD GLM-5.3 Qwen3.x-35B-A3B gpt-oss-20b │ ▼ health/warmup │ ▼ traffic switch 여기서는 전환시간 자체가 테스트 결과 입니다. 측정값을: Prefetch time Model load time Warm-up time Route switch time Drain time 총 전환시간 전환 중 실패 request 전환 중 P95/P99 latency 로 남깁니다. 12. 이 단계에서야 LiteLLM을 붙이는 것이 좋음 여기까지 통과하면: Keycloak │ ▼ Users ───────── LiteLLM │ ┌───────┼────────┐ ▼ ▼ ▼ GLM Qwen DeepSeek │ │ │ ▼ ▼ ▼ vLLM vLLM vLLM 으로 바꿉니다. 그 후 실제 사용자 패턴을 만들어: Team A 50 users Team B 20 users Batch 5 jobs RPM TPM Concurrency model quota 를 적용한 부하 테스트를 합니다. 이 단계에서 LiteLLM overhead와 quota가 의도대로 작동하는지 를 별도로 측정하면 됩니다. 13. MemKV도 마지막 쪽에서 A/B test MemKV도 처음부터 켜면 원인 분석이 어려워집니다. Test A vLLM └── HBM KV only Test B vLLM ├── HBM KV └── MemKV 동일한 workload를 사용해서: TTFT TPOT throughput KV hit rate HBM usage RDMA traffic 를 비교합니다. 특히: Shared system prompt Repeated RAG context Multi-turn conversation Long context 를 따로 만들어야 합니다. random prompt만 사용하면 external KV cache의 효과를 제대로 측정하지 못할 수 있습니다. 제가 추천하는 실제 테스트 순서 GPU/node validation — nvidia-smi , topology, NVLink/NVSwitch, NCCL, HBM, CPU NUMA부터 검증합니다. 모델 하나씩 vLLM에 올리기 — 일단 “실행된다”를 확인합니다. GPU/TP/DP/EP matrix — 각 모델 최적 parallelism을 찾습니다. Context × concurrency sweep — 최대 처리량이 아니라 SLA를 만족하는 saturation point를 찾습니다. 주간 모델 세트 동시 실행 — 실제 GPU capacity와 interference를 측정합니다. 야간 모델 세트 동시 실행 — 같은 방식으로 측정합니다. AIStor → NVMe → HBM — cold/warm startup 시간을 측정합니다. Day ↔ Night 전환 — prefetch/warm-up/drain까지 포함해 검증합니다. LiteLLM + 사용자 quota — 실제 multi-user traffic을 재현합니다. MemKV A/B — KV reuse가 높은 workload에서만 효과를 검증합니다. 여기서 가장 먼저 만들 산출물은 모델별 Test Matrix 입니다. 예를 들어 각 모델마다 precision × GPU수 × TP × DP × EP × max-model-len × concurrency × gpu-memory-utilization 을 바꾸면서 HBM / KV capacity / TTFT P95 / TPOT P95 / tok/s 를 자동 수집하고, 마지막에 “이 모델의 B300 권장 vLLM parameter” 한 줄을 자동으로 뽑는 테스트 패키지 를 만드는 게 좋습니다. 지금 진행 중인 Stage7의 목적이 바로 “실제 사용 모델별 설정값 찾기”였으므로, 이 테스트를 기존 Stage7에 7a 모델 적재 → 7b TP/EP sweep → 7c context/concurrency sweep → 7d day-set → 7e night-set → 7f AIStor/NVMe cold-warm → 7g 전환 으로 넣는 방식 이 현재 프로젝트 구조와 가장 잘 맞습니다. vLLM === 테스트가 끝나 각 모델의 GPU/TP/DP/EP/HBM/KV/context/concurrency 값이 확정됐다고 보면, 실제 서비스는 “모델 Pod들을 띄운다”보다 하나의 Inference Platform으로 운영 하는 게 좋습니다. 제가 현재 환경이라면 아래 구조를 목표로 하겠습니다. ┌──────── ADMIN CLUSTER ────────┐ │ │ │ Keycloak │ │ GitOps / CI-CD │ │ Private Registry │ │ Model/Profile Repository │ │ Prometheus / Grafana │ └──────────────┬────────────────┘ │ Management │ ▼ ┌──────────────────────────── GPU CLUSTER ─────────────────────────────┐ │ │ │ Compute Cluster / Users │ │ │ │ │ ▼ │ │ ┌───────────────────────┐ │ │ │ LiteLLM │ ← 인증: Keycloak │ │ │ │ │ │ │ API Key / Team │ │ │ │ Model ACL │ │ │ │ RPM / TPM / Quota │ │ │ │ Usage Accounting │ │ │ │ Logical Model Name │ │ │ └───────────┬───────────┘ │ │ │ │ │ ▼ │ │ ┌──────────────────────────┐ │ │ │ Inference Routing Layer │ ← replica 증가 시 │ │ │ Gateway API + EPP │ │ │ └────────────┬─────────────┘ │ │ │ │ │ ┌──────┴─────────────────────────────────────────┐ │ │ │ │ │ │ │ vLLM Serving Pools │ │ │ │ │ │ │ │ DeepSeek │ GLM │ Qwen │ gpt-oss │ OCR/VLM │ │ │ │ │ │ │ └───────────────────┬────────────────────────────┘ │ │ │ │ │ B300 GPU / HBM │ │ │ │ │ KV L1 / Prefix Cache │ │ │ │ │ MemKV (*) │ │ │ │ ┌──────────────────────────────────────────────────────────────────┐ │ │ │ Node Local NVMe │ │ │ │ 8 NVMe RAID0 + XFS │ │ │ │ /model-cache │ │ │ └────────────────────────────┬─────────────────────────────────────┘ │ └──────────────────────────────┼───────────────────────────────────────┘ │ S3 / Ethernet ▼ ┌──── STORAGE CLUSTER ────┐ │ │ │ AIStor │ │ │ │ models/ │ │ datasets/ │ │ checkpoints/ │ │ artifacts/ │ │ AIMem (*) │ └─────────────────────────┘ 여기서 중요한 운영 원칙은 LiteLLM / vLLM / Kubernetes / AIStor의 책임을 섞지 않는 것 입니다. 1. 모델마다 ServingProfile 을 고정 Stage7 테스트 결과를 그대로 운영 configuration으로 승격합니다. 예를 들어: model: glm-5.3-flash runtime: vllm gpu: count: 4 tensorParallel: 2 dataParallel: 2 expertParallel: true memory: gpuMemoryUtilization: 0.90 maxModelLen: 32768 cpu: cores: 32 memory: 256Gi cache: localNVMe: true prefixCaching: true memkv: false limits: maxConcurrency: 16 이 값은 사람이 production에서 즉흥적으로 바꾸지 않고 Git으로 관리합니다. 즉: Stage7 benchmark │ ▼ Approved Serving Profile │ ▼ Git │ ▼ GitOps │ ▼ vLLM Deployment 으로 연결합니다. 이렇게 하면 Stage7 결과가 production configuration의 근거 가 됩니다. 2. 모델별 Deployment를 완전히 분리 하나의 거대한 vLLM에서 모델을 계속 갈아끼우는 것보다: glm-5.3-flash │ └── Deployment/ServingPool deepseek-v4.1-flash │ └── Deployment/ServingPool qwen │ └── Deployment/ServingPool 처럼 모델 단위 serving pool 로 가져가는 것을 권합니다. 그러면 모델별로: GPU TP/DP/EP CPU memory max-model-len KV replica SLA 를 독립적으로 설정할 수 있습니다. 장애 격리도 훨씬 쉽습니다. 3. 사용자에게는 실제 모델 Deployment를 노출하지 않음 외부에서는: /v1/chat/completions model = glm model = deepseek model = qwen m
반 전체의 과목별 점수를 표로 정리해 본 적 있나요? 그 표가 바로 행렬 입니다. 📋 딥러닝 코드를 읽다 보면 shape mismatch 에러를 정말 자주 만나는데, 그 대부분은 "이 행렬이 몇 행 몇 열인가" 를 확인하는 습관 하나로 막을 수 있어요. 이번 글에서는 행렬의 shape , 행렬 곱셈의 패턴( 행과 열을 짝지어 내적 ), 그리고 행렬에는 왜 나눗셈 대신 역행렬 이 필요한지를 정리합니다. 📘 이 글은 위키독스 도서 Zero to 머신러닝 딥러닝 Master 의 00-02 행렬 — 성적표는 곧 행렬이다 을 블로그용으로 다듬은 글입니다. 💻 실습 코드: GitHub · 🏠 mldict.net · ✍️ 기술 블로그 💻 이 글의 코드: 00-02-matrices-report-card · Open in Colab — 핵심 코드와 실제 실행 결과는 글 아래 💻 GitHub 실습 섹션에 있습니다. ⬅️ 이전 글: #02 벡터란? 장바구니로 이해하는 벡터·내적·코사인 유사도 (파이썬 NumPy 실습) ➡️ 다음 글: #04 최소제곱법과 정규방정식 — 선형회귀가 머신러닝의 첫 모델인 이유 (파이썬 NumPy) TL;DR — 3줄 요약 행렬의 크기는 행 → 열 순서("3×2" = 3행 2열)로 읽고, 코드에서는 .shape 로 가장 먼저 확인합니다. 행렬 곱셈은 앞 행렬의 행 × 뒤 행렬의 열의 내적 을 반복하는 연산입니다. 그래서 안쪽 차원이 같아야 해요. 행렬에는 나눗셈이 없어서, $Ax=b$를 풀 때는 역행렬 $A^{-1}$을 곱합니다. 00-02-D 📏 행렬의 크기(shape) 표현하기 — "몇 행 몇 열인가요?" 사람을 소개할 때 키와 몸무게를 말하듯이, 행렬을 소개할 때는 "가로로 몇 줄, 세로로 몇 줄인가"를 먼저 말합니다. 이 "행렬의 몸집"을 크기(size) 또는 모양(shape)이라고 부릅니다. 앞으로 행렬을 다룰 때마다 "이 행렬의 shape가 뭐지?"를 가장 먼저 확인하게 될 텐데, 그 이유는 뒤에서 배울 덧셈·곱셈이 전부 이 크기가 맞느냐 안 맞느냐로 가능 여부가 갈리기 때문입니다. 🔑 앞서 만든 성적표 행렬을 다시 봅시다. 가로로 3줄(학생 철수·영희·민수), 세로로 3줄(수학·영어·과학)이 있었습니다. 이런 행렬을 "3행 3열 행렬" , 줄여서 "3×3 행렬"이라고 부릅니다. 읽을 때는 "삼 바이 삼(3 by 3)"이라고 읽습니다. 🎯 절대 잊으면 안 되는 약속 — 행이 먼저! 행(가로)의 개수를 먼저 쓰고, 열(세로)의 개수를 나중에 씁니다. "3×2"라고 쓰면 "행이 3개, 열이 2개"라는 뜻이지, 그 반대가 아닙니다. 이 순서를 뒤집어 부르면 완전히 다른 행렬을 가리키게 되므로, 처음부터 확실히 몸에 익혀두어야 합니다. 💜 더 쉽게 이해하기 — "행렬"이라는 이름 자체가 힌트 외우기 어렵다면, "행렬(行列)"이라는 단어를 그대로 읽어보세요. 한자 행(行, 가로)이 먼저 나오고 열(列, 세로)이 뒤에 나옵니다. 크기를 쓰는 순서도 똑같이 행 → 열 입니다. 영어로도 R ow → C olumn, 알파벳 순서 그대로라 "알씨(RC)" 순서라고 기억하면 편합니다. 🗂️ 이제 처음 예시를 정확히 정리해봅시다. 학생이 4명 이고 과목이 2개 라면, 행(학생)이 4개, 열(과목)이 2개이므로 이 행렬의 크기는 4×2 입니다. 순서를 헷갈려 "2×4"라고 쓰면 "학생 2명, 과목 4개"라는 전혀 다른 표를 가리키게 됩니다. 숫자 두 개는 같아 보여도 순서가 의미를 완전히 바꿔버립니다. 🔄 🧩 크기에 따라 특별한 이름이 붙는 행렬들 크기 이름 설명 n×n 정사각행렬 행과 열의 개수가 같은 "정사각형" 행렬 (단위행렬·역행렬이 여기서 등장) 1×n 행벡터 한 줄짜리 가로 벡터 — 00-01장에서 본 벡터의 정체 m×1 열벡터 한 칸짜리 세로 벡터 — 장바구니 예시의 "가격표"가 이것 1×1 스칼라 숫자 하나 — 우리가 평소에 쓰는 그냥 "수" 🔬 수학적 표기 — $\mathbb{R}^{m\times n}$ 수학책에서는 "$A$는 $m$행 $n$열의 실수 행렬"이라는 말을 다음과 같이 짧게 씁니다. $$ A \in \mathbb{R}^{m \times n} $$ 여기서 $\mathbb{R}$은 실수(real number) 전체를 뜻하고, 오른쪽 위의 $m \times n$이 바로 크기입니다. 이 표기 하나에 "이 행렬은 실수로 채워져 있고, 행이 $m$개, 열이 $n$개다"라는 정보가 모두 담겨 있습니다. 논문이나 교재에서 아주 자주 보게 될 표기이니 눈에 익혀두세요. 👀 🐍 Python import numpy as np # 학생 4명 × 과목 2개 → 4행 2열(4×2) 행렬 scores = np.array([ [85, 90], # 철수 [92, 88], # 영희 [70, 85], # 민수 [60, 75] # 지수 ]) print("shape(행, 열):", scores.shape) # (4, 2) → 행 먼저, 열 나중 print("차원 수(ndim) :", scores.ndim) # 2 (행렬은 2차원) print("전체 원소 수 :", scores.size) # 8 (=4×2) 🔗 GitHub에서 코드 보기 — 00_02_matrices_report_card.py L12–L24 ✅ Output shape(행, 열): (4, 2) 차원 수(ndim) : 2 전체 원소 수 : 8 .shape 가 돌려주는 (4, 2) 는 튜플이고, 항상 (행, 열) 순서 입니다. 우리가 손으로 "4행 2열"이라고 셌던 것과 정확히 같습니다. 🎉 🐞 실수하기 쉬운 부분 — 엑셀 셀 주소와 헷갈리지 마세요 엑셀에서 셀 주소 B3 은 열(B)을 먼저, 행(3)을 나중에 씁니다. 즉 엑셀은 행렬 수학과 정반대 순서 입니다. 그래서 엑셀에 익숙한 사람일수록 "열-행" 순서로 착각하기 쉽습니다. 수학·NumPy에서는 무조건 행이 먼저 라는 점을 별도로 각인해두세요. ⚠️ 00-02-E 🌍 우리 주변의 행렬들 — "세상은 표로 가득 차 있다" 행렬을 "성적표"라는 딱딱한 수학 개념으로만 생각하면 금방 지루해집니다. 하지만 일단 "행과 열로 정리된 숫자 표"라는 눈으로 세상을 보기 시작하면, 우리 주변이 온통 행렬 투성이라는 사실이 보입니다. 사실 컴퓨터와 AI가 세상을 이해하는 거의 유일한 방법이 "모든 것을 행렬(숫자 표)로 바꾸는 것"입니다 . 몇 가지 예를 자세히 들여다봅시다. 🔍 💜 더 쉽게 이해하기 — 사물함 비유 학교 복도의 사물함 🗄️을 떠올려보세요. 사물함은 여러 층·여러 칸으로 반듯하게 나뉘어 있고, 각 칸에는 물건이 하나씩 들어 있습니다. "몇 층 몇 번째 칸"만 말하면 원하는 물건을 정확히 찾을 수 있죠. 행렬도 똑같습니다. "몇 행 몇 열"이라는 주소만 있으면 그 칸의 숫자를 콕 집어 꺼낼 수 있습니다. 세상의 수많은 데이터가 이 "반듯한 사물함" 구조에 딱 들어맞습니다. 📊 엑셀 스프레드시트 : 우리가 매일 보는 그 표가 바로 행렬입니다. 첫 행에 항목 이름, 왼쪽 열에 이름표를 붙이고 나면, 안쪽의 숫자들이 통째로 하나의 행렬입니다. 회사의 월별 매출표, 가계부, 반 친구들 연락처 — 전부 행렬이라고 부를 수 있습니다. 🖼️ 디지털 사진 : 흑백 사진은 가로·세로로 픽셀이 촘촘히 박혀 있고, 각 픽셀은 "얼마나 밝은가"를 나타내는 0(검정)~255(흰색) 사이의 숫자 하나입니다. 그래서 가로 1000·세로 1000 픽셀의 흑백 사진은 그대로 1000×1000 행렬 입니다. 컬러 사진은 여기에 빨강·초록·파랑(RGB) 세 장이 겹쳐 있어서 행렬 세 개, 즉 3차원 "텐서"가 됩니다 (텐서는 뒤에서 다룹니다). 🎬 영화 평점 데이터(추천 시스템) : 행에 사용자, 열에 영화를 두면, 각 칸에는 "그 사용자가 그 영화에 준 별점"이 들어갑니다. 넷플릭스·유튜브의 추천 알고리즘은 바로 이 거대한 (그리고 대부분 빈칸인) 행렬에서 "빈칸을 채워 넣는(=아직 안 본 영화의 예상 별점을 맞히는)" 문제를 풉니다. 🕸️ 친구 관계(그래프/SNS) : 행과 열에 똑같이 사람들을 나열하고, "A와 B가 친구면 1, 아니면 0"을 적으면 인접행렬(adjacency matrix)이 됩니다. SNS의 친구 추천, 지하철 환승 경로 계산이 이런 행렬 위에서 이루어집니다. 🔎 검색 엔진(문서-단어 행렬) : 행에 문서, 열에 단어를 두고 "그 문서에 그 단어가 몇 번 나왔는지"를 적으면, 검색 엔진이 문서의 내용을 이해하는 기초 행렬이 됩니다. 🧠 신경망의 가중치 : AI 모델 내부에는 수많은 행렬이 저장되어 있고, 이 행렬들의 숫자 하나하나가 AI의 "지식"에 해당합니다. AI가 학습한다는 것은 결국 이 행렬 속 숫자들을 조금씩 바꿔 나가는 과정입니다. (이 장의 마지막 절에서 다시 만납니다.) 📋 한눈에 보는 "행렬로 표현되는 데이터" 분야 행(가로) 열(세로) 각 칸의 의미 성적표 학생 과목 점수 흑백 사진 세로 픽셀 가로 픽셀 밝기(0~255) 추천 시스템 사용자 영화 별점 SNS 그래프 사람 사람 친구면 1, 아니면 0 검색 엔진 문서 단어 등장 횟수 "사진이 정말 숫자 표일까?" 5×5짜리 아주 작은 흑백 이미지를 행렬로 직접 만들어보면 실감이 납니다. 아래에서 255 는 흰색, 0 은 검정입니다. 숫자 배치가 화면의 밝기 패턴과 그대로 대응됩니다. 🖼️ 🐍 Python import numpy as np # 5×5 흑백 이미지 (255=흰색, 0=검정) — 가운데에 십자 모양이 그려진 그림 image = np.array([ [ 0, 0, 255, 0, 0], [ 0, 0, 255, 0, 0], [255, 255, 255, 255, 255], [ 0, 0, 255, 0, 0], [ 0, 0, 255, 0, 0] ]) print("이미지 크기(shape):", image.shape) # (5, 5) # 밝은 칸(255)은 ■, 어두운 칸(0)은 · 로 그려보기 for row in image: print("".join("■" if v > 127 else "·" for v in row)) 🔗 GitHub에서 코드 보기 — 00_02_matrices_report_card.py L28–L42 ✅ Output 이미지 크기(shape): (5, 5) ··■·· ··■·· ■■■■■ ··■·· ··■·· 숫자 255 가 있던 자리에 정확히 십자(+) 모양이 나타났습니다. 이미지가 곧 행렬 이라는 것을 눈으로 확인한 셈입니다. 나중에 배울 "이미지를 알아보는 AI(CNN)"는, 결국 이 숫자 행렬 위에서 계산을 하는 것입니다. 🎯 📌 핵심 : 사진이든, 평점이든, 관계망이든 — 세상의 데이터는 일단 행렬(숫자 표)로 바뀐 다음에야 컴퓨터와 AI의 계산 대상이 됩니다. 그래서 행렬은 "선택 과목"이 아니라 머신러닝의 공용 언어 입니다. 🗣️ 00-02-Q 🔁 패턴 정리 — "행과 열을 짝지어서 내적한다" 앞에서 2×2 행렬 곱셈을 하며 네 칸(1행1열, 1행2열, 2행1열, 2행2열)을 하나씩 채웠습니다. 그 네 번의 계산에는 완전히 똑같은 한 가지 패턴 이 반복되고 있었습니다. 그 패턴을 딱 한 문장으로 뽑아내면 행렬 곱셈의 전부를 손에 쥘 수 있습니다. 👀 ✨ 한 문장 요약 결과 행렬의 (i행, j열) 자리에 들어갈 숫자 = 왼쪽 행렬 A의 i번째 행과 오른쪽 행렬 B의 j번째 열을 짝지어 "내적"한 값 💜 잠깐 복습 — "내적"이 뭐였죠? (00-01 벡터) 내적은 "같은 자리끼리 곱해서, 그것을 전부 더하는" 연산이었습니다. 예를 들어 $(1,2)$와 $(5,7)$의 내적은 $1\times5 + 2\times7 = 19$입니다. 장바구니 예시에서 "개수 × 단가를 다 더해 총액을 구한 것"이 바로 내적이었죠. 🛒 행렬 곱셈은 이 내적을, "A의 각 행"과 "B의 각 열"의 모든 짝에 대해 반복하는 것뿐입니다. 🔬 수학적 의미 — 공식과 변수 정의 $$ C_{ij} = \sum_{k=1}^{n} A_{ik}, B_{kj} $$ 변수 정의 (기호를 하나씩 확실히 짚고 갑니다): • $A$ : 왼쪽 행렬, 크기 $m \times n$ • $B$ : 오른쪽 행렬, 크기 $n \times p$ • $C$ : 결과 행렬, 크기 $m \times p$ • $i$ : 결과에서 지금 채우려는 행 번호 ($1 \le i \le m$) • $j$ : 결과에서 지금 채우려는 열 번호 ($1 \le j \le p$) • $k$ : 짝지어 곱할 대상을 훑는 합의 인덱스 , $1$부터 $n$까지 • $n$ : 짝지을 대상의 개수 = A의 열 개수 = B의 행 개수 (이 둘이 같아야만 곱셈 가능) 공식 $\sum_{k=1}^{n} A_{ik} B_{kj}$를 말로 풀면 이렇습니다. "A의 i행을 왼쪽에서 오른쪽으로($A_{i1}, A_{i2}, \dots, A_{in}$), B의 j열을 위에서 아래로($B_{1j}, B_{2j}, \dots, B_{nj}$) 훑으면서, 같은 순번(k)끼리 곱해 전부 더한다." 이게 정확히 내적입니다. ✏️ 공식을 예시에 대입해보기. 앞의 $A=\begin{bmatrix}1&2\3&4\end{bmatrix}$, $B=\begin{bmatrix}5&6\7&8\end{bmatrix}$에서 결과의 (1행, 1열), 즉 $C_{11}$을 공식으로 구하면: ✅ Output i=1, j=1 이므로 A의 1행(1,2), B의 1열(5,7) C11 = Σ(k=1..2) A1k·Bk1 = A11·B11 + A12·B21 = 1 × 5 + 2 × 7 = 5 + 14 = 19 ✅ (손으로 계산했던 값과 일치!) 🧠 직관적 의미 — 왜 하필 "곱하고 더하기"일까? 내적은 결국 가중합(weighted sum)입니다 . B의 한 열이 "각 항목에 얼마씩 가중치를 줄지"를 정하는 규칙이라면, A의 한 행에 그 규칙을 적용해 "하나의 대표 숫자"로 요약하는 것이 내적입니다. 장바구니 예시에서 "각 과일 개수에 단가라는 가중치를 곱해 총액 하나로 요약"한 것과 똑같습니다. 이 "가중합으로 요약하기"가 뒤에서 배울 신경망의 뉴런 하나가 하는 일과 정확히 같습니다. 🔗 공식 $C_{ij}=\sum_k A_{ik}B_{kj}$를 삼중 반복문 으로 그대로 옮겨보면, NumPy의 @ 가 내부에서 무슨 일을 하는지 손에 잡힙니다. 💻 🐍 Python import numpy as np A = np.array([[1, 2], [3, 4]]) # (m=2, n=2) B = np.array([[5, 6], [7, 8]]) # (n=2, p=2) m, n = A.shape # A: m행 n열 n2, p = B.shape # B: n행 p열 assert n == n2, "내부 차원(n)이 안 맞으면 곱할 수 없음!" C = np.zeros((m, p)) # 결과는 m×p 크기 for i in range(m): # 결과의 행 for j in range(p): # 결과의 열 for k in range(n): # 짝지어 곱할 대상(합의 인덱스) C[i, j] += A[i, k] * B[k, j] # 곱해서 누적 = 내적 print("직접 구현한 결과:\n", C) print("NumPy @ 결과:\n", A @ B) 🔗 GitHub에서 코드 보기 — 00_02_matrices_report_card.py L46–L62 ✅ Output 직접 구현한 결과: [[19. 22.] [43. 50.]] NumPy @ 결과: [[19 22] [43 50]] 공식을 그대로 옮긴 삼중 루프의 결과와 @ 의 결과가 완전히 같습니다. 즉 @ 는 이 세 겹 반복을 (아주 빠르게) 대신 해주는 것뿐입니다. 실제로는 항상 @ 를 쓰지만, "속을 열어보면 이 공식"이라는 걸 아는 것과 모르는 것은 큰 차이입니다. 🔧 ⚖️ 프레임워크 관점 — 같은 공식, 다른 이름 개념 NumPy PyTorch TensorFlow JAX 행렬 곱 A @ B torch.matmul tf.matmul jnp.matmul 공식 그대로 (아인슈타인 표기) np.einsum('ik,kj->ij', A, B) einsum 은 네 프레임워크 모두 동일 문법으로 지원 특히 einsum('ik,kj->ij') 는 방금 배운 공식 $\sum_k A_{ik}B_{kj}$의 인덱스를 문자 그대로 적은 것입니다. 공식을 이해했다면 이 표기가 오히려 가장 직관적으로 보일 것입니다. 🧠 🐞 디버깅 포인트 — 내부 차원(n)이 생명 곱셈이 가능하려면 A의 열 개수와 B의 행 개수(둘 다 $n$)가 같아야 합니다. 안 맞으면 ValueError: ... not aligned 가 납니다. 곱하기 직전에 print(A.shape, B.shape) 로 안쪽 두 숫자 가 같은지 확인하는 습관을 들이세요. 예: (2, 3 ) @ ( 3 ,4) → OK, 결과는 (2,4). 00-02-Y 🤔 역행렬은 왜 필요할까? — "행렬에는 나눗셈이 없다" 역행렬($A^{-1}$)을 배웠지만, "그래서 이걸 어디에 쓰지?"라는 의문이 남습니다. 역행렬이 태어난 이유는 딱 하나, 행렬에는 "나눗셈"이라는 연산이 아예 없기 때문 입니다. 그런데 우리는 종종 나눗셈이 필요합니다. 그 필요를 대신 채워주는 것이 역행렬입니다. 🧩 가장 흔한 상황은 이런 식입니다. 어떤 값 $x$를 모르는데, "$x$에 $A$를 적용했더니 $b$가 나왔다"는 사실만 알고 있습니다. 수식으로는: $$ A x = b $$ 여기서 우리가 알고 싶은 건 "원래 $x$가 무엇이었나?"입니다 . 이건 사실 연립방정식 을 푸는 것과 같고, 현실에서는 "결과($b$)를 보고 원인($x$)을 거꾸로 알아내는" 아주 흔한 문제입니다. 예컨대 "여러 재료를 섞어 만든 음료의 성분($b$)을 보고, 원래 재료를 얼마씩 넣었는지($x$)를 역추적"하는 상황이죠. 🔎 💜 더 쉽게 이해하기 — "되돌리기(Undo)" 버튼 비유 역행렬은 컴퓨터의 Ctrl+Z(되돌리기) 🔙 같은 존재입니다. $A$가 "$x$에 어떤 변형을 가하는 작업"이라면, $A^{-1}$은 그 변형을 정확히 원상복구하는 작업 입니다. 자물쇠를 잠그는 열쇠($A$)가 있으면 여는 열쇠($A^{-1}$)가 있고, 둘을 이어서 쓰면 아무 일도 없던 것처럼($I$) 됩니다. 그래서 $A^{-1}A = I$인 것입니다. 일반 숫자였다면 $3x = 6$에서 양변을 3으로 나눠 $x = 2$를 구했을 겁니다. 하지만 행렬에는 나눗셈이 없으니, "나누기" 대신 "역행렬을 곱하기"를 씁니다. 🔬 공식 유도 — 단계별 출발: $$ A x = b $$ 1 양변의 왼쪽 에 $A^{-1}$을 곱합니다 (여기가 핵심!): $$ A^{-1}(A x) = A^{-1} b $$ 2 왼쪽에서 $A^{-1}A = I$ (역행렬 × 원래 행렬 = 단위행렬): $$ I x = A^{-1} b $$ 3 단위행렬 $I$는 곱해도 값이 변하지 않으므로 ($Ix = x$): $$ \boxed{,x = A^{-1} b,} $$ ⚠️ 왜 "왼쪽에" 곱해야 하나요? 행렬 곱셈은 순서를 바꾸면 결과가 달라진다는 것($AB \neq BA$)을 앞에서 배웠습니다. $Ax=b$에서 $A$는 $x$의 왼쪽 에 붙어 있으므로, 이를 떼어내려면 $A^{-1}$도 반드시 양변 모두 왼쪽 에 곱해야 합니다. 만약 오른쪽에 곱하면($xA^{-1}$) 위치가 안 맞아 $A^{-1}A$를 만들 수 없어 $x$를 분리할 수 없습니다. "붙어 있는 쪽과 같은 쪽에서 떼어낸다"고 기억하세요. 🔑 이렇게 역행렬을 이용하면 $Ax = b$ 형태의 방정식에서 $x = A^{-1}b$로 답을 구할 수 있습니다. 이 논리는 00-03장에서 연립방정식을 본격적으로 풀 때 그대로 다시 등장합니다. 🔁 ⚠️ 모든 행렬에 역행렬이 있는 것은 아닙니다. 일반 숫자에서 $0$의 역수 $\frac{1}{0}$이 정의되지 않는 것처럼, 어떤 행렬은 역행렬이 존재하지 않습니다(이를 특이행렬, singular matrix 라 합니다). 역행렬이 있느냐 없느냐는 행렬식(determinant)이 0이 아니냐 0이냐로 판별하는데, 이 개념은 뒤에서 따로 다룹니다. 🚀 머신러닝에서는? — 선형회귀의 "정규방정식" 머신러닝에서 가장 기본이 되는 선형회귀 의 정답 공식(정규방정식)이 바로 역행렬로 쓰입니다. $$ w = (X^\top X)^{-1} X^\top y $$ 데이터 $X$와 정답 $y$로부터 최적의 가중치 $w$를 한 번에 구하는 이 식에 $(\cdots)^{-1}$이 등장합니다. 즉 "$Xw = y$를 거
현재 구조라면 AIStor를 GPU Pod에 filesystem처럼 직접 mount해서 모델을 실행하기보다, AIStor = 원본 저장소 , GPU node NVMe = 실행용 local cache 로 명확히 분리 하는 것을 가장 추천합니다. 핵심 data path는 이것입니다. Storage Cluster GPU Cluster ┌──────────────────┐ ┌─────────────────────────────┐ │ MinIO AIStor │ S3 / 400GbE │ GPU Node │ │ │ =================>│ │ │ Model Repository │ │ Local NVMe RAID0 + XFS │ │ Dataset │ │ /model-cache │ │ Checkpoint │ │ │ │ │ Artifact │ │ ▼ │ └──────────────────┘ │ RAM │ │ │ │ │ ▼ │ │ B300 HBM / vLLM │ └─────────────────────────────┘ AIStor = Source of Truth NVMe = Disposable Local Cache 왜 이 방식이 좋은가 vLLM이 뜰 때마다 AIStor에서 직접 weight를 읽는 구조라면 재시작/전환 때마다 Storage network 성능과 AIStor 상태가 model startup의 critical path가 됩니다. 반대로 local NVMe에 모델을 캐시해 두면 주/야간 전환 시 대부분 NVMe → RAM → HBM 만 거치면 됩니다. 또한 GPU node 장애 시 local NVMe 데이터가 사라져도 괜찮습니다. 새 node에서 AIStor로부터 다시 구성하면 됩니다. 따라서 AIStor는 durable tier, NVMe는 performance tier 입니다. 1. 연결은 S3 API를 기본으로 GPU cluster에서 AIStor까지는 S3 endpoint를 하나 고정해서 사용하는 게 좋습니다. GPU Cluster │ │ S3 HTTPS │ high-speed Ethernet ▼ s3.aistor.internal │ ▼ AIStor Service │ ├── model-prod ├── datasets ├── checkpoints └── artifacts 예를 들어 bucket을 단순히 하나 크게 쓰기보다 역할별로 나눕니다. model-prod/ glm-5.3/ v1/ manifest.json ... v2/ manifest.json ... glm-5.3-flash/ deepseek-v4.1-flash/ qwen3.6-35b-a3b/ gpt-oss-20b/ datasets/ checkpoints/ artifacts/ 모델은 특히 mutable한 latest 에 의존하지 않고 version/hash를 고정 하는 것을 추천합니다. 2. GPU Node에는 /model-cache 앞서 이야기한 8개 NVMe라면 우선: NVMe0 ─┐ NVMe1 ─┤ NVMe2 ─┤ NVMe3 ─┤ NVMe4 ─┼── RAID0 ── XFS ── /model-cache NVMe5 ─┤ NVMe6 ─┤ NVMe7 ─┘ 로 구성합니다. 그리고 Kubernetes에서 해당 디렉터리를 사용할 수 있게 합니다. 가장 단순하게는: volumes: - name: model-cache hostPath: path: /model-cache type: Directory containers: - name: vllm volumeMounts: - name: model-cache mountPath: /models readOnly: true vLLM에서는: /models/glm-5.3/<version>/ 을 읽습니다. vLLM Pod 자체가 S3에서 매번 다운로드하도록 만들지 않는 것 이 포인트입니다. 3. 별도의 Model Cache/Prefetch Job을 둠 구조를 이렇게 분리합니다. AIStor │ │ S3 ▼ Model Prefetch Job │ download │ hash verify │ ▼ /model-cache │ read-only │ ▼ vLLM │ ▼ B300 Prefetch Job 역할은 딱 네 가지면 충분합니다. 1. AIStor manifest 조회 2. local version/hash 확인 3. 필요한 파일만 download 4. checksum 검증 후 READY 표시 예를 들어: /model-cache/ glm-5.3/ sha256-abc123/ config.json tokenizer... *.safetensors .READY glm-5.3-flash/ sha256-def456/ ... .READY .READY 는 모든 파일의 hash 검증이 끝난 뒤 마지막에 생성합니다. 그러면 vLLM startup script는 .READY 없는 모델은 절대로 사용하지 않게 하면 됩니다. 4. 주/야간 전환과 아주 잘 맞음 현재 요구사항에서는 이 방식의 효과가 큽니다. 예를 들어 야간 전환이 22시라면: 20:30 AIStor │ │ S3 ▼ GPU Node NVMe GLM-5.3 download/check Qwen download/check gpt-oss download/check ↓ 21:30 /model-cache DAY ✓ NIGHT ✓ DAY vLLM은 계속 서비스 중 22시가 되면: DAY vLLM │ ├─ drain └─ stop │ ▼ GPU free │ ▼ NIGHT vLLM │ │ /model-cache에서 load ▼ HBM │ warm-up │ ▼ Service 가 됩니다. 따라서 AIStor→NVMe 전송시간은 서비스 중단시간에서 빠집니다. 5. GPU node가 여러 개면 "어느 node에 cache할 것인가"가 중요 예를 들어: AIStor │ ├────────── GPU01 /model-cache ├────────── GPU02 /model-cache ├────────── GPU03 /model-cache └────────── GPU04 /model-cache 모든 모델을 모든 node에 복제할 필요는 없습니다. ServingProfile과 연계해서: GPU01 DeepSeek GLM-Flash GLM GPU02 DeepSeek GLM-Flash Qwen GPU03 GLM Qwen gpt-oss 처럼 배치할 수도 있습니다. 다만 현재처럼 Day/Night workload가 명확하고 NVMe 용량이 충분하다면 저는 가능한 한 각 serving node에 DAY+NIGHT 모델을 모두 캐시 하는 쪽을 먼저 검토하겠습니다. 운영이 훨씬 단순해집니다. 6. AIStor credential은 Pod YAML에 직접 넣지 않음 예를 들어 이런 건 피합니다. env: - name: AWS_ACCESS_KEY_ID value: "AKIA...." - name: AWS_SECRET_ACCESS_KEY value: "xxxx" 최소한 Kubernetes Secret을 사용합니다. Secret │ ├─ S3 endpoint ├─ access key ├─ secret key └─ CA │ ▼ Model Prefetch Job 그리고 credential 권한도 분리합니다. vLLM S3 credential 없음 Model Prefetch model-prod : READ Training/Checkpoint writer checkpoints : READ/WRITE 이 구조가 좋습니다. 즉 serving vLLM 자체에는 가능하면 AIStor credential조차 주지 않습니다. 7. NetworkPolicy도 이 역할에 맞춰 분리 예를 들어: Model Prefetch Pod │ │ TCP/443 ▼ AIStor ✓ vLLM Pod ───────────X────> AIStor Other Pod ──────────X────> AIStor 처럼 만들 수 있습니다. Training Pod은 별도 policy로 checkpoint bucket 접근을 허용합니다. AIStor model-prod datasets checkpoints ▲ ▲ ▲ │ R │ R │ R/W │ │ │ Prefetch Training Training 이렇게 하면 credential과 network authorization이 같이 맞물립니다. 8. ClusterMesh와 AIStor data path는 구분해서 생각 현재 Compute/GPU/Storage를 ClusterMesh로 연결한다 하더라도 저는 다음처럼 생각하는 것을 추천합니다. Control / Service Connectivity ────────────────────────────── Cilium ClusterMesh Service discovery NetworkPolicy Bulk Data Path ────────────────────────────── GPU node │ │ high-speed Ethernet │ S3/HTTPS ▼ AIStor 즉 ClusterMesh가 모델 데이터를 운반하는 storage 기술인 것은 아닙니다. 물론 실제 packet은 Cilium networking/routing을 이용할 수 있지만, AIStor 모델 전송 성능을 설계할 때는 별도의: GPU NIC ↓ Leaf ↓ ECMP routed fabric ↓ Storage Leaf ↓ AIStor NIC 경로의 bandwidth/MTU/ECMP/failure를 검증해야 합니다. NDR InfiniBand는 기본적으로 이 S3 모델 전송 경로에 넣지 않고: B300 ↔ B300 NCCL / RDMA 용도로 분리하는 것을 우선 권합니다. 9. 특히 여러 GPU node가 동시에 AIStor를 때리는 상황을 테스트 평상시보다 아침/저녁 prefetch 시점 이 더 위험합니다. 예를 들어 GPU node 8대가 동시에: AIStor ▲ ┌──────┼──────┐ │ │ │ GPU01 GPU02 GPU03 ... │ │ │ 100GB 100GB 100GB 를 받으면 AIStor와 Ethernet에 순간적인 부하가 몰립니다. 따라서 production에서는 약간 stagger할 수도 있습니다. 20:20 GPU01 prefetch 20:22 GPU02 20:24 GPU03 20:26 GPU04 ... 혹은 concurrency/bandwidth를 제한합니다. Stage7 후반부에 단일 node download 성능뿐 아니라 N개 GPU node 동시 prefetch 성능 도 측정하는 게 좋습니다. 10. Checkpoint는 반대 방향 Serving model은: AIStor ↓ NVMe ↓ HBM 이지만 학습/튜닝 checkpoint는 반대입니다. GPU/HBM ↓ Local NVMe ↓ async upload ↓ AIStor 가능하면 checkpoint를 매번 synchronous하게 AIStor에 쓰면서 GPU를 기다리게 하지 않고, local NVMe에 먼저 안전하게 생성한 후 uploader가 AIStor로 올리는 구조를 검토합니다. 완료 후: checkpoint-001/ checkpoint-002/ checkpoint-003/ manifest.json 처럼 version 관리합니다. 11. CSI mount는? AIStor를 CSI/POSIX 형태로: vLLM │ ▼ /models │ CSI │ ▼ AIStor 처럼 직접 mount하고 싶을 수 있는데, 현재 vLLM model serving의 기본 경로로는 제가 우선 선택하지 않겠습니다. 현재 요구사항에는: AIStor → Local NVMe → vLLM 이 더 단순하고, 성능 특성이 예측 가능하며, AIStor/network 장애가 이미 running 중인 vLLM에 미치는 영향도 작습니다. CSI/POSIX mount가 유용한 workload가 별도로 있다면 그때 사용하면 됩니다. 결국 가장 추천하는 구조 STORAGE CLUSTER ┌───────────────────────────────────┐ │ AIStor │ │ │ │ models Source of Truth │ │ datasets │ │ checkpoints │ │ artifacts │ └───────────────┬───────────────────┘ │ │ S3 / HTTPS │ High-speed Ethernet │ ════════════════╪════════════════════════ │ ▼ GPU CLUSTER ┌───────────────────────────────────────┐ │ GPU Node │ │ │ │ Model Prefetch Job │ │ │ │ │ ├─ version check │ │ ├─ download │ │ └─ SHA256 verify │ │ │ │ │ ▼ │ │ 8 × NVMe RAID0 / XFS │ │ /model-cache │ │ │ │ │ │ read-only │ │ ▼ │ │ vLLM │ │ │ │ │ ▼ │ │ B300 HBM │ └───────────────────────────────────────┘ 그리고 운영 자동화는: AIStor Model Repository │ ▼ Prefetch CronJob │ ▼ /model-cache READY │ ▼ Switch Workflow │ ┌────┴─────┐ │ │ old drain scale 0 │ GPU free │ scale 1 │ NVMe → HBM │ warmup │ OPEN 으로 연결하면 됩니다. 현재 환경에서는 이 방식이 AIStor와 B300 GPU cluster 사이의 가장 단순하면서도 production으로 확장하기 좋은 출발점 이라고 봅니다. 특히 다음 Stage7에 AIStor→NVMe cold prefetch , NVMe→vLLM Ready , 동시 N-node prefetch , cache hit/miss , AIStor/network 장애 상태에서 기존 vLLM 서비스 영향 까지 넣어두면, 앞에서 이야기한 주/야간 자동전환 시간을 꽤 정확하게 산출할 수 있습니다. === 네. 추론에서는 model-cache 외 사용처가 많지 않은 반면, 학습에서는 local NVMe의 역할이 훨씬 커집니다. 그래서 8개 NVMe를 전부 하나의 /model-cache 라고 보기보다는 물리적으로는 하나의 고속 local pool을 만들고 그 안을 용도별 디렉터리로 나누는 것을 추천합니다. 8 × NVMe │ └── RAID0 + XFS │ ├── /local/model-cache ├── /local/dataset-cache ├── /local/checkpoints ├── /local/scratch └── /local/tmp 중요한 원칙은 여기에 있는 데이터는 모두 node가 죽으면 없어져도 복구 가능해야 한다 는 것입니다. 영구 보관은 AIStor가 담당합니다. 추론(Inference)에서는 가장 큰 용도는 역시 1 model weight cache 입니다. AIStor ↓ /local/model-cache ↓ RAM ↓ GPU HBM 여기에 model weight뿐 아니라 같은 버전의 실행 artifact를 묶어두는 게 좋습니다. /local/model-cache/ └── glm-5.3/ └── <model-hash>/ ├── *.safetensors ├── config.json ├── tokenizer.* ├── generation_config.json └── .READY 두 번째는 2 모델 변환/컴파일 cache 입니다. 사용하는 runtime과 기능에 따라 CUDA/Triton/torch compile 계열의 cache가 생길 수 있습니다. /local/runtime-cache/ ├── torch/ ├── triton/ └── vllm/ 이걸 container filesystem에만 두면 Pod 재생성 때 다시 만들어질 수 있으므로, 실제 테스트에서 startup 시간이 의미 있게 줄어든다면 local NVMe에 persist시키는 것이 좋습니다. 단, runtime/driver/GPU architecture가 바뀌었을 때 stale cache를 재사용하지 않도록 versioning이 필요합니다. 세 번째 3 /tmp / scratch 도 있습니다. 모델 load/변환, preprocessing 등의 임시파일이 container root filesystem을 채우지 않게: /local/tmp/<pod-id>/ 같은 node-local 영역을 줄 수 있습니다. 반면 일반적인 vLLM의 KV cache를 local NVMe에 기본적으로 두는 것은 권하지 않습니다. Inference Model AIStor → NVMe → HBM KV cache HBM ← 기본 │ 필요시 MemKV KV cache NVMe ← 기본 설계로는 X KV는 latency에 매우 민감하기 때문입니다. NVMe KV/offload는 HBM 부족이나 특수한 long-context 요구가 있고 실제 benchmark에서 이득이 확인된 경우에만 별도 선택지로 보는 게 좋습니다. 따라서 추론 node는 대략: /local/ ├── model-cache/ ★★★★★ ├── runtime-cache/ ★★~★★★ ├── scratch/ ★ └── tmp/ ★ KV cache → HBM Persistent data → AIStor 정도로 생각하면 됩니다. 학습에서는 훨씬 많습니다 학습 시 가장 중요한 추가 용도는 1 Dataset cache/staging 입니다. AIStor │ │ training 시작 전 ▼ Local NVMe /local/dataset-cache │ ▼ CPU/RAM │ ▼ GPU 매 epoch마다 AIStor에서 dataset을 반복해서 읽는 것보다 학습 시작 전에 필요한 shard를 local NVMe로 staging하는 것이 좋습니다. 예를 들어: /local/dataset-cache/ ├── dataset-A/ │ └── version-202610/ │ ├── shard-00001 │ ├── shard-00002 │ └── ... └── dataset-B/ 대규모 dataset이면 모든 node가 전체 dataset을 복제할 필요도 없습니다. Distributed training에서 node별 shard를 나눠 staging할 수 있습니다. AIStor Dataset shard 000~099 → GPU01 NVMe shard 100~199 → GPU02 NVMe shard 200~299 → GPU03 NVMe shard 300~399 → GPU04 NVMe 다만 training framework의 data sharding 방식과 맞춰야 합니다. 2 Checkpoint staging 학습에서는 매우 중요합니다. 나쁜 형태는 매 checkpoint마다 GPU 학습 경로가 AIStor upload 완료를 기다리는 것입니다. 가능하면: Training │ ▼ Local NVMe /local/checkpoints │ │ async ▼ AIStor 로 가져갑니다. 예를 들어: step 10000 │ ▼ local checkpoint write │ ├─────────── Training 계속 │ ▼ background uploader │ ▼ AIStor 입니다. 단, 여기서 주의할 게 있습니다. local write가 끝났다고 checkpoint가 안전한 것은 아닙니다. GPU node 자체가 죽으면 NVMe checkpoint도 사라지기 때문입니다. 그래서 상태을 구분합니다. WRITING ↓ LOCAL_COMPLETE ↓ UPLOADING ↓ AISTOR_COMPLETE ↓ VERIFIED AISTOR_COMPLETE/VERIFIED 가 되어야 durable checkpoint로 취급합니다. 3 Training scratch 학습 중에는 preprocessing이나 데이터 변환으로 임시 공간이 상당히 필요할 수 있습니다. /local/scratch/ 에: dataset preprocessing tokenization output shuffle files temporary shards intermediate artifacts packing output 등을 둘 수 있습니다. 특히 대규모 dataset을: Raw data ↓ tokenization ↓ packing ↓ training shards 로 변환한다면 local NVMe가 상당히 유용합니다. 4 Model/cache 학습에서도 base model을 당연히 cache할 수 있습니다