--- title: "Replicabilidade ponta-a-ponta — do codebook ao relatório de método" output: rmarkdown::html_vignette: toc: true toc_depth: 2 vignette: > %\VignetteIndexEntry{Replicabilidade ponta-a-ponta — do codebook ao relatório de método} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include=FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.width = 8.5, fig.height = 5.5, fig.align = "center", out.width = "100%", dpi = 140 ) library(acR) library(dplyr) ``` Esta vignette demonstra o pipeline **completo** de análise de conteúdo qualitativa assistida por LLM, com foco na **replicabilidade**: cada decisão metodológica é documentada de forma que outro pesquisador possa reproduzir a análise apenas com o codebook em YAML e o relatório gerado por `ac_qual_report()`. A demonstração usa dados sintéticos (`ac_qual_code()` requer chave de LLM paga); a estrutura, formatos e sequência são idênticos a uma rodada real. ## O pipeline em 6 etapas 1. **Coleta** — corpus real ou fabricado 2. **Codebook** — instrumento analítico (`ac_qual_codebook`) 3. **Classificação** — LLM com `live view` (`ac_qual_code(live = ...)`) 4. **Amostragem para revisão** — `ac_qual_sample()` 5. **Confiabilidade inter-codificador** — `ac_qual_reliability()` 6. **Relatório de método** — `ac_qual_report()` ## 1. Corpus Corpus fabricado de 12 pronunciamentos com posição declarada (favor/contra/neutro) — em uso real, este data.frame viria de `ac_fetch_camara()`, `ac_fetch_senado()` ou de importação de PDFs. ```{r corpus} df <- data.frame( doc_id = paste0("d", sprintf("%02d", 1:12)), text = c( "Apoio integralmente esta reforma que simplifica o sistema tributario.", "Sou favoravel a proposta: reduz distorcoes historicas do setor.", "Voto sim com plena adesao: precisamos modernizar a estrutura fiscal.", "Aprovo a reforma tributaria, e uma conquista para o desenvolvimento.", "Rejeito esta proposta, e um retrocesso para os trabalhadores.", "Voto contra: a reforma prejudica os mais pobres e as pequenas empresas.", "Sou contrario a essa proposta, ela beneficia apenas grandes corporacoes.", "Nao apoio o texto atual, precisa de revisao profunda antes da votacao.", "O texto substitutivo altera o artigo 145 da Constituicao Federal.", "O relatorio incorporou 47 emendas apresentadas em plenario.", "A comissao aprovou o parecer com 15 votos a favor e 8 contra.", "O projeto seguira para votacao na proxima sessao ordinaria." ), partido = c("PT","PSD","PL","MDB","PSOL","PT","PDT","PSOL", "MDB","PSDB","PL","MDB"), stringsAsFactors = FALSE ) corpus <- ac_corpus(df) corpus ``` ## 2. Codebook O codebook é o instrumento central. Aqui usamos três categorias (favor, contra, neutro/técnico) com definições operacionais e exemplos positivos e negativos para desambiguar categorias vizinhas. ```{r codebook} cb <- ac_qual_codebook( name = "posicao_reforma_tributaria", instructions = paste( "Classifique a posicao do parlamentar sobre a reforma tributaria", "com base no discurso apresentado." ), categories = list( favor = list( definition = "Apoio explicito a aprovacao da reforma tributaria.", examples_pos = c("Sou a favor desta reforma que simplifica o sistema."), examples_neg = c("O texto altera o artigo 145 da Constituicao Federal."), weight = 1 ), contra = list( definition = "Oposicao explicita a reforma, com argumentos de rejeicao.", examples_pos = c("Voto contra: prejudica os trabalhadores."), examples_neg = c("Precisa de ajustes antes da votacao."), weight = 1.2 # categoria com mais dificuldade retorica ), neutro = list( definition = "Discurso tecnico ou processual, sem posicionamento claro.", examples_pos = c("O relatorio incorporou emendas apresentadas."), examples_neg = c("Sou totalmente contra esta proposta.") ) ), lang = "pt" ) cb ``` Salvar o codebook em YAML permite versionamento em Git e retomada da análise em outra sessão: ```{r save-codebook} arquivo_cb <- tempfile(fileext = ".yaml") ac_qual_save_codebook(cb, path = arquivo_cb) cat("Codebook salvo em:", arquivo_cb, "\n") ``` ## 3. Classificação com live view Em uma rodada real, o comando seria: ```r library(ellmer) chat <- chat_anthropic(model = "claude-sonnet-4-5") resultado <- ac_qual_code( corpus = corpus, codebook = cb, chat = chat, k_consistency = 3, # 3 rodadas de self-consistency reasoning = TRUE, # pede raciocinio estruturado live = "terminal" # ver o LLM classificando ao vivo ) ``` Com `live = "terminal"`, cada documento aparece na hora: ``` 1/12 | => 8% | ETA 45s | d01 -> favor (conf 1.00) "Apoio integralmente..." 2/12 | ==> 17% | ETA 40s | d02 -> favor (conf 1.00) "Sou favoravel a..." 3/12 | ====> 25% | ETA 35s | d03 -> favor (conf 0.67) "Voto sim com conviccao..." ... ``` Para esta vignette, simulamos o resultado que o LLM retornaria (formato idêntico ao real): ```{r simular-resultado} set.seed(42) resultado <- tibble::tibble( doc_id = df$doc_id, categoria = c(rep("favor", 4), rep("contra", 4), rep("neutro", 4)), confidence_score = c(1.00, 1.00, 0.67, 1.00, 1.00, 1.00, 1.00, 0.67, 1.00, 1.00, 0.67, 1.00), reasoning = c( "Apoio explicito com 'apoio integralmente'.", "Uso do adjetivo 'favoravel' e 'reduz distorcoes'.", "Voto declarado, mas ambivalente entre favor e neutro.", "'Aprovo' e 'conquista' marcam adesao.", "'Rejeito' e 'retrocesso' marcam oposicao.", "'Voto contra' e argumento distributivo.", "'Sou contrario' com justificativa.", "'Nao apoio' + pede revisao (borderline neutro/contra).", "Descreve alteracao normativa sem posicionar.", "Descreve processo legislativo.", "Numeros do resultado, sem opiniao. Borderline.", "Encaminhamento processual." ) ) resultado ``` Distribuição dos resultados: ```{r distribuicao} resultado |> dplyr::count(categoria) |> dplyr::mutate(pct = round(100 * n / sum(n), 1)) ``` Casos com baixa confiança (candidatos prioritários para revisão humana): ```{r low-conf} resultado |> dplyr::filter(confidence_score < 1.0) |> dplyr::select(doc_id, categoria, confidence_score, reasoning) ``` ## 4. Amostra para revisão humana `ac_qual_sample(strategy = "uncertainty")` prioriza documentos com menor `confidence_score` — foca o esforço humano onde o LLM mais errou. ```{r amostra} amostra <- ac_qual_sample( resultado, n = 4, strategy = "uncertainty" ) amostra |> dplyr::select(doc_id, categoria, confidence_score, sample_reason) ``` Em uma rodada real, você exportaria essa amostra para Excel, um codificador humano preencheria a coluna `categoria_humano`, e o resultado seria reimportado: ```{r export-excel, eval=FALSE} ac_qual_export_for_review(amostra, path = "revisao.xlsx", corpus = corpus) # ... revisor humano preenche a coluna categoria_humano no Excel ... revisado <- ac_qual_import_human("revisao.xlsx") ``` ## 5. Confiabilidade inter-codificador Simulamos a revisão humana (com 1 discordância em 12) e calculamos as métricas de concordância — no artigo, essas métricas aparecem na seção de método: ```{r reliability} humano <- tibble::tibble( doc_id = resultado$doc_id, categoria = c(rep("favor", 4), rep("contra", 4), "neutro","neutro","favor","neutro") # 1 discordancia ) irr <- ac_qual_reliability( llm = resultado, human = humano, bootstrap = 100L ) irr ``` ## 6. Relatório de método — replicabilidade automática Aqui está o **coração desta vignette**: `ac_qual_report()` empacota tudo — codebook, config LLM, distribuição de resultados, métricas de IRR — em um documento único, pronto para anexar como material suplementar de um artigo. ```{r report} arquivo_md <- tempfile(pattern = "relatorio-", fileext = ".md") ac_qual_report( coded = resultado, codebook = cb, reliability = irr, chat = "anthropic/claude-sonnet-4-5", # ou objeto Chat title = "Classificacao de posicionamento na reforma tributaria", author = "Silva, A.; Souza, B.", method = "Corpus de 12 pronunciamentos parlamentares (2023-2024).", format = "md", path = arquivo_md, lang = "pt" ) ``` Primeiras 40 linhas do relatório gerado: ```{r preview-report} cat(head(readLines(arquivo_md), 40), sep = "\n") ``` O relatório completo cobre 8 seções: metadados, codebook completo, histórico de modificações, configuração da LLM, distribuição de resultados, confiabilidade (com IC 95%), referências metodológicas e sugestão de citação. Para gerar em HTML autocontido (com CSS embutido, pronto para publicação web): ```{r html, eval=FALSE} ac_qual_report( coded = resultado, codebook = cb, reliability = irr, format = "html", path = "apendice_metodo.html", lang = "pt" # ou "en" para submissao internacional ) ``` ## Fluxo completo em 6 linhas Recapitulando toda a vignette em código executável: ```r library(acR); library(ellmer) corpus <- ac_corpus(meu_data_frame) cb <- ac_qual_codebook(name = "...", instructions = "...", categories = list(...)) resultado <- ac_qual_code(corpus, cb, chat = chat_anthropic("..."), live = "terminal") amostra <- ac_qual_sample(resultado, n = 30, strategy = "uncertainty") # ... revisao humana ... irr <- ac_qual_reliability(llm = resultado, human = revisado) ac_qual_report(resultado, cb, reliability = irr, path = "metodo.md") ``` Seis funções principais, um pipeline reproduzível, um relatório automático — do texto bruto ao apêndice metodológico do artigo. ## Referências * Gilardi, F.; Alizadeh, M.; Kubli, M. (2023). ChatGPT outperforms crowd workers for text-annotation tasks. *PNAS*, 120(30). * Krippendorff, K. (2018). *Content Analysis: An Introduction to Its Methodology* (4th ed.). SAGE. * Wang, X. et al. (2022). Self-consistency improves chain-of-thought reasoning in language models. *arXiv:2203.11171*.