--- title: "Análise de Conteúdo Qualitativa com LLMs" output: rmarkdown::html_vignette: toc: true toc_depth: 2 vignette: > %\VignetteIndexEntry{Análise de Conteúdo Qualitativa com LLMs} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", eval = FALSE ) ``` ## Visão geral O módulo qualitativo do **acR** implementa um pipeline completo de análise de conteúdo assistida por modelos de linguagem (LLMs), seguindo as diretrizes metodológicas de Krippendorff (2018) e as recomendações empíricas de Gilardi, Alizadeh e Kubli (2023), que mostraram que LLMs modernas superam trabalhadores de plataformas em várias tarefas de anotação de textos políticos, **desde que guiadas por um codebook bem construído e validadas por revisão humana**. O pipeline tem sete etapas encadeadas: ``` ac_fetch_camara() / ac_fetch_senado() ← coleta ↓ ac_corpus() ← estruturação ↓ ac_qual_codebook() + funções de gestão ← codebook ↓ as_prompt() ← system prompt (opcional) ↓ ac_qual_code() ← classificação com LLM ↓ ac_qual_sample() + ac_qual_reliability() ← validação humana ↓ ac_qual_report() ← relatório reprodutível ``` A função `ac_qual_code()` aceita o argumento `chat =`, que recebe qualquer objeto `Chat` do pacote **ellmer** (Wickham et al., 2025). Isso permite usar qualquer provedor (Groq, OpenAI, Anthropic, Google Gemini, Ollama, Mistral, DeepSeek, OpenRouter) sem alterar a lógica de análise. Também suporta modelos locais via Ollama para pesquisas com dados sensíveis. > **Por que um codebook explícito?** A alternativa naïve seria pedir para o modelo > "classificar o texto como positivo ou negativo". Isso funciona mal porque cada > LLM tem prior próprio sobre o que essas palavras significam. Um codebook > transforma a classificação em **operacionalização reproduzível**: outro > pesquisador (humano ou LLM) chega aos mesmos rótulos aplicando as mesmas > definições e exemplos. ### Por que essa ordem, e o que reportar em cada etapa O diagrama acima mostra a ordem de **execução**. A tabela abaixo explica a ordem de **reporte**: o que cada etapa produz que precisa aparecer na seção de método do seu estudo, e por que pular uma etapa compromete a defensabilidade do resultado. | Ordem | Etapa | O que reportar | Por que importa | |:-----:|---------------------------------|----------------------------------------------------------|-----------------------------------------------------------------------------------| | 1 | Codebook (Etapa 1-3) | Categorias, definições, exemplos positivos/negativos | Sem definição operacional explícita, o leitor não sabe o que o rótulo significa, nem consegue replicar a classificação (Krippendorff, 2018). | | 2 | Classificação (Etapa 5) | Modelo, provedor, temperatura, `k_consistency`, se usou `reasoning` | Modelos diferentes (ou o mesmo modelo em versões diferentes) produzem classificações diferentes; sem registrar isso, o estudo não é replicável mesmo com o codebook em mãos. | | 3 | Confiança (saída de Etapa 5) | Distribuição de `confidence_score`, quantos documentos ficaram abaixo de 0.80 | Mostra a incerteza interna do modelo *antes* de qualquer comparação com humano: uma confiança baixa generalizada é sinal de codebook ambíguo, não só de limitação do modelo. | | 4 | Validação humana (Etapa 7) | Tamanho e estratégia da amostra, métricas de concordância com IC 95% | É o único jeito de saber se a classificação automática é válida, não só consistente internamente. Pular essa etapa é o motivo mais comum de rejeição em revisão por pares de estudos com LLM. | | 5 | Replicabilidade (Etapa 8) | Relatório consolidado (`ac_qual_report()`) com todas as decisões acima | Reúne as etapas 1-4 num documento único, anexável como material suplementar: a transparência mínima esperada hoje para análise assistida por LLM em ciências sociais. | Pular a etapa 4 é a falha mais comum e mais grave: uma classificação pode ter `confidence_score` alto (o modelo "tem certeza") e ainda assim estar sistematicamente errada, porque o problema não é a estocasticidade do modelo, mas uma categoria do codebook mal definida. Só a comparação com codificação humana revela isso. ## Quando usar LLM (e quando **não** usar) Antes de acender API, vale escolher a técnica certa para a pergunta. LLM não é o melhor caminho para todo problema de análise de conteúdo: é caro, tem variabilidade estocástica e depende de um provedor externo. A tabela abaixo resume quando **cada** abordagem do `acR` faz sentido: | Você quer… | Use | |------------------------------------------------------------------------------|---------------------------------------------------------------------------------------| | Rotular textos com **categorias teóricas pré-definidas** (populismo, framing) | LLM + codebook: esta vignette | | Medir **valência afetiva** (positivo/negativo/neutro) em português | `ac_sentiment()` (léxico OpLexicon): mais rápido, determinístico, sem chave de API | | Descobrir **tópicos emergentes** sem categorias a priori | `ac_lda()`: modelo probabilístico não supervisionado | | Detectar **tipologias latentes** para amostragem estratificada | `ac_cluster_documents()`: hard clustering; veja a `vignette("cluster")` | | **Comparar** vocabulário entre dois ou mais grupos | `ac_keyness()`: teste estatístico, sem LLM | | **Explorar** vocabulário distintivo dentro de cada documento | `ac_tf_idf()` | Regra prática: **se a categoria pode ser detectada por palavras-chave, use léxico ou keyness: é mais barato, reprodutível e defensável.** LLM brilha quando a categoria depende de **contexto, ironia, referência implícita ou raciocínio sobre argumento** (populismo, framing, posicionamento, tom, estilo retórico). ### Custo real de um estudo com LLM Para calibrar expectativas, estimativa em dólares para um corpus típico brasileiro (500 discursos parlamentares, ~800 tokens cada) com `k_consistency = 3` e `reasoning = TRUE, reasoning_length = "medium"`: | Modelo | Custo estimado | Tempo estimado | |---------------------------------|----------------|----------------| | `groq/openai/gpt-oss-120b` | US$ 0,50 – 1 | ~10 min | | `openai/gpt-4o-mini` | US$ 3 – 5 | ~15 min | | `anthropic/claude-sonnet-4-5` | US$ 10 – 20 | ~25 min | | `anthropic/claude-opus-4-7` | US$ 40 – 80 | ~40 min | | `ollama/llama3.1:70b` (local) | US$ 0 (GPU) | ~2 h em RTX 4090 | `ac_qual_recommend_model()` (chamado a seguir) sugere o modelo mais custo-efetivo para o tamanho e a dificuldade da sua tarefa. --- ## Instalação e configuração Antes de começar, garanta que o `ellmer` está instalado e que a chave da API do seu provedor está no ambiente (`.Renviron` é o local usual; nunca no código versionado): ```{r instalacao} # Instalar acR remotes::install_github("andersonheri/acR") # Instalar ellmer install.packages("ellmer") # Configurar chave de API (exemplo: Anthropic) Sys.setenv(ANTHROPIC_API_KEY = "sk-ant-...") ``` Se você não sabe qual provedor escolher, use `ac_qual_recommend_model()`: a função consulta um banco interno com custo, contexto e qualidade estimada por tipo de tarefa, sem precisar de rede. --- ## Etapa 1: Criar o codebook O codebook é o instrumento central da análise de conteúdo. Ele define as **categorias analíticas**, suas **definições operacionais**, **exemplos** positivos (o que É a categoria) e negativos (o que NÃO é, para desambiguar categorias vizinhas), e **pesos** relativos que orientam a LLM em fronteiras difíceis. > **Dica metodológica:** exemplos negativos são frequentemente subestimados. Um > exemplo negativo para "populista" (como "Apresento esta emenda técnica") > ajuda muito mais que dois positivos adicionais. Eles servem de contraste, > reduzindo confusões entre categorias similares. ```{r codebook-manual, eval = TRUE} library(acR) cb <- ac_qual_codebook( name = "tom_discurso", instructions = "Classifique o tom geral do discurso parlamentar.", categories = list( positivo = list( definition = "Discurso com tom propositivo e colaborativo.", examples_pos = c("Proponho que trabalhemos juntos nesta agenda."), examples_neg = c("Este governo é um desastre completo."), weight = 1 ), negativo = list( definition = "Discurso com tom crítico ou confrontacional.", examples_pos = c("Esta proposta vai arruinar o país."), examples_neg = c("Apresento esta emenda para melhorar o texto."), weight = 1.5 # categoria mais difícil: peso maior no prompt ), neutro = list( definition = "Discurso descritivo, sem posicionamento claro.", examples_pos = c("O projeto foi apresentado na sessão de hoje."), weight = 1 ) ), multilabel = FALSE, # cada doc recebe UMA categoria; se TRUE, a coluna # `categoria` na saida vira uma string pipe-separada # ("técnica|politica") quando mais de uma se aplicar. lang = "pt" ) print(cb) ``` ### Adicionar e remover categorias Codebooks quase nunca ficam corretos na primeira tentativa. As funções `ac_qual_codebook_add()` e `ac_qual_codebook_remove()` permitem **refinamento iterativo**: comum quando você roda o codebook numa amostra piloto e percebe que faltou uma categoria ("tecnico") ou que duas se sobrepõem. Todas as modificações ficam registradas em `codebook$history` para reprodutibilidade metodológica. ```{r codebook-add-remove} # Adicionar categoria iterativamente cb <- ac_qual_codebook_add(cb, tecnico = list( definition = "Discurso com linguagem técnica e referências normativas.", examples_pos = c("Conforme o art. 37 da CF, a administração pública..."), weight = 1 ) ) # Remover se necessário cb <- ac_qual_codebook_remove(cb, "tecnico") ``` --- ## Etapa 2: Enriquecer o codebook com literatura Definir categorias apenas com base no conhecimento do pesquisador funciona, mas ancorar as definições em literatura publicada aumenta a **validade de construto**. O `acR` oferece dois modos automatizados: * **Híbrido** (`ac_qual_codebook_hybrid`): parte do seu codebook manual e **enriquece** cada categoria com citações teóricas relevantes, sem alterar os exemplos que você já validou. * **Literature** (`mode = "literature"`): constrói o codebook **do zero** a partir da literatura sobre um conceito. Útil quando você tem clareza do conceito teórico mas quer que o pacote extraia as dimensões operacionais. ### Modo híbrido: definições ancoradas em referências `ac_qual_codebook_hybrid()` re-ancora as definições manuais em referências bibliográficas buscadas via LLM, preservando os exemplos originais: ```{r codebook-hybrid} cb_hybrid <- ac_qual_codebook_hybrid( codebook = cb, model = "anthropic/claude-sonnet-4-5", journals = "default", # periódicos de CP/CS brasileiros e internacionais n_refs = 3L, lang = "pt" ) # Ver definição enriquecida da categoria "negativo" cat(cb_hybrid$categories$negativo$definition) cat("\nReferências:\n") print(cb_hybrid$categories$negativo$references) ``` ### Modo literature: construção inteiramente baseada em literatura Aqui você fornece o **conceito** que quer capturar (em inglês, para melhor recall na base OpenAlex) e o pacote gera categoria, definição e exemplos. ```{r codebook-literature} cb_lit <- ac_qual_codebook( name = "frames_politicos", instructions = "Identifique o frame predominante no discurso.", categories = list( conflito = list(definition = "", concept = "conflict framing politics"), consenso = list(definition = "", concept = "consensus framing politics"), moralidade = list(definition = "", concept = "moral framing political discourse") ), mode = "literature", model = "anthropic/claude-sonnet-4-5", lang = "pt" ) ``` --- ## Etapa 3: Fundir e traduzir codebooks Análises multidimensionais frequentemente combinam duas ou mais tipologias (tom + estilo, posicionamento + tema, etc.). `ac_qual_codebook_merge()` faz essa combinação, com controle de conflitos entre categorias de mesmo nome. Traduzir codebooks é útil para: **replicabilidade internacional** (publicar versão em inglês do instrumento), **corpora bilíngues**, ou apenas para checar se as definições sobrevivem sem ambiguidade em outra língua. ### Fundir dois codebooks ```{r codebook-merge} cb_estilo <- ac_qual_codebook( name = "estilo_retórico", instructions = "Classifique o estilo retórico dominante.", categories = list( pathos = list(definition = "Apelo emocional predominante."), logos = list(definition = "Apelo racional/argumentativo predominante."), ethos = list(definition = "Apelo à autoridade ou credibilidade do orador.") ) ) # Fundir: tom + estilo retórico em um único codebook cb_completo <- ac_qual_codebook_merge( cb1 = cb_hybrid, cb2 = cb_estilo, name = "discurso_parlamentar", on_conflict = "rename_second", instructions = "Classifique o tom e o estilo retórico do discurso." ) ``` ### Traduzir para inglês ```{r codebook-translate} cb_en <- ac_qual_codebook_translate( codebook = cb_completo, to = "en", model = "anthropic/claude-sonnet-4-5", translate_examples = TRUE ) ``` --- ## Etapa 4: Inspecionar histórico e gerar system prompt Todo codebook mantém um `history` das modificações: quem alterou, quando e o quê. Isso é essencial para publicação: o revisor pode auditar exatamente como o instrumento foi construído. O `as_prompt()` converte o objeto `ac_codebook` em uma string de **system prompt** formatada, pronta para ser injetada num objeto `Chat` do `ellmer`. Você pode usar essa string diretamente se quiser rodar a classificação com sua própria lógica de retry/paralelismo. ```{r codebook-history} # Ver todas as modificações feitas no codebook ac_qual_codebook_history(cb_completo) ``` ```{r as-prompt} # Gerar system prompt para uso direto com ellmer prompt <- as_prompt( cb_completo, reasoning = TRUE, # pede raciocinio estruturado reasoning_length = "medium" # "short" | "medium" | "detailed" ) # O prompt pode ser passado diretamente a um objeto Chat: # chat$set_system_prompt(prompt) ``` > **Sobre `reasoning`:** pedir raciocínio *aumenta* a qualidade da > classificação em casos difíceis (o modelo "pensa antes de responder"), mas > **dobra o custo** por documento (mais tokens gerados). Use `"short"` como > padrão; `"detailed"` só quando você planeja auditar decisões > individualmente. --- ## Etapa 5: Classificar o corpus Com codebook pronto e corpus estruturado, `ac_qual_code()` faz a classificação em lotes. Três parâmetros são chave: * `k_consistency`: número de repetições de *self-consistency* (Wang et al., 2022). O mesmo texto é classificado k× (padrão 3) com pequena variação de temperatura, e a categoria final é a moda. O `confidence_score` sai daí: 1.0 = todas as k rodadas concordaram; 0.67 = 2 de 3. * `temperature`: **variação estocástica** entre as rodadas de self-consistency (padrão `0.3`). A rodada principal usa `temperature = 0` (determinística); as `k - 1` rodadas de consistência usam este valor para diversificar as saídas. Desde a v0.3.3 é de fato repassado ao provedor via `ellmer::params()` (versões anteriores aceitavam o parâmetro mas não o aplicavam, inflando `confidence_score` espuriamente). * `reasoning`: pede raciocínio estruturado em JSON. * `live`: **visualização em tempo real** da classificação, tirando o processo do "caixa-preta". Ver blockquote abaixo. ```{r corpus} library(ellmer) # Coletar e estruturar corpus discursos <- ac_fetch_camara( id_deputado = 204379, data_inicio = "2023-01-01", data_fim = "2023-06-30" ) corpus <- ac_corpus(discursos, text_col = "transcricao", id_col = "id") ``` ```{r classificar} # Classificar chat <- chat_anthropic(model = "claude-sonnet-4-5") resultado <- ac_qual_code( corpus = corpus, codebook = cb_completo, chat = chat, k_consistency = 3, # self-consistency live = "terminal" # ver a maquina classificando ao vivo ) head(resultado) ``` O tibble de saída traz: `doc_id`, `categoria`, `confidence_score` (via *self-consistency*), `reasoning` (raciocínio do modelo, se pedido) e os metadados originais do corpus. > **Como ler esta tabela** > > 1. **Onde olhar.** Na saída de `head(resultado)`, olhe a coluna > `confidence_score`: a fração das `k_consistency` rodadas que > escolheram a categoria final. Com `k_consistency = 3` (este > exemplo), ela só pode valer 0,33 (as três rodadas discordaram), > 0,67 (duas concordaram) ou 1,00 (todas concordaram). > > 2. **O que este exemplo mostra.** Num corpus de textos claros, a > maioria das linhas tem 1,00; os documentos com 0,67 ou 0,33 são os > que o modelo achou ambíguos, e são eles que você deve abrir > primeiro. > > 3. **Em palavras simples.** `confidence_score` mede se o modelo > **concorda consigo mesmo**, não se ele **acertou**. Um modelo pode > errar as três rodadas do mesmo jeito (por exemplo, quando o > codebook tem uma definição ambígua) e sair com 1,00. > > 4. **Cuidado.** A ideia de usar concordância entre rodadas como sinal > de incerteza vem de Wang et al. (2023) e Xiong et al. (2024), que > mostram que ela se relaciona com acerto, mas não oferecem cortes > universais. Use os casos de confiança baixa para **diagnosticar** o > codebook (`ac_qual_sample(strategy = "uncertainty")`); a validação > que vai para o artigo tem de ser feita numa amostra **aleatória** > codificada por humanos (Krippendorff, 2018, cap. 12). ### Live view: tirando o LLM do caixa-preta O argumento `live` de `ac_qual_code()` mostra a máquina classificando em tempo real. Três modos: * `live = "off"` (padrão): sem visualização. * `live = "terminal"`: barra de progresso `cli` com doc atual, categoria, confiança e início do raciocínio. Zero dependências, roda em qualquer setup (batch, CI, servidor sem interface gráfica). * `live = "shiny"`: janela Shiny em background com tabela atualizando a cada 500 ms, destaque para casos de baixa confiança. Requer `shiny` e `callr`. Ideal para apresentações e demonstrações. ```{r live-terminal} resultado <- ac_qual_code( corpus, cb_completo, chat = chat, live = "terminal" ) # 42/120 | ============> 35% | ETA 2m10s # doc_042 -> populista (conf 1.00) "Apela ao povo contra elite..." ``` > **Por que isso importa?** Numa rodada de 500 documentos, sem `live` você > não sabe se o modelo travou, se está devolvendo lixo, ou se está indo > bem: só descobre no fim, depois de gastar todo o orçamento de tokens. > Com `live = "terminal"`, você vê nos primeiros 10 docs se o raciocínio > faz sentido e a distribuição de categorias está plausível. Se algo > estiver errado, `Ctrl+C` e ajusta. --- ## Etapa 6: Salvar e carregar Codebook e resultados devem ser **serializados** para replicabilidade. YAML foi escolhido por ser legível por humanos e versionável em Git. ```{r save-load} # Salvar em YAML para replicabilidade ac_qual_save_codebook(cb_completo, path = "codebook_discurso.yaml") # Carregar em outra sessão cb_recarregado <- ac_qual_load_codebook("codebook_discurso.yaml") ``` --- ## Etapa 7: Validação e confiabilidade **Sem validação humana, não há análise de conteúdo publicável.** LLM é uma ferramenta poderosa, mas nenhuma referência metodológica aceita hoje um estudo de análise categorial sem um subconjunto codificado por humano e métricas de concordância entre codificadores. O fluxo mínimo: 1. `ac_qual_sample()`: seleciona uma amostra representativa (estratificada, ou priorizando casos incertos via `strategy = "uncertainty"`). 2. `ac_qual_export_for_review()`: exporta para `.xlsx` com a coluna `categoria_humano` em branco para o revisor preencher. 3. `ac_qual_import_human()`: reimporta o Excel preenchido. 4. `ac_qual_reliability()`: calcula percent agreement, *alpha* de Krippendorff, AC1 de Gwet e F1 macro, com IC 95% via *bootstrap*. > **Quanto amostrar, e como?** Neuendorf (2017) sugere uma subamostra de > confiabilidade entre 10% e 20% do corpus, raramente menor que 50 > unidades; Krippendorff (2018, sec. 12.3) dá um cálculo formal a partir > do alfa mínimo aceitável e da frequência da categoria mais rara. A > amostra deve ser **aleatória** (ou estratificada proporcional): se você > escolher só os casos com `confidence_score` baixo, a concordância > medida descreve os casos difíceis, não o corpus, e subestima a > confiabilidade real. Os casos incertos são ótimos para uma segunda > rodada de **diagnóstico** do codebook, separada da estimativa. ```{r validacao} # Amostra aleatória de 50 documentos (representativa do corpus) amostra <- ac_qual_sample(resultado, n = 50, strategy = "random") ac_qual_export_for_review(amostra, path = "revisao.xlsx", corpus = corpus) # Após preenchimento manual, calcular IRR revisado <- ac_qual_import_human("revisao_preenchida.xlsx") irr <- ac_qual_reliability(llm = resultado, human = revisado) print(irr) ``` Cada métrica tem a sua referência de leitura; não as misture: | Métrica | Faixas | Fonte | |:--|:--|:--| | Alfa de Krippendorff | ≥ 0,800 confiável; 0,667–0,800 só conclusões provisórias; < 0,667 insuficiente | Krippendorff (2018, sec. 12.4) | | AC1 de Gwet (e kappa) | < 0 pobre; 0–0,20 leve; 0,21–0,40 razoável; 0,41–0,60 moderada; 0,61–0,80 substancial; 0,81–1 quase perfeita | Landis & Koch (1977), usado como referência por Gwet (2014) | | Percent agreement | ≥ 0,90 alta; ≥ 0,80 aceitável na maioria dos casos; ≥ 0,70 só estudos exploratórios | Neuendorf (2017) | | F1 macro | sem faixa canônica (não corrige por acaso) | — | Para publicação, o critério de referência em análise de conteúdo é o de Krippendorff: alfa ≥ 0,800, aceitando 0,667 apenas para conclusões provisórias e com discussão dos casos divergentes. As faixas de Landis & Koch são descritivas (os próprios autores as chamam de arbitrárias) e não definem o que é publicável. Olhe também o IC: um alfa de 0,82 com IC de 0,61 a 0,95 não permite afirmar que a confiabilidade passa de 0,800. > **E se eu usar dicionário em vez de LLM?** A mesma exigência de validação > vale para classificação por dicionário (`ac_dictionary()`/`ac_emotion()`, > ver `vignette("quantitativo")`): um dicionário é determinístico e > transparente, mas insensível a contexto, negação e ironia. Use > `ac_dictionary_validate()`, o equivalente de `ac_qual_reliability()` para > esse método, antes de reportar qualquer classificação por dicionário > como válida (Grimmer & Stewart, 2013). --- ## Diagnosticando problemas comuns Antes de partir para o relatório final, vale conhecer os quatro modos de falha mais frequentes de uma rodada com LLM, e o que cada um pede. Os limiares de `confidence_score` citados abaixo (0,67; 0,80) assumem `k_consistency = 3`, como no exemplo desta vignette: com outro `k_consistency`, ajuste para o valor proporcional mais próximo (ver "Como ler" na seção anterior). ### 1. Categorias com concordância baixa entre `k_consistency` **Sintoma:** `confidence_score` mediano abaixo de 0,80. **Causa provável:** definições ambíguas ou exemplos negativos ausentes. A LLM está literalmente hesitando entre categorias em cada repetição. **Fix:** rodar `ac_qual_codebook(check_overlap = TRUE)` para detectar definições semanticamente próximas; adicionar exemplos negativos cruzados (o que uma categoria **não** é, especialmente perto das vizinhas); revisar manualmente 5–10 documentos com `confidence_score < 0.67` e verificar se o problema está no texto (documento genuinamente ambíguo) ou no codebook. ### 2. LLM devolve categoria fora do codebook **Sintoma:** categoria como "misto", "outro" ou uma variante da sua ("populismo_forte") que **não está** no `codebook$categories`. **Causa:** o modelo entendeu a tarefa mas achou a categoria correta insuficiente. **Fix:** ou você acrescenta a categoria emergente (via `ac_qual_codebook_add()`), ou reforça no prompt que **só as categorias listadas** são válidas. A segunda geralmente é preferível: categorias emergentes indicam refinamento metodológico, não desvio da LLM. ### 3. Distribuição colapsada em uma categoria **Sintoma:** 90%+ dos documentos vão para o mesmo rótulo. **Causa:** categoria com definição muito abrangente ou peso implicitamente alto (mais exemplos positivos que as outras). **Fix:** equilibrar o número de exemplos positivos por categoria; usar o argumento `weight` para dar peso extra às categorias mais raras; considerar `multilabel = TRUE` se os documentos genuinamente cobrem mais de um tema. ### 4. IRR humana × LLM inaceitável **Sintoma:** `ac_qual_reliability()` retorna α < 0,60. **Causa:** três possibilidades, em ordem de frequência: (i) codebook não está claro nem para humanos (peça a **outro** humano codificar; se dois humanos discordam, a LLM não vai salvar), (ii) modelo escolhido é pequeno demais para a tarefa (troque para um tier acima), (iii) o próprio conceito teórico é contestado, reformule a pergunta. > **Regra de ouro:** se a IRR entre dois humanos está abaixo de 0,70, o > problema é do codebook, não da LLM. Nenhum modelo vai ter mais > concordância consigo mesmo do que humanos treinados têm entre si. ## Etapa 8: Replicabilidade e transparência Análises com LLM têm um risco de comunicação: **o revisor ou leitor não consegue reproduzir a rodada** sem saber exatamente que modelo, que codebook, que parâmetros e que amostra foram usados. `ac_qual_report()` gera um documento estruturado com **todas essas decisões**, pronto para anexar como material suplementar de um artigo ou como apêndice metodológico. O relatório cobre oito seções: 1. **Metadados**: data, versão do `acR`, autor(es), método 2. **Codebook completo**: categorias, definições, exemplos ± e pesos 3. **Histórico de modificações**: auditoria das alterações no codebook 4. **Configuração da LLM**: provedor, modelo, temperatura, k, reasoning 5. **Resultados**: distribuição por categoria, quartis de `confidence_score`, contagem de casos com confiança < 0.80 6. **Confiabilidade inter-codificador**: se `ac_qual_reliability()` foi rodado, tabela completa com IC 95% 7. **Referências metodológicas**: Krippendorff, Landis-Koch, Gilardi, Wang, Gwet 8. **Sugestão de citação**: formatada em ABNT (PT) ou APA (EN) Uso mínimo: ```{r report-minimal} # Após ter o resultado da classificação ac_qual_report( coded = resultado, codebook = cb_completo, chat = chat, # opcional: extrai provedor/modelo author = "Anderson Henrique", path = "relatorio_metodo.md" ) ``` Uso completo (com IRR e HTML autocontido): ```{r report-full} irr <- ac_qual_reliability(llm = resultado, human = revisado) ac_qual_report( coded = resultado, codebook = cb_completo, reliability = irr, chat = chat, title = "Codificação do posicionamento parlamentar - 57ª legislatura", author = "Silva, A.; Souza, B.", method = "Discursos coletados via API da Câmara (jan-jun/2023, n=847).", format = "html", path = "metodo_apendice.html", lang = "pt" # ou "en" para submissao internacional ) ``` O arquivo gerado é **autocontido** (HTML embute todos os estilos; MD é Markdown puro versionável em Git). Pode ser anexado como material suplementar do artigo, incluído como apêndice, ou publicado num repositório de dados junto com o codebook em YAML (`ac_qual_save_codebook()`) e a saída bruta da LLM. > **Nota metodológica.** A prática de publicar codebook + rodada da LLM + > métricas IRR num único documento é a **transparência mínima** para > análise assistida por LLM em ciências sociais. Sem isso, o leitor tem > que confiar no autor, algo que a tradição de análise de conteúdo > (Krippendorff, 2018) sempre rejeitou. O `ac_qual_report()` empacota > essa transparência num único comando. --- ## Referências Gilardi, F., Alizadeh, M., & Kubli, M. (2023). ChatGPT outperforms crowd workers for text-annotation tasks. *PNAS*, 120(30). https://doi.org/10.1073/pnas.2305016120 Grimmer, J., & Stewart, B. M. (2013). Text as Data: The Promise and Pitfalls of Automatic Content Analysis Methods for Political Texts. *Political Analysis*, 21(3), 267-297. Gwet, K. L. (2014). *Handbook of Inter-Rater Reliability* (4th ed.). Advanced Analytics. Krippendorff, K. (2018). *Content Analysis: An Introduction to Its Methodology* (4th ed.). SAGE. Landis, J. R., & Koch, G. G. (1977). The measurement of observer agreement for categorical data. *Biometrics*, 33(1), 159-174. Neuendorf, K. A. (2017). *The Content Analysis Guidebook* (2nd ed.). SAGE. Maerz, S., & Benoit, K. (2025). *quallmer: Qualitative Analysis with Large Language Models in R*. GitHub. https://github.com/quallmer/quallmer Sampaio, R. C., & Lycarião, D. (2021). *Análise de conteúdo categorial: manual de aplicação*. Brasília: ENAP. Wang, X., et al. (2023). Self-consistency improves chain of thought reasoning in language models. *International Conference on Learning Representations (ICLR)*. Wickham, H., et al. (2025). *ellmer: Chat with Large Language Models*. R package. https://ellmer.tidyverse.org Xiong, M., et al. (2024). Can LLMs express their uncertainty? An empirical evaluation of confidence elicitation in LLMs. *International Conference on Learning Representations (ICLR)*.