TL;DR
Eris는 약 50개 도구를 사용하는 로컬 14B 모델에서 도구 선택을 grep과 키워드 매칭에서 임베딩 기반 후보 검색으로 바꿨습니다. 사용자 문장과 도구별 routing hints를 nomic-embed-text로 벡터화하고 cosine similarity 임계값 0.50을 적용한 뒤, 정책 계층이 약한 단일 적중을 낮추거나 관련 도구 클러스터로 범위를 넓힙니다. 최종 목록은 slim tool prompt와 llama.cpp의 GBNF grammar에 동시에 전달되며, 문법은 해당 턴에 허용된 도구와 JSON Schema에 맞는 출력만 생성하게 만듭니다. 이 구조는 모델의 지능을 높이기보다 잘못된 단일 도구를 강제하는 오류를 줄이는 데 초점을 둡니다.
섹션별 상세
fn enrich_for_routing( name: &str, description: &str, descriptors: Option, ) -> String {
if let Some(registry) = descriptors && let Some(desc) = registry.get(name) && !desc.routing_hints.is_empty() {
return format!( "{}: {}. Common triggers: {}", name, description, desc.routing_hints.join(", ") );
}
let hints = crate::tools::routing_phrases::fallback_triggers(name);
if hints.is_empty() { format!("{}: {}", name, description) } else { format!("{}: {}. Common triggers: {}", name, description, hints) }
}도구별 routing_hints가 있으면 우선 사용하고, 없으면 fallback triggers와 도구 설명을 결합해 라우팅용 텍스트를 만듭니다.
let thought_vec = self.embed_text(thought).await?;
let mut hits: Vec = self
.tool_embeddings
.iter()
.filter_map(|(name, emb)| {
let sim = cosine_similarity(&thought_vec, emb);
if sim >= self.threshold {
Some((name.clone(), sim))
} else {
None
}
})
.collect();
hits.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap_or(std::cmp::Ordering::Equal));사용자 문장을 임베딩한 뒤 각 도구 벡터와 cosine similarity를 계산하고 임계값 이상인 후보를 점수 내림차순으로 정렬합니다.
pub async fn new(
embed: Arc,
tool_descriptions: Vec,
descriptors: Option>,
threshold: f32,
) -> Result {
let mut tool_embeddings = Vec::with_capacity(tool_descriptions.len());
for (name, description) in &tool_descriptions {
let text = Self::enrich_for_routing(name, description, descriptors.as_deref());
let embedding = embed.embed(&text).await?;
tool_embeddings.push((name.clone(), embedding));
}
Ok(Self { embed, tool_embeddings, threshold })
}시작 시 각 도구의 설명과 routing hints를 결합해 도구별 임베딩을 한 번만 만들고 메모리에 보관합니다.
용어 해설
- 임베딩(Embeddings)
- — 텍스트를 의미를 반영한 숫자 벡터로 변환하는 방식입니다. 사용자 문장과 도구별 설명을 같은 임베딩 공간에 놓은 뒤 벡터 간 cosine similarity를 계산하면, 단어가 정확히 일치하지 않는 동의어나 패러프레이즈도 관련 도구 후보로 연결할 수 있습니다.
- GBNF 문법(GBNF Grammar)
- — 모델이 생성할 수 있는 토큰의 순서와 형태를 문법으로 제한하는 방식입니다. llama.cpp에서는 도구 이름과 JSON Schema를 문법에 반영해 유효한 구조만 샘플링하게 만들므로, 모델이 허용되지 않은 도구 호출이나 잘못된 출력 형식을 만들지 못하게 합니다.
- Cosine Similarity
- — 두 벡터가 같은 방향을 향하는 정도를 측정하는 값입니다. Eris는 사용자 문장 벡터와 각 도구의 사전 계산 벡터를 비교하고, 기본 임계값 0.50 이상인 도구를 후보로 남겨 의미 기반 라우팅에 활용합니다.
- 정책 계층(Policy Layer)
- — 임베딩 점수만으로 도구를 고르지 않고 강제 호출, 약한 단일 적중의 제외, 관련 도구 묶음 확장, 대화 맥락 연결을 적용하는 규칙 계층입니다. 특히 GBNF가 선택 결과를 강제하는 환경에서 잘못된 단일 후보를 여러 후보로 넓혀 복구 여지를 보존합니다.
기술
- Ollama
- Obsidian
- Redis
- bash
- TypeScript
- Rust
- llama.cpp
- nomic-embed-text
- GBNF
- JSON Schema
- TOML
활용 사례
- 로컬 LLM의 다중 도구 선택
- 약 50개 도구를 사용하는 개인용 에이전트
- 임베딩 기반 도구 후보 검색
- 문법 제약 구조화 출력
- 대화 맥락을 활용한 연속 도구 호출
언급된 리소스
AI 요약 · 북마크 · 개인 피드 설정 — 무료
출처 · 인용 안내
인용 시 "요약 출처: AI Trends (aitrends.kr)"를 표기하고, 사실 확인은 원문 보기 기준으로 진행해 주세요. 자세한 기준은 운영 정책을 참고해 주세요.