2026.09 ~ 진행 중 · 1인 개발 · 캡스톤디자인 2 · GitHub

한눈에 보기


1. 왜 만들었나

한국어 대화에서는 사람을 이름으로 잘 부르지 않습니다. 같은 사람이 직함, 대명사, 승진 후 호칭으로 계속 바뀌어 나옵니다. 대화에서 자동으로 "인물 메모리"를 쌓으려면 이 지칭들을 하나로 묶어야 합니다.

이때 두 가지 실패가 있습니다.

실패 결과 비용
오병합 — 다른 사람을 같은 사람으로 합침 "이모 이야기를 고모 기억에 저장" → 신뢰가 즉시 무너짐 매우 큼
미검출 — 같은 사람을 못 합침 메모리가 여러 조각으로 나뉨 상대적으로 작음, 나중에 합칠 수 있음

그래서 설계의 출발점을 "오병합은 미검출보다 훨씬 나쁘다"는 비대칭 비용으로 두었습니다. 확신이 기준에 못 미치면 절대 자동으로 합치지 않고 사용자에게 묻습니다.


2. 엔티티 해석 4단계

flowchart TD
  IN["호칭 '부장님' + 발화"] --> S1[1. 후보 검색<br/>별칭 일치 ∪ pgvector 유사도 top-K]
  S1 --> S2[2. 규칙 필터<br/>관계 태그 · 위계 · 호칭 사전]
  S2 -->|통과 후보 0건| ASKN[새 인물인지 묻기]
  S2 -->|통과 후보만 전달| S3[3. LLM 판정<br/>구조화 출력 · 후보 밖 id 거부]
  S3 --> S4{"4. 확신도<br/>0.5·LLM + 0.3·임베딩 + 0.2·규칙"}
  S4 -->|"≥ 0.8"| MERGE[자동 병합<br/>별칭 누적]
  S4 -->|"0.3 ~ 0.8"| ASKI["'김팀장님 말씀이신가요?'"]
  S4 -->|"< 0.3"| ASKN
단계 설계 포인트
1. 후보 검색 별칭 정확 · 부분 일치와 임베딩 유사도를 합집합으로. 이 단계에서는 아무도 배제하지 않음
2. 규칙 필터 모순일 때만 배제. 정보가 없는 검사는 점수 분모에서 뺌. 통과 후보가 없고 위계 1칸 차이로만 떨어진 후보가 있으면 승진으로 보고 완화 규칙으로 한 번 더 평가
3. LLM 판정 규칙을 통과한 후보만 전달. "목록에 없는 사람을 지어내지 말고, 확신 없으면 null". 후보 밖 id를 답하면 장애와 구분해 거부
4. 확신도 분기 임계치 두 개로 "합치기 / 누구인지 묻기 / 새 인물인지 묻기"를 구분. LLM 실패 · 후보 없음 · null은 어떤 경로로도 병합 불가

판정과 실행의 분리resolve()는 인물 데이터를 바꾸지 않고 판정과 판정 기록(trace 1행)만 남깁니다. 실제 변경은 apply_resolution()만 하고, 같은 판정을 두 번 적용하면 예외를 냅니다(중복 질문 방지).

호칭 사전의 작은 함정 — "김팀장"에서 성씨 1글자를 떼면 "팀장"이 됩니다. 그런데 "이모"에서 "이"를 떼면 안 됩니다. 그래서 남은 부분이 사전 표제어일 때만 성씨를 떼도록 했습니다.


3. 임베딩 모델은 파일럿으로 골랐습니다

호칭 30개 × 모델 2종으로 코사인 유사도 행렬을 만들어 비교했습니다.

기준: "팀장↔부장님"이 "팀장↔이모"보다 가까운가 small large
팀장↔부장님 0.529 0.531
팀장↔이모 0.257 0.342
여유폭 +0.272 +0.190