AI 자동화 프로젝트 5: 로컬 모델 대신 Codex CLI를 붙여 봤다
TL;DR
- Ollama의 작은 로컬 모델 대신, 로그인된 Codex CLI와
gpt-6-astra를 연결했다. Kafka와 Coral을 사용하는 기존 처리 흐름은 유지했다. - 잘못된 감정 분류 초안을 넣자 검토자가 오류를 지적했다. 다만 바로 재작성한 답도 맞았으므로, 이 한 사례로 검토 단계의 이득까지 확인한 것은 아니다.
- 실제 화면에서 답변과 전달 과정을 확인했다. 모델·실행 방식·기본 지시문이 함께 바뀐 이번 기록은 연동 확인이며, 모델 성능을 비교하는 통제 실험은 아니다.
들어가며
4편에서는 같은 초안을 바로 재작성하는 경로와 검토 후 수정하는 경로를 비교했다. 작은 로컬 모델 qwen2.5:1.5b로 15쌍을 실행했지만, 검토자는 모든 사례에 “수정 불필요”라고 답했다. 검토 단계를 붙였다는 사실만으로 답이 더 좋아지지는 않았다.
이후 콘솔에서 “저녁 친구랑 술한잔 할건데, 장소 추천. 종로3가 근처”라는 요청을 실행했다. 초안은 “예스 카카오 리뷰 리빙하우스”, 검토는 다시 “수정 불필요”였다. 마지막에는 검증되지 않은 주소가 붙었다. 세 단계가 모두 완료되어도 사용자가 쓸 만한 답변이라는 뜻은 아니었다. 이번에는 처리 구조를 더 늘리기 전에, 답변을 만드는 모델부터 바꿔 보기로 했다.
이미 로그인한 Codex CLI를 작업 실행기로 썼다
로컬에 설치하고 로그인해 둔 Codex CLI를 사용했다. 별도의 모델 API 키를 애플리케이션에 넣는 대신, codex exec로 요청을 전달하고 최종 응답을 받는 방식이다. 비대화형 실행과 결과 파일 출력은 Codex 공식 문서에서 제공하는 기능이다.
이번 환경에서 사용한 모델은 gpt-6-astra, 추론 설정은 medium이다. 작성·검토·수정 역할 모두 같은 모델을 쓴다. Claude 연결이나 역할별 모델 선택은 아직 구현하지 않았다.
여기서 CLI가 로컬에서 실행된다는 것과 모델을 로컬에서 추론한다는 것은 다르다. Codex는 원격 모델을 호출하며, 로그인한 계정의 사용 조건과 한도에 영향을 받는다. 이번 구성은 CLI의 ChatGPT 로그인을 재사용한다.
Consumer는 Docker에, CLI 실행기는 Windows에 뒀다
Kafka Consumer를 Windows로 옮기지는 않았다. 기존 Java Consumer가 Windows의 작은 Python 실행기에 요청을 보내고, 실행기가 네이티브 Codex CLI를 호출하도록 연결했다.
앱·Kafka·PostgreSQL·Coral은 Docker에서, CLI 실행기만 Windows에서 돌아간다. 내부 연결에는 HTTP와 전용 토큰을 사용한다. 모델 API 키를 직접 관리하지 않는 구성이지, HTTP 통신 자체를 없앤 구성은 아니다. CLI 로그인 파일을 컨테이너로 복사할 필요도 없다.
이렇게 나누면 Consumer가 이미 처리하던 작업 상태, 실패 후 재처리, 결과 저장을 그대로 사용할 수 있다. Kafka는 작업을 전달하고, DB는 결과를 보존하며, Coral은 다음 역할에 문맥을 전달한다. 답변을 생성하는 부분만 교체한 셈이다.
실행기는 세 가지를 구분하도록 만들었다.
- 입력과 명령: 사용자 프롬프트는 UTF-8 표준 입력으로 전달한다. 요청 문자열을 셸 명령에 이어 붙이지 않는다.
- 진행 로그와 최종 답변: JSON 이벤트에서 정상 완료를 확인하고,
--output-last-message로 저장된 최종 응답을 읽는다. 중간 로그를 답변으로 저장하지 않는다. - 완료와 실패: 종료 코드·완료 이벤트·응답 내용을 확인한다. 5분 제한을 넘기거나 실행이 실패하면 기존 작업 실패 경로로 전달한다.
동시에 하나의 CLI 요청만 실행하며, 읽기 전용 샌드박스를 사용하고 셸 실행·앱·웹 검색 기능은 비활성화했다. 이번 연결의 역할은 전달받은 문맥으로 텍스트를 생성하는 것이다.
이번에는 잘못된 초안을 지적했다
먼저 답을 명확히 판단할 수 있는 감정 분류를 다시 실행했다.
다음 리뷰의 감정을 긍정, 부정, 중립 중 정확히 한 단어로 분류하세요: 제품이 고장 나서 사용할 수 없습니다.
두 경로에 같은 잘못된 초안 “긍정”을 넣고, 기대 답변을 “부정”으로 지정했다. 이번 검토 의견은 다음과 같았다.
오류: 사용할 수 없다는 불만이므로 ‘긍정’을 ‘부정’으로 수정해야 합니다.
| 경로 | 최종 답변 | 모델 호출 수 |
|---|---|---|
| 바로 재작성 | 부정 | 1회 |
| 검토 후 수정 | 부정 | 2회 |
4편과 달리 검토자가 오류의 이유를 설명했다. 하지만 최종 답변은 두 경로 모두 맞았다. 검토가 없어도 고쳐진 사례이므로, 추가 호출 한 번의 효과를 입증한 결과로 해석할 수는 없다.
또한 이번에는 기존의 다섯 사례를 세 번씩 전부 다시 실행하지 않았다. 이 한 쌍의 결과를 4편의 15쌍과 정확도로 비교하지 않는다.
장소 추천은 자연스러워졌지만, 사실 확인은 남았다
앞에서 실패했던 종로3가 요청도 같은 문장으로 실행했다. 새 답변은 익선동 골목, 포장마차 거리, 돈의동 갈매기살 골목을 제안하고 식사와 2차를 나누는 흐름을 설명했다. 마지막에는 다음 문장을 덧붙였다.
실시간 영업 여부는 확인하지 못했으니, 방문할 곳은 출발 전에 확인해 주세요.
이전의 짧고 불분명한 응답에 비해 요청에 맞는 형태로 답했고, 확인하지 못한 정보도 표시했다. 다만 이번 실행에서 지도나 검색으로 장소·위치·영업 여부를 검증하지는 않았다. 화면에 나온 지명과 출구 정보도 모델이 생성한 내용이다. 이 글에서 확인한 것은 저장된 응답과 처리 흐름이며, 해당 장소 정보의 정확성이 아니다.
이 요청의 검토 의견은 여전히 “수정 불필요”였다. 검토자가 오류를 한 번 찾아냈다고 해서, 다른 요청의 사실관계까지 검증할 수 있게 된 것은 아니다.
달라진 조건도 함께 남겨야 한다. 모델뿐 아니라 Ollama에서 Codex CLI로 실행 방식이 바뀌었고, 실행기에 “실시간 검색을 하지 않았으니 현재 장소 정보나 주소를 지어내지 말고 확인하지 못한 사실을 밝히라”는 기본 지시도 추가했다. 따라서 답변의 변화 전체를 모델 교체 하나의 효과로 돌릴 수 없다.
기존 처리 흐름을 통과하는지 확인했다
실제 앱에서는 단일 작업 1회, 배치 작업 2회, 비교 실험 3회, 작성 → 검토 → 수정 3회로 총 9번의 모델 실행을 확인했다. 모두 첫 시도에 성공했고, 각 작업의 결과와 Coral 전달 기록을 확인했다. 이는 아홉 개 품질 평가 사례가 아니라 기능별 연동 확인이다.
자동 테스트는 Java 테스트 63개 통과·외부 서비스 설정이 필요한 2개 제외, Python 실행기 테스트 6개 통과다. 데스크톱과 모바일에서 모델 표시와 단계별 결과도 확인했다. 구현 커밋과 CI 결과에 구현 및 검증 내역을 남겼다.
Windows에서 Python 3.11 이상, Docker Desktop, 로그인된 Codex CLI를 준비했다면 프로젝트 루트에서 실행할 수 있다.
.\scripts\start-codex.ps1
기본 Docker 구성은 여전히 DEMO 모드이고, 위 스크립트가 CLI 실행기와 Codex용 Compose 설정을 적용한다. 모델 지정 등 자세한 설정은 저장소 README에 정리했다.
다음에는 답변의 근거를 연결하려 한다
이번에는 같은 콘솔과 처리 흐름에서 다른 모델을 실행하고, 바뀐 답변과 검토 의견을 확인할 수 있게 됐다. 다음 과제는 더 자연스러운 문장을 넘어 답변이 맞는지 확인할 자료를 갖추는 것이다.
장소 추천처럼 현재 정보가 필요한 요청에는 검색 결과와 출처를 문맥에 넣는 단계가 필요하다. 검토 효과를 비교할 때는 사례·지시문·실행 조건을 맞추고, 검토 판정과 최종 수정 결과를 따로 평가하려 한다. Jev의 실제 연동과 판정에 따른 자동 재생성·토픽 선택도 아직 남아 있다.
작성 기준: 2026년 10월 2일. 모델 실행 결과는 10월 1일의 실제 기록이며, 비교 화면은 저장된 결과를 다시 열어 캡처했다.


Comments