e2c5471046
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
7.1 KiB
7.1 KiB
id, title, category, status, verification_status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, created_at, updated_at, review_reason, merge_history, tags, raw_sources, applied_in, github_commit
| id | title | category | status | verification_status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | created_at | updated_at | review_reason | merge_history | tags | raw_sources | applied_in | github_commit | |||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| tfidf-bilingual-scoring | TF-IDF 이중언어 스코어링 | AI_and_ML | draft | applied |
|
A | 0.92 | 2026-06-13 | 2026-06-13 |
|
|
|
TF-IDF 이중언어 스코어링
🎯 한 줄 통찰 (One-line insight)
임베딩 엔진 없이도 쓸 수 있는 가벼운 검색의 핵심은 "좋은 토크나이저 + TF-IDF 가중"이며, ConnectAI 는 한국어/영어 혼합 토크나이저·불용어·동의어 확장·제목 가중·충돌 신호 를 더해 단순 includes() 매칭을 넘어선 점수를 낸다 [S1].
🧠 핵심 개념 (Core concepts)
- TF-IDF: 용어 빈도(TF, 문서 내 흔함) × 역문서빈도(IDF, 전체에서 희소함). 흔하면서 그 문서에만 자주 나오는 단어가 고득점 [S1].
- 이중언어 토큰화: 한글-영문 경계를 분리(
성능optimization→성능optimization), 특수기호 보존(C++, C#, .net) [S1]. - 불용어(Stop words): 검색에 무의미한 단어(영/한 각각 집합)를 제거 [S1].
- 동의어 확장: 질의 토큰을 관련어로 확장(
성능→performance,optimization,최적화) [S1]. - 제목 가중: 제목 일치는 본문보다 3배 가중(
TITLE_MULTIPLIER: 3.0) [S1]. - 토큰 캐시: 같은 텍스트의 토큰화를 Map 으로 캐시(한도 초과 시 전체 clear) [S1].
🧩 추출된 패턴 (Extracted patterns)
- 중앙 설정 객체:
SCORING_CONFIG에 불용어·동의어·임계값·가중치를 모아 한 곳에서 조정 [S1]. - 경계 분리 정규식:
replace(/([a-z0-9]+)([가-힣]+)/gi, '$1 $2')로 언어 경계 분할,split(/[^a-z0-9가-힣+#.-]+/g)로 특수기호(C++) 보존 [S1]. - TF 계산 1회화:
buildTermCounts로 문서당 용어 빈도 맵을 한 번 만들고 질의 용어마다 재사용 — O(질의×문서) 재스캔 회피 [S1]. - IDF smoothing: 문서 수가 적을 때도 안정적이도록 평활화 적용 [S1].
- 충돌 신호 탐지: "반대/충돌/conflict/vs" 등 지표 단어 수로 conflictSeverity 산출 — 지식 충돌 가능 문서를 표시 [S1].
- 순수 함수 분리: chunker/scoring 은 fs·네트워크 의존 없는 순수 함수라 단위 테스트·재현이 쉽다 [S2].
📖 세부 내용 (Details)
토크나이저 (가장 중요한 부품)
const normalized = text.toLowerCase()
.replace(/[-]/g, '') // zero-width 제거
.replace(/[^\w\s가-힣_+#.-]/g, ' '); // 의미 없는 기호 → 공백
const splitText = normalized
.replace(/([a-z0-9]+)([가-힣]+)/gi, '$1 $2') // 영→한 경계 분리
.replace(/([가-힣]+)([a-z0-9]+)/gi, '$1 $2');// 한→영 경계 분리
const tokens = splitText.split(/[^a-z0-9가-힣+#.-]+/g) // C++, C#, .net 보존
.map(t => t.trim().replace(/[.,]$/g, ''))
.filter(t => /[가-힣]/.test(t) ? t.length >= 1 : t.length >= 2) // 한글 1자+, 영문 2자+
.filter(t => !STOP_EN.has(t) && !STOP_KO.has(t));
한국어는 한 글자도 의미를 가질 수 있어 1자 이상 허용, 영문은 2자 이상으로 노이즈를 줄인다 [S1].
동의어 확장
질의 [성능] → [성능, performance, optimization, 최적화, speed]. Set 으로 중복 제거 후 반환. brain 문서가 영어로, 질의가 한국어로 와도(또는 반대) 매칭되게 하는 양국어 다리 [S1].
섹션 청킹과의 결합
긴 문서를 통째 색인하면 5000자 다주제 문서가 흐릿한 한 단위가 되어 정밀도가 떨어진다. chunker.ts 가 헤딩(#~######) 경계로 섹션을 나누고, 짧은 섹션은 병합·긴 섹션은 문단 경계로 재분할한다. fenced code block(```) 안의 # 는 헤딩으로 보지 않는다. 헤딩 breadcrumb 을 보존해 청크가 문맥을 잃지 않게 한다 [S2].
⚖️ 모순 및 업데이트 (Contradictions & updates)
- TF-IDF 의 한계: 어휘가 다르면(동의어 사전에 없는 환언) 못 잡는다. 그래서 임베딩 하이브리드로 보완한다 → RAG 검색 파이프라인.
- 동의어 사전의 유지보수: 수작업 사전이라 도메인이 늘면 누락이 생긴다. 핵심 도메인 용어 위주로 관리하는 절충.
- 형태소 분석 부재: 한국어 조사/어미를 정밀 분해하지 않는다(경량 우선). 정밀도가 더 필요하면 형태소 분석기 도입 여지.
🛠️ 적용 사례 (Applied in summary)
ConnectAI/src/retrieval/scoring.ts— tokenize/expandQuery/TF-IDF/충돌 탐지 [S1].ConnectAI/src/retrieval/chunker.ts— splitIntoSections 섹션 청킹 [S2].
💻 코드 패턴 (Code patterns)
// 1) 중앙 설정 객체 — 가중치/임계값 한 곳에서 (src/retrieval/scoring.ts)
const SCORING_CONFIG = {
STOP_WORDS_EN: new Set(['the','a','and',/* ... */]),
STOP_WORDS_KO: new Set(['그리고','그런데',/* ... */]),
SYNONYM_DATA: [['성능', ['performance','optimization','최적화','speed']], /* ... */],
TITLE_MULTIPLIER: 3.0,
GLOBAL_CACHE_LIMIT: 2000,
};
// 2) TF 계산 1회화 (src/retrieval/scoring.ts)
function buildTermCounts(tokens: string[]): Map<string, number> {
const counts = new Map<string, number>();
for (const t of tokens) counts.set(t, (counts.get(t) || 0) + 1);
return counts; // 질의 용어마다 재스캔 대신 이 맵을 조회
}
// 3) 동의어 확장 (src/retrieval/scoring.ts)
export function expandQuery(tokens: string[]): string[] {
const expanded = new Set(tokens);
for (const t of tokens) (synonymMap.get(t) ?? []).forEach(s => expanded.add(s));
return Array.from(expanded);
}
// 4) 헤딩 경계 섹션 청킹 — fence 안의 # 무시 (src/retrieval/chunker.ts)
const fence = line.trimStart().startsWith('```'); if (fence) inFence = !inFence;
const m = !inFence ? line.match(HEADING_RE) : null; // 코드블록 내 #는 헤딩 아님
✅ 검증 상태 및 신뢰도
- 상태: draft
- 검증 단계: applied
- 출처 신뢰도: A
- 신뢰 점수: 0.92
- 중복 검사 결과: 신규 생성 (New discovery)
🔗 지식 그래프 (Knowledge Graph)
- 상위/루트: ConnectAI 아키텍처 개요
- 관련 개념: RAG 검색 파이프라인, 5계층 메모리 시스템, TypeScript 기초와 타입 시스템
- 참조 맥락: 로컬 LLM 이 가벼운 텍스트 검색·토큰화·점수 함수를 작성할 때(특히 한/영 혼용) 참조.
📚 출처 (Sources)
- [S1] ConnectAI/src/retrieval/scoring.ts — 토크나이저, TF-IDF, 동의어, 불용어, 충돌 탐지, 캐시
- [S2] ConnectAI/src/retrieval/chunker.ts — 섹션 청킹(순수 함수)
📝 변경 이력 (Change history)
- 2026-06-13: ConnectAI 코드 분석 기반 초안 생성.