Featured Post

GPT-4o API로 회의록 자동화해봤더니, 금요일 저녁이 조금은 편해졌습니다

GPT-4o - 회의록 자동화 관련 이미지

지난달쯤이었어요. 금요일 저녁에 오랜만에 강릉으로 훌쩍 다녀오려고 KTX 표까지 예매해 뒀거든요. 바다도 보고, 커피도 한 잔 마시고, 운 좋으면 새벽에 서핑까지 해볼까 하고요. 그런데 금요일 오후 4시에 시작한 스프린트 회의가 이상하게 끝날 생각을 안 하더라고요. 회의는 길어지고, 결정 사항은 여기저기 흩어지고, 결국 회의록 정리까지 제가 맡게 됐습니다. 연차가 좀 쌓여도 이런 순간은 참 허탈해요. “아, 나 지금 뭐 하고 있지?” 싶은 그 느낌 있잖아요.

녹음본 다시 들으면서 회의록을 치다 보니 밤 9시가 훌쩍 넘었습니다. 강릉행 기차표는 조용히 취소했고요. 그날 밤에 살짝 열받은 마음으로 노트북을 다시 열었습니다. 솔직히 말하면 반쯤은 오기였어요. 개발자로 먹고살면서 이 반복 노동을 아직도 손으로 하고 있다는 게 좀 억울하더라고요. 그래서 그 주말에 강릉 대신 방구석에서 GPT-4o APIWhisper를 엮어서, 녹음 파일을 넣으면 회의록과 Action Items까지 뽑아주는 작은 파이프라인을 만들었습니다.

요즘 회의록 자동화 툴이야 많죠. Notion AI도 있고, 클로바노트도 있고, 이런저런 SaaS도 많고요. 그런데 회사 보안 규정 때문에 외부 서비스를 마음대로 못 쓰는 경우가 은근히 많습니다. 또 우리 팀에서만 쓰는 약어, 프로젝트 코드명, 이상한 별명 같은 건 범용 툴이 잘 못 알아듣더라고요. 그래서 저는 결국 직접 만들었습니다. 거창한 제품은 아니고, 딱 우리 팀에서 쓰기 좋은 개발자용 회의록 자동화 파이프라인 정도라고 보면 됩니다.

제가 만든 회의록 자동화 흐름은 생각보다 단순합니다

처음부터 멋진 웹서비스를 만들 생각은 없었어요. 괜히 프론트 붙이고 로그인 붙이고 권한 관리 붙이다 보면, 회의록 자동화하려다 또 다른 야근을 만들게 되거든요. 저는 그냥 로컬이나 사내 서버에서 실행할 수 있는 Python 스크립트로 시작했습니다. 지금도 이 구조가 제일 마음 편합니다. 작고, 단순하고, 고장 나도 어디가 문제인지 금방 보이니까요.

meeting-summarizer/
├── config/
│   └── settings.py
├── src/
│   ├── __init__.py
│   ├── transcriber.py
│   ├── summarizer.py
│   └── sanitizer.py
├── templates/
│   └── prompt_template.txt
├── output/
│   └── minutes/
├── requirements.txt
└── main.py

흐름은 이렇습니다. 회의가 끝나면 녹음 파일을 하나 넣습니다. 보통 m4a나 mp3 파일이죠. 그러면 transcriber.pyWhisper API로 녹취록을 만듭니다. 이 단계에서는 꽤 날것입니다. 중간중간 이상한 단어도 나오고, 사람 이름도 틀리고, 기술 용어는 가끔 외계어처럼 변합니다. 그다음 sanitizer.py에서 민감 정보를 살짝 가리고, summarizer.pyGPT-4o에게 녹취록을 넘겨 회의록 형태로 정리합니다.

제가 한 달 정도 굴려보니, 이 정도 구조가 꽤 현실적이더라고요. 너무 복잡하지 않아서 팀원들에게 설명하기도 좋고, 문제가 생겼을 때 로그만 봐도 어디서 삐끗했는지 대충 감이 옵니다.

단계 하는 일 제가 느낀 포인트
녹음 파일 입력 회의 음성 파일을 스크립트에 전달 앞뒤 잡담 구간을 잘라내면 비용이 꽤 줄어듭니다.
Whisper 변환 음성을 텍스트 녹취록으로 변환 기술 용어가 자주 깨져서 후처리가 필요합니다.
민감 정보 마스킹 이메일, 전화번호, 계좌번호 같은 정보 제거 사내 보안 설득할 때 이 단계가 은근히 중요합니다.
GPT-4o 요약 회의록, 결정 사항, Action Items 생성 프롬프트 품질이 결과의 거의 전부입니다.

GPT-4o API 연동 코드는 이 정도면 충분했습니다

실제 코드는 생각보다 심플합니다. 저는 처음에 괜히 LangChain 같은 걸 붙일까 고민했는데요. 막상 해보니 이 정도 작업에는 OpenAI 공식 Python SDK만으로도 충분했습니다. 오히려 처음부터 너무 많은 도구를 얹으면 디버깅할 때 피곤해집니다. 뭐랄까, 캠핑 가는데 의자 하나 펴면 될 걸 갑자기 텐트촌을 짓는 느낌이랄까요.

import openai
from config import settings

class MeetingSummarizer:
    def __init__(self):
        self.client = openai.OpenAI(api_key=settings.OPENAI_API_KEY)

    def _load_prompt_template(self) -> str:
        with open("templates/prompt_template.txt", "r", encoding="utf-8") as file:
            return file.read()

    def generate_minutes(self, raw_transcript: str) -> str:
        system_prompt = self._load_prompt_template()

        response = self.client.chat.completions.create(
            model="gpt-4o",
            temperature=0.3,
            messages=[
                {
                    "role": "system",
                    "content": system_prompt
                },
                {
                    "role": "user",
                    "content": "아래 녹취록을 바탕으로 회의록을 작성해 주세요.\n\n" + raw_transcript
                }
            ]
        )

        return response.choices[0].message.content

여기서 제가 제일 신경 쓴 건 temperature 값을 낮게 잡는 것이었습니다. 저는 보통 0.3 정도로 둡니다. 회의록은 소설이 아니니까요. 창의력보다는 정확도가 중요합니다. 회의 중에 아무도 말하지 않은 일정이 갑자기 Action Items에 들어가 있으면 그건 자동화가 아니라 사고입니다. 실제로 초반에 temperature를 0.7로 올려봤다가, “다음 주 금요일까지 배포”라는 말이 없었는데도 모델이 그럴듯하게 기한을 만들어내는 걸 보고 바로 낮췄습니다.

설정 파일은 이렇게 따로 빼뒀습니다. API Key를 코드에 박아두면 언젠가는 사고가 납니다. 진짜로요. Git에 한 번 올라가면 그때부터는 마음이 편하지 않습니다.

import os
from dotenv import load_dotenv

load_dotenv()

OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
OUTPUT_DIR = os.getenv("OUTPUT_DIR", "output/minutes")
DEFAULT_MODEL = os.getenv("DEFAULT_MODEL", "gpt-4o")

회의록 품질은 프롬프트에서 거의 갈립니다

처음에는 저도 순진하게 “이 녹취록 요약해 줘”라고만 던졌습니다. 결과요? 그럭저럭 읽을 만은 한데, 실무에서 바로 쓰기엔 애매했습니다. 너무 두루뭉술하고, 개발팀 회의 특유의 맥락을 잘 못 잡더라고요. 특히 Kafka, Kubernetes, Redis, React 같은 단어가 문제였습니다. Whisper가 듣고 “카프카”는 그나마 괜찮은데, “레디스”를 이상하게 받아쓰거나, “컨슈머 그룹”을 엉뚱하게 쪼개는 경우가 꽤 있었습니다.

그래서 프롬프트 안에 우리 팀만의 작은 용어집을 넣었습니다. 이게 생각보다 효과가 좋았습니다. AI에게 “잘 알아서 해봐”라고 맡기는 것보다, “우리 팀에서는 이런 말을 이렇게 쓴다”라고 알려주는 게 훨씬 낫습니다. 사람도 그렇잖아요. 새로 온 동료에게 업무 맥락을 알려줘야 일을 잘하지, 아무 설명 없이 회의실에 앉혀두면 당연히 헤맵니다.

당신은 IT 개발팀의 회의록을 정리하는 테크니컬 라이터이자 PM 역할을 맡습니다.
입력되는 텍스트는 회의 녹음 파일을 자동 변환한 녹취록입니다.
오타, 비문, 잘못 인식된 기술 용어가 포함될 수 있습니다.
문맥을 보고 기술 용어를 자연스럽게 보정한 뒤, 읽기 쉬운 회의록을 작성해 주세요.

용어 보정 가이드
카프카, 캅카는 Kafka로 정리합니다.
쿠버, 쿠베, 쿠버네티스는 Kubernetes로 정리합니다.
리액트, 리엑트는 React로 정리합니다.
레디스, 래디스, 내디스는 Redis로 정리합니다.
컨슈머, 컨슈마는 Consumer로 정리합니다.
프로듀서, 프러듀서는 Producer로 정리합니다.

회의록 형식
회의 제목: 회의 내용에서 자연스럽게 추정합니다.
일시: 녹취록에 정보가 있으면 작성하고, 없으면 비워둡니다.
참석자: 대화에서 확인 가능한 사람만 작성합니다.

회의 개요
전체 회의의 목적과 결정된 방향을 2문장 안팎으로 정리합니다.

주요 논의 사항
주제별로 나누어 정리합니다.
각 주제에는 논의 배경, 쟁점, 결정 사항을 포함합니다.
발언자가 명확한 경우 이름을 함께 적습니다.

Action Items
담당자, 해야 할 일, 기한을 분리해서 작성합니다.
기한이 명확하지 않으면 미정이라고 적습니다.
녹취록에 없는 내용은 추측해서 만들지 않습니다.

주의 사항
회의에서 언급되지 않은 일정, 담당자, 결정 사항은 새로 만들지 않습니다.
불확실한 내용은 불확실하다고 표시합니다.
잡담이나 인사말은 회의록에서 제외합니다.

이 프롬프트를 넣고 나서 결과물이 확 달라졌습니다. 특히 “녹취록에 없는 내용은 추측해서 만들지 않습니다” 이 문장이 꽤 중요했습니다. GPT-4o가 똑똑하긴 한데, 너무 똑똑한 척할 때가 있거든요. 빈칸이 있으면 그럴듯하게 채워 넣으려는 습성이 있습니다. 회의록에서는 그게 제일 위험합니다.

실제 보정 전후를 보면 감이 바로 옵니다

아래는 제가 실제 팀 회의에서 겪었던 상황을 살짝 익명화해서 정리한 예시입니다. 원문 그대로는 아니지만, 분위기는 거의 비슷합니다. 개발 회의 녹취록 열어보면 정말 이런 문장들이 수두룩합니다. 말로 할 때는 자연스러운데, 텍스트로 바꾸면 갑자기 굉장히 어수선해 보이죠.

구분 Whisper가 받아쓴 날것의 녹취록 GPT-4o가 정리한 회의록
장애 논의 아 그 카프카 토픽에 컨슈머가 붙었는데 자꾸 컨슈머 그룹이 터져요. 이거 내디스 캐싱 문제인가? Kafka Consumer Group 장애 분석
Kafka 토픽에 연결된 Consumer Group에서 비정상 종료 현상이 발생했습니다.
Redis 캐싱 레이어와의 연관성을 의심하고 추가 점검이 필요합니다.
업무 지시 민수님 그러면 그거 리액트 담주 목요일까지 프론트 대시보드 배포 끝내주시고 영희님은 서버 모니터링 좀 봐주세요. Action Items
민수: React 기반 프론트엔드 대시보드 배포 완료, 기한은 다음 주 목요일입니다.
영희: 서버 모니터링 상태 점검 및 이상 징후 확인을 진행합니다.
일정 조율 배포는 음 수요일은 좀 그렇고 목요일 오전에 QA 보고 오후에 나가는 걸로 할까요? 배포 일정 조율
수요일 배포는 부담이 있어 목요일 오전 QA 확인 후, 목요일 오후 배포하는 방향으로 논의되었습니다.
최종 확정 여부는 추가 확인이 필요합니다.

이 정도면 사람이 살짝만 검수해도 바로 공유할 수 있습니다. 저는 이 부분이 가장 마음에 들었습니다. 완전 자동으로 끝내겠다는 욕심을 버리고, 80퍼센트까지는 AI가 정리하고 남은 20퍼센트는 사람이 확인한다는 식으로 접근하니 훨씬 편하더라고요. 사실 회의록은 사람 이름, 일정, 결정 사항만 틀리지 않으면 대부분의 스트레스가 사라집니다.

바이브 코딩으로 만들 때는 프롬프트를 너무 믿으면 안 됩니다

요즘 바이브 코딩 많이 하잖아요. 저도 합니다. 퇴근 후에 커피 한 잔 내려놓고 “대충 이런 기능 만들어줘” 하고 AI에게 던지면, 예전 같으면 한참 걸렸을 코드가 금방 나옵니다. 이건 정말 좋은 변화라고 생각합니다. 다만 회의록 자동화처럼 실제 업무 데이터가 들어가는 도구는 조금 다르게 봐야 합니다.

제가 처음 만든 버전도 거의 바이브 코딩으로 시작했습니다. “Whisper로 음성 변환하고 GPT-4o로 회의록 만드는 Python CLI 만들어줘”라고 던졌더니 기본 구조는 금방 나오더라고요. 그런데 막상 회사 회의 녹음 파일을 넣어보니 문제가 하나씩 나왔습니다. 긴 파일에서 타임아웃이 나고, 중간에 네트워크 오류가 나면 처음부터 다시 돌려야 하고, 기술 용어는 틀리고, 민감 정보 마스킹은 빠져 있고요. 겉보기에는 잘 돌아가는 듯한데, 실무에서는 묘하게 불안한 상태였습니다.

그래서 제가 쓰는 프롬프트 방식은 조금 바뀌었습니다. 기능을 한 번에 크게 요청하지 않고, 실제 실패 사례를 붙여서 작게 고치게 합니다. 예를 들면 이런 식입니다.

아래 Python 코드는 회의 녹음 파일을 Whisper API로 변환한 뒤 GPT-4o로 요약하는 스크립트입니다.
현재 90분 이상 녹음 파일에서 타임아웃이 자주 발생합니다.
파일을 10분 단위로 나누어 처리하고, 각 조각의 변환 결과를 순서대로 합치는 방식으로 수정해 주세요.
중간에 실패한 조각만 재시도할 수 있도록 로그 파일도 남겨 주세요.
기존 함수 이름은 가능한 유지해 주세요.

이렇게 요청하면 결과가 훨씬 낫습니다. “좋은 코드 만들어줘”보다 “어디서 어떻게 실패했고, 어떤 제약을 지켜야 하는지”를 알려주는 게 중요합니다. 사람 개발자에게 이슈 티켓 줄 때도 똑같잖아요. 맥락 없이 “안 돼요”라고 하면 서로 힘듭니다. AI도 별반 다르지 않습니다.

    • 실패 로그를 같이 넣기: 에러 메시지, 입력 파일 길이, 실패한 단계까지 알려주면 수정 코드 품질이 확 좋아집니다.
    • 기존 구조를 유지하라고 말하기: 안 그러면 AI가 갑자기 프로젝트를 새로 지어버립니다. 은근히 자주 그래요.
    • 회사 용어집을 따로 관리하기: 프롬프트 안에 매번 넣기보다 텍스트 파일로 관리하면 업데이트가 편합니다.
    • 사람 검수 단계를 남겨두기: 회의록은 법적, 조직적 책임이 걸릴 수 있어서 완전 자동 발송은 아직 조심하는 편이 좋습니다.

실무에 붙여보니 좋았던 점과 은근히 귀찮았던 점

자동화라고 하면 뭔가 한 번 만들어두면 영원히 편할 것 같지만, 현실은 조금 다릅니다. 잘 굴러가게 하려면 자잘한 손질이 필요합니다. 저는 한 달 정도 써보면서 아래 정도의 장단점을 느꼈습니다.

항목 좋았던 점 조심할 점
시간 절약 1시간 회의 기준으로 회의록 정리 시간이 40분에서 5분 정도로 줄었습니다. 초안 검수는 꼭 해야 합니다. 특히 날짜와 담당자요.
비용 우리 팀 기준 한 달에 대략 커피 몇 잔 값 정도로 버텼습니다. 긴 회의를 통째로 넣으면 비용이 생각보다 빨리 늘어납니다.
보안 마스킹 단계를 넣으니 내부 설득이 훨씬 쉬웠습니다. 프로젝트 코드명이나 고객사 이름은 별도 처리 규칙이 필요했습니다.
품질 Action Items를 뽑아주는 품질은 꽤 만족스러웠습니다. 프롬프트를 방치하면 팀 상황 변화에 점점 둔해집니다.

비용 이야기를 조금 더 해보면, 저희 팀은 주 3회 정도 회의를 녹음해서 돌렸고, 한 달 사용량이 아주 부담스러운 수준은 아니었습니다. 다만 2시간짜리 회의를 아무 생각 없이 통째로 넣으면 확실히 아깝습니다. 저는 회의 앞뒤 잡담 5분에서 10분 정도는 잘라내고 처리합니다. 별거 아닌 것 같지만 누적되면 차이가 납니다. 회의 시작 전에 “오늘 다들 점심 뭐 드셨어요?” 이런 대화까지 AI에게 돈 주고 분석시킬 필요는 없으니까요.

민감 정보 마스킹은 생각보다 빨리 넣는 게 좋습니다

처음에는 개인 프로젝트처럼 가볍게 만들었는데, 회사에서 쓰려면 이야기가 달라집니다. 녹취록에는 생각보다 많은 정보가 들어갑니다. 사람 이름, 이메일, 고객사 이름, 장애 상황, 내부 URL, 가끔은 계약 금액 같은 것도 튀어나옵니다. 그래서 저는 GPT-4o로 보내기 전에 정규표현식으로 기본 마스킹을 합니다.

import re

def mask_sensitive_info(text: str) -> str:
    text = re.sub(r"[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+", "[MASKED_EMAIL]", text)
    text = re.sub(r"\b010[-.\s]?\d{4}[-.\s]?\d{4}\b", "[MASKED_PHONE]", text)
    text = re.sub(r"\b\d{2,3}[-]\d{2,4}[-]\d{4,6}\b", "[MASKED_ACCOUNT]", text)
    text = re.sub(r"https?://[^\s]+", "[MASKED_URL]", text)
    return text

물론 이 정도로 모든 보안 이슈가 해결되는 건 아닙니다. 그래도 최소한의 안전벨트는 됩니다. 저는 보안팀에 설명할 때도 “외부 API로 보내기 전에 이런 정보는 제거합니다”라고 보여줬고, 그때부터 대화가 훨씬 부드러워졌습니다. 개발자는 기술만 잘 만들면 끝이라고 생각하기 쉬운데, 회사 안에서는 설득 가능한 구조를 만드는 것도 꽤 중요합니다.

제가 실제로 쓰는 운영 습관 몇 가지

한 달 정도 쓰다 보니 제 나름의 루틴이 생겼습니다. 대단한 건 아니고, 조금 덜 귀찮아지기 위한 생활형 팁에 가깝습니다.

    • 회의 시작 전에 녹음 목적을 말합니다. 나중에 괜한 오해가 생기지 않게 “회의록 자동 정리를 위해 녹음하겠습니다”라고 짧게 공유합니다.
    • 회의 제목을 파일명에 넣습니다. 2025-01-frontend-sprint.m4a처럼 저장하면 나중에 찾기 편합니다.
    • 회의 끝나고 바로 돌립니다. 하루 지나면 맥락이 흐려져서 검수할 때 더 오래 걸립니다.
    • 잘못 정리된 표현은 용어집에 추가합니다. 한 번 틀린 단어는 다음에도 틀릴 가능성이 높습니다.
    • 자동 발송은 하지 않습니다. 저는 아직 사람이 확인한 뒤 Slack이나 메일에 공유하는 방식을 고집합니다.

특히 자동 발송은 조심하는 편입니다. 편하긴 하죠. 회의 끝나자마자 Slack 채널에 회의록이 올라가면 멋있어 보입니다. 그런데 한 번이라도 잘못된 담당자나 기한이 올라가면 그 뒤처리가 더 피곤합니다. 저는 그냥 초안까지만 자동으로 만들고, 최종 공유 버튼은 사람이 누르는 게 맞다고 봅니다. 약간 보수적일 수 있는데, 회사 일은 그 정도가 마음 편하더라고요.

이걸 만들고 나서 금요일 저녁이 조금 달라졌습니다

이 파이프라인을 만든 뒤로 금요일 늦은 회의가 아주 무섭지는 않습니다. 회의가 끝나면 녹음 파일을 스크립트에 넣고, 결과가 나오는 동안 커피를 마시거나 짐을 챙깁니다. 나온 회의록을 휴대폰으로 슥 훑어보고, 담당자와 일정만 확인한 뒤 공유하면 끝입니다. 예전처럼 녹음본을 처음부터 끝까지 들으며 손으로 받아치는 일은 거의 없어졌습니다.

물론 이 도구가 모든 회의 스트레스를 없애주지는 않습니다. 회의 자체가 길고 산만하면 AI도 힘들어합니다. 그래도 적어도 반복적인 정리 노동은 많이 줄여줍니다. 저는 그 정도면 충분히 가치 있다고 봅니다. 기술이 꼭 세상을 거창하게 바꿔야만 의미 있는 건 아니잖아요. 금요일 저녁 1시간을 돌려주는 것만으로도, 직장인에게는 꽤 큰 선물입니다.

GPT-4o API로 회의록 자동화를 해보고 싶은 개발자, 사내 보안 때문에 외부 회의록 SaaS를 쓰기 어려운 팀, 매번 Action Items 정리하다가 퇴근 시간이 밀리는 PM이라면 한 번쯤 직접 만들어볼 만합니다. 작게 시작해도 됩니다. 녹음 파일 하나 넣고 회의록 초안 하나 뽑는 것부터요. 그렇게 조금씩 다듬다 보면, 어느 순간 내 금요일 저녁이 조용히 돌아와 있을지도 모릅니다. 저는 그 시간에 다시 강릉행 표를 예매했고요. 이번엔 취소 안 했습니다.


👨‍💻

작성자: 20년 경력 IT 전문 아키텍트

실무 개발과 아키텍처 설계를 거쳐 현재는 AI 바이브 코딩과 개발 자동화를 연구하고 있습니다. 직접 삽질하며 깨달은 실전 꿀팁과 에러 극복 사례만 투명하게 공유합니다.

댓글