BossHunter
스마트 구직 에이전트(소스 공개, PolyForm 비상업적 라이선스; 상업적 이용은 별도 서면 허가 필요)
조달핏 — 수주 영업의 나라장터 공고 탐색을 대신하는 서비스. 회사명 하나로 등록업종·공급물품·수주이력을 임베딩 매칭해 자격 필터 통과 공고 TOP 5 추천
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
회사명을 입력하면 등록업종·공급물품·수주 이력을 함께 분석해, 검토할 만한 나라장터(G2B) 입찰공고 TOP 5를 추천한다. 문제. 입찰 알리미는 키워드 알림이라 "우리가 들어갈 수 있는 공고"와 "검토할 가치가 있는 공고"를 구분하지 못한다. 접근. 회사를 벡터로 만들어 공고와 비교한다. 다만 임베딩은 후보 정렬용이고, 자격(면허·지역·마감) 하드 필터가 먼저다. 100점 매칭이어도 자격이 안 되면 못 들어가기 때문이다. 실데이터로 확인한 것. 초기 설계는 "과거 수주 이력"을 메인 시그널(α=0.7)로 잡았다. 실데이터에 돌려 보니 수주 이력이 매칭되는 회사가 1.1%에 그쳐 추천이 성립하지 않았다. "이 회사가 뭐 하는 회사인가"(등록업종·공급물품)를 메인으로 옮기고, 가중치를 회사 데이터 양에 따라 동적으로 정하는 쪽으로 피벗했다 (2026-05-25). 규모. 공고 10,990건 임베딩, 계약 32,580건, 회사 34,517개. 나라장터 OpenAPI 8종을 매일 GitHub Actions cron으로 누적한다. 상태. WIP MVP. 사내 수주 영업 도입 추진 중. 한국 공공조달(나라장터, G2B) 입찰공고 추천 사이트.README 전문 보기 ↗
회사명을 입력하면 등록업종·공급물품·수주 이력을 함께 분석해, 검토할 만한 나라장터(G2B) 입찰공고 20건을 추천한다 (비로그인은 상위 5건 공개).
문제. 입찰 알리미는 키워드 알림이라 "우리가 들어갈 수 있는 공고"와 "검토할 가치가 있는 공고"를 구분하지 못한다.
접근. 회사를 벡터로 만들어 공고와 비교한다. 다만 임베딩은 후보 정렬용이고, 자격(면허·지역·마감) 하드 필터가 먼저다. 100점 매칭이어도 자격이 안 되면 못 들어가기 때문이다.
실데이터로 확인한 것. 초기 설계는 "과거 수주 이력"을 메인 시그널(α=0.7)로 잡았다. 실데이터에 돌려 보니 수주 이력이 매칭되는 회사가 1.1%에 그쳐 추천이 성립하지 않았다. "이 회사가 뭐 하는 회사인가"(등록업종·공급물품)를 메인으로 옮기고, 가중치를 회사 데이터 양에 따라 동적으로 정하는 쪽으로 피벗했다 (2026-05-25).
규모 (2026-11-05). 공고 누적 41.8만 건(지금 입찰 가능 약 9,500건), 계약 67.6만 건, 회사 19.6만 개(벡터 91,585). 나라장터 OpenAPI 8종을 GitHub Actions(매일 05:00 + 매시)로 누적한다.
상태. jodalfit.co.kr 운영 중. 이메일·구글·네이버 로그인, 검토함, 저장 회사 주간 메일, 어드민. 임베딩은 KURE-v1 운영 중이고 Gemini embedding-001 로 전환하기 위한 백필이 진행 중이다(아래 6장).
한국 공공조달(나라장터, G2B) 입찰공고 추천 사이트.
컨셉:
회사명/벡터 미확보 시에는 자유 키워드 모드로 폴백 — 콜드스타트에도 즉시 추천.
경쟁사 대비 차별화:
| 일반 입찰 알리미 | jodalfit |
|---|---|
| 키워드 알림 | 등록업종/공급물품 + 수주 이력 통합 임베딩 매칭 |
| 점수 없음 | 매칭 점수 + 게이지 + 적합도 라벨 |
| 이유 없음 | LLM이 "왜 추천했는지" 자연어 설명 ⭐ |
| 단일 공고 페이지만 | 발주계획 → 사전규격 → 공고 → 낙찰 → 계약 라이프사이클 페이지 ⭐ |
| 자격 미확인 공고 다수 | 자격(면허/지역/마감) 하드 필터 |
초기 설계는 수주 메인(α=0.7)이었으나, 실데이터 검증 결과 수주 매칭 커버리지가 1.1%에 그쳐 추천 자체가 불가능했습니다. "이 회사가 뭐 하는 회사인가"가 메인 시그널이고, 과거에 뭘 따냈는가는 보조라는 사용자 직관 + 코덱스 재검토를 반영해 γ(업종)을 메인으로 옮기고 가중치를 동적으로 산출합니다.
회사 벡터 = 3가지 시그널의 동적 가중합
회사 벡터 = α · 수주벡터 + β · 관심벡터 + γ · 업종벡터 (α+β+γ = 1, 회사 데이터별 동적)
| 회사 상태 | 업종 γ | 수주 α | 관심 β | 메모 |
|---|---|---|---|---|
| 수주 0건 (콜드스타트) | 1.00 | 0.00 | 0.00 | 등록업종만으로 추천 |
| 수주 1~5건 (균형) | 0.65 | 0.30 | 0.05 | 업종 메인, 수주 보조 |
| 수주 6건+ (수주 풍부) | 0.50 | 0.45 | 0.05 | 업종/수주 비등 |
시그널 소스
| 시그널 | 소스 |
|---|---|
| 업종(γ) | company_industries 등록업종 + company_supply_products 공급물품 + corp_bsns_div_nm + mnfctr_div_nm 텍스트 (회사당 1회 임베딩) |
| 수주(α) | contracts → 따낸 공고들의 bid_notices.embedding 평균 |
| 관심(β) | 사전규격 의견 (v0.2.1 — 회사명 매핑 후 활성화) |
가용한 시그널만 정규화해서 가중합 → 콜드스타트도 즉시 추천 가능. 회사 식별/벡터가 없으면 키워드 모드(자유 텍스트 → 직접 임베딩)로 폴백.
추천 파이프라인:
회사명 입력
↓
[1] 회사 식별 (pg_trgm fuzzy + 사업자번호 매칭)
↓
[2] 하드 필터 ← 못 들어가는 공고 제거 (자격/지역/마감/예산)
↓
[3] pgvector 코사인 검색 ← 통과 공고 중 TOP 100
↓
[4] 휴리스틱 rerank ← 마감 임박 패널티, 지역 매칭 보너스 등
↓
[5] LLM 설명 생성 ← Claude Haiku 4.5, ThreadPoolExecutor(5) 병렬 호출 (~3초)
↓
20건 + 매칭 이유 반환
핵심 통찰:
조달 단계마다 별도 OpenAPI가 있고, jodalfit은 모든 단계를 누적합니다.
[발주계획] → [사전규격(+의견)] → [입찰공고] → [낙찰/개찰] → [계약]
선행지표 SW식별, 관심신호 추천 대상 참여신호 수주신호
| 단계 | API 서비스 | 핵심 가치 |
|---|---|---|
| 발주계획 | OrderPlanSttusService | "1개월 전" 알림 가능 |
| 사전규격 | HrcspSsstndrdInfoService | swBizObjYn SW 사업 자동 필터 |
| 사전규격 의견 | 동일 (getPublicPrcureThngOpinionInfo*) | 회사 관심 신호 (콜드스타트 해결) |
| 입찰공고 | PubDataOpnStdService/getDataSetOpnStdBidPblancInfo | 추천 대상 공고 풀 |
| 입찰공고 자격 | BidPublicInfoService (면허제한/참가지역) | 자격 하드 필터 |
| 낙찰/개찰 | ScsbidInfoService | 참가 업체 정보 = 회사 3번째 시그널 |
| 계약 | PubDataOpnStdService/getDataSetOpnStdCntrctInfo | 사업자번호 → 수주 이력 |
| 회사 마스터 | UsrInfoService02 | 등록업종, 공급물품, 부정당 제재 |
| 업종 lookup | IndstrytyBaseLawrgltInfoService | 자격요건 매핑 |
flowchart LR
U[회사명 입력] --> FE[Next.js 16<br/>SEO 회사·공고 페이지]
FE -->|POST /recommendations| BE[FastAPI]
BE --> DB[(Supabase Postgres<br/>pgvector HNSW · pg_trgm)]
BE -->|추천 이유| LLM[Claude Haiku 4.5]
subgraph J[GitHub Actions · 매일 KST 5시 + 매시]
I[ingest 잡들<br/>나라장터 OpenAPI 8종] --> E[embed 잡들<br/>KURE-v1 · Gemini 백필] --> CV[compute_company_vectors]
end
CV --> DB
추천 요청 경로: 회사 식별(pg_trgm) → 자격 하드 필터 → pgvector 코사인 TOP 100 → 가중치 score + 협업 시그널 + MMR 다양성 → LLM 설명(병렬).
여기까지가 README 앞부분입니다. 나머지는 원문에서 읽을 수 있습니다. README 전문 보기 ↗