text-as-data: teaching an LLM to read the news like a coder

A new open-source pipeline for LLM-assisted event/concept coding — and why validating it against human judgment is the whole point

software
LLM
text-as-data
Published

August 30, 2026

Anyone who has done qualitative political science knows this routine: a newspaper article reports a statement, a protest, a land occupation — and someone has to turn that paragraph into a row of data. Date, location, actor, and then the column that actually requires judgment: is this a protest? Does this statement support or oppose the policy in question?

That routine has a name in computational political science — automated event coding, or more broadly text-as-data — and it has been an active research area for exactly the reason the manual version is slow: the hard part was never typing the spreadsheet. The hard part is making the coding match the theoretical concept you actually have in mind, not a flattened, generic version of it.

LLMs promise to automate that step: give the model a codebook — your definition of the concept, written the way you’d explain it to a human research assistant — and let it apply that categorization across thousands of texts. The catch is that a model can look like it is following your codebook while quietly falling back on the generic notion of the concept it picked up during training — a construct validity problem, not an accuracy problem (see Halterman & Keith, “Codebook LLMs: Evaluating LLMs as Measurement Tools for Political Science Concepts”, Political Analysis, 2025).

What text-as-data is

A small, honest pipeline about that trap. Unstructured text goes in, a structured table comes out, and validating the output against a human-coded sample is not a script nobody runs — it’s part of the pipeline from the first commit:

texts.csv (id, text)
     │
     ▼
codebook   — the construct: an output schema, instructions written the way
             you'd brief a human coder, and a few worked examples that pin
             down the edge cases
     │
     ▼
extraction — calls an LLM, validates the response against the schema
     │
     ▼
validation — compares against human labels: accuracy, Cohen's kappa, and
             the list of disagreements, for inspection

codebook is deliberately kept separate from the extraction/validation engine: the codebook is what changes from project to project, the engine underneath shouldn’t have to.

Where it stands

Right now it’s a working MVP with a synthetic toy example — enough to prove the pipeline runs end to end, not a real research instrument yet. No real pilot domain is picked: land-occupation coding (in the spirit of DATALUTA), industrial-policy/antitrust stance coding, and public-safety event coding are all candidates on the table. Scraping is deliberately out of scope for now — the pipeline assumes text has already been collected.

Code and technical docs live at github.com/mancano-tales/text-as-data (in English, with a Portuguese README telling the longer version of this story). I’ll post an update here once a real pilot domain is picked and the toy example gets replaced by an actual validated codebook.

Quem já fez pesquisa qualitativa em ciência política conhece essa rotina: uma notícia de jornal relata uma declaração, um protesto, uma ocupação de terra — e alguém precisa transformar aquele parágrafo em uma linha de dados. Data, local, ator, e a coluna que exige julgamento de verdade: isso é um protesto? aquela fala é a favor ou contra a política em questão?

Essa rotina tem nome na ciência política computacional — automated event coding, ou de forma mais ampla, text-as-data — e é uma área de pesquisa ativa justamente porque a parte difícil nunca foi digitar a planilha. A parte difícil é fazer a categorização bater com o conceito teórico que você tem em mente, não com uma versão genérica e achatada dele.

Com LLMs, a promessa é automatizar essa etapa: dar ao modelo um codebook — a definição do seu conceito, do jeito que você explicaria para um assistente de pesquisa humano — e deixar que ele aplique essa categorização em milhares de textos. A armadilha é que o modelo pode parecer que está seguindo seu codebook e, na prática, aplicar silenciosamente o conceito genérico que aprendeu no treinamento — um problema de validade de construto, não de acurácia técnica (ver Halterman & Keith, “Codebook LLMs: Evaluating LLMs as Measurement Tools for Political Science Concepts”, Political Analysis, 2025).

O que é o text-as-data

Um pipeline pequeno e honesto sobre essa armadilha. Texto não-estruturado entra, tabela estruturada sai, e validar a saída contra uma amostra codificada por humano não é um script que ninguém roda — é parte do pipeline desde o primeiro commit:

textos.csv (id, texto)
     │
     ▼
codebook   — o construto: um schema de saída, instruções escritas do jeito
             que você explicaria para um codificador humano, e alguns
             exemplos que fecham os casos de borda
     │
     ▼
extração   — chama um LLM, valida a resposta contra o schema
     │
     ▼
validação  — compara contra rótulos humanos: acurácia, Cohen's kappa, e a
             lista de discordâncias, para inspeção

O codebook fica separado de propósito do motor de extração/validação: é a peça que muda a cada projeto novo; o motor por baixo não deveria precisar mudar.

Onde o projeto está

Por enquanto é um MVP funcional com um exemplo sintético de teste — o suficiente para provar que o pipeline roda ponta a ponta, ainda não é um instrumento de pesquisa real. Nenhum domínio-piloto real foi escolhido ainda: codificação de ocupações de terra (na linha do DATALUTA), posicionamento em política industrial/antitruste, e eventos de segurança pública são candidatos na mesa. Scraping fica de fora de propósito por enquanto — o pipeline assume que o texto já foi coletado.

Código e documentação técnica estão em github.com/mancano-tales/text-as-data (em inglês, com um README em português contando a versão mais longa dessa história). Devo postar uma atualização aqui quando um domínio-piloto real for escolhido e o exemplo sintético for substituído por um codebook de verdade, validado.