이 글은 Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady에 제출하는 내용입니다.
제가 만든 것 (What I Built)
Sloth Sort는 미루고 있는 쌓인 일들을 가져가서 거의 전부 돌려줍니다.
비슷한 숙제가 다시 나타나도, 이 앱은 처음부터 결정하라고 요구하지 않습니다. Tiger Data가 이미 이전 호출을 가지고 있기 때문입니다.
데모 (Demo)
모델이 기기에 남아있기 때문에, 이는 호스팅된 URL이라기보다는 로컬 실행입니다.
Sloth Sort: sample pile, local sort, and the minutes handed back
코드 (Code)
하나의 작은 움직임으로 골치 아픈 쌓인 일들을 돌려주고, Tiger Data에 호출을 기억하는 로컬 Gemma 소터.
Sloth Sort
미루고 있는 쌓여있는 일들을 버리세요. 로컬 Gemma 모델이 오늘 할 가치가 있는 작은 것 하나를 고르고, Tiger Data가 그 호출을 기억하여 내일 비슷한 숙제가 재결정되는 것을 막아줍니다.
이는 Hacktoberfest Open-Source AI Challenge: Week 3, Slow and Steady에 대한 새로운 프로젝트입니다.
절약해주는 것 (What it saves)
골치 아픈 목록은 보통 모든 것이 지금 당장 일어나야 한다고 주장하는 여덟 가지 과제로 이루어져 있습니다. Sloth Sort는 작은 움직임 하나를 제외한 나머지 모든 것에 대해 분(minutes)을 돌려줍니다. 첫 번째 샘플 쌓인 일들은 실제 모델에서 숙제를 지어내지 않고도 그 느낌을 받을 수 있도록 제공됩니다.
구축 방법 (How it is built)
flowchart LR
pile[붙여넣은 쌓인 일]
api[FastAPI]
embed[Ollama를 통한 EmbeddingGemma]
embed --> tiger[(Tiger Data)]
tiger --> memory[BM25 plus pgvector]
memory --> gemma[Ollama를 통한 Gemma 4 E4B]
gemma --> api
api --> ledger[effort_events hypertable]
ledger --> chart[minutes_saved_daily]
로딩 중
- Gemma 4 E4B (
gemma4:e4b in Ollama)는...
GitHub에서 확인하기: View on GitHub
github.com/tharun634/sloth-sort. MIT 라이선스. README.md에는 실행 단계가 나와 있습니다: Ollama, Tiger Cloud 연결 문자열, 그리고 uvicorn.
구축 과정 (How I Built It)
flowchart LR
pile[붙여넣은 묶음] --> api[FastAPI]
api --> embed[Ollama를 통한 EmbeddingGemma]
...
두 개의 오픈 모델을 사용하며, 둘 다 localhost의 Ollama를 통해 연결하고 SDK는 사용하지 않았습니다. 클라이언트 전체가 /api/chat과 /api/embed로 POST 요청을 보내는 것으로 구성되어 있습니다. 이는 한 번 호출(one-shot local call)을 위해 Damiano builds에서 설명한 것과 동일한 형태입니다: 문자열 입력, 문자열 출력이며, 로컬 모델의 특성상 느릴 수 있기 때문에 긴 타임아웃이 설정되어 있습니다.
Gemma 4 E4B (gemma4:e4b)가 분류기(sorter) 역할을 합니다. 이 모델은 하나의 JSON 객체로 응답하며, 정확히 하나의 do 항목과 나머지는 각각 later와 skip으로 분할합니다. 저는 사고 과정을 비활성화했습니다. 이를 활성화하면 모델이 추적 과정에 토큰 예산을 소모하여 JSON이 절반으로 잘려 나왔습니다.
EmbeddingGemma는 모든 라인에 대해 halfvec(768)을 작성합니다. 이 행들은 Tiger Data에 존재하며, pg_textsearch에서 가져온 BM25 인덱스 옆에 위치합니다. 앱은 새로운 라인이 들어올 때마다 두 검색을 모두 실행하고, 이를 상호 순위 융합(reciprocal rank fusion)으로 결합하여 사용하는데, k 값은 60이며 이는 Tiger가 문서화하는 하이브리드 패턴입니다. 이렇게 융합된 이웃 정보는 지시사항이 아닌 힌트로 프롬프트에 포함됩니다. 날짜가 적힌 청구서나 티켓이 과거의 소셜 답글보다 더 중요합니다.
결정표(decision table)는 일반적인 표입니다. 벡터 컬럼과 Timescale 컬럼스토어는 같은 관계(relation)에 속해서는 안 됩니다. 분 단위 기록은 별도의 append-only 하이퍼테이블인 effort_events로 관리되며, 결정별로 세분화되고, 차트가 읽는 연속 집계 값(minutes_saved_daily)을 포함하여 오늘 날짜의 행까지도 포함합니다.
pg_textsearch는 여전히 상위 버전에서 프리릴리스(prerelease) 상태입니다. 이곳은 개발용 데이터베이스(DEV database)이며, 검색어 절반(half of the search)이 이를 사용해야 하는 이유입니다. 인덱스가 단순히 문자열만으로 응답하지 않았습니다. 쿼리는 반드시 item_text <@> to_bm25query(text, index_name) 형태여야 합니다.
스택 선택은 사람들이 이미 배포한 것을 따릅니다. MindMirror는 개인적인 잡일 더미에 제가 원했던 분할과 같습니다: 텍스트가 다른 사람의 모델에 대한 요청이 아니도록 프론트엔드에 FastAPI를, 백엔드에 Ollama를 배치하는 방식입니다.
Open Innovation은 왜 중요할까요?
이 더미는 호스팅되는 채팅창에 붙여넣지 않을 목록의 종류입니다: 치과 의사, 청구서, 엄마, 다운로드 폴더의 난장판 같은 것들입니다. 오픈 웨이트(Open weights)가 사용하기에 충분히 저렴하게 만듭니다. Gemma는 이 기기에서 실행되고, EmbeddingGemma도 이 기기에서 실행되며, 정렬기는 라인을 모델 API로 전송하지 않습니다. 토큰당 비용이 없으므로 다음 더미를 위해 앱을 계속 실행하는 데 아무런 비용이 들지 않습니다. 또한 모델들도 교체 가능합니다. 정렬기와 임베더는 환경 변수입니다. 폐쇄형 API(closed API)였다면 호출하기는 빨랐겠지만, 실제로 중요한 일인 개인 목록을 비공개로 유지하는 능력은 더 떨어졌을 것입니다.
제 에이전트 세션
세션은 Grok과 함께 Cursor에서 기록되었습니다. DEV의 업로더에는 Cursor 도구 이름이 없으므로, 이 세션은 승인된 하네스 레이블 아래에 보관됩니다. 스크립트를 보면 첫 번째 답변에서 경로(Paths), 데이터베이스 URL, 토큰 등이 포함되어 있지 않다고 합니다.
Hacktoberfest Week 3 grok-4.7을 위한 Sloth Sort 구축
당신
Hacktoberfest 오픈 소스 AI 챌린지 3주차('느리고 꾸준하게')를 위해 웹 앱을 만드세요. 저는 로컬에 Python, Ollama, 그리고 Tiger Cloud를 가지고 있습니다. 프로젝트가 실제로 사용하는 파트너 카테고리를 목표로 하세요. 그런 다음 DEV 게시물과 정제된 에이전트 세션을 게시하고, HobbyProjects 아래에 레포지토리를 생성한 후 GitHub에 푸시하며, 앱의 GIF를 포함하세요.
에이전트
이 세션은 Cursor에서 Grok을 사용하여 실행되었습니다. DEV의 업로더는 Cursor 라벨이 없기 때문에, 세션에 표시되는 도구 이름은 플랫폼에서 요구하는 버킷만 사용합니다. 3주차 내용은 10월 25일까지 진행됩니다. 주제는 누구나 더 게으를 수 있게 해주는 오픈 웨이트(open-weight) AI입니다. 기계에는 이미 Ollama에 gemma4:e4b가 있었고, Tiger Cloud에는 Timescale, pgvector, pg_textsearch가 있었습니다. 이 프로젝트가 진입할 두 가지 트랙은 'Gemma의 최적 활용 사례'와 'Tiger Data의 최적 활용 사례'입니다.
▸ search_dev_to_semantic 검색 DEV에서 로컬 Ollama 앱 및 Timescale 이벤트 스토리지
Input
search DEV for local Ollama apps and Timescale event storage
Output
A FastAPI와 Ollama 컴패니언으로, 개인 텍스트를 클라우드 모델에 저장하지 않으며, Ollama 호출이 포트 11434로의 일반 HTTP임을 알려줍니다. 두 스레드 모두 주석이 없었습니다.
Sloth Sort는 무시무시한 더미(pile)의 최대 여덟 줄을 차지합니다. EmbeddingGemma는 각 줄에 대해 halfvec를 작성합니다. Tiger Data는 BM25와 pgvector로 유사한 과거 결정을 검색하고, 이를 상호 순위 융합(reciprocal rank fusion)과 결합합니다. Gemma 4 E4B는 작은 움직임 하나를 선택하여 나머지를 보류하거나 건너뜁니다. 각 줄은 또한 minutes를 반환하는 연속 집계(continuous aggregate)에 의해 통합되는 effort_events 하이퍼테이블 행이기도 합니다. 결정 테이블은 벡터 컬럼과 컬럼스토어가 혼합되지 않기 때문에 하이퍼테이블이 아닙니다.
Agent
첫 번째 라이브 정렬은 두 가지 로컬 방식에서 실패했습니다. BM25 연산자는 인덱스 이름과 함께 to_bm25query가 필요했습니다. Gemma 4는 또한 생각 추적(thinking trace)에 토큰 예산을 소모하여 잘린 JSON을 반환했습니다. think를 false로 설정하자 완전한 JSON 객체를 반환하게 되었습니다.
▸ browser 로컬 브라우저에서 샘플 더미를 불러와 정렬하기
Input
load the sample pile in the browser and sort it
Output
당신은
리포지토리, 정리된 세션, 그리고 기사를 게시합니다.
4/4 메시지
게으름의 보상(The Lazy Payoff)
저는 샘플 더미를 불러와 이 기계에서 정렬했습니다.
-
15.9초 (Gemma 4 E4B에서 사고(thinking) 기능을 끈 후 소요된 시간).
-
한 가지 행동: 가장 가까운 마감 기한이었던 목요일 기차표를 구매함, 10분 동안.
-
나중에 처리할 것들: 치과 이메일, 금요일에 납부해야 할 전기 요금 고지서, 그리고 일요일 점심 식사.
-
그 분류 작업에서 230분이 회수됨. 차트의 그날 막대는 연속 집계(continuous aggregate)로부터 읽은 그 숫자가 됩니다.
수상 부문 (Prize Categories)
- Gemma 활용 최우수 사례. Gemma 4 E4B가 더미를 결정합니다. EmbeddingGemma는 메모리 역할을 합니다. 둘 다 Ollama을 통해 로컬에서 실행됩니다.
- Tiger Data 활용 최우수 사례. 과거 결정 사항은 하이브리드 BM25 및 pgvector 검색으로 검색되며, 회수된 분(minutes)은 하이퍼테이블(hypertable)과 연속 집계(continuous aggregate)로 구성되어 있습니다.