06 · Developer Guide · 레시피

AI 안내봇 (FAQ 즉답형)Chatbot / AI Assistant

예배·위치·새가족 등 자주 묻는 질문을 사이트 안에서 즉답하는 플로팅 안내봇.
외부 AI 키·서버 없이 키워드 매칭 FAQ로 동작하며, 나중에 Claude API 한 단계만 얹어 자연어 챗봇으로 확장할 수 있습니다.

언제 쓰는가

  • 예배 시간·오시는 길·새가족·주보·교구 등 반복 문의를 24시간 즉답
  • 사무실 전화 응대 부담 경감 (모르면 사무국 번호로 안내)
  • 운영 비용 0원으로 먼저 도입하고, 트래픽이 늘면 AI로 승급

구조 — 3단 파이프라인

비용을 최소화하는 단계형 응답 구조입니다. 현재 시안은 ①단계(FAQ 즉답)만 사용하므로 API 비용이 0원입니다.

  1. ① FAQ 즉답 — 키워드 매칭으로 정해진 답을 반환. 모델 호출 없음, 비용 $0.
  2. ② 응답 캐시 (선택) — 과거 AI 답을 해시로 재사용.
  3. ③ AI 호출 (선택) — ①②가 실패할 때만 Claude 호출.

① FAQ 지식베이스 + 매칭

lib/preview/chatbot-faq.tstsx
// lib/preview/chatbot-faq.ts
export type FaqLink = { label: string; href: string };

export type FaqItem = {
  id: string;
  suggest?: string;        // 추천 질문 칩 라벨
  keywords: string[];      // 사용자 입력에 포함되면 가점
  answer: string;          // 답변 본문 (\n 줄바꿈 지원)
  links?: FaqLink[];       // 답변 하단 바로가기 (내부 라우트만)
};

export const FAQ_ITEMS: FaqItem[] = [
  {
    id: "worship-time",
    suggest: "예배 시간이 언제인가요?",
    keywords: ["예배", "시간", "몇시", "언제", "주일", "새벽", "수요"],
    answer:
      "주일예배는 1부 07:00 · 2부 09:00 · 3부 11:00 · 4부 12:50 · 5부(청년) 14:30…",
    links: [{ label: "예배 안내 자세히 보기", href: "/site/worship" }],
  },
  // … 위치 · 새가족 · 주보 · 교구 · 큐티 · 교역자 · 양육 · 선교 · 헌금 · 문의
];

// 키워드 가점으로 가장 잘 맞는 FAQ를 찾는다. 0점이면 null(→ fallback).
export function matchFaq(input: string): FaqItem | null {
  const text = input.toLowerCase().replace(/\s+/g, " ").trim();
  if (!text) return null;
  let best: FaqItem | null = null;
  let bestScore = 0;
  for (const item of FAQ_ITEMS) {
    let score = 0;
    for (const kw of item.keywords) {
      if (text.includes(kw.toLowerCase().trim())) score += kw.length >= 2 ? 2 : 1;
    }
    if (score > bestScore) { bestScore = score; best = item; }
  }
  return bestScore > 0 ? best : null;
}

위젯 컴포넌트

components/preview/ChatWidget.tsxtsx
// components/preview/ChatWidget.tsx  (요약)
"use client";
import { useState } from "react";
import { matchFaq, CHATBOT_INTRO, CHATBOT_FALLBACK, SUGGESTED } from "@/lib/preview/chatbot-faq";

export function ChatWidget() {
  const [open, setOpen] = useState(false);
  const [messages, setMessages] = useState([{ role: "bot", text: CHATBOT_INTRO }]);

  function send(text: string) {
    const q = text.trim();
    if (!q) return;
    const hit = matchFaq(q);                                  // ① FAQ 즉답 (무료)
    const bot = hit
      ? { role: "bot", text: hit.answer, links: hit.links }
      : { role: "bot", text: CHATBOT_FALLBACK };              // ② 미스 → 사무실 안내
    setMessages((m) => [...m, { role: "user", text: q }, bot]);
  }

  // 플로팅 버튼(+"안내봇" 뱃지) → 패널(모바일 풀스크린 / 데스크톱 380×560)
  // 헤더(초기화·닫기) · 말풍선 · 추천질문 칩(SUGGESTED) · 입력창 · 면책 푸터
  // …
}

마운트

tsx
// app/(site)/layout.tsx — 모든 시안 페이지에 공통 마운트
import { ChatWidget } from "@/components/preview/ChatWidget";

export default function SiteLayout({ children }) {
  return (
    <div className="flex min-h-screen flex-col">
      <PreviewHeader />
      <div className="flex-1">{children}</div>
      <PreviewFooter />
      <ChatWidget />        {/* 우하단 플로팅 */}
    </div>
  );
}

설계 포인트

확장 — Claude AI 하이브리드

자연어 대응이 필요해지면, 현재 구조를 그대로 두고 FAQ 미스일 때만 Claude를 호출하는 API route 한 단계만 추가하면 됩니다. (Anthropic API 키 + 월 소액 토큰 비용)

app/api/chat/route.ts (확장 예시)tsx
// (확장) FAQ 미스일 때만 Claude 호출 — app/api/chat/route.ts
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();  // ANTHROPIC_API_KEY (서버 환경변수)

export async function POST(req: Request) {
  const { question } = await req.json();
  const msg = await client.messages.create({
    model: "claude-haiku-4-5-20251001",
    max_tokens: 400,
    system: SYSTEM_PROMPT,   // 지침 + 시안 데이터(예배·교구·선교…) + 링크 화이트리스트
    messages: [{ role: "user", content: question }],
  });
  return Response.json({ answer: msg.content[0].text });
}
// 위젯 send(): matchFaq() 실패 시 fetch("/api/chat") 한 단계만 추가하면 됨
Need Help

도움이 필요하신가요?

주님의교회 PCL 디자인 시스템을 적용하시다가 막히는 부분이 있다면, 다음 경로로 직접 문의하실 수 있습니다.