Lead Enrich
Pesquise uma pessoa (nome + empresa) usando a Serper.dev (Pesquisa Google). Usa o modelo embutido do agente para extração. Nenhuma API LLM externa necessária.
Funciona de forma independente — apenas uma chave Serper. Combina com Outreach Magic para deduplicação economizando créditos (evita Serper quando leads já têm LinkedIn/email) e armazenamento persistente entre sessões.
Economia de crédito (com OM): verifica o outreachmagic primeiro. Se o lead já tiver LinkedIn + email na mesma empresa, zero créditos Serper gastos. LinkedIn sem email pula Serper — use email-finder para trykitt. Registros apenas com email ainda recebem pesquisas de LinkedIn (1–2 créditos Serper). Correspondências de nome em empresas diferentes retornam
ambiguouspara que APIs não sejam desperdiçadas.
Configuração
Autônomo (sem OM)
Apenas uma chave Serper. Execute serper-search diretamente. Os resultados são impressos como JSON.
| Chave | Para |
|---|---|
SERPER_API_KEY | serper.dev — API de Pesquisa Google |
python3 scripts/enrich.py serper-search --query '"Acme Corp" site oficial'
python3 scripts/enrich.py serper-search --query 'site:linkedin.com/in Jane Doe Acme Corp'
# → direcione os resultados para seu modelo extrair, ou use serper-format
Defina SERPER_API_KEY em seu ambiente ou via ~/.hermes/skills/lead-enrich/config.json.
Com Outreach Magic (dedup + salvar)
Adiciona deduplicação pré-voo (pular leads já no OM) e salva o enriquecimento estruturado
em seu pipeline SQLite local. Requer o skill outreachmagic
com pipeline.py login.
| Chave | Para |
|---|---|
| Todas as chaves autônomas acima + | |
OUTREACHMAGIC_AGENT_KEY | Login OM via pipeline.py login |
python3 scripts/enrich.py check "Jane Doe" "Acme Corp" # 0 créditos
python3 scripts/enrich.py batch-check --workspace W input.json # dedup em lote
Salve sua chave Serper no Portal Outreach Magic → Configurações → Chaves de API, então execute
pipeline.py sync-secrets. Verifique com enrich.py config (serper_api_key_source
deve ser agent_secrets).
3. Localização de email (skill email-finder)
A localização de email não está no lead-enrich v2+. Instale email-finder com o outreachmagic usando o guia de instalação da plataforma. Ou instale de forma autônoma via npx skills add outreachmagic/email-finder.
Após o enriquecimento Serper salvar company_domain, execute:
python3 ~/.hermes/skills/email-finder/scripts/email_finder.py find --name "Jane Doe" \
--domain acme.com --linkedin "https://linkedin.com/in/janedoe" --save
Veja references/email-finder.md e a documentação do skill email-finder.
Resumos de workspace (sem créditos Serper): após salvar leads, use o outreachmagic
workspace summary --workspace <slug> --json para contagens de tags e
conexões do LinkedIn aceitas por remetente. Em workspaces grandes (>2.000 leads), adicione
--tags-only para contagens de tags mais rápidas. Apenas DB local — pull opcional.
Fluxos de trabalho comuns
| Usuário diz | Você faz |
|---|---|
| "Pesquise esta pessoa" | Pesquisa Serper → salva via import-profiles |
| "Enriqueça meu CSV" | batch-check / import → enriquece campos ausentes → salva no OM |
| "Encontre também o email dele" | Após o enriquecimento, passe para email-finder |
CSVs do Sales Nav / Vayne: use o outreachmagic import-profiles --file … (detecta colunas automaticamente).
Fluxo de trabalho CSV / lista de premiações (preferido para 10+ pessoas)
Caminhos como outreachmagic/imports/awards.csv são relativos ao seu diretório de workspace (onde o agente executa o comando), não à pasta de instalação do skill.
# 0 créditos — deduplica o arquivo inteiro primeiro (carimba automaticamente serper_attempted em linhas completas)
python3 scripts/enrich.py batch-check --workspace your_workspace outreachmagic/imports/awards.csv
# Re-executa dedup pulando leads já marcados com serper_attempted
python3 scripts/enrich.py batch-check --workspace your_workspace --skip-tagged outreachmagic/imports/awards.csv
# Serper apenas para linhas que precisam de LinkedIn/domínio (pula team_award, exists_linkedin_*, skipped_serper_attempted)
# Após a pesquisa — corrige título/indústria apenas (0 créditos Serper)
python3 scripts/enrich.py backfill --fields title,industry --workspace your_workspace outreachmagic/imports/patch.csv
batch-check aceita .json ou .csv. backfill requer email ou linkedin por linha; usa import-profiles em blocos via companion_common (200 linhas/bloco, até 300s/bloco; preenche campos vazios; adicione --overwrite para substituir).
Quando usar
- Usuário diz "pesquise esta pessoa" / "procure Jane Doe da Acme"
- Usuário quer enriquecer uma lista de prospects antes do contato
- Usuário pergunta "já temos este lead?" antes de pesquisar
- Usuário fornece um CSV/JSON de nomes e empresas para enriquecer em lote
- Usuário menciona Serper, enriquecimento de lead ou pesquisa de pessoas
Regras de Comportamento do Agente (Importante)
- Deduplicar primeiro (com OM). Antes de qualquer chamada à API Serper, execute
enrich.py check. Se o lead tiver LinkedIn + email na mesma empresa, pule o Serper completamente. Se o LinkedIn existir mas sem email, pule o Serper e ofereça email-finder quando o usuário quiser um endereço. Nunca gaste créditos Serper em leads já completos no outreachmagic. Autônomo: pule a verificação — executeserper-searchdiretamente. - Apenas Serper. Prefira
enrich.py serper-search --query "..."(stdlib HTTP, chave do config/env). Ou usecurlcom$SERPER_API_KEY— nunca incorpore a chave em logs de chat. Nunca raspe o Google ou LinkedIn diretamente. - Apenas modelo embutido. Você (o agente) extrai JSON dos resultados do Serper. Nenhuma API LLM externa (sem Gemini, sem OpenAI) — seu próprio raciocínio é o motor de extração.
- Pesquisa completa antes de salvar. Execute toda a escada de pesquisa primeiro, depois salve de uma vez.
- Salvar via outreachmagic (com OM). Use
import-profilespara leads com LinkedIn. Sempre anexeserper_attemptedàs tags ao salvar (incluído automaticamente na saída demap-to-om). Para leads sem LinkedIn mas comlead_idconhecido, carimbe a tag viastamp-attemptedouimport-profilescomid+ tags — não confie apenas em notas. Para verificações de dedup somente leitura, usepipeline.py queryouenrich.py check— nuncaINSERT/UPDATEbrutos. Nunca execute ambos os caminhos de salvamento para a mesma pessoa. Autônomo: salve a saída JSON em um arquivo — sem necessidade de OM. - Marcar após enriquecimento (com OM). Todo lead que passar pelo Serper deve receber
serper_attemptedao salvar. Evita reprocessamento em execuções futuras. - Verificar tag antes do Serper (com OM). Antes de gastar créditos Serper, verifique
serper_attempted(viaenrich.py check --skip-taggedouskip_reasonna saída de verificação). Se presente e o LinkedIn ainda estiver vazio, pule a menos que o usuário queira explicitamente uma nova tentativa (por exemplo, desatualizado >30 dias). - Transparência. Mostre quais consultas Serper foram executadas, a confiança e o que foi salvo. O usuário deve ver exatamente para onde seus créditos foram.
- Lote com sabedoria. Limite a 50 pessoas por execução. Para listas CSV/premiações execute
batch-checkuma vez no arquivo inteiro (JSON ou CSV) antes de qualquer Serper. Processe o Serper apenas para status que precisam de LinkedIn/domínio. Pule linhasteam_award,exists_linkedin_emaileskipped_serper_attempted. - Localização de email — use email-finder. Após o enriquecimento salvar
company_domain, passe para email-finder (email_finder.py find --save). Vejareferences/email-finder.md. Nunca invente ou adivinhe emails neste skill.
Início Rápido
# Pessoa única (mais comum)
python3 scripts/enrich.py check "Jane Doe" "Acme Corp"
# → se "not_found", prossiga com o pacote de pesquisa Serper abaixo
# Com workspace (associa lead ao seu pipeline de workspace)
python3 scripts/enrich.py check --workspace your_workspace "Jane Doe" "Acme Corp"
# Lote de JSON ou CSV (execute isso antes do Serper em listas)
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
# Carimbar serper_attempted após falha na pesquisa do LinkedIn (quando lead_id é conhecido)
python3 scripts/enrich.py stamp-attempted --workspace your_workspace --lead-ids 42,43 \
--notes "Nenhum LinkedIn encontrado via Serper"
# Preencher título/indústria em leads existentes (linkedin ou email obrigatório)
python3 scripts/enrich.py backfill --fields title,industry outreachmagic/imports/patch.csv
# Atualizar skill com segurança a partir do lançamento do GitHub (verificado por checksum)
python3 scripts/enrich.py update --check
python3 scripts/enrich.py update
update verifica checksums SHA256 de update-manifest.json antes de substituir
arquivos. Se os checksums estiverem ausentes ou não coincidirem, a atualização é abortada.
Fluxo de Trabalho Principal
Fase 1 — Verificação de Dedup (0 créditos)
Para cada pessoa, execute:
# Sem workspace (consulta em toda a organização)
python3 scripts/enrich.py check "Jane Doe" "Acme Corp"
# Com workspace (escopo para seu pipeline de workspace)
python3 scripts/enrich.py check --workspace your_workspace "Jane Doe" "Acme Corp"
Saída por pessoa:
| Status | Significado | Ação |
|---|---|---|
exists_linkedin_email | Mesma empresa, LinkedIn + email | Pule Serper e APIs de email |
exists_linkedin_no_email | Mesma empresa, LinkedIn, sem email | Pule Serper → email-finder se usuário quiser email |
exists_no_linkedin_email | Mesma empresa, email, sem LinkedIn | Apenas consultas Serper de LinkedIn |
exists_no_linkedin | Mesma empresa, nenhum | Apenas consultas Serper de LinkedIn |
skipped_serper_attempted | Tem tag serper_attempted, sem LinkedIn | Pule Serper — já tentado |
ambiguous | Nome corresponde, empresa não corresponde | Execute pacote Serper completo — não pule |
not_found | Nenhuma correspondência | Execute pacote de pesquisa Serper completo |
team_award | Linha de equipe/grupo (sem indivíduo) | Pule Serper — marque team_award, adicione nota de contato |
dedup_disabled | dedup_before_search: false no config | Execute Serper conforme solicitado |
A saída de verificação inclui tags e skip_reason opcional (has_linkedin ou
skipped_serper_attempted). Usa batch-lead-lookup (local, zero créditos Serper).
Fase 2 — Pacote de Pesquisa Serper
Execute apenas para pessoas que precisam dele. 2 a 4 pesquisas por pessoa dependendo da qualidade do resultado:
Estimador de Orçamento de Créditos Serper
- Por pessoa mínimo:
0créditos Serper (exists_linkedin_email). - Caminho comum:
2créditos (2aempresa estrita +2cperfil LinkedIn). - Por pessoa máximo absoluto:
4créditos quando todos os fallbacks são necessários (2a+2b+2c+2e). - Fórmula de lote:
min=0,max=4*NondeNé o número de pessoas na execução. - Exemplo de limite de lote: com
N=50, máximo absoluto é200créditos (pior caso).
2a. Descoberta de empresa — estrita (sempre)
Preferido (sem chave no histórico do shell):
python3 scripts/enrich.py serper-search --query '"Acme Corp" site oficial' --label company_discovery_strict
Ou tente novamente com uma consulta mais simples:
python3 scripts/enrich.py serper-search --query 'Acme Corp website' --label company_discovery_broad
2b. Descoberta de empresa — ampla (condicional)
Execute apenas se 2a não retornar resultados orgânicos com um link http:// ou https://:
python3 scripts/enrich.py serper-search --query 'Acme Corp site oficial' --label company_discovery_broad
(Mesmo modelo, nome da empresa sem aspas.)
2c. Perfil LinkedIn (sempre)
Construa a consulta (empresa sem aspas — corresponde a nomes variantes de empregador em snippets):
site:linkedin.com/in {Primeiro Último} {até 5 palavras do cargo} {Nome da Empresa}
Exemplo:
python3 scripts/enrich.py serper-search \
--query 'site:linkedin.com/in Jane Doe VP Marketing Acme Corp' \
--label linkedin_profile
Fase 3 — Extração do Modelo
Passe os resultados formatados do Serper para si mesmo (o modelo agente) com esta instrução de sistema:
Você é um assistente de pesquisa. A mensagem do usuário contém resultados de pesquisa do Google Serper.dev
em seções rotuladas. Você NÃO tem pesquisa web ao vivo — use apenas os blocos colados.
Tarefa: para UMA pessoa específica em UMA empresa, extraia:
- company_domain: apenas o hostname registrável (sem caminho, sem www), ou string vazia
- company_website: URL completa https:// da página inicial se suportada, ou string vazia
- linkedin_url: https://linkedin.com/in/… para a pessoa nomeada nesta empresa, ou string vazia
- confidence: alta | média | baixa
- note: explicação opcional de ambiguidade ou lacunas
Regras:
- Toda URL não vazia deve aparecer nos blocos Serper (normalização menor de query string é aceitável)
- O nome no LinkedIn pode diferir da entrada (apelido vs nome legal) — corresponda na mesma pessoa + empregador
- Antes de aceitar `linkedin_url`, verifique a qualidade da correspondência:
- Extraia tokens de primeiro e último nome de `Nome completo: {full_name}` (ignore pontuação)
- O resultado `/in/` escolhido deve ter *ambos* os tokens presentes no `title` ou `snippet` do resultado
- Se nenhum resultado `/in/` atender ao requisito de token, retorne `linkedin_url` como string vazia e defina `confidence` como `baixa`
- O site público da empresa pode usar um nome de banner diferente da entrada — prefira evidências oficiais
- Ao resolver `company_domain`:
- Prefira `knowledgeGraph.website` quando presente
- Rejeite agregadores/registros comuns (exemplos: `naceweb.org`, `usnews.com`, `wikipedia.org`, `niche.com`, `facebook.com`, `instagram.com`, `twitter.com`)
- Se `company_name` parecer ausente ou corresponder de perto ao nome da pessoa, retorne string vazia
- Nunca invente URLs ou slugs
Responda APENAS com um único objeto JSON (sem cercas markdown):
{"company_domain":"","company_website":"","linkedin_url":"","confidence":"média","note":""}
Use este modelo de mensagem do usuário:
### Pessoa alvo
Nome completo: {full_name}
Cargo/função informado: {stated_role}
Empresa (conforme fornecida): {company_name}
### Resultados da pesquisa
{formatted_serper_sections}
### Tarefa
Retorne o objeto JSON descrito na instrução de sistema.
Em seguida, analise sua própria resposta: remova cercas markdown, extraia o objeto JSON.
Fallback de colheita do LinkedIn: se linkedin_url estiver vazio após a extração, escaneie
os resultados orgânicos brutos do Serper em busca de URLs /in/ onde o título contenha
os tokens de primeiro e último nome. Prefira correspondências
…
[truncado para tradução — o conteúdo original foi cortado; mantive a tradução fiel até onde o original foi fornecido.]