Can AI Write a Sports Recap Without Making Up Stats? Mostly.
AI는 통계를 지어내지 않고 경기 요약을 쓸 수 있을까요? 대체로 그렇습니다
WNBA 경기 기록을 코드로 집계하고 AI가 팀별 목소리로 요약을 쓰는 팬진 ‘Full Court Press’의 제작기입니다. 숫자와 이름을 검증하는 규칙만으로는 문장의 사실성까지 보장하지 못했으며, AI 요약이 탈락하면 코드가 기록에 근거한 대체 요약을 쓰도록 설계했습니다.
- 주제
AI 요약
개발자는 WNBA 경기가 끝난 다음 날마다 팀별 팬진 ‘Full Court Press’를 발행합니다. 경기별 요약과 선수 조명, 10초 오디오, 공유 카드, 인쇄용 접지 레이아웃을 제공합니다. 승패와 상관없이 양 팀 팬에게 각자의 관점으로 쓴 판을 전달하는 것이 목표입니다.
통계는 코드가 세고, AI는 문체를 씁니다
사용하는 BALLDONTLIE의 ALL-STAR 요금제에는 WNBA 박스스코어가 없지만 플레이바이플레이 데이터는 있습니다. 프로젝트는 경기 기록을 읽어 득점, 리바운드, 어시스트, 스틸, 블록을 직접 집계합니다. 최종 점수는 별도 기록과 대조하며, 팀별 득점 합계가 맞지 않으면 해당 경기에서 계산한 모든 파생 통계를 제외합니다. 어시스트가 성공한 야투 수보다 많지 않은지 확인하는 등 다른 항목도 각각 검증합니다.
다섯 경기로 시험했을 때 득점 합계는 연장전을 포함해 모두 맞았습니다. 개발자는 그중 세 경기의 통계 줄을 Basketball Reference와 직접 대조했고, Alyssa Thomas의 트리플더블도 집계한 리바운드와 어시스트가 일치했습니다. 다만 이 확인이 다른 경기의 리바운드와 어시스트까지 검증해 주지는 않는다고 명시합니다.
Claude Haiku 4.5는 Amazon Bedrock에서 제목, 경기 요약, 선수 조명, ‘오늘의 숫자’를 작성합니다. 게시 전 검증기는 각 문단의 숫자가 경기 사실표에 있는지, 대문자로 시작하는 이름이 해당 경기의 선수나 팀인지 확인합니다. 영문으로 풀어 쓴 숫자는 거부하고, 도박·부상·소문처럼 근거가 없는 주장을 금지 목록으로 막습니다. 검증에 실패한 문단에는 실패 항목을 알려 한 번 더 작성하게 합니다. 재시도도 통과하지 못하면 해당 문단을 잘라내고 페이지에 이유를 표시합니다. 로그에는 작동한 규칙과 식별 정보, 횟수만 남기고 모델 문장은 저장하지 않습니다.
숫자가 맞아도 문장은 틀릴 수 있습니다
초기 다섯 경기 시험에서 검증기는 문단 9개를 걸러냈지만, 개발자가 추가로 발견한 오류 7개는 통과했습니다. 숫자 자체는 사실표에 있었지만, 모델이 숫자를 바탕으로 잘못된 계산을 했기 때문입니다. 예를 들어 “4쿼터는 애틀랜타의 시간이었다”고 썼지만, 인디애나가 4쿼터를 17대 9로 이겼습니다. 프롬프트를 더 엄격하게 바꿔도 해결되지 않았습니다. 각 쿼터 승자, 하프타임 점수, 팀의 연속 득점, 팀 내 최다 득점자, 순위처럼 코드가 계산한 문장을 사실표에 넣고 모델이 직접 계산하지 않도록 바꿨습니다.
서비스를 공개한 뒤 14경기에서 게시 가능한 문단 151개를 다시 검사했습니다. 그중 13개에 사실과 다른 주장이 있었고, 가상의 기록을 만들거나 맞는 숫자를 엉뚱한 주장에 붙인 사례도 있었습니다. 새 규칙으로 6개를 잡았지만 7개는 남았습니다. 숫자와 이름이 사실에서 왔다는 검증만으로 그 문장이 사실을 올바르게 설명하는지 확인할 수는 없습니다.
규칙을 강화하자 기존에 통과했던 문단도 다시 검사하면서 요약이 잘려 나갔습니다. 재검사는 문장을 제거할 뿐 새로 쓰지 않습니다. 그 결과 실제 56개 페이지 중 20개에 경기 요약이 없었고, 어느 날은 20페이지 중 12페이지가 비었습니다. 개발자는 AI 요약이 탈락하면 코드가 같은 경기 사실을 바탕으로 평이한 대체 문장을 쓰게 했습니다. 이 요약에는 ‘코드 작성, 집계한 사실 기반, AI 미사용’이라고 표시하고 AI 문장이 빠진 이유도 설명합니다. 골든 세트의 모든 코드 요약은 AI 문장과 같은 검증기를 통과하는지 테스트합니다. 배포 뒤 56개 페이지 모두에 요약이 생겼습니다. AI 작성은 36개, 코드 작성은 20개였습니다.
고정 테스트 데이터와 AWS 구성
시즌 일정이 끝나면 실시간 경기가 없어 서비스를 시험하거나 심사받기 어렵습니다. 이를 보완하려고 개발자는 8월과 9월 경기 다섯 개를 ‘골든 세트’로 저장했습니다. 연장전, 역전, 트리플더블처럼 오류가 나기 쉬운 경기를 골랐습니다. 실시간 페이지와 같은 코드로 만들되 저장된 데이터임을 표시하며, 오디오는 제공하지 않습니다. 득점 검증과 AI 문장 감사, 코드 대체 요약의 검증 테스트에 이 세트를 사용합니다.
구성은 AWS SAM 스택 하나와 예약 실행 Lambda 하나를 중심으로 합니다. 태평양 시간 오전 6시 15분에 EventBridge Scheduler가 Python 3.13 Lambda를 실행합니다. 문장은 Amazon Bedrock의 Claude Haiku 4.5가 만들고, 오디오는 코드가 구성한 대본을 Amazon Polly 신경망 음성으로 읽습니다. 정적 파일은 비공개 S3에 저장하고 CloudFront로 제공합니다. Origin Access Control, 엄격한 Content Security Policy, HSTS를 적용했으며 API 키는 SSM Parameter Store의 SecureString에 보관합니다. AWS Budgets는 프로젝트에 10달러, Polly에 2달러 한도를 두고 CloudWatch 로그에는 식별자와 건수만 기록합니다.
AI 에이전트 작업에서 얻은 교훈
개발자는 AWS의 명세 기반 코딩 에이전트 Kiro와 Claude를 함께 사용했습니다. Kiro는 AWS 연결과 배포, Bedrock, Polly를 맡았고 Claude는 통계 집계, 사실 검증, 템플릿, 테스트, 디자인을 담당했습니다. 에이전트마다 작업 기록을 따로 남기게 했습니다.
한 번은 Kiro가 한 달간 44경기를 확인했지만 연장전이 없다고 보고했습니다. 명령 출력이 잘리거나 비어 있었고, 실제로는 스크립트가 파일에 결과를 기록하고 있었습니다. Claude가 파일을 열어 확인한 결과 62경기 중 연장전이 한 번 있었고, 인디애나가 애틀랜타를 95대 91로 이겼습니다. 긴 출력은 화면에 지나간 요약이 아니라 파일에서 읽어야 한다는 규칙을 세웠습니다.
배포 중 Kiro는 예상과 다른 결과가 나오면 임의로 수정하지 않고 멈추라는 규칙에 따라 네 번 작업을 중단했습니다. 그중 한 번만 실제 버그를 찾았습니다. 나머지는 프롬프트에 데이터가 아니라 추론으로 적은 예상 경기 수가 잘못된 탓이었습니다. API가 경기 날짜를 UTC 기준으로 분류해 동부 시간 오후 8시 경기가 다음 날로 표시된다는 점도 읽기 전용 확인으로 밝혔습니다. 예상값 역시 근거가 필요한 주장이라는 교훈을 얻었습니다.
개발자가 제시하는 한계도 분명합니다. 데이터 공급자는 하나이며, 독립된 기준과 대조한 통계는 득점뿐입니다. 검증기는 숫자와 이름을 확인하지만 문장의 의미를 보증하지 않습니다. 코드가 쓰는 대체 요약은 사실에 근거하지만 박스스코어에 가까운 평이한 문장입니다. WNBA만 지원하며 NBA는 시즌 시작 전까지 준비 상태입니다.
원문: dev.to / 번역·요약: Trawling