Logo냥냠감자기술 블로그
Skip to Content
Dev Log임금지킴이[Google x 서울시 ] 2024 새싹 해커톤 회고

2024년 8월 1일~2일 DDP에서 새싹 해커톤이 열렸다.

그동안 많은 해커톤에 참여했지만 이번 해커톤이 유독 특별했던 점은 잘 몰랐던 사람들과 팀을 이뤄 참여한 해커톤이라는 점이었다.

게다가 보통 개발 해커톤에 참여하면 남성 팀원이 적어도 한두명은 있었는데 이번 해커톤은 우리 팀에서 나만 남자였다.

그게 싫었던건 아니고 오히려 신선하고 재밌었다.

BlockNote image

주제

이번 해커톤의 주제는 “생성형 AI를 활용한 약자와의 동행” 이었다.

우리팀은 고민 끝에 외국인 노동자를 위해 임금체불진정서를 작성해주는 소프트웨어를 개발하길로 하였다.

이름은 임금 지킴이로 정했다.

이런 소프트웨어를 만든 이유는 다음과 같다.

사회적 약자가 겪는 여러 문제에 대해 조사하던 중 외국인 노동자에 대한 임금 체불 문제가 심각하다는 것을 알 수 있었다.

임금 체불 문제를 해결하기 위해선 임금 체불 진정서를 작성해야 하는데 이런 진정서는 특정한 형식과 필수 정보가 요구되기 때문에, 한국어 조차 익숙하지 않은 외국인 노동자들에겐 신고 과정 자체가 진입장벽이 된다는 사실을 알 수 있었다.

우리는 AI를 이용하면 언어적 장벽을 비롯한 여러 문제들을 해결할 수 있을 것이라 생각하였고, 임금 체불 외국인 노동자를 위한 소프트웨어 임금 지킴이를 개발하게 되었다

BlockNote image

기술 스택

  • Spring Boot, Spring Data JPA, MySQL

  • WebFlux, SSE, Reactor

  • LLM(GPT 4o)

  • iText html2pdf

핵심 기능

상태 기반 LLM 대화 파이프라인

임금 체불 진정서를 작성하기 위해선 사건 정보, 근무 기간, 임금, 사업주 정보 등 여러 필수 정보가 필요하다.

이런 정보를 수집하는 일반적인 방식은 사용자에게 폼 입력을 받는 것인데 이 경우 사용자가 무엇을 입력해야 하는지 스스로 판단해야 한다.

외국인 노동자는 폼만 보고는 어떤 정보를 써야 하는지 알기 어렵고, 중요한 정보를 빠뜨리기도 쉽다.

가장 좋은 방식은 외국인 노동자가 자기가 겪은 억울한 일을 자연어로 털어놓으면 LLM이 알아서 깔끔하게 필요한 데이터를 뽑아내는 시스템이다.

하지만 유저와 시스템 없이 대화하면서 LLM 컨텍스트에 쌓이는 정보만을 가지고 진정서를 작성하는 것은 컨텍스트가 길어질수록 중요한 정보가 희석될 위험도 있고, 필요한 정보를 묻지 않고 누락시키기도 쉬웠다.

따라서 5단계의 상태로 이루어진 LLM 대화 파이프라인을 개발했다.

5단계 상태 기반 구조를 아래와 같이 설계했다.

  1. 사건 정보 (언제, 어떤 일이 있었는지)

  2. 근무 정보 (기간, 업무 내용)

  3. 임금 정보 (미지급 금액, 지급 여부)

  4. 사업주 정보

  5. 진정서 생성

LLM은 상태별로 현재 단계에서 수집해야 하는 정보를 정의하고, 해당 정보가 수집되지 않거나 유저의 설명이 부족한 경우 LLM이 능동적으로 추가적인 질문을 생성하도록 했다.

또한 LLM의 현재 상태와 무관하게 사용자가 미리 정보를 말해준 경우, 해당 정보를 저장하여 이후 단계에서 중복 질문을 방지하도록 하였다.

하나의 상태에서 얻어야 하는 정보를 충분히 획득한 경우 다음 상태로 전이되며, 1~4단계를 모두 거치면서 자유 형식의 대화임에도 필요한 모든 데이터를 안정적으로 수집 및 가공할 수 있는 시스템을 개발했다.

screenshot

진정서 생성 및 PDF 변환 시스템

LLM이 생성한 결과는 자연어 텍스트 형태이기 때문에 실제 제출 가능한 진정서 문서로 활용하기 위해선 pdf 파일로 변환이 필요했다. 애초에 서비스의 목적이 진정서 제출까지 외국인 노동자가 겪는 심적인 부담을 줄여주는 것이었기 때문에 사용자가 별도의 편집 과정 없이 제출할 수 있도록 PDF로 진정서를 반환하는 기능을 개발했다.

진정서의 구조를 HTML 템플릿으로 정의하고, LLM이 수집한 데이터를 해당 템플릿에 매핑하는 방식으로 문서를 생성하도록 설계했다. 이후 iText html2pdf 라이브러리를 활용하여 HTML을 PDF로 변환하고, 한글 출력 문제를 해결하기 위해 폰트를 직접 임베딩하는 방식을 적용했다.

진정서

서버에만 구현한 기능

실시간 대화형 인터페이스

LLM 응답을 실시간으로 전달하기 위해 SSE 기반 스트리밍 구조를 설계했다.

초기에는 WebFlux + Flux 기반으로 GPT 응답을 토큰 단위로 처리하고, 이를 클라이언트에 실시간으로 전달하는 구조를 구현했다.

하지만 해커톤의 특성 상 개발 기한이 촉박했고, 기능을 개발할 당시엔 클라이언트 측 스트리밍 처리 코드를 작성할 수 있을지 여부가 불투명한 상황이었다.

따라서 서버는 스트리밍 처리 코드를 작성한 상황과 그렇지 못한 상황, 두 가지를 모두 수용할 수 있는 구조가 필요했다.

이에 따라 서버 내부에서는 스트리밍 데이터 흐름을 유지하면서도, 이를 StringBuilder로 수집하여 서버 내부에서 완성된 응답을 만들어 반환하는 구조로 개발했다.

이를 통해:

  • 클라이언트가 스트리밍을 지원할 경우 → 완성된 응답을 만드는 코드를 삭제하고 즉시 스트리밍 방식 적용 가능

  • 지원하지 않을 경우 → 완성된 응답을 만들어 반환하는 동기 응답 방식 유지

하도록 구성하였다.

아쉽게도 클라이언트 측 스트리밍 처리 코드를 작성하진 못했지만, 위 구조로 개발한 덕분에 문제없이 소프트웨어를 작동시킬 수 있었다.

회고

이번 해커톤 기간 동안 너무 재미있게 고민하고 개발했다.

저녁엔 팀원들과 행사장 밖으로 나와서 산책도 하고, 잔디밭에 누워서 미니언즈도 보고, 맥주 시음 부스에서 간단히 술도 마셨다.

재밌고 좋은 경험이었기에 결과가 나오지 않아도 괜찮다 생각했었는데 과분하게도 우수상까지 수상하게 되었다.

post-thumbnail

좋은 팀원들을 만나 재밌게 공모전을 진행했고, 결과까지 좋아서 너무 좋은 기억으로 남은 공모전이었다.