[n8n] 나라장터 입찰공고를 AI Agent로 물어보기

소개

시도하고자 했던 것과 그 이유를 알려주세요.

1차로 나라장터(G2B) 입찰공고를 구글시트로 받아보기를 해 보았습니다. 챗gpt API를 호출하여 내용을 요약하기는 해 보았지만 제대로 된 AI 에이전트를 활용하지는 못했습니다. 그러던 차에 이번주(3주차) 사례발표 중에 디디님이 발표하신 "서브워크플로우를 툴로 사용하기"에서 영감을 받아, AI Agent와 Sub Workflow를 활용하여 나라장터 공고(사전규격, 입찰공고, 개찰결과)를 채팅 형식으로 Q&A하는 자동화에 도전하게 되었습니다.

진행 방법

전체 워크플로우는 다음과 같이 설계하였습니다.

애플리케이션의 흐름을 보여주는 다이어그램

모델은 오픈AI의 챗(gpt-4o-mini) 모델을 사용했습니다.

질의 형식은 기본적으로 다음 3가지 유형을 처리하도록 설계하였습니다.

  1. 어제 정보화 관련 입찰공고 찾아줘

  2. 최근 1주일 정보시스템 사전규격 찾아줘

  3. 2025년 11월 1일부터 11월 10일까지 컨설팅 사업 개찰결과 알려줘

AI Agent는 질의에서 날짜 관련 정보(어제, 최근 1주일, 2025년 11월 1일)와 키워드(정보화, 정보시스템, 컨설팅)를 추출하고, 입찰공고/사전규격/개찰결과에 따라 해당 모듈(도구)을 호출하게 됩니다. 실제 날짜 계산은 Sub Workflow에서 수행합니다.

AI Agent에 설정한 System Message는 다음과 같습니다.

You help users search Korean G2B (Narajangteo) bid notices(입찰공고),
bid opening results(개찰결과),
and preliminary specifications(사전규격).

Your main responsibilities are:

1. 정확하게 사용자의 의도를 해석한다.
2. 다음 중 올바른 도구를 단 1개만 선택해서 호출한다:
   - Bid Notice Search Tool (입찰공고 조회)
   - Bid Opening Result Tool (개찰결과 조회)
   - Preliminary Specification Tool (사전규격 조회)
3. 날짜 표현(3가지 패턴)을 정확히 분류한다.
4. bidNtceNm에서 검색 키워드를 정확히 추출한다.
5. 도구 결과(summaryText, results, totalCount)를 읽고 한국어로 자연스럽게 답한다.

툴은 사전규격을 호출하여 결과를 받아오는 도구, 입찰공고를 받아오는 도구, 개찰결과를 받아오는 도구를 설계하였고, Sub Workflow로 설계하였습니다.

Sub Workflow로 설계한 이유는 단순히 api를 호출하여 답을 받는 게 아니고, 추가적인 작업들이 필요했기에 워크플로우가 필요했습니다.

예를 들어, 입찰공고를 호출하는 Sub 워크플로우는 다음과 같습니다.

프로세스의 단계를 보여주는 다이어그램

결과와 배운 점

처음에는 오늘/내일/어제, 최근 1주일, 특정 날짜 구간 등을 AI Agent가 바로 이해할 줄 알았으나, 아직까지는 일상적인 날짜 언어에 대해 이해하고, 이를 정확한 날짜로 변환하는 게 어려웠습니다. 그래서 날짜 처리시 엄청 애를 먹었습니다. 그래서 다음과 같이 어느 정도 유형을 정의하고 접근하였습니다.(javascript로 구현 <- 챗gpt에 물어보면서 코딩하였습니다)

/* --------------------------------------------------------
   1) 명시적 날짜 범위
---------------------------------------------------------*/
if (startDateText && endDateText) {
  const bg = parseTextDate(startDateText);
  const ed = parseTextDate(endDateText);
}

/* --------------------------------------------------------
   2) 단일 날짜 (어제 / 오늘 / 그저께)
---------------------------------------------------------*/
else if (dayKeyword) {
  const target = new Date(now);

  if (dayKeyword.includes('어제')) {
    target.setDate(target.getDate() - 1);
  } else if (dayKeyword.includes('그저께')) {
    target.setDate(target.getDate() - 2);
  } else if (dayKeyword.includes('오늘')) {
    // today 그대로
  }

/* --------------------------------------------------------
   3) 상대 기간 (최근 n일, 최근 1주일, 최근 한달)
---------------------------------------------------------*/
else if (relativeDays > 0) {
  const end = new Date(now);
  const start = new Date(now);

  // 최근 n일 = 오늘 포함 n일
  // 예: 최근 7일 → 시작 = 오늘 - 6일
  start.setDate(start.getDate() - (relativeDays - 1));
}

/* --------------------------------------------------------
   4) 아무 조건도 없으면 기본 최근 7일
---------------------------------------------------------*/
if (!inqryBgnDt || !inqryEndDt) {
  const end = new Date(now);
  const start = new Date(now);
  start.setDate(start.getDate() - 6); // 오늘 포함 7일
}

도움 받은 글

19기 N대리비서봇의 스터디장님과 팀원의 사례 공유에 감사드립니다. 특히 디디님의 케이스에 영감을 받아 도전할 수 있었습니다. 특별히 감사드립니다^^

2

뉴스레터 무료 구독

👉 이 게시글도 읽어보세요