Engineering
LongMemEval: RAG 엔진은 답변이 아니라 근거 검색으로 봐야 한다
Schift memory layer가 LongMemEval-S 500문항에서 98.6% Recall@10, 96.6% Recall@5를 기록했습니다. RAG 엔진 평가에서 final answer와 evidence retrieval을 분리해야 하는 이유.
LongMemEval은 대화형 AI의 장기 기억을 평가하는 벤치마크입니다. 질문 하나와 여러 개의 대화 세션(haystack)이 주어지고, 시스템은 정답을 낼 수 있는 과거 대화를 찾아야 합니다.
여기서 중요한 구분이 있습니다.
Schift는 고정된 answer model이 아닙니다. Schift는 AI 애플리케이션이 쓸 수 있는 RAG / memory engine입니다. 따라서 우리가 먼저 증명해야 하는 것은 “최종 답변을 어느 모델이 얼마나 잘 썼는가”가 아니라, 정답 근거가 되는 기억을 얼마나 잘 찾아서 downstream model에 넘겼는가입니다.
이번 full run에서 Schift memory layer는 LongMemEval-S 500문항 기준:
| 지표 | 결과 |
|---|---|
| Recall@10 | 98.6% |
| Recall@5 | 96.6% |
| Recall@1 | 86.4% |
| NDCG@10 | 0.9146 |
다르게 말하면, 500개 질문 중 493개는 정답 근거 세션이 top 10 안에 있었고, 483개는 top 5 안에 있었습니다.
이 글은 “어떤 answer model이 LongMemEval에서 몇 점을 냈다”는 글이 아닙니다. RAG 엔진의 memory layer를 어떻게 따로 평가해야 하는지, 그리고 Schift가 그 계층에서 어디까지 왔는지에 대한 기록입니다.
왜 final answer accuracy만 보면 부족한가
다른 memory layer나 agent memory 제품은 LongMemEval 결과를 end-to-end answer accuracy로 보여주는 경우가 많습니다. 그 방식도 의미가 있습니다. 사용자가 보는 것은 결국 답변이기 때문입니다.
하지만 RAG 스택 안에서는 계층을 분리해서 봐야 합니다.
| 계층 | 묻는 질문 | 대표 지표 |
|---|---|---|
| Memory / retrieval layer | 정답 근거를 찾았나? | Recall@K, NDCG@K, MRR |
| Context assembly layer | 찾은 근거를 제한된 budget 안에 잘 압축했나? | context tokens, evidence coverage |
| Answer model layer | 근거를 읽고 답을 잘 썼나? | answer accuracy, judge score |
Schift가 책임지는 핵심 계층은 첫 번째입니다. 정답 근거가 top-k 안에 들어오지 않으면 어떤 모델을 붙여도 답변은 흔들립니다. 반대로 정답 근거가 이미 top-k 안에 있다면, 이후 점수는 answer model, prompt, context compression, judge prompt의 영향을 크게 받습니다.
그래서 Schift는 final answer score와 retrieval-layer score를 섞지 않고 분리해서 봅니다.
실험 조건
이번 결과는 기존 100문항 샘플이 아니라 LongMemEval-S 전체 500문항 기준입니다.
| 항목 | 조건 |
|---|---|
| Dataset | LongMemEval-S cleaned, full 500 questions |
| 평가 단위 | 질문별 haystack 세션 중 정답 세션 검색 |
| Engine | Schift Engine local gRPC |
| Retrieval mode | L# Cache |
| Embedding model | schift-embed-1-small |
| Embedding dimension | 1024d |
| Top-k | 10 |
| Collection policy | 질문마다 fresh collection 생성 후 삭제 |
| Context levels | L0 full session, L1 user turns, L2 lead user turns |
| Score fusion | 0.5 * L1 + 0.3 * L2 + 0.2 * L0 |
각 질문마다 별도의 collection을 만들었습니다. haystack 세션을 임베딩하고, 검색하고, Recall@K와 NDCG@10을 계산한 뒤 collection을 삭제했습니다. 같은 질문의 haystack 바깥 데이터는 보지 않습니다.
L# Cache가 한 일
L# Cache는 같은 대화를 여러 해상도로 저장합니다.
- L0: 전체 세션. user와 assistant turn을 모두 포함합니다. 맥락은 가장 풍부하지만 노이즈도 큽니다.
- L1: user turn만 저장합니다. assistant의 장황한 응답을 제거하고 사용자의 의도를 더 직접적으로 봅니다.
- L2: 앞쪽 user turn만 저장합니다. LLM 호출 없는 lead-summary proxy입니다.
검색할 때는 각 level을 독립적으로 찾고, session 단위로 점수를 합칩니다.
merged_score = 0.5 * L1 + 0.3 * L2 + 0.2 * L0이것은 LLM reranker나 cross-encoder reranker가 아닙니다. Schift Engine 안에서 metadata level별 vector search를 수행하고, score fusion으로 session ranking을 만드는 방식입니다.
결과
| Metric | Value |
|---|---|
| Recall@1 | 86.4% |
| Recall@5 | 96.6% |
| Recall@10 | 98.6% |
| NDCG@10 | 0.9146 |
R@10은 IR/retrieval에서 가장 익숙한 headline 지표입니다. 그래서 headline은 98.6% R@10으로 잡는 것이 자연스럽습니다.
하지만 실제 RAG 제품 관점에서는 R@5도 중요합니다. downstream answer model에 넘길 context budget은 무한하지 않기 때문입니다. top 10까지 열어보면 거의 모든 질문에서 근거를 찾지만, top 5 안에 들어오는지가 더 빡센 운영 지표입니다.
이번 run에서 Schift는 **R@5 96.6%**를 기록했습니다. 즉, 대부분의 질문에서 answer model은 처음 다섯 개 후보 안에서 정답 근거를 볼 수 있습니다.
유형별 결과
| Question type | Count | R@1 | R@5 | R@10 |
|---|---|---|---|---|
| knowledge-update | 78 | 91.03% | 100.0% | 100.0% |
| multi-session | 133 | 87.22% | 96.99% | 99.25% |
| single-session-assistant | 56 | 98.21% | 100.0% | 100.0% |
| single-session-preference | 30 | 63.33% | 96.67% | 100.0% |
| single-session-user | 70 | 81.43% | 94.29% | 95.71% |
| temporal-reasoning | 133 | 85.71% | 93.98% | 97.74% |
두 가지가 보입니다.
첫째, knowledge-update와 assistant 관련 질문은 거의 풀렸습니다. 정답 근거가 top-k 안에 안정적으로 들어옵니다.
둘째, single-session-preference와 temporal-reasoning은 R@1이 낮습니다. 정답이 아주 가까이에 있기는 하지만, 첫 번째 결과로 고정되지는 않습니다. 이 영역은 단순 유사도보다 “현재 선호”, “시간 순서”, “업데이트된 사실”을 점수에 더 잘 반영해야 합니다.
latency
이번 benchmark는 production traffic용 latency 측정이 아닙니다. 질문마다 fresh collection을 만들고, haystack 전체를 새로 임베딩하고, 검색 후 삭제하는 replay입니다.
그래도 비용 구조를 보기 위해 측정값을 남겼습니다.
| 항목 | 평균 |
|---|---|
| Ingest | 5,739.2 ms / question |
| Search | 128.1 ms / question |
| Total ingest | 2,869.6 s |
| Total search | 64.0 s |
ingest가 긴 이유는 질문마다 평균 200개 안팎의 chunk를 새로 임베딩하기 때문입니다. 실제 제품에서는 이미 저장된 memory layer 위에서 query search가 일어나므로, 이 숫자를 사용자-facing query latency로 읽으면 안 됩니다.
검색 자체는 평균 128.1ms였습니다.
그래서 answer generation은 안 하나?
합니다. 다만 그것은 별도 계층입니다.
LongMemEval final-answer accuracy를 보고 싶다면, top-k retrieved evidence를 제한된 context budget 안에 넣고 answer model을 붙인 뒤, LongMemEval judge prompt로 채점해야 합니다.
그 결과는 다음 요소에 따라 달라집니다.
- answer model이 무엇인지
- retrieved session 전체를 넣는지, evidence chunk만 넣는지
- context budget을 4k로 둘지, 8k로 둘지
- temporal / preference 질문에 어떤 answer prompt를 쓰는지
- judge model과 judge prompt가 무엇인지
이 숫자는 제품 관점에서 중요하지만, Schift memory layer의 순수 retrieval 성능과는 분리해서 봐야 합니다.
우리가 이 글에서 공개하는 것은 retrieval ceiling입니다. Schift는 full LongMemEval-S에서 정답 근거를 top 10 안에 98.6%, top 5 안에 96.6%로 올렸습니다. 이후 answer model이 그 근거를 얼마나 잘 사용하는지는 다음 계층의 문제입니다.
다른 memory layer와 비교할 때
memory layer 벤치마크는 종종 한 숫자로 압축됩니다. 하지만 실제 RAG 시스템에서는 한 숫자가 너무 많은 것을 섞습니다.
예를 들어 어떤 시스템이 높은 final-answer accuracy를 냈다면, 그 숫자 안에는 다음이 모두 들어갑니다.
- memory retrieval 성능
- reranking 성능
- context compression 성능
- answer model 성능
- prompt engineering
- judge leniency
Schift는 이 중 retrieval layer를 독립적으로 보고합니다. 이것이 RAG 엔진을 평가하는 더 직접적인 방법입니다.
좋은 answer model을 붙이면 최종 답변 점수는 올라갈 수 있습니다. 하지만 answer model이 좋아도 정답 근거가 검색되지 않으면 답은 추측이 됩니다. RAG 엔진의 첫 번째 책임은 추측이 아니라 근거를 제공하는 것입니다.
결론
LongMemEval-S full 500에서 Schift memory layer는:
- 98.6% Recall@10
- 96.6% Recall@5
- 86.4% Recall@1
- 0.9146 NDCG@10
을 기록했습니다.
이 숫자는 “Schift가 모든 질문에 최종 답을 98.6% 맞혔다”는 뜻이 아닙니다. 더 정확하게는, Schift가 정답을 만들 수 있는 근거 세션을 top 10 안에 98.6% 확률로 제공했다는 뜻입니다.
RAG 엔진에게는 이것이 먼저입니다. 답변은 그 다음 계층입니다.
RAG Lab 구독
schift 만들면서 직접 굴린 RAG 실험 일지. 매주 새 실험이 올라옵니다.