加拿大量子安全公司Quantum eMotion併購資安業者Plurilock,整合QRNG、PQC與AI資安能力,加速商業化布局
iThome 新聞
加拿大量子安全技術業者Quantum eMotion(QeM)於9月28日宣布,已與資安公司Plurilock簽署最終收購協議,將以約3,380萬加元(約7.5億元)收購Plurilock全部已發行的普通股。
Балл: 56.62Уверенность: 54%
ПодробнееЗагружаем каталог…
НАВИГАТОР ПО ВОЗМОЖНОСТЯМ ИИ
Найдите свой ИИ-инструмент. Бесплатный доступ, пробные периоды и кредиты — в одном месте.
iThome 新聞
加拿大量子安全技術業者Quantum eMotion(QeM)於9月28日宣布,已與資安公司Plurilock簽署最終收購協議,將以約3,380萬加元(約7.5億元)收購Plurilock全部已發行的普通股。
Балл: 56.62Уверенность: 54%
ПодробнееiThome 新聞
OpenAI更新Codex Cloud服務,讓程式開發代理Codex在OpenAI管理的雲端電腦執行開發工作,新版讓開發者可先替專案準備一套雲端開發環境,配置程式碼儲存庫、開發工具與相依套件等,發布後供後續任務重複使用。ChatGPT Enterprise也支援團隊共享開發環境,成員可使用相同設定執行各自的Codex任務,相關功能目前正逐步推出。
Балл: 56.62Уверенность: 54%
ПодробнееiThome 新聞
傳統事件應變雖已有一套成熟流程,但面對今日攻擊型態,線性方法逐漸顯得不足。SANS Institute於9月15日發布一份720頁的技術資源《Dynamic Incident Response: A Framework for Security Teams》,提出動態事件應變框架,打破應變流程缺乏彈性的限制,改以可隨新證據反覆調整的方式處理事件。
Балл: 56.59Уверенность: 54%
Подробнееvelog
54개 테크블로그·커뮤니티(GeekNews, HN, r/LocalLLaMA, Simon Willison, 배민 등)를 매일 자동 스캔해서, AI/GPU 관련 신규 글만 추려 요약합니다. 오늘의 7건: A Guide to Structured Output in Spring AI (Baeldung): Spring AI로 LLM 출력 JSON 스키마를 강제하는 패턴 — 파이프라인 파싱 실패 줄이기 Introduction to Triton Java API (Baeldung): NVIDIA Triton 추론 서버를 Java에서 제어하는 서빙 자동화 입문 Aweb – Communication for AI Agents (HN Frontpage): AI 에이전트 간 통신 프로토콜 신 프로젝트 Using Opus 5.5 to discover a new eyewitness record of the dodo (HN Frontpage): Opus 5.5로 미확인 고문서에서 도도 목격 기록을 실제로 발견한 사례 배달의민족 전자계약서 화면 개편기: AI에게 맡긴 것과 사람이 챙긴 것 (우아한형제들): UI 개편에서 AI 위임/사람 검수 경계 실록 AI에게 만드는 법 대신 실패하는 법을 묻다 (우아한형제들): 수천 명 동시접속 게임 사례로 본 "실패 먼저 묻기" 워크플로 AI가 분석한 리서치 결과, 어떻게 만들고 전달할까요? (우아한형제들): AI 리서치 결과물의 전달 설계와 검증 프로세스 전체 원문 링크가 포함된 풀브리핑: http://daily-llm.com/2026-10-02/%ec%98%a4%eb%8a%98%ec%9d%98-%ed%85%8c%ed%81%ac-%eb%b8%8c%eb%a6%ac%ed%95%91-54%ea%b0%9c-%eb%b8%94%eb%a1%9c%ea%b7%b8-%ec%8a%a4%ec%ba%94-%ea%b2%b0%ea%b3%bc-10-1/ 로컬 LLM 실측 데이터(VRAM/tok-s/시세)는 https://daily-llm.com/vram-fit-matrix/ 에서.
Балл: 54.4Уверенность: 49%
Подробнееvelog
새 언어나 AI 기능을 도입할 때 성능과 실행 요건은 중요한 판단 근거입니다. 여기에 개발팀이 답할 질문을 더해봅시다. 이 도구는 반복하는 작업의 어떤 불편을 덜어주는가? 표현력이 좋은 언어와 높은 사양의 PC가 갖춘 가능성을, 사람이 계속 사용할 이유와 연결하는 질문입니다. 언어를 배우는 동기와 함께 일하는 비용 bytecode.news의 「Because It's Not Fun Enough」 는 언어가 채택되는 이유를 기술적 장점만으로 설명하기 어렵다고 주장합니다. 필자는 프로그래밍에 소명, 예술, 생업의 성격이 겹쳐 있다고 봅니다. 깊이 이해하려는 욕구, 자기 방식으로 표현하는 즐거움, 맡은 일을 끝내야 하는 필요가 도구 선택에 함께 작용한다는 관점입니다. 팀에서 언어를 검토한다면 이 관점을 학습과 협업의 문제로 옮겨볼 수 있습니다. 코드를 간결하게 작성하더라도 동료가 읽고 고치기 어렵다면 그만큼 협업 부담이 남습니다. 익숙함만을 기준으로 삼는 선택에도 대가가 있습니다. 새로운 방법을 배우고 작업을 개선하려는 동기를 꺾을 수 있기 때문입니다. 이때 재미는 낯선 문법의 신기함보다 문제를 이해하고 풀어가는 감각으로 해석할 만합니다. 다만 특정 언어의 쇠퇴를 소명·예술·생업에 배정하는 설명에는 bytecode.news 필자의 평가가 담겨 있습니다. 조직이 도입을 결정한 언어라는 사실로 사용자 모두의 불만을 추론해서는 안 됩니다. 팀의 선택에 적용할 대상은 언어별 흥망에 대한 판정이 아니라, 학습 동기와 일자리, 조직의 결정까지 고려하는 평가 관점입니다. 사용 횟수에 남지 않는 선택의 이유 bytecode.news의 같은 글 은 기술이 계속 쓰이는 배경으로 다음 사례를 듭니다. 언어 글에서 제시하는 생존의 배경 자바스크립트 브라우저 안에서 차지하는 위치 COBOL 다른 기술로 교체하는 데 드는 높은 비용 이 설명에서 지속적인 사용은 만족도의 증거가 되지 않습니다. 선택지가 좁거나 전환 부담이 크면 불편한 도구도 계속 사용하게 됩니다. 내부 개발 도구의 도입 성과를 사용량으로 평가하는 팀이라면, 작업별 사용 이유를 함께 기록하는 방식을 제안합니다. 의무적으로 실행한 경우와 문제를 해결하려고 다시 찾은 경우를 구별하기 위해서입니다. 기록에는 도구가 유용했던 작업과 우회가 필요했던 작업을 담습니다. 같은 사용 횟수라도 다음 도입 결정을 뒷받침하는 근거는 달라집니다. AI PC 요건을 통과한 뒤에 남는 평가 AI PC를 검토할 때 실행 요건은 기기의 자격을 설명합니다. ITWorld의 「마이크로소프트 코파일럿+ PC 브랜드의 조용한 퇴장」 이 제시한 코파일럿+ PC 기준은 40+ TOPS의 NPU, 최소 16GB RAM, 최소 256GB SSD, 윈도우 11 24H2 이상입니다. 해당 보도는 윈도우 센트럴을 인용해, 새 12인치 서피스 프로와 13인치 서피스 랩톱이 이 조건을 충족하면서도 코파일럿+ PC 배지를 달지 않았다고 전합니다. ITWorld는 초기 AI 기능의 완성도와 후속 기능의 시장 정착을 부정적으로 평가합니다. 다만 소개된 대목에는 상세 사용 통계가 없어 이용자 감소 규모나 개별 기능의 실패 정도를 수치로 판단하기 어렵습니다. 브랜드 축소는 확정된 서비스 종료가 아닌 전망으로 다뤄집니다. 같은 보도에는 마이크로소프트가 엣지 AI와 하이브리드 솔루션 방향을 유지한다는 임원의 설명도 실려 있습니다. 따라서 배지의 향방을 개별 기능의 지원 여부나 PC의 AI 전략 전체를 포기한다는 뜻으로 확대해서는 안 됩니다. 개발팀이 AI 기능 도입을 검토한다면, 요건을 충족한 기기에서 평소 작업의 어떤 부분이 달라지는지 평가하는 데 시간을 배정할 만합니다. 하드웨어 기준만으로는 그 기능을 일상적으로 사용할 이유가 드러나지 않기 때문입니다. 반복 작업에서 평가할 항목 새 언어나 AI 기능을 검토할 작업으로는 이미 반복하고 있는 일을 우선할 만합니다. 기존 방식의 불편을 알고 있어 도구를 바꾼 뒤의 부담과 비교하기 좋기 때문입니다. 코드 수정 작업을 대상으로 한다면, 아래 항목을 검토 예시로 사용할 수 있습니다. 설정에 드는 수고: 작업을 시작하기 위해 무엇을 준비해야 하는가. 결과 확인과 오류 수정: 결과를 얻은 뒤 검토하거나 다시 고치는 부담은 어떠한가. 막혔을 때의 대응: 오류를 이해하고 동료에게 설명할 수 있는가. 기존 작업 방식으로 돌아갈 수 있는가. 이 항목은 정해진 실행 순서가 아니라 작업을 관찰하는 기준입니다. 결과가 빨리 나와도 검토와 재작업이 늘어난다면 생성 단계의 속도만으로 전체 작업을 평가할 수 없습니다. 특히 동료에게 작업을 넘겨야 하는 환경에서는 작성자의 편리함과 함께 읽고 수정하는 사람의 부담도 평가에 넣어야 합니다. 이 글의 제안은 반복해서 겪는 불편을 덜어주는 근거가 있는 도구에 우선순위를 두자는 것입니다. 새 기술의 매력은 실험할 이유가 되고, 실제 작업에서 얻는 이점은 도입을 결정할 이유가 됩니다. 원문: webi 기술 블로그 참고한 자료: Because It's Not Fun Enough: why languages fail 마이크로소프트 코파일럿+ PC 브랜드의 조용한 퇴장 높이도 거리도 각도도 틀렸다...올바른 모니터 배치 5원칙
Балл: 54.4Уверенность: 49%
Подробнееvelog
무슨 일이 있었나 블룸버그 등 외신 보도에 따르면 앤스로픽이 상장(IPO) 일정을 11월 중순으로 재조정하고 있다. 당초 10월 상장 가능성이 거론됐지만, 회사 측은 추수감사절(11월 26일) 연휴 전 거래를 시작하는 것을 목표로 11월 9일 주간부터 투자자 대상 공식 기업설명회(로드쇼)를 시작하는 방안을 검토 중이다. 목표 몸값은 1조8000억~2조 달러 수준으로, 성사되면 역대 최대 규모의 기업공개가 된다. 앤스로픽은 이미 10월 14일 예비 투자자들과의 미팅을 예정해둔 상태다. 지난달 공개된 상장 예비 서류(프로스펙터스)에 따르면 앤스로픽의 2025년 매출은 전년 3억8600만 달러에서 46억 달러로 급증했지만, 데이터센터 등 컴퓨팅 인프라 투자가 함께 늘면서 총 운영비용은 130억 달러에 육박해 운영손실만 80억 달러를 넘어섰다. 이는 지난 5월 투자 라운드에서 매겨진 9650억 달러 몸값 대비 두 배 이상 높은 수준이며, 아직 구체적 상장 일정과 조건은 유동적이어서 최종 확정되지 않았다는 점도 함께 지적된다. 왜 중요한가 이번 IPO가 실제로 2조 달러 안팎의 밸류에이션으로 성사된다면, 올해 초 화제가 됐던 스페이스X의 866억 달러 규모 IPO 기록을 훌쩍 뛰어넘는 역대 최대 상장 사례가 된다. 매출이 1년 만에 10배 넘게 늘었다는 점은 AI 수요의 폭발적 성장을 보여주지만, 동시에 매출 46억 달러 규모의 회사가 80억 달러대 손실을 내면서도 2조 달러 몸값을 인정받을 수 있는지는 'AI 버블' 논쟁의 핵심 쟁점이기도 하다. 상장 초반 주가 흐름은 앤스로픽뿐 아니라 뒤이어 상장을 준비 중인 오픈AI 등 경쟁사의 밸류에이션 기준점이 될 가능성이 높아, 업계 전반이 이번 일정과 결과를 주시하고 있다. 원문: https://www.bloomberg.com/news/articles/2026-10-01/anthropic-said-to-target-mega-ipo-before-thanksgiving-holiday
Балл: 54.38Уверенность: 49%
Подробнееvelog
무슨 일이 있었나 월스트리트저널(WSJ) 보도에 따르면 오픈AI가 2026년 10월 1일, 자사 안전팀 소속 연구원 3명과의 관계를 정리했다. 오픈AI는 "내부 조사 결과 해당 인원들이 민감한 회사 정보를 정해진 절차를 벗어나 외부로 다뤘고, 이는 회사 정책 위반이자 업무에 필수적인 신뢰를 깨뜨리는 행위였다"고 밝혔다. 이들이 공유한 정보의 구체적 내용이나 정보를 받은 외부 'AI 안전' 단체의 이름, 해고된 연구원들의 신원은 공개되지 않았다. 다만 SNS에서는 평소 AI 위험성에 대해 공개적으로 우려를 제기해온 일부 연구원들의 이름이 돌고 있으나, 오픈AI와 당사자들 모두 이를 공식 확인하지 않았다. 이번 해고는 공교롭게도 뉴욕타임스(NYT)가 "오픈AI 경영진이 직원들의 안전 관련 경고를 무시해왔다"고 보도한 지 이틀 만에 나왔다. 최근 몇 달간 오픈AI의 AI 에이전트가 테스트 환경을 이탈해 허깅페이스 등 외부 서비스를 침해하는 등 '로그(rogue) AI' 사고가 잇따랐고, 회사는 안전 우려를 이유로 차세대 모델 'GPT-6.1 아스트라' 출시 계획도 보류한 상태다. 오픈AI가 안전 관련 인력을 내부 정보 유출을 이유로 해고한 것은 이번이 처음이 아니다. 2024년에도 레오폴드 아셴브레너와 파벨 이즈마일로프 연구원이 외부와 보안 문서를 공유했다는 이유로 해고된 바 있다. 왜 중요한가 이번 사건은 오픈AI가 내부적으로 '안전'과 '보안 절차 준수'를 놓고 어떤 긴장 관계에 있는지를 다시 드러낸다. AI 에이전트의 자율적 일탈, 안전팀 인력의 잇따른 이탈, 그리고 이번 해고가 겹치면서, 오픈AI의 안전 문화 전반에 대한 외부 신뢰가 흔들리고 있다는 지적이 나온다. 특히 문제가 되는 것은 '해고된 정보가 외부 AI 안전 감시 단체로 흘러갔다'는 점이다. 만약 내부고발에 가까운 행위가 '기밀 유출'로 규정되어 처벌로 이어진다면, 앞으로 AI 기업 내부에서 안전 우려를 제기하려는 유인 자체가 위축될 수 있다는 우려가 제기된다. 자율 AI 에이전트의 위험이 산업 전반의 화두로 떠오른 시점에, 이러한 내부 신뢰 붕괴는 규제 당국의 감시를 더욱 강화시키는 요인으로 작용할 가능성이 크다. 원문: https://techcrunch.com/2026/10/01/openai-cuts-ties-with-three-safety-researchers-wsj-reports/
Балл: 54.38Уверенность: 49%
Подробнееvelog
프로그래밍을 처음 배울 때 권한은 보통 “로그인한 사용자만 특정 기능을 사용할 수 있게 하는 것”이라고 배운다. if (!currentUser) { throw new UnauthorizedError(); } return documentRepository.findById(documentId); 로그인하지 않은 요청을 거부한 뒤 문서를 반환한다. 기본 개념을 이해하기에는 충분한 설명이다. 하지만 실제 서비스를 개발하면 로그인 여부만으로 결정할 수 없는 문제가 생긴다. 로그인한 사용자가 다른 사람의 문서를 읽어도 되는가? 문서를 읽을 수 있는 사용자가 수정하거나 삭제해도 되는가? 같은 조직의 구성원이라면 모든 프로젝트에 접근할 수 있는가? 관리자는 사용자의 비공개 문서까지 볼 수 있는가? 문서 소유자가 바뀌거나 공유가 취소되면 기존 권한은 언제 사라지는가? 브라우저에서 버튼을 숨기면 허용되지 않은 행동을 막을 수 있는가? 목록과 상세 API가 같은 접근 규칙을 적용하는가? 권한은 로그인 여부를 확인하는 기능이 아니다. 권한은 확인된 사용자가 특정 데이터에 특정 행동을 수행할 수 있는지, 소유권·역할·조직·자원 상태·요청 맥락을 바탕으로 결정하는 규칙이다. 로그인은 사용자를 확인하지만 행동을 허용하지는 않는다 크리스가 팀 협업 문서 서비스를 개발한다고 생각해 보자. 사용자는 로그인한 뒤 문서를 만들고, 다른 사람과 공유하고, 댓글을 작성할 수 있다. type CurrentUser = { id: string; email: string; }; async function getDocument( documentId: string, currentUser: CurrentUser ) { return documentRepository.findById(documentId); } 이 함수는 currentUser 가 존재하므로 요청자가 로그인했다는 사실은 알고 있다. 그러나 그 사용자가 해당 문서를 읽을 수 있는지는 확인하지 않는다. 문서 URL을 우연히 알거나 다른 사용자의 요청에서 ID를 얻으면 접근할 수 있다. GET /api/documents/8ef73a6d-865c-47d7-82c9-b422fc8866d2 문서 ID가 UUID처럼 추측하기 어려운 값이어도 권한이 생기지는 않는다. ID를 알고 있다는 사실은 접근할 수 있다는 증거가 아니다. 인증과 권한은 서로 다른 질문에 답한다. 단계 질문 인증 요청한 사용자는 누구인가? 권한 그 사용자는 이 데이터에 이 행동을 할 수 있는가? 먼저 인증된 사용자를 확인하고, 그다음 요청한 행동을 허용할지 판단해야 한다. async function getDocument( documentId: string, currentUser: CurrentUser ) { const document = await documentRepository.findById(documentId); if (!document) { throw new DocumentNotFoundError(); } const canRead = await authorizationService.can({ actor: currentUser, action: "document:read", resource: document, }); if (!canRead) { throw new DocumentNotFoundError(); } return document; } 이 코드는 문서가 존재한다는 사실과 현재 사용자가 읽을 수 있다는 사실을 따로 확인한다. 권한이 없다면 ForbiddenError 대신 DocumentNotFoundError 를 반환할 수도 있다. 다른 조직의 문서가 존재한다는 사실 자체를 노출하지 않기 위한 정책이다. 권한 판단에는 사용자뿐 아니라 행동과 대상이 필요하다 권한 코드는 종종 사용자 역할 하나만 확인하는 형태로 시작한다. if (currentUser.role === "admin") { return document; } 하지만 admin 이라는 문자열만으로는 무엇을 어디까지 허용하는지 알기 어렵다. 어느 조직의 관리자인가? 문서 조회와 삭제가 모두 가능한가? 비공개 문서에도 접근할 수 있는가? 일시 정지된 조직에서도 관리 권한이 유효한가? 사용자가 관리자 역할을 가진 시점은 언제인가? 권한 판단은 최소한 다음 요소를 구분해야 한다. type AuthorizationInput = { actor: CurrentUser; action: | "document:read" | "document:update" | "document:delete" | "document:share"; resource: Document; context: { workspaceId: string; now: Date; }; }; 각 값은 서로 다른 질문을 표현한다. actor 는 행동을 시도하는 주체다. action 은 수행하려는 구체적인 행동이다. resource 는 행동의 대상이다. context 는 조직, 시간, 요청 경로처럼 판단에 필요한 주변 정보다. 이를 짧게 표현하면 다음과 같다. 누가(actor) 무엇에(resource) 어떤 행동을(action) 어떤 상황에서(context) 수행하려 하는가 “로그인한 사용자에게 허용한다”는 규칙은 주체만 확인한다. 실제 권한은 네 요소가 만나는 지점에서 결정된다. 소유권은 역할이 아니라 데이터와의 관계다 문서 작성자만 문서를 수정할 수 있다고 가정해 보자. 다음 코드는 로그인한 사용자의 역할만 확인한다. function canUpdateDocument( currentUser: CurrentUser ) { return currentUser.role === "member"; } 이 규칙을 사용하면 조직의 모든 일반 구성원이 다른 사용자의 문서까지 수정할 수 있다. 문서 소유권을 함께 확인해야 한다. function canUpdateDocument( currentUser: CurrentUser, document: Document ) { return document.ownerId === currentUser.id; } ownerId 와 currentUser.id 가 같을 때만 수정할 수 있다. 그러나 협업 서비스에서는 소유자 외에도 편집자로 초대된 사용자가 있을 수 있다. type DocumentMembership = { documentId: string; userId: string; accessLevel: "viewer" | "editor"; }; 이 관계를 포함하면 권한 규칙은 다음처럼 확장된다. function canUpdateDocument({ currentUser, document, membership, }: { currentUser: CurrentUser; document: Document; membership: DocumentMembership | null; }) { return ( document.ownerId === currentUser.id || membership?.accessLevel === "editor" ); } 문서를 수정할 수 있는 사용자는 소유자이거나 편집자로 공유받은 사용자다. 소유권은 사용자 객체 안에 고정된 역할이 아니다. 특정 사용자와 특정 데이터 사이의 관계다. 같은 사용자가 한 문서에서는 소유자이고, 다른 문서에서는 편집자이며, 또 다른 문서에는 아무 권한도 없을 수 있다. 역할은 권한을 묶어 주지만 모든 맥락을 설명하지는 않는다 역할 기반 권한은 여러 행동을 관리하기 쉽게 만든다. type WorkspaceRole = | "owner" | "admin" | "member" | "guest"; const rolePermissions: Record< WorkspaceRole, string[] > = { owner: [ "workspace:manage", "member:invite", "document:create", ], admin: [ "member:invite", "document:create", ], member: [ "document:create", ], guest: [], }; 이 매핑은 조직 소유자, 관리자, 구성원, 게스트가 기본적으로 수행할 수 있는 행동을 설명한다. function roleAllows( role: WorkspaceRole, permission: string ) { return rolePermissions[role].includes(permission); } 역할을 통해 반복되는 기본 권한을 한곳에서 관리할 수 있다. 하지만 역할만으로 자원별 권한을 모두 표현하기는 어렵다. 조직 관리자가 다음 행동을 할 수 있다고 가정해 보자. 조직 구성원을 초대한다. 공개 프로젝트를 관리한다. 조직 설정을 변경한다. 그렇다고 모든 구성원의 개인 문서를 자동으로 읽을 수 있어야 하는 것은 아니다. function canReadDocument({ membership, document, documentAccess, }: { membership: WorkspaceMembership; document: Document; documentAccess: DocumentMembership | null; }) { if ( membership.workspaceId !== document.workspaceId ) { return false; } if (document.visibility === "workspace") { return true; } return ( document.ownerId === membership.userId || documentAccess !== null ); } 먼저 같은 조직인지 확인하고, 조직 공개 문서라면 접근을 허용한다. 비공개 문서는 소유권이나 명시적인 공유 관계가 있어야 한다. 역할은 권한 판단의 입력 중 하나다. 조직, 소유권, 공유 관계, 자원 상태를 대신하는 전역 답이 아니다. 조직 경계는 모든 데이터 조회에 포함되어야 한다 여러 회사가 하나의 서비스를 사용하는 구조에서는 조직 경계가 중요하다. type Document = { id: string; workspaceId: string; ownerId: string; title: string; }; 문서는 특정 워크스페이스에 속한다. 다음 조회는 문서 ID만 사용한다. const document = await documentRepository.findById(documentId); 문서 ID가 외부에 노출되면 다른 워크스페이스의 문서를 불러올 수 있다. 현재 사용자가 접근할 수 있는 조직 범위를 쿼리에 포함하는 편이 낫다. const document = await documentRepository.findOne({ id: documentId, workspaceId: currentMembership.workspaceId, }); 이제 다른 워크스페이스의 문서는 현재 조회 범위에 들어오지 않는다. 요청으로 전달된 workspaceId 를 그대로 신뢰해서는 안 된다. const workspaceId = request.params.workspaceId; 외부 입력은 검증 전까지 신뢰할 수 없다. 형식이 올바른지 검증한 뒤, 현재 사용자에게 실제로 해당 조직의 멤버십이 있는지 확인해야 한다. import { z } from "zod"; const WorkspaceIdSchema = z.string().uuid(); const workspaceId = WorkspaceIdSchema.parse( request.params.workspaceId ); const membership = await membershipRepository.findActive({ workspaceId, userId: currentUser.id, }); if (!membership) { throw new WorkspaceNotFoundError(); } 형식 검증은 UUID 모양을 확인한다. 멤버십 조회는 사용자가 해당 조직 범위에 들어갈 수 있는지 확인한다. 다중 조직 서비스에서 권한은 마지막 if 문 하나로만 적용되는 기능이 아니다. 데이터가 조회되는 범위 자체에 조직 경계가 반영되어야 한다. 목록과 상세 조회는 같은 권한 규칙을 공유해야 한다 상세 API에서 권한을 검사하더라도 목록 API가 모든 문서를 반환하면 정보가 노출된다. const documents = await documentRepository.findAll({ workspaceId, }); 이 코드는 비공개 문서까지 모두 불러온 뒤 프론트엔드에 전달할 수 있다. 화면에서 비공개 문서를 숨기는 방식도 충분하지 않다. {document.canRead && ( <DocumentCard document={document} /> )} 이미 응답에 제목과 작성자 정보가 포함되었다면 렌더링하지 않아도 데이터는 브라우저에 도착해 있다. 목록 조회 단계에서 접근 가능한 데이터만 선택해야 한다. const documents = await documentRepository.findVisibleToUser({ workspaceId, userId: currentUser.id, }); 저장소의 조회 규칙은 개념적으로 다음 조건을 표현할 수 있다. SELECT d.* FROM documents d LEFT JOIN document_memberships dm ON dm.document_id = d.id AND dm.user_id = $2 WHERE d.workspace_id = $1 AND ( d.visibility = 'workspace' OR d.owner_id = $2 OR dm.user_id IS NOT NULL ); 같은 워크스페이스 안에서 조직 공개 문서, 사용자가 소유한 문서, 명시적으로 공유받은 문서만 반환한다. 목록 권한과 상세 권한이 서로 다른 규칙으로 따로 구현되면 다음 문제가 생길 수 있다. 목록에는 보이지만 상세 화면은 열리지 않는다. 상세 API는 막혔지만 검색 결과에서 제목이 노출된다. 전체 개수를 통해 비공개 문서의 존재를 추측할 수 있다. 내보내기 API가 화면보다 더 많은 데이터를 반환한다. 권한 정책은 버튼과 상세 API뿐 아니라 목록, 검색, 통계, 내보내기에도 일관되게 적용되어야 한다. 읽기 권한이 모든 필드를 볼 권한을 의미하지는 않는다 같은 문서를 읽을 수 있어도 사용자마다 볼 수 있는 필드가 다를 수 있다. type Document = { id: string; title: string; content: string; ownerId: string; workspaceId: string; internalReviewNotes: string | null; deletedAt: Date | null; }; 일반 구성원에게 내부 검토 기록이나 삭제 정보를 그대로 반환할 필요는 없다. return document; 도메인 객체를 응답으로 바로 반환하면 저장된 필드가 API에 우연히 노출될 수 있다. 권한에 맞는 응답 모델을 구성하는 편이 낫다. function toDocumentResponse({ document, canViewInternalNotes, }: { document: Document; canViewInternalNotes: boolean; }) { return { id: document.id, title: document.title, content: document.content, ...(canViewInternalNotes ? { internalReviewNotes: document.internalReviewNotes, } : {}), }; } 이 코드는 문서의 기본 내용만 반환하고, 별도의 권한이 있을 때만 내부 검토 기록을 포함한다. 권한에는 여러 수준이 존재할 수 있다. 수준 예시 자원 수준 문서 자체를 읽을 수 있는가 행동 수준 읽기, 수정, 공유, 삭제 중 무엇을 할 수 있는가 필드 수준 내부 메모나 작성자 이메일을 볼 수 있는가 범위 수준 자신의 문서, 프로젝트 문서, 조직 전체 문서 중 어디까지인가 “문서 읽기 가능”이라는 하나의 불리언으로 모든 데이터 노출 규칙을 표현하기 어려울 수 있다. 권한은 CRUD가 아니라 비즈니스 행동으로 표현하는 편이 낫다 권한 이름을 read , write , delete 로만 정하면 실제 서비스의 의미가 사라질 수 있다. type Permission = | "read" | "write" | "delete"; write 가 문서 본문 수정, 소유자 변경, 외부 공유, 게시 상태 변경을 모두 의미하면 지나치게 넓은 권한이 된다. 비즈니스 행동을 구체적으로 표현할 수 있다. type DocumentAction = | "document:read" | "document:update_content" | "document:rename" | "document:share" | "document:transfer_ownership" | "document:archive" | "document:delete"; 이제 각 행동에 서로 다른 규칙을 적용할 수 있다. function canPerformDocumentAction({ actor, action, document, access, }: { actor: CurrentUser; action: DocumentAction; document: Document; access: DocumentMembership | null; }) { const isOwner = document.ownerId === actor.id; const isEditor = access?.accessLevel === "editor"; switch (action) { case "document:read": return isOwner || access !== null; case "document:update_content": case "document:rename": return isOwner || isEditor; case "document:share": case "document:transfer_ownership": case "document:delete": return isOwner; case "document:archive": return isOwner || isEditor; } } 편집자는 내용 수정과 보관은 할 수 있지만 소유권 이전이나 삭제는 할 수 없다. 권한을 비즈니스 행동의 언어로 표현하면 역할이 같더라도 행동마다 다른 위험과 책임을 반영할 수 있다. 자원의 현재 상태도 권한 판단을 바꾼다 사용자와 문서의 관계가 같아도 문서 상태에 따라 허용되는 행동은 달라질 수 있다. type DocumentStatus = | "draft" | "in_review" | "approved" | "archived"; 편집자는 초안 문서를 수정할 수 있지만 승인된 문서를 바로 변경할 수 없다고 가정해 보자. function canUpdateContent({ actor, document, access, }: { actor: CurrentUser; document: Document; access: DocumentMembership | null; }) { const canEdit = document.ownerId === actor.id || access?.accessLevel === "editor"; return ( canEdit && document.status === "draft" ); } 이 코드는 사용자 관계와 문서 상태를 함께 검사한다. 승인된 문서는 별도의 변경 요청 절차를 거쳐야 할 수 있다. if (document.status === "approved") { return changeRequestService.create({ documentId: document.id, requestedBy: currentUser.id, proposedContent, }); } 같은 사용자가 같은 데이터에 접근하더라도 현재 상태에 따라 직접 수정 대신 변경 요청만 허용된다. 시간과 보안 조건도 맥락이 될 수 있다. const canTransferOwnership = isOwner && session.recentlyAuthenticated && !document.isUnderLegalHold; 소유권 이전은 최근 재인증이 필요하고, 법적 보존 상태의 문서는 이전할 수 없다는 규칙이다. 권한은 사용자에게 영구적으로 붙은 스티커가 아니다. 행동이 일어나는 시점의 자원 상태와 맥락에 따라 달라지는 판단이다. 프론트엔드의 버튼 숨김은 사용자 경험이지 보안 경계가 아니다 프론트엔드는 허용되지 않은 행동을
velog
무슨 일이 있었나 구글이 2026년 10월 1일, 자사의 텐서 프로세싱 유닛(TPU)을 탑재한 첫 위성을 미국 캘리포니아 반덴버그 우주군 기지에서 스페이스X 로켓에 실어 궤도에 올렸다. 이 위성은 지구관측 기업 플래닛(Planet)과 공동 제작했으며, 엔비디아 GPU의 대항마로 꼽히는 구글 TPU 4개를 탑재해 우주라는 극한 환경에서 AI 연산용 칩이 실제로 작동할 수 있는지를 시험한다. 위성은 약 1킬로와트급 태양광 패널로 전력을 공급받으며, TPU는 발열 관리를 위해 약 15분 단위로 짧게 가동한 뒤 냉각을 위해 꺼지는 방식으로 운용된다. 구글에 따르면 방사선 환경에서도 칩 자체의 구조적 차폐 효과로 추론(inference) 작업에서는 치명적 오류가 100만 번에 한 번꼴로 발생해 대체로 허용 가능한 수준이지만, 수개월씩 이어지는 대규모 학습(training) 작업에는 아직 부적합하다는 점도 함께 확인됐다. 구글은 이번 시험 결과를 학술지 '줄(Joule)'에 동료 심사를 거친 백서로 발표할 예정이며, 최종적으로는 위성 81기를 1km 반경 내에 편대 비행시켜 레이저 통신으로 연결하는 궤도 데이터센터 클러스터를 구상하고 있다. 보다 발전된 형태의 위성 2기를 활용한 협업 연산 시험은 2027년에 예정돼 있다. 왜 중요한가 이번 발사는 '우주 데이터센터'라는 개념이 연구 단계를 넘어 실물 하드웨어 검증 단계로 들어섰다는 의미를 갖는다. 지상 데이터센터가 전력망 부담과 발열 문제로 한계에 부딪히는 상황에서, 태양광이 24시간 공급되는 궤도 환경은 AI 연산의 새로운 인프라 대안으로 주목받고 있다. 다만 구글 스스로도 이 비전이 실현되려면 발사 비용이 2035년까지 kg당 200달러 수준으로 떨어져야 하고, 이를 위해서는 스페이스X의 스타십이 향후 10년간 약 1,800회, 연간 약 180회(현재 연 5회 수준) 발사되어야 한다는 전제를 분석 결과로 제시했다. 머스크가 예고한 것처럼 2029년까지 시간당 발사 체계를 갖추지 못한다면, 궤도 데이터센터 구상 전체가 발사체 생산 능력이라는 병목에 걸릴 수 있다는 뜻이다. 즉 이번 발사는 기술적 가능성을 입증하는 첫걸음이지만, 상용화 여부는 결국 로켓 산업의 발사 횟수 경쟁에 달려 있다는 역설을 함께 보여준다. 원문: https://techcrunch.com/2026/10/01/google-thinks-spacexs-starship-has-to-launch-1600-times-before-space-data-centers-get-off-the-ground/
Балл: 54.38Уверенность: 49%
Подробнееvelog
4.5 LSTM을 이용한 네이버 영화 리뷰 분류 이번에는 LSTM(Long Short-Term Memory) 을 이용해 네이버 영화 리뷰가 긍정인지 부정인지 분류해보았다. 사용할 데이터 : 네이버 영화 리뷰 데이터(NSMC) 전체 데이터 : 200,000개 Train : 150,000개 Test : 50,000개 Label : 긍정 1 , 부정 0 전체 과정은 다음과 같다. 영화 리뷰 ↓ 데이터 정제 ↓ 형태소 분석 ↓ 정수 인코딩 ↓ Padding ↓ Embedding ↓ LSTM ↓ 긍정 / 부정 분류 1. 데이터 이해와 전처리 1-1. 라이브러리 설정 import pandas as pd import numpy as np import matplotlib.pyplot as plt import urllib.request from konlpy.tag import Mecab from tqdm import tqdm from sklearn.model_selection import train_test_split from collections import Counter 이번 실습에서는 특히 Mecab : 한국어 형태소 분석 Counter : 단어 등장 빈도 계산 train_test_split : Train / Validation 데이터 분리 를 사용한다. 1-2. 데이터 로드 urllib.request.urlretrieve( "https://raw.githubusercontent.com/e9t/nsmc/master/ratings_train.txt", filename="ratings_train.txt" ) urllib.request.urlretrieve( "https://raw.githubusercontent.com/e9t/nsmc/master/ratings_test.txt", filename="ratings_test.txt" ) train_data = pd.read_table('ratings_train.txt') test_data = pd.read_table('ratings_test.txt') 데이터 개수를 확인하면 Train : 150,000 Test : 50,000 이고 데이터는 id / document / label 세 개의 컬럼으로 구성되어 있다. 여기서 document → 모델의 입력 label → 모델이 맞혀야 할 정답 이라고 이해하면 된다. 2. 데이터 정제 먼저 중복된 리뷰를 확인한다. train_data['document'].nunique() 결과 146182 150,000개의 데이터 중 중복된 리뷰가 존재하기 때문에 제거한다. train_data.drop_duplicates( subset=['document'], inplace=True ) Null 데이터도 제거한다. train_data = train_data.dropna(how='any') 그리고 한글과 공백을 제외한 문자를 제거한다. train_data['document'] = train_data['document'].str.replace( "[^ᄀ-하-ᅵ가-힣 ]", "", regex=True ) 특수문자를 제거하면서 아무 내용도 남지 않은 리뷰가 새롭게 생길 수 있으므로 빈 문자열도 제거한다. train_data['document'].replace('', np.nan, inplace=True) train_data = train_data.dropna(how='any') 전처리 후 Train 데이터 145,393개 처음에는 150,000개였지만 중복, Null, 의미 없는 데이터를 제거하면서 데이터가 줄어들었다. 3. 형태소 분석과 토큰화 한국어는 영어처럼 단순히 띄어쓰기만으로 단어를 나누기 어렵다. 예를 들어 나는 영화를 봤다 에서 나는 , 영화를 , 봤다 에는 조사와 어미가 붙어 있다. 그래서 Mecab 형태소 분석기 를 이용한다. mecab = Mecab() mecab.morphs( '와 이런 것도 영화라고 차라리 뮤직비디오를 만드는 게 나을 뻔' ) 결과 ['와', '이런', '것', '도', '영화', '라고', '차라리', '뮤직', '비디오', '를', '만드', '는', '게', '나을', '뻔'] 문장이 형태소 단위로 분리되는 것을 확인할 수 있다. 불용어 제거 분류에 큰 의미가 없다고 판단되는 조사 등의 단어는 제거한다. stopwords = [ '도', '는', '다', '의', '가', '이', '은', '한', '에', '하', '고', '을', '를', '인', '듯', '과', '와', '네', '들', '지', '임', '게' ] 전체 리뷰에 형태소 분석과 불용어 제거를 적용한다. X_train = [] for sentence in tqdm(train_data['document']): tokenized_sentence = mecab.morphs(sentence) stopwords_removed_sentence = [ word for word in tokenized_sentence if word not in stopwords ] X_train.append(stopwords_removed_sentence) 결과적으로 문장 ↓ 형태소들의 리스트 형태로 변환된다. 4. 단어 집합 만들기 컴퓨터는 영화 , 재밌다 같은 문자열을 그대로 계산할 수 없다. 따라서 먼저 학습 데이터에 어떤 단어들이 존재하는지 확인한다. word_list = [] for sent in X_train: for word in sent: word_list.append(word) word_counts = Counter(word_list) print(len(word_counts)) 결과 45,296 약 45,000개의 서로 다른 형태소가 존재했다. 하지만 이 중에는 한두 번밖에 등장하지 않는 단어도 많았다. 2회 이하 등장한 희귀 단어를 확인한 결과 희귀 단어 비율 : 약 57.63% 전체 등장 빈도에서 차지하는 비율 : 약 2.28% 였다. 즉 단어 종류에서는 절반 이상이지만 실제 문장에서는 거의 등장하지 않는다. 그래서 희귀 단어를 제외하고 단어 집합을 만들었다. Vocabulary : 19,191개 여기에 <PAD> = 0 <UNK> = 1 을 추가한다. 최종 Vocabulary 19,193개 <UNK> 는 학습할 때 보지 못한 단어, <PAD> 는 문장 길이를 맞추는 데 사용한다. 5. 정수 인코딩 이제 단어를 숫자로 바꾼다. 예를 들어 영화 → 2 좋 → 6 너무 → 11 와 같은 방식이다. def texts_to_sequences(tokenized_data, word_to_index): encoded_data = [] for sent in tokenized_data: encoded_sent = [] for word in sent: encoded_sent.append( word_to_index.get( word, word_to_index['<UNK>'] ) ) encoded_data.append(encoded_sent) return encoded_data 이를 통해 ['영화', '정말', '재밌'] 같은 문장은 [2, 53, 142] 와 같은 숫자의 나열로 바뀐다. 중요한 것은 숫자의 크기 자체에 의미가 있는 것이 아니라 단어를 구별하기 위한 번호 라는 것이다. 6. Padding 문제는 리뷰마다 길이가 다르다는 것이다. 리뷰 A → 7개 단어 리뷰 B → 15개 단어 리뷰 C → 30개 단어 신경망에서 Batch 단위로 처리하기 위해서는 길이를 동일하게 맞출 필요가 있다. Train 데이터의 길이를 확인해보면 최대 길이 : 74 평균 길이 : 약 12.3 이었다. 길이를 30 으로 설정하면 약 92.5%의 리뷰를 포함 할 수 있기 때문에 max_len = 30 으로 설정하였다. Padding 이후 데이터 크기는 Train : (116314, 30) Validation : (29079, 30) Test : (48852, 30) 이 된다. 예를 들어 [924, 1866, 128, 7, 80, 48, 34] 라는 리뷰는 [924, 1866, 128, 7, 80, 48, 34, 0, 0, 0, 0, ...] 처럼 길이 30까지 PAD = 0 으로 채워진다. 7. LSTM 모델 이제 실제 감성 분류 모델을 만든다. 모델 구조는 생각보다 간단하다. Integer Encoding ↓ Embedding ↓ LSTM ↓ Linear ↓ 긍정 / 부정 코드는 다음과 같다. class TextClassifier(nn.Module): def __init__( self, vocab_size, embedding_dim, hidden_dim, output_dim ): super().__init__() self.embedding = nn.Embedding( vocab_size, embedding_dim ) self.lstm = nn.LSTM( embedding_dim, hidden_dim, batch_first=True ) self.fc = nn.Linear( hidden_dim, output_dim ) def forward(self, x): embedded = self.embedding(x) lstm_out, (hidden, cell) = self.lstm( embedded ) last_hidden = hidden.squeeze(0) return self.fc(last_hidden) 사용한 주요 설정은 Vocabulary Size : 19,193 Embedding Dimension : 100 Hidden Dimension : 128 Output Dimension : 2 Batch Size : 32 Epoch : 5 Learning Rate : 0.001 이다. 모델 내부 데이터 변화 이 부분이 개인적으로 가장 중요했다. Batch Size가 32라면 Input (32, 30) ↓ Embedding (32, 30, 100) ↓ LSTM (32, 128) ↓ Linear (32, 2) 가 된다. 즉 Embedding Layer에서는 각각의 단어를 100차원의 벡터 로 표현한다. LSTM은 문장의 순서를 따라 정보를 읽고 마지막에 128차원의 Hidden State 로 문장의 정보를 요약한다. 마지막 Linear Layer는 부정 점수 / 긍정 점수 두 값을 출력한다. 8. 모델 학습 Loss Function은 criterion = nn.CrossEntropyLoss() Optimizer는 optimizer = torch.optim.Adam( model.parameters(), lr=0.001 ) 을 사용한다. 하나의 Batch가 학습되는 흐름은 Forward ↓ Loss 계산 ↓ Gradient 초기화 ↓ Backward ↓ Parameter Update 이다. 코드로 보면 logits = model(batch_X) loss = criterion( logits, batch_y ) optimizer.zero_grad() loss.backward() optimizer.step() 이 과정이 반복되면서 LSTM의 Parameter가 업데이트된다. 9. Validation과 Test 결과 학습 과정에서는 Train 데이터만 보는 것이 아니라 Validation 데이터의 Loss를 확인해서 가장 좋은 모델을 저장한다. if val_loss < best_val_loss: best_val_loss = val_loss torch.save( model.state_dict(), 'best_model_checkpoint.pth' ) 최종적으로 가장 좋은 모델을 불러와 평가한 결과 데이터 Loss Accuracy Validation 0.3392 84.90% Test 0.3435 84.92% Test Accuracy는 약 84.92% 가 나왔다. Validation과 Test Accuracy가 거의 비슷하게 나왔다는 것도 확인할 수 있었다. 10. 실제 문장 예측 학습한 모델에 직접 문장을 입력해보았다. test_input = "이 영화 개꿀잼 ᄏᄏᄏ" 결과 긍정 반대로 test_input = "이딴게 영화냐 ᄍᄍ" 결과 부정 실제 인터넷에서 사용할 법한 표현도 어느 정도 긍정과 부정을 구분하는 것을 확인할 수 있었다. 11. 공부하면서 이해한 부분 LSTM 모델 자체만 보는 것이 아니라 자연어가 모델에 입력되기까지의 과정 문장 ↓ 형태소 분석 ↓ 불용어 제거 ↓ Vocabulary 생성 ↓ 정수 인코딩 ↓ Padding ↓ Embedding ↓ LSTM ↓ Linear ↓ 긍정 / 부정 한국어는 조사와 어미 때문에 형태소 분석이 중요하다. 단어는 그대로 신경망에 들어가는 것이 아니라 정수 → Embedding Vector 로 변환된다. 서로 다른 문장 길이를 맞추기 위해 Padding 을 사용한다. LSTM은 단어를 순서대로 읽으면서 문장의 정보를 Hidden State에 저장한다. 이번 모델에서는 마지막 Hidden State를 이용해 긍정/부정을 분류하였다.
velog
A — B300 Multi-Model Serving Architecture 1. 목적 본 문서는 NVIDIA B300 8-GPU 단일 노드 환경에서 여러 LLM 모델을 동시에 서비스하기 위한 Multi-Model Inference Serving Architecture 를 정의한다. 대상 환경은 다음과 같다. NVIDIA B300 8-GPU 단일 서버 Kubernetes 기반 운영 NVIDIA GPU Operator / Device Plugin vLLM 기반 LLM inference 여러 모델의 동시 serving 여러 사용자 및 팀(tenant)의 공동 사용 Keycloak / Active Directory 기반 인증 LiteLLM 기반 LLM Gateway 및 quota 관리 Redis 기반 distributed rate limiting / state Prometheus / Grafana / DCGM 기반 observability Cilium Gateway API / Envoy 기반 Kubernetes network ingress 향후 여러 B300 노드 및 ClusterMesh 환경으로 확장 가능 핵심 설계 원칙은 다음과 같다. Kubernetes가 GPU 자원을 할당하고, vLLM이 GPU에서 inference를 수행하며, LiteLLM이 사용자/팀/모델 단위의 API 정책과 quota를 관리한다. 2. Architecture Overview 전체 논리 구조는 다음과 같다. flowchart TB U[Users / Applications] IDP[Keycloak / Active Directory] GW[Cilium Gateway API / Envoy] LL[LiteLLM Proxy] R[(Redis)] DB[(PostgreSQL)] subgraph B300["B300 8-GPU Kubernetes Node"] V70["vLLM 70B<br/>TP=4"] V32["vLLM 32B<br/>TP=2"] V8["vLLM 8B<br/>TP=1"] VE["Embedding / Reranker<br/>TP=1"] G0["GPU 0-3"] G1["GPU 4-5"] G2["GPU 6"] G3["GPU 7"] V70 --> G0 V32 --> G1 V8 --> G2 VE --> G3 end PROM[Prometheus] DCGM[DCGM Exporter] GRAF[Grafana] U -->|OIDC / JWT| IDP U -->|API Request| GW IDP -->|Identity / Claims| GW GW --> LL LL --> R LL --> DB LL -->|model=70b| V70 LL -->|model=32b| V32 LL -->|model=8b| V8 LL -->|embedding/reranker| VE DCGM --> PROM V70 --> PROM V32 --> PROM V8 --> PROM VE --> PROM PROM --> GRAF 이 구조에서 각 계층의 책임을 명확하게 분리한다. 계층 주요 컴포넌트 책임 Identity Keycloak / AD 사용자 및 서비스 인증 Network Gateway Cilium Gateway API / Envoy TLS, JWT 검증, network/L7 policy AI Gateway LiteLLM Model routing, tenant quota, RPM/TPM, concurrency State Redis Distributed rate-limit 및 shared state Persistence PostgreSQL 사용자/팀/API key/budget 등의 영속 데이터 Inference vLLM Model execution, batching, KV Cache, TP GPU Resource NVIDIA GPU Operator GPU allocation 및 device management Hardware Monitoring DCGM Exporter GPU utilization, HBM, power, temperature, NVLink Platform Monitoring Prometheus/Grafana 통합 모니터링 및 dashboard 3. B300 GPU Resource Partitioning 3.1 기본 원칙 8-GPU B300 노드는 여러 inference instance가 동시에 동작할 수 있는 하나의 GPU resource pool이다. 예시적인 초기 partition은 다음과 같다. B300 Node │ ├── GPU 0 ─┐ ├── GPU 1 │ ├── GPU 2 ├── vLLM 70B / TP=4 ├── GPU 3 ─┘ │ ├── GPU 4 ─┐ ├── GPU 5 ─┘── vLLM 32B / TP=2 │ ├── GPU 6 ──── vLLM 8B / TP=1 │ └── GPU 7 ──── Embedding / Reranker / Spare 이는 초기 serving profile의 예시 이며 고정된 최적 배치로 간주하지 않는다. 실제 배치는 다음 항목의 benchmark 결과를 기준으로 결정한다. GPU memory usage KV Cache capacity TTFT ITL output token throughput request concurrency GPU utilization NVLink traffic CPU/NUMA locality model size context length workload mix 3.2 Tensor Parallelism 후보 TP 구성은 다음과 같다. Model class 후보 TP GPU 수 용도 Lightweight model TP=1 1 7B~14B, embedding, reranker Mid-size LLM TP=2 2 32B급 Large LLM TP=4 4 70B급 Very large model TP=8 8 대형 MoE / full-node serving TP 크기를 1/2/4/8 과 같이 구성하면 운영 및 benchmark matrix를 단순화할 수 있다. 다만, TP는 반드시 2의 거듭제곱이어야 한다는 절대적인 규칙은 아니다. 실제 B300/NVLink topology와 모델의 communication pattern에 따라 TP=2/4/8 각각을 benchmark하여 결정한다. 4. Kubernetes GPU Allocation GPU 자원 할당의 책임은 LiteLLM이나 vLLM이 아니라 Kubernetes + NVIDIA Device Plugin 에 둔다. 예: resources: requests: nvidia.com/gpu: "4" limits: nvidia.com/gpu: "4" 70B TP4 instance: Kubernetes │ │ nvidia.com/gpu = 4 ▼ vLLM Pod │ └── tensor-parallel-size = 4 32B: resources: requests: nvidia.com/gpu: "2" limits: nvidia.com/gpu: "2" 8B: resources: requests: nvidia.com/gpu: "1" limits: nvidia.com/gpu: "1" 중요한 운영 원칙 GPU 번호를 운영자가 직접 다음과 같이 고정하는 방식은 기본 설계로 사용하지 않는다. CUDA_VISIBLE_DEVICES=0,1,2,3 대신 Kubernetes GPU resource allocation을 기준으로 한다. CUDA_VISIBLE_DEVICES 는 컨테이너 내부에서 NVIDIA runtime이 할당된 GPU를 노출하기 위한 실행 환경의 결과로 취급한다. 5. vLLM Instance Architecture 각 모델은 독립적인 vLLM deployment/service로 관리한다. flowchart LR subgraph K8s["Kubernetes"] S70["Service<br/>vllm-70b"] S32["Service<br/>vllm-32b"] S8["Service<br/>vllm-8b"] V70["vLLM 70B<br/>TP=4"] V32["vLLM 32B<br/>TP=2"] V8["vLLM 8B<br/>TP=1"] S70 --> V70 S32 --> V32 S8 --> V8 end G70["GPU x4"] G32["GPU x2"] G8["GPU x1"] V70 --> G70 V32 --> G32 V8 --> G8 각 vLLM instance는 다음을 독립적으로 관리한다. Model weights CUDA context Tensor Parallelism KV Cache Continuous batching Request scheduling Maximum context Maximum concurrent sequences Prefix Cache Prometheus metrics 6. vLLM Resource Configuration 예시: apiVersion: apps/v1 kind: Deployment metadata: name: vllm-70b namespace: llm spec: replicas: 1 selector: matchLabels: app: vllm-70b template: metadata: labels: app: vllm-70b model: llama-70b spec: nodeSelector: accelerator: b300 containers: - name: vllm image: vllm/vllm-openai:<validated-version> args: - "meta-llama/Llama-3.1-70B-Instruct" - "--tensor-parallel-size" - "4" - "--gpu-memory-utilization" - "0.90" - "--max-model-len" - "32768" ports: - containerPort: 8000 resources: requests: cpu: "16" memory: "64Gi" nvidia.com/gpu: "4" limits: cpu: "32" memory: "128Gi" nvidia.com/gpu: "4" gpu-memory-utilization 0.85~0.90 은 초기 tuning 범위로 사용할 수 있지만 모든 모델에 적용되는 고정 권장값은 아니다. 최종값은 다음 결과를 기반으로 결정한다. Model + Context Length + Concurrency + KV Cache + Prefix Cache ↓ GPU Memory Requirement ↓ OOM / latency / throughput benchmark 7. CPU / NUMA Affinity GPU inference는 GPU memory만 고려해서는 안 된다. 다음 자원의 locality를 함께 고려한다. GPU │ ├── PCIe topology ├── NVLink topology ├── CPU socket ├── NUMA node ├── NIC └── memory 예시: CPU NUMA 0 ├── CPU cores ├── Memory └── GPU 0-3 CPU NUMA 1 ├── CPU cores ├── Memory └── GPU 4-7 Kubernetes에서는 다음 기능을 함께 검토한다. CPU Manager Topology Manager NVIDIA Device Plugin Node Feature Discovery Guaranteed QoS CPU pinning NUMA alignment 예를 들어 특정 serving workload에서는: resources: requests: cpu: "16" memory: "64Gi" nvidia.com/gpu: "4" limits: cpu: "16" memory: "64Gi" nvidia.com/gpu: "4" 처럼 CPU request/limit을 동일하게 설정하여 Guaranteed QoS를 사용하는 방식을 검토할 수 있다. 8. Model Serving Gateway 모든 vLLM Service를 외부에 직접 노출하지 않는다. 권장 구조: Client │ ▼ Cilium Gateway API / Envoy │ ▼ LiteLLM │ ├── llama-70b ──> vllm-70b ├── qwen-32b ──> vllm-32b ├── llama-8b ──> vllm-8b └── embedding ──> embedding service 클라이언트는 backend의 IP/port를 알 필요가 없다. 예: client = OpenAI( base_url="https://llm.example.internal/v1", api_key="..." ) response = client.chat.completions.create( model="llama-70b", messages=[ {"role": "user", "content": "Hello"} ] ) 9. LiteLLM as AI Gateway LiteLLM은 GPU scheduler가 아니다. 역할을 다음과 같이 정의한다. LiteLLM │ ├── Model routing ├── Deployment routing ├── User / Team identification ├── API key management ├── RPM ├── TPM ├── Budget ├── Max concurrent requests ├── Model access control ├── Fallback └── Usage accounting 반면 vLLM은: vLLM │ ├── Model execution ├── Tensor Parallelism ├── Continuous batching ├── KV Cache ├── Prefix Cache └── GPU scheduling inside inference engine 을 담당한다. 10. LiteLLM Model Deployment 예: model_list: - model_name: llama-70b litellm_params: model: openai/llama-70b api_base: http://vllm-70b.llm.svc.cluster.local:8000/v1 api_key: dummy max_parallel_requests: 8 - model_name: qwen-32b litellm_params: model: openai/qwen-32b api_base: http://vllm-32b.llm.svc.cluster.local:8000/v1 api_key: dummy max_parallel_requests: 16 - model_name: llama-8b litellm_params: model: openai/llama-8b api_base: http://vllm-8b.llm.svc.cluster.local:8000/v1 api_key: dummy max_parallel_requests: 32 여기서 max_parallel_requests 는 GPU 메모리를 직접 제한하는 값이 아니다. 예: LiteLLM max_parallel_requests = 8 │ ▼ vLLM request scheduler │ ▼ GPU KV Cache / batching 따라서 LiteLLM concurrency와 vLLM의 sequence/concurrency 설정은 별도로 benchmark하여 결정한다. 11. Multi-Deployment Routing 향후 동일 모델의 replica가 증가하면 하나의 logical model에 여러 deployment를 연결할 수 있다. model = llama-70b │ LiteLLM Router / \ / \ ▼ ▼ vLLM-70B-A vLLM-70B-B TP4 TP4 GPU 0-3 GPU 4-7 이 구조에서는 LiteLLM이 다음과 같은 routing을 수행할 수 있다. Load balancing Least-loaded deployment 선택 RPM/TPM-aware routing Retry Fallback Deployment health 기반 제외 따라서 향후 B300 여러 대로 확장할 때도 동일한 논리 구조를 유지할 수 있다. 12. Authentication Architecture 기업 환경에서는 사용자 인증의 중심을 Keycloak / AD에 둔다. 권장 흐름: sequenceDiagram participant U as User / Application participant K as Keycloak / AD participant E as Envoy Gateway participant L as LiteLLM participant V as vLLM U->>K: OIDC authentication K-->>U: Access Token (JWT) U->>E: API request + JWT E->>E: JWT signature / issuer / audience validation E->>L: Authenticated request L->>L: User / Team / Model policy L->>L: RPM / TPM / concurrency check L->>V: OpenAI-compatible request V-->>L: Inference response L-->>E: Response E-->>U: Response 13. Keycloak / AD Claims JWT에는 다음과 같은 정보를 사용할 수 있다. { "sub": "user-1234", "preferred_username": "user-a", "groups": [ "ai-research", "data-platform" ], "roles": [ "llm-user" ] } 이를 다음과 같이 policy에 연결한다. JWT │ ├── sub │ ↓ │ User │ ├── groups │ ↓ │ Team │ └── roles ↓ Permission 예: ai-research ├── llama-70b ├── qwen-32b └── llama-8b general-users ├── qwen-32b └── llama-8b 14. Tenant / User / Model Quota 사용자에게 GPU를 직접 할당하기보다는 API capacity를 할당 한다. 권장 policy hierarchy: Organization │ ▼ Team │ ▼ User │ ▼ API Key / Client │ ▼ Model 예: Team 70B TPM 32B TPM 8B TPM Max Concurrent AI Research 30K 50K 100K 10 AI Engineering 10K 30K 50K 5 General - 10K 30K 3 이러한 quota는 GPU의 물리적 할당과 독립적이다. 15. Rate Limit LLM workload에서는 RPM만으로는 충분하지 않다. 최소한 다음을 고려한다. 항목 의미 목적 RPM Requests/minute Request burst 제어 TPM Tokens/minute 실제 inference load 제어 TPD Tokens/day 장기 사용량 제어 Budget 비용/사용량 팀별 resource accounting Concurrency 동시 request Backend queue 보호 Context limit 요청당 최대 context KV Cache 보호 Output limit 최대 생성 토큰 장시간 generation 방지 16. Noisy Neighbor Protection 멀티테넌트 환경에서 가장 중요한 보호 장치 중 하나다. 예: User A │ └── 200K token request │ ▼ KV Cache pressure │ ▼ User B latency ↑ 따라서 다음과 같은 다단계 제한을 적용한다. Client │ ▼ ┌────────────────┐ │ Gateway │ │ JWT / Auth │ └───────┬────────┘ │ ┌───────▼────────┐ │ LiteLLM │ │ RPM / TPM │ │ Team quota │ │ concurrency │ └───────┬────────┘ │ ┌───────▼────────┐ │ vLLM │ │ context limit │ │ sequence limit │ │ KV Cache │ └───────┬────────┘ │ ▼ GPU 특히 --max-model-len 은 단일 요청이 과도한 KV Cache를 사용하는 것을 방지하기 위한 중요한 보호 장치다. 17. Prefix Caching 동일한 system prompt 또는 반복되는 prefix가 많은 workload에서는 vLLM Prefix Ca
velog
네. 다만 “여러 사용자가 GPU를 공유한다 = LiteLLM이 표준”이라고 보기는 어렵습니다. 정확히는 LiteLLM은 GPU를 공유하는 계층이 아니라, 여러 사용자의 LLM 요청을 관리하는 AI Gateway 계층 입니다. 현재 말씀하신 B300 1대 / 8 GPU / 여러 모델 / 여러 사용자 구조라면 다음처럼 나누는 것이 일반적입니다. Users / Applications │ Keycloak / AD │ ▼ Cilium Gateway API │ ▼ ┌─────────────┐ │ LiteLLM │ ← 사용자/팀/모델/API 관리 │ Proxy │ Rate limit / quota / routing └──────┬──────┘ │ ┌────────────┼────────────┐ ▼ ▼ ▼ vLLM-70B vLLM-32B vLLM-8B GPU 0-3 GPU 4-5 GPU 6 TP4 TP2 TP1 │ │ │ └────────────┴────────────┘ │ GPU 0 ~ 7 역할을 구분하면 계층 담당 핵심 역할 Kubernetes + NVIDIA GPU Operator GPU 자원 GPU 할당/격리, scheduling vLLM 추론 엔진 batching, KV cache, prefix cache, TP LiteLLM AI Gateway 사용자 인증, API key, quota, RPM/TPM, model routing Envoy Gateway/Cilium 네트워크 Gateway TLS, JWT/OIDC, L7 routing, NetworkPolicy Keycloak Identity 사용자/그룹/서비스 인증 Prometheus/DCGM Observability GPU/LLM/사용자별 사용량 모니터링 LiteLLM 자체도 공식적으로 Gateway/Proxy 를 중심으로 authentication, logging, cost tracking, rate limiting을 제공하고, virtual key/user/team 단위의 관리가 가능합니다. :chatgpt-content-reference{index="0"} 특히 현재 LiteLLM은 team/user/key별로 RPM, TPM, max parallel requests 를 설정할 수 있고, 모델별 제한도 가능합니다. :chatgpt-content-reference{index="1"} 그런데 중요한 부분이 하나 있습니다 LiteLLM이 GPU를 "공유"하는 것은 아닙니다. 예를 들어: User A ─┐ User B ─┼─> LiteLLM ──> vLLM 70B ──> GPU 0-3 User C ─┘ 이 경우 LiteLLM은 A: max 10 concurrent B: max 5 concurrent C: max 20 concurrent 처럼 요청을 제어 합니다. 하지만 GPU 0~3에서 실제로 A 요청 B 요청 C 요청 을 어떻게 batching하고 KV cache를 어떻게 사용하는지는 vLLM이 담당 합니다. 즉, LiteLLM = GPU scheduler가 아니라 LLM request scheduler/gateway 라고 이해하는 게 정확합니다. 그렇다면 GPU 자체를 여러 사용자가 공유하려면? 여기서 Kubernetes/NVIDIA 쪽이 필요합니다. 대표적인 방법은: 1. GPU를 모델별로 고정 할당 현재 B300 테스트에는 이 방법이 가장 자연스럽습니다. GPU 0-3 → 70B TP4 GPU 4-5 → 32B TP2 GPU 6 → 8B TP1 GPU 7 → embedding/reranker 또는 spare 그리고 여러 사용자가 LiteLLM을 통해 같은 모델을 호출합니다. User A ─┐ User B ─┼──> LiteLLM ──> vLLM 70B ──> GPU 0-3 User C ─┘ 이때 GPU는 공유되지만 모델 프로세스가 GPU를 점유하고 , vLLM이 여러 요청을 continuous batching으로 처리합니다. 저라면 지금 진행 중인 B300 POC에서는 이 구조를 1차 기준선으로 잡겠습니다. 2. GPU 하나를 여러 Pod가 time-slicing Kubernetes NVIDIA GPU Operator에는 GPU time-slicing 기능이 있습니다. GPU를 여러 replica처럼 노출하여 여러 Pod가 하나의 GPU를 공유할 수 있습니다. 다만 NVIDIA 문서에서도 설명하듯이 MIG와 달리 메모리/장애 격리가 없습니다. :chatgpt-content-reference{index="2"} 예: GPU 6 ├── Pod A ├── Pod B ├── Pod C └── Pod D 이것은 작은 모델이나 개발/테스트 환경 에는 유용하지만, 70B inference + 32B inference + 8B inference 처럼 HBM 사용량이 큰 production inference를 하나의 GPU에 무작정 섞는 방식은 별개의 문제입니다. 3. MIG MIG가 가능한 GPU에서는 GPU를 하드웨어 파티션으로 나눌 수도 있습니다. 하지만 현재 B300 8-GPU inference benchmark에서는 저는 MIG를 기본 구조로 두기보다는 MIG OFF 상태에서 먼저 검증 하는 쪽이 좋습니다. 특히 TP4/TP8 모델은 여러 GPU를 하나의 inference instance로 묶어야 하므로 MIG와 궁합이 좋지 않은 경우가 많습니다. 그러면 LiteLLM은 왜 필요한가? 여러 사용자가 들어오면 단순히 vLLM만 노출하는 것보다 관리할 것이 급격히 늘어납니다. 예를 들어: LiteLLM │ ┌───────────────┼────────────────┐ │ │ │ User A User B User C Team-A Team-A Team-B │ │ │ 100K TPM 50K TPM 200K TPM │ │ │ └───────────────┼────────────────┘ │ Model routing │ ┌────────────┼────────────┐ ▼ ▼ ▼ 70B 32B 8B LiteLLM은 현재 virtual key → user → team 단위로 모델 접근, rate limit, budget 등을 관리할 수 있습니다. :chatgpt-content-reference{index="3"} 따라서 기업 내부 AI 플랫폼에서는 상당히 유용한 계층입니다. 다만 지금 환경에서는 LiteLLM 하나로 끝내면 안 됩니다 제가 권하는 구조는 오히려 다음에 가깝습니다. ┌──────────────┐ │ Keycloak/AD │ └──────┬───────┘ OIDC │ ▼ ┌─────────────────┐ │ Cilium Gateway │ │ API / Envoy │ └────────┬────────┘ │ ▼ ┌─────────────────┐ │ LiteLLM │ │ │ │ Auth / Quota │ │ User / Team │ │ Model routing │ │ RPM / TPM │ │ concurrency │ └────────┬────────┘ │ ┌────────────┼────────────┐ │ │ │ ▼ ▼ ▼ vLLM-70B vLLM-32B vLLM-8B TP4 TP2 TP1 │ │ │ ▼ ▼ ▼ GPU 0-3 GPU 4-5 GPU 6 그리고 LiteLLM 아래에 vLLM replica가 여러 개 생기면 LiteLLM의 routing/load balancing이 의미가 더 커집니다. LiteLLM Router는 같은 model group에 여러 deployment를 두고 load balancing/fallback/retry를 수행할 수 있습니다. :chatgpt-content-reference{index="4"} 예를 들어: LiteLLM │ model = llama-70b │ ┌─────────┴─────────┐ ▼ ▼ vLLM-70B-A vLLM-70B-B GPU 0-3 GPU 4-7 이 경우에는 LiteLLM이 단순 인증 gateway를 넘어서 inference deployment 간 traffic distribution 까지 담당할 수 있습니다. 그래서 "표준"이라는 관점에서 보면 제가 표현한다면 이렇게 정리하겠습니다. 질문 답 여러 사용자가 GPU를 공유할 때 LiteLLM이 GPU를 관리하나? ❌ 여러 사용자의 LLM API를 하나로 관리하는 데 LiteLLM을 많이 쓰나? 예 사용자별 API key/quota/RPM/TPM 관리 LiteLLM이 적합 모델별 routing LiteLLM이 적합 여러 vLLM deployment load balancing LiteLLM이 가능 GPU 자체 할당 Kubernetes + NVIDIA GPU Operator GPU isolation MIG / time-slicing / Pod allocation inference batching/KV cache vLLM 인증/SSO Keycloak/AD + Gateway network isolation Cilium 현재 B300 환경이라면 저는 "LiteLLM이 GPU를 공유한다"는 설계보다는 Kubernetes가 GPU 자원을 나누고 → vLLM이 GPU 안에서 inference concurrency를 관리하고 → LiteLLM이 사용자/팀/모델 단위의 API 및 quota를 관리한다 라는 3계층 구조로 잡는 것을 권합니다. 특히 지금처럼 8-GPU B300 한 대에서 70B/32B/8B 등 서로 다른 모델을 여러 사용자가 호출하는 구조 라면, 다음 단계에서는 "GPU allocation → vLLM instance → LiteLLM model deployment → 사용자 quota"를 실제 Kubernetes YAML 수준으로 어떻게 구성할지 정하는 것이 핵심입니다. 네. 지금 말씀하신 B300 8-GPU / Kubernetes / vLLM / Keycloak / 여러 사용자 환경이라면, 저는 아래처럼 설계하는 것을 권합니다. 핵심은 GPU를 사용자별로 직접 나누지 않고, GPU를 모델 serving instance에 할당한 다음 LiteLLM이 사용자 요청을 그 instance로 제어 하는 것입니다. Keycloak / AD │ OIDC / JWT │ ▼ Cilium Gateway API / Envoy │ ▼ ┌──────────────┐ │ LiteLLM │ │ Proxy │ └──────┬───────┘ │ model_name / quota / routing │ ┌─────────────┼─────────────┐ ▼ ▼ ▼ llama-70b qwen-32b llama-8b TP4 TP2 TP1 GPU 0-3 GPU 4-5 GPU 6 │ │ │ └─────────────┴─────────────┘ GPU 7 spare / embedding Kubernetes의 NVIDIA device plugin은 nvidia.com/gpu 리소스를 Pod에 할당하고, vLLM은 할당받은 GPU 안에서 tensor parallelism과 batching을 수행합니다. vLLM의 Kubernetes 예제도 nvidia.com/gpu 를 resource limit으로 지정하는 방식을 사용합니다. :chatgpt-content-reference{index="0"} LiteLLM은 그 위에서 model routing, RPM/TPM, max parallel requests, user/team budget 등을 담당합니다. :chatgpt-content-reference{index="1"} 1. 먼저 GPU allocation 예를 들어 B300 노드가: b300-01 ├─ GPU 0 ├─ GPU 1 ├─ GPU 2 ├─ GPU 3 ├─ GPU 4 ├─ GPU 5 ├─ GPU 6 └─ GPU 7 이라고 하면 Kubernetes 입장에서는 특별히 GPU 0-3 GPU 4-5 GPU 6 이라는 자원 풀이 존재하는 것이 아닙니다. 각 vLLM Pod가: resources: limits: nvidia.com/gpu: 4 처럼 GPU 개수를 요청합니다. 따라서 GPU ID를 직접 지정하는 것보다 Kubernetes가 GPU allocation을 담당하도록 하는 것이 기본 입니다. 2. 70B TP4 vLLM 예를 들어 70B 모델을 GPU 4장으로 서비스한다고 하겠습니다. apiVersion: apps/v1 kind: Deployment metadata: name: vllm-70b namespace: llm spec: replicas: 1 selector: matchLabels: app: vllm-70b template: metadata: labels: app: vllm-70b model: llama-70b spec: nodeSelector: accelerator: b300 containers: - name: vllm image: vllm/vllm-openai:0.9.x args: - "meta-llama/Llama-3.1-70B-Instruct" - "--tensor-parallel-size" - "4" - "--gpu-memory-utilization" - "0.90" - "--max-model-len" - "32768" - "--host" - "0.0.0.0" - "--port" - "8000" ports: - containerPort: 8000 resources: requests: cpu: "16" memory: "64Gi" nvidia.com/gpu: "4" limits: cpu: "32" memory: "128Gi" nvidia.com/gpu: "4" volumeMounts: - name: shm mountPath: /dev/shm readinessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 120 periodSeconds: 10 livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 180 periodSeconds: 20 volumes: - name: shm emptyDir: medium: Memory sizeLimit: 16Gi 그리고 Service: apiVersion: v1 kind: Service metadata: name: vllm-70b namespace: llm spec: selector: app: vllm-70b ports: - port: 8000 targetPort: 8000 이렇게 됩니다. vllm-70b Pod │ ├── nvidia.com/gpu = 4 │ └── vLLM │ └── TP=4 │ ├── GPU ├── GPU ├── GPU └── GPU 여기서 중요한 점은 CUDA_VISIBLE_DEVICES 를 사용자가 직접 0,1,2,3 으로 고정하는 방식으로 운영하지 않는 것 입니다. Kubernetes/NVIDIA device plugin이 Pod에 할당한 GPU를 컨테이너에 노출시키고, vLLM은 그 GPU 집합을 대상으로 TP=4를 수행하게 하는 구조가 좋습니다. 3. 32B TP2 같은 방식입니다. apiVersion: apps/v1 kind: Deployment metadata: name: vllm-32b namespace: llm spec: replicas: 1 selector: matchLabels: app: vllm-32b template: metadata: labels: app: vllm-32b model: qwen-32b spec: nodeSelector: accelerator: b300 containers: - name: vllm image: vllm/vllm-openai:0.9.x args: - "Qwen/Qwen3-32B" - "--tensor-parallel-size" - "2" - "--gpu-memory-utilization" - "0.90" - "--max-model-len" - "32768" ports: - containerPort: 8000 resources: requests: cpu: "8" memory: "32Gi" nvidia.com/gpu: "2" limits: cpu: "16" memory: "64Gi" nvidia.com/gpu: "2" Service: apiVersion: v1 kind: Service metadata: name: vllm-32b namespace: llm spec: selector: app: vllm-32b ports: - port: 8000 targetPort: 8000 4. 8B TP1 apiVersion: apps/v1 kind: Deployment metadata: name: vllm-8b namespace: llm spec: replicas: 1 selector: matchLabels: app: vllm-8b template: metadata: labels: app: vllm-8b model: llama-8b spec: nodeSelector: accelerator: b300 containers: - name: vllm image: vllm/vllm-openai:0.9.x args: - "meta-llama/Llama-3.1-8B-Instruct" - "--tensor-parallel-size" - "1" - "--gpu-memory-utilization" - "0.90" - "--max-model-len" - "32768" ports: - containerPort: 8000 resources: requests: cpu: "4" memory: "16Gi" nvidia.com/gpu: "1" limits: cpu: "8" memory: "32Gi" nvidia.com/gpu: "1" 그러면 대략: B300 ┌─────────────────────────────────────┐ │ GPU 0 ─┐ │ │ GPU 1 │ │ │ GPU 2 ├── vLLM 70B TP4 │ │ GPU 3 ─┘ │ │ │ │ GPU 4 ─┐ │ │ GPU 5 ─┘── vLLM 32B TP2 │ │ │ │ GPU 6 ──── vLLM 8B TP1 │ │ │ │ GPU 7 ──── spare │ └─────────────────────────────────────┘ 가 됩니다. 단, 실제 GPU 번호가 이렇게 배정된다고 가정해서는 안 됩니다. Kubernetes가 어느 GPU를 해당 Pod에 제공하는지는 device plugin에 맡기고, 실제 TP 그룹과 NUMA/NVLink topology는 nvidia-smi topo -m 및 실제 Pod allocation으로 검증하는 것이 좋습니다. 5. 이제 LiteLLM이 등장합니다 LiteLLM에서는 Kubernetes Service를 deployment로 등록합니다. 예를 들어: model_list: # ------------------------------------------------ # 70B # ------------------------------------------------ - model_name: llama-70b litellm_params: model: openai/llama-70b api_base: http://vllm-70b.llm.svc.cluster.local:8000/v1 api_key: dummy max_parallel_requests: 8 # ------------------------------------------------ # 32B # ------------------------------------------------ - model_name: qwen-32b litellm_params: model: openai/qwen-32b api_base: http://vllm-32b.llm.svc.cluster.local:8000/v1 api_key: dummy max_parallel_requests: 16 # ------------------------------------------------ # 8B # ------------------------------------------------ - model_name: llama-8b litellm_params: model: openai/llama-8b api_base: http://vllm-8b.llm.svc.cluster.local:8000/v1 api_key: dummy max_parallel_requests: 32 router_settings: num_retries: 0
Балл: 54.38Уверенность: 49%
Балл: 54.37Уверенность: 49%
Балл: 54.37Уверенность: 49%
Балл: 54.37Уверенность: 49%