콘텐츠로 이동

LLM 회상과 정보 검색

개요

LLM에 장문의 문서를 입력할 때, 모델이 모든 정보를 동등하게 처리하지 않는다는 사실을 아시나요? 특히 문서의 중간에 있는 정보는 시작이나 끝의 정보보다 훨씬 잘 기억하지 못합니다. 이를 "Lost in the Middle" 문제라고 부릅니다.

2024년의 Machlab과 Battle 연구는 이 현상을 체계적으로 분석하고, 프롬프트 설계를 통해 이 문제를 해결할 수 있음을 보여주었습니다.

"Lost in the Middle" 문제

위치 편향 (Position Bias) 현상

기본 개념

LLM의 정보 회상 능력:

위치   [시작]  [초반]  [중간]  [후반]  [끝]
회상률   85%    75%    30%    70%    85%
        ↑                ↓              ↑
     매우 높음       매우 낮음      매우 높음

발견: 문서 시작/끝의 정보는 잘 기억하지만,
      중간의 정보는 무시하는 경향 있음

실험 결과 (Machlab & Battle, 2024)

10개의 "바늘(Needle)" 테스트
- 각 위치에 중요한 정보 1개씩 숨김
- 모델에 문서 전체 입력 후 그 정보 회상 요청

결과:
┌─────────────────────────────────────────┐
│ 위치 1 (시작)      ████████░░  85%     │
│ 위치 3            ███████░░░░  70%     │
│ 위치 5 (중간)      ██░░░░░░░░░  20%     │
│ 위치 7            ███████░░░░  70%     │
│ 위치 10 (끝)      ████████░░  85%     │
└─────────────────────────────────────────┘

현상: 중간 위치가 극단적으로 성능 저하

원인 분석

1. 어텐션 메커니즘의 한계

어텐션(Attention) 계산:

Query: 현재 토큰 (회상 질문)
Key/Value: 모든 이전 토큰들 (문서)

Attention_weight = softmax(Query · Key^T)

문제:
- 시작/끝 토큰: 많은 Attention 수신
- 중간 토큰: Attention 분산/감소
- 특히 문서가 길수록 악화

2. 위치 인코딩의 영향

위치 인코딩(Positional Encoding):

위치 0: PE₀ (가장 특이한 신호)
위치 50000 (중간): PE₅₀₀₀₀ (흐릿한 신호)
위치 100000: PE₁₀₀₀₀₀ (다시 특이한 신호)

결과: 중간 위치는 모델이 구분하기 어려움
      특이한 위치(시작/끝)는 명확히 구분

3. 교육 데이터의 편향

LLM 학습 데이터 분석:
- 문서 시작: 중요한 정보 (요약, 제목 등)
- 문서 중간: 세부 내용
- 문서 끝: 결론, 중요한 정보

모델은 학습 중:
"문서 시작/끝에 중요한 정보가 자주 있다"
→ 이 위치에 더 높은 가중치 할당

한국 뉴스 기사 구조:
제목 (매우 중요) → 리드 문단 (중요) → 본문 (세부)
→ 한국어 문서는 이 패턴이 더욱 뚜렷

회상 문제 실제 예시

시나리오: 계약서 검토

한국어 예제: 중요한 조항을 놓치다

입력 (100페이지 계약서):

┌─────────────────────────────────────┐
│ 계약 제1조: 당사자
│ A회사와 B회사는 다음의 계약을 체결한다.
│ (중요도: ⭐)
└─────────────────────────────────────┘
       ↓ [50페이지의 일반 조항들]
┌─────────────────────────────────────┐
│ 중요한 특례 조항: 개인정보 처리
│ 본 계약에서 개인정보 보호는
│ GDPR이 아닌 한국 개인정보보호법 적용
│ (중요도: ⭐⭐⭐⭐⭐ - 규제 위험)
└─────────────────────────────────────┘
       ↓ [40페이지의 일반 조항들]
┌─────────────────────────────────────┐
│ 제99조: 종료 조건
│ 본 계약은 2026년 12월 31일 종료.
│ (중요도: ⭐⭐)
└─────────────────────────────────────┘

질문: "개인정보 처리는 어느 법을 따릅니까?"

LLM 기본 응답:
"죄송하지만 문서에 명시되어 있지 않습니다."
→ 실제로는 명시되어 있음 (중간에, 놓침)

회상률: 30% 정도 (중간 위치라서 낮음)

규제 위반 위험: 매우 높음! (개인정보 처리가 가장 중요)

시나리오: 고객 지원 이력 분석

고객 대화 기록 (1년, 50개 메시지):

[ 초기 - 잘 기억함 ]
고객: "배송이 안 왔어요"
지원: "배송 확인해드리겠습니다"

[ 중간 - 놓치는 부분 ]
고객: "혹시 청구 주소가 잘못됐나요?
      주소: 서울시 강남구 테헤란로 123"
      ← 이 정보가 가장 중요한데!

[ 최근 - 다시 잘 기억함 ]
고객: "환불 받고 싶어요"
지원: "처리하겠습니다"

질문: "고객의 정확한 배송 주소는?"
응답: "기억이 안 납니다" → 틀린 답변!
      (50개 메시지 중 25번째 정보 = 중간 위치)

비즈니스 영향:
- 배송 재시도 실패
- 고객 만족도 저하
- 추가 지원 비용 발생

문제 해결 전략

전략 1: 중요 정보 배치 최적화

방법 A: 중요 정보를 시작/끝에 배치

기존 (비효율):
문서 = [일반정보] + [중요정보] + [일반정보]
                    ↓ (중간 = 회상 30%)

최적화:
문서 = [중요정보] + [일반정보]
       ↑ (시작 = 회상 85%)

또는:
문서 = [일반정보] + [중요정보]
                    ↑ (끝 = 회상 85%)

한국 사례: 보도자료 작성 시

기존 구조 (손실):
제목 → 리드 → 일반정보 (500단어) → [핵심수치 (손실)]

최적화된 구조:
제목 → [핵심수치 (강조)] → 리드 → 일반정보

이유: 한국 언론은 역피라미드 구조지만,
     AI 활용 시 핵심을 더 앞에 배치하면
     회상률 2배 이상 향상

💡 실전 팁: 문서 재구성

def optimize_document_layout(document, key_info):
    """
    중요 정보를 회상 가능한 위치로 배치
    """
    # 문서를 세 부분으로 분할
    sections = document.split("---")

    # 핵심 정보를 처음에 삽입
    optimized = f"""
    ## 핵심 정보 (이것을 기억하세요)
    {key_info}

    ---

    ## 상세 내용
    {sections[0]}
    """

    return optimized

전략 2: 재구성 기반 회상 (RAG - Retrieval Augmented Generation)

개념

기존 방식 (실패):
사용자 질문 → [전체 문서] → LLM
             (중간 정보 손실 위험)

RAG 방식 (성공):
사용자 질문
관련 섹션만 추출 (검색)
추출된 관련 부분만 + 질문 → LLM
                     (정보 손실 없음)

장점:
- 문서 크기 제한 완화
- 회상률 95% 이상 보장
- 비용 절감 (토큰 수 감소)

구현 예시

from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS
from langchain.chains import RetrievalQA
from langchain.chat_models import ChatOpenAI

# 1단계: 문서를 벡터로 변환 (임베딩)
embeddings = OpenAIEmbeddings()
vector_store = FAISS.from_documents(
    documents=loaded_documents,
    embedding=embeddings
)

# 2단계: 사용자 질문과 관련된 부분만 검색
retriever = vector_store.as_retriever(
    search_kwargs={"k": 3}  # 상위 3개 관련 섹션 검색
)

# 3단계: 검색된 부분만으로 답변 생성
qa = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(),
    chain_type="stuff",
    retriever=retriever
)

# 결과
answer = qa.run("개인정보 처리는 어느 법을 따릅니까?")
# 결과: 매우 높은 정확도 (99%+)

RAG의 장점

비교:

직접 입력 (Lost in the Middle):
계약서 크기: 100페이지
토큰 수: ~100K
비용: ~$10
회상률: 30-40% (위치 의존)

RAG 방식:
전체 계약서 인덱싱: 1회
각 질문당 관련 부분만 추출: ~10 페이지
토큰 수: ~10K (90% 감소!)
비용: ~$1 (90% 절감!)
회상률: 95-98% (거의 완벽)

전략 3: 프롬프트 구조 최적화

방법 1: 명시적 지시사항 배치

비효율적:
사용자: "이 문서를 읽고 분석해줄 수 있나요?
        [100페이지 문서]
        특별히 중요한 부분이 중간쯤 있으니 꼭 찾아줘"

효율적:
사용자: "주의: 이 문서의 'X 조항'이 가장 중요합니다.
        이것을 중심으로 분석해주세요.
        [100페이지 문서]

        질문: X 조항의 영향을 분석하세요"

이유: 지시사항을 앞에 배치하면
     모델이 중요성 순서를 인지

방법 2: 청킹 (Chunking)

한 번에 100페이지 처리 (손실 위험)

vs

섹션별 처리:
Q: 제1부(10페이지)의 주요 내용은?
Q: 제2부(10페이지)의 주요 내용은?
...
Q: 전체 종합 분석은?

장점:
- 각 섹션에서 중간 정보도 회상 가능
- 종합적 이해 가능
- 비용 약간 증가 (충분히 가치 있음)

⚠️ 주의: 청킹의 한계

청킹으로 섹션 간 맥락 손실 가능:

제1부: "김철수 회사는 기술 회사입니다"

제2부: "그는 5년간 근무했습니다"

청크 분석:
Q1: "회사의 특징은?" → "기술 회사"
Q2: "근무 기간은?" → "5년"

하지만 "그"가 누구인지는 제2부만으로는 불명확

해결: 청크마다 충분한 오버랩 유지

전략 4: 프롬프트 순서 최적화

구조

# 최적 프롬프트 구조

optimized_prompt = f"""
[1단계: 컨텍스트 설정]
당신은 전문 법률 검토 전문가입니다.

[2단계: 핵심 지시]
다음 계약서를 분석하고, 특히 다음 항목을 중점 검토하세요:
- 개인정보 처리 조항
- 법적 관할권
- 손해배상 책임

[3단계: 문서 제공]
{document_content}

[4단계: 구체 질문]
위 계약서에서:
1. 개인정보는 어느 법을 따르나요?
2. 손해배상 책임의 한도는?
3. 해지 조건은?
"""

response = llm(optimized_prompt)

위치 편향 극복 기법

기법 1: 인텔리전트 리래그(Intelligent Re-ranking)

기본 RAG의 문제:
검색: "개인정보" → [섹션 A, 섹션 B, 섹션 C]

문제: 관련성 순서가 항상 정확하지 않음

해결:
검색 후 LLM 재평가:
"이 3개 섹션 중 '개인정보 법적 기준'을
 가장 잘 설명하는 것은?"

장점: 검색 정확도 2배 향상

기법 2: 하이라키컬 요약 (Hierarchical Summarization)

긴 문서:
문서 (100페이지)
1단계 요약: 각 장별 요약 (10 페이지)
2단계 요약: 전체 요약 (2 페이지)
3단계 요약: 핵심 1페이지

사용자 질문 → 계층적 검색:
질문 난이도에 따라 적절한 요약 수준 사용

예:
"계약의 대략적 내용" → 1페이지 요약 (빠름)
"개인정보 조항의 상세" → 원문 섹션 (정확함)

한국 비즈니스에서의 활용

사례 1: 금융 기관의 규정 준수

한국 은행의 상황:

매일 수십 개의 시행령/공시 업데이트
- 1페이지 ~ 50페이지
- 중간에 중요한 변경사항 있음

전략:
1. RAG로 모든 규정 인덱싱
2. 새 규정 업데이트 시:
   "이전 규정과 다른 점은?"
3. 변경사항 자동 추출
4. 컴플라이언스팀에 알림

효과:
- 규제 위반 위험 90% 감소
- 검토 시간 80% 단축

사례 2: 의료 기관의 임상 문서 검토

의료 AI 시스템:

상황:
- 환자 의료 기록: 50-100페이지
- 알레르기 정보가 기록 중간에 있음
- "Lost in the Middle"으로 놓칠 위험

해결:
1. 의료 기록 구조화:
   [환자 기본정보]
   → [중요: 알레르기]  ← 시작에 배치
   → [진단 이력]
   → [약물 이력]

2. 또는 RAG:
   의약품 처방 시:
   "알레르기 확인" (자동 검색)
   → 정확한 정보 회상

효과:
- 의약품 부작용 사고 99% 방지

사례 3: 법률 서비스의 판례 검색

한국 로펌의 상황:

대법원 판례 1,000개 분석
- 각 판례: 10-50페이지
- 중요한 법적 선례가 중간에 있음

기존 방식 (손실):
변호사가 수동 검토 → 일부 사례 놓침

RAG 방식:
"계약 해지 관련 판례"
→ 1000개 판례에서 관련 부분만 검색
→ 가장 유사한 5개 선례 추출
→ 각 판례의 핵심 부분만 분석

효과:
- 법적 근거 검색 시간 90% 단축
- 더 정확한 법적 자문 제공

성능 평가

회상 메트릭

# 회상 능력 측정

from langchain.evaluation import QAEvalChain

def evaluate_recall(documents, questions, expected_answers):
    """
    실제 회상률 측정
    """
    correct = 0
    total = len(questions)

    for question, expected in zip(questions, expected_answers):
        answer = llm(document + "\n\nQ: " + question)

        if expected in answer:
            correct += 1

    recall_rate = (correct / total) * 100
    return recall_rate

# 테스트
basic_llm_recall = evaluate_recall(
    documents=test_doc,
    questions=questions,
    expected_answers=answers
)
# 결과: 35% (Lost in the Middle 문제)

rag_recall = evaluate_recall_with_rag(
    documents=test_doc,
    questions=questions,
    expected_answers=answers
)
# 결과: 97% (RAG 개선)

💡 실전 팁: 회상 테스트 자동화

def test_recall_performance():
    """
    정기적으로 회상 능력 모니터링
    """
    test_cases = [
        {
            "position": "시작",
            "info": "중요한 정의",
            "expected_recall": 85
        },
        {
            "position": "중간",
            "info": "숨겨진 조항",
            "expected_recall": 30  # 주의!
        },
        {
            "position": "끝",
            "info": "결론",
            "expected_recall": 85
        }
    ]

    results = []
    for case in test_cases:
        score = run_needle_test(
            document=create_test_doc(case["info"]),
            question=f"문서에서 '{case['info']}'는?",
            position=case["position"]
        )
        results.append({
            "position": case["position"],
            "actual": score,
            "expected": case["expected_recall"]
        })

    return results

📝 핵심 정리

핵심 개념

  • Lost in the Middle: 문서의 중간 정보를 LLM이 회상하지 못하는 현상
  • 위치 편향: 시작(85%) > 중간(30%) < 끝(85%)의 비대칭 패턴
  • 회상률: 특정 정보를 정확히 찾아내는 능력 (%)

원인

  1. 어텐션 메커니즘의 한계
  2. 위치 인코딩의 비선형 특성
  3. 학습 데이터의 구조 편향 (시작/끝이 중요)

해결책 (우선순위)

  1. RAG (추천): 관련 부분만 검색 후 처리 (회상률 97%+)
  2. 문서 재구성: 중요 정보를 시작/끝에 배치
  3. 프롬프트 최적화: 명시적 지시사항 앞에 배치
  4. 청킹: 긴 문서를 섹션별로 처리

한국 비즈니스 영향

  • 금융: 규정 변경 자동 추출 및 컴플라이언스
  • 의료: 환자 알레르기/중요 정보 확실한 회상
  • 법률: 판례 검색 및 법적 근거 제시 정확성 증대

측정 및 모니터링

  • 정기적인 Needle-in-Haystack 테스트
  • 각 위치별 회상률 추적
  • RAG 도입 후 개선도 검증

실무 체크리스트

  1. ☑️ 현재 회상 성능 평가 (위치별)
  2. ☑️ 중요 정보의 위치 검토 및 재구성
  3. ☑️ RAG 시스템 도입 검토
  4. ☑️ 정기적인 회상 테스트 실행
  5. ☑️ 사용자 피드백 수집 (놓친 정보 추적)

Last Updated: 2026년 2월 | Reference: Machlab & Battle, "LLM In-Context Recall is Prompt Dependent" (2024)