LLM으로 복습 퀴즈를 생성하다 보면 한 가지 문제가 생긴다. 여러 번 생성하다 보면, 기존에 만들었던 문제와 너무 비슷한 문제가 다시 나오는 경우가 있다.

예를 들면 이런 식이다.

기존 문제:
useEffect의 의존성 배열이 비어 있을 때 실행 시점으로 올바른 것은?

새로 생성된 문제:
React에서 useEffect에 빈 배열을 전달하면 언제 실행되는가?

문장 자체는 다르지만 실제로 묻는 개념은 거의 같다.

공통 개념:
- React
- useEffect
- 빈 의존성 배열
- 최초 실행 시점

교육생 입장에서는 새로운 복습 문제가 아니라, 기존 문제를 말만 바꿔서 다시 푸는 느낌을 받을 수 있다.

그래서 LLM이 문제를 생성한 뒤 바로 저장하는 것이 아니라, 기존 문제들과 얼마나 유사한지 검토하는 단계가 필요했다.

이때 사용한 개념이 임베딩코사인 유사도다.


처음에는 단순히 문장끼리 비교하면 되지 않을까 생각할 수 있다.

문장 A:
React에서 useState를 사용하는 이유는 무엇인가?

문장 B:
React에서 useState를 사용하는 이유는 무엇인가?

이런 경우에는 문자열이 완전히 같으니 쉽게 중복이라고 판단할 수 있다.

하지만 실제로 문제되는 건 이런 경우다.

문장 A:
React에서 useState를 사용하는 이유는 무엇인가?

문장 B:
컴포넌트 내부 상태를 관리하기 위해 사용하는 React Hook은 무엇인가?

표현은 다르지만 의미는 거의 같다.

반대로 단어는 비슷하지만 실제로 묻는 내용이 다른 경우도 있다.

문장 A:
useEffect의 의존성 배열이 비어 있을 때 실행 시점은?

문장 B:
useEffect의 의존성 배열에 state를 넣어야 하는 이유는?

두 문장 모두 useEffect, 의존성 배열이라는 단어를 포함한다.

하지만 하나는 최초 실행 시점에 대한 문제이고, 다른 하나는 의존성 변경에 따른 재실행에 대한 문제다.

즉, 단어가 겹친다고 무조건 같은 문제는 아니다.