happy_various AI 실전 기록

LLM 중계기 개발기 1부 · 3편 / 전체 33편

2026년 10월 1일 기준

이 글에는 제휴 링크가 없고 OpenAI·앤트로픽·NVIDIA·LM Studio와 아무 관계가 없습니다. 제가 직접 만든 중계기의 개발 기록을 바탕으로 썼습니다. 삽화는 GPT 이미지 생성, 도식은 직접 제작했습니다.

‘OpenAI 호환’은 왜 표준 콘센트가 됐나 — 모양은 같은데 전압이 살짝 다를 때

우리나라 집에서는 어느 방에 가도 콘센트 모양이 같습니다. 새로 산 헤어드라이어를 들고 와서 아무 콘센트에나 꽂으면 그냥 돌아가요. 모양도, 전압(220V)도 정해져 있으니까요. 가전을 만드는 쪽은 이 모양에 맞춰 플러그를 만들고, 집을 짓는 쪽은 이 모양으로 콘센트를 답니다. 서로 상대를 몰라도 되는 거죠.

그런데 모양만 같고 전압이 살짝 다르다면 어떨까요. 플러그는 쏙 들어가는데 드라이어 바람이 약하거나, 엉뚱하게 돌 수도 있을 거예요.

AI 세계에도 이런 표준 콘센트가 있습니다. 바로 ‘OpenAI 호환’이라는 형식이에요. 제가 만든 LLM 중계기도 이 콘센트 모양으로 창구를 열었고, 덕분에 많은 것을 거저 얻었습니다. 대신 전압이 살짝 다른 곳들을 하나씩 맞추느라 꽤 애를 먹었어요.

이 글은 LLM 중계기 개발기의 3편입니다. 지난 2편 ‘중계기란 무엇인가’에서 여러 AI를 한 창구 뒤에 세우는 이야기를 했다면, 이번에는 그 창구가 왜 하필 ‘OpenAI 호환’ 모양인지, 그리고 ‘호환’이라는 말을 어디까지 믿을 수 있는지를 다룹니다.

서로 다른 나라에서 온 로봇들이 제각각인 플러그를 들고 큰 콘센트 하나 앞에 줄을 선다 (GPT 이미지 생성)

결론 요약

📨 1. 프로그램이 AI에게 보내는 ‘편지’의 모양

프로그램이 AI에게 일을 시킬 때는 정해진 모양의 편지를 보냅니다. 개발자들은 이 편지를 요청(request)이라고 불러요. OpenAI 형식의 대화 요청에서 중심이 되는 칸은 세 개입니다.

① 받는 AI — 어느 모델에게 보낼지, 모델 이름을 적습니다

② 지금까지의 대화 — 누가 무슨 말을 했는지 순서대로 적은 목록이에요. ‘역할 지시’, ‘사용자’, ‘AI’가 각자 한 말을 줄줄이 담습니다

③ 받는 방식 — 답을 다 만든 뒤 한꺼번에 받을지, 만들어지는 대로 조금씩 흘려 받을지(스트리밍)를 고릅니다

예를 들어 회의록 요약을 시키는 편지는 이런 모양이에요.

  • 받는 AI — Claude의 한 모델
  • 대화 — [역할 지시] 너는 회의록을 짧게 정리하는 도우미야 → [사용자] 이 회의록을 세 줄로 요약해 줘 (회의록 본문 첨부)
  • 받는 방식 — 조금씩 흘려 받기

답장도 정해진 모양으로 옵니다. AI가 쓴 답 본문과 함께, 왜 거기서 멈췄는지를 적은 끝난 이유 칸이 붙어 와요. 이 칸은 4절에서 다시 나옵니다.

재미있는 점이 하나 있어요. 이 형식에서는 보통 요청할 때마다 지금까지의 대화 전체를 다시 담아 보냅니다. AI가 앞선 대화를 기억해 주는 게 아니라, 편지에 대화 기록을 통째로 동봉하는 방식이에요.

🔌 2. 왜 이 모양이 ‘표준 콘센트’가 됐나

OpenAI는 ChatGPT를 만든 곳이고, 이 대화 형식은 OpenAI가 자기 AI를 프로그램에서 부를 수 있게 내놓은 것입니다. 이 형식이 널리 쓰이면서, 이 모양에 맞춰 만든 프로그램과 도구가 많이 쌓였어요.

그러자 다른 곳들도 같은 모양을 따르는 경우가 흔해졌습니다. 콘센트 규격이 정해지면 새로 나오는 가전이 그 플러그를 다는 것과 비슷해요. 새 AI 프로그램이 이 모양으로 창구를 열면, 이미 이 모양을 아는 프로그램들이 따로 고치지 않고도 붙을 수 있으니까요.

제가 중계기에 연결한 것 중에도 그런 예가 있습니다.

반대로 이 모양을 말하지 않는 AI도 있어요. Codex와 Claude의 명령어 도구는 사람이 터미널에서 쓰라고 만든 것이라, OpenAI 모양의 편지를 받는 창구가 없습니다. 이쪽은 중계기가 번역을 맡아야 했어요(3절).

이름 때문에 헷갈리기 쉬운 점도 하나 짚어 둘게요. ‘OpenAI 호환’은 OpenAI의 AI를 쓴다는 뜻이 아니라, OpenAI가 정한 편지 모양을 따른다는 뜻입니다. 220V 콘센트를 쓴다고 해서 특정 발전소의 전기만 쓰는 게 아닌 것처럼요.

🧩 3. 중계기가 이 콘센트를 고른 이유

중계기는 첫 버전부터 창구를 이 모양으로 열었습니다. 창구는 크게 둘이에요. “지금 쓸 수 있는 모델이 뭐가 있나요?”에 답하는 모델 목록 창구, 그리고 1절에서 본 편지를 받는 대화 창구입니다.

그 덕분에 쓰는 쪽 프로그램이 할 일이 아주 적어졌어요.

뒤쪽에서는 번역이 일어납니다.

통역사 로봇이 두 로봇 사이에서 빛나는 편지를 건네준다 (GPT 이미지 생성)

다만 처음부터 약속한 범위가 넓지는 않았어요. 중계기 설명서에 적어 둔 공통 약속은 받는 AI, 대화, 받는 방식 세 칸이 중심입니다. 답 길이 제한이나 답의 무작위성(temperature) 같은 설정은 그 AI가 지원하는 범위에서만 적용되고, 도구 목록 같은 고급 칸은 공통 약속에 넣지 않았어요. 콘센트 모양은 맞춰 줬지만, 그 뒤로 흐르는 전기까지 똑같다고 장담하지는 않은 셈이죠.

왼쪽 프로그램들이 중계기의 OpenAI 호환 창구에 꽂히고, 중계기가 플러그 모양이 다른 AI 다섯 곳으로 번역해 보낸다. 아래에 호환의 빈틈 4가지 (직접 제작)

⚡ 4. 모양은 같은데 전압이 살짝 다르다 — 호환의 빈틈 4가지

로봇 기술자가 똑같아 보이는 콘센트 세 개를 측정기로 재며 고개를 갸웃한다 (GPT 이미지 생성)

실제로 써 보니 같은 콘센트에 꽂혀 있어도 AI마다 미묘하게 달랐습니다. 그중 중계기가 직접 손봐야 했던 네 가지를 골랐어요.

① 끝난 이유 — ‘다 했음’인지 ‘잘렸음’인지

답장의 끝난 이유 칸에는 보통 둘 중 하나가 적힙니다. 할 말을 다 해서 멈췄다(stop), 아니면 정해 둔 분량에 걸려 잘렸다(length).

처음 만든 중계기는 한꺼번에 받는 답장의 이 칸에 늘 ‘다 했음’을 적었습니다. 그래서 한 AI 서버가 “분량 때문에 잘렸다”고 알려 줘도, 쓰는 쪽 프로그램은 잘린 답을 완성된 답으로 알았어요. 개발 둘째 날, AI가 알려 준 값을 그대로 전달하도록 고쳤습니다.

일주일쯤 뒤에는 Claude와 Codex 쪽도 손봤어요. Claude는 같은 뜻을 다른 낱말로 말합니다. 분량 초과는 ‘max_tokens’, 정상 종료는 ‘end_turn’이라고 하죠. 중계기가 이걸 OpenAI 형식의 낱말로 바꿔 적습니다. 지금은 모델마다의 특성표에 “이 AI가 알려 주는 끝난 이유를 믿을 수 있는지”도 함께 적고, 확인되지 않은 AI는 ‘모름’으로 표시해요. 이 이야기는 4부에서 따로 자세히 다룹니다.

② 생각 과정 — 같은 내용, 세 가지 포장

답하기 전에 먼저 생각을 하는 AI들이 있어요. 문제는 그 생각을 어디에 담아 보내느냐가 제각각이었다는 점입니다.

처음 중계기는 첫 번째 칸을 그냥 버렸어요. 그런데 생각에도 출력 분량이 들어서, 생각을 길게 하다 정작 답이 잘리는 일이 생겼습니다. 생각 칸이 버려졌으니 프로그램은 왜 잘렸는지 알 수 없었죠. 개발 둘째 날 이 칸을 그대로 전달하고, 생각에 쓴 분량을 기록에 경고로 남기게 고쳤습니다.

이름이 다른 칸은 원래 이름 그대로 보존해서 넘기게 했고(개발 일주일째), 본문 앞에 섞여 오는 생각은 한 달쯤 뒤에 중계기가 앞머리의 꼬리표 부분만 떼어 생각 칸으로 옮기게 했어요. 그대로 두면 생각이 답인 척 새어 나오고, 쓰는 프로그램마다 그걸 각자 떼어 내야 하니까요.

③ 빈 도구 목록 — ‘없음’을 말하는 방법의 차이

요청에는 AI가 쓸 수 있는 도구(웹 검색 등)를 적는 칸도 있습니다. “이번엔 도구를 쓰지 마”라고 하고 싶을 때 이 칸에 빈 목록을 보내기도 해요.

이걸 ‘도구 없음’으로 알아듣는 AI도 있지만, 한 AI 서버는 “목록이 비어 있으면 안 된다”며 요청 자체를 거절했습니다. 개발 막바지인 9월 말의 일이에요. 해결은 단순했습니다. OpenAI 모양으로 말하는 AI 서버에 보낼 때는 빈 목록을 아예 빼고 보냅니다. 칸이 없어도 뜻은 똑같이 ‘도구 없음’이니까요. 반대로 Claude 같은 명령어 도구에는 빈 목록을 그대로 전해서, 기본으로 켜져 있는 도구를 끄게 합니다. 같은 뜻을 상대가 알아듣는 모양으로 바꿔 보내는 거예요.

설정 칸에서도 비슷한 일이 있었어요. 생각하는 AI 중에는 답의 무작위성 설정(temperature)을 받지 않고 거절하는 경우가 있어서, 중계기는 거절당한 설정만 빼고 한 번 다시 보냅니다. 다만 답 길이 제한처럼 결과의 뜻을 바꾸는 설정은 함부로 빼지 않고, 원래 오류를 그대로 돌려줘요.

④ 거절 이유 — 오류의 모양도 제각각

AI가 요청을 거절할 때는 이유를 적어 보내는데, 그 모양이 AI마다 다릅니다. 어떤 곳은 정해진 칸에, 어떤 곳은 다른 이름의 칸에, 어떤 곳은 그냥 글로 보내요.

첫날의 중계기는 이유가 예상한 모양이 아니면 버리고, “HTTP 400”이라는 번호 한 줄만 전달했습니다. ‘요청이 잘못됐다’는 뜻의 번호일 뿐, 무엇이 잘못됐는지는 빠져 있었죠. 그날 바로 고쳤어요. 이제는 원문을 통째로 보관하고, 여러 모양 가운데서 사람이 읽을 이유 문장을 골라 OpenAI 모양의 오류에 담되, 원문도 함께 붙여 보냅니다.

다음 날에는 반대쪽 사고가 있었어요. 오류를 받긴 했는데 기록에 남길 때 앞부분만 잘라 두는 바람에, Codex가 보낸 “더 새 버전으로 업데이트하라”는 정작 중요한 안내가 잘려 나갔습니다. 진짜 원인이 이렇게 잘려 사라진 게 벌써 세 번째여서, 그 뒤로는 오류를 자르지 않는다는 규칙과 그걸 확인하는 자동 검사를 함께 만들었어요. 이 이야기도 4부에서 자세히 하겠습니다.

🧭 5. 모양을 맞추는 일과 전압을 맞추는 일

정리하면 ‘OpenAI 호환’은 콘센트 모양을 맞추는 약속이었어요. 그 덕분에 중계기는 주소 한 줄로 어떤 프로그램이든 받아들일 수 있었습니다. 하지만 전압, 그러니까 칸 하나하나의 뜻과 쓰임은 AI마다 조금씩 달랐죠.

이 차이를 다루면서 남긴 규칙이 세 가지 있습니다.

① 믿을 수 있는지 모르면 그렇다고 적어 둔다 — 끝난 이유를 확인하지 못한 AI는 스펙 카드에 ‘모름’으로 표시합니다. 답장 칸은 여전히 ‘다 했음’이 기본값이라, 쓰는 쪽은 카드를 함께 봐야 해요(16편에서 자세히)

② 원문은 버리지 않는다 — 생각 칸도, 거절 이유도 일단 그대로 전합니다

③ 같은 뜻이면 상대가 알아듣는 모양으로 바꿔 보낸다 — 빈 도구 목록처럼요

중계기가 모든 차이를 숨길 수는 없어서, 중계기에 프로그램을 붙이는 사람을 위한 연결 안내서도 따로 써 두었습니다. “끝난 이유가 ‘잘림’이면 완성된 답으로 저장하지 말 것”, “본문이 비어 있으면 생각 칸을 확인할 것”, “오류에 붙은 원문을 볼 것” 같은 내용이에요. 콘센트 옆에 붙여 둔 “이 콘센트는 이런 점이 다릅니다” 안내문인 셈입니다.

정리

① ‘OpenAI 호환’은 OpenAI의 AI를 쓴다는 뜻이 아니라 OpenAI가 정한 대화 편지의 모양을 따른다는 뜻이고, 널리 쓰이다 보니 표준 콘센트처럼 됐어요 ② 중계기는 이 모양으로 창구를 열어서, 쓰는 쪽은 주소 한 줄만 바꾸고 뒤쪽 번역은 중계기가 맡아요 ③ 하지만 끝난 이유·생각 과정·빈 도구 목록·거절 이유처럼 ‘전압’은 AI마다 달라서, 믿을 수 없는 칸은 카드에 ‘모름’으로 표시하고 원문은 버리지 않는 규칙으로 맞췄어요 — 다음 편은 “AI와 함께 하루 만에 만든 첫 버전”입니다


2026년 10월 1일 기준입니다. 제가 만든 중계기의 개발 기록을 바탕으로 썼고, 특정 기업·서비스의 공식 입장이 아닙니다.