Codezusammenfassung mit Granite

Veröffentlicht 14. Januar 2026
Aktualisiert 17. Juli 2026
3D-Rendering von Glasbögen
By Joshua Noble

Einführung

Codezusammenfassung ist der Prozess, bei dem eine Beschreibung von Codefragmenten in natürlicher Sprache generiert wird. Gängige Aufgaben der Code-Zusammenfassung sind das Erkunden einer neuen Codebasis, das Erlernen einer neuen Programmiersprache oder das Generieren von Codekommentaren und Funktionserklärungen. Das Generieren einer Zusammenfassung eines Code-Snippets ist vergleichbar mit dem Generieren einer Textzusammenfassung eines Dokuments in natürlicher Sprache. Es unterscheidet sich, weil das Large Language Model (LLM) die Programmiersprache verstehen muss, durch die es liest, und gleichzeitig die zugrundeliegende Logik dessen erkennen muss, was es erreichen will.

Code-Zusammenfassungen sind ein wertvoller Bestandteil der Softwareentwicklung, da sie bei der Softwarewartung helfen, indem sie automatische Quellcode-Zusammenfassungen, das Erstellen von Zusammenfassungen in natürlicher Sprache für Dokumentationen oder das Parsen groß angelegter Codebasen unterstützen. Neuere LLM-Modelle, die einen Transformer-basierten Ansatz verwenden, können entweder als Codezusammenfassungsmodelle oder auch zur Codegenerierung dienen. Diese Funktionen sind möglich, weil die Modelle auf großen Datensätzen trainiert wurden, die aus Quellen wie Github-Repositories gebaut wurden, die Code und Kommentare sowie Dokumentation für diesen Code enthalten.

Bevor LLMs populär wurden, erforderten Ansätze zur Codezusammenfassung das Parsen der Codesemantik und die Generierung eines abstrakten Syntaxbaums (AST) jedes Itentifiers aus dem Code, der dann zur Erstellung von Dokumentation verwendet werden konnte. 1,2 Mit dem Aufkommen von Deep Learning und neuronalen Netzen wurden Ansätze, die in der Informatik wurzeln, zugunsten von Ansätzen aufgegeben, die mehr von der Methodik der neuronalen maschinellen Übersetzung übernommen haben3,4.

Bei Transformer-Modellen führen größere Kontextfenster zu besseren Ergebnissen. Viele der neuesten Granite Code-Modelle wie Granite-8B-Code-Instruct-128K haben ein Kontextfenster von 128.000 Tokens. Ein größeres Kontextfenster ermöglicht es dem Modell, mehr Text im Arbeitsspeicher zu halten. Dies hilft dabei, wichtige Momente und Details in einem langwierigen Chat, einem umfangreichen Dokument oder einer Codebasis im Blick zu behalten. Dieses Arbeitsgedächtnis ermöglicht es einem LLM-basierten Chatbot, Antworten zu generieren, die im unmittelbaren Moment und über einen längeren Kontext Sinn ergeben, sodass sie Modelle mit kleineren Kontextfenstern sowohl durch menschliche Bewertung als auch durch Metriken übertreffen können.5

Größere Kontextfenster ermöglichen es Modellen, mehr Text in ihrem Arbeitsspeicher zu halten, wodurch wichtige Momente und Details in langwierigen Chats, umfangreichen Dokumenten oder Codebasen besser im Blick behalten werden können.

Als ChatGPT zum ersten Mal eingeführt wurde, hatte das Kontextfenster 4.000 Token. Wenn Ihre Konversation das Limit von 3.000 Wörtern für die Chat-Oberfläche überschreiten würde, halluzinierte der Chatbot wahrscheinlich und schweifte vom Thema ab. Heute liegt der Standard bei 32.000 Token, wobei die Branche auf 128.000 Token umsteigt. Das entspricht ungefähr der Länge eines 250-seitigen Buches. IBM bietet derzeit zwei Granite-Modelle mit einem Token-Fenster von 128.000 an, weitere sind in Planung.

3D-Design aus Kugeln, die auf einer Schiene rollen

Die neuesten Erkenntnisse und Insights zu KI

Von Experten kuratierte Erkenntnisse und Neuigkeiten zu KI, Cloud und mehr im wöchentlichen Think Newsletter. 

Schritt 1: Einrichten Ihrer Umgebung

In diesem Schritt zeigen wir Ihnen, wie Sie ein IBM-Konto erstellen, um auf Jupyter Notebooks zuzugreifen.

1. Melden Sie sich mit Ihrem IBM Cloud-Konto bei watsonx.ai an.

2. Klicken Sie auf „+“, um ein neues Projekt zu erstellen.

a. Wählen Sie „Create an empty project“.

b. Geben Sie im Feld „Name“ einen Projektnamen ein.

c. Erstellen Sie einen Cloud Object Storage zum Speichern Ihrer Assets, falls dieser noch nicht erstellt wurde.

d. Wählen Sie „Create“ aus.

3. Erstellen Sie ein Jupyter Notebook.

a. Wählen Sie die Registerkarte „Assets“ in Ihrer Projektumgebung.

b. Klicken Sie auf „New asset“.

c. Wählen Sie im linken Bereich die Option „Working with models“ aus.

d. Klicken Sie auf „Working with data and models using Python and R notebooks“.

e. Geben Sie im Feld „Name“ einen Namen für Ihr Notebook ein. Wählen Sie „Runtime 23.1 on Python (4 vCPU 16 GB RAM)“ aus, um die Konfiguration zu definieren.

f. Wählen Sie „Create“ aus.

4. Richten Sie eine watsonx.ai Runtime-Instanz und einen API-Schlüssel ein.

a. Erstellen Sie eine watsonx.ai Runtime-Service-Instanz (wählen Sie Ihre entsprechende Region aus und wählen Sie den Lite-Plan, der eine kostenlose Instanz ist).

b. Generieren Sie einen API-Schlüssel.

c. Verknüpfen Sie die watsonx.ai Runtime-Service-Instanz mit dem Projekt, das Sie in watsonx.ai erstellt haben.

Schritt 2: Granite Code Instruct laden

Zuerst installieren wir die Open-Source-Bibliothek Hugging Face Hub, um Modelle herunterzuladen:

!pip install huggingface_hub

Jetzt können wir Granite-8B-Code-Instruct-128K herunterladen:

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")

Jetzt können wir mit der Verwendung von Granite Code Instruct beginnen.

Schritt 3: Eine einfache Erklärung abrufen

Geben wir unserem Modell einen recht komplexen Funktionsaufruf aus der GluonTS-Bibliothek, der aus deren GitHub-Repository stammt. Das ist ein langer Codeblock, der in einen Prompt eingefügt werden soll, sodass wir ihn in einer Variablen speichern:

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

        # if observed data is all zeros, nanmedian returns 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)

        # assert no nans in scaled data, loc or 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"

 

Jetzt können wir Granite Code um eine Zusammenfassung bitten, indem wir unseren Chat tokenisieren und dann callingmodel.generate() aufrufen.

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

# have the encoder turn text into output tokens
inputs = tokenizer(chat, return_tensors="pt").input_ids
start_index = inputs.shape[-1]

# generate output tokens
output = model.generate(inputs, max_new_tokens=1500)

# have the decoder turn output tokens into text
output = tokenizer.batch_decode(output[start_index:])

# loop over the batch to print, in this example the batch size is 1
print(output[0])

Schauen wir uns die generierte Zusammenfassung an:

Answer:
This function performs data normalization using the interquartile range (IQR) method. It takes two arguments: data and weights. The data argument is a tensor of shape (batch_size, sequence_length, hidden_size), where batch_size is the number of samples in a batch, sequence_length is the length of the input sequence, and hidden_size is the dimensionality of the hidden state. The weights argument is a tensor of shape (batch_size, sequence_length), where each element is either 0 or 1, indicating whether the corresponding element in the data tensor is observed or missing.

The function first checks that the data and weights tensors have the same shape. Then, it computes the median and IQR of the observed data points (those with a weight of 1) using the torch.nanmedian and torch.nanquantile functions. The torch.nanmedian function computes the median along the specified dimension (`self.dim`), while the torch.nanquantile function computes the 25th and 75th percentiles.

Next, the function computes the location (`loc`) and scale (`scale`) parameters of the normalized distribution. The location is set to the median of the observed data points, and the scale is set to the IQR of the observed data points. If the observed data points are all zeros, the function sets the location to zero. The function also ensures that the scale is at least a minimum value (`self.minimum_scale`) to avoid division by zero.

Finally, the function computes the normalized data (`scaled_data`) by subtracting the location and dividing by the scale. If the keepdim argument is set to False, the function removes the specified dimension from the location and scale tensors. The function also performs assertions to ensure that the normalized data, location, and scale tensors do not contain any NaN values or zeros in the scale.

The function returns a tuple containing the normalized data, location, and scale tensors.

Die Beschreibung ist sowohl sehr detailliert als auch präzise und beschreibt die übergebene Funktion sowie den zugrunde liegenden Algorithmus.

Schritt 4: Dokumentation generieren

Die Generierung von Dokumentation ist eine leistungsstarke Anwendung der Code-Zusammenfassung, da sie nicht nur den Code für jeden zukünftigen Benutzer, der den Code liest, erklärt, sondern auch bei der Generierung von Dokumentation mithilfe eines Tools wie pydoc helfen kann.

Wir können jetzt Granite Code dazu auffordern, Docstrings für eine Funktion zu generieren. Aufgrund des größeren Kontextfensters können wir eine ganze Funktion zusammen mit einer Anfrage zur Generierung eines Docstrings übergeben. 

„Please write a properly formatted Python docstring for the following function:“

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]

Granite Code liefert ausgezeichnete Dokumentation im Python-Format:

Extracts a JSON object from the given HTML string using the specified key and stop character.
Args:

    html (str): The input HTML string to extract the JSON object from.

    key (str): The key used to locate the start of the JSON object in the HTML string.

    num_chars (int, optional): The number of characters after the key to include in the extracted JSON object. Defaults to 2.

    stop (str, optional): The character that marks the end of the JSON object in the HTML string. Defaults to '"'.

Returns:

    str: The extracted JSON object as a string.

Wenn wir wollen, können wir nun den vorherigen Prompt wiederverwenden, der im großen Kontextfenster noch vorhanden ist:

chat = "Rewrite the previous function to be a class method and include the docstrings."

# have the encoder turn text into output tokens
inputs = tokenizer(chat, return_tensors="pt").input_ids
start_index = inputs.shape[-1]

# generate output tokens
output = model.generate(inputs, max_new_tokens=1500)

# have the decoder turn output tokens into text
output = tokenizer.batch_decode(output[start_index:])

# loop over the batch to print, in this example the batch size is 1
print(output[0])

Dies gibt Folgendes zurück:

class HtmlJsonExtractor:

    def init(self, html):

    """
    Initializes the HtmlJsonExtractor object with the given HTML string.

    Args:

        html (str): The input HTML string to extract JSON objects from.
    """

        self.html = html

    @classmethod

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

    """
    Extracts a JSON object from the given HTML string using the specified key and stop character.

    Args:

        html (str): The input HTML string to extract the JSON object from.

        key (str): The key used to locate the start of the JSON object in the HTML string.

        num_chars (int, optional): The number of characters after the key to include in the extracted JSON object. Defaults to 2.

             stop (str, optional): The character that marks the end of the JSON object in the HTML string. Defaults to '"'.

    Returns:

        str: The extracted JSON object as a string.
    """

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

Das Modell hat nun eine Klasse mit entsprechendem Namen erstellt, den vorherigen Code zu einer Methode dieser Klasse gemacht und unsere Docstrings eingefügt.

Schritt 5: Code-Review erhalten

Prompten wir nun das Modell, uns bei der Optimierung eines Code-Snippets zu helfen:

chat = """Please optimize the following code:

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

Granite Code gibt Folgendes zurück:

The given Python function fib(n) calculates the nth Fibonacci number using recursion. However, this implementation has a time complexity of O(2^n), which is inefficient for large inputs. We can

optimize it using dynamic programming or memoization to reduce the time complexity to O(n). Here's an optimized version of the function:

```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]
```

This optimized version uses a dictionary memo to store previously calculated Fibonacci numbers. When calculating the nth Fibonacci number, it first checks if it has already been calculated and stored in memo. If so, it returns the stored value instead of recalculating it, which saves time and improves performance.

Hier hat das Modell nicht nur erklärt, was an der Funktion in Bezug auf Effizienz nicht stimmt und der Implementierung eine Big-O-Komplexität gegeben, sondern auch eine bessere Implementierung geliefert. Das Bereitstellen von Überprüfungen und Erklärungen ist eine Möglichkeit, Zusammenfassungen zu nutzen und als Teil der allgemeineren Codegenerierung Entwicklern zu helfen, sich zu verbessern.

Zusammenfassung

In diesem Tutorial haben Sie etwas über Code-Zusammenfassung gelernt und das Granite Code-Modell mit einem erweiterten Kontextfenster von 128.000 Tokens verwendet, um Erklärungen für Python-Code zu generieren. Wir haben außerdem Prompts verwendet, um neue Dokumentation zu generieren, eine class um ein Stück Code hinzuzufügen und das erweiterte Kontextfenster zu nutzen, um diese Dokumentation an ein neues Codefenster anzuhängen. Zum Schluss ließen wir Granite Code einen Codeausschnitt analysieren und zusammenfassen und erläutern, wie er verbessert werden könnte.

Autor

Joshua Noble

Data Scientist

Verwandte
IBM Bob

Beschleunigen Sie die Softwarebereitstellung mit Bob, Ihrem KI-Partner für sichere, absichtsorientierte Entwicklung.

IBM Bob erkunden
KI für Entwicklerlösungen

Entwickeln, bereitstellen und verwalten Sie KI-Anwendungen schneller mit unternehmensgerechten Tools.

KI für Entwickler erkunden
Services zur Anwendungsmodernisierung

Gestalten Sie Altsysteme durch intelligente KI-Modernisierung neu.

Services zur Anwendungsmodernisierung erkunden
Machen Sie den nächsten Schritt

Nutzen Sie generative KI und fortschrittliche Automatisierung, um unternehmensgerechten Code schneller und konsistenter bereitzustellen. Bob-Modelle erweitern die Kompetenzen der Entwickler, optimieren Workflows für die Modernisierung und vereinfachen komplexe Entwicklungsaufgaben.

  1. AI Coding Agenten erkunden
  2. Lösungen für KI-Entwickler entdecken
Verweise

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.