Duże modele językowe (ang. Large Language Model, LLM) są coraz częściej wykorzystywane do analizy i generowania treści związanych z kodem źródłowym. W szczególności dwa obszary – streszczanie kodu oraz opisywanie zmian w kodzie (generowanie „commit message”) – są przedmiotem aktywnych badań i eksperymentów ze względu na możliwość usprawnienia dokumentowania zmian w repozytoriach kodu.
Niniejszy wpis przedstawia przegląd zastosowań, aktualnych rozwiązań, narzędzi i benchmarków w tym zakresie oraz podsumowuje wyniki eksperymentów przeprowadzonych na repozytorium LangChain przy użyciu modeli OpenAI.
Zastosowanie LLM w analizie kodu
LLM-y są wykorzystywane w szerokim zakresie zadań związanych z tzw. code intelligence [1]. Wśród przykładowych zastosowań wymienić można:
- generowanie kodu,
- tłumaczenie między językami programowania, migracja między pakietami/wersjami,
- generowanie testów, danych syntetycznych, mocków,
- refaktoryzację,
- wykrywanie błędów i luk bezpieczeństwa,
- streszczanie i dokumentowanie kodu,
- wsparcie w tworzeniu pull requestów i commitów.
Przypadki użycia
Poprawa jakości dokumentacji zmian
Commit message to podstawowy mechanizm dokumentowania zmian w kodzie. Dobrze sformułowane wiadomości:
- ułatwiają przeglądanie historii zmian (git log, git blame),
- wspomagają debugowanie i analizę regresji,
- są używane do automatycznego generowania changelogów i release notes.
Jednak w praktyce wiele commitów zawiera:
- lakoniczne wiadomości typu „fix”, „update”, „changes”,
- niepełne lub niezgodne z rzeczywistą zmianą opisy,
- zbędne szczegóły techniczne, które nie wyjaśniają celu zmiany.
Automatyzacja może poprawić spójność i jakość takich opisów.
Redukcja obciążenia programistów
Pisanie dobrych commitów wymaga czasu i koncentracji. Wiadomości commitów są często traktowane jako zadanie poboczne. Automatyzacja tego procesu pozwala odciążyć programistów przy jednoczesnym zachowaniu standardu jakości.
Wsparcie dla standardów organizacyjnych
W większych firmach i projektach open-source obowiązują konwencje commitów, np.:
- Conventional Commits (feat:, fix:, refactor:, docs:),
- Semantic Versioning (patch/minor/major),
- Gitmoji, PR templates itd.
Automatyczne generowanie commitów pozwala egzekwować takie standardy programowo, bez ręcznego pilnowania konwencji przez code reviewers.
Wspomaganie analizy zmian przez inne zespoły
W projektach z podziałem na zespoły (np. backend, QA, DevOps), commit message może służyć jako źródło informacji:
- dla QA: co testować, jakie funkcjonalności uległy zmianie,
- dla DevOps: które komponenty wymagają deploymentu,
- dla analityków biznesowych: które zgłoszenia z JIRA zostały zrealizowane.
LLM może wzbogacić wiadomość o informacje typu: „Zmiana dotyczy walidacji danych wejściowych dla endpointu /user/register – potencjalny wpływ na rejestrację nowych użytkowników”.
Wsparcie przy generowaniu changelogów i automatyzacji release’ów
W narzędziach typu Release Drafter treść commitów jest używana do generowania changelogów. Automatyczne generowanie spójnych i treściwych opisów zmian pozwala tworzyć changelogi bez dodatkowego nakładu pracy.
Metody klasyczne vs. LLM
Punktem wyjścia dla automatycznego streszczanie zmian w kodzie jest wynik git diff (unified diff format). Dodatkowo wykorzystać może:
- pierwotne pliki z kodem źródłowym,
- opisy z systemu śledzenia zgłoszeń (JIRA, GitHub),
- zależności w kodzie (wynik statycznej analizy kodu: relacje wywołujący-wołany).
W okresie poprzedzającym powszechne użycie LLM-ów, generowanie commitów opierało się na:
- podejściach regułowych (szablony w postaci: Modyfikacja funkcji X w pliku Y),
- analizie składniowej – zamiast analizy zmian plików z kodem analizowane są zmiany w AST (Abstract Syntax Tree),
- prostych metodach tekstowych lub statystycznych modelach języka.
Przegląd takich metod zawiera publikacja Automatic Code Summarization: A Systematic Literature Review.
Obecnie dominują modele typu transformer, trenowane na dużych korpusach kodu i komentarzy. Modele takie jak CodeT5+, CodeLlama, DeepSeek-Coder czy GPT-4 mogą być wykorzystywane do tłumaczenia kodu na język naturalny, generowania streszczeń lub automatycznych commitów. Więcej na ten temat można znaleźć w pracy Source Code Summarization in the Era of Large Language Models.
Ewaluację generowania commit message przeprowadza się, porównując otrzymany tekst z referencją w postaci oryginalnego wpisu. Standardowe metryki oparte na N-gramach, takie jak BLEU czy ROUGE, mają problem z uchwyceniem niuansów semantycznych, stąd dużą popularnością cieszą się metody ewaluacji wykorzystujące podobieństwo semantyczne w przestrzeni embaddingów oraz stosowanie dużych modeli językowych jako „sędziów” (ang. LLM-as-a-judge).
Badania empiryczne [2] pokazują wysoką zgodność między oceną ekspercką a oceną dostarczoną przez modele językowe. Dodatkowo, ewaluacja w oparciu o LLM-as-a-judge pozwala w łatwy sposób określić kryteria ewaluacji: na czym się skupić, co ignorować.
Wykorzystanie modeli językowych do oceny jakości generowanych przez nie opisów może budzić skojarzenia z „podnoszeniem się na własnych sznurówkach”. Ta metoda ewaluacji wykorzystuje jednak fakt, że porównywanie i ocena tekstów jest łatwiejsza niż ich generowanie [3]

Ewaluacja i benchmarki
Ocena jakości generowanych opisów zmian wymaga odpowiednich zbiorów danych. Wymienić tutaj można:
- CommitBench: ponad 11 000 commitów z projektów open-source. Dane zawierają git diff, oryginalne wiadomości commitów i metadane.
- CodeXGLUE: repozytorium benchmarków do wielu zadań związanych z kodem (m.in. streszczenia i generowanie dokumentacji).
- CodeSearchNet: ponad 6 mln funkcji z docstringami, repozytorium na potrzeby generowania podsumowań oraz przeszukiwania kodu na podstawie zapytań w języku naturalnym.
Eksperymenty na repozytorium LonhChain
Eksperymenty z automatycznym streszczaniem zmian w kodzie prowadzone były w oparciu o publiczne repozytorium dla pakietu LangChain.
Wybranych zostało 100 commitów, w których:
- modyfikowany był co najmniej 1 plik .py z modułów core lub community,
- zmiany dotyczyły nie więcej niż 10 plików,
- commit powiązany był z jednym zgłoszeniem (jeden numer z issue trackera).
W eksperymentach korzystano głównie z modeli GPT-4o, GPT-3.5, o3-mini, o4-mini. Do statycznej analizy kodu wykorzystano pakiety AST oraz PyCG (arXiv:2103.00587).
Do oceny przydatności modeli językowych wykorzystano następujące zadania:
- Identyfikacja zmodyfikowanych elementów kodu (lista klas, funkcji, metod, których dotyczyły zmiany) na podstawie git diff: podstawowe zadanie pozwalające ocenić, na ile LLM „rozumie”, czego dotyczyły zmiany wprowadzone w kodzie.
- Wydobycie zależności między komponentami (lista par: caller → callee): kolejny test, na ile LLM „rozumie” zależności w kodzie. Zależności między komponentami pozwalają ocenić wpływ zmian na pozostałe elementy aplikacji oraz ułatwić analizę zmian przez inne zespoły (np. na potrzeby testów).
- Generowanie treści commit message na podstawie kodu i różnic (git diff): docelowe zadanie.
Identyfikacja elementów kodu, których dotyczyły zmiany z commitu
Rysunek poniżej przedstawia schemat przepływu danych i sterowania w realizacji zadania identyfikacji elementów kodu, których dotyczyły zmiany pochodzące z danego commitu:
- Dane wejściowe to git diff (unified diff format) oraz plik źródłowy przed modyfikacjami.
- Dane wejściowe przetwarzane są przez LLM w oparciu o prompt podany w ramce (przedstawiony poniżej prompt jest mocno uproszczony i ma jedynie oddawać charakter instrukcji zleconych LLM-owi).
- Wynikiem działania LLM-a jest lista klas, funkcji oraz metod, których dotyczyły zmiany: zmodyfikowane fragmenty kodu pokrywały się z kodem tych elementów. Przyjęto, że zmiany dotyczące elementów podrzędnych oznaczają zmianę elementu nadrzędnego: zmiany w metodzie danej klasy oznaczają również modyfikację klasy.
- Ocena jakości wyników dostarczonych przez LLM polega na ich porównaniu z referencją otrzymaną ze statycznej analizy kodu. Metryka, na której bazujemy, to precyzja: liczba elementów zidentyfikowanych przez LLM i mających pokrycie w referencji do całkowitej liczby elementów zidentyfikowanych przez LLM.
Modele GPT-4o, o3-mini oraz o4-mini poradziły sobie bardzo dobrze z tym zadaniem.

Wykrywanie zależności w kodzie
Rysunek poniżej przedstawia schemat przepływu danych i sterowania w realizacji zadania identyfikacji zależności semantycznych/funkcjonalnych typu caller → callee):
- Dane wejściowe to plik źródłowy oraz lista nazw z importowanych w danym pliku pakietów/modułów.
- Dane wejściowe przetwarzane są przez LLM w oparciu o prompt podany w ramce.
- Wynikiem działania LLM-a jest lista par: funkcja wywołująca, funkcja wołana. W analizie ograniczamy się tylko do funkcji wołanych pochodzących spoza analizowanego pliku oraz funkcji wołanych, które nie są funkcjami ze standardowych pakietów Python.
- Ocena jakości wyników dostarczonych przez LLM polega na ich porównaniu z referencją otrzymaną ze statycznej analizy kodu przy użyciu pakietu PyCG. Analizowane metryki to: precyzja oraz czułość.
Na podstawie uzyskanych wyników widzimy, że modele nie radzą sobie z zadaniem wykrywania zależności semantycznych w kodzie i mają duży problem z halucynacjami.

Generowanie treści commit message
- Dane wejściowe: zestaw plików źródłowych modyfikowanych w ramach commitu w ich wersji przed wprowadzeniem zmian oraz zestaw zmian w postaci unified git diff.
- Dane wejściowe przetwarzane są przez LLM w oparciu o prompt podany w ramce.
- Wynikiem działania LLM jest commit message.
- Wygenerowany commit message jest porównywany z oryginalnym commit message pochodzącym z repozytorium. Ocena w skali 1-5 wykonywana jest przez LLM (LLM-as-a-judge).
- Ocena wykonywana jest na podstawie przedstawionego poniżej promptu. LLM ma ignorować brak odwołania do informacji, do których nie ma dostępu w trakcie generowania, np. issue number.
Prompt:
Read generated and reference commit message. Check if the generated message captures all important changes described in the reference message. Ignore minor wording differences; focus on the meaning and completeness. If anything important is missing, mention what was omitted. Ignore lack of references to tasks or issues or persons or standards or guidelines in generated commit message. Score adequacy of generated message 1 (low) – 5 (high).

Przykład commit message z wysoką ocenę (czarna ramka – wygenerowany commit message, niebieska ramka – referencja).

Przykład commit message z niską oceną (czarna ramka – wygenerowany commit message, niebieska ramka – referencja).

Do oceny generowanych commit message użyto GPT-4o.
Wykres poniżej pokazuje, jak model wypada w testowych przypadkach kontrolnych:
- Hard negative – dane pochodzące z tego samego commit, co referencyjny commit message; LLM generujący commit message został poinstruowany, żeby wygenerować odpowiedź przypominajacą prawidłowy opis, ale wprowadzającą w błąd.
- Negative – commit message wygenerowany dla danych pochodzących z innego commita niż referencyjny (oczekiwany score: 1).
- Negative (paraphrased) – tak jak negative, ale treść została sparafrazowana przez LLM.
- Reference – referencyjny commit message (oczekiwany score: 5).
- Reference (paraphrased) – tak ja reference, ale treść została sparafrazowana przez LLM.
Wybrany model dobrze radzi sobie z oceną komunikatów na zbiorze kalibracyjnym.

Wyniki przeprowadzonych eksperymentów zostały przedstawione na rysunku poniżej.
- Jako modele generujące commit message najlepiej wypadają: GPT-4o, o3-mini oraz o4-mini, średnia ocena powyżej 3.5.
- Model GPT-3.5-turbo ma mniejsze okno kontekstowe i wymaga dzielenia treści commitów na mniejsze porcje (ang. chunks). Model ten ma stosunkowo niską jakość generowanych commit message. Chunkowanie commitów nie wpływa znacząco na jakość generowania dla GPT-4o.

Przedstawiony wyżej proces generowania commit message można rozszerzyć do procesu generowania change logów/podsumowań wydania (ang. release summary) poprzez agregację wygenerowanych commit message’y oraz dołączenie informacji z grafu zależności (ang. dependency graph).
Jak zostało pokazane, LLM całkiem dobrze radzi sobie z identyfikacją elementów, których dotyczą zmiany. Generowanie grafu zależności lepiej jednak oprzeć na statycznej analizie kodu. Łącząc te dwa komponenty, możemy rozszerzyć wejście LLM o listę obszarów projektu, na które wpływ mają zmiany wprowadzone w commicie.


Wnioski i podsumowanie
Zastosowanie LLM do analizy i dokumentowania kodu przynosi mierzalne korzyści. Modele dobrze rozpoznają lokalne zmiany, potrafią generować spójne i zrozumiałe wiadomości commitów, a ich ocena przez inne modele językowe okazuje się skuteczna.
LLM mają trudności z analizą zależności semantycznych w kodzie (relacje caller-callee), dlatego warto łączyć LLM z klasyczną analizą kodu (np. PyCG) w celu poprawy dokładności.
Wyspecjalizowane LLM trenowane na potrzeby code intelligence (CodeLlama, DeepSeek-Coder) mogą również być efektywne w zadaniach tego typu. Wymaga to jednak osobnej oceny.
Literatura
[1] Deep Learning for Code Intelligence: Survey, Benchmark and Toolkit
[2] Automated Commit Message Generation with Large Language Models: An Empirical Study and Beyond
[3] A Survey on LLM-as-a-Judge; LLM-as-a-judge: a complete guide to using LLMs for evaluations; Source Code Summarization in the Era of Large Language Models
Zostaw komentarz