10

RAG só busca. GraphRAG raciocina. Como o LinkedIn cortou 28,6% do tempo de suporte

Passei um bom tempo defendendo o Vector RAG como se fosse a resposta para tudo. Montei o pipeline, gerei os embeddings dos documentos, fiz a busca por similaridade funcionar e me senti um gênio. Aí veio a primeira pergunta de verdade do usuário: "esse erro de pagamento tem a ver com aquele bug de autenticação que vocês corrigiram mês passado?". O sistema me devolveu três trechos de FAQ que falavam de pagamento. Nenhum deles sabia que os dois problemas estavam ligados. O Vector RAG tinha achado texto parecido. Eu queria que ele tivesse raciocinado sobre uma relação. São coisas diferentes, e eu levei tempo demais para aceitar isso.

Esse artigo é sobre essa diferença, e sobre um caso do LinkedIn que coloca número em cima dela.

Comparação entre Vector RAG (busca por similaridade) e GraphRAG (raciocínio sobre relações), com os números do LinkedIn: tempo mediano de resolução -28,6%, MRR +77,6%, 6 meses em produção

Vector RAG busca. E busca muito bem.

Vou dar o crédito que o Vector RAG merece, porque ele merece bastante. Você pega seus documentos, transforma cada pedaço em um vetor, e na hora da pergunta você procura os pedaços mais próximos no espaço vetorial. É rápido, é barato de manter, e para "me ache os documentos que falam sobre o tema X" funciona quase sempre.

O modelo mental que ajuda: o Vector RAG mede distância. Pergunta e resposta ficam perto no espaço se as palavras e os conceitos forem parecidos. Quando a sua dúvida é semântica ("o que é GraphRAG?"), proximidade é exatamente o que você quer.

# Vector RAG: similaridade pura
query_vec = embed("erro de pagamento recusado")
resultados = index.search(query_vec, top_k=3)
# devolve os 3 trechos mais "parecidos" com a pergunta
# e para no exato momento em que você precisa de uma relação

O problema não é o Vector RAG ser ruim. O problema é que metade das perguntas reais de uma empresa não pede proximidade, pede conexão.

Onde a busca por similaridade trava

Pensa no ticket de suporte de verdade. O usuário abre um chamado descrevendo um sintoma. Você, atendente humano, não procura na sua cabeça o ticket com as palavras mais parecidas. Você lembra que esse sintoma costuma vir depois de uma mudança específica, que já apareceu em três clientes do mesmo segmento, e que a correção mexe num módulo que tem dependência com outro. Você está navegando relações, não medindo distância de texto.

O Vector RAG não tem essa estrutura. Cada trecho é uma ilha. "Problema A causa problema B", "ticket X é pré-requisito de Y", "essa falha encadeia naquela outra": nada disso vive no embedding. Ele foi recortado fora na hora em que você picou o documento em chunks.

Um número ajuda a enxergar o tamanho do buraco. Em benchmarks de pergunta multi-salto (onde a resposta exige juntar dois ou três fatos ligados), levantamentos de 2026 mostram a recuperação baseada em grafo chegando perto de 86% de acerto enquanto o Vector RAG fica na casa dos 32%. Na busca semântica simples os dois empatam. A diferença aparece exatamente quando a pergunta deixa de ser "ache parecido" e vira "raciocine sobre a relação". (SIGIR 2024, LinkedIn traz o caso de produção; comparativos de multi-salto em levantamentos de arquitetura RAG 2026.)

E aqui entra um detalhe brasileiro que dói: a gestão de conhecimento na maioria das empresas que eu vi é uma bagunça honesta. Tem Wiki, tem Confluence, tem aquela planilha que só a Camila entende, tem o canal do Slack que ninguém mais rola pra cima. O conhecimento existe. O que não existe é o mapa de como uma coisa puxa a outra. "Pergunta pro fulano que ele sabe" é o knowledge graph mais usado do país, e ele pede demissão sem dar deploy.

GraphRAG: a estrutura que o embedding jogou fora

GraphRAG é Knowledge Graph mais RAG. A ideia, sem firula: em vez de só guardar pedaços de texto, você guarda entidades (problema, causa, solução, cliente, módulo) e as arestas entre elas (causa, depende de, é parecido com, é pré-requisito de). Na hora da pergunta, você não pega só os trechos parecidos. Você pega um pedaço do grafo: a entidade relevante e a vizinhança dela.

# GraphRAG: recupera uma subestrutura, não trechos soltos
entidade = grafo.localizar("erro de pagamento recusado")
subgrafo = grafo.vizinhanca(entidade, profundidade=2)
# subgrafo agora carrega:
#  - a causa provável
#  - o bug de autenticação ligado por aresta "causa"
#  - os tickets que já encadearam essa falha
contexto = subgrafo.para_texto()
resposta = llm.gerar(pergunta, contexto)

A virada mental é essa: o Vector RAG entrega os documentos, e o LLM tem que adivinhar como eles se conectam. O GraphRAG entrega a conexão já montada, e o LLM só precisa redigir. A relação parou de ser um chute do modelo e virou um dado recuperável.

Não vou vender milagre, porque não é. Construir o grafo custa: você precisa extrair entidades e relações dos documentos, e isso normalmente passa por chamadas de LLM, que custam dinheiro e tempo. A primeira indexação de um corpus grande chegou a sair na faixa de dezenas de milhares de dólares nas abordagens iniciais. Em 2026 já tem variante que adia parte desse trabalho para a hora da consulta e derruba o custo para alguns dólares por corpus, mas o ponto continua: GraphRAG é mais caro de montar que Vector RAG. Você paga adiantado pela estrutura. A pergunta certa não é "qual é melhor", é "essa pergunta precisa de relação ou só de proximidade?".

O caso LinkedIn: número, não opinião

Aqui está a parte que me fez parar de discutir e começar a medir.

O time de suporte ao cliente do LinkedIn construiu um sistema de KG mais RAG em cima do histórico de tickets. Em vez de tratar cada ticket passado como um chunk solto, eles montaram um grafo que preserva duas coisas: a estrutura interna de cada chamado (categoria do problema, passos de resolução, FAQ ligada) e as relações entre chamados (problemas parecidos, pré-requisitos, falhas que encadeiam). Na hora de um ticket novo, o sistema recupera o subgrafo relevante e entrega esse contexto para o LLM responder.

Os resultados, depois de cerca de 6 meses rodando em produção de verdade:

  • Tempo mediano de resolução por chamado: 28,6% menor.
  • MRR (Mean Reciprocal Rank): 77,6% acima da linha de base.
  • Ganho também em BLEU na qualidade das respostas.

Vou traduzir o MRR, porque ele é o herói discreto dessa história. MRR mede o quão alto a resposta certa aparece na lista. Subir 77,6% quer dizer que o atendente para de rolar a tela atrás da solução: ela já chega lá em cima. E o tempo mediano cair 28,6% é o reflexo prático disso na vida de quem está do outro lado do chat esperando.

O dado vem do paper publicado pelos pesquisadores do LinkedIn na SIGIR 2024 (arXiv:2404.17723). Não é slide de fornecedor. É produção, com linha de base e com seis meses de chão.

O detalhe que eu mais gosto: o ganho não veio de um modelo maior nem de um embedding mais esperto. Veio de parar de jogar fora a relação entre os tickets. A informação sempre esteve lá. O Vector RAG só não tinha onde guardá-la.

Como eu decido hoje

Depois de apanhar, minha régua ficou simples e quase decepcionante de tão direta:

  • A pergunta é "ache o documento que fala sobre X"? Vector RAG. Não complica.
  • A pergunta é "como X se conecta com Y, e isso já aconteceu antes em situação parecida"? Aí o grafo paga o próprio custo.
  • Não sabe? A indústria em 2026 está convergindo para híbrido: Vector RAG para puxar o contexto narrativo, grafo para percorrer as relações estruturadas. Os dois no mesmo pipeline, cada um fazendo o que faz bem.

E tem o passo zero, que é o mais brasileiro de todos: antes de sonhar com grafo, alguém precisa decidir que "pergunta pro fulano" não é arquitetura de conhecimento. O GraphRAG não conserta uma base bagunçada sozinho. Ele dá estrutura para um conhecimento que a equipe topou estruturar. A ferramenta é boa. Mas ela continua precisando que você acesse o problema certo primeiro.

Resumo

  • Vector RAG mede proximidade de texto e é ótimo para busca semântica. Ele trava quando a resposta depende de uma relação, porque a relação foi recortada fora na hora do chunking.
  • GraphRAG guarda entidades e as arestas entre elas, então recupera a conexão já montada em vez de deixar o LLM adivinhar.
  • O LinkedIn provou em produção: 28,6% a menos no tempo mediano de resolução e MRR 77,6% acima da linha de base, em cerca de 6 meses, segundo o paper da SIGIR 2024.
  • O custo de construir o grafo é real. A decisão certa é por pergunta: proximidade pede Vector RAG, relação pede grafo, e na dúvida o híbrido virou o padrão de 2026.

Comecei esse texto confessando que defendi o Vector RAG demais. Vou fechar admitindo o resto: eu não troquei de lado, eu só parei de pedir para uma ferramenta de busca fazer o trabalho de raciocínio. Buscar e raciocinar são verbos diferentes. O LinkedIn botou 28,6% em cima dessa frase, e eu finalmente parei de discutir.

ken imoto · WebRTC & Voice AI engineer · kenimoto.dev · TabNews

Carregando publicação patrocinada...
4

Meus 2 cents,

Parabens pelo post !

Notei que o RAG tem duas finalidades distintas: procurar por um documento e extrair informacao para gerar conhecimento - e o pipeline acaba sendo diferente para cada um, onde:

  • Informacao: dados dentro da base

  • Conhecimento: analise ou acao do usuario baseado na informacao obtida

Tenho criado pipelines de RAG usando 3 pilares: busca hibrida (semantica + metadados + resumo/abstract), graphRAG e Elasticsearch/OpenSearch - com uma interface unificada e com um LLM local como roteador direcionando para o pipeline mais adequado dependendo do prompt do usuario (existem opcoes na pesquisa que podem mudar isso, mas de um modo geral eh por ai)

Na ingestao do DOC um LLM barato (local ou openrouter) gera os metadados e abstract.

Alem disso, dependendo do tipo de documento o prompt de resumo muda: p.ex. contratos geram tambem json relativos a questoes muito usadas, livros tem json proprio, sites/posts tem outro formato - isso acaba ajudando a organizar melhor a base de conhecimento.

Mas eh uma disciplina em construcao - no final das contas sempre pergunto para o usuario: "sua questao foi resolvida ?"

Obrigado por compartilhar !

Saude e Sucesso !


Este post foi favoritado via extensão TABNEWS FAVORITOS

Tem curiosidade sobre IA ? Da uma olhada no meu LIVRO: IA PARA ENGENHEIROS

2

Essa régua "informação vs conhecimento" eu vou roubar, obrigado. Explica direitinho por que dois pipelines diferentes acabam saindo naturalmente do mesmo problema.

O que mais me chamou atenção foi o LLM como roteador na entrada. Em apresentação de fornecedor essa parte some ("o sistema decide sozinho"), mas na prática é onde grande parte da qualidade vive. E o "sua questão foi resolvida?" no fim é o feedback loop que quase todo mundo pula.

Você tem alguma coisa aberta sobre esse pipeline, ou é tudo interno? Se puder falar sobre o critério que o roteador usa pra escolher entre híbrido, grafo e Elastic, eu agradeço bastante.

2

Meus 2 cents,

Ate pouco tempo usava apenas o roteador e um pipeline, prompt no final do post.

Agora estou testando multiplos pipelines interligados, mas escolhidos pelo planner (basicamente o roteador) - o pipeline macro segue abaixo mas ainda esta sendo refinado, eh basicamente formado por 5 prompts:

1 - Planner: identifica quais as pesquisas necessarias
2 - Hibrido: pesquisa semantica
3 - ElasticSearch: pesquisa por termos
4 - GraphRAG: pesquisa por relacoes
5 - Responser: junta tudo e monta a resposta final

Neste caso optei para fazer em ingles porque nem todo modelo de baixo custo tem treinamento em pt-br.

Existe alguma diferenca no que estou testando com os prompt abaixo, mas sao ajustes mais voltados a guardrails, formatacao e tipos de documentos disponiveis - o mostrado eh bem proximo da producao.

Saude e Sucesso !


PROMPT e CODIGOS: nao sao exatamente estes que estou usando, mas a ideia geral eh

Prompt planner/orquestrador (p.ex. mini, medio porque precisa estrutura quem faz o que)

# Role
You are the Retrieval Planner. Your sole function is to generate an evidence retrieval plan. 

# Strict Constraints
- Never answer the user's question directly.
- Never summarize documents or generate knowledge.
- Output ONLY a JSON object. No conversational filler, no markdown blocks around the JSON, just the raw JSON.

# Available Pipelines
- `DIRECT`: Model internal knowledge only.
- `HYBRID`: Vector + BM25 + Reranking. Best for: document QA, semantic search, specific snippets.
- `GRAPHRAG`: Knowledge graph. Best for: relationships, entities, hierarchies, multi-hop reasoning, timelines, cause-effect.
- `ELASTICSEARCH`: Lexical search. Best for: names, codes, IDs, dates, contracts, exact words/filters.

# Instructions
1. You can combine multiple pipelines.
2. Always design the shortest, most efficient plan possible.
3. Every step in `execution_plan` must contain: `step`, `pipeline`, `goal`, `query`, `expected_output`, `handoff`.

# Output Format
Output exclusively in this JSON structure:
{
  "intent": "string",
  "complexity": "low/medium/high",
  "requires_retrieval": true/false,
  "execution_plan": [
    {
      "step": 1,
      "pipeline": "PIPELINE_NAME",
      "goal": "string",
      "query": "string",
      "expected_output": "string",
      "handoff": "string"
    }
  ]
}

Prompt Elasticsearch (p.ex. small, basicamente so traducao de saida)

# Role
You are an Elasticsearch specialist.

# Objective
Transform the input user query into the best possible lexical query.

# Strict Constraints
- Never answer the user directly.
- Never explain your reasoning or the output.
- Output ONLY a raw JSON object. No markdown code blocks, no conversational text.

# Extraction Rules
Identify and extract from the user input:
- Proper names, numbers, codes, and dates.
- Explicit or implicit filters, aliases, and known synonyms.

# Output Format
Output exclusively in this JSON structure:
{
  "keywords": ["string"],
  "must_terms": ["string"],
  "should_terms": ["string"],
  "metadata_filters": {
    "key": "value"
  },
  "boost_terms": {
    "term": 1.0
  }
}

Prompt hibrido (p.ex. small, basicamente so traducao de saida)

# Role
You are a semantic retrieval specialist.

# Objective
Transform the input user query into the best possible embedding query to maximize recall.

# Strict Constraints
- Never answer the user's question directly.
- Never explain your reasoning.
- Output ONLY a raw JSON object. No markdown blocks, no conversational text.

# Optimization Rules
- Expand synonyms.
- Rewrite vague or ambiguous terms.
- Strictly maintain the original semantic meaning.

# Output Format
Output exclusively in this JSON structure:
{
  "semantic_query": "string",
  "expanded_query": "string",
  "important_entities": ["string"],
  "important_topics": ["string"],
  "reranking_hint": "string"
}

Prompt GraphRAG (p.ex. small, basicamente so traducao de saida)

# Role
You are a graph exploration specialist.

# Objective
Create an optimized graph exploration plan based on the input.

# Strict Constraints
- Never answer the user's question directly.
- Never explain your reasoning.
- Output ONLY a raw JSON object. No markdown blocks, no conversational text.

# Extraction Rules
Identify from the input:
- Entities and their types.
- Relationships, including direction, depth, and expansion rules.

# Output Format
Output exclusively in this JSON structure:
{
  "seed_nodes": [
    {
      "id": "string",
      "type": "string"
    }
  ],
  "relationships": ["string"],
  "max_depth": 1,
  "expansion_strategy": "string",
  "ranking_strategy": "string"
}

prompt do Responser (p.ex. medium, costura tudo)

# Role
You are a Question-Answering specialist who relies exclusively on the provided evidence.

# Strict Constraints
- Never invent facts or use external knowledge.
- If the provided evidence is insufficient to answer, state this explicitly.
- Output ONLY the requested JSON object. No conversational filler or markdown blocks.

# Input Format
You will receive:
1. Original question
2. Execution plan
3. Retrieved evidence

# Output Format
Output exclusively in this JSON structure:
{
  "answer": "string",
  "cited_sources": ["string"],
  "gaps_identified": ["string"],
  "confidence_level": "low/medium/high"
}

Exemplo (mockup) do codigo python usado

def run_pipeline(user_question: str):
    manager = RAGPipelineManager()
    
    print(f"--- [PASSO 1] Chamando o Planner ---")
    plan: PlannerResponse = manager.call_planner(user_question)
    print(f"Intenção detectada: {plan.intent}")
    print(f"Complexidade: {plan.complexity}\n")
    
    if not plan.requires_retrieval:
        print("O plano determinou que não é necessário recuperar evidências externas.")
        return

    all_collected_evidence = []
    context_from_previous_steps = ""

    # Percorre cada etapa gerada pelo Planner
    for step in plan.execution_plan:
        print(f"➔ Executando Etapa {step.step} [{step.pipeline}] - Objetivo: {step.goal}")
        
        # Injeta o contexto acumulado dos passos anteriores (Handoff), se houver
        combined_query = f"{step.query} (Contexto prévio: {context_from_previous_steps})".strip()
        
        if step.pipeline == "ELASTICSEARCH":
            es_query = manager.call_elasticsearch_specialist(combined_query)
            print(f"   [DSL Gerado]: {es_query.model_dump_json(indent=2)}")
            # Aqui entraria sua chamada real de banco: db.elasticsearch_search(es_query)
            mock_evidence = f"[ElasticSearch Doc] Resultado para termos obrigatorios {es_query.must_terms}"
            all_collected_evidence.append(mock_evidence)
            context_from_previous_steps += f" | Encontrado no Elastic: {es_query.must_terms}"

        elif step.pipeline == "HYBRID":
            hybrid_query = manager.call_hybrid_specialist(combined_query)
            print(f"   [Vetorial Gerado]: {hybrid_query.model_dump_json(indent=2)}")
            # Aqui entraria sua busca vetorial + BM25: db.hybrid_search(hybrid_query)
            mock_evidence = f"[Hybrid Doc] Trecho sobre o tópico '{hybrid_query.semantic_query}'"
            all_collected_evidence.append(mock_evidence)
            context_from_previous_steps += f" | Tópicos do Híbrido: {hybrid_query.important_topics}"

        elif step.pipeline == "GRAPHRAG":
            graph_query = manager.call_graphrag_specialist(combined_query)
            print(f"   [Plano de Grafo Gerado]: {graph_query.model_dump_json(indent=2)}")
            # Aqui entraria sua query Cypher ou busca em Grafo: db.graph_search(graph_query)
            mock_evidence = f"[Graph Doc] Relações encontradas a partir dos nós {graph_query.seed_nodes}"
            all_collected_evidence.append(mock_evidence)
            context_from_previous_steps += f" | Nós do Grafo: {graph_query.seed_nodes}"
            
        elif step.pipeline == "DIRECT":
            print("   [Direct]: Usará apenas o conhecimento interno do modelo no passo final.")
            
        print("-" * 50)

    print(f"\n--- [PASSO FINAL] Chamando o Responser ---")
    final_response = manager.call_responser(
        original_question=user_question, 
        plan=plan, 
        evidence=all_collected_evidence
    )
    
    print("\n================ RESPOSTA FINAL CACHEADA ================")
    print(final_response.model_dump_json(indent=2))

# --- Execução de Exemplo ---
if __name__ == "__main__":
    pergunta = "Quais empresas participaram de projetos semelhantes ao Projeto Atlas e depois firmaram contratos com o Grupo Delta ?"
    run_pipeline(pergunta)

Originalmente o roteador era so isto (para modelos 9B, sem multiplos pipelines e agora estou testando multiplos pipelines conectados - visto acima)

# Role
You are a query router for a RAG system. Your sole function is to select the best pipeline to answer the query.

# Strict Constraints
- Never answer the user's query.
- Output ONLY a raw JSON object. No conversational text, no markdown blocks.

# Available Pipelines
- `elasticsearch`: Use for specific documents, names, codes, numbers, IDs, dates, contracts, articles, exact words, filters, or metadata.
- `hybrid`: Use for understanding topics, content Q&A, finding relevant snippets, summarizing documents, factual questions, or retrieving knowledge from few documents.
- `graphrag`: Use for connecting scattered information, identifying relationships (people, companies, events), dependencies, conceptual navigation, multi-hop reasoning, or synthesizing across multiple sources.

# Allowed Intent Categories
`document_lookup`, `factual_question`, `semantic_search`, `relationship_query`, `multi_hop_reasoning`, `analytical_question`

# Output Format
Output exclusively in this JSON structure:
{
  "pipeline": "elasticsearch/hybrid/graphrag",
  "intent": "string",
  "confidence": 0.0,
  "reason": "One short sentence explaining the choice."
}

# Input Query
{{USER_QUERY}}

Este post foi favoritado via extensão TABNEWS FAVORITOS

Tem curiosidade sobre IA ? Da uma olhada no meu LIVRO: IA PARA ENGENHEIROS

3

Fiquei abstraindo aqui fora da programação em si, e percebi um detalhe, o problema pelo que entendi ai todo é perder informação na verdade, tipo classificar informações relevantes como se fossem irrelevantes, ou seja o que você chama de relações, que é justamente a cola entre os contextos correto? Eu resolvi isso com um RAG semântico que usa IA local para analisar a "cola" e te devolver os resultados, na epoca chamei de Autoreflex e coloquei no GIT a primeirissima versão. Que em minha stack pessoal gora esta bem mais avançada e ja transformei em uma orquestra de MCPs, mas voltando a questão, o que ele faz é usar um qdrant para indexar e o modelo Gemma Embed do google para fazer buscas semanticas, no caso uso para skills, então eu tenho milhares de skill, mas elas tem um indice com descrição e palavras chaves, cada nova skill criada é indexada, elas podem ser mescladas, apagadas, revisadas. O modelo consulta apenas o indice e devolve resultados curtos aos agentes de IA ou a ser humano mesmo buscando por uma url de api, a resposta são as skills com sua pontuação de relevancia, mas filtradas pelo conteudo e relação sintatica a perguta que pode ser em qualquer idioma e de qualquer forma.

Talvez ache interessante, como disse dá para fazer muito alem, eu coloquei lá bem limitado confesso por falta de tempo:

https://www.tabnews.com.br/macnator/autoreflex-o-servidor-de-memoria-que-faz-agentes-de-ia-aprenderem-com-o-proprio-trabalho

1

"Cola" ficou uma palavra ótima pra isso, obrigado. É exatamente o pedaço que o chunking joga fora sem avisar, e você deu nome nele.

Fui olhar o Autoreflex no seu link. Indexar skills por embedding e deixar o modelo escolher pela descrição é um setup que a Anthropic acabou formalizando agora com Claude Skills, mas você chegou lá antes por outro caminho, o que já diz alguma coisa.

Fico curioso pra ver a versão MCP-orquestra. Quando você tiver tempo de publicar um follow-up, eu leio.

1

Coloquei o inicio da abordagem aqui, acho que isso sem duvida vai ser o futuro, aqui uso direto a arquitetura e funciona muito bem principalmente para criar ferramentas que devolvem resultados exatos e manter a ia longe de dados reais ou informações que não podem sofrer alteraçoes, mas isso ai é o inicio, isso pode expandir para n propositos, é um um tipo novo de rede.

https://www.tabnews.com.br/macnator/model-context-protocol-mcp-a-nova-camada-de-abstracao-que-todo-desenvolvedor-precisa-entender

1