GenAILLMRAGPeople AnalyticsPython

Chatbot de RH com LLM e RAG

Assistente conversacional que responde perguntas sobre políticas de RH, benefícios e carreira usando Retrieval-Augmented Generation com GPT-4.

2026·Banco BV·Concluído

Demonstração do projeto

O time de RH do Banco BV recebia mais de 800 perguntas mensais repetitivas sobre benefícios, políticas, processos de promoção e férias — tópicos com respostas claras na documentação interna, mas que consumiam 40% do tempo dos HRBPs. Desenvolvemos um chatbot baseado em RAG que indexa toda a base de documentos de RH e responde perguntas em linguagem natural, com citação das fontes, histórico de conversa e fallback humano quando a confiança é baixa.

Impacto & Métricas

800+

Perguntas respondidas/mês

73%

Taxa de resolução automática

4.7 / 5

CSAT médio

< 2s

Tempo de resposta

40%

Redução de carga HRBP

Arquitetura RAG

O sistema usa Retrieval-Augmented Generation (RAG) em vez de fine-tuning por dois motivos:

1. As políticas de RH mudam com frequência — RAG permite atualização sem retreinar o modelo
2. RAG cita as fontes, aumentando confiança e auditabilidade das respostas

Pipeline de Ingestão

1. Extração: PDFs e DOCXs de políticas de RH são extraídos com `pdfplumber` e `python-docx`

2. Chunking: documentos são divididos em chunks de 512 tokens com overlap de 50 tokens,
preservando contexto entre partes
3. Embeddings: `text-embedding-3-small` da OpenAI gera vetores de 1536 dimensões
4. Indexação: FAISS como vector store local (migração para Azure AI Search planejada)

Estratégias de Qualidade

- MMR Retrieval: reduz redundância nos documentos recuperados

- Score de confiança: se o score de similaridade do retriever for < 0.65,
o chatbot escala para um HRBP automaticamente
- Guardrails: o prompt proíbe explicitamente invenção de informações e
orienta o tom formal mas acessível

Próximos Passos

- Migração do índice vetorial para Azure AI Search (escala enterprise)

- Multimodalidade: responder com base em tabelas e fluxogramas de documentos
- Analytics de conversas para identificar gaps na documentação de RH

python·rag_pipeline.py
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_community.vectorstores import FAISS
from langchain.chains import ConversationalRetrievalChain
from langchain.memory import ConversationBufferWindowMemory
from langchain.prompts import PromptTemplate

SYSTEM_PROMPT = """Você é o Assistente de RH do Banco BV. Responda perguntas dos
colaboradores com base EXCLUSIVAMENTE nos documentos fornecidos como contexto.

Regras:
- Seja direto e use linguagem simples
- Cite sempre a fonte (nome do documento)
- Se não souber, diga: "Não encontrei essa informação. Entre em contato com o RH."
- Nunca invente informações sobre políticas, valores ou processos

Contexto dos documentos:
{context}

Histórico da conversa:
{chat_history}
"""

def create_hr_chatbot(documents_path: str) -> ConversationalRetrievalChain:
    """
    Cria pipeline RAG para chatbot de RH.

    Args:
        documents_path: caminho para pasta com PDFs e DOCXs de RH

    Returns:
        Chain conversacional com memória de janela (últimas 5 trocas)
    """
    # Embeddings e índice vetorial
    embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
    vectorstore = FAISS.load_local(documents_path, embeddings)

    retriever = vectorstore.as_retriever(
        search_type="mmr",           # Maximal Marginal Relevance — reduz redundância
        search_kwargs={"k": 5, "fetch_k": 20},
    )

    # LLM com temperatura baixa para respostas factuais
    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.1)

    # Memória de janela: mantém contexto das últimas 5 trocas
    memory = ConversationBufferWindowMemory(
        memory_key="chat_history",
        return_messages=True,
        k=5,
    )

    chain = ConversationalRetrievalChain.from_llm(
        llm=llm,
        retriever=retriever,
        memory=memory,
        combine_docs_chain_kwargs={
            "prompt": PromptTemplate.from_template(SYSTEM_PROMPT)
        },
        return_source_documents=True,
        verbose=False,
    )

    return chain