Lead Enrich (리드 인리치)
Serper.dev Google Search를 사용하여 사람(이름 + 회사)을 조사합니다. 에이전트 내장 모델을 사용하여 추출합니다. 외부 LLM API가 필요하지 않습니다.
단독 실행 가능 — Serper 키만 있으면 됩니다. 크레딧을 절약하는 중복 제거(리드에 이미 LinkedIn/이메일이 있으면 Serper 건너뜀)와 세션 간 지속적 저장을 위해 Outreach Magic과 함께 사용할 수 있습니다.
크레딧 절약(OM 사용 시): outreachmagic을 먼저 확인합니다. 리드에 같은 회사의 LinkedIn + 이메일이 이미 있으면 Serper 크레딧이 전혀 소모되지 않습니다. 이메일 없는 LinkedIn은 Serper를 건너뜁니다 — trykitt의 email-finder를 사용하세요. 이메일만 있는 레코드는 여전히 LinkedIn 검색을 수행합니다(1–2 Serper 크레딧). 다른 회사의 이름 일치는
ambiguous를 반환하여 API가 낭비되지 않도록 합니다.
설정
단독 실행 (OM 없음)
Serper 키만 있으면 됩니다. serper-search를 직접 실행하세요. 결과는 JSON으로 출력됩니다.
| 키 | 용도 |
|---|---|
SERPER_API_KEY | serper.dev — Google Search API |
python3 scripts/enrich.py serper-search --query '"Acme Corp" official website'
python3 scripts/enrich.py serper-search --query 'site:linkedin.com/in Jane Doe Acme Corp'
# → 결과를 모델에 파이프하여 추출하거나 serper-format을 사용하세요
SERPER_API_KEY를 환경 변수에 설정하거나 ~/.hermes/skills/lead-enrich/config.json에 설정하세요.
Outreach Magic 사용 시 (중복 제거 + 저장)
사전 중복 제거(OM에 이미 있는 리드 건너뜀)를 추가하고 구조화된 인리치 결과를 로컬 SQLite 파이프라인에 저장합니다. pipeline.py login이 있는 outreachmagic 스킬이 필요합니다.
| 키 | 용도 |
|---|---|
| 위 모든 단독 실행 키 + | |
OUTREACHMAGIC_AGENT_KEY | pipeline.py login을 통한 OM 로그인 |
python3 scripts/enrich.py check "Jane Doe" "Acme Corp" # 0 크레딧
python3 scripts/enrich.py batch-check --workspace W input.json # 일괄 중복 제거
Outreach Magic 포털 → 설정 → API 키에 Serper 키를 저장한 후 pipeline.py sync-secrets를 실행하세요. enrich.py config로 확인하세요(serper_api_key_source가 agent_secrets여야 함).
3. 이메일 찾기 (email-finder 스킬)
이메일 찾기는 lead-enrich v2+에 포함되지 않습니다. 플랫폼 설치 가이드를 사용하여 outreachmagic과 함께 email-finder를 설치하세요. 또는 npx skills add outreachmagic/email-finder를 사용하여 단독 설치할 수 있습니다.
Serper 인리치가 company_domain을 저장한 후 다음을 실행하세요:
python3 ~/.hermes/skills/email-finder/scripts/email_finder.py find --name "Jane Doe" \
--domain acme.com --linkedin "https://linkedin.com/in/janedoe" --save
references/email-finder.md 및 email-finder 스킬 문서를 참조하세요.
워크스페이스 롤업(Serper 크레딧 없음): 리드 저장 후, outreachmagic workspace summary --workspace <slug> --json을 사용하여 발신자별 태그 개수와 LinkedIn 연결 수락 현황을 확인하세요. 대규모 워크스페이스(2,000개 이상 리드)의 경우 더 빠른 태그 개수를 위해 --tags-only를 추가하세요. 로컬 DB 전용 — 선택적 가져오기입니다.
일반적인 워크플로우
| 사용자 요청 | 수행할 작업 |
|---|---|
| "이 사람을 조사해 줘" | Serper 검색 → import-profiles를 통해 저장 |
| "내 CSV를 인리치해 줘" | batch-check / 가져오기 → 누락된 필드 인리치 → OM에 저장 |
| "그 사람의 이메일도 찾아 줘" | 인리치 후 email-finder로 전달 |
Sales Nav / Vayne CSV: outreachmagic import-profiles --file … 사용(열 자동 감지).
CSV / 어워드 목록 워크플로우 (10명 이상에게 권장)
outreachmagic/imports/awards.csv와 같은 경로는 스킬 설치 폴더가 아닌 워크스페이스 디렉토리(에이전트가 명령을 실행하는 곳)를 기준으로 합니다.
# 0 크레딧 — 전체 파일을 먼저 중복 제거합니다 (완료된 행에 serper_attempted 자동 스탬프)
python3 scripts/enrich.py batch-check --workspace your_workspace outreachmagic/imports/awards.csv
# 이미 serper_attempted 태그가 있는 리드를 건너뛰며 중복 제거 재실행
python3 scripts/enrich.py batch-check --workspace your_workspace --skip-tagged outreachmagic/imports/awards.csv
# LinkedIn/도메인이 필요한 행만 Serper 검색 (team_award, exists_linkedin_*, skipped_serper_attempted 제외)
# 조사 후 — 제목/산업만 업데이트 (0 Serper 크레딧)
python3 scripts/enrich.py backfill --fields title,industry --workspace your_workspace outreachmagic/imports/patch.csv
batch-check는 .json 또는 .csv를 허용합니다. backfill은 행당 email 또는 linkedin이 필요합니다. companion_common을 통해 청크 단위 import-profiles를 사용합니다(청크당 200행, 청크당 최대 300초; 빈 필드를 채움; 덮어쓰려면 --overwrite 추가).
사용 시점
- 사용자가 "이 사람을 조사해 줘" / "Acme 회사의 Jane Doe를 찾아 봐"라고 말할 때
- 사용자가 아웃리치 전에 잠재 고객 목록을 인리치하려고 할 때
- 사용자가 조사 전에 "이 리드가 이미 있나요?"라고 물을 때
- 사용자가 대량 인리치를 위해 이름과 회사가 포함된 CSV/JSON을 제공할 때
- 사용자가 Serper, 리드 인리치 또는 인물 조사를 언급할 때
에이전트 행동 규칙 (중요)
- 먼저 중복 제거(OM 사용 시). Serper API 호출 전에
enrich.py check를 실행하세요. 리드에 같은 회사의 LinkedIn + 이메일이 있으면 Serper를 완전히 건너뜁니다. LinkedIn은 있지만 이메일이 없으면 Serper를 건너뛰고 사용자가 이메일 주소를 원할 경우 email-finder를 제공하세요. outreachmagic에서 이미 완료된 리드에 Serper 크레딧을 절대 소비하지 마세요. 단독 실행: 체크를 건너뜁니다 —serper-search를 직접 실행하세요. - Serper만 사용.
enrich.py serper-search --query "..."를 선호하세요(stdlib HTTP, config/env의 키). 또는$SERPER_API_KEY와 함께curl을 사용하세요 — 키를 채팅 로그에 절대 포함시키지 마세요. Google이나 LinkedIn을 직접 스크래핑하지 마세요. - 내장 모델만 사용. 당신(에이전트)은 Serper 결과에서 JSON을 추출합니다. 외부 LLM API는 사용하지 마세요(Gemini, OpenAI 없음) — 당신의 자체 추론이 추출 엔진입니다.
- 저장하기 전에 조사를 완료하세요. 전체 검색 단계를 먼저 실행한 다음 한 번에 저장하세요.
- Outreach Magic을 통해 저장(OM 사용 시). LinkedIn이 있는 리드에는
import-profiles를 사용하세요. 저장 시 항상 태그에 **serper_attempted**를 추가하세요(map-to-om출력에 자동 포함). LinkedIn이 없지만 알려진lead_id가 있는 리드의 경우,stamp-attempted또는id+ 태그가 있는import-profiles를 통해 태그를 스탬프하세요 — 메모에만 의존하지 마세요. 읽기 전용 중복 제거 확인에는pipeline.py query또는enrich.py check를 사용하세요 — 절대 직접INSERT/UPDATE하지 마세요. 같은 사람에 대해 두 저장 경로를 모두 실행하지 마세요. 단독 실행: JSON 출력을 파일에 저장하세요 — OM이 필요하지 않습니다. - 인리치 후 태그 지정(OM 사용 시). Serper를 거친 모든 리드는 저장 시
serper_attempted를 받아야 합니다. 향후 실행 시 재처리를 방지합니다. - Serper 전 태그 확인(OM 사용 시). Serper 크레딧을 소비하기 전에
serper_attempted가 있는지 확인하세요(enrich.py check --skip-tagged또는 체크 출력의skip_reason사용). 태그가 있고 LinkedIn이 여전히 비어 있으면 사용자가 명시적으로 재시도를 원하지 않는 한(예: 30일 이상 지난 경우) 건너뜁니다. - 투명성. 어떤 Serper 쿼리가 실행되었는지, 신뢰도, 저장된 내용을 보여주세요. 사용자는 자신의 크레딧이 정확히 어디에 사용되었는지 볼 수 있어야 합니다.
- 현명하게 배치 처리. 실행당 최대 50명으로 제한하세요. CSV/어워드 목록의 경우 Serper 전에 전체 파일에 대해
batch-check를 한 번 실행하세요(JSON 또는 CSV). LinkedIn/도메인이 필요한 상태에 대해서만 Serper를 처리하세요.team_award,exists_linkedin_email,skipped_serper_attempted행은 건너뜁니다. - 이메일 찾기 — email-finder 사용. 인리치가
company_domain을 저장한 후 email-finder(email_finder.py find --save)로 전달하세요.references/email-finder.md를 참조하세요. 이 스킬에서 이메일을 조작하거나 패턴으로 추측하지 마세요.
빠른 시작
# 한 사람 (가장 일반적)
python3 scripts/enrich.py check "Jane Doe" "Acme Corp"
# → "not_found"이면 아래 Serper 검색 팩을 진행하세요
# 워크스페이스 사용 (리드를 파이프라인 워크스페이스와 연결)
python3 scripts/enrich.py check --workspace your_workspace "Jane Doe" "Acme Corp"
# JSON 또는 CSV에서 일괄 처리 (목록에 대해 Serper 전에 실행)
python3 scripts/enrich.py batch-check --workspace your_workspace outreachmagic/imports/people.json
python3 scripts/enrich.py batch-check --workspace your_workspace --skip-tagged outreachmagic/imports/awards.csv
# LinkedIn 조회 실패 후 serper_attempted 스탬프 (lead_id를 알고 있을 때)
python3 scripts/enrich.py stamp-attempted --workspace your_workspace --lead-ids 42,43 \
--notes "Serper를 통해 LinkedIn을 찾을 수 없음"
# 기존 리드의 제목/산업 백필 (linkedin 또는 email 필요)
python3 scripts/enrich.py backfill --fields title,industry outreachmagic/imports/patch.csv
# GitHub 릴리스에서 스킬 안전하게 업데이트 (체크섬 확인)
python3 scripts/enrich.py update --check
python3 scripts/enrich.py update
update는 파일을 교체하기 전에 update-manifest.json의 SHA256 체크섬을 확인합니다. 체크섬이 없거나 일치하지 않으면 업데이트가 중단됩니다.
핵심 워크플로우
1단계 — 중복 제거 확인 (0 크레딧)
각 사람에 대해 다음을 실행하세요:
# 워크스페이스 없음 (조직 전체 조회)
python3 scripts/enrich.py check "Jane Doe" "Acme Corp"
# 워크스페이스 사용 (파이프라인 워크스페이스로 범위 지정)
python3 scripts/enrich.py check --workspace your_workspace "Jane Doe" "Acme Corp"
사람별 출력:
| 상태 | 의미 | 조치 |
|---|---|---|
exists_linkedin_email | 같은 회사, LinkedIn + 이메일 | Serper 및 이메일 API 건너뜀 |
exists_linkedin_no_email | 같은 회사, LinkedIn, 이메일 없음 | Serper 건너뜀 → 사용자가 이메일을 원하면 email-finder |
exists_no_linkedin_email | 같은 회사, 이메일, LinkedIn 없음 | LinkedIn Serper 쿼리만 실행 |
exists_no_linkedin | 같은 회사, 둘 다 없음 | LinkedIn Serper 쿼리만 실행 |
skipped_serper_attempted | serper_attempted 태그 있음, LinkedIn 없음 | Serper 건너뜀 — 이미 시도함 |
ambiguous | 이름 일치, 회사 불일치 | 전체 Serper 팩 실행 — 건너뛰지 않음 |
not_found | 일치 항목 없음 | 전체 Serper 검색 팩 실행 |
team_award | 팀/그룹 행 (개인 아님) | Serper 건너뜀 — team_award 태그, 연락처 메모 추가 |
dedup_disabled | config에서 dedup_before_search: false | 요청된 대로 Serper 실행 |
체크 출력에는 tags와 선택적 skip_reason(has_linkedin 또는 skipped_serper_attempted)이 포함됩니다. batch-lead-lookup을 사용합니다(로컬, Serper 크레딧 0).
2단계 — Serper 검색 팩
필요한 사람에 대해서만 실행하세요. 결과 품질에 따라 사람당 2–4회 검색:
Serper 크레딧 예산 추정기
- 사람당 최소:
0Serper 크레딧(exists_linkedin_email). - 일반적인 경로:
2크레딧(2a엄격한 회사 +2cLinkedIn 프로필). - 사람당 최대: 모든 대체 경로가 필요할 때
4크레딧(2a+2b+2c+2e). - 배치 공식:
min=0,max=4*N여기서N은 실행의 사람 수입니다. - 배치 상한 예시:
N=50인 경우 최대200크레딧(최악의 경우).
2a. 회사 찾기 — 엄격 (항상)
선호 (쉘 기록에 키가 표시되지 않음):
python3 scripts/enrich.py serper-search --query '"Acme Corp" official website' --label company_discovery_strict
또는 더 간단한 쿼리로 재시도:
python3 scripts/enrich.py serper-search --query 'Acme Corp website' --label company_discovery_broad
2b. 회사 찾기 — 광범위 (조건부)
2a가 http:// 또는 https:// 링크가 있는 유기적 결과를 반환하지 않는 경우에만 실행:
python3 scripts/enrich.py serper-search --query 'Acme Corp official website' --label company_discovery_broad
(동일 템플릿, 회사 이름 따옴표 없음)
2c. LinkedIn 프로필 (항상)
쿼리 구성 (회사 이름 따옴표 없음 — 스니펫에서 다양한 고용주 이름 변형과 일치):
site:linkedin.com/in {이름 성} {직무 최대 5단어} {회사명}
예시:
python3 scripts/enrich.py serper-search \
--query 'site:linkedin.com/in Jane Doe VP Marketing Acme Corp' \
--label linkedin_profile
3단계 — 모델 추출
형식화된 Serper 결과를 자신(에이전트 모델)에게 다음 시스템 지시문과 함께 전달하세요:
당신은 연구 조수입니다. 사용자 메시지에는 레이블이 지정된 섹션의 Serper.dev Google 검색 결과가 포함되어 있습니다. 실시간 웹 검색 기능이 없습니다 — 붙여넣은 블록만 사용하세요.
과제: 한 회사의 특정 한 사람에 대해 다음을 추출:
- company_domain: 등록 가능한 호스트 이름만 (경로, www 없음), 또는 빈 문자열
- company_website: 지원되는 경우 전체 https:// 홈페이지 URL, 또는 빈 문자열
- linkedin_url: 이 회사의 해당 사람에 대한 https://linkedin.com/in/…, 또는 빈 문자열
- confidence: high | medium | low
- note: 모호성 또는 간격에 대한 선택적 설명
규칙:
- 비어 있지 않은 모든 URL은 Serper 블록에 나타나야 함 (사소한 쿼리 문자열 정규화는 허용)
- LinkedIn의 이름은 입력과 다를 수 있음 (별명 vs 법적 이름) — 동일한 사람 + 고용주 기준으로 일치
- `linkedin_url`을 수락하기 전에 일치 품질 확인:
- `Full name: {full_name}`에서 이름 + 성 토큰 추출 (구두점 무시)
- 선택된 `/in/` 결과는 결과 `title` 또는 `snippet`에 *두* 토큰이 모두 있어야 함
- 토큰 요구 사항을 충족하는 `/in/` 결과가 없으면 `linkedin_url`을 빈 문자열로 반환하고 `confidence`를 `low`로 설정
- 회사 공개 사이트는 입력과 다른 배너 이름을 사용할 수 있음 — 공식 증거 선호
- `company_domain` 확인 시:
- `knowledgeGraph.website`가 있으면 선호
- 일반적인 집계기/레지스트리 거부 (예: `naceweb.org`, `usnews.com`, `wikipedia.org`, `niche.com`, `facebook.com`, `instagram.com`, `twitter.com`)
- `company_name`이 누락되었거나 사람 이름과 매우 유사하면 빈 문자열 반환
- 절대 URL이나 슬러그를 조작하지 않음
단일 JSON 객체로만 응답 (마크다운 펜스 없음):
{"company_domain":"","company_website":"","linkedin_url":"","confidence":"medium","note":""}
이 사용자 메시지 템플릿을 사용하세요:
### 대상 인물
전체 이름: {full_name}
명시된 직무/제목: {stated_role}
회사 (제공된 대로): {company_name}
### 검색 결과
{formatted_serper_sections}
### 과제
시스템 지시문에 설명된 JSON 객체를 반환하세요.
그런 다음 자신의 응답을 구문 분석하세요: 마크다운 펜스를 제거하고 JSON 객체를 추출하세요.
LinkedIn 수확 대체: 추출 후 linkedin_url이 비어 있으면 원시 Serper 유기적 결과에서 제목에 이름과 성 토큰이 모두 포함된 /in/ URL을 스캔하세요. 제목이 부분적으로 일치하는 경우(예: "Jane Smith" 대 "Jane Doe-Smith")에도 토큰이 둘 다 있으면 일치로 간주하세요. 첫 번째 유효한 결과를 linkedin_url로 선택하고 confidence를 medium으로 설정하고 note에 "수확된"이라고 표시하세요. 일치하는 항목이 없으면 linkedin_url을 빈 문자열로 유지하세요.
저장
OM 사용 시: 구조화된 리드 저장을 위해 import-profiles --phone을 선호하세요. import-profiles는 map-to-om JSON을 읽고, 새 리드를 생성하거나 기존 리드를 업데이트하며 지정된 워크스페이스에 연결합니다. python3 scripts/enrich.py import-profiles --input enriched_leads.json --workspace your_workspace --phone을 실행하세요. --phone 플래그는 전화번호가 제공된 경우 가져오도록 합니다. 태그의 serper_attempted가 자동 포함됩니다.
저장 형식 (맵-투-OM 입력):
[
{
"name": "Jane Doe",
"company_name": "Acme Corp",
"company_domain": "acme.com",
"linkedin": "https://linkedin.com/in/janedoe",
"email": "[email protected]" (선택 사항 — email-finder에서),
"title": "VP Marketing" (선택 사항),
"phone": "+1234567890" (선택 사항),
"tags": ["serper_attempted", "other-tag"] // serper_attempted 자동 포함
}
]
단독 실행: serper-search의 JSON 출력을 output.json과 같은 파일에 저장하고 위치를 사용자에게 알리세요.
5단계 — 이메일 찾기 (선택 사항, email-finder 스킬 필요)
인리치가 company_domain을 저장한 후 사용자가 이메일 주소를 원하면 email-finder (~/.hermes/skills/email-finder/scripts/email_finder.py find --name ... --domain ... --linkedin ... --save)로 전달하세요. 이메일을 조작하거나 패턴으로 추측하지 마세요.
문제 해결
"Serper API 키를 찾을 수 없음" — SERPER_API_KEY가 환경 변수에 설정되어 있거나 ~/.hermes/skills/lead-enrich/config.json에 있는지 확인하세요. OM과 함께 사용하는 경우 pipeline.py sync-secrets를 실행하세요.
"체크섬 불일치" — 업데이트 중에 파일이 변조되었습니다. GitHub에서 수동으로 다시 설치하거나 enrich.py update를 다시 실행하세요.
"리드를 찾을 수 없음" — 워크스페이스가 올바른지 확인하거나 워크스페이스를 생략하여 조직 전체 조회를 수행하세요.
전체 기능 목록
| 명령 | 설명 | 크레딧 비용 |
|---|---|---|
check | 중복 제거 확인 (로컬 조회) | 0 |
batch-check | CSV/JSON 파일의 일괄 중복 제거 | 0 |
serper-search | Google Search API 쿼리 | 1/serper-search 호출 |
backfill | 기존 리드의 제목/산업 업데이트 (import-profiles 사용) | 0 |
stamp-attempted | lead_id로 알려진 리드에 serper_attempted 스탬프 | 0 |
import-profiles | 구조화된 리드를 OM에 저장 | 0 |
config | 현재 설정 표시 | 0 |
update | GitHub에서 체크섬 확인 업데이트 | 0 |