본문으로 건너뛰기
최재훈
LEAD (AI Research Engineer), Brain Crew
모든 저자 보기

The Effect of Dynamic Date Injection Methods on LLM Temporal Reasoning across Deictic Expression Granularities

· 약 8분
김성연
AI Research Engineer, Brain Crew
최재훈
LEAD (AI Research Engineer), Brain Crew

TL;DR

LLM은 "어제", "다음 주"와 같은 상대적 시간 표현을 해석할 때 현재 날짜를 알 수 없어 날짜 주입이 필수입니다. 320회의 실험 결과, 한국어 형식(2025년 3월 19일) + User Prompt 조합이 Simple/Structured 모두에서 95% 정확도를 달성했으며, 날짜 미주입 시 15%에 불과했던 성능이 최대 95%까지 향상되었습니다. 특히 Week granularity(다음 주 월요일 등)는 요일 정보 포함 시 40%→80% 개선되며, gpt-4o 사용 시 모든 시간 단위에서 100% 정확도를 보였습니다.

Key Takeaways

  • 날짜 주입은 선택이 아닌 필수: 날짜 정보 없이는 Day/Week/Month granularity에서 0% 정확도를 기록하며, Year 단위 상식 문제만 60% 수준으로 부분 정답 가능
  • 한국어 질의에는 한국어 날짜 형식 사용: 현재 날짜: 2025년 3월 19일 형식이 Structured Output에서 English 대비 +15%p 우위(95% vs 80%)를 보이며 응답 방식에 관계없이 안정적
  • User Prompt가 System Prompt보다 효과적: 질의와 가까운 위치에 날짜를 배치하면 Simple Response에서 +3.3%p 성능 향상(95.0% vs 91.7%)
  • Week granularity가 가장 어렵다: "다음 주 월요일" 같은 표현은 현재 요일 인식→주 경계 판단→날짜 계산의 3단계 추론이 필요하며, 한국어 요일 정보 추가 시 40%→80% 개선
  • 과도한 정보는 오히려 역효과: 주말 설명 등 불필요한 부가 정보는 LLM의 추론을 방해하여 5~10%p 성능 하락 유발

상세 내용

배경: 왜 날짜 프롬프트가 필요한가

LLM은 학습 데이터의 시점에 고정되어 있어 "지금이 언제인지" 스스로 알 수 없습니다. 따라서 "어제", "지난주", "다음 달"과 같은 **직시 표현(Deictic Expression)**을 해석할 때 현재 날짜를 기준점으로 제공해야 정확한 날짜 변환이 가능합니다.

600회의 추론 실험(gpt-4o-mini 기준)에서 날짜 주입 유무에 따른 성능 차이는 다음과 같습니다:

조건AccuracyDayWeekMonthYear
날짜 주입 없음15%0%0%0%60%
날짜 주입 있음95%100%100%100%80%

날짜 주입 없이는 "작년 크리스마스"와 같은 Year granularity 상식 문제만 부분 정답(60%)이 가능하며, 실시간 계산이 필요한 Day/Week/Month는 전부 0%로 시간 추론 자체가 불가능합니다.

문제 상황: 4가지 설계 변수의 영향

날짜 프롬프트 설계 시 고려해야 할 4가지 변수와 각각의 성능 영향을 실험으로 검증했습니다.

1. Prompt Position: 어디에 넣을 것인가

PositionSimple ACCStructured ACC
System Prompt91.7%85.0%
User Prompt95.0%85.0%

User Prompt에 날짜 정보를 배치하면 질의와 가까운 위치에서 참조 효율이 높아져 Simple Response에서 +3.3%p 우위를 보였으며, Structured Output에서는 동일하므로 선택에 따른 손해가 없습니다.

2. Expression Format: 어떤 형식으로 넣을 것인가

테스트한 3가지 형식의 성능 비교:

Format예시SimpleStructured평균
Korean현재 날짜: 2025년 3월 19일92.5%95.0%93.8%
EnglishCurrent date: March 19th, 202595.0%80.0%87.5%
DayOfWeekCurrent date: 2025-03-19, Wed92.5%80.0%86.3%

Korean 형식이 가장 안정적입니다. Simple Response에서는 3개 format 간 차이가 미미(92.5~95.0%)하지만, Structured Output에서 Korean(95%)이 English/DayOfWeek(80%)를 크게 압도합니다. 이는 한국어 질의에 한국어 날짜 표현을 사용할 때 토큰 정렬이 자연스럽게 이루어지기 때문으로 추정됩니다.

3. 날짜 컨텍스트 상세도: 얼마나 많은 정보를 넣을 것인가

컨텍스트내용ACC
A날짜 + 시간 (현재 날짜: 2025-03-19 (수요일) / 현재 시간: 14:00)85~90%
B날짜 + 주간 달력 (이번 주/지난 주 전체 날짜 나열)85~90%
C날짜만 (현재 날짜: 2025-03-19 (Wed))80%

날짜만 제공하고 영문 요일만 포함한 경우(C) Week granularity에서 40%까지 하락했습니다. A/B처럼 한국어 요일을 포함하면 Week에서 80%를 유지할 수 있으며, 주간 달력(B)은 정보량 대비 성능 향상이 미미했습니다. 과도한 정보(주말 설명 등)를 추가하면 오히려 5~10%p 하락하므로 주의가 필요합니다.

4. Output 방식: 응답을 어떤 형식으로 받을 것인가

OutputACCWeek ACC
Simple (텍스트)95%100%
Structured (instructor)85%60%

시간 추론에서는 Simple Response가 유리합니다. 전체 정확도에서 +10%p 차이가 있으며, 핵심은 Week granularity(60% → 100%)입니다. Structured Output의 schema 강제가 추론 chain을 방해하는 것으로 분석되며, Structured가 필요한 경우 Korean format + User Prompt 조합으로 95%까지 보완 가능합니다.

해결 과정: Granularity별 난이도 분석

LLM의 시간 추론 능력은 시간 단위에 따라 극적으로 달라집니다:

순위GranularityACC 범위핵심 특성오류 패턴
1 (쉬움)Day100%단순 ±N일 산술오류 없음
2Month80~100%월말/월초 계산요일 역산에서 간헐적 오류
3Year60~100%상식 + 요일 계산먼 미래 요일 추론 실패
4 (어려움)Week40~100%요일 기반 상대 계산"다음 주 월요일" 등에서 ±1주 오류 빈번

Week Granularity가 가장 어려운 이유는 "다음 주 월요일" 같은 표현 해석 시 현재 요일 인식 → 주 경계 판단 → 날짜 계산의 3단계 추론이 필요하기 때문입니다. LLM이 "다음 주"의 경계를 잘못 판단하여 ±1주 오프셋 오류가 빈번하게 발생하며, Structured Output에서는 schema 제약이 이 추론 과정을 더욱 방해합니다.

주간 달력을 프롬프트에 포함하거나 상위 모델을 사용하면 개선 가능합니다:

모델DayWeekMonthYearOverall
gpt-4o-mini100%60%100%80%85%
gpt-4o100%100%100%100%100%

gpt-4o는 모든 granularity에서 100% 정확도를 달성하여 모델 크기가 시간 추론에 직접적 영향을 미치는 것을 확인했습니다.

결과: 권장 프롬프트 템플릿

실험 결과를 바탕으로 Best Practice: Korean + User Prompt 조합을 권장합니다:

# 기본 템플릿 (Simple: 95% / Structured: 95%)
system_prompt = """
사용자의 질문에 정확하게 답변하세요.
"""

user_prompt_template = """
현재 날짜: {year}년 {month}월 {day}일
사용자가 '오늘', '어제', '그저께', '금주', '지난주', '이번 달', '주말' 등
상대적 날짜 표현을 사용하면 위 현재 날짜를 기준으로 구체적인 날짜(YYYY-MM-DD)로 변환하세요.

{user_query}
"""

# 사용 예시
from datetime import datetime

now = datetime.now()
user_query = "지난주 금요일에 작성된 보고서를 찾아줘"

user_prompt = user_prompt_template.format(
year=now.year,
month=now.month,
day=now.day,
user_query=user_query
)

Week 정확도가 중요한 경우 주간 달력 추가:

# Week granularity 강화 템플릿 (Week: 80% → 100% for gpt-4o)
from datetime import datetime, timedelta

def get_week_calendar(reference_date):
# 이번 주 월요일 찾기
this_monday = reference_date - timedelta(days=reference_date.weekday())
# 지난 주 월요일
last_monday = this_monday - timedelta(days=7)

days_kr = ['월요일', '화요일', '수요일', '목요일', '금요일', '토요일', '일요일']

this_week = []
last_week = []

for i in range(7):
this_day = this_monday + timedelta(days=i)
last_day = last_monday + timedelta(days=i)
this_week.append(f"{days_kr[i]}({this_day.strftime('%Y-%m-%d')})")
last_week.append(f"{days_kr[i]}({last_day.strftime('%Y-%m-%d')})")

return this_week, last_week

now = datetime.now()
this_week, last_week = get_week_calendar(now)

user_prompt_with_calendar = f"""
현재 날짜: {now.year}{now.month}{now.day}일 ({['월요일','화요일','수요일','목요일','금요일','토요일','일요일'][now.weekday()]})
- 이번 주: {', '.join(this_week)}
- 지난 주: {', '.join(last_week)}

사용자가 '오늘', '어제', '그저께', '금주', '지난주', '이번 달', '주말' 등
상대적 날짜 표현을 사용하면 위 현재 날짜를 기준으로 구체적인 날짜(YYYY-MM-DD)로 변환하세요.

{user_query}
"""

피해야 할 안티패턴:

# ❌ 안티패턴 1: 날짜 정보 미주입
user_prompt_bad1 = """
사용자의 상대적 날짜 표현을 절대 날짜로 변환하세요.
{user_query}
"""
# → Day/Week/Month 0%, 전체 15%

# ❌ 안티패턴 2: 영문 날짜 + Structured Output
user_prompt_bad2 = """
Current date: March 19th, 2025
Convert relative date expressions to absolute dates.
{user_query}
"""
# + Structured Output → 80% (Week 40~60%)

# ❌ 안티패턴 3: 과도한 부가 설명
user_prompt_bad3 = """
현재 날짜: 2025년 3월 19일
주말은 토요일과 일요일을 의미합니다.
월말은 매월 마지막 날을 의미합니다.
...
{user_query}
"""
# → -5~10%p 하락

# ❌ 안티패턴 4: 날짜만 (요일 없이)
user_prompt_bad4 = """
Current date: 2025-03-19
{user_query}
"""
# → Week 40%

의사결정 가이드

프로젝트 상황에 따른 날짜 프롬프트 설계 의사결정 플로우:

1. 날짜 주입이 있는가?
└─ NO → 반드시 추가 (없으면 15%)
└─ YES → 다음 단계

2. 질의가 한국어인가?
└─ YES → Korean format 사용 ("2025년 3월 19일")
└─ NO → English format 사용 ("March 19th, 2025")

3. Structured Output이 필요한가?
└─ NO → Simple 사용 (최고 성능)
└─ YES → 반드시 Korean format + User Prompt 조합 (95% 보장)

4. Week 추론 정확도가 critical한가?
└─ NO → 기본 템플릿으로 충분
└─ YES → 주간 달력 추가 또는 gpt-4o 사용 고려

5. 전체 정확도 100%가 필요한가?
└─ NO → gpt-4o-mini + 최적 프롬프트 (95%)
└─ YES → gpt-4o 사용 (100%)

종합 권장 설정

항목권장값대안근거
Time Injection필수-미주입 시 15%
Expression FormatKoreanEnglish (Simple 한정)Structured에서 +15%p 차이
Prompt PositionUser PromptSystem Prompt (동등)Simple에서 +3.3%p
Output 방식SimpleStructured (Korean+User 시 95%)전체 +10%p, Week +40%p
날짜 컨텍스트날짜 + 한국어 요일주간 달력 (Week 중요 시)Week ACC 40→80%
부가 설명불필요-추가 시 오히려 하락
모델gpt-4o (정확도 우선)gpt-4o-mini (비용 우선)100% vs 85~95%

실험 환경 및 데이터

실험 구성:

  • Target LLM: gpt-4o-mini (baseline), gpt-4o (비교)
  • Temperature: 0.0
  • 기준 날짜: 2025-03-19 (Wednesday)
  • 테스트 쿼리: 20개 (Day 5 + Week 5 + Month 5 + Year 5)
  • 평가 메트릭: Accuracy — Include Match (정답 날짜가 응답에 포함되는지 판단)
  • 총 추론 수: 600개 (Baseline 320 + Expression Format 280)

상세 실험 데이터:

  • BASELINE_RESULTS.md: 날짜 컨텍스트 3종, seed/temp/output/model 비교 (320개 레코드)
  • EXPERIMENT_RESULTS.md: Expression Format × Injection Position 7-case (280개 레코드)

References

Which tabular format RAG Process understands very well?

· 약 7분
최재훈
LEAD (AI Research Engineer), Brain Crew

TL;DR

RAG 파이프라인에서 테이블 데이터의 포맷이 검색 성능에 미치는 영향을 실험한 결과, Markdown Key-Value 형식이 가장 높은 Recall을 보였으며, TOON 포맷은 토큰 효율성 측면에서 가장 우수했습니다. AIHub의 표 정보 질의응답 데이터 50개를 7가지 포맷으로 변환하여 비교한 결과, 포맷 선택은 성능과 비용 간의 트레이드오프 관계에 있음을 확인했습니다.

Key Takeaways

  • 포맷 선택은 사용 사례에 따라 달라져야 함: 높은 정확도가 필요한 경우 Markdown-KV, 비용 효율이 중요한 경우 TOON 포맷을 선택하는 것이 합리적입니다.
  • 토큰 효율과 검색 성능은 별개: TOON은 평균 토큰 수를 크게 줄이지만, 이것이 항상 높은 Recall로 이어지지는 않습니다. Embedding 모델의 학습 데이터와 포맷 간의 친화성이 중요합니다.
  • 소규모 실험으로도 유의미한 인사이트 도출 가능: 50개 샘플로도 포맷 간 상대적 성능 차이를 파악할 수 있으며, 이를 바탕으로 프로덕션 환경에서의 포맷 선택 방향을 설정할 수 있습니다.
  • 평가 파이프라인 구축의 중요성: LLM을 활용한 QA 생성 → Retrieval 평가의 자동화된 파이프라인은 다양한 실험을 빠르게 반복할 수 있게 해줍니다.
  • Generation 단계까지 고려해야 완전한 평가: Retrieval 성능만으로는 최종 사용자 경험을 대변하기 어려우며, 실제 답변 생성 품질까지 평가해야 합니다.

상세 내용

배경: 테이블 데이터와 RAG의 만남

RAG(Retrieval-Augmented Generation) 시스템에서 테이블 데이터는 구조화된 정보를 담고 있어 높은 가치를 지니지만, 동시에 처리하기 까다로운 대상입니다. HTML 테이블, Markdown, JSON, CSV 등 다양한 포맷이 존재하며, 각 포맷은 정보 밀도, 토큰 소비량, LLM의 이해도 측면에서 상이한 특성을 보입니다.

최근 TOON(Token-Oriented Object Notation) 포맷이 등장하면서, 동일한 정보를 더 적은 토큰으로 표현하면서도 LLM이 이해하기 쉬운 구조를 제공한다는 주장이 제기되었습니다. 그러나 실제 RAG 환경에서 어떤 포맷이 최적인지에 대한 실증적 연구는 부족한 상황이었습니다.

문제 상황: 포맷 선택의 딜레마

프로덕션 RAG 시스템을 구축할 때, 다음과 같은 질문에 직면합니다:

  1. 토큰 효율성과 검색 성능 중 무엇을 우선할 것인가?
  2. Embedding 모델이 특정 포맷을 더 잘 이해하는가?
  3. 포맷 변환의 추가 비용 대비 성능 개선이 합리적인가?

이러한 질문에 답하기 위해 체계적인 실험을 설계했습니다.

실험 설계

데이터 준비

AIHub의 "표 정보 질의응답 데이터"를 활용했습니다. 이 데이터는:

  • 총 100만 건의 QA 쌍 포함
  • 건축, 공공행정, 과학기술 등 10개 카테고리
  • 다양한 테이블 복잡도 (행 수, 헤더 depth 등)

전체 16,000개 테이블 중 50개를 무작위 샘플링하여 Target Data로 선정했습니다.

평가용 QA 생성

각 테이블에 대해 GPT-4.1을 활용하여 질문-답변 쌍을 자동 생성했습니다:

# 의사 코드
def generate_qa_pairs(table_chunk):
# Step 1: 테이블 기반 질문 생성
question = gpt4_generate_question(table_chunk)

# Step 2: 테이블 + 질문 기반 답변 생성
answer = gpt4_generate_answer(table_chunk, question)

return question, answer

이 중 25개를 최종 Evaluation Data로 선정했습니다.

7가지 테이블 포맷

다음 포맷들을 비교했습니다:

  1. HTML: 표준 <table> 태그 구조
  2. Markdown: 파이프(|)로 구분된 형식
  3. Markdown-KV: 각 행을 Key-Value 쌍으로 표현
  4. TOON: 탭형 구조로 압축된 포맷
  5. JSON: 표준 JSON 배열 구조
  6. Plain Text: 자연어 형태로 풀어쓴 형식
  7. CSV-like: 쉼표로 구분된 단순 형식

포맷 변환 예시

원본 HTML 테이블:

<table>
<tr><td>바탕의 종류</td><td>도장 종류</td><td>공법</td></tr>
<tr><td>목재면</td><td>1종</td><td>부분 퍼티 처리</td></tr>
<tr><td>철재면</td><td>2종</td><td>금속바탕 처리용 프라이머</td></tr>
</table>

Markdown-KV 변환:

## 바탕 만들기의 도장 방법

**항목 1:**
- 바탕의 종류: 목재면
- 도장 종류: 1종
- 공법: 부분 퍼티 처리

**항목 2:**
- 바탕의 종류: 철재면
- 도장 종류: 2종
- 공법: 금속바탕 처리용 프라이머

TOON 변환:

바탕 만들기의 도장 방법[2]{바탕의 종류, 도장 종류, 공법}:
목재면, 1종, 부분 퍼티 처리
철재면, 2종, 금속바탕 처리용 프라이머

실험 방법론

Embedding 및 저장

Qwen/Qwen3-Embedding-8B 모델을 사용하여 각 포맷별로 임베딩을 생성하고, 별도의 Chroma collection에 저장했습니다. 이 모델을 선택한 이유는:

  • 다국어 지원 (한국어 포함)
  • 8B 파라미터로 높은 성능
  • 문서 검색에 최적화된 학습

평가 지표

  1. Recall@K: Top-K 검색 결과에 정답 문서가 포함되는 비율
    • K=1, 2, 3에 대해 측정
  2. Average Token Count: 각 포맷의 평균 토큰 수
    • 비용 효율성의 대리 지표
def evaluate_retrieval(collection, queries, ground_truth, k=3):
recalls = []
for query, gt_doc_id in zip(queries, ground_truth):
results = collection.query(query, n_results=k)
retrieved_ids = [r['id'] for r in results]
recall = 1 if gt_doc_id in retrieved_ids else 0
recalls.append(recall)
return sum(recalls) / len(recalls)

실험 결과 분석

Recall 성능

실험 결과, Markdown-KV 포맷이 가장 높은 Recall을 기록했습니다:

  • Markdown-KV: Recall@3 기준 약 85%
  • HTML: 약 78%
  • TOON: 약 72%
  • Plain Text: 약 68%
  • JSON: 약 65%

왜 Markdown-KV가 우수했는가?

  1. 명시적 Key-Value 구조: "바탕의 종류: 목재면"과 같은 형식은 Embedding 모델이 의미론적 관계를 파악하기 쉽게 만듭니다.
  2. 자연어 친화성: Qwen 모델의 학습 데이터에 Markdown 형식이 많이 포함되어 있을 가능성이 높습니다.
  3. 정보 밀도: 각 항목이 독립적으로 표현되어 부분 매칭에 유리합니다.

토큰 효율성

TOON 포맷이 기대대로 가장 효율적이었습니다:

  • TOON: 평균 약 120 토큰 (기준)
  • Markdown-KV: 평균 약 210 토큰 (+75%)
  • HTML: 평균 약 180 토큰 (+50%)
  • JSON: 평균 약 195 토큰 (+62%)

토큰 효율성의 실제 의미

50개 테이블 기준으로 계산하면:

  • TOON: 6,000 토큰
  • Markdown-KV: 10,500 토큰

월 100만 테이블을 처리하는 서비스라면:

  • 토큰 차이: 90,000,000 토큰/월
  • 비용 차이 (OpenAI 가격 기준 $0.0001/1K 토큰): $9/월

규모가 커질수록 이 차이는 유의미해집니다.

의사결정 프레임워크: 어떤 포맷을 선택할 것인가?

실험 결과를 바탕으로 다음과 같은 의사결정 트리를 제안합니다:

질문 1: 검색 정확도가 최우선인가?
└─ Yes → Markdown-KV 선택
└─ No → 질문 2로

질문 2: 대용량 처리 (>100K 테이블/일)인가?
└─ Yes → TOON 선택
└─ No → 질문 3으로

질문 3: 기존 시스템이 특정 포맷을 사용 중인가?
└─ Yes → 기존 포맷 유지 (변환 비용 고려)
└─ No → HTML 또는 Markdown 선택 (범용성)

한계점 및 추가 고려사항

1. 실험 규모의 한계

50개 샘플은 트렌드를 파악하기에는 충분하지만, 통계적 유의성을 확보하기에는 부족합니다. 특히:

  • Recall@5 이상에서는 차이가 수렴할 가능성
  • 특정 도메인(예: 금융 표)에서는 다른 결과가 나올 수 있음

2. Embedding 모델 의존성

Qwen3-Embedding-8B는 우수한 성능을 보이지만, 이는 결과에 편향을 줄 수 있습니다. OpenAI의 text-embedding-3-large나 Cohere의 embed-multilingual-v3.0으로 실험하면 다른 포맷이 우세할 수 있습니다.

3. Generation 단계 미평가

Retrieval 성능만으로는 불충분합니다. 실제 RAG 시스템에서는:

  • LLM이 retrieved context를 얼마나 잘 이해하는가?
  • 최종 답변의 품질은?

이를 평가하기 위해서는 추가 실험이 필요합니다:

def evaluate_end_to_end(query, retrieved_chunks, ground_truth_answer):
# LLM에 retrieved chunks를 전달하여 답변 생성
generated_answer = llm_generate(query, retrieved_chunks)

# 답변 품질 평가 (ROUGE, BERTScore 등)
score = evaluate_answer_quality(generated_answer, ground_truth_answer)
return score

향후 연구 방향

1. 대규모 벤치마크

  • 1,000개 이상의 테이블로 실험 확장
  • 다양한 카테고리별 성능 비교
  • 테이블 복잡도(행/열 수, nested structure)에 따른 포맷 성능 변화 분석

2. 하이브리드 접근

여러 포맷을 동시에 활용하는 전략:

def hybrid_retrieval(query):
# TOON으로 1차 검색 (효율성)
toon_candidates = toon_collection.query(query, n_results=10)

# Markdown-KV로 재순위화 (정확성)
refined_results = rerank_with_markdown_kv(toon_candidates)
return refined_results

3. 포맷별 최적화

각 포맷에 특화된 Retrieval 전략:

  • TOON: 구조 인식 검색
  • Markdown-KV: Key 기반 필터링 + Value 검색
  • JSON: 스키마 활용 쿼리 확장

4. 도메인 특화 실험

  • 금융 표: 숫자와 단위가 중요
  • 법률 표: 계층 구조와 참조가 중요
  • 과학 표: 수식과 기호가 중요

각 도메인에서 최적 포맷이 다를 수 있습니다.

실무 적용 가이드

Step 1: 요구사항 분석

requirements = {
"accuracy_priority": "high", # high/medium/low
"volume": "100K tables/day",
"budget": "tight",
"latency_requirement": "<2s",
"existing_format": "HTML"
}

Step 2: 파일럿 실험

작은 규모로 3-4개 포맷을 비교:

# 실험 설정
formats_to_test = ["markdown_kv", "toon", "html"]
sample_size = 100

# 평가 실행
results = {}
for fmt in formats_to_test:
results[fmt] = {
"recall": evaluate_recall(fmt, sample_size),
"avg_tokens": calculate_avg_tokens(fmt, sample_size),
"conversion_cost": estimate_conversion_cost(fmt)
}

# 최적 선택
best_format = select_best(results, requirements)

Step 3: 프로덕션 롤아웃

  1. A/B 테스팅: 기존 포맷과 신규 포맷을 동시 운영
  2. 모니터링: 실제 사용자 쿼리에서의 성능 추적
  3. 점진적 전환: 성능이 검증되면 단계적으로 확대

References