Facebook Chatbot

Messenger 기반 고객 응대 자동화 봇

챗봇자동화Java
2023챗봇자동화JavaRepo ↗

시스템 아키텍처

구조

내부 운영용으로 구축한 규칙 기반 메시징 어시스턴트입니다. 수신 메시지를 분류하고 정책에 매칭한 뒤, UI/제어(데스크톱), 자동화 로직, 영속성/내보내기 계층을 명확히 분리해 예측 가능한 흐름으로 라우팅합니다.

메시징 채널 (Facebook) ↓ 봇 오케스트레이터 (정책 엔진) ↓ 정책 데이터 (키워드 / 템플릿) ↓ 저장 계층 (SQLite/CSV/Excel) ↓ 에스컬레이션 / 이관 (Email / 수동 대응)

도메인 원칙

원칙

목표는 실제 운영 환경의 변동성 속에서도 일관된 동작을 유지하는 것입니다. 메시지 분류는 결정적으로 수행되고, 정책 조회는 중앙화되며, 불확실한 경우에는 침묵적으로 추측하지 않고 명시적인 폴백(질문 감지/에스컬레이션) 경로로 전환합니다.

Impact: 반복적인 수동 응답을 줄이고 더 빠르고 일관된 고객 응답을 가능하게 했습니다. 또한 정책(키워드/템플릿)은 데이터로 관리되어, 핵심 오케스트레이션 로직을 크게 수정하지 않고도 동작을 점진적으로 개선할 수 있습니다.

Trade-offs: 중앙화된 정책 엔진은 소규모 내부 도구에선 운영이 단순하지만, 정책이 늘어나면 복잡도가 증가할 수 있습니다. 향후 개선에서는 전략(Strategy) 핸들러와 더 강한 타입의 메시지 의도 모델을 도입해 관심사를 분리하고 확장성을 높일 수 있습니다.

정책 우선 워크플로우

메시지는 예측 가능한 파이프라인으로 처리됩니다: 분류 → 정책 매칭 → 응답 → 로깅 → 필요 시 이관(에스컬레이션).

명시적 폴백

확신 있는 매칭이 없으면 임의로 추측하지 않고, 질문 감지 또는 에스컬레이션 등 명시적인 폴백 경로로 전환합니다.

스토리지 경계

영속성 및 내보내기(SQLite/CSV/Excel)는 헬퍼 계층 뒤로 격리하여, 정책 로직이 읽기 쉽고 변경에 안전하도록 유지합니다.

운영 중심

실제 운영을 전제로 설계했습니다: 예측 가능한 규칙, 로그 기반 관찰 가능성, 그리고 사람이 개입할 수 있는 안전한 이관.

Example: PocketQuest와 동일한 경계 원칙을 적용했습니다. 오케스트레이션 흐름은 간결하게 유지하고, 인프라 세부사항(Selenium/SMTP/저장소)은 헬퍼 계층 뒤에 격리했습니다.

코드 발췌

코드

다음 발췌문은 메시징 오케스트레이션의 핵심 경계를 담고 있습니다: 결정적 분기, 중앙화된 정책 조회, 격리된 인프라 헬퍼, 그리고 명시적인 담당자 이관 경로.

오케스트레이터 분기 (핵심 정책 흐름)

핵심 워크플로우: 구조화된 세부사항 추출, 결정적 분기, 결과 로깅, 필요 시 담당자에게 이관.

// src/models/Automate.java (excerpt)
HashMap<String, String> details = Util.fetchDetails(customerMsg);
String email = details.get("email");
String phone = Util.formatPhoneNumber(details.get("number"));

if(!email.contentEquals("")) {
  String reply = BotAnswers.getInstance()
    .getAnswerHasEmail()
    .replace(AnswerReferences.AGENT_NAME.toString(), agentName)
    .replace(AnswerReferences.AGENT_NUMBER.toString(), agentNumber);

  sendMessage(reply);
  ExcelHelper.saveMessage(name, customerMsg);

  Email.send(record.getString("subject"),
              record.getString("email"),
              mailText);
  return;
}

// Keyword-based response
String msg = DBHelper.getKeywordBasedMessage(itemId, customerMsg);
if(msg != null && !totalMessage.contains(msg)) {
  sendMessage(msg);
  return;
}

// Question fallback → escalate
if(customerMsg.contains("?")) {
  Email.send("Need Manual Reply", agentEmail, customerMsg);
}

정책 조회 엔진 (AND/OR/단일/전역)

규칙이 명확한 우선순위로 평가되어 정책 진화 시에도 동작이 예측 가능하게 유지됩니다.

// src/storages/DBHelper.java (excerpt)
public static String getKeywordBasedMessage(String itemId, String keyword)
    throws SQLException {

  String response;

  response = getAndFromTagBased(itemId, keyword);
  if(!response.isEmpty()) return response;

  response = getOrFromTagBased(itemId, keyword);
  if(!response.isEmpty()) return response;

  response = getOnlyOneTagBased(itemId, keyword);
  if(!response.isEmpty()) return response;

  return getFromAllTagBased(keyword);
}

SQLite PreparedStatement (정책은 데이터에 유지)

키워드 정책이 SQLite에 있어 오케스트레이션 코드 변경 없이 동작을 업데이트할 수 있습니다.

// src/storages/DBHelper.java (excerpt)
PreparedStatement ps = DB.getInstance().prepareStatement(
  "SELECT * FROM keyword " +
  "WHERE ? LIKE '%'||keyword.keyword||'%' " +
  "AND product_id = ?"
);

인프라 경계: ChromeDriver 생명주기

WebDriver 생성/설정이 중앙화되어 오케스트레이션을 읽기 쉽고 복원력 있게 유지합니다.

// src/models/apis/ChromeDriverHelper.java (excerpt)
if(conn == null) {
  System.setProperty(WEB_DRIVER_ID, WEB_DRIVER_PATH);

  ChromeOptions options = new ChromeOptions();
  options.addArguments("--disable-extensions");
  options.addArguments("--ignore-certificate-errors");

  conn = new ChromeDriver(options);
}
return conn;

의미 있는 실패 시맨틱 (래퍼 + 커스텀 예외)

Selenium 실패가 도메인 수준 예외로 변환되어 실패가 명시적이고 진단 가능해집니다.

// src/models/utils/Util.java (excerpt)
public static WebElement findElement(FindElementBy by, String target)
    throws ElementNotFoundException {
  try {
    WebDriver driver = ChromeDriverHelper.getInstance().getConnection();
    return driver.findElement(By.xpath(target));
  } catch (Exception e) {
    throw new ElementNotFoundException(
      Util.getStackTrace(Thread.currentThread().getStackTrace())
    );
  }
}

이 발췌문들은 시스템 우선 설계를 보여줍니다: 결정적 분기가 있는 단일 오케스트레이터, 데이터 기반 정책 계층(SQLite), 격리된 인프라 헬퍼(Selenium/SMTP), 그리고 낮은 신뢰도 사례를 위한 명시적 에스컬레이션 경로.

Java 데스크톱 도구이지만, 이 경험은 이후 풀스택 작업에도 그대로 이어졌습니다. 명시적 경계, 중앙화된 정책, 운영과 유지보수가 쉬운 예측 가능한 동작이라는 원칙을 일관되게 적용합니다.