Como as respostas são mantidas fundamentadas
Um assistente de documentação só vale a pena se não inventar informações. Uma resposta errada em um tom confiante custa mais do que não ter assistente algum: o leitor age com base nela, e sua fila de suporte sofre as consequências um dia depois.
Portanto, a pergunta importante não é "ele usa IA" — é com base em que o modelo pode responder e o que acontece quando a passagem correta não está diante dele. Esta página é a resposta, no nível de detalhe que você obteria ao ler a implementação.
O que você obtém#
Cada resposta que o leitor vê é escrita com base no texto da página que o Docsbook buscou para aquela pergunta específica, nessa solicitação. O leitor acompanha tudo acontecendo: o widget imprime Found N results e uma linha Reading <page> para cada página aberta, cada uma sendo um link para a própria página. Abaixo da resposta há uma lista de citações, e uma citação só permanece se o modelo tiver citado o caminho daquela página no texto da própria resposta ou se o servidor tiver realmente buscado aquela página para essa pergunta. Um caminho inventado pelo modelo e nunca citado não pode se tornar uma citação.
Quando a recuperação não encontra nada relevante, o modelo é instruído a dizer que a documentação não aborda o assunto, em vez de compor algo plausível. Essa recusa é registrada, não descartada — ela se torna uma linha no relatório de perguntas não respondidas e um webhook chat.no_answer, que é o sinal que informa qual página você deve escrever em seguida.
Como uma resposta é produzida?#
Sete etapas, nesta ordem. Cada etapa abaixo é uma ramificação real na solicitação, não um diagrama.
1. Seus documentos são divididos em unidades e depois incorporados#
A indexação automática é executada na granularidade de títulos: uma unidade por seção de uma página. O texto enviado ao modelo de incorporação é a trilha de navegação do título da seção seguida pelo corpo da seção — Billing > Refunds antes do texto sobre reembolsos — porque uma seção chamada "Limites" significa algo diferente sob "Webhooks" do que sob "Chat de IA", e o vetor precisa carregar essa diferença. Cada unidade é limitada a 6.000 caracteres. A granularidade no nível da página e da linha também existe no indexador; o caminho automático usa títulos.
A identidade de uma unidade é o caminho da página mais a âncora do título. As âncoras se repetem dentro de uma página — um registro de alterações pode conter quarenta títulos ### Fixed — portanto, uma âncora repetida recebe um sufixo ordinal. Sem isso, cada uma dessas seções seria a mesma unidade, e a gravação entraria em conflito.
2. As unidades tornam-se vetores, e unidades inalteradas não custam nada#
Os embeddings são openai/text-embedding-3-small, 1.536 dimensões, solicitados por meio do OpenRouter em lotes de 96 unidades por chamada. A coluna de armazenamento é um vector(1536), e um modelo que retorna uma largura diferente é rejeitado imediatamente, em vez de ser gravado e ficar silenciosamente incompatível mais tarde.
Cada unidade contém um hash de conteúdo de sha256(model + NUL + text). Em uma reindexação, uma unidade cujo hash já está armazenado é ignorada, portanto editar uma página custa o embedding de uma página, não o corpus. A estimativa exibida antes de uma execução tem uma contagem exata de unidades (o divisor é determinístico e já foi executado) e uma contagem aproximada de tokens de characters ÷ 4 — considere esse valor como ±30%, e é por isso que ele é apresentado como uma estimativa, e não como o preço.
3. A reindexação acompanha seus commits#
Cada commit na sua documentação enfileira uma reindexação. Uma execução enfileirada é processada por um executor em segundo plano a cada dois minutos, e não por um callback anexado à resposta que já foi enviada — um callback é exatamente o que costumava morrer durante a execução e deixar para trás um índice marcado, mas vazio. Commits consecutivos dentro de cinco minutos são agrupados em uma única execução, pois um fluxo de publicação faz commit do conteúdo, depois da navegação e, por fim, da identidade visual.
A decisão de usar recuperação semântica é baseada na presença de vetores, nunca em um registro de data e hora de "última indexação". Um registro de data e hora é uma alegação; uma linha é uma prova, e essa diferença é todo o abismo entre "a pesquisa semântica está ativada" e "a pesquisa semântica está funcionando".
4. A recuperação executa ambos os recuperadores, todas as vezes#
| Recuperador | Quando é executado | O que contribui |
|---|---|---|
Páginas mencionadas pelo leitor @ |
Sempre que presentes | Forçadas para o início da lista |
| Pesquisa vetorial | Sempre que o workspace tiver vetores e o toggle do proprietário estiver ativado | Até 3 páginas distintas |
| Pesquisa de texto completo do Postgres | Sempre, junto com a pesquisa vetorial | Pelo menos 2 posições, mais quando a pesquisa vetorial encontra menos |
| Pesquisa lexical do grafo de documentos | Somente quando ambas as opções acima não retornarem nada | Até 4 páginas |
| Loop de pesquisa agêntica | Somente quando tudo acima não retornar nada | Até 2 páginas |
A pesquisa vetorial obtém as 6 linhas mais próximas por distância de cosseno, converte-as em uma similaridade de 1 − distance, descarta tudo abaixo de um limite de similaridade de 0.25, remove duplicatas por página antes de reduzir para 3 (seis resultados frequentemente são seis seções de uma única página) e mantém sua posição de prioridade na lista final.
A pesquisa de texto completo não é um fallback aqui. Ela é executada em todas as perguntas e suas páginas são mescladas, com um limite para que vetorial + lexical nunca ultrapassem 5 páginas juntas. O motivo é medido em nosso próprio índice: para a pergunta "Que padrão de URL o Docsbook usa para servir meu site de documentação?", o trecho correspondente à página correta ficou em 48º lugar entre 1.341 trechos por similaridade de cosseno — 18 outras páginas tiveram pontuação maior — enquanto a pesquisa lexical o retornou como o principal resultado, porque a página contém literalmente os termos da consulta. Nenhum valor de top-k corrige isso; a própria classificação estava errada para essa consulta. Um resultado vetorial não vazio, mas incorreto, é a falha que esta mesclagem existe para corrigir, e uma regra de "executar a pesquisa lexical somente quando o vetor estiver vazio" não consegue detectá-la.
As duas últimas linhas da tabela são para corpora sem nenhum índice. O loop agêntico fornece ao modelo uma ferramenta search_docs e permite que ele faça novas consultas com diferentes formulações por até 4 interações, com temperatura 0, antes de ter que se comprometer com no máximo dois caminhos de página — da mesma forma que você usaria o grep em uma base de código depois que sua primeira tentativa não encontrou o que procurava.
5. As páginas são obtidas e recortadas a partir do final#
Cada página selecionada é obtida do seu repositório no ramo padrão e inserida no prompt com seu caminho e título em uma linha de cabeçalho. Uma página com mais de 12.000 caracteres não é truncada a partir do início: os primeiros 9.000 caracteres e os últimos 3.000 são mantidos, com a omissão indicada entre eles. As políticas de reembolso, as seções "Relacionados" e de solução de problemas ficam no final de uma página; portanto, o truncamento do início elimina exatamente a parte sobre a qual uma pergunta provavelmente trata. A página em que o leitor está no momento é incluída separadamente, recortada para 8.000 caracteres.
6. O modelo é restringido antes de escrever#
O modelo padrão do chat do leitor é openai/gpt-4o-mini — uma janela de contexto de 128.000 tokens e um limite de saída de 16.384 tokens, de acordo com a referência de modelos da OpenAI. Você pode escolher um modelo diferente por projeto; consulte Chat de IA.
A mensagem do sistema é curta e pode ser substituída por você. As regras de fundamentação ficam no bloco de instruções que acompanha o conteúdo, e são específicas porque cada uma corresponde a uma falha que aconteceu:
- Fundamente-se apenas no conteúdo fornecido. Nunca recorra ao conhecimento pré-treinado para definir um termo ou preencher uma lacuna que a documentação não aborde.
- Não afirme que algo está ausente quando o fato está presente. Leia novamente as páginas fornecidas antes de dizer que algo está faltando — inclusive quando o fato estiver em uma página que também aborde um recurso pago ou opcional.
- Mantenha distintos os comportamentos gratuitos e pagos. Não misture um detalhe da página paga à descrição do comportamento padrão.
- As páginas foram encontradas por pesquisa, não verificadas por uma pessoa. Confira cada página em relação ao aspecto específico solicitado, não apenas à sobreposição de palavras. Uma página sobre subdiretórios de localidade contém as palavras "padrão de URL", mas não responde a uma pergunta sobre a URL padrão.
- Fique atento à pergunta mais restrita. Se uma página responder a uma versão qualificada da pergunta (um idioma, um plano, um complemento) e a pergunta não tiver esse qualificador, essa página está respondendo a outra coisa.
- Perguntas de configuração exigem uma frase exata. Para "como configuro X", encontre a frase que indique um caminho de menu, botão ou etapa concreta para X. Se não houver nenhuma, diga que a documentação não descreve uma integração integrada de X — uma menção a X em outro lugar ou um mecanismo genérico que poderia, em teoria, ser conectado a X não constitui um fluxo de configuração.
- Os pré-requisitos são obrigatórios e declarados duas vezes. Examine a página inteira em busca de um plano, função, etapa anterior, versão ou cota necessária — a documentação os coloca em uma linha curta em negrito no início, que é fácil de ignorar ao passar para as etapas numeradas. Uma verificação final imediatamente antes da geração relê o início de cada página, porque um pré-requisito declarado apenas na introdução da página não compete com nada local quando o modelo já chegou à subseção relevante.
A resposta é solicitada como JSON estrito — um corpo em markdown e um array refs — e transmitida a uma temperatura de 0,3.
7. As citações são anexadas pelo servidor, não confiadas ao modelo#
Esta é a etapa que determina se uma citação significa alguma coisa.
| O modelo fornece | O servidor faz |
|---|---|
pagePath |
Mantém a referência somente se esse caminho tiver sido citado inline no próprio marcador [ref:…] da resposta ou for uma página que o servidor realmente buscou. Um caminho que o modelo não leu nem citou é removido antes que o leitor o veja. |
pageTitle |
Usado como rótulo do link |
headingText, copiado literalmente da página |
Recalcula a âncora por conta própria, com o mesmo gerador de slugs usado pelo renderizador |
| (nada) | O id da âncora nunca é solicitado nem aceito do modelo |
A regra da âncora não é preciosismo. Uma regra de slug escrita manualmente ("minúsculas, espaços para hífens, remover caracteres especiais") diverge do renderizador em relação à pontuação ASCII simples — Edge cases & errors torna-se edge-cases--errors na página e edge-cases-errors em uma regra feita manualmente — e reduz um título não latino a nada além de hífens. Um único responsável calcula essa string; todos os demais a consultam.
O que acontece quando nada relevante é encontrado#
Nada é inventado para preencher a lacuna. Quando todos os retrievers retornam vazios, nenhuma página é anexada, nenhuma linha Found N results aparece, e a instrução deixada para o modelo é dizer claramente que o conteúdo fornecido não responde à pergunta.
A recusa é então tratada como dado:
- O texto da resposta é analisado em busca de um padrão de ausência de resposta; uma correspondência dispara um webhook
chat.no_answerjunto com o eventochat.question_askedcomum. - A pergunta aparece em Perguntas sem resposta, que é a visualização filtrada de todas as perguntas de chat registradas cuja resposta falhou nessa verificação.
- Os leitores podem avaliar negativamente uma resposta no widget; essas avaliações aparecem como uma contagem de rejeições por página nas suas análises.
Uma lacuna na sua documentação vale mais como uma linha de relatório do que como um parágrafo inventado — essa é a troca em torno da qual toda esta página foi criada.
Por que esta é a maneira correta (evidências)#
| Regra no Docsbook | Por que funciona | Fonte |
|---|---|---|
| Responda com base nas páginas recuperadas, não na memória do modelo | Modelos aumentados por recuperação "geram uma linguagem mais específica, diversificada e factual do que uma linha de base seq2seq paramétrica de última geração" | Lewis et al., 2020 — Geração aumentada por recuperação para tarefas de PLN intensivas em conhecimento (NeurIPS) |
| Uma citação só é válida se indicar uma página que foi realmente lida | Medido em quatro mecanismos de busca generativa, "apenas 51,5% das frases geradas são totalmente fundamentadas por citações" e "apenas 74,5% das citações fundamentam sua frase associada" — uma citação que o sistema não verifica não é evidência | Liu, Zhang & Liang, 2023 — Avaliando a verificabilidade em mecanismos de busca generativa |
| Execute uma busca lexical em todas as perguntas, não como alternativa de reserva | Em mais de 18 conjuntos de dados de recuperação, "BM25 é uma linha de base robusta" em configurações zero-shot, enquanto os recuperadores densos "frequentemente apresentam desempenho inferior… destacando o considerável espaço para melhorias em suas capacidades de generalização" — seu corpus está fora do domínio de qualquer modelo de embeddings | Thakur et al., 2021 — BEIR |
| Vetores de 1.536 dimensões, unidades de 6.000 caracteres | text-embedding-3-small produz 1.536 dimensões e aceita 8.192 tokens de entrada; uma unidade limitada a 6.000 caracteres permanece dentro desse limite, com espaço para a trilha de navegação |
OpenAI — Guia de embeddings |
| Limite o prompt a cinco páginas e corte as páginas longas a partir do final | O desempenho do modelo "é frequentemente mais alto quando as informações relevantes ocorrem no início ou no fim do contexto de entrada e se degrada significativamente quando os modelos precisam acessar informações relevantes no meio de contextos longos" — mais páginas não significam mais precisão | Liu et al., 2023 — Perdido no meio |
| Instrua explicitamente a recusa e registre-a | O ajuste comum por instruções "força o modelo a completar uma frase, independentemente de o modelo conhecer ou não o conhecimento"; é preciso solicitar a recusa | Zhang et al., 2023 — R-Tuning: instruindo LLMs a dizer "Eu não sei" (NAACL 2024) |
| A fundamentação reduz as alucinações, mas não as elimina | A anotação de aproximadamente 18.000 respostas RAG constatou que, mesmo com recuperação, "os LLMs ainda podem apresentar afirmações sem suporte ou contraditórias em relação ao conteúdo recuperado" | Niu et al., 2024 — RAGTruth |
O que medimos — e o que não publicamos#
Não publicamos nenhuma porcentagem de precisão para o chat do Docsbook AI. Não executamos um benchmark rotulado sobre corpora de clientes, e um número produzido com base em nossa própria documentação não diria nada sobre a sua. Citar um deles violaria a regra segundo a qual o restante desta documentação foi escrito.
O que existe em vez disso:
| Medição | O que ela faz | Onde aparece |
|---|---|---|
| Avaliador de respostas | Um LLM lê uma transcrição de conversa concluída (limitada a 8.000 caracteres) com temperatura 0 e retorna um veredito estrito {answered, reasoning} |
A coluna Respondida na aba Chat |
| Armazenado uma vez, nunca avaliado novamente | Uma transcrição não muda, portanto seu veredito também não — cada um é gravado uma vez e lido posteriormente | — |
| Limitado por solicitação | No máximo 6 novas conversas são avaliadas por carregamento de página, portanto um workspace com mil threads não avaliadas não paga por mil chamadas na primeira vez que alguém abre a aba | — |
| Detecção de ausência de resposta | Uma correspondência de padrão no texto da resposta, acionando chat.no_answer e alimentando Perguntas sem resposta |
Webhooks, Perguntas sem resposta |
| Indicadores por resposta | O próprio veredito do leitor sobre aquela resposta, contabilizado por página | Analytics |
| Rótulo de recuperação | O fluxo de cada resposta informa qual recuperador produziu suas páginas — semantic, fulltext, semantic+fulltext, doc_graph, agentic ou mentions |
O fluxo de resposta; verificável com uma chamada HTTP |
Essa última linha é deliberada. "A pesquisa semântica está ativada" não pode ser falsificado externamente, que é exatamente como um índice marcado, mas vazio, chegou a ser considerado funcional por meses. Nomear o recuperador em cada resposta torna a afirmação verificável por qualquer pessoa, inclusive você.
O Docsbook também executa duas suítes internas — um conjunto dourado de 40 casos que avalia qual ferramenta o modelo utiliza primeiro com temperatura 0, e uma suíte de cenários reais com verificações determinísticas e um avaliador LLM restrito. Ambas abrangem o assistente administrativo no seu painel, não o chat voltado ao leitor, e deixamos isso claro em vez de permitir que seus indicadores verdes sejam interpretados como uma alegação de qualidade sobre o assunto desta página.
Limitações#
- Nenhum índice de precisão publicado. Consulte acima. Considere qualquer número único de precisão de um fornecedor — incluindo o nosso, caso algum dia publiquemos um — inutilizável até que seu corpus, conjunto de perguntas e avaliador sejam publicados.
- A recuperação pode estar errada com confiança. O caso do 48.º entre 1.341 acima é nosso, em nosso próprio corpus. Combinar a recuperação lexical corrige uma grande classe desses casos; isso não os elimina. A recuperação também é menos confiável exatamente onde mais importa: trabalhos avaliados mostram que a recuperação ajuda mais em fatos menos populares, nos quais o modelo não tem nada memorizado para usar como alternativa (Mallen et al., 2023).
- O limite de similaridade de 0,25 é uma constante fixa, não ajustada por corpus. Um corpus com vocabulário incomum pode precisar de um limite diferente, e atualmente não há controle por projeto para isso.
- O filtro de citações é um OR, não um AND. Uma referência permanece se o caminho foi obtido ou se o modelo a citou no texto. Exigir ambos deixou
refsvazio em quase todas as respostas, porque os modelos preenchem o array e ignoram o marcador. A consequência é que um caminho que o modelo inventou e citou no texto passaria pelo filtro; apenas a metade obtida é fundamentada por construção. Em análise até que a metade inserida no texto também seja verificada em relação ao corpus. - A fundamentação não é uma prova de fidelidade. O servidor pode garantir que uma página citada foi lida; ele não pode garantir que toda frase da resposta decorra dela. Esse resíduo é o que o RAGTruth mede, e ele é real.
- O detector de ausência de resposta é uma correspondência de padrão em inglês. Uma recusa escrita em outro idioma não será reconhecida, portanto
chat.no_answere o relatório de perguntas sem resposta subestimam os números em sites que não estão em inglês. Em análise até publicarmos uma substituição avaliada. - Páginas muito longas perdem o conteúdo do meio. Uma página com mais de 12.000 caracteres chega ao modelo como início + fim, com o meio marcado como omitido. Um fato que exista apenas no meio de uma página muito longa pode não ser encontrado. Dividir essa página é a solução, e isso também melhora a página para os humanos.
- O comportamento do modelo depende da versão. O modelo leitor padrão, sua janela de contexto e seu comportamento de recusa podem ser alterados pelo provedor. O mecanismo nesta página é nosso; a conformidade do modelo com ele não é.
- A recuperação semântica precisa de vetores. Até que uma execução do índice seja concluída, a recuperação recorre ao texto completo e ao grafo de documentos. Isso é um chat funcional, não um chat quebrado — mas não é aquele descrito no estágio 4.
Relacionado#
- Chat com IA — o contrato: o que o assistente pode e não pode fazer.
- Pesquisa — o índice lexical compartilhado por este pipeline.
- Fontes — o que o assistente tem permissão para ler além das suas páginas.
- Hooks de chat — bloqueie uma pergunta ou forneça ao modelo um fato que somente os seus sistemas conhecem.
- Como o Docsbook comprova o que afirma — a regra segundo a qual esta página é escrita.