Sumarização de código com Granite

Publicado 14/01/2026
Atualizado 17/07/2026
Renderização 3D de arcos de vidro
By Joshua Noble

Introdução

A sumarização de código é o processo de gerar uma descrição em linguagem natural de trechos de código. As tarefas comuns de sumarização de código incluem explorar uma nova base de código, aprender uma nova linguagem de programação ou gerar comentários e explicações de funções. Gerar sumarização de trechos de código é semelhante a gerar um resumo de texto de um documento em linguagem natural. A diferença reside no fato de que o grande modelo de linguagem (LLM), que gera o resumo, precisa compreender a linguagem de programação que está analisando, ao mesmo tempo que identifica a lógica subjacente daquilo que se pretende realizar.

A sumarização de código é uma parte valiosa do desenvolvimento de software, auxiliando na manutenção do software ao realizar a sumarização automática do código-fonte, criar resumos em linguagem natural para documentação ou analisar grandes bases de código. Os modelos de LLM mais recentes, que utilizam uma abordagem baseada em transformadores, podem funcionar tanto como modelos de sumarização de código quanto para geração de código. Essas funções são possíveis porque os modelos foram treinados em grandes conjuntos de dados construídos a partir de fontes como repositórios do Github, que incluem código e comentários juntamente com a documentação desse código.

Antes da popularização dos LLMs, as abordagens de sumarização de código exigiam a análise da semântica do código e a geração de uma árvore de sintaxe abstrata (AST) de cada identificador a partir do código, que poderia então ser usada para gerar a documentação.1,2 Com o advento da deep learning e das redes neurais, as abordagens enraizadas na ciência da computação foram abandonadas em favor de abordagens que se inspiravam mais na metodologia de tradução automática neural3,4.

Para modelos de transformadores, janelas de contexto maiores levam a melhores resultados. Muitos dos mais novos modelos de última geração do Granite Code, como o Granite-8B-Code-Instruct-128K, têm uma janela de contexto de 128k. Uma janela de contexto maior permite que o modelo armazene mais texto na memória de trabalho. Isso ajuda a monitorar os principais momentos e detalhes em uma conversa prolongada ou em um documento ou base de código longo. Essa memória de trabalho permite que um chatbot baseado em LLM gere respostas que façam sentido no momento imediato e em um contexto mais amplo, ajudando-o a superar modelos com janelas contextuais menores, tanto na avaliação humana quanto nas métricas de avaliação.5

Janelas de contexto maiores permitem que os modelos armazenem mais texto em sua memória de trabalho, o que ajuda a acompanhar momentos e detalhes importantes em conversas prolongadas, documentos extensos ou bases de código complexas.

Quando o ChatGPT foi lançado pela primeira vez, sua janela de contexto era de 4.000 tokens. Se a conversa ultrapassasse o limite de 3.000 palavras da interface de bate-papo, era provável que o chatbot tivesse alucinações e se desviasse do assunto. Atualmente, o padrão é de 32.000 tokens, com o mercado avançando para 128.000 tokens. Isso é aproximadamente o comprimento de um livro de 250 páginas. A IBM agora tem dois modelos Granite com uma janela de contexto de 128.000 tokens, e mais estão a caminho.

Projeto 3D de bolas rolando em uma pista

As últimas notícias e insights sobre IA 


Informações e notícias selecionadas por especialistas sobre IA, nuvem e muito mais no boletim informativo semanal Think. 

Etapa 1. Configure seu ambiente

Nesta etapa, orientaremos você na criação de uma conta IBM para acessar os Jupyter Notebooks.

1. Faça login no watsonx.ai usando sua conta IBM Cloud.

2. Clique em + para criar um novo projeto.

a. Selecione Criar um projeto.

b. Insira o nome do projeto no campo Nome.

c. Crie um Cloud Object Storage para armazenar os ativos do seu projeto, caso ainda não tenham sido criados.

d. Selecione Criar.

3. Crie um Jupyter Notebook.

a. Selecione a guia Ativos no seu ambiente de projeto.

b. Clique em Novo ativo.

c. Selecione a opção Trabalhar com modelos no painel esquerdo.

d. Clique em Trabalhar com dados e modelos usando notebooks Python e R.

e. Insira um nome para o notebook no campo Nome. Escolha o Runtime 23.1 em Python (4 vCPUs e 16 GB de RAM) para definir a configuração.

f. Selecione Criar.

4. Configure uma instância do watsonx.ai Runtime e uma chave de API

a. Crie uma instância do serviço do watsonx.ai Runtime (selecione a região apropriada e escolha o plano Lite, que é uma instância gratuita).

b. Gere uma chave de API.

c. Associe a instância do serviço do watsonx.ai Runtime ao projeto que você criou em watsonx.ai.

Passo 2: carregar o Granite Code Instruct

Primeiro, instalaremos a biblioteca de código aberto do Hugging Face Hub para baixar os modelos:

!pip install huggingface_hub

Agora podemos baixar o Granite-8B-Code-Instruct-128K:

from transformers import AutoTokenizer, AutoModelForCausalLM

tokenizer = AutoTokenizer.from_pretrained("ibm-granite/granite-8b-code-instruct-128k")
model = AutoModelForCausalLM.from_pretrained("ibm-granite/granite-8b-code-instruct-128k")

Agora podemos começar a usar o Granite Code Instruct.

Passo 3: obter uma explicação simples

Vamos adicionar ao nosso modelo uma chamada de função bastante complexa da biblioteca GluonTS, retirada do repositório deles no GitHub. Este é um bloco de código extenso para colar em um prompt, então vamos armazená-lo em uma variável:

ll_func_2 = """

    def call(
        self, data: torch.Tensor, weights: torch.Tensor
    ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:

    assert (
        data.shape == weights.shape
    ), "data and observed_indicator must have same shape"

    with torch.no_grad():

        observed_data = torch.where(weights == 1, data, torch.nan)
        med = torch.nanmedian(observed_data, dim=self.dim, keepdim=True).values
        q1 = torch.nanquantile(observed_data, 0.25, dim=self.dim, keepdim=True)
        q3 = torch.nanquantile(observed_data, 0.75, dim=self.dim, keepdim=True)
        iqr = q3 - q1

        # se os dados observados forem todos zero, nanmedian retornará NaN
        loc = torch.where(torch.isnan(med), torch.zeros_like(med), med)
        scale = torch.where(torch.isnan(iqr), torch.ones_like(iqr), iqr)
        scale = torch.maximum(scale, torch.full_like(iqr, self.minimum_scale))
        scaled_data = (data - loc) / scale

        if not self.keepdim:
            loc = torch.squeeze(loc, dim=self.dim)
            scale = torch.squeeze(scale, dim=self.dim)

        # verifica se não há valores NaN nos dados dimensionados, em loc ou scale
        assert not torch.any(torch.isnan(scaled_data))
        assert not torch.any(torch.isnan(loc))
        assert not torch.any(torch.isnan(scale))
        assert not torch.any(scale == 0)

        return scaled_data, loc, scaledef call(
            self, data: torch.Tensor, weights: torch.Tensor
        ) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]:

        assert (
            data.shape == weights.shape
        ), "data and observed_indicator must have same shape"

 

Agora podemos solicitar ao Granite Code que gere uma sumarização. Para isso, tokenizamos nosso chat e, em seguida, chamamos, callingmodel.generate()

chat = [
{ "role": "user", "content": "Explain what this function does" + ll_func_2 },
]
chat = tokenizer.apply_chat_template(chat, tokenize=False, add_generation_prompt=True)

# fazer com que o codificador transforme o texto em token de saída
inputs = tokenizer(chat, return_tensors="pt").input_ids
start_index = inputs.shape[-1]

# gerar tokens de saída
output = model.generate(inputs, max_new_tokens=1500)

# fazer com que o decodificador transforme o token de saída em texto
output = tokenizer.batch_decode(output[start_index:])

# percorrer o lote a ser impresso; neste exemplo, o tamanho do lote é 1
 print(output[0])

Vamos ver a sumarização gerada:

Resposta:
Essa função realiza a normalização de dados usando o método do intervalo interquartil (IQR). São necessários dois argumentos: data e weights. O argumento data é um tensor de formato (batch_size, sequence_ length, hidden_size), em que batch_size é o número de amostras em um lote, sequence_ length é o comprimento da sequência de entrada e hidden_size é a dimensionalidade do estado oculto. O argumento weights é um tensor de forma (batch_size, sequence_ length), em que cada elemento é 0 ou 1, indicando se o elemento correspondente no tensor data está observado ou ausente.

A função primeiro verifica se os tensores de data e weights têm a mesma forma. Em seguida, calcula a mediana e o IQR dos pontos de dados observados (aqueles com um peso de 1) usando as funções torch.nanmedian e torch.nanquantile. A função torch.nanmedian calcula a mediana ao longo da dimensão especificada (self.dim), enquanto a função torch.nanquantile calcula os percentis 25 e 75.

Em seguida, a função calcula os parâmetros de localização (loc) e escala (scale) da distribuição normalizada. A localização é definida como a mediana dos pontos de dados observados, e a escala é definida como o IQR dos pontos de dados observados. Se todos os pontos de dados observados forem zero, a função define a localização como zero. A função também garante que a escala tenha pelo menos um valor mínimo (self.minimum_scale) para evitar a divisão por zero.

Finalmente, a função calcula os dados normalizados (scaled_data) subtraindo a localização e dividindo pela escala. Se o argumento keepdim for definido como False, a função removerá a dimensão especificada dos tensores de loc e scale. A função também realiza asserções para garantir que os tensores de dados normalizados, loc e scale não contenham valores NaN nem valores zero em scale.

A função retorna uma tupla contendo os tensores de dados normalizados, localização e escala.

A descrição é extremamente detalhada e descreve com precisão a função que passamos como parâmetro e o algoritmo subjacente.

Etapa 4: gerar documentação

A geração de documentação é uma aplicação poderosa do sumarização de código, pois não só explica o código para qualquer usuário futuro que o leia, como também pode ajudar a gerar documentação usando uma ferramenta como o pydoc.

Agora podemos solicitar para o Granite Code gerar docstrings para uma função. Devido à janela de contexto maior, podemos transmitir uma função inteira com uma solicitação para gerar uma docstring.

Por favor, escreva uma docstring em Python formatada corretamente para a seguinte função:

def get_json_from_html(html: str, key: str, num_chars: int = 2, stop: str = '"') -> str:
    pos_begin = html.find(key) + len(key) + num_chars
    pos_end = html.find(stop, pos_begin)
    return html[pos_begin:pos_end]

O Granite Code retorna uma excelente documentação no formato Python:

Extrai um objeto JSON da string HTML fornecida, utilizando a chave e o caractere de parada especificados.
Argumentos:

     html (str): a string HTML de input da qual o objeto JSON será extraído.

    key (str): a chave usada para localizar o início do objeto JSON na string HTML.

    num_chars (int, opcional): o número de caracteres após a chave a serem incluídos no objeto JSON extraído. O padrão é 2.

    stop (str, opcional): o caractere que marca o fim do objeto JSON na string HTML. O valor padrão é "".

Retorna:

    str: o objeto JSON extraído como uma string.

Agora, se quisermos, podemos reutilizar o prompt anterior que ainda está presente na grande janela de contexto:

chat = "Reescreva a função anterior para que seja um método de classe e inclua as docstrings."

# fazer com que o codificador transforme texto em tokens de saída
inputs = tokenizer(chat, return_tensors="pt").input_ids
start_index = inputs.shape[-1]

# gerar tokens de saída
output = model.generate(inputs, max_new_tokens=1500)

# fazer com que o decodificador transforme o token de saída em texto
output = tokenizer.batch_decode(output[start_index:])

# percorrer o lote a ser impresso; neste exemplo, o tamanho do lote é 1
 print(output[0])

Isso retorna

class HtmlJsonExtractor:

    def init(self, html):

    """
    Inicializa o objeto HtmlJsonExtractor com a string HTML fornecida.

    Argumentos:

 html (str): a string HTML de input da qual o objeto JSON será extraído.
    """

        self.html = html

    @classmethod

    def extract(cls, html, key, num_chars=2, stop='"'):

    """
    Extrai um objeto JSON da string HTML fornecida usando a chave especificada e o caractere de parada.

    Argumentos:

         html (str): a string HTML de input da qual o objeto JSON será extraído.

        key (str): a chave usada para localizar o início do objeto JSON na string HTML.

        num_chars (int, opcional): o número de caracteres após a chave a serem incluídos no objeto JSON extraído. O padrão é 2.

             stop (str, opcional): o caractere que marca o fim do objeto JSON na string HTML. O padrão é '".

    Retorna:

        str: o objeto JSON extraído como uma string.
    """

        pos_begin = html.find(key) + len(key) + num_chars
        pos_end = html.find(stop, pos_begin)
        return html[pos_begin:pos_end]

O modelo agora criou uma classe com um nome apropriado, tornou o código anterior um método dessa classe e inseriu nossas docstrings.

Passo 5: obter uma revisão de código

Vamos agora solicitar ao modelo para nos ajudar a otimizar um trecho de código:

chat = """Por favor, otimize o código a seguir:

def fib(n):
    if (n < 2):
        return 1
    else:
        return fib(n-1) + fib(n-2)"""

O Granite Code retorna:

A função Python fib(n) fornecida calcula o enésimo número de Fibonacci usando recursão. No entanto, essa implementação tem uma complexidade de tempo de O(2^n), que é ineficiente para grandes entradas. Podemos

otimizar isso usando programação dinâmica ou memorização para reduzir a complexidade de tempo para O(n). Aqui está uma versão otimizada da função:

```python

def fib_optimized(n, memo={}):
    if n < 2:
        return 1
    elif n not in memo:
        memo[n] = fib_optimized(n-1, memo) + fib_optimized(n-2, memo)
    return memo[n]
```

Essa versão otimizada usa um dicionário memo para armazenar números de Fibonacci calculados anteriormente. Ao calcular o enésimo número de Fibonacci, ele primeiro verifica se já foi calculado e armazenado na memória. Em caso afirmativo, ele retorna o valor armazenado em vez de recalculá-lo, o que economiza tempo e melhora o desempenho.

Aqui, o modelo explicou não apenas os problemas de eficiência da função e forneceu a complexidade Big-O da implementação, mas também apresentou uma implementação aprimorada. Fornecer revisões e explicações é uma forma de aproveitar a sumarização e, como parte de uma geração de código mais geral, ajudar os desenvolvedores a melhorar.

Resumo

Neste tutorial, você aprendeu sobre sumarização de código e usou o modelo Granite Code com uma janela de contexto expandida de 128 mil tokens para gerar explicações do código Python. Também usamos prompts para gerar nova documentação, adicionar uma classe em torno de um trecho de código e usar a janela de contexto expandido para acrescentar essa documentação a uma nova janela de código. Por fim, fizemos com que o Granite Code analisasse e resumisse um trecho de código e explicasse como ele poderia ser aprimorado.

Autor

Joshua Noble

Data Scientist

Soluções relacionadas
IBM Bob

Acelere a entrega de software com o IBM® Bob, seu parceiro de IA para desenvolvimento seguro e consciente de intenção.

Explore o IBM Bob
Soluções de IA para desenvolvedores

Desenvolva, implemente e gerencie aplicações de IA mais rápido com ferramentas prontas para empresas.

Explore IA para desenvolvedores
Serviços de modernização de aplicações

Reimagine sistemas legados com modernização inteligente de IA.

Explore os serviços de modernização de aplicações
Dê o próximo passo

Utilize IA generativa e automação avançada para oferecer código pronto para empresas com maior velocidade e consistência. Os modelos do Bob aumentam os conjuntos de habilidades dos desenvolvedores, agilizando os fluxos de trabalho de modernização e simplificando tarefas complexas de desenvolvimento.

  1. Conheça o agente de programação de IA
  2. Explore soluções de IA para desenvolvedores
Referências

1 Sonia Haiduc, Jairo Aponte, Andrian Marcus, “Supporting program comprehension with source code summarization,” ICSE ‘10: Proceedings of the 32nd ACM/IEEE International Conference on Software Engineering https://doi.org/10.1145/3377811.3380383.

2 Paul W. McBurney, Collin McMillan, “Automatic Source Code Summarization of Context for Java Methods,” https://ieeexplore.ieee.org/document/7181703.

3 Chen Lin, Zhichao Ouyang, Junqing Zhuang, Jianqiang Chen, Hui Li, Rongxin Wu, “Improving Code Summarization with Block-wise Abstract Syntax Tree Splitting” IEEE/ACM, International Conference on Program Comprehension (ICPC 2021) https://arxiv.org/abs/2103.07845.

4 Jian Zhang, Xu Wang, Hongyu Zhang, Hailong Sun, Xudong Liu, “Retrieval-based neural source code summarization,” ICSE ‘10: Proceedings of the 32nd ACM/IEEE International Conference on Software Engineeringhttps://doi.org/10.1145/1810295.1810335.

5 Xinyi Hou, Yanjie Zhao, Yue Huang, Zhou Yang, Kailong Wang, Li Li, Xiapu Luo, David Jin, John Grundy, Haoyu Wang, “Large Language Models for Software Engineering: A Systematic Literature Review”, https://arxiv.org/abs/2308.10620.