Pular para o conteúdo

Além de RAG: crie do zero um mecanismo de contexto relacional — Peter Werry, Unblocked

Ver no idioma original →

Autoria: AI Engineer · Assistir no YouTube

Vídeo de autoria do canal indicado, não da IANIA; todos os direitos pertencem ao criador. Transcrição, resumo e tradução gerados automaticamente; o conteúdo no idioma original é preservado na versão em idioma original.

Idioma original: inglês

Vídeo original: Beyond RAG: Build a Relational Context Engine from Scratch — Peter Werry, Unblocked · Canal: AI Engineer · 37:55 · Assistir no YouTube

Tópicos: Agentes de IA, Dados, bancos de dados e embeddings, Engenharia de prompts e contexto, RAG, busca e recuperação de informação, Segurança de IA

Peter Werry, da Unblocked, apresenta um mecanismo de contexto que combina busca semântica com consultas estruturadas a dados de engenharia. A demonstração constrói gradualmente um sistema que descobre o schema, resolve identidades, gera consultas a partir de linguagem natural e valida os resultados. O fluxo inclui controles de segurança, tentativas de autocorreção e busca textual, e pode alimentar uma interface de consulta ou um agent de chat. Na sessão de perguntas, Werry comenta escala, ingestão de dados, MCP, busca híbrida e atualização de schemas.

  • RAG por similaridade semântica não basta para responder perguntas sobre estados, datas, autores e relações entre registros.
  • O LLM deve gerar a consulta que acessa o banco de dados, em vez de responder diretamente à pergunta.
  • A geração confiável de consultas requer disponibilizar o schema e as relações dos dados, além de resolver nomes e logins.
  • A validação deve usar uma allowlist de operadores e, quando necessário, de campos; controles de segurança devem ser implementados com código procedural.
  • Erros de validação ou execução podem ser devolvidos ao LLM para novas tentativas, limitadas por um número máximo de tentativas.
  • A demonstração combina filtros estruturados, escopo temporal e busca textual para responder perguntas mais específicas.
  • Busca semântica e busca estruturada são complementares: a primeira pode encontrar um ponto de partida, e a segunda pode recuperar registros precisos.
  • Para escalar, é possível selecionar o schema relevante para cada consulta; a ingestão contínua pode ser atualizada por eventos e webhooks.
Início Capítulo Resumo
00:12 Contexto organizacional e a tese da apresentação Peter Werry apresenta a Unblocked e propõe complementar a busca semântica com consultas a bancos de dados.
02:58 Contexto disperso e relações estruturais O contexto de engenharia está distribuído em PRs, issues, documentos e conversas, com relações que a busca vetorial não representa por si só.
06:36 Como gerar consultas confiáveis O modelo precisa conhecer o schema, mapear identidades, evitar consultas inseguras e poder corrigir erros.
09:12 Descoberta do schema A demonstração infere o schema a partir de uma amostra de documentos e usa código procedural para extrair seus tipos.
12:19 Resolução de identidade O sistema precisa associar nomes conhecidos, como Peter, aos identificadores usados nos dados, como o login do GitHub.
14:24 Plano de consulta e dimensão temporal O modelo recebe o schema e uma ferramenta para gerar consultas, com a data e a hora atuais para interpretar referências temporais.
16:33 Validação e segurança O apresentador explica como restringir operadores e campos para impedir consultas perigosas ou vazamento de dados internos.
19:38 Tentativas de autocorreção e busca textual Erros de validação ou execução podem ser devolvidos ao modelo, e a busca textual ajuda a responder consultas por palavras-chave.
22:29 Demonstração do agent e resumo O agent combina a consulta ao banco com raciocínio para responder perguntas sobre atividades recentes relacionadas a um tema.
25:17 Escala, seleção de schemas e ingestão Na sessão de perguntas, Werry aborda como selecionar schemas relevantes e manter a ingestão de dados atualizada.
27:21 Fontes de dados e memória organizacional A conversa destaca Slack e comentários em PRs como fontes de contexto sobre decisões e práticas da equipe.
29:27 MCP e combinação de estratégias de busca Werry discute como expor consultas por MCP e combinar busca estruturada, lexical e semântica.
32:54 Experimentos e limites da descoberta automática O palestrante descreve a busca híbrida e explica que a inferência de schema exige experimentação e pode deixar casos de fora.
35:09 Validação de chamadas e mudanças no schema A sessão termina com detalhes sobre verificar chamadas de extração de nomes e atualizar schemas quando os dados mudam.

RAG é apenas metade da recuperação. — 00:43

O modelo não responde à pergunta nesse paradigma; ele escreve a consulta que acessa o banco de dados. — 06:36

Eu não recomendaria usar LLMs para essa parte. — 18:05

A tentativa de corrigir erros é uma das partes mais importantes. — 24:11

Não são incompatíveis; são absolutamente complementares. — 30:40

  • Unblocked (empresa): Empresa que constrói um mecanismo de contexto para disponibilizar contexto organizacional a pessoas e agents.
  • Peter Werry (pessoa): Apresentador da Unblocked que demonstra a construção de um mecanismo de contexto relacional.
  • Brandon (pessoa): Colega de Peter Werry na Unblocked, mencionado como participante da sessão.
  • RAG (conceito): Na apresentação, refere-se à busca por similaridade semântica ou recuperação vetorial, útil para encontrar conteúdo relacionado, mas insuficiente para algumas consultas estruturadas.
  • Mecanismo de contexto relacional (conceito): Sistema que conecta contexto organizacional e permite consultar relações estruturadas entre os dados usando linguagem natural.
  • Descoberta dinâmica de schema (conceito): Processo que infere um schema amostrando documentos e combinando os campos encontrados.
  • Resolução de identidade (conceito): Mapeamento entre nomes mencionados em uma pergunta e identificadores correspondentes nos dados, como um nome e um login do GitHub.
  • Validação de consultas (conceito): Verificação procedural das consultas geradas para permitir apenas operadores e campos autorizados e reduzir riscos de segurança.
  • Busca híbrida (conceito): Combinação de busca por similaridade semântica e busca lexical para recuperar tanto conceitos quanto correspondências textuais.
  • MCP (conceito): Interface mencionada como uma forma de expor consultas estruturadas ou consultas em linguagem natural a outros sistemas.

00:12 Certo. Então, eu sou Peter, da Unblocked. Aqui está meu colega Brandon. E hoje, bem, antes de tudo, quero falar um pouco sobre o que fazemos. Nós criamos um mecanismo de contexto. O nome da nossa empresa é Unblocked. Nós fornecemos contexto organizacional para pessoas e, cada vez mais, é claro, para agents. A sessão originalmente duraria algumas horas. Agora ela tem uma hora, então está bem condensada. Isso significa que vou percorrer o workshop bem rápido. Se você não

00:43 conseguir acompanhar todos os passos enquanto avançamos, não se preocupe, porque o repo está disponível online e você pode percorrê-lo no seu próprio ritmo depois. Então, a tese aqui é que RAG — e hoje vou dizer que, no nosso vocabulário, RAG significa busca por similaridade semântica ou recuperação vetorial — é apenas metade da recuperação. Hoje vamos construir a outra metade, que é transformar linguagem natural em consultas reais ao banco de dados.

01:14 Então, aqui está de novo o código QR para a configuração, caso alguém ainda não tenha feito isso. Agora vou pular para a próxima parte e só vou abrir rapidamente isto. Tomara que apareça. Não, claro que não. Me deem um segundo para trocar. Opa. Espero que todos consigam ver. Este é o repo. As etapas de configuração são bem simples. Há algumas dependências aqui, pré-requisitos

01:46 que vocês vão precisar seguir. Ao longo do workshop, vamos percorrer uma série de pull requests, e a rede basicamente caiu, ou pelo menos não está funcionando direito. Vamos tentar este aqui. Bem, pelo menos não precisamos

02:18 da rede para esta palestra. Espero que vocês tenham conseguido tudo antes de começarmos, porque este aqui obviamente não vai funcionar. De qualquer forma, vamos acompanhar uma série de seis pull requests, que se acumulam uns sobre os outros. Então, vou… Aí está. Vou fazer referência a eles conforme avançamos. Vou voltar para cá para que todos possam ver. E volto à apresentação. Agora vou ter que ampliar de novo. Desculpem.

02:58 >> Aí está. Certo. Espero que todos consigam ver. Ótimo. Nossos agents precisam de contexto, e o contexto está espalhado por todas as ferramentas usadas pelas equipes de engenharia. Vocês vão encontrá-lo em PRs, comentários de revisão, issues e tickets em ferramentas como Linear e Jira, documentos e wikis, Notion e Confluence e, claro, em conversas e lugares como Slack e Teams. E tudo isso pode ser consultado semanticamente

03:28 mas também tem estrutura. Há autores, datas, estados, labels, relações etc. E, sabe, gosto de dizer que até mesmo dois anos atrás é história antiga no mundo da IA, mas, ainda dois anos atrás, o instinto era simplesmente despejar tudo isso em um banco vetorial, recuperar os dados, reclassificá-los e torcer para obter a resposta certa. Mas isso não vai funcionar. Então, vou dar um passo atrás e relacionar isso à discussão mais ampla sobre contexto.

03:59 no contexto de um mecanismo de contexto que fornece contexto organizacional, isso é composto por mais do que apenas código, como eu disse. Estamos conectando tudo. O contexto disperso à esquerda — em todo o código, nos PRs, documentos etc. — entra, e a ideia é obter do outro lado um contexto fundamentado, cujas partes estejam relacionadas entre si e que seja adaptado especificamente à tarefa em questão. Nesse modelo, temos que nos importar não apenas com as relações semânticas, mas também com as

04:30 relações estruturais que conectam todos os dados. Então, novamente, RAG consiste em gerar um embedding da consulta, encontrar documentos com significado semelhante e, depois, colocar esse material no prompt, certo? Isso funciona muito bem para perguntas sobre conteúdo, como “encontre o código”, “encontre o PR que o alterou” e “encontre a conversa no Slack em que isso foi debatido”. E, se você envolver isso em um loop de agent, pode ir bem longe. Você também pode conectar isso a ferramentas que percorrem arquivos e que servem como um bom ponto de partida.

05:02 Você obtém um bom ponto de partida semântico e, a partir daí, seu agent pode percorrer o sistema de arquivos real no GitHub, e pode ir bem longe com isso. Mas, na nossa experiência, não é bem assim que as coisas acontecem na prática. Engenheiros costumam fazer perguntas como: “Quais PRs eu mesclei na semana passada?” ou “Quais PRs minha equipe mesclou na semana passada?”. Basicamente, eles estão procurando algo específico e sabem

05:33 qual é o ponto de partida, mas não sabem qual é o destino — embora conheçam as relações. Por exemplo, “PRs que eu mesclei na semana passada”. Vamos pensar nisso no contexto de RAG. Você geraria um embedding dessa frase, encontraria os vetores mais próximos e os reclassificaria, selecionando os K primeiros. Você obteria PRs que mencionam mesclagem e uma conversa da semana passada, mas não obteria as relações reais, como o autor, o estado da mesclagem e se

06:06 o PR foi realmente mesclado na semana passada. Então, você poderia acabar com a resposta errada, mostrando um PR semanticamente relacionado, mas que foi mesclado há três anos. Isso não responde à pergunta, porque há um aspecto estrutural, um aspecto temporal nessa pergunta. Portanto, a recuperação tem duas partes: semântica e, como vamos abordar hoje, consultas estruturadas. E aqui está o ponto principal. Vamos pegar

06:36 O modelo não responde à pergunta de fato nesse paradigma. Ele escreve a consulta que acessa o banco de dados. Certo. Seria ingênuo dizer que gerar a consulta é a única coisa que precisamos fazer. Para gerar a consulta de forma confiável e talvez até lidar com algumas questões de segurança, precisamos considerar estes quatro pontos. Primeiro, o LLM precisa estar

07:06 ciente do esquema antes de criar a consulta. Ele precisa entender algumas das relações nos dados. Por exemplo, se você passar uma consulta em linguagem natural como “mostre os PRs abertos de Peter”, ele não vai saber o que fazer, porque vai sintetizar uma consulta com o nome Peter, quando, na verdade, o nome de login no GitHub pode ser diferente. Então, ele precisa conseguir fazer essa correspondência. E, claro, você pode receber consultas não confiáveis. Talvez

07:38 usando o operador de função, na terminologia, que poderia executar JavaScript diretamente no servidor, e provavelmente não queremos isso. Por fim, se houver erros na primeira tentativa, queremos conseguir corrigi-los automaticamente. Então, é assim que isso fica em uma única etapa. Queremos algo parecido com isto. Ele mapeia: o nome do meu colega é Rashine; o nome de login dele é Rashab. Depois, queremos conseguir mapear coisas como o estado e talvez obter operadores como limite e ordenação.

08:10 Então, é isto que vamos construir. Vamos começar com uma experiência de usuário completa e um mecanismo simulado, que inicialmente não será capaz de fazer nada, e vamos desenvolvê-lo aos poucos. No terceiro passo, ele vai ganhar vida. Aí, vamos conseguir enviar consultas e ver o que ele faz. E, se você ainda não fez isso, agora é outro bom momento para escanear esse código QR

08:40 e configurar tudo. Estou aqui para ajudar. >> Sim. >> Isso. Qualquer repo serve. Não importa qual. E, se quiser pegar um atalho, você pode simplesmente apontar um agent para isso e deixar que ele configure tudo.

09:12 para você. Isso funciona. Certo, vamos continuar. Então, é isso que vamos fazer para começar. A essa altura, você provavelmente já deve ter executado esse processo de ingestão. Não se preocupe se ainda não fez isso. Você pode voltar a essa etapa no final. Vou mostrar rapidamente como é a interface básica dessa ferramenta. Agora, ela está em execução. Se eu digitar qualquer coisa aqui, obviamente não vai funcionar. O que você deve ver é algo assim.

09:44 Também há uma aba de chat. Este é um agent totalmente implementado que pode realizar tarefas para você. Vamos voltar a ele daqui a pouco. E este é o contrato no código, caso você queira ler. Não se preocupe com isso. Vamos passar por essa parte. Basicamente, esse é o ponto de entrada, e vamos construir a partir dele. Então, a primeira coisa sobre a qual queremos falar é a descoberta de schema. Durante

10:15 a ingestão, se você observar como o script de ingestão funcionava, ele precisou montar um schema para baixar e armazenar o conteúdo. Mas você pode imaginar que talvez não conheça o schema. Então, a ingestão pode estar acontecendo em outro serviço, e você quer criar um mecanismo totalmente dinâmico de descoberta de schema. Sem schema. Não há schema para consultar, ao contrário do que acontece, por exemplo, no PG, onde poderíamos ler as definições das tabelas. Então, o que faremos é amostrar os documentos para inferir o

10:46 schema, e esse é o truque todo. Vamos simplesmente reconstruí-lo. Vamos pegar todos os nós e mesclá-los. Isso vai amostrar 300 documentos e condensá-los em uma única árvore. Os valores nulos são ignorados, porque os campos ausentes não permitem restringir o tipo. E então vamos fazer algo interessante com os tipos enum.

11:17 Com os tipos enum, podemos usar um truque procedural interessante. É só uma possibilidade. Eu recomendaria usar truques procedurais para esse tipo de coisa, porque você poderia passar isso por um LLM e fazer a extração, e isso funciona, mas é bastante não determinístico. Então, você sempre precisa de algum tipo de harness estrutural em volta, que execute código procedural para validar o que foi extraído ou para fazer a própria extração. E, neste

11:48 projeto de exemplo, é o código procedural que faz a extração. Vamos mostrar. Vamos executar isso de novo. E agora temos isto aqui. O schema foi executado — o processo de descoberta foi executado — e criou um schema para nós que descreve como é o schema de pull request

12:19 no GitHub. Ele até criou alguns índices para nós. Agora, isso está em Markdown de propósito, porque vamos pegar esse schema e passá-lo ao LLM quando sintetizarmos a consulta propriamente dita. A segunda etapa é aquela que mencionei alguns slides atrás: a resolução de identidade. Isso porque meu login no GitHub é parecido,

12:50 mas não é exatamente igual. Então, se eu perguntasse algo como “ei, encontre todos os PRs do Peter”, sem algum tipo de mapeamento de identidade, ele simplesmente faria a correspondência com “Peter” e não encontraria nada. Então, precisamos resolver isso. E, de novo, vamos fazer isso. À primeira vista, parece que estamos acoplando um pouco ao schema aqui. Mas é perfeitamente possível determinar isso dinamicamente. Você pode fazer com que seu LLM sintetize os mapeamentos para você. No nosso caso, porém, vamos usar esses truques simples. Um tipo de correspondência aproximada bem simples. A distância de Levenshtein funciona. Basta comparar os nomes e pronto. Ah, na verdade, quero mostrar uma coisa antes de passarmos para essa etapa.

13:22 Então, vamos fazer a mesma coisa de novo. Podemos abrir… Ah, sim, desculpe. Claro. Me avise quando estiver grande. Ótimo, obrigado. Bem lembrado. Certo. Vamos executar de novo. E agora… Ah, na verdade, preciso esperar até a próxima etapa. Desculpe. Isso ainda não está conectado.

13:54 Então, vamos passar para o que realmente vai nos trazer o resultado esperado: a etapa três. Esta é a etapa do plano de consulta e, sem dúvida, é a parte mais simples. É a parte do LLM. Aqui, passamos o schema, fornecemos uma ferramenta e obrigamos o LLM a chamar essa ferramenta para extrair nomes e sintetizar a consulta. Depois, ele executa o plano.

14:24 Há mais uma coisa: o aspecto temporal. Os LLMs são, na verdade, muito bons em gerar consultas temporais se você passar a data e a hora atuais. Então, isso é outra coisa importante a incluir no prompt. E aqui está a etapa de extração de nomes. Neste caso, vamos forçar a chamada dessa ferramenta.

14:56 E, neste ponto, vou mostrar o resultado disso. Aí está. Agora posso fazer coisas como esta: “PRs abertos do Peter”. E pronto. O que vamos ver aqui é que

15:28 ele gerou esta cláusula de correspondência e, embora não dê para ver daqui, mapeou Peter para meu login de usuário do GitHub, puery, e gerou a consulta. Esse é o resultado. Legal, mas precisamos passar para a próxima etapa porque, embora agora possamos consultar os dados, temos algumas preocupações de segurança. Pode

16:00 acontecer de ele produzir uma saída não confiável e, então, usar as cláusulas where ou function e executar JavaScript no servidor, o que faz deste um ponto de injeção de prompt. Também pode haver campos ocultos no schema, como campos de ID ou de metadados, que vazam informações internas. Então, precisamos sanitizar. Não usamos uma lista de bloqueio; usamos uma lista de permissões. Portanto, o padrão é negar.

16:33 Você basicamente quer criar uma lista de permissões com os operadores permitidos e, potencialmente, uma lista de permissões com os campos permitidos. No nosso caso, a descoberta de schema é dinâmica, então não vamos fazer isso. Mas poderíamos ter alguns campos conhecidos, como os campos de metadados. Isso é útil para o isolamento de tenants. Se você tiver uma coleção que abriga vários tenants, não recomendo isso. Provavelmente, você deveria separar suas coleções por

17:04 tenant. Mas, se fizesse isso, poderia ter um campo de metadados que contivesse o ID do tenant. Você iria querer ocultar essas informações do LLM, mas também validar a saída. Se ele produzir esse campo de metadados, você precisa removê-lo e, em seguida, injetar seu próprio campo de metadados.

17:34 E, de novo, tecnicamente, isso não é tão difícil de fazer. Basta escrever o código. É tudo procedural. Eu não recomendaria usar LLMs para essa parte. Então, mais uma vez: use uma lista de permissões; não use uma lista de bloqueio — ou, melhor dizendo, negue tudo por padrão. Agora, na última parte, vamos…

18:05 Isso se encaixa na próxima etapa. No fim da validação, obviamente vamos retornar um erro, e ele será exibido. Por enquanto, esse erro simplesmente fica ali. Ainda não vamos fazer nada com ele. Mas agora vou mostrar como isso fica. Opa. Fique nessa tela e

18:35 execute nosso serviço. Agora vou escrever outra consulta que verifica se há autenticação no título, e nós proibimos expressões regulares. Assim, podemos ver que a consulta é rejeitada. E, por fim, a parte que

19:07 amarra tudo é o loop de tentativas novamente. O plano pode falhar de algumas maneiras diferentes, certo? Pode falhar na validação. Talvez o LLM produza algo que seja ilegal segundo nosso validador. Ou pode falhar durante a execução. Por exemplo, imagine que ele misture um projeto de inclusão e um de exclusão.

19:38 que amarra tudo é o loop de nova tentativa. O plano pode falhar de algumas maneiras diferentes, certo? Ele pode falhar na validação. Talvez o modelo de linguagem realmente gere coisas inválidas segundo o nosso validador. Ou pode falhar durante a execução. Por exemplo, vamos imaginar que ele misturou um projeto de inclusão-exclusão.

20:09 Então, obviamente, isso vai falhar. Mas podemos fazer uma autocorreção. Podemos pegar esse erro, passá-lo de volta para o LLM e dizer: “Ei, isso estava errado. Talvez você consiga fazer melhor”, até um número máximo de tentativas, claro. Agora vou mostrar como isso fica no nosso projeto, para subirmos um nível. Opa.

20:41 Desculpem. Peço que me perdoem. Na verdade, preciso ler isso na tela aqui. Certo. Agora, se executarmos a mesma consulta… Perfeito. Então, o que podemos ver é que ela

21:11 precisou de várias tentativas para acertar. Mas, na terceira tentativa, há um pequeno problema, porque dissemos que não usaríamos expressões regulares nem FTS. Então, agora ela disse que simplesmente usaria match, mas isso é uma correspondência exata. Assim, ela tenta encontrar “authentication fails”. Isso significa que há mais uma coisa que podemos fazer, que é isto.

21:42 Vamos adicionar busca de texto completo. É bem básica. Precisamos criar um índice, obviamente, e vamos combiná-la com filtros de autor e estado na mesma correspondência. Assim, agora devemos conseguir responder a uma pergunta como esta. Vamos ver o que acontece e se ela realmente vai fazer o que eu disse que faria.

22:29 Pronto. Aí está. E agora, o resultado final é que, se formos para a aba de chat, podemos fazer perguntas mais sofisticadas, que um agent consegue realmente analisar nos bastidores. Por exemplo: “Trabalhamos em algo relacionado à autenticação na semana passada?”

23:10 Aqui podemos ver que ela gerou a consulta. Agora está buscando os dados e, de certa forma, raciocinando sobre eles. Aí está. É isso. Então, um resumo rápido do que construímos. Basicamente, estamos chegando ao fim.

23:41 Ainda vai sobrar bastante tempo para perguntas. Então, para recapitular, há perguntas que o RAG não consegue responder. Todas aquelas perguntas estruturais sobre coisas como estado ou temporalidade. Quando você faz esse tipo de pergunta usando RAG tradicional, não obtém os dados certos. Portanto, o mesmo mecanismo está por trás do playground de consultas e do agent de chat. São a mesma coisa. Então, se quiserem experimentar depois, podem. É a mesma estrutura de suporte. A

24:11 única diferença, claro, é que o agent de chat realmente raciocina, enquanto a interface de consulta serve apenas para consultas. Para recapitular, estas são as ideias reutilizáveis: prompting com reconhecimento do schema, descoberta dinâmica do schema, resolução de identidade, validação e novas tentativas após erros. O ciclo de erro é, na verdade, uma das coisas mais importantes.

24:45 E construímos algo capaz de filtrar, fornecer agregações, limitar-se a um período e fazer busca de texto completo. É validado, corrige os próprios erros e alimenta um agent de chat completo. Então, vocês poderiam levar isso para a organização de vocês e fazer o deploy. Eu recomendaria talvez trabalhar um pouco mais nos harnesses de validação antes de fazer o deploy internamente, mas, sim, isso vai responder a todas as perguntas de vocês sobre seus PRs. E é isso. Deixamos bastante

25:17 tempo para perguntas agora. [risos] Todos conseguiram configurar tudo? Só por curiosidade. Não? Certo. Se quiserem, podem vir falar comigo e com Brandon depois; vamos ficar por aqui. Ah, e também no estande P16. Sim, mas isso começa mais tarde hoje, por volta das quatro, e estaremos lá a semana toda. >> Legal. Alguma pergunta? >> Sim. >> Tenho uma pergunta. Acho que você fez um ótimo trabalho explicando o básico.

25:49 >> Sim. >> Muitas vezes, fico pensando: certo, e em escala? Por exemplo, como vocês geram o schema e o colocam no system prompt? Como isso funciona em escala? Também depende do tamanho da empresa: como vocês acomodam todos esses dados? Como escolhem quais dados usar? E quanto tempo leva para processar tudo isso? Qual é o custo? É nisso que estou pensando. >> Sim, é uma boa pergunta. Vou repetir a pergunta para que todos possam ouvir. A demonstração mostrou, obviamente, um exemplo bastante artificial, em que o foco são apenas os pull requests. Então, a

26:20 pergunta é: como escalar isso? Como fazer isso com várias coleções, várias tabelas etc.? Você pode adicionar mais uma etapa com um LLM, em que as coleções do schema têm pequenos resumos e descrições. Então, dependendo da consulta, você carrega o schema certo para ela. Os LLMs são surpreendentemente bons nisso. Não eram há um ano, mas agora são muito bons. Essa é uma maneira de reduzir o tamanho do contexto

26:50 e, assim, lidar com a sua pergunta sobre como escalar. Havia outro aspecto da escalabilidade que interessava a você? >> Obter todos os dados e, imagino, parte disso é o custo. >> Sim, a vivacidade e essas coisas também. >> Quanto tempo leva? Que dados eu deveria escolher para incluir nisso? >> Sim, é uma boa pergunta. Na Unblocked, estamos ingerindo conteúdo continuamente. Recebemos callbacks de webhook para todos os eventos, por exemplo, nos PRs. Então, sempre que há uma alteração, recebemos esse

27:21 evento de webhook, ingerimos o conteúdo, o rem… e o armazenamos no banco de dados. Isso é realmente uma questão de sistemas distribuídos: como escalar esse processo do ponto de vista da ingestão. O armazenamento é a mesma coisa. Então, sim. >> Talvez isso deixe a questão mais concreta. E se você dissesse, por exemplo: “Estas são as três principais fontes de dados”? Parece que alguém mencionou o GitHub, talvez algo… >> O Slack, com certeza. Muitas das perguntas sobre “por quê” e as tomadas de decisão acontecem no Slack. As pessoas, no contexto desse tipo de consulta estrutural, normalmente pensam em conversas que tiveram no passado. Aí podem consultar a Unblocked e dizer: “Ah, sim, mais ou menos três semanas atrás, eu estava conversando com fulano”. E esse é um caso perfeito para consulta estrutural. Sim, eu diria que o Slack é a fonte mais importante para perguntas sobre “por quê”. Muitas das decisões sobre “por quê”

27:52 também ficam registradas nos PRs. Os PRs contêm todo esse histórico organizacional nos comentários, e isso é basicamente um buraco negro, certo? Então, você pode percorrer esses dados antes de disponibilizá-los e, de certa forma, minerá-los em busca de insights interessantes. Por exemplo, na Unblocked, criamos o que chamamos de memórias de boas práticas, que são sintetizadas a partir de comentários em PRs anteriores. Faz sentido? >> Sim. Sim. Mais alguém? Sim.

28:24 >> Uma pergunta: diretamente sobre como isso está sendo construído. [fungada] >> Sim, quer dizer, com certeza dá para fazer

28:57 isso. Se você tiver uma consulta estruturada, se tiver uma tabela de consultas estruturadas, pode expô-la por meio de MCP. Dá até para fazer isso dinamicamente, atualizando a ferramenta sempre que o schema mudar nos bastidores. Esse tipo de coisa mostra o que acontece na outra ponta dessa chamada de MCP. Então, você poderia ter uma interface MCP que simplesmente recebe consultas em linguagem natural, por exemplo, e depois as traduz no backend, ou poderia oferecer uma interface direta para o banco de dados. Depende da interface que o cliente tem, mas, sim.

29:27 >> Sim. >> Sim. >> Sim. Certo. A segunda parte é melhor. O que você pensa sobre…

30:02 >> Como combinar isso, quer dizer, como unir as coisas? Deixe-me só confirmar que entendi a sua última pergunta. >> Sim. Acho que isso é… >> Não, de jeito nenhum. Não, não, são totalmente complementares. Sim, sim. Quer dizer, você pode ter uma busca de texto completo que faça esse tipo de coisa. Isso é busca de texto completo, certo? Ela identifica palavras-chave. Ainda é necessário algum mecanismo para fazer a busca propriamente dita por similaridade semântica

30:40 >> Como… quer dizer, como combinar isso? Ou, deixa eu só confirmar se entendi sua última pergunta. >> Sim. Parece que isso é como… >> Não, de jeito nenhum. Não, não, elas são absolutamente complementares. Sim. Sim. Quer dizer, você pode ter uma busca textual completa que faz esse tipo de coisa, sabe? Isso é busca textual completa, certo? Então, ela identifica palavras-chave. Você ainda precisa de algum tipo de mecanismo para fazer a busca efetiva por similaridade semântica.

31:13 porque aí vocês têm ideias e frases codificadas que não são necessariamente correspondências textuais. Então vocês querem esse tipo de correspondência conceitual, certo? Como eu disse no começo, a busca por similaridade é muito poderosa como ponto de partida. Por exemplo, vocês podem começar com uma busca vetorial e, a partir daí, dar acesso a ferramentas como esta, porque assim ela terá alguns dados iniciais interessantes e ajudará

31:43 a formular consultas para buscar e obter os dados. Então, sim, é isso que fazemos. E, desculpe, qual era a primeira parte da sua pergunta? >> Então vocês pegam, de qualquer forma, todos esses documentos, e eles acabam sendo convertidos em JSON. Assim, vocês podem combinar esses itens e procurar certos tokens

32:15 e então extrair os tokens, e é assim que vocês deduzem os tipos. Vocês podem examinar o código-fonte e vão ver que, pelo menos nesta iteração do algoritmo, a implementação é bem improvisada, certo? Ela faz coisas como verificar se a contagem de caracteres está entre dois e oito para as informações de tipo, e, para as enumerações, também procura padrões específicos. >> Sim. >> Sim.

32:54 Sim. >> Sim. >> Esse termo tem muitos significados, então vou confirmar se entendi exatamente a que você está se referindo. Você quer dizer busca híbrida no sentido de um provedor que faz busca por similaridade semântica e também busca lexical, e depois faz fusão de ranking?

33:34 Sim. Ah, sim. Sim. Não. Então, fazemos isso. Sim, a resposta é sim. >> Sim. >> Sim. >> Apenas tentativa e erro empírica. Quer dizer, não há uma solução fácil para isso. Nos bastidores, na Unblocked, nós estamos

34:05 usando muitos esquemas estáticos porque queremos garantir totalmente a correção. Essa foi apenas uma técnica que eu queria mostrar porque, para explorar dados, fazer experimentos ou conectar bancos de dados arbitrários, é uma boa técnica. Chegamos a isso por meio de algumas tentativas e iterações com clientes. Ingeríamos uma grande quantidade de conteúdo do repositório de documentos e recebíamos respostas de

34:37 clientes dizendo: “Ah, vocês não encontraram o que eu estava procurando”, e então investigávamos e descobríamos o motivo. Aos poucos, chegamos ao tamanho da amostra que fazia mais sentido. Sim, >> isso é absolutamente verdade. Sim, com certeza. Sempre vai acabar faltando alguma coisa. Sempre vai haver algum documento com algum detalhe peculiar. Sim.

35:09 Mais alguém? Achei que tinha visto uma pergunta ali. Ah, sim. Desculpe, pode repetir a primeira parte? >> Você mencionou que entende o esquema. >> Sim, o que fazemos é forçar a chamada de uma ferramenta — não para descobrir o esquema, porque isso acontece no início, mas para extrair nomes.

35:48 Temos um validador que monitora o que o agent está fazendo. Então, se ele não chamar a primeira etapa, que é a extração de nomes… Na verdade, há duas técnicas para isso. Uma é criar uma ferramenta que executa a consulta e aceitar um nome de usuário como argumento da ferramenta. Assim, você pode falhar imediatamente se o nome de usuário estiver incorreto ou malformado. Se quiser fazer a extração de nomes por meio de uma chamada de ferramenta, então

36:18 você precisa monitorar o que o agent faz. E, se ele não fizer essa chamada, basta inserir uma mensagem de usuário dizendo: “Você se esqueceu de chamar a ferramenta de extração. Faça isso agora.” Sim. >> Sim. Como vocês lidam com as mudanças?

36:52 Sim. >> Sim. Lembrem-se de que, neste exemplo específico, o esquema é completamente desconhecido e, conforme documentos são adicionados, esse esquema pode ser atualizado. Então, vocês podem, por exemplo, executar novamente a geração do esquema em intervalos definidos. No nosso caso, na Unblocked, o esquema

37:24 é estático e está vinculado à nossa base de código; nós controlamos o esquema. Então, se o esquema do GitHub mudar — o que raramente acontece, claro, porque isso teria implicações sérias para os clientes —, simplesmente adotaríamos estaticamente as mudanças feitas e, obviamente, faríamos o deploy disso por meio de CI. Sim. Mais alguém?

37:55 >> Ótimo. Acho que, nesse caso, podemos devolver um pouco do tempo. Obrigado. [aplausos] >> [música]

Transcrição original

[00:12] Okay. So, I’m I’m Peter. I’m from Unblocked. Um, over here is my colleague Brandon. And today, uh, well, first of all, I just want to talk a little bit about what we do. So, uh, we build a context engine. Our company’s name is Unblocked. And uh we deliver organizational context to humans and increasingly of course agents. Um so the session was originally a couple hours. It’s it’s now one hour so it’s quite condensed. U which means that I’m going to step through the workshop pretty quickly. If you don’t

[00:43] get uh you know all the steps nailed down as we go don’t worry about it because the repos up online um and you can run through it at your leisure um afterwards. Um, so the thesis here is that rag and I’m just going to say that rag in our parlance today is going to be semantic similarity search or vector retrieval. Okay, rag is only half of retrieval and today we’re going to build the other half which is turning na natural language into real database queries.

[01:14] So here’s the again the QR code for setup um if people haven’t already done so. I’m gonna now skip um on to the next thing and I’m just going to briefly bring up hopefully that renders. No, it won’t. Of course. Give me one second to switch. Whoops. And hopefully people can see this. Uh this is the repo here. So setup steps are pretty simple. Um there are a few sort of uh dependencies up here, prerexs

[01:46] that that uh you’ll need to run through. Um and the the course throughout the course of the workshop, we’re going to be running through a series of pull requests uh and the network is basically gone or at least isn’t running properly. Let’s try this one instead. Well, the good thing is we don’t need

[02:18] network for this talk. Um, so hopefully you got everything before we started. Um, because this one’s obviously not going to work. But at any rate, uh, we’re going to be following a series of six pull requests and they stack on top of each other. So, I’ll be There we go. I’ll be referencing these as we go. Um, and I’ll just go back to here so that everyone can see that. And back to the keynote. Now I’m gonna have to extend it again. Sorry.

[02:58] >> There we go. All right. Hopefully people can see that. Great. So um our agents need context and context is scattered across every tool that engineering teams live in. So you’re going to find it in PRs, review comments, um issues and tickets like in linear and jura docs [clears throat] and wikis, notion confluence, and of course in conversations and places like Slack and Teams. And all of that is semantically

[03:28] queryable, but it’s it also has structure. It has authors, dates, uh, states, labels, relationships, etc. And you know, the the instinct I I love to say this like even two years ago is ancient history in the realm of AI, but the instinct even two years ago was let’s just dump this all in a vector store and retrieve it and rerank it and hopefully we get the right thing. Um, but that’s that’s not going to work. So I’m just going to step back and and kind of relate this to the larger discussion about context.

[03:59] um in in the context of a context engine that serves organizational context um this is this is made up of more than just code as I said we’re connecting everything together so the scattered context uh on the left in all your code and PRs docs etc goes in and the idea is to get you know grounded context that relates to each other out the other side that’s specifically tailored to the task at hand um and in that model uh we have to care not just about the semantic relationships, but of course the

[04:30] structural relationships that connect all the data. So again, rag is about embedding the query, finding docs with similar meaning, and then we take that stuff and we stuff it into the prompt, right? Well, um, that shines for content questions like find the code, find the PR that changed it, find the Slack thread that debated it, but um, and if you wrap it in an agent loop, you can get pretty far with that. And you can also wire this thing up to like

[05:02] um, you know, tools that can recurse files and it acts as a good jump off point. you get a good semantic head start and then from there your agent can recurse over the actual file system in GitHub um and you can get pretty far with that. But in our experience um our this is not really the way things go in practice. engineers often ask questions like this PRs that I merged last week or my team merged last week. Um they’re they’re basically, you know, hunting for something in particular and they know

[05:33] where the starting point is, but they don’t know where the destination is, but they do know the relationships. So, as an example, PRs I merged last week, let’s think about this in a rag context. you’d you’d you know embed that sentence, you’d find the nearest vectors, you’d rerank it top K. Uh you get PRs that mention merging about a talk last week, but uh you wouldn’t get the actual relationships like the author, the merge state, um and whether

[06:06] it was merged last week actually. So what you could end up with is the wrong answer where you pull up PR that’s semantically related but it was merged three years ago. Um and so that doesn’t actually answer the question because there’s a structural there’s a temporal aspect to that question. And so retrieval has two halves here semantic and again today we’re going to be talking about this structured queries. And here’s the key. We’re going to take

[06:36] uh the model doesn’t actually answer the question in this paradigm. It writes the query that accesses the database. Okay. So, um it would be naive to say that generating the query is the only thing that we have to do. Um in order to generate the query and to do it reliably um and and to take care of maybe even some security concerns, we need to look at all four of these points here. So that first of all the LM needs to be

[07:06] aware of what the schema is before uh creating the query. It needs to understand uh some of the relationships in the data. So for example, if you pass a natural language query that says show me Peter’s open PRs, um then it’s not going to know what to do because it’ll synthesize a query that says Peter when really the GitHub login name might be different. So it needs to be able to map that across. Um, and of course you’re going to have some uh untrusted queries coming out the other end. Um, maybe

[07:38] using the function operator in the in parlance which might execute JavaScript directly on the server and we probably don’t want that. Um, and then finally, if there are errors the first time around, we want to be able to self-correct those things. So here’s here’s what this looks like in one single shot. What we want is something that looks like this. Um it it maps uh my colleagueu’s name is Rashine. His user login name is is Rashab. Um and then we want to be able to map things like the state and get maybe uh

[08:10] operators like limit and sort. So uh this is what we’re going to build. We’re going to start with a full UX, a stubbed engine, um, that is not capable to start with, and we’re going to gradually build this up. And then at step three, the thing will come alive. And so we’ll actually be able to issue queries to it and see what it does. And uh, if you hadn’t seen that before, now is another good time to scan that

[08:40] and get it in. I’m here to help you. >> Yeah. >> Yes. Any repo is fine. Doesn’t matter which one. Um and if if you want to take a shortcut, you can just point an agent at the thing and let it set everything up

[09:12] for you. That works. Okay, let’s move. So, this is what we’re going to do to start with. Um, by now you you probably should have run this ingestion thing. Don’t worry if you haven’t. Um, again, like you can revisit this at the end. I’m just going to quickly show what the the kind of barebones interface looks like for this thing. So, now this thing is running. Now, if I type anything in here, this is obviously not going to work. Um, and what you should see is something like that. Um,

[09:44] there’s also a tab for chat. This is a fully implemented agent uh that can uh do work for you. So, we’ll come back to that in a sec. And so, this this is the contract in the code if you wanted to read. Um, we’re going to don’t worry about this. We’re going to skip through this. Um, but basically like that’s the entry point and we’re going to be building around that. So the first thing we want to talk about is schema discovery. Um during

[10:15] ingestion, if you if you look at the way that the ingestion script worked, it it actually had to build out a schema in order to download the content and store it. Um but you can imagine that you may not know the schema. So the ingestion may be happening in a service elsewhere and you want to build like a fully dynamic schema discovery engine. Um schemalis. So there’s no schema to read. um unlike you know PG or something where we could read the table definitions. Um so what we’ll do is we’ll sample the documents to infer the

[10:46] schema and that’s the whole trick. So the we’re just going to reconstruct it. We’re going to take um all the nodes and merge them down. So this is going to sample 300 documents, collapse it into a single tree. uh nulls are skipped because missing fields won’t be able to constrain the type. And then uh we’re going to do something kind of interesting here with enum types.

[11:17] And so now uh with with enum types, we can do an interesting sort of procedural trick. This is just one thing. I would suggest using procedural tricks to to do this type of thing because you could pass it through an LLM and do extraction and that works u but it’s fairly non-deterministic. So you always need some kind of structural um harness around it that is running procedural code to either validate the things that you pull out or to actually do the extraction itself. And in this

[11:48] sample project um it’s the procedural code that’s doing the extraction. And let’s go and show that. So we’ll do and then run it again. And now what we get is this thing here. So the schema ran uh the the discovery process ran and it created a schema for us that outlines what the pull request

[12:19] schema looks like in GitHub. It even created some indexes for us. Now, this is like marked down on purpose because we’re going to take this schema and pass it to the LLM when we synthesize the actual uh query. Now, the second step is the thing that I referred to a few slides ago about identity resolution. And this is because like my lo GitHub login um is similar

[12:50] but it’s not quite the same. And so if I were to ask a question like um hey find all the PRs by Peter um it if without doing some sort of identity mapping it would just say you know it would just match across Peter and it’s not going to find anything. So we have to be able to solve that. [snorts] And again, um, we’re going to do this. At first blush, this seems like we’re coupling to the schema a little bit here. Um, but you know, it is absolutely

[13:22] possible to determine this dynamically. And you can have uh your LLM essentially synthesize the mappings for you. So, but in in our case, we’re just going to do these simple little tricks. Um very simple sort of fuzzy matching. Um Levenstein distance is fine. You can just like match across the names and uh there you go. Oh, actually I want to show you one thing before we get on to that one.

[13:54] So let’s do the same thing again. We can pop up >> Oh yeah, I’m sorry. Absolutely. Tell me when it’s big. Good. Thanks. Good call out. Okay. So, let’s run our thing again. And now, um Oh, actually, I have to I have to wait till the next step. I apologize. That’s not going to be wired up just yet. So,

[14:24] we’ll go on to the thing that will really give us the payoff here, which is step three. So this is the actual query plan step and it’s it’s it’s arguably sort of the simplest part. It’s the LM part. Um and what we do here is we pass the schema give it a tool and force it to call that tool for name extraction and synthesis. Um and then it will execute the plan.

[14:56] There’s one other thing which is the temporal aspect. uh LLMs are actually pretty good about generating temporal queries if you pass them the current date and time. So that’s another important thing to do in the in the prompt. And so here this is the name extraction part. We’re going to force that tool call to happen in this case.

[15:28] And at this point I am going to show you the the payoff for this. So there we go. So now I can do things like this. open PRS by Peter and bam. So what we’ll see here is that

[16:00] it uh generated this um this match clause and uh you can’t see it from here but it it mapped Peter to my GitHub user login puery and generated the query and that’s the outcome. So that’s cool, but um we need to get on to the next step because even though we are able now to query the data, we have some safety concerns. Um it could be the

[16:33] case that it produces untrusted output and so you know it could use the wear or function clauses and literally run JavaScript on the server which means that this is now a prompt injection point. Um, you could also have hidden fields in your schema like ID or metadata fields that leak internals. So, we need to sanitize um, and we don’t deny list these things. We allow list them. So, it’s deny by

[17:04] default. You want to create basically an allow list of allowed operators and uh, you know, potentially an allow list of allowed fields. In our case, this is dynamic schema discovery, so we’re not going to do that. Um, but we could have some fields that we know about like metadata fields. And this is a a useful thing for like tenant uh tenant isolation. So if you have a a uh collection that houses multiple tenants, I don’t recommend that. you should probably separate your collections by

[17:34] tenant, but if you did, then you could have a metadata field that contains the tenant ID and you would want to hide that no that um information from the LLM, but also validate the output. So if it outputs that metadata field, you need to wipe it out and then you need to inject your own metadata field underneath.

[18:05] And again, like technically this is it’s not actually that difficult to do. You just have to write the code. It’s all procedural. Um I I wouldn’t recommend using LLMs for this part. And so again, allow list, don’t deny or deny everything, I should say. Now the last part is um we’re going to

[18:35] this kind of dovetales into the next step. At the end of validation we’re obviously going to return an error and it’s going to get dumped out. And right now that error is just it’s just there. We’re not going to do anything with it just yet. But I will show you now what this looks like. Um, oops. Stay on that one and

[19:07] run our service. So now I’m going to write run another query that checks for authentication in the title and we’ve disallowed regular expressions. So now what we can see is that it rejects the query. And finally, this is the thing that kind

[19:38] of ties it all together is the retry loop. The plan can fail in a couple of different ways, right? Um, it can fail validation. So maybe the uh the LM actually outputs things that are illegal according to our validator. Or it could actually fail during execution. Um, so for example, let’s imagine that it it mixed an inclusion exclusion project.

[20:09] Um, then that’s obviously going to fail. And then but we can self-correct. We can take that error and pass it back into the LLM and say hey that was wrong. Um maybe you can do better up to some number of max attempts of course. So I’m going to show now what this looks like back over to our project so we can punch up a level. Whoops.

[20:41] Sorry. You have to forgive me. I actually have to read this off of the screen out here. Okay. So now if we run that same query. Perfect. So, what we can see is that it

[21:11] took several attempts to get it right. Um, by the third attempt though, there’s a bit of a problem here because we said no regular expressions, no FTS. Um, so now it said we’re going to just use match, but now it’s an exact match. So it tries to find authentication fails which means there’s one more thing that we can do which is this.

[21:42] We’ll add full text search. It’s pretty basic. Um we need to create an index obviously and we’ll combine it with author and state filters uh in the same match. And so now we should be able to answer a question like this. And let’s see what happens. And see if it is actually going to do what I said it’s going to do.

[22:29] Bam. There we go. And so now the the final payoff here is if we go into the chat tab, we can ask some sophistic more sophisticated questions that um you know an agent can actually reason about behind the scenes. So you can say things like um did we work on anything authentication related last week.

[23:10] So here we can see that it generated the query. Now it’s pulling the data and kind of reasoning about it. There we go. That’s it. So, just a quick summary of what we built. We’re basically like reaching the end.

[23:41] There’s going to leave lots of time for questions. So just to recap here, um there are questions that that rag can’t touch. All those structural questions around things like state or temporality. Um you don’t get the right data out when you ask those types of questions with rag, traditional rag. So the same engine behind the query playground and the chat agent, uh they’re they’re the same. So if you guys want to play with that after, go ahead. Um it’s it’s the same backing thing. The

[24:11] only difference is of course that uh the chat agent actually does reasoning whereas the query interface is just for queries. So just to to recount on this here are the reusable ideas here. Schema aware prompting dynamic schema discovery identity resolution validation and error retries. The error loop is actually one of the most important things.

[24:45] And so we built something that’s capable of filtering, providing aggregations, it’s time scoped, has full text search. Um, it’s validated, it self-corrects, and it powers a full-blown chat agent. So you could take this into your organization and just deploy. I I would recommend maybe working a little bit more on the validation harnesses before deploying this internally, but um yeah, it’ll it’ll answer all your questions about your PRs. And that’s it. So, we’ve left lots of

[25:17] time for questions now. [laughter] Did Did everyone uh was everyone able to actually set it up? Just curious. No. Okay. If if you want uh you can come and fetch Brandon and I afterwards, we’ll just kind of linger outside here. Oh, at the and at the P16 booth as well. Yeah, but that that starts later today at around four o’clock and we’ll be there all week. >> Cool. Any questions? >> Yes, >> I have a question. I think you did a great job breaking down like basics.

[25:49] >> Yeah, >> a lot of my mind goes like okay so at scale how does for example you you generate the schema and you put it into the system prompt how does that work at scale? It’s like also depending on the size of your company, how are you fitting all this data? How do you choose what data and like how long does it take to process all this? What’s the cost? That’s where my mind is. >> Yeah, it’s a good question. So, you know, um I’m just going to repeat the question so everyone can can hear it. The demo showed obviously a fairly contrived example where you’re just focusing on pull requests. Um and so the

[26:20] question is how do you scale this? Like how do you do this across multiple different collections, multiple different tables, etc. Um, so you you can add uh another LM step on top where uh this the schema collections have tiny little summaries and descriptions and then uh depending on what the query is, you can load the right schema for that query. LMS are surprisingly good at this. They weren’t a year ago, but now they’re very good at it. Um, so that’s kind of the way to shave the context

[26:50] thing down. And that’s to your question about scaling things out. Um, was there another aspect of scaling that you were interested in? >> Getting all the data in and I guess like part of that is like cost. >> Yeah, it’s livveness and stuff too. >> How long does it take to do like what is what data should I pick to put into this? >> Yeah, it’s it’s a good question. So unblocked um at unblocked like we’re continuously ingesting content. Uh we get web hook callbacks for all the events for example in in PRs. And so every time there’s a change, we get that

[27:21] web hbook event, we ingest the content, we rem um and store it in the database. Um that that’s just really just like a distributed systems question about how you scale that out from an ingestion level. Um you know, storage, same thing. So yeah, >> so maybe this will make it more concrete. So what if you would say like these are the top three data sources like someone seems like GitHub maybe like something >> um so Slack for sure a lot of the like

[27:52] why questions and and decision- making happens in Slack um people uh in the context of this sort of like structural query um people usually think about conversations that they’ve had in the past um and they’ll be able to query unblocked and say Oh yeah, you know, roughly three weeks ago, I was having a conversation with so- and so. And so that that’s a perfect thing for structural query. Um yeah, like I would say that um Slack is the most important for why questions. Um a lot of the why

[28:24] decision-m is also embedded in PRs. PRs uh have all of that like organizational history in the comments and that’s just basically black hole, right? So uh you can basically run over that data before you serve it and and kind of mine it for interesting insights. So for example at unblocked we we create these things called best practice memories which are distilled from PR comments in the past. Does that make sense? >> Yeah. Yep. Any else? Yeah.

[28:57] >> Question. directly into how this building. [snorts] >> Yeah, I mean you you can definitely do

[29:27] that. So if you have a structured if you have a structured query table, you could express that through MCP. You can even do that dynamically by updating the tool every time the schema changes behind the scenes. Um this this type of thing is showing like what happens on the other end of that MCP call. So you you could you know have an MCP interface that just takes natural language queries for example and then translate that all on the back end or you could provide a direct interface to the database. It depends on like what the customer interface looks like, but yeah. Yeah.

[30:02] >> Yeah. >> Yeah. >> Yeah. Yep. Second part is better. Thoughts around

[30:40] >> uh how to mean how to combine it or let me just make sure I understand your last question. >> Yeah. feel like this is like >> No, not at all. No, no, they’re absolutely complimentary. Yeah. Yeah. I mean, you can have a full text search that does this kind of um you know, like that’s full text search, right? So, it’ll identify keywords. You still need some kind of mechanism to to do like the actual semantic similarity search

[31:13] because there you all have ideas and sentences that are encoded that aren’t not ne necessarily textual matches. So you want you want that like conceptual matching, right? So as I said um at the beginning like there’s similarity search is actually really powerful for jump off points. So you can for example start with a vector search and then from there give it access to tools like this because then it’ll actually have like some interesting starting data and help

[31:43] it form queries to go and and fetch the data. So yeah that that’s that’s something that we do and so sorry the first part of your question was >> so you take um you take you know in in anyways like these are all documents and they’re they kind of like form into JSON so you can merge those things down and look for certain tokens

[32:15] and then you you know, extract the tokens and then that’s how you distill the types. So you you can look through the source code and you’ll see that at least like this iteration of that algorithm is pretty hacky, right? It’ll do things like look to make sure that the character count is between two and eight for uh for type information and then for enumerations it’s it’s looking for particular patterns as well. >> Yeah. >> Yeah.

[32:54] Yes. >> Yeah. >> Now, that that’s a very overloaded term, so I’ll just make sure I understand exactly what you’re talking about. Do you mean hybrid search in terms of um a provider that does semantic similarity and then also does a lexical search and then does rank fusion?

[33:34] Yeah. Oh, yeah. Yeah. No. So, so we we do that. Yes. The answer is yes. Yeah. >> Yeah. >> Yeah. >> Uh just empiric empirical trial and error. And so I mean there’s there’s no easy solution to this. Um be behind the scenes like at unblocks we’re we’re

[34:05] using a lot of static schemas because we want to get the correctness absolutely nailed down. This this was like a just a technique that I wanted to show because um you know for exploration of data or experimental um uh for experiments or either to wire up like arbitrary databases this is a good technique. So we we got this through some trial and iteration with customers and you know we we’d ingest a whole bunch of contents from the document store and we’d get responses back from

[34:37] customers that said oh you missed the thing that I was searching for and we’d dig into it and we’d figure out why and we kind of got to the sample size that made the most sense. Yeah, >> it’s absolutely true. Yeah, definitely. You’re always actually gonna you’re going to miss something. There’s always going to be some document that has a little edgy thing. Yeah.

[35:09] Anyone else? I thought I saw a question over there. Oh, yep. Sorry, can you say that first part again? >> There’s mention that you understand the schema. >> Uh yeah, what we do is we force a tool to be called for not for schema discovery because that happens at the start. It’s for name extraction.

[35:48] we so we have a validator that watches what the agent’s doing. So like if it doesn’t call the the first part which is name extraction. Um so there’s there’s actually two techniques for this. One is you create a tool that does the the query and as an argument to the tool you accept a username. So you can fail right there if the username is not correct or malformed. Um, if you want to do name extraction uh via tool call, then you

[36:18] have to watch what the agent does. And then if it doesn’t call it, you just basically insert a user message that says you forgot to call the extraction tool. Do so now. Yeah. >> Yeah. How do you handle the changes?

[36:52] Yeah. >> Yeah. So remember like for this particular example the schema is is completely unknown and so as documents get added um that schema could update. So you your your choice is either you know on a sampling interval you you rerun the schema generation um in our case at unblock the schema is

[37:24] is static and it’s tied to our codebase and we control the schema actually. So if the schema of if GitHub decides to change the schema um that of course rarely happens because that would have serious implications for their customers but if they did then we would just adopt whatever changes are made statically and then obviously deploy that through CI. Yeah. Anyone else?

[37:55] >> Awesome. I think we can uh reclaim some time in that case. Thanks. [applause] >> [music]