정부지원사업 공고를 법인별 검토 카드로 만들기
공고 수집부터 법인별 검토 카드까지 자동화하고 사람이 판단할 부분을 나눴다.
지원사업 공고를 찾으려면 열 곳이 넘는 사이트를 확인해야 했다. 공고를 찾아 요건과 사업 취지를 검토한 뒤, 사업을 기획하고 계획서를 쓰는 과정까지 담당자가 챙기고 있었다.
사내 업무 자동화를 맡으며 이 과정을 줄여 보기로 했다. 여러 법인의 지원사업을 함께 관리하고 있어서, 같은 공고라도 법인별로 지원 자격과 진행 여부를 따로 확인해야 했다.
어디까지 자동화할지
담당자들과 논의해 공고 수집, 요건 검토, 취지 분석까지 자동화하기로 했다. 사업을 기획하고 사업계획서를 쓰는 단계는 사람이 맡았다.
수집은 기업마당과 K-스타트업 API부터 연결하고, 나머지 사이트는 크롤링을 추가하는 순서로 잡았다.
검토한 뒤의 상태가 남아야 했다
업무를 더 들여다보니 공고 수집 뒤에도 문제가 있었다. 누가 무엇을 검토했고, 어떤 이유로 진행하거나 제외했는지 추적하기 어려웠다.
그래서 수집 결과를 보여 주는 화면보다 검토 기록을 남길 장부가 먼저 필요했다.
장부는 Notion에
처음에는 Slack에서 질문하고 추천을 받는 방식을 논의했다. 하지만 반복해서 목록을 보고 상태를 관리하려면 장부 형태가 필요했다. 별도 웹 대시보드도 검토했지만, 먼저 Notion으로 업무 흐름을 확인해 보기로 했다. 권한을 따로 관리해야 하는 데이터는 스프레드시트로 분리했다.
이후 Notion DB를 API로 연동하는 방식으로 정했다. 별도 웹 대시보드는 빠졌고 Slack은 필요할 때 브리핑 채널로만 쓰기로 했다. 통합 API용 봇 계정을 만들고 해당 DB 페이지를 공유하는 식으로 연결했다.
카드 하나는 공고 × 법인
장부의 단위를 정하는 게 중요했다. 공고 하나에 카드 하나를 만들고 해당 법인을 여러 개 선택해 묶는 방법도 있었고 구조 없이 자유 메모로 운영하는 방법도 있었다. 결국 공고와 법인 조합마다 카드를 따로 만들기로 했다.
이유는 단순했다. 같은 공고라도 법인마다 진행 상태, 담당자, 다음 할 일이 다를 수 있다. 카드 한 장에 여러 법인을 묶으면 실제 추적이 흐려진다.
같은 결정에서 자동으로 채울 필드도 정했다. 마감 일시, 주관 기관, 지원 유형, 자격 요건, 공고 내용, 모집 취지, 공고·양식 링크처럼 공고 원문과 첨부 문서에 적힌 값만 자동으로 채운다. 평가 지표처럼 공고에 없거나 불분명한 정보는 빈칸으로 둔다. LLM이 추정해서 채우지 않는다.
검토 특이사항, 제외 사유, 진행 확정 이유, 운영 코멘트는 사람이 쓴다. 진행 상태(검토 요청 → 검토 중 → 진행 확정)도 사람이 바꾸고 제외할 때는 사유를 꼭 남기게 했다. 자동화가 맡는 칸과 사람이 맡는 칸이 필드 단위로 나뉜 셈이다.
LLM은 어디에 썼나
법인별 지원 자격과 공고 내용을 비교하는 데 LLM을 썼다. 처음에는 지역 같은 조건으로 전체 공고의 대부분을 먼저 걸러 내고 남은 공고를 법인마다 LLM으로 적합한지 확인해 점수를 매긴 뒤, 고득점인 것만 장부에 올렸다.
그런데 점수가 낮아 빠진 공고는 사람이 검토할 기회도 없었다. 사람이 전체 목록을 보던 때는 그래도 모든 공고를 한 번은 봤다. 그래서 공고를 넓게 수집하되 검토 우선순위를 상·중·하로 나누자는 의견을 냈다.
그 뒤로 LLM은 이 공고가 우리 법인과 왜 맞는지 또는 덜 맞는지, 검토 우선순위가 상·중·하 중 어디인지를 설명하는 쪽으로 역할이 바뀌었다. 올릴지 말지를 막는 역할은 줄었다. 결격 조건에 걸리지 않는 공고는 폭넓게 올리고 사람이 우선순위를 보고 검토하도록 바꿨다.
매일 오전 9시
상·중·하 우선순위
공식 원문 필드만 자동 입력
80개와 130개
장부를 배포한 뒤에는 매일 아침 9시에 공고를 수집하도록 했다. 첫 수집에서 공고는 80개쯤, 카드는 130개쯤 만들어졌다.
숫자가 다른 건 카드 단위 때문이다. 한 공고가 여러 법인에 해당하면 카드가 여러 장 생긴다. 80은 공고 수, 130은 공고와 법인 조합의 수다. 그리고 이건 하루치가 아니라, 기존에 올라와 있던 공고까지 처음에 한꺼번에 가져온 양이다.
장부 운영은 업무 담당자에게 넘겼다. 공고와 검토 이력을 모으는 부분을 자동화하고, 그 자료를 바탕으로 사업을 기획하고 지원 여부를 정하는 일은 담당자가 이어서 맡았다.
매장 데이터 수집 워커
매장 관리 서비스에 데이터를 채우는 수집 워커도 함께 정리했다. 메인 앱이 수집 작업을 큐에 넣으면 두 종류의 워커가 가져가서 처리했다. TypeScript 수집기는 네이버 플레이스, 배달의민족, POS 데이터를 맡았고 쿠팡이츠는 Python 에이전트가 맡았다. 원천마다 가져오는 방식이 달랐다. 공개되지 않은 API를 쓰는 곳, 엑셀 다운로드와 크롤링을 같이 쓰는 곳, DB에서 직접 읽는 곳이 섞여 있었다.
두 워커는 실행 환경이 달라서 언어를 하나로 합치지 않고 프로세스 두 개로 돌렸다. 대신 저장소는 하나로 합쳐서 운영과 배포 경로를 한곳에 모았다. 프로세스 관리 설정과 Ubuntu·macOS 설치 스크립트를 두고 인수인계 문서로 핵심 위험, 실행·로그·재시작·API 계약, 플랫폼별 장애 대응, 워커 담당자 요구사항을 정리했다. 외부 위키 없이 저장소 안에서 다 읽히게 썼다.
운영하면서는 외부 플랫폼 쪽 문제가 자주 생겼다. 한 배달 플랫폼에서는 요청이 많아 계정이 일시 제한됐고 하루 여러 번 하던 수집을 마감 때 한 번으로 줄였다. 플랫폼이 사이트를 바꾸거나 차단 정책을 바꿔서 수집기를 고친 일도 있었다.
자동화 범위, 카드 단위, 자동 필드는 업무 담당자들과 함께 정했다. 내가 맡은 건 수집과 장부 연동을 만들고 회의에서 나온 요구를 이런 구조로 옮기는 일이었다.