distance_function은 벡터 간 유사도를 어떻게 계산할지를 결정하는 핵심 설정입니다. 특히 ChromaDB, FAISS, Pinecone, Weaviate 등 모든 벡터 DB에서 반드시 지정하는 요소이며, 챗봇의 "답변 정확도"에 직접적인 영향을 미칩니다.
종류 |
의미 |
특징 |
유사도 판단 방식 |
'cosine' |
코사인 거리 |
벡터 간 방향(각도) 비교 |
0에 가까울수록 유사 |
'l2' 또는 'euclidean' |
유클리드 거리 |
벡터 간 직선 거리 비교 |
0에 가까울수록 유사 |
'ip' 또는 'dot' |
inner product (내적) |
벡터 간 길이 포함 곱 |
값이 클수록 유사 |
- cosine: A와 B의 방향이 같은지 비교 (문장이 길든 짧든 무관)
- l2: A와 B가 얼마나 가까운 위치에 있는지 (길이도 중요)
- ip: A와 B를 dot product 하여 문장이 길수록 유리 (크기가 커질수록 값도 커짐)
분야 |
distance_function 추천 |
검색엔진(텍스트 유사도) |
cosine 👍 |
이미지 검색 |
l2 또는 ip |
고객 FAQ 챗봇 |
cosine 👍👍 |
추천 시스템 (행동 기반 벡터) |
ip (dot product) |
항목 |
선택 |
고객지원 챗봇에서 추천 |
✅ cosine |
내적 기반 빠른 추천이 필요할 때 |
ip 가능 (but 정밀도 낮음) |
검색 정확도와 정밀도 우선 |
cosine 필수 |
- ip를 쓰면 normalize 하지 말고 쓰는 게 좋습니다.
- cosine을 쓰면 normalize 벡터 필수입니다.
- l2는 일반 텍스트에는 잘 안 씁니다. (단어 순서 중요할 때도 적합하지 않음)
import { ChromaClient } from 'chromadb';
..........
client = new ChromaClient();
..........
normalize(vec) {
const norm = Math.sqrt(vec.reduce((sum, v) => sum + v * v, 0));
return vec.map(v => v / norm);
}
// 데이타 저장
async function getOrCreateCollection() {
this.collection = await client.getOrCreateCollection({
name: this.collectionName,
metadata: { distance_function: 'cosine' }
});
console.log('📝 FAQ 데이터 저장 중...');
const embeddings = await Promise.all(
this.faqData.map(item =>
this.getEmbedding(item.question).then(this.normalize)
)
);
await this.collection.add({
ids: this.faqData.map((_, i) => 'faq_' + i),
documents: this.faqData.map(item => item.question),
metadatas: this.faqData.map(item => ({ answer: item.answer })),
embeddings
});
}
// 답변 가져오기
async findAnswer(userQuestion) {
if (!this.collection) {
this.collection = await this.client.getCollection({ name: this.collectionName });
}
const queryEmbedding = this.normalize(await this.getEmbedding(userQuestion));
const results = await this.collection.query({
queryEmbeddings: [queryEmbedding],
nResults: 1
});
const best = results?.metadatas?.[0]?.[0];
const bestScore = results?.distances?.[0]?.[0]; // cosine: 낮을수록 유사함
console.log('🔍 유사도 검색 결과(best):', best, '코사인 거리(bestScore):', bestScore);
// ✅ cosine 거리 기준: 0.3 이하이면 매우 유사
const COSINE_THRESHOLD = 0.35;
if (!best || bestScore > COSINE_THRESHOLD) {
return await this.generateGeneralResponse(userQuestion);
}
const final = await this.paraphraseAnswer(best.answer, userQuestion);
return final;
}