본문으로 건너뛰기

Eris의 임베딩 기반 도구 선택 구조

Eris는 임베딩과 정책 계층으로 도구 후보를 고르고 GBNF grammar로 허용 범위를 강제합니다.

이 요약은 AI가 원문을 분석해 생성했습니다. 정확한 내용은 원문 기준으로 확인하세요.

TL;DR

Eris는 약 50개 도구를 사용하는 로컬 14B 모델에서 도구 선택을 grep과 키워드 매칭에서 임베딩 기반 후보 검색으로 바꿨습니다. 사용자 문장과 도구별 routing hints를 nomic-embed-text로 벡터화하고 cosine similarity 임계값 0.50을 적용한 뒤, 정책 계층이 약한 단일 적중을 낮추거나 관련 도구 클러스터로 범위를 넓힙니다. 최종 목록은 slim tool prompt와 llama.cpp의 GBNF grammar에 동시에 전달되며, 문법은 해당 턴에 허용된 도구와 JSON Schema에 맞는 출력만 생성하게 만듭니다. 이 구조는 모델의 지능을 높이기보다 잘못된 단일 도구를 강제하는 오류를 줄이는 데 초점을 둡니다.

섹션별 상세

01
Eris의 도구 선택은 모델 출력에서 API: 문자열을 grep하던 방식에서 시작했습니다. 모델이 도구 계약을 안정적으로 받지 못하자 OpenAI function-call 형식과 TypeScript 패치를 추가했지만, Ollama 기반 로컬 모델에서는 streaming 중 tool_calls가 raw text로 돌아오거나 system prompt가 누락되는 문제가 남았습니다. 이 경험은 도구 선택과 구조화 출력을 별도 문제로 다루기보다, 작은 모델이 실제로 호출할 후보와 생성 가능한 형식을 함께 제한해야 한다는 방향으로 이어졌습니다.
02
사용자 문장의 키워드를 contains로 검사하는 방식은 동의어, 독일어 입력, 이전 발화를 가리키는 표현, 문맥에 따른 단어 충돌에 취약했습니다. Eris는 기존 키워드 목록을 버리지 않고 도구를 원하는 사용자가 자주 쓰는 routing phrases로 재활용해 도구 설명과 함께 임베딩했으며, URL이나 도메인처럼 강한 신호에는 web:fetch를 직접 추가하는 lexical guard를 유지했습니다. 그 결과 의미가 비슷하지만 단어가 다른 표현은 임베더가 연결하고, 명확한 URL 의도는 규칙이 우선하는 혼합 구조가 되었습니다.
rust
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와 도구 설명을 결합해 라우팅용 텍스트를 만듭니다.

03
Eris는 시작 시 각 도구의 설명과 routing hints를 nomic-embed-text로 한 번 임베딩하고, 매 턴 사용자 문장을 같은 모델로 변환해 모든 도구 벡터와 cosine similarity를 계산합니다. 기본 임계값은 0.50이며, “hey”, “thanks”, “test” 같은 짧은 입력은 임베딩과 grammar 재컴파일을 건너뜁니다. Moltbook 도구처럼 일반 대화와 0.50에서 0.56 사이로 겹치는 영역에는 “moltbook” 또는 “submolt”가 없을 때 0.58 미만 적중을 제거하는 별도 바닥값도 적용합니다.
rust
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를 계산하고 임계값 이상인 후보를 점수 내림차순으로 정렬합니다.

rust
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를 결합해 도구별 임베딩을 한 번만 만들고 메모리에 보관합니다.

04
임베딩 점수의 상위 도구만 제공하면 GBNF grammar가 그 선택을 구조적으로 고정하므로, top-1 오선택은 단순한 낮은 정확도가 아니라 회복할 수 없는 잘못된 호출이 됩니다. 정책 계층은 0.58 미만의 단일 약한 적중을 전체 도구 목록이나 해당 도메인 클러스터로 넓히고, 관련 도메인의 near-tie에는 시간·웹·지식처럼 실제 관계가 있는 도구만 묶습니다. 반대로 Moltbook, web, database, document처럼 서로 무관한 후보가 비슷한 0.55에 모이면 클러스터 전체를 열지 않고 cosine 순위 기반의 좁은 후보만 유지합니다.
05
최종 제공 목록은 도구 이름과 짧은 설명, routing phrases를 담은 slim tool prompt와 도구 이름 및 인자 JSON Schema를 제한하는 GBNF grammar에 함께 사용됩니다. web:fetch나 web:search가 있으면 web:find를 추가하고, doc:read가 있으면 상태가 허용하는 경우 vault:write를 연결하는 overlay도 같은 목록에 적용됩니다. prompt와 grammar가 서로 다른 도구를 허용하는 drift를 막기 위해 두 소비자가 동일한 함수와 동일한 순서의 목록을 사용하므로, 모델에게 보이는 선택지와 실제 생성 가능한 선택지가 일치합니다.

용어 해설

임베딩(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 요약 · 북마크 · 개인 피드 설정 — 무료

출처 · 인용 안내

원문 발행 2026. 09. 09.수집 2026. 09. 09.출처 타입 RSS

인용 시 "요약 출처: AI Trends (aitrends.kr)"를 표기하고, 사실 확인은 원문 보기 기준으로 진행해 주세요. 자세한 기준은 운영 정책을 참고해 주세요.