~/.wigolo/ 폴더에 산다. 이 문서는 소스를 직접 클론해 "이 저장소에서 무엇을 배울 수 있는가"를 파고든다.
(저장소: KnockOutEZ/wigolo · TypeScript · MCP 서버 · AGPL-3.0-only © 2026 Towhid Khan · v0.2.0 · 최신 커밋 2026-07-17 c0afc83 · TrendShift Daily #25)
KnockOutEZ/wigolo는 내 컴퓨터에서 도는 MCP(Model Context Protocol) 서버다. Claude Code·Cursor·Codex 같은 AI 코딩 에이전트에 붙여 두면, 에이전트가 "이거 검색해 줘 / 이 페이지 읽어 줘 / 이 사이트 크롤해 줘 / 이 표만 뽑아 줘 / 이 주제 리서치해 줘" 같은 웹 작업을 단 하나의 창구로 시킬 수 있다. package.json의 설명 그대로 "Local-first web intelligence MCP server for AI coding agents"이다.
가장 먼저 풀어야 할 오해 — 이름이 "위골로"라 낯설지만, 이건 Firecrawl·Exa·Tavily처럼 돈 받고 API를 파는 웹 서비스의 "키 없는 로컬 버전"이다. 보통 이런 도구는 회원가입 → API 키 발급 → 쿼리마다 과금이지만, wigolo는 공개 검색엔진(DuckDuckGo·Bing·Mojeek…)의 결과 HTML을 직접 긁어 오고, 그 결과의 순위 매기기·유사도 계산을 내 CPU에서 도는 작은 AI 모델(ONNX)로 처리한다. 그래서 검색 키가 필요 없고, 쿼리당 비용이 0이다.
stdio(표준 입출력) — 즉 네트워크 포트를 열지 않고 프로그램끼리 파이프로 대화한다.linkedom으로 파싱해 긁는다(src/search/engines/duckduckgo.ts가 lite.duckduckgo.com/lite를 긁는 식). ② 클라우드 없음 = 순위 재정렬(리랭킹)과 임베딩을 기기 안 ONNX 모델로 돌린다. ③ 종량 요금 없음 = 캐시·모델·설정이 전부 ~/.wigolo/에 있어 재질의는 로컬 캐시가 답한다. 단, 이 "무료"는 핵심 6개 도구(search·fetch·crawl·extract·cache·find_similar)에 해당하고, 글을 써 주는 research·agent는 LLM이 필요하다(뒤에서 상술).Firecrawl·Exa 같은 유료 API는 외부 대행사와 같다 — 검색·크롤을 대신 해 주지만, 요청 한 건마다 요금이 붙고 내 질의가 그 회사 서버를 지난다. wigolo는 이 대행사를 내 책상 위 사서 로봇으로 바꾼다. 로봇은 공개 도서관(공개 검색엔진)에 직접 가서 목록을 베껴 오고, 어떤 자료가 더 쓸모 있는지 스스로(기기 안 작은 AI로) 판단해 순위를 매긴다.
로봇이 한 번 찾아 온 자료는 책상 서랍(~/.wigolo/ 캐시)에 넣어 두니, 같은 질문엔 인터넷 없이도 즉시 답한다. 요금 청구서도, 회원 카드도 없다. 다만 "긴 보고서를 문장으로 써 달라"는 부탁만은 글솜씨 좋은 작가(LLM)를 따로 불러야 한다 — 그 작가는 내 키로 부르거나, 동네 작가(로컬 Ollama)를 써도 된다.
wigolo가 트렌딩에 오른 이유는 "또 하나의 크롤러"여서가 아니다. AI 에이전트가 폭발적으로 늘면서 "에이전트에게 웹을 어떻게 쥐여 줄 것인가"가 병목이 됐는데, 지금까지의 답은 대부분 Firecrawl·Exa·Tavily 같은 유료 API였다. wigolo는 그걸 키도 클라우드도 없이, 내 기기에서 공짜로 하겠다고 나선 정면 도전이다. README 스스로 밝히길, 공개 직후 48시간 만에 별 대부분이 몰렸다(2026년 7월 초).
| 포인트 | 내용 |
|---|---|
| 정체 | 로컬 우선 웹 인텔리전스 MCP 서버. 검색·수집·크롤·추출·캐시·유사문서·리서치·에이전트·diff·watch까지 웹 작업 10종을 하나의 서버로. 조각이 아니라 완결된 도구 세트다. |
| 차별점 ① | 검색 키가 필요 없다. 공개 엔진 HTML을 직접 긁고(duckduckgo·bing·mojeek…), 순위는 기기 안 크로스 인코더로 재정렬. Firecrawl/Exa/Tavily 대비 "쿼리당 0원". |
| 차별점 ② | 클라우드가 없다. 캐시(SQLite)·임베딩(fastembed)·모델(ONNX)·설정·API 키가 전부 ~/.wigolo/에. 내 질의가 제3자 서버를 안 지난다(LLM 합성은 선택). |
| 차별점 ③ | "코드가 모델을 이긴다"는 설계. 정규화·중복제거·순위융합·해싱 같은 확정적 작업은 LLM을 절대 안 거치고, LLM이 채운 값은 원문과 대조해 없으면 지운다(환각 차단). |
| 제작자 | Towhid Khan(GitHub 핸들 KnockOutEZ) 1인. 라이선스는 AGPL-3.0(카피레프트)이고 "wigolo"는 상표로 주장. |
지금 AI 에이전트 생태계의 뜨거운 병목은 "모델은 똑똑한데 최신 웹을 못 본다"는 것이다. 그 틈을 Firecrawl·Exa·Tavily 같은 유료 API가 메워 왔다. wigolo는 같은 일을 MCP 도구 10개로 표준화해 어떤 에이전트에도 꽂히게 하면서, 비용은 공개 엔진 스크래핑 + 온디바이스 ML로 0에 눌렀다. "에이전트 시대의 인프라를 오픈소스로, 그것도 공짜로"라는 서사가 트렌딩의 동력이다.
단순 스크래핑은 결과가 지저분하다. wigolo가 흥미로운 건 여러 엔진 결과를 합치고 순위를 매기는 과정을 전부 확정적 알고리즘 + 작은 기기 모델로 처리한다는 점이다. 여러 엔진 순위를 RRF(상호 순위 융합)로 합치고, 기기 안 크로스 인코더(ms-marco-MiniLM)로 질의–결과 적합도를 재계산해 재정렬한다. "큰 LLM 없이도 검색 품질을 어떻게 올리나"의 실전 교재다.
wigolo는 사실 MCP 서버이자, CLI이자, REST API 서버이자, npm 라이브러리이자, SDK 묶음이다. 같은 구현을 stdio(MCP)·터미널 명령·127.0.0.1:3333 REST로 동시에 노출한다. "하나의 핵심 로직을 여러 진입점으로 파는" 현대적 도구 패키징을 통째로 관찰할 수 있다. 게다가 브라우저 자동화(Playwright)·SQLite 벡터검색·온디바이스 임베딩·TLS 지문 위장까지, 한 저장소 안에 요즘 인프라 기술이 밀집해 있다.
냉정히 보면 wigolo는 아직 public beta다(README가 "충분히 많은 사람이 써 보고 별을 줄 때까지 beta로 둔다"고 명시). 배포 채널도 지금 검증된 건 npm 하나뿐이고, curl | sh·Homebrew·컨테이너 레지스트리·in-repo SDK는 "정식 릴리스 때 열린다"는 예고 상태다. 그리고 "키 없음/무료"는 핵심 6개 도구에만 해당한다 — research·agent처럼 문장을 써 주는 기능은 LLM이 필요하고, 첫 실행 때 리랭커·임베딩 ONNX 모델을 수백 MB 내려받고 디스크 ~1.5GB를 쓴다. 즉 "완성된 무료 만능툴"이라기보다 "아키텍처가 알찬, 진행 중인 실전 인프라"로 보는 게 정확하다.
wigolo는 TypeScript로 짠 Node ≥ 20 프로그램이다("type": "module" ESM). 코드의 압도적 다수가 .ts(1,073개)이고, .py(44개)는 별도로 버전 관리되는 파이썬 SDK·프레임워크 연동일 뿐 핵심이 아니다. 스택을 ① 프로토콜·런타임, ② 웹 수집(브라우저·HTTP), ③ 저장·검색(SQLite), ④ 지능(온디바이스 ML), ⑤ 부가(LLM·CLI UI)로 나눠 지도를 그려 보자.
| 영역 | 기술 · 버전 |
|---|---|
| MCP 서버 | @modelcontextprotocol/sdk ^1.29.0 — Server + StdioServerTransport로 stdio(JSON-RPC) 통신. 사용 안내 마크다운을 MCP Resource로도 노출 |
| 런타임 · 언어 | Node ≥ 20(engines.node), ESM, TypeScript ^6.0.2 |
| 빌드 | tsup(esbuild 기반, bundle:false=파일별 ESM 트랜스파일) + tsc로 타입 선언 생성. 개발은 tsx |
| 테스트 | vitest ^4.1.4 — 633개 테스트 파일(README의 "7,600 테스트"는 케이스 수) |
| 패키징 | npm(주 배포) · @yao-pkg/pkg 6.21.0 + esbuild 0.28.0(단일 실행파일) · Docker(node:22-bookworm-slim, slim/full 2종) |
수집은 가벼운 것부터 시도하고 막히면 더 강한 수단으로 올라가는 계단식이다. 이게 src/fetch/router.ts(63KB, 저장소에서 가장 큰 파일)의 SmartRouter다.
| 단계 | 기술 · 역할 |
|---|---|
| 1단 · 순수 HTTP | http-client.ts — 그냥 HTTP 요청. 가장 빠르고 가볍다. 대부분의 정적 페이지는 여기서 끝 |
| 2단 · TLS 위장 | tls-tier.ts(28KB) + 선택 의존성 wreq-js ^2.3.1 — TLS 지문을 실제 브라우저처럼 위장해 봇 차단을 통과 |
| 3단 · 헤드리스 브라우저 | Playwright 1.60.0 — MultiBrowserPool(browser-pool.ts)이 chromium/firefox/webkit을 라운드로빈. JS로 그리는 SPA·챌린지 페이지를 실제 렌더 |
| 본문 추출 | @mozilla/readability ^0.6.0 + defuddle ^0.16.0(본문 골라내기), linkedom ^0.18.12(서버 DOM 파싱), turndown ^7.2.4(HTML→마크다운), pdf-parse ^2.4.5(PDF), tinyld(언어감지) |
| 구분 | 기술 · 버전 |
|---|---|
| 로컬 DB | better-sqlite3 ~12.9.0 — ~/.wigolo/wigolo.db에 캐시·색인 저장 |
| 단어 검색 | FTS5(url_cache_fts 가상 테이블) — SQLite 내장 전문 검색, BM25 점수 |
| 벡터 검색 | sqlite-vec ^0.1.9(vec0 가상 테이블) — 같은 SQLite 안에서 코사인 유사도(의미 검색) |
| 토큰 계산 | gpt-tokenizer ^3.4.0 — 결과 길이를 토큰 예산에 맞춰 잘라 주기 |
| 스키마 검증 | ajv 8.17.1 — extract가 받는 커스텀 JSON Schema 검증 |
| 기능 | 기술 · 모델 |
|---|---|
| 임베딩 | fastembed ^2.1.0(네이티브 ONNX) — 모델 BAAI/bge-small-en-v1.5(384차원), ~/.wigolo/fastembed에 캐시 |
| 리랭킹(재정렬) | @huggingface/transformers 3.5.0(Transformers.js) — 크로스 인코더 Xenova/ms-marco-MiniLM-L-6-v2로 질의–결과 적합도 재계산 |
| 순위 융합 | src/search/rrf.ts — 여러 엔진 순위를 RRF(Reciprocal Rank Fusion)로 합침. LLM 없이 확정적 계산 |
LLM은 전적으로 선택이며 문장 합성(research·agent·search format=answer)에만 쓴다 — @anthropic-ai/sdk·openai·@google/genai·groq-sdk, 또는 로컬 Ollama. API 키는 선택 의존성 @napi-rs/keyring ^1.3.0으로 OS 키체인에 넣거나 AES 암호화 파일로 보관한다(config.json엔 절대 평문 저장 안 함). 터미널 UI(설정 마법사·대화형 셸)는 ink ^5.2.1 + react ^18.3.1 + @inquirer/prompts로 그린다.
null로 지운다(환각 차단). 큰 모델에 다 떠넘기지 않고 확정적 코드로 뼈대를 세우는 이 태도가 "키 없이 무료"를 가능케 한 진짜 이유다.~/.wigolo/ 캐시wigolo의 데이터 흐름은 "에이전트의 요청이 MCP 창구로 들어와, 도구 계층을 지나, 웹과 로컬 캐시를 오가며 답을 만들어 돌아가는" 구조다. 전체 지도를 먼저 그리고, 두 개의 핵심 엔진(수집 사다리 · 검색 파이프라인)을 확대해 보자.
웹 수집의 난제는 "어떤 페이지는 그냥 HTTP로 되고, 어떤 페이지는 봇 차단 때문에 진짜 브라우저가 필요하다"는 것이다. wigolo는 가장 싼 수단부터 시도하고, 실패 신호(403·SPA 빈 껍데기·본문 빈약·챌린지 페이지)를 보면 한 단계 올라간다. 그리고 결정적으로 — 어느 도메인이 몇 단을 요구하는지 학습해 SQLite(domain_routing)에 저장한다. 다음번 같은 도메인은 처음부터 맞는 단계로 간다.
wigolo의 search는 그냥 한 엔진에 던지는 게 아니다. 먼저 질의의 "의도"를 분류(intent-router.ts)해 버티컬(general·news·papers·docs·code·images)을 정하고, 그 버티컬에 맞는 엔진 묶음만 병렬로 부른다. 예컨대 논문 질의면 arXiv·Semantic Scholar가, 코드 질의면 GitHub 코드검색·StackOverflow가 붙는 식이다. 그렇게 모은 여러 순위를 RRF로 융합하고, 기기 안 크로스 인코더로 최종 재정렬한 뒤, 인용 ID가 달린 근거·하이라이트로 돌려준다.
모든 로컬 상태는 ~/.wigolo/wigolo.db 하나에 모인다(src/cache/db.ts). 표 하나에 여러 검색 방식을 얹은 게 특징이다.
| 테이블 | 역할 |
|---|---|
| url_cache | 수집한 페이지 본문·메타데이터. embedding·embedding_model·embedding_dims 열이 붙어 벡터까지 동거 |
| url_cache_fts | FTS5 가상 테이블 — 단어(BM25) 검색용 |
| vec0 (sqlite-vec) | 임베딩 벡터의 코사인 유사도 검색 — 의미 검색 |
| domain_routing | 도메인별 "몇 단 수집이 필요한가" 학습값 — SmartRouter가 읽고 씀 |
| domain_boilerplate | 사이트 공통 군더더기(헤더·푸터) 지문 — 크롤 시 중복 제거에 사용 |
| search_cache | 검색 결과 캐시 — 같은 질의 재질의를 즉답(오프라인 가능) |
wigolo의 또 다른 설계 미덕은 honest degradation(정직한 성능 저하)이다. 캐시가 낡았거나, 어떤 엔진이 실패했거나, 결과가 잘렸거나, 봇 차단(blocked_by_challenge)에 걸렸으면 — 그 사실을 결과에 그대로 표시한다. "빈 성공"으로 위장하지 않는다. 각 엔진은 wrapWithRetryAndBreaker(재시도 + 서킷 브레이커)로 감싸, 한 엔진이 죽어도 전체가 멈추지 않는다. 에이전트가 "이 답이 완전한지 아닌지"를 알 수 있게 하는, 신뢰성 설계다.
src/가 두뇌(71K줄), tests/가 절반(633파일) — "한 서버, 여러 진입점"저장소를 열면 압도되기 쉽다(파일 1,543개, 코드 20만 줄). 하지만 뼈대는 단순하다 — src/가 실제 두뇌이고 나머지는 테스트·배포·연동·문서다. 진입점부터 따라가 보자.
진입점 읽는 순서는 이렇다. ① src/index.ts(CLI 라우팅 — 무슨 명령이 뭘 하는지) → ② src/server.ts(MCP 서버가 어떻게 뜨고 도구를 등록하는지) → ③ src/server/tool-schemas.ts(각 도구가 받는 입력 스키마) → ④ 관심 도구의 src/tools/*.ts → ⑤ 그 도구가 부르는 서브시스템(search/ 또는 fetch/). 가장 큰 파일 src/fetch/router.ts(63KB)와 src/types.ts(71KB)가 각각 "수집 두뇌"와 "타입 지도"라, 이 둘을 훑으면 전체 그림이 빠르게 잡힌다.
엔진: src/search/engines/엔 파일이 18개지만 하나(user-agents.ts)는 헬퍼라 실제 엔진 어댑터는 17개다(arxiv·bing·bing_news·brave·brave-image·ddg-image·devdocs·duckduckgo·github-code·hn-algolia·lobsters·marginalia·mdn·mojeek·semantic-scholar·stackoverflow·wikipedia). 게다가 한 질의에 다 쓰지 않는다 — intent-router가 버티컬별로 부분집합만 고른다. 도구: package.json의 mcp.tools 배열엔 8개만 적혀 있지만(diff·watch 누락), 실제 src/server.ts가 등록하는 건 10개다. 문서·코드가 맞고 package.json 필드가 낡았다 — 코드(10개)를 믿어라.
wigolo가 학습 표본으로 훌륭한 이유는 MCP 서버 설계, 웹 스크래핑, 브라우저 자동화, SQLite 벡터 검색, 온디바이스 ML, TLS 위장, 다중 진입점 패키징이 한 저장소에 모여 있기 때문이다. 관심사별로 배울 것을 짚어 보자.
src/server.ts + src/server/tool-schemas.ts는 MCP 서버의 실전 레퍼런스다. 도구를 어떻게 등록하고(ListToolsRequestSchema/CallToolRequestSchema), 입력 스키마를 어떻게 선언하며, 사용 안내를 MCP Resource로 어떻게 노출하는지 볼 수 있다. 특히 도구 10개가 하나의 stdio 서버에 깔끔히 얹힌 구조는, 직접 MCP 서버를 만들 때 그대로 베낄 만한 골격이다.
src/fetch/는 웹 스크래핑의 현실을 담은 교재다. 순수 HTTP → TLS 지문 위장 → 헤드리스 브라우저로 올라가는 escalation 전략, 실패 신호(403·SPA 껍데기·챌린지)를 읽는 법, 그리고 도메인별로 필요한 강도를 학습·저장해 다음번을 빠르게 하는 최적화까지. "왜 어떤 페이지는 requests로 안 되는가"를 코드로 이해하게 된다.
src/search/는 정보 검색(IR)의 압축 강의다. 여러 엔진 순위를 RRF로 융합하고, 크로스 인코더로 재정렬하고, 중복을 지우고, 근거·하이라이트를 뽑는 전 과정이 확정적 코드 + 작은 온디바이스 모델로 짜여 있다. "검색은 무조건 큰 LLM"이라는 통념 대신, 값싼 부품으로 품질을 조립하는 법을 배운다.
src/cache/db.ts + src/embedding/는 SQLite에 FTS5(단어)와 sqlite-vec(벡터)를 함께 얹어 하이브리드 검색을 만드는 법을 보여 준다. 임베딩을 기기 안 fastembed(ONNX)로 뽑아 url_cache 테이블에 벡터째 저장하는 구조는, RAG를 "서버 없이 로컬로" 만들고 싶은 사람에게 최고의 참고 예시다.
같은 로직을 MCP(stdio)·CLI·REST(127.0.0.1:3333)·npm 라이브러리로 동시에 파는 구조(src/index.ts·src/daemon/)는 현대적 도구 배포의 정석이다. tsup로 빌드하고 @yao-pkg/pkg로 단일 실행파일을 만들고 Docker 이미지를 굽는 packaging/까지, "라이브러리를 여러 채널로 배포"하는 전 과정을 통독할 수 있다.
npx wigolo search "your query"로 CLI 한 방을 때려 보고, 나온 결과에 붙은 설명 가능한 점수·인용 ID를 관찰한다. ② ~/.wigolo/wigolo.db를 SQLite 뷰어로 열어 url_cache·domain_routing 테이블이 어떻게 채워지는지 본다. ③ wigolo tune으로 도메인별 학습된 수집 단계를 확인한다. 이 세 가지만 해 봐도 "이 도구가 안에서 뭘 하는지"가 손에 잡힌다.wigolo는 클라우드 인프라가 필요 없다. 대신 첫 실행 때 브라우저 엔진 바이너리와 온디바이스 ONNX 모델을 ~/.wigolo/로 한 번 내려받는다(수백 MB). 이후 유휴 메모리는 ~47MB로 가볍다(v0.2.0 기준).
| 항목 | 요구/설명 |
|---|---|
| 런타임 | Node ≥ 20(engines.node 명시), ESM |
| 디스크 | ~1.5GB 여유 — 브라우저 바이너리 + ONNX 모델(임베딩·리랭커) + 캐시 DB |
| OS | macOS · Linux · Windows (Docker 이미지엔 브라우저 OS 라이브러리 내장) |
| 메모리 | 유휴 ~47MB. 모델·브라우저는 첫 사용 시 지연 로드(lazy) |
| API 키 | 핵심 6개 도구는 불필요. research·agent·answer만 LLM 키(또는 로컬 Ollama) 필요. Brave·GitHub 키는 검색을 강화하는 선택지일 뿐 |
| 네트워크 | 실시간 웹 접근 필요(공개 엔진·대상 사이트). 재질의만 캐시로 오프라인 가능 |
# 가장 쉬운 길: 에이전트에 자동 연결 (MCP 설정 + 스킬 + 모델 다운로드 + 헬스체크)
npx wigolo init --agents=claude-code
# 지원: claude-code · cursor · codex · gemini-cli · vscode · windsurf · zed · antigravity
# 또는 MCP 클라이언트 설정에 직접 등록
# mcpServers: { "wigolo": { "command": "npx", "args": ["-y", "wigolo"] } }
# CLI 한 방 (MCP 없이 바로 도구 실행)
npx wigolo search "rust async runtime comparison"
npx wigolo fetch "https://example.com/article"
# 관리 명령
npx wigolo doctor # 환경 점검
npx wigolo tune # 도메인별 학습된 수집 단계 확인
npx wigolo serve # REST API 모드 (127.0.0.1:3333, OpenAPI 3.1)
① "키 없음" ≠ "다운로드 없음" — 검색 키는 정말 필요 없지만, 리랭커·임베딩 ONNX 모델을 첫 실행 때 수백 MB 내려받고 디스크 ~1.5GB를 쓴다. ② "로컬" = 저장이 로컬이라는 뜻이지 오프라인이 아니다 — 도구는 실시간 웹을 친다. 캐시된 재질의만 오프라인으로 답한다. ③ research·agent는 LLM 필수 — 클라우드 키를 넣거나, 키 없이 가려면 로컬 Ollama를 깔아야 한다. "완전 공짜 만능"으로 오해하면 실제 사용에서 어긋난다.
npx wigolo search "your topic"를 실행하고, 결과에 붙은 per-result 점수·인용 ID·하이라이트를 관찰한다. 같은 질의를 format=answer로도 돌려(LLM 필요) "근거만 주는 것" vs "문장으로 써 주는 것"의 차이를 비교한다. 목표: wigolo가 "검색 → 융합 → 재정렬 → 근거 제시"를 어떻게 투명하게 보여 주는지 체감.
몇 개 사이트를 fetch한 뒤 ~/.wigolo/wigolo.db를 SQLite 뷰어로 열어 url_cache·domain_routing·domain_boilerplate 테이블을 관찰한다. 같은 도메인을 다시 fetch했을 때 수집 단계가 학습대로 바뀌는지 wigolo tune으로 확인한다. 목표: "재질의가 왜 빠른가"와 "도메인 학습"을 직접 목격.
src/search/rrf.ts의 Reciprocal Rank Fusion을 파이썬/JS로 옮겨, "서로 다른 순위표 2~3개를 하나로 합치는" 작은 함수를 만든다. 같은 문서가 여러 순위표에서 어떻게 위로 올라오는지 실험한다. 목표: LLM 없이 검색 품질을 올리는 확정적 알고리즘의 원리를 코드로 증명.
examples/plugin-search-engine/와 src/search/engines/duckduckgo.ts를 참고해, 공개 검색/목록 사이트 하나를 긁는 어댑터를 ~/.wigolo/plugins/에 얹어 본다. HTML을 linkedom으로 파싱해 제목·URL·스니펫을 뽑아 표준 결과 형태로 반환하면 된다. 목표: wigolo의 플러그인 확장점과 스크래핑 어댑터 패턴을 체득.
better-sqlite3 + FTS5(단어) + sqlite-vec(벡터)로, 문서 몇 개를 넣으면 BM25 점수와 임베딩 코사인 유사도를 합쳐 순위를 내는 작은 검색기를 직접 짠다. 임베딩은 fastembed로 기기 안에서 뽑는다. wigolo의 src/cache/db.ts·src/embedding/가 참고 예시. 목표: "서버 없는 로컬 RAG 검색"을 스스로 완성.
| 주차 | 주제 · 학습 목표 |
|---|---|
| 1주차 MCP · 에이전트 도구 | MCP와 에이전트 툴링을 이해한다. Model Context Protocol의 개념, stdio 전송, 도구 등록(ListTools/CallTool)과 입력 스키마 설계, Resource 노출. wigolo의 src/server.ts·tool-schemas.ts를 뜯어보며 "하나의 서버에 도구 10개를 얹는 법"을 익히고, 작은 MCP 서버를 직접 만들어 본다. |
| 2주차 웹 스크래핑 · 브라우저 | 현실의 웹 수집. HTTP → TLS 지문 위장 → 헤드리스 브라우저(Playwright)로 올라가는 escalation, 봇 차단 신호 읽기, @mozilla/readability·defuddle로 본문 추출, turndown으로 마크다운화. 도메인별 수집 강도 학습(domain_routing)의 캐싱 전략까지. |
| 3주차 정보 검색(IR) | 모델 없이 검색 품질 올리기. BM25(FTS5)의 원리, RRF(상호 순위 융합)로 여러 엔진 합치기, 크로스 인코더 리랭킹(ms-marco-MiniLM)의 개념, 중복 제거와 근거·하이라이트 추출. wigolo src/search/를 교재로 "값싼 부품으로 좋은 검색 조립하기"를 실습. |
| 4주차 온디바이스 RAG | 서버 없는 로컬 지능. 임베딩·벡터 검색의 기초, sqlite-vec로 SQLite에 벡터 얹기, fastembed(ONNX)로 기기 안에서 임베딩 뽑기, FTS5 + 벡터 하이브리드 검색. 나아가 research·agent처럼 "분해→탐색→합성" 하는 에이전트 루프와 BYOK LLM 추상화를 살펴본다. |
stdio(포트 없이 파이프로 대화).~/.wigolo/)에 있는 설계. 단 "저장이 로컬"이라는 뜻이지 오프라인은 아니다 — 도구는 실시간 웹을 치고, 재질의만 캐시가 오프라인으로 답한다.src/fetch/router.ts의 수집 두뇌. HTTP → TLS 위장 → 헤드리스 브라우저로 "막히면 한 단계 세게" 올라가고, 도메인별 필요 단계를 학습·저장(domain_routing)해 다음을 빠르게 한다.wreq-js가 담당.browser-pool.ts)해 JS로 그리는 SPA·챌린지 페이지를 실제 렌더한다.rrf.ts). 여러 순위에서 자주 상위에 뜬 문서가 위로 올라온다. LLM 없이 검색 품질을 올리는 핵심.Xenova/ms-marco-MiniLM-L-6-v2로 돈다(클라우드·키 불필요).fastembed+ONNX, 모델 BAAI/bge-small-en-v1.5 384차원) 계산. ~/.wigolo/fastembed에 캐시.vec0 가상 테이블 = 벡터 코사인 유사도(의미 검색). 둘을 합치면 하이브리드 검색.null로 지우는 설계 원칙(환각 차단). "무료·로컬"을 가능케 한 진짜 이유.search·fetch·crawl·extract·cache·find_similar(키 없는 핵심 6) + research·agent(LLM 합성) + diff·watch(비교·변경감시). package.json엔 8개만 적혀 있으나 코드는 10개를 등록.blocked_by_challenge)을 "빈 성공"으로 위장하지 않고 결과에 정직히 표시. BYOK(Bring Your Own Key) = LLM은 사용자 자신의 키로(또는 로컬 Ollama로) 부르고, 키는 OS 키체인에 보관.저장소 · 제품
· GitHub: github.com/KnockOutEZ/wigolo (AGPL-3.0-only © 2026 Towhid Khan · v0.2.0)
· 최신 커밋: c0afc83 (2026-07-17, PR #184 "fix/vercel-ai-sdk-ignore-scripts" 병합)
· 겨냥한 유료 대체 대상: Firecrawl · Exa · Tavily
핵심 파일(클론 후)
· src/server.ts — MCP 서버 코어(도구 10개 등록)
· src/index.ts — CLI 진입점(명령 라우팅)
· src/fetch/router.ts — SmartRouter 3단 수집 사다리(63KB, 최대 파일)
· src/search/core/ + verticals/ — 의도 분류 → 버티컬 엔진 → RRF → 재정렬
· src/cache/db.ts — SQLite(FTS5 + vec0) 로컬 저장
· src/embedding/fastembed-provider.ts — 온디바이스 임베딩
배경 지식
· Model Context Protocol — MCP 규격의 원전
· Playwright · sqlite-vec · fastembed
· Reciprocal Rank Fusion(RRF) — 순위 융합의 개념
· SQLite FTS5 — 내장 전문 검색
① 검색 API 아님 — 공개 엔진 HTML을 긁고 순위는 온디바이스 ML로 내는 로컬 도구다. ② "무료"의 경계 — 키 없는 건 핵심 6개 도구뿐, research·agent는 LLM 필요(클라우드 키 또는 로컬 Ollama). ③ "로컬" ≠ 오프라인 — 저장이 로컬이란 뜻이고 도구는 실시간 웹을 친다(재질의만 캐시로 오프라인). ④ 첫 실행 다운로드 — 브라우저·ONNX 모델 수백 MB, 디스크 ~1.5GB. ⑤ 도구는 10개 — package.json의 mcp.tools는 8개만 적었으나(diff·watch 누락) 코드가 10개를 등록한다. ⑥ 배포는 아직 npm만 검증 — curl|sh·Homebrew·컨테이너·in-repo SDK는 "정식 릴리스 때" 예고(public beta). ⑦ 제작자 이름 vs 핸들 — 저작권자 Towhid Khan = GitHub 핸들 KnockOutEZ(동일인, Docker Hub는 towhid69420). 라이선스는 AGPL-3.0(카피레프트)이니 상용 통합 시 조항 확인.