Skill Extractor

Índice


O que é

O processor-skill-extractor é o terceiro serviço da pipeline de processamento. Ele recebe o histórico de chat estruturado produzido pelo Prompt Generator, envia para o modelo Gemma3 1B via Ollama com Structured Output habilitado e retorna uma lista de habilidades candidatas classificadas por tipo (hard, soft, knowledge).

messages: list[dict] → Ollama API (/api/chat) → JSON validado → SkillCandidateExtracted

A extração usa zero-shot learning combinado com few-shot no histórico de chat — o modelo não foi fine-tuned, mas aprende pelo contexto dos exemplos embutidos no prompt.


Como Funciona

Fluxo de Funcionamento

Eventos Consumidos e Produzidos

TipoEventoConteúdo
ConsumidoOpportunityPromptGeneratedmessages: list[dict], metadados da vaga
ConsumidoResumePromptGeneratedmessages: list[dict], metadados do currículo
ProduzidoHardSkillCandidateExtractedCandidatos com type == "hard"
ProduzidoSoftKnowledgeCandidateExtractedCandidatos com type in ("soft", "knowledge")
Separação por tipo de evento

A separação em dois eventos de saída (hard vs. soft/knowledge) é uma decisão de roteamento do ADR-045: cada tipo segue um algoritmo diferente no Entity Linker downstream, por isso já são separados aqui na origem.

Decisões Abordadas

Gemma3 1B como modelo: quatro modelos foram avaliados com os mesmos parâmetros e prompt. O Gemma3 1B foi o único que capturava termos compostos ("machine learning engineering") e preenchia todos os campos do schema (position, company, hard_skills, soft_skills, knowledge_skills) de forma consistente. Modelos acima de 1B foram descartados: ao tentar ser mais elaborados, gastam tokens em contexto e explicações em vez de retornar a lista de forma objetiva.

Temperatura 0 para determinismo: o mesmo currículo deve gerar sempre as mesmas skills — variabilidade estocástica tornaria o sistema não-reproduzível e dificultaria a comparação de resultados entre execuções do pipeline.

Separação dos eventos de saída em dois tipos (hard vs. soft/knowledge): o Entity Linker usa algoritmos diferentes por tipo (fuzzy-first para hard, Duplo Diamante para soft/knowledge). Separar na origem elimina lógica de roteamento dentro do Entity Linker e torna cada consumer mais coeso.

Schema de Saída (Structured Output)

O Ollama enforça o schema via JSON Schema antes de retornar a resposta — respostas malformadas são rejeitadas no nível do modelo:

{
  "type": "object",
  "required": ["position", "company", "hard_skills", "soft_skills", "knowledge_skills"],
  "properties": {
    "position":         { "type": "string" },
    "company":          { "type": "string" },
    "hard_skills":      { "type": "array", "items": { "type": "string" }, "uniqueItems": true },
    "soft_skills":      { "type": "array", "items": { "type": "string" }, "uniqueItems": true },
    "knowledge_skills": { "type": "array", "items": { "type": "string" }, "uniqueItems": true }
  }
}

Após o retorno do Ollama, o serviço valida novamente via Pydantic para garantir que o payload do evento downstream esteja correto antes de publicar no RabbitMQ.


Parâmetros de Inferência

ParâmetroValorRacional
temperature0.0Output determinístico — o mesmo texto deve gerar sempre as mesmas skills
top_k40Limita o vocabulário aos 40 tokens mais prováveis, reduzindo criatividade desnecessária
top_p0.95Inclui tokens que somam 95% da probabilidade acumulada
min_p0.05Descarta tokens com probabilidade abaixo de 5%, removendo ruído
repeat_penalty1.0Sem penalização de repetição — skills podem se repetir entre domínios
num_ctx8192Janela de contexto expandida para suportar o histórico few-shot + texto completo
Structured Output no Ollama

O Ollama implementa Structured Output via guided decoding: o modelo só pode emitir tokens que mantêm o JSON parcial em estado válido segundo o schema fornecido. Isso é mais robusto do que apenas pedir JSON no prompt.


Mitigação de Alucinações

SLMs podem inventar habilidades que não estão no texto original. O serviço aplica três camadas de defesa:

1. No prompt (Negative Constraints):

"Extraia SOMENTE skills que estão EXPLICITAMENTE mencionadas no texto"
"NÃO invente, infira ou suponha skills que não estão escritas"

2. Na inferência (temperatura 0): Temperatura zero elimina a variabilidade estocástica do modelo, tornando o output reproduzível e mais conservador.

3. No schema (Structured Output + Pydantic): Skills inventadas ainda podem aparecer, mas o formato estruturado garante que o payload sempre seja processável. O Entity Linker downstream trata skills sem match na ESCO como SkillCustom — elas não são descartadas, mas são sinalizadas para revisão.

SkillCustom

Habilidades sem correspondência na ESCO (alucinações ou termos legítimos não catalogados) são marcadas como SkillCustom pelo Entity Linker. O histórico de processamento persiste ambas as categorias para análise futura e eventual fine-tuning.


ADR's Relacionadas

ADRDataDecisão
ADR-0182026Seleção do Gemma3 1B após comparação de 4 modelos
ADR-045Jun 2026Separação de eventos de saída em hard vs. soft/knowledge para roteamento no Entity Linker