Stored Procedures를 활용한 보안 이커머스 채팅 에이전트 구축

발행: (2026년 1월 6일 오후 11:58 GMT+9)
8 min read
원문: Dev.to

I’m happy to translate the article for you, but I need the text you’d like translated. Could you please paste the content (or the portion you want translated) here? I’ll keep the source line exactly as you provided it and translate the rest into Korean while preserving all formatting.

배경

최근에 나는 특정 전자상거래 플랫폼용 GPT‑유사 채팅 에이전트를 구축하려고 시도했다 – 일반적인 챗봇이 아니라, 데모도 아닌, 실제 제품에 적용되는 어시스턴트로서 다음과 같은 질문에 답할 수 있어야 했다:

  • “내 주문은 어디에 있나요?”
  • “환불을 받을 수 있나요?”
  • “마지막 구매를 보여줘.”

이를 위해 에이전트는 실제 운영 데이터에 접근해야 했다 – 주문, 배송, 결제 등. 바로 그때 중요한 문제에 직면했다.

내가 직면한 문제

에이전트가 데이터베이스 접근이 필요해지면, 유혹적인 생각이 떠오릅니다:

“왜 LLM이 사용자의 질문을 기반으로 SQL을 생성하도록 그냥 두지 않을까?”

간단해 보이고 데모에서는 잘 작동하지만, 실제 전자상거래 시스템에서는 금방 위험해집니다.

Scenario

You are building a chat application for a specific e‑commerce platform. The chat agent supports:

  • Order status inquiries → 주문 상태 조회
  • Shipping & delivery tracking → 배송 및 배송 추적
  • Refund eligibility checks → 환불 자격 확인
  • Purchase history summaries → 구매 내역 요약
  • Account‑related questions → 계정 관련 질문

This is not a general‑purpose GPT. It is a platform‑bound assistant with access to sensitive user data.

Source:

핵심 문제

채팅 에이전트는 종종 데이터베이스 접근이 필요합니다. 일반적이지만 안전하지 않은 접근 방식은 다음과 같습니다:

  1. 데이터베이스 스키마를 LLM에 공유한다.
  2. 사용자 입력을 바탕으로 LLM에게 SQL을 생성하도록 요청한다.
  3. 그 SQL을 바로 실행한다.

실제 운영 환경에서는 이 접근 방식이 실패합니다.

LLM이 생성한 SQL이 나쁜 이유

보안 위험

  • 프롬프트 인젝션으로 쿼리를 조작할 수 있습니다.
  • SELECT *와 같이 과도하게 포괄적인 쿼리는 민감한 데이터를 노출시킵니다.
  • 권한 상승이 가능해집니다.

환각된 쿼리

  • 존재하지 않는 테이블이나 컬럼.
  • 잘못된 조인.
  • 잘못된 비즈니스 로직.

거버넌스 부재

  • 허용되는 쿼리에 대한 명확한 계약이 없습니다.
  • 데이터 접근을 감사하기 어렵습니다.
  • 스키마 변경으로 프롬프트가 깨집니다.

핵심 원칙

LLM은 어떤 의도를 수행할지는 결정하지만, 데이터를 어떻게 쿼리할지는 결정하지 않아야 합니다.
이는 전통적인 백엔드 설계와 일치합니다.

올바른 아키텍처: 저장 프로시저를 에이전트 도구로 활용

고수준 흐름

Architecture diagram

주요 설계 규칙

  • 데이터베이스 로직은 저장 프로시저에 존재합니다.
  • LLM은 테이블 이름이나 컬럼을 절대 보지 못합니다.
  • 에이전트는 어떤 프로시저를 호출할지만 선택합니다.

단계 1: 저장 프로시저 정의 (데이터베이스 계층)

최신 주문 가져오기

CREATE PROCEDURE get_latest_order (
  IN p_user_id BIGINT
)
BEGIN
  SELECT
    order_id,
    order_status,
    total_amount,
    created_at
  FROM orders
  WHERE user_id = p_user_id
  ORDER BY created_at DESC
  LIMIT 1;
END;
  • ✔ 사용자 수준 데이터 격리를 적용합니다.
  • ✔ 에이전트에게 스키마가 노출되지 않습니다.

주문에 대한 배송 상태 가져오기

CREATE PROCEDURE get_order_shipping_status (
  IN p_order_id BIGINT,
  IN p_user_id BIGINT
)
BEGIN
  SELECT
    shipping_provider,
    tracking_number,
    shipping_status,
    estimated_delivery
  FROM shipments
  WHERE order_id = p_order_id
    AND user_id = p_user_id;
END;
  • ✔ 데이터베이스 수준에서 소유권 검증을 수행합니다.
  • ✔ 사용자 간 접근을 방지합니다.

Step 2: 절차를 에이전트 도구로 노출하기

The LLM은 SQL을 보지 않으며, 도구를 봅니다:

[
  {
    "name": "get_latest_order",
    "description": "Get the most recent order for the authenticated user",
    "parameters": {}
  },
  {
    "name": "get_order_shipping_status",
    "description": "Get shipping details for a specific order",
    "parameters": {
      "order_id": "number"
    }
  }
]

User identity는 시스템에 의해 주입됩니다 – LLM이 아니라.

Step 3: 에이전트 추론 흐름

사용자 메시지

Where is my last order?

에이전트 행동

  1. 의도를 식별합니다: order inquiry.
  2. 주문 ID가 제공되지 않음 → get_latest_order 호출.
  3. 반환된 order_id를 사용하여 get_order_shipping_status를 호출합니다.

단계 4: 사용자 응답

Your latest order was placed on March 2.

Status: Shipped
Carrier: Yamato
Tracking Number: 1234‑5678
Estimated Delivery: March 6

고급 예시: 환불 자격

저장 프로시저

CREATE PROCEDURE check_refund_eligibility (
  IN p_order_id BIGINT,
  IN p_user_id BIGINT
)
BEGIN
  SELECT
    CASE
      WHEN order_status = 'DELIVERED'
           AND DATEDIFF(NOW(), delivered_at) <= 7
      THEN 'ELIGIBLE'
      ELSE 'NOT_ELIGIBLE'
    END AS refund_status
  FROM orders
  WHERE order_id = p_order_id
    AND user_id = p_user_id;
END;

비즈니스 규칙은 프롬프트에서 제외합니다.

왜 이 설계가 효과적인가

기본 보안

  • 임의의 SQL 실행이 없습니다.
  • 엄격한 접근 경계.
  • 최소한의 영향 범위.

환각 방지

  • LLM이 테이블이나 조인을 만들어낼 수 없습니다.
  • 허용된 작업만 호출 가능합니다.

강력한 가시성

각 호출은 다음과 같이 기록될 수 있습니다:

user_id=123
tool=check_refund_eligibility
order_id=88921
timestamp=2026-01-06T12:34:56Z

Stored Procedures vs. LLM‑Generated SQL

항목LLM‑Generated SQLStored Procedures
보안❌ 위험함✅ 안전함
환각❌ 흔함✅ 불가능
감사❌ 어려움✅ 용이
스키마 변경❌ 프롬프트 깨짐✅ 격리됨
엔터프라이즈‑준비❌ 아니오✅ 예

Final Thoughts

Chat agents feel new, but backend fundamentals still apply.

Treat your database like a private API.

Stored procedures give you:

  • Safety
  • Stability
  • Observability
  • Enterprise‑grade control

This is how you build real, production‑ready e‑commerce chat agents — not demos.

Back to Blog

관련 글

더 보기 »