0Pricing
AI Engineering Academy · Lekcja

Pętla wykonywania kodu

Zaprojektuj pętlę zapis–wykonanie–obserwacja, w której agent generuje kod, izolowany wykonawca go uruchamia, stdout i stderr są przechwytywane oraz przekazywane jako obserwacje, a agent naprawia błędy.

Pętla wykonywania kodu to bezpłatna lekcja AI Engineering Academy na CoddyKit. To lekcja 1 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej AI Engineering Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.

Agenci kodu: pisanie i uruchamianie kodu

Agent wykonujący kod to szczególny typ agenta AI, który rozwiązuje problemy, pisząc kod, uruchamiając go, analizując wynik i iteracyjnie powtarzając te czynności aż do ukończenia zadania. W przeciwieństwie do agentów korzystających wyłącznie ze wstępnie zdefiniowanych narzędzi agenci kodu tworzą nowe narzędzia obliczeniowe na bieżąco. Dzięki temu są niezwykle elastyczni: agent kodu może podjąć próbę wykonania każdego zadania, które da się zaprogramować.

Pętla pisz–wykonaj–obserwuj

Podstawą agenta wykonującego kod jest pętla składająca się z trzech kroków: Pisanie — LLM generuje kod Python rozwiązujący bieżący etap zadania. Wykonanie — kod jest uruchamiany w środowisku sandbox, a stdout/stderr są przechwytywane. Obserwacja — wynik wykonania jest przekazywany do LLM jako nowa obserwacja, na podstawie której model decyduje, co napisać dalej. Pętla działa do momentu ukończenia zadania lub osiągnięcia limitu iteracji.

def code_execution_loop(task: str, max_iterations=10):
    messages = [
        {'role': 'system', 'content': 'You are a Python coding agent. Write code to solve tasks step by step.'},
        {'role': 'user', 'content': task}
    ]
    
    for i in range(max_iterations):
        # WRITE: LLM generates code
        response = llm.complete(messages)
        code = extract_code_block(response)
        
        if not code:
            return response  # LLM gave a final answer without code
        
        # EXECUTE: run the code
        output, error = execute_safely(code)
        
        # OBSERVE: feed output back
        observation = f'Output:\n{output}' if not error else f'Error:\n{error}'
        messages.append({'role': 'assistant', 'content': response})
        messages.append({'role': 'user', 'content': observation})
    
    return 'Max iterations reached'

Wyodrębnianie bloków kodu z danych wyjściowych LLM

LLM zwykle umieszcza wygenerowany kod w blokach kodu Markdown oznaczonych potrójnymi backtickami: ```python ... ```. Pętla wykonywania musi niezawodnie wyodrębnić kod z tych bloków przed jego uruchomieniem. Należy użyć wyrażenia regularnego lub prostego parsera do wyszukiwania bloków ogrodzonych i obsłużyć przypadki brzegowe, takie jak zagnieżdżone backticki, wiele bloków kodu w jednej odpowiedzi lub kod bez określonego języka.

import re

def extract_code_block(response: str) -> str | None:
    # Match ```python ... ``` or ``` ... ```
    pattern = r'```(?:python)?\n(.*?)```'
    matches = re.findall(pattern, response, re.DOTALL)
    if not matches:
        return None
    # Return the LAST code block (often the most complete version)
    return matches[-1].strip()

# Test
sample_response = '''I will calculate the sum:\n\n```python\nnumbers = [1, 2, 3, 4, 5]\nprint(sum(numbers))\n```'''
code = extract_code_block(sample_response)
print(repr(code))  # 'numbers = [1, 2, 3, 4, 5]\nprint(sum(numbers))'

Przechwytywanie stdout i stderr

Podczas wykonywania kodu wygenerowanego przez agenta należy przechwytywać zarówno stdout (zwykłe dane wyjściowe), jak i stderr (komunikaty o błędach i tracebacki), aby przekazać je z powrotem do LLM. Najprostszym rozwiązaniem jest użycie modułu Pythona subprocess: należy uruchomić kod jako osobny proces i przechwycić oba strumienie. Należy ustawić limit czasu, aby kod, który się zawiesił, nie blokował agenta.

import subprocess
import tempfile
import os

def execute_code(code: str, timeout_seconds=30) -> tuple[str, str]:
    # Write code to a temp file
    with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
        f.write(code)
        tmp_path = f.name
    
    try:
        result = subprocess.run(
            ['python', tmp_path],
            capture_output=True,
            text=True,
            timeout=timeout_seconds
        )
        stdout = result.stdout[:5000]  # cap output length
        stderr = result.stderr[:2000]  # cap error length
        return stdout, stderr
    except subprocess.TimeoutExpired:
        return '', f'TimeoutError: code exceeded {timeout_seconds}s limit'
    finally:
        os.unlink(tmp_path)  # always clean up temp file

Inteligentna obsługa błędów

Gdy kod generuje błąd, komunikat o błędzie (traceback, typ wyjątku, numer wiersza) jest przekazywany do LLM jako obserwacja. LLM analizuje błąd i zapisuje poprawiony kod. Aby ułatwić LLM skuteczne debugowanie, należy do obserwacji dołączyć dokładny tekst błędu, uwzględnić wiersz kodu, który spowodował błąd, oraz wyraźnie poprosić LLM o jego naprawienie przed ponowną próbą.

def format_error_observation(code: str, error: str) -> str:
    lines = code.split('\n')
    
    # Extract line number from traceback if available
    line_match = re.search(r'line (\d+)', error)
    error_context = ''
    if line_match:
        line_num = int(line_match.group(1))
        if 1 <= line_num <= len(lines):
            error_context = f'\nFailing line: {lines[line_num - 1].strip()}'
    
    return f'''Execution failed with error:{error_context}\n\n{error}\n\nPlease analyze the error and write corrected code.'''

# Usage in loop
output, err = execute_code(code)
if err:
    observation = format_error_observation(code, err)
else:
    observation = f'Output:\n{output}\n\nContinue with the next step or provide the final answer.'

Wykrywanie ukończenia zadania

Pętla wykonywania kodu musi wiedzieć, kiedy się zatrzymać. Typowe sygnały ukończenia obejmują: odpowiedź LLM bez bloku kodu (zawierającą wyłącznie odpowiedź w języku naturalnym), zapisanie przez LLM specjalnego znacznika, takiego jak # TASK_COMPLETE, wygenerowanie przez kod pliku wyjściowego, którego utworzenie zlecono agentowi, lub potwierdzenie przez funkcję walidującą, że wynik spełnia kryteria sukcesu. Zawsze należy wdrożyć limit iteracji jako zabezpieczenie awaryjne.

COMPLETION_MARKERS = ['TASK COMPLETE', 'FINAL ANSWER:', 'DONE:']

def is_task_complete(response: str, code: str | None, output: str, success_fn=None) -> bool:
    # Check for explicit completion markers
    for marker in COMPLETION_MARKERS:
        if marker in response.upper():
            return True
    
    # No code generated - LLM is done
    if code is None:
        return True
    
    # Custom success function (e.g., check output file exists)
    if success_fn and success_fn(output):
        return True
    
    return False

# Example success function
def report_was_generated(output: str) -> bool:
    import os
    return os.path.exists('analysis_report.pdf')

Przekazywanie danych między iteracjami

Jednym z wyzwań w pętlach wykonywania kodu jest utrwalanie stanu między iteracjami. Każdy blok kodu działa w nowym procesie Pythona, dlatego zmienne zdefiniowane w jednej iteracji nie są dostępne w następnej. Możliwe rozwiązania to: zapisywanie danych pośrednich w plikach, użycie trwałego procesu z kodem wstrzykiwanym za pomocą exec() lub wyraźne poinstruowanie LLM, aby na początku każdego bloku kodu ponownie definiował niezbędne zmienne.

# Strategy 1: Save to files between iterations
# Iteration 1: LLM writes
'''
import pandas as pd
df = pd.read_csv('data.csv')
df_cleaned = df.dropna()
df_cleaned.to_parquet('cleaned.parquet')  # save for next iteration
print('Cleaned rows:', len(df_cleaned))
'''

# Iteration 2: LLM reads previous output
'''
import pandas as pd
df = pd.read_parquet('cleaned.parquet')  # reload from file
result = df.groupby('category').sum()
result.to_csv('result.csv')
print(result.head())
'''

Struktura promptu systemowego

Prompt systemowy agenta wykonującego kod musi nauczyć LLM skutecznego korzystania z pętli. Należy uwzględnić w nim: sposób zapisywania wykonywalnych bloków kodu Python, sposób sprawdzania wyników pośrednich przed przejściem dalej, sposób sygnalizowania ukończenia zadania, biblioteki dostępne w sandboxie oraz ścieżki plików, z których agent może odczytywać dane i do których może je zapisywać.

CODE_AGENT_SYSTEM_PROMPT = '''
You are a Python code execution agent. Solve tasks by writing and running code.

Rules:
1. Write ALL code inside ```python ... ``` blocks.
2. Write small, testable code blocks - do not try to do everything in one block.
3. When you see execution output, analyze it and decide whether to continue or fix errors.
4. Available libraries: pandas, numpy, matplotlib, requests, json, os, pathlib.
5. You can read/write files only in /workspace/ directory.
6. When the task is fully complete, say TASK COMPLETE and summarize the result.
7. If you are stuck after 3 attempts at the same error, say ESCALATE and explain the problem.
'''

Skracanie danych wyjściowych i zarządzanie tokenami

Kod wygenerowany przez agenta może tworzyć ogromne ilości danych wyjściowych: wydruki DataFrame, długie listy czy rozbudowane logi. Przekazywanie pełnych danych wyjściowych do LLM marnuje tokeny i może przepełnić okno kontekstu. Przed dodaniem wyniku wykonania do rozmowy należy zawsze skrócić dane wyjściowe. Dobrym ustawieniem domyślnym jest 2000–5000 znaków oraz informacja, że wynik został skrócony, aby LLM wiedział, że może istnieć więcej danych do przeanalizowania.

MAX_OUTPUT_CHARS = 3000

def format_observation(stdout: str, stderr: str) -> str:
    if stderr:
        # Errors take priority - show full error
        return f'Error:\n{stderr[:MAX_OUTPUT_CHARS]}'
    
    if len(stdout) > MAX_OUTPUT_CHARS:
        truncated = stdout[:MAX_OUTPUT_CHARS]
        remaining = len(stdout) - MAX_OUTPUT_CHARS
        return f'{truncated}\n... [output truncated, {remaining} more characters]'
    
    return f'Output:\n{stdout}' if stdout else 'Code executed successfully (no output)'

Pętla kodu w praktyce

Rzeczywisty agent wykonujący kod na potrzeby analizy danych może wykonać od 5 do 15 iteracji, aby: wczytać plik CSV, zbadać jego strukturę, oczyścić dane, obliczyć statystyki, wygenerować wykres i utworzyć raport podsumowujący. Każda iteracja opiera się na poprzedniej, a LLM dostosowuje podejście na podstawie rzeczywistych wartości i kształtów danych odkrytych w czasie działania. To dynamiczne dostosowywanie sprawia, że agenci kodu są tak skuteczni w zadaniach eksploracyjnych.

Zagadnienia bezpieczeństwa w pętlach kodu

Uruchamianie kodu wygenerowanego przez LLM w Państwa infrastrukturze stanowi poważne zagrożenie bezpieczeństwa. Nigdy nie należy uruchamiać kodu agenta bez zastosowania sandboxa. LLM może przypadkowo (lub w wyniku prompt injection) wygenerować kod, który: usuwa pliki, wyprowadza dane, wysyła żądania sieciowe do zewnętrznych usług lub wyczerpuje zasoby systemowe. Kod należy zawsze wykonywać w odizolowanym środowisku z restrykcyjnymi limitami zasobów, ograniczeniami sieciowymi i ograniczeniami dostępu do systemu plików.

Szybki test

Sprawdź swoje zrozumienie pętli wykonywania kodu na podstawie tej lekcji.

Podsumowanie lekcji

W tej lekcji poznali Państwo następujące zagadnienia: pętla pisz–wykonaj–obserwuj jest podstawowym wzorcem agentów wykonujących kod; dane stdout i stderr z wykonania są przekazywane z powrotem jako obserwacje, które kierują kolejnym generowaniem kodu przez LLM; a skracanie danych wyjściowych i limity iteracji są niezbędnymi mechanizmami bezpieczeństwa. W następnej części omówimy izolowanie wykonywania kodu za pomocą Dockera i RestrictedPython.

Często zadawane pytania

Czy lekcja „Pętla wykonywania kodu” jest bezpłatna?

Tak — pełny tekst „Pętla wykonywania kodu” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu AI Engineering Academy, przejdź na CoddyKit PRO. Kurs AI Engineering Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Pętla wykonywania kodu”?

Zaprojektuj pętlę zapis–wykonanie–obserwacja, w której agent generuje kod, izolowany wykonawca go uruchamia, stdout i stderr są przechwytywane oraz przekazywane jako obserwacje, a agent naprawia błęd… Ćwiczysz AI Engineering Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć AI Engineering Academy?

Nie wymagamy żadnego doświadczenia. AI Engineering Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 1 z 4.

Ile czasu zajmuje lekcja „Pętla wykonywania kodu”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji AI Engineering Academy?

Tak. Każda lekcja AI Engineering Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Pętla wykonywania kodu
  2. Izolowanie za pomocą Docker i RestrictedPython
  3. Zarządzanie stanem między krokami wykonywania
  4. Budowanie agenta do analizy danych
← Powrót do AI Engineering Academy