기술

"2025년 프로젝트 알려줘" 했더니 LLM이 날짜를 +1년 조작했습니다

2026.04.308분 읽기

"2025년 프로젝트 뭐뭐 있어?" 한마디에서 시작됐습니다

채팅 화면에서 "2025년에 진행한 프로젝트가 뭐뭐 있어?"라고 물어봤거든요. LLM이 꽤 그럴듯한 답변을 내놨습니다.

2025년 2월: CVT 진행

2025년 7월: 상용 이관

2025년 11월: SFTP 전환

2025년 12월: 공인 IP DMZ 작업

날짜도 구체적이고, 프로젝트 내용도 그럴듯해요. 별 의심 없이 넘어갈 만한 답변이었습니다.

그런데 화면 하단의 출처 카드를 무심코 봤더니 이상한 게 보였어요. 인용된 이메일들 날짜가 전부 2024년이었거든요.

LLM 답변 (거짓)

실제 이메일 날짜

2025년 2월 CVT 진행

2024년 11~12월

2025년 7월 상용 이관

2024년 11월

2025년 11월 SFTP 전환

2024년 12월

2025년 12월 공인 IP DMZ

2024년 9~10월

LLM이 사용자 질문에 맞추려고 모든 날짜를 +1년 조작한 거였어요. 실제 데이터는 2024년인데 답변에서 2025년으로 둔갑시켰습니다. 단순 반올림이나 혼동이 아니라 일관되게 1년씩 밀려 있었어요.


왜 이런 일이 일어났는가

원인을 분석해보니 세 가지가 겹쳐 있었어요.

첫째, 데이터 분포가 비대칭이었어요. 임포트한 PST 파일 이름이 "2025년.pst"였는데, 실제로는 2024년 이메일이 2,636건, 2025년 이메일이 단 1건이었습니다. 파일 이름과 내용물이 안 맞았던 거예요. PST 파일을 받았을 때 "이 안에 정확히 뭐가 들었나"를 데이터 분포로 검증하지 않고, 파일 이름만 보고 임포트한 게 1차 원인이었습니다.

둘째, 벡터 검색은 의미 유사도 기반이라 날짜에 둔감해요. "2025년 프로젝트"라는 질문에 대해 벡터 검색은 "프로젝트 진행", "이관", "전환" 같은 의미가 비슷한 이메일을 가져오거든요. 그게 2024년 이메일이든 2025년 이메일이든 의미가 비슷하면 가져옵니다. 시점 필터링은 벡터의 일이 아니에요.

셋째, LLM은 사용자 의도에 맞추려는 경향이 강합니다. 검색 결과로 받은 이메일은 2024년인데, 사용자 질문은 "2025년"이라고 했으니까 LLM이 그 사이를 자기가 알아서 메꾼 거예요. "사용자가 2025년이라고 했으니 2025년이라고 답해주자"가 LLM의 자연스러운 행동 패턴이었습니다.

세 요인이 따로따로면 별 문제 아닌데, 합쳐지니까 거짓말 답변이 되었어요. 데이터 비대칭 + 벡터의 시점 둔감성 + LLM의 의도 맞춤 성향. 셋 다 자체로는 자연스러운데 결과는 환각이었습니다.

1.jpeg


출처 카드가 검증 도구 역할을 했습니다

이 사건을 잡아낸 건 운이 아니라 출처 카드 UI 덕분이었어요.

원래 출처 카드는 "이 답변의 근거가 뭐야?"를 보여주는 신뢰성 표시 용도로 만들었거든요. 답변 하단에 인용된 이메일 카드들이 표시되고, 각 카드엔 발신자·수신자·날짜·제목이 적혀 있습니다. 사용자가 "출처 보고 싶다"고 할 때 클릭해서 원본 이메일을 열어보는 그런 기능이었어요.

그런데 이번 사건에서 출처 카드는 검증 도구로 작동했어요. LLM 답변의 날짜와 출처 카드의 날짜가 안 맞아서 환각이 드러났거든요. 사용자가 따로 검증하지 않아도, 화면 안에 답변과 근거가 같이 표시되니까 즉시 비교가 가능했습니다.

만약 출처 카드가 없었다면 어떻게 됐을까요. LLM 답변만 보고 "2025년에 이런 프로젝트가 있었구나" 하고 받아들였을 거예요. 누가 다른 자료를 찾아보지 않는 한 거짓말인지 모르고 지나갔을 겁니다. 환각은 답변이 그럴듯해 보일수록 발견하기 어렵거든요.

이 경험으로 출처 카드를 "보조 정보"가 아니라 답변과 함께 봐야 하는 1차 검증 장치로 자리매김했습니다.

2.png


프롬프트에 가드를 추가했습니다

UI에서 잡았으니 됐다고 끝낼 일이 아니거든요. 모든 사용자가 출처 카드를 매번 비교할 수는 없으니까, LLM이 처음부터 거짓말을 못 하도록 프롬프트에 명시적인 규칙을 추가했어요.

답변 생성 프롬프트에 두 줄을 추가했습니다.

규칙 7: 날짜를 절대 변경하거나 추측하지 마세요.
        검색 결과에 나온 날짜를 그대로 사용하세요.

규칙 8: 질문한 기간에 해당하는 데이터가 없으면
        솔직하게 "없다"고 답하세요.

규칙 7은 "조작 금지", 규칙 8은 "없으면 없다고 말하기"입니다. 사실 규칙 8이 더 중요해요. LLM이 환각을 만드는 가장 큰 동기가 "사용자 질문에 답을 해야 한다"는 압박이거든요. "데이터가 없으면 없다고 답해도 된다"는 출구를 열어주면, 억지로 답을 만들어내는 빈도가 줄어듭니다.

이전에도 비슷한 결의 작업을 한 적이 있어요. LLM이 자유롭게 엔티티를 만들어내는 걸 막기 위해 프롬프트와 코드 양쪽에 가드를 두는 구조였거든요.

이번에도 같은 발상이에요. 프롬프트만으로 100% 막을 수는 없지만, 1차 가드로는 작동합니다. 그리고 출처 카드가 2차 검증 역할을 하니까 두 겹의 방어선이 있는 셈이에요.


데이터 분포 점검도 입구에 두기로 했습니다

이번 사건에서 가장 부끄러운 부분은 사실 PST 파일 이름만 보고 임포트한 것이었어요. 파일 이름이 "2025년.pst"라고 해서 안의 데이터가 다 2025년인 게 아니거든요. 실제로 열어보니 2024년 데이터가 99.96%였습니다.

그래서 임포트 파이프라인 입구에 간단한 데이터 분포 점검을 추가했어요.

이메일 날짜 히스토그램을 임포트 직후 자동 출력

파일 이름과 실제 분포가 큰 차이가 나면 경고 표시

운영자가 "이거 정말 임포트할 거냐"를 한 번 더 확인

이건 거버넌스 차원의 변화예요. 데이터를 받은 그 자리에서 "이게 뭔지" 확인하지 않으면, 나중에 그 데이터로 만든 답변이 모두 의심받게 됩니다. 입구에서 1분 점검하는 게 출구에서 한참 디버깅하는 것보다 싸요.


마무리

데이터 비대칭과 벡터의 시점 둔감성, LLM의 의도 맞춤 성향이 겹쳐서 환각 답변이 만들어졌습니다. 출처 카드 UI가 답변과 근거를 같이 보여주니까 불일치가 즉시 드러났고, 그 덕에 사건이 잡혔어요. 프롬프트에는 "날짜 변경 금지"와 "없으면 없다고 말하기" 규칙을 추가했고, 임포트 입구에는 데이터 분포 점검 단계를 넣었습니다.

LLM이 그럴듯한 답변을 만들 때, 그게 진짜인지 거짓인지를 사용자 혼자 검증하기는 어렵습니다. 답변 옆에 근거를 같이 보여주는 UI는 신뢰성 표시 이상의 가치가 있어요. 사용자가 의식적으로 비교하지 않아도, 한 화면에 답과 근거가 같이 있으면 환각이 잡히는 빈도가 올라갑니다.

LLM 기반 검색·답변 시스템을 운영 중이라면, 답변과 출처를 같은 화면에 띄우는 UI를 한번 점검해보시길 추천합니다. 신뢰성 표시뿐 아니라 검증 도구로 작동하거든요.

#LLM할루시네이션#RAG#벡터검색#출처표시#프롬프트엔지니어링#데이터검증#AI전환기