1편에서 캡셔닝과 임베딩의 차이를 정리하고 나서, 바로 다음에 부딪힌 질문이 있었다. 그래서 어떤 VLM을 쓸 건데. 처음에는 이 질문을 너무 가볍게 봤다. 어차피 비슷한 모델들일 텐데 인기 많은 걸로 고르면 되겠지 싶었다. 그런데 실제로 후보군을 놓고 벤치마크를 돌려보니, 같은 회로도 이미지를 넣어도 모델에 따라 캡션 품질이 확연히 갈렸다. 어떤 모델은 다이어그램 안의 화살표 방향을 완전히 반대로 읽었고, 어떤 모델은 표 안의 숫자를 아예 무시하고 뭉뚱그려 설명했다. 게다가 모델 선택은 vLLM 서빙 구성과도 직결되는 문제였다. 텍스트 전용 LLM을 서빙할 때 짜놨던 설정을 그대로 가져다 썼다가 GPU 메모리가 순식간에 터진 경험도 있다. 이번 글에서는 VLM을 고를 때 실무에서 진짜 봐야 하는 기준과, vLLM으로 멀티모달 모델을 서빙할 때 텍스트 서빙과 무엇이 다른지를 정리해보려 한다. 벤치마크 표를 훑어보고 점수 높은 모델을 고르는 것과, 실제로 우리 서버에 올려서 안정적으로 돌리는 것 사이에는 생각보다 큰 간극이 있다는 걸 이번 과정에서 뼈저리게 배웠다.
VLM을 고를 때 진짜 봐야 하는 기준
먼저 오픈소스와 상용 API 사이의 선택부터 짚어야 한다. GPT-4V 계열이나 Claude의 비전 기능은 캡셔닝 품질 자체는 대체로 안정적이다. 별도 인프라를 구축할 필요 없이 API 호출 몇 줄이면 끝난다는 점도 매력적이다. 그런데 문서 수천 건, 이미지 수만 장을 한 번에 처리해야 하는 인덱싱 작업에서는 비용이 순식간에 불어난다. 게다가 사내 문서에 민감 정보가 섞여 있는 경우, 이미지를 외부 API로 보내는 것 자체가 보안 정책에 걸리는 조직도 많다. 이런 이유로 나는 인덱싱 단계의 대량 캡셔닝은 오픈소스 VLM을 자체 서빙하는 쪽으로, 사용자 질의 시점의 실시간 이미지 이해는 응답 품질이 더 중요하니 상용 API를 섞어 쓰는 하이브리드 구성을 선호한다. 이 구분 없이 하나의 모델로 모든 걸 해결하려 하면 비용과 품질 둘 다 애매해지는 경우를 여러 번 봤다.
라이선스 조건도 생각보다 중요한 변수다. 오픈소스라고 해서 다 같은 오픈소스가 아니다. 어떤 모델은 상업적 이용에 제한이 없지만, 어떤 모델은 월간 활성 사용자 규모나 특정 산업군에 따라 별도 라이선스 협의가 필요하다. 실제로 후보 모델 하나를 팀 내부에서 거의 확정 단계까지 검토했다가, 라이선스 조항을 뒤늦게 확인하고 방향을 바꾼 적이 있다. 모델 선정 초기 단계에서 성능만 보지 말고 라이선스 문서를 먼저 읽는 습관이 필요하다는 걸 그때 배웠다.
Qwen 계열 VLM의 변천사와 실무 체감 차이
오픈소스 VLM 중에서 내가 가장 오래 써본 건 Qwen 계열이다. Qwen2-VL부터 시작해서 지금은 Qwen2.5-VL, 그리고 최신 Qwen3-VL까지 세대가 빠르게 넘어갔다. Qwen2-VL 시절에는 이미지 해상도를 고정된 크기로 리사이즈해서 넣어야 했는데, 이 과정에서 작은 텍스트나 세밀한 다이어그램 정보가 뭉개지는 문제가 있었다. Qwen2.5-VL부터는 동적 해상도 처리가 개선되면서 원본 이미지의 종횡비를 유지한 채로 처리할 수 있게 됐고, 표나 문서 구조를 이해하는 능력도 눈에 띄게 좋아졌다. 실제로 회로도 캡셔닝 작업을 Qwen2-VL에서 Qwen2.5-VL로 옮기고 나서, 화살표 방향을 잘못 읽던 오류가 눈에 띄게 줄었다.
최근 나온 Qwen3-VL은 여기서 한 단계 더 나아갔다. 단순히 이미지를 설명하는 수준을 넘어서, 화면 안의 UI 요소를 인식하고 실제로 조작하는 것 같은 에이전틱 능력까지 갖추기 시작했다. 대형 모델 라인업과 경량 모델 라인업이 함께 제공되기 때문에, 인덱싱용으로는 가벼운 버전을 배치 처리에 쓰고, 실시간 질의 응답에는 더 큰 버전을 쓰는 식으로 용도별 조합도 가능해졌다. 다만 최신 모델일수록 vLLM 쪽 지원이 안정화되는 데 시간이 걸리는 경우가 있어서, 나는 신규 모델이 나오면 프로덕션에 바로 올리기보다 한두 세대 앞선 안정 버전으로 먼저 파일럿을 돌려보는 편이다. 새 모델의 벤치마크 수치만 보고 성급하게 전환했다가, 정작 vLLM 쪽 통합 코드가 아직 실험 단계라 배포 파이프라인에서 예상치 못한 오류가 계속 터진 적이 있다. 특히 이미지 전처리 파라미터 이름이 버전마다 조금씩 바뀌는 경우가 있어서, 마이그레이션할 때마다 설정 파일을 하나하나 다시 확인해야 했다.
버전 간 체감 차이 중에서 가장 크게 느꼈던 건 문서형 이미지, 그러니까 스캔한 계약서나 표 형태의 자료를 처리하는 정확도였다. 초기 버전에서는 표의 행과 열 구조를 텍스트로 풀어낼 때 셀 경계를 자주 놓쳤는데, 최근 버전으로 올수록 이 부분이 눈에 띄게 안정됐다. 사내 계약서 검토 파이프라인에 VLM 캡셔닝을 붙이면서 이 차이를 직접 확인했고, 결국 문서형 이미지 비중이 높은 프로젝트라면 모델 세대 선택이 품질에 미치는 영향이 생각보다 크다는 결론에 이르렀다.
InternVL과 LLaVA, 그리고 상용 모델과의 격차
Qwen 계열 말고도 InternVL 시리즈를 실무에서 검토한 적이 있다. InternVL은 처음부터 이미지와 텍스트를 함께 학습하는 네이티브 멀티모달 방식을 쓰는데, 이 부분이 텍스트 전용 LLM에 비전 인코더를 나중에 붙이는 방식과 근본적으로 다르다. 후자를 대표하는 게 LLaVA 계열이다. LLaVA는 비전 인코더와 언어 모델을 각각 따로 학습한 다음 어댑터로 연결하는 구조라서, 구현이 상대적으로 단순하고 커스터마이징하기도 쉽다. 반면 이미지와 텍스트 사이의 깊은 정렬이 필요한 작업에서는 네이티브 학습 방식인 InternVL 쪽이 더 안정적인 결과를 보여줬다.
상용 모델과의 격차는 예전만큼 크지 않다는 게 요즘 실무에서 느끼는 체감이다. 몇 년 전만 해도 오픈소스 VLM은 상용 모델 대비 확실히 뒤처졌는데, 최근 세대로 넘어오면서 일반적인 문서 이해나 OCR 수준의 작업에서는 격차가 많이 좁혀졌다. 다만 복잡한 추론이 필요한 이미지, 예를 들어 여러 장의 이미지를 비교하면서 맥락을 종합해야 하는 질의에서는 여전히 상용 모델이 앞서는 경우가 많다. 이 지점에서 다시 한번 하이브리드 구성이 현실적인 답이 된다.
모델을 고를 때 벤치마크 점수만큼이나 중요하게 보는 게 커뮤니티 활성도와 vLLM 통합 성숙도다. 아무리 벤치마크가 좋아도 vLLM에서 제대로 지원되지 않으면 자체 서빙이 사실상 불가능하거나, 지원되더라도 최적화가 덜 되어 처리량이 형편없이 나오는 경우가 있다. 나는 새 모델을 검토할 때 항상 vLLM 저장소의 이슈 트래커부터 확인한다. 해당 모델 관련 이슈가 활발히 논의되고 있고 최근에 병합된 PR이 많다면, 그만큼 커뮤니티에서 실전 검증이 진행 중이라는 신호로 받아들인다.
vLLM에서 멀티모달 모델을 서빙할 때 텍스트 서빙과 다른 점
여기서부터가 진짜 실무의 영역이다. 텍스트 전용 LLM을 vLLM으로 서빙할 때는 프롬프트를 토큰화해서 프리필하고, 이후 디코딩 단계로 넘어가는 흐름이 단순하다. 그런데 멀티모달 모델은 이미지를 먼저 비전 인코더에 통과시켜서 이미지 토큰으로 변환하는 단계가 앞에 하나 더 붙는다. 이 인코딩 단계는 텍스트 프리필과 성격이 완전히 다른 연산이라서, 같은 GPU 안에서 두 작업을 어떻게 스케줄링하느냐에 따라 처리량이 크게 갈린다. 최근 vLLM 커뮤니티에서는 인코딩, 프리필, 디코딩 세 단계를 아예 분리해서 서로 다른 자원에 배치하는 방향으로 발전하고 있는데, 이게 왜 필요한지는 직접 운영해보면 바로 체감된다. 이미지가 많이 섞인 요청과 텍스트만 있는 요청이 같은 배치에 섞여 들어오면, 인코딩 단계에서 병목이 생겨서 텍스트만 있는 요청까지 덩달아 느려진다.
메모리 관점에서도 신경 쓸 게 하나 늘어난다. 텍스트 전용 모델은 KV 캐시 크기만 잘 잡으면 되는데, 멀티모달 모델은 여기에 비전 인코더가 처리하는 이미지 토큰 수까지 얹힌다. 이미지 한 장이 해상도에 따라 수백에서 수천 개의 토큰으로 변환될 수 있어서, 요청마다 이미지 개수와 해상도가 들쭉날쭉하면 메모리 사용량 예측이 훨씬 어려워진다. 내가 Azure에서 텐서 병렬 설정을 텍스트 모델 기준으로 그대로 가져다 멀티모달 모델에 적용했다가 GPU 메모리가 터진 것도 이 지점을 간과해서였다. 이미지 토큰까지 감안해서 배치 크기와 최대 시퀀스 길이를 다시 계산해야 한다는 걸 그 사고 이후로 뼈저리게 배웠다.
이 사고를 겪고 나서 내가 취한 조치는 크게 두 가지였다. 하나는 요청 단위로 이미지 개수와 예상 토큰 수를 미리 계산해서, 특정 임계값을 넘는 요청은 별도 큐로 분리하는 것이었다. 두 번째는 최대 배치 크기를 텍스트 모델 기준값에서 상당히 보수적으로 낮춰서, 이미지가 많이 섞인 순간에도 메모리 여유분이 남아 있도록 만든 것이다. 처음에는 이렇게 하면 전체 처리량이 떨어질까 걱정했는데, 실제로는 크래시로 인한 재시작과 큐 적체가 줄면서 오히려 안정적인 처리량이 나왔다. 안정성과 처리량은 트레이드오프처럼 보이지만, 크래시가 반복되는 상황에서는 보수적인 설정이 결과적으로 더 나은 처리량을 만든다는 걸 실감했다.
실제 배포에서 만난 문제들
배치 처리 관점에서 하나 더 짚을 부분이 있다. 인덱싱 단계에서 이미지 수천 장을 한 번에 캡셔닝할 때, 모든 요청을 동시에 던지면 서버가 감당을 못 한다. 나는 동시 요청 수를 제한하고, 이미지 해상도를 사전에 일정 기준으로 정규화한 다음에 vLLM 서버로 보내는 전처리 레이어를 따로 뒀다. 이 전처리 레이어가 없었을 때는 어쩌다 고해상도 스캔 이미지가 하나 섞여 들어오면 그 요청 하나 때문에 큐 전체가 밀리는 상황이 자주 벌어졌다. 최대 픽셀 수를 제한하는 옵션을 모델 쪽에서 지원하긴 하지만, 서버에 부담을 주기 전에 애플리케이션 레벨에서 먼저 걸러주는 게 운영 안정성 측면에서 훨씬 낫다.
또 하나, 실시간 질의 응답 경로와 배치 인덱싱 경로를 같은 vLLM 인스턴스로 묶어서 운영하다가 곤란해진 적이 있다. 사용자가 이미지를 올리고 즉시 답을 기다리는 요청과, 백그라운드에서 수천 장을 순차 처리하는 배치 작업이 같은 GPU 큐를 두고 경쟁하면, 사용자 체감 지연이 들쭉날쭉해진다. 결국 인스턴스를 분리해서, 실시간 경로는 지연에 민감한 설정으로, 배치 경로는 처리량 위주 설정으로 따로 운영하는 구조로 바꿨다. 인프라 비용은 조금 늘었지만 사용자 경험과 운영 안정성 모두 확실히 개선됐다.
이미지 전처리 레이어를 설계할 때 놓치기 쉬운 부분이 하나 더 있다. PDF에서 추출한 이미지 중에는 실질적으로 의미 없는 장식용 아이콘이나 로고가 섞여 있는 경우가 많다. 이런 이미지까지 전부 VLM에 태워서 캡셔닝하면 처리 비용만 늘어나고 검색 품질에는 도움이 안 된다. 나는 이미지 크기와 종횡비를 기준으로 1차 필터링을 걸어서, 일정 크기 이하이거나 극단적으로 가로세로 비율이 치우친 이미지는 캡셔닝 대상에서 제외했다. 이 필터 하나만으로도 전체 처리량의 상당 부분을 줄일 수 있었고, 결과적으로 진짜 의미 있는 이미지에 컴퓨팅 자원을 더 집중할 수 있었다.
장애 대응 측면에서도 배운 게 있다. VLM 서버가 특정 이미지 하나 때문에 응답을 반환하지 못하고 계속 대기 상태에 걸리는 경우가 간헐적으로 발생했다. 원인을 추적해보니 손상된 이미지 파일이나 극단적으로 큰 해상도의 이미지가 인코더 단계에서 무한정 시간을 잡아먹는 패턴이었다. 이후로는 모든 VLM 호출에 타임아웃을 명시적으로 걸고, 타임아웃이 발생한 요청은 실패로 처리한 뒤 재시도 큐로 넘기는 구조를 추가했다. 사소해 보이지만 이런 방어 로직이 없으면 이미지 한 장 때문에 전체 배치 작업이 몇 시간씩 멈춰 서는 상황을 겪게 된다.
그래서 어떤 모델을 고르면 되나
정리하면 이렇다. 문서 안의 이미지를 대량으로 캡셔닝해야 하는 인덱싱 작업이라면, 최신 세대보다 한두 버전 앞선 안정적인 오픈소스 VLM을 자체 서빙하는 게 비용과 안정성 면에서 유리하다. 사용자가 실시간으로 이미지를 들고 와서 복잡한 질의를 던지는 경로라면, 비용을 조금 더 쓰더라도 상용 모델의 안정적인 품질을 섞는 편이 사용자 경험에는 낫다. vLLM으로 직접 서빙하기로 했다면, 텍스트 모델 서빙 경험을 그대로 옮겨오지 말고 이미지 인코딩 단계의 자원 소모와 요청별 이미지 토큰 편차를 처음부터 별도로 설계에 반영해야 한다. 이 세 가지를 프로젝트 초반에 명확히 정해두면, 이후 모델을 교체하거나 스케일을 늘릴 때 훨씬 수월하다.
결론, 모델 선택은 서빙 전략과 함께 결정해야 한다
VLM 선택을 단순히 벤치마크 점수 비교로 끝내면 안 된다는 게 이번 과정에서 가장 크게 배운 점이다. 같은 모델이라도 어떤 방식으로 서빙하느냐에 따라 실제 체감 성능과 운영 비용이 완전히 달라진다. 모델 자체의 캡셔닝 품질, 오픈소스와 상용 API 사이의 트레이드오프, 그리고 vLLM에서 인코딩과 프리필 단계를 어떻게 분리해서 자원을 배분할지까지 한 세트로 고민해야 실제로 쓸 만한 시스템이 나온다. 다음 글에서는 이렇게 준비된 모델을 가지고 실시간 이미지 질의 아키텍처를 어떻게 설계하고 프로덕션에 배포하는지를 다뤄보려 한다.
돌이켜보면 이번 과정에서 겪은 시행착오는 대부분 텍스트 서빙 경험을 그대로 옮겨오려고 했던 데서 시작됐다. 텍스트 모델을 오래 운영해본 사람일수록 오히려 이 함정에 빠지기 쉽다고 생각한다. KV 캐시 크기 계산이나 배치 스케줄링에 익숙하다는 자신감이, 이미지 인코딩이라는 완전히 다른 성격의 연산을 과소평가하게 만들기 때문이다. 나도 처음에는 어차피 vLLM이니까 설정 몇 개만 바꾸면 되겠지 하는 마음으로 시작했다가, 결국 아키텍처 단위로 다시 설계해야 했다. 멀티모달 서빙을 준비하는 팀이 있다면, 기존 텍스트 서빙 경험을 참고는 하되 처음부터 별도의 검증 단계를 거치라고 권하고 싶다.