Aprendizado adaptativo utilizando processamento de linguagem natura
Implementando um sistema de perguntas e respostas utilizando LLM com o objetivo de demostrar como os avanços recentes em técnicas de processamento natural podem auxiliar no estudo infantil.
Ao longo dos anos, observamos ciclos nos quais governantes prometem implementar políticas públicas destinadas a revitalizar o sistema educacional brasileiro, que enfrenta um declínio preocupante devido à falta de suporte do Estado e engajamento por parte dos estudantes matriculados na rede pública de ensino. Essa questão não se limita apenas ao Brasil; ela ecoa em âmbito global, agravada pela pandemia de COVID-19, que retardou o acompanhamento, investimento e recursos destinados aos alunos [1]. A crise sanitária evidenciou ainda mais a carência de atenção individualizada no processo educativo. No ensino médio das escolas públicas, é comum encontrar alunos desinteressados em buscar oportunidades em universidades públicas devido às lacunas de conhecimento acumuladas.
A situação enfrentada pelos alunos nas escolas públicas brasileiras é um dilema que transcende a mera falta de financiamento; é enraizado na cultura da sociedade. Muitos pais já pertencem a gerações marcadas por desafios educacionais, resultando em um início de trajetória escolar para os estudantes com pouca orientação e incentivo familiar [2]. A obsolescência do sistema educacional também contribui para a falta de motivação, tratando os alunos como estatísticas dentro de uma estrutura desatualizada [3] .
Diante desse cenário, surge a pergunta: como podemos inspirar os alunos a buscar o aprendizado não apenas como um investimento ao longo prazo, mas como uma jornada prazerosa e gratificante? A resposta pode residir na incorporação estratégica da tecnologia. A gamificação e a personalização do ensino por meio da tecnologia têm o potencial de estabelecer uma conexão mais profunda entre os alunos e o processo de aprendizado, dando espaço para que a curiosidade e a criatividade do próprio aluno impulsionem essa transformação. No entanto, a verdadeira dificuldade reside na capacidade de envolver os alunos nessas plataformas adaptativas e gamificadas.
É aqui que os avanços na área de processamento de linguagem natural podem desempenhar um papel fundamental. Ao criar interfaces mais intuitivas e acessíveis, a tecnologia pode atuar como uma ponte para transmitir informações de maneira envolvente e compreensível. Essa abordagem permitirá que os alunos se aproximem do conhecimento de forma menos intimidante e mais instigante. Uma abordagem interessante pode ser a criação de personagens cativantes que envolvam o público infantil de forma a atuar como orientadores no processo de estudo, auxiliando os alunos na compreensão dos tópicos.
Com o avanço dos modelos de linguagem de grande escala (Large Language Models — LLMs), agora é viável conduzir conversas que se assemelham a interações humanas com chatbots (interfaces de conversação computador-humanos) sobre uma ampla gama de assuntos e personalidades.
Nesse contexto, sugiro neste artigo a concepção de um chatbot de perguntas e respostas que se conecte a uma fonte de dados, proporcionando respostas embasadas em um personagem que se comunica na primeira pessoa. O objetivo final consiste em utilizar transcrições de episódios de um anime conhecido, como Pokémon, e integrá-las a uma base de conhecimento sobre a a História do Brasil. Dessa maneira, busca-se criar uma interface em que o personagem principal do anime, Ash, possa responder a questões relacionadas ao descobrimento do Brasil.
Para resolver essa tarefa, analisaremos a arquitetura geral e desenvolvemos utilizando a linguagem python e a biblioteca LangChain. A biblioteca LangChain é uma ferramenta de IA que permite criar e encadear diferentes modelos de AI, agentes e prompts de forma estruturada. É perfeito para criar aplicativos de IA complexos em que você precisa interagir com vários modelos em sequência [4].
- Consumo dos Dados
Os dados utilizados para criação do personagem foram retirados do projeto colaborativo online Wikiquote que funciona como uma compilação de citações, transcrições e frases célebres. Foram importados as transcrições dos 10 primeiros episódios através do loader UnstructuredURLLoader, fornecido pela biblioteca langchain, como demonstrado:
from langchain.document_loaders import UnstructuredURLLoader
def get_knowledge_by_url():
urls = []
for i in range(10):
urls.append(f"https://en.wikiquote.org/wiki/Pok%C3%A9mon/Season_{i}")
loader = UnstructuredURLLoader(urls)
pages = loader.load()
logger.info(f"Data loaded successuflly: {len(pages)} pages")
return pages
Para os dados de contexto sobre a linguagem python, foi utilizado o loader PyPDFLoader, que realiza a extração do conteúdo de arquivos PDFs para a utilização como contexto nas perguntas enviadas para o chatbot. O PDF utilizado como contexto será o livro “História do Brasil — da colonização portuguesa até nossos dias” [5];
from langchain.document_loaders import PyPDFLoader
def get_knowledge_by_pdf():
loader = PyPDFLoader(file_path=config.file_path)
pages = loader.load()
logger.info(f"Data loaded successuflly: {len(pages)} pages")
filtered_pages = [clean_page(page) for page in pages if config.start_page <= page.metadata["page"] <= config.end_page]
logger.info(f"Filtred page in the following rand: [{config.start_page}, {config.end_page}]")
return filtered_pages
def clean_page(page: Document):
content = page.page_content
lines = content.split("\n")
header = lines[0]
if "Chapter" in header or "Item" in header:
clean_content = "\n".join(lines[1:])
page.page_content = clean_content
return page
2. Pré-processamento dos documentos
Depois que os dados foram coletados, dividimos em partes (chunks) para evitar posteriormente limites de tokens impostos pelos modelos de linguagem durante o processo de incorporação. A divisão em partes também traz eficiência computacional, uma vez que processar documentos longos podem demandar alto custo computacional. Esse processo tambem traz uma melhoria na generalização do modelo, pois dividindo em pedaços, o modelo tem a oportunidade de capturar nuances e informações relevantes de diferentes partes do texto, potencialmente melhorando sua capacidade de generalização.
Dividimos cada página e transcrição em blocos de 1.024 caracteres com uma sobreposição de 128 caracteres entre os blocos. (Ter sobreposições entre partes posteriormente ajuda a construir o contexto completo em um longo trecho de texto).
from langchain.text_splitter import RecursiveCharacterTextSplitter
def set_embedding(data):
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1024, chunk_overlap=128)
chunks = text_splitter.split_documents(data)
logger.info(f"Splitted documents into {len(chunks)} chunks")
3. Geração das incorporações dos documentos
Uma incorporação, conhecida também como embedding, é uma representação numérica de tamanho fixo que facilita a manipulação de dados não estruturados como texto na execução de operações matemáticas, como medidas de similaridade. Para geração dessas incorporações existem diversas opções, inclusive de código aberto como, LLama e Falcon, ou como serviços de terceiros como o da OpenAi que convertem os pedaços criados dos dados consumidos em vetores numéricos. Como no exemplo da chamada para a API da OpenAi abaixo:
curl https://api.openai.com/v1/embeddings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{
"input": "Your text string goes here",
"model": "text-embedding-ada-002"
}'
Response: {
"data": [
{
"embedding": [
-0.006929283495992422,
-0.005336422007530928,
...
-4.547132266452536e-05,
-0.024047505110502243
],
"index": 0,
"object": "embedding"
}
],
"model": "text-embedding-ada-002",
"object": "list",
"usage": {
"prompt_tokens": 5,
"total_tokens": 5
}
}
4. Incorporações em banco de dados vetoriais
Depois que os embeddings forem calculados, podemos armazenar em um banco de dados vetorial. Para essa tarefa existem várias opções como Chroma, Deeplake e Pinecone.
Bancos de dados vetoriais são úteis para armazenar dados de alta dimensão e calcular semelhanças vetoriais. Para o desenvolvimento, utilizamos o Chroma localmente utilizando o SQlite para manter os dados.
from langchain.text_splitter import RecursiveCharacterTextSplitter
def set_embedding(data):
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1024, chunk_overlap=128)
chunks = text_splitter.split_documents(data)
logger.info(f"Splitted documents into {len(chunks)} chunks")
Chroma.from_documents(
documents=chunks,
embedding=OpenAIEmbeddings(),
persist_directory="db"
)
logger.info("Chunks indexed into Chroma")
5. Pergunta
Após os documentos terem sido incorporados e indexados no banco de dados vetorial, a aplicação deve ficar disponível para receber perguntas. Ao consumir a pergunta é necessário que a aplicação utilize o mesmo modelo de incorporação realizado nos dados de contexto para gerar a incorporação da pergunta e assim, utilizar o banco vetorial com os dados salvos anteriormente para buscar os documentos mais semelhantes a incorporação da pergunta recem realizada.
As consultas são retornadas com base na quantidade de documentos selecionados de antemão. Para a proposta estão sendo selecionados 3 pedaços de documentos que mais se assemelham com a pergunta. Importante ressaltar que esses pedaços não são a resposta final mas o contexto relevante que dará insumos para a resposta final.
from langchain.embeddings import OpenAIEmbeddings
def get_embeddings():
db = Chroma(persist_directory="db", embedding_function=OpenAIEmbeddings())
return db.similarity_search(query=config.question, k=3)
6. Formatação do Prompt
Um “prompt” é uma instrução ou uma entrada dada a um sistema de processamento de linguagem natural para solicitar uma resposta ou uma continuação textual sendo essa uma maneira de interagir e direcionar o comportamento do modelo. Esse prompt tem a estrutura representada no trecho de código abaixo, onde o contexto são os documentos resgatados por similaridade da pergunta.
prompt_question = """Answer the question using the personality of ash character from the pokemon anime.
Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer.
{context}
Question: {question}
Answer in Portuguese with very didactically. if possible, use the character's adventures to help explain:"""
8 . Geração da Resposta
Após o prompt criado definimos um pipeline de recuperação que utiliza o armazenamento vetorial retornado e o prompt criado como argumento adicional. Quando repassamos o prompt ao modelo LLM a mágica acontece, o LLM executa o prompt e retorna uma resposta através da integração com a API da OpenAI utilizando o modelo gpt-3.5-turbo;
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import PromptTemplate
from langchain.chat_models import ChatOpenAI
def main(config: Config):
learning_retriever = get_embeddings()
llm = ChatOpenAI(model="gpt-3.5-turbo",temperature=0)
logger.info("Generating answer with LLM")
template_question = """Answer the question using the personality of ash character from the pokemon anime.
Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer.
{context}
Question: {question}
Answer in Portuguese with very didactically. if possible, use the character's adventures to help explain:"""
QA_CHAIN_PROMPT = PromptTemplate(template=template_question, input_variables=["context", "question"])
chain = load_qa_chain(llm, chain_type="stuff", prompt=QA_CHAIN_PROMPT, verbose=True)
answer = chain({"input_documents": learning_retriever, "question": config.question }, return_only_outputs=True)
print(answer["output_text"])
9. Resultados
Após a conclusão da implementação, utilizando o comando a seguir, faço uma pergunta sobre o evento histórico do descobrimento do Brasil. Nesse processo, a resposta adquire traços didáticos e a personalidade do treinador de Pokemon, mostrando o potêncial da proposta.
Pergunta: "Olá Ash, tudo bem ? quem descobriu o Brasil?"
Resposta: "Olá! Tudo bem? Bem, acredito que você esteja se referindo à descoberta
do Brasil pelos portugueses. Na verdade, o Brasil foi descoberto por
Pedro Álvares Cabral em 1500.
Ele era um explorador português que estava em uma expedição para
encontrar uma nova rota para as Índias. Durante a viagem, ele acabou
chegando às terras brasileiras, mais especificamente na região que hoje
conhecemos como Porto Seguro, na Bahia. Foi assim que o Brasil foi
oficialmente descoberto pelos europeus.
Durante minhas aventuras, também tive a oportunidade de conhecer
muitas regiões do Brasil e aprender sobre sua história e cultura.
É um país incrível, cheio de diversidade e belezas naturais.
Espero ter ajudado com sua pergunta!

Conclusão
Para transformar a educação brasileira, é necessário adotar uma abordagem multifacetada com diversas abordagens de ensino. Isso envolve não apenas um aumento nos investimentos e recursos, mas também uma mudança cultural que valorize o aprendizado como um meio de crescimento pessoal e desenvolvimento social. A tecnologia, quando empregada estrategicamente, pode desempenhar um papel crucial nesse processo de transformação, capacitando os alunos a se tornarem aprendizes autônomos e entusiastas.
O experimento realizado é simples e básico mas pode dar uma idéia do potencial e enjar soluções de processamento natural dentro da sala de aula como apoio aos alunos.
O futuro da educação brasileira dependerá da nossa capacidade coletiva de abraçar essa mudança e de nutrir uma mentalidade de aprendizado contínuo. A educação necessita ser estabelecida como uma política de Estado, transcendendo os limites de um governo específico. Entretanto, compreendemos que esperar essa perspectiva da classe política pode se mostrar um desafio complexo. Por essa razão, é fundamental que a mudança seja abraçada pelo próprio aluno, à luz do conhecimento que adquire.
O código está disponivel eim: https://github.com/jairodrigues/langchain-qna/tree/feat/lang-chain-qna
Bibliográfia:
[1] Educação infantil e pandemia COVID-19: o que dizem as pesquisas — https://ojs.brazilianjournals.com.br/ojs/index.php/BRJD/article/view/47335/pdf
[2] Desinteresse escolar: Em busca de uma compreensão: https://www.nucleodoconhecimento.com.br/educacao/desinteresse-escolar
[3] Fatores influenciadores no prodcesso de aprendizagem: http://pepsic.bvsalud.org/scielo.php?script=sci_arttext&pid=S0103-84862017000100008
[4] bibliteca Python com abstrações flexíveis e o conjunto abrangente de ferramentas que permitem aos desenvolvedores aproveitar o poder dos LLMs: https://www.langchain.com
[5] História do Brasil — Um período de mais de quinhentos anos, desde as raízes da colonização portuguesa até nossos dias. Boris Fausto. Edusp — 1996.
[6] You Can Now Build A Chatbot To Talk To Your Internal Knowledge Base. https://levelup.gitconnected.com/you-can-now-build-a-chatbot-to-talk-to-your-internal-knowledge-base-b6066cacf2d5