0Pricing
AI Engineering Academy · Lekcja

Budowanie agenta do analizy danych

Utwórz kompleksowego agenta do analizy danych, który przyjmuje plik CSV i pytanie w języku naturalnym, iteracyjnie tworzy kod pandas i matplotlib oraz generuje dopracowany raport.

Budowanie agenta do analizy danych to bezpłatna lekcja AI Engineering Academy na CoddyKit. To lekcja 4 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.

Wizja agenta do analizy danych

Agent do analizy danych przyjmuje plik CSV i pytanie zadane w języku naturalnym, a następnie samodzielnie bada dane, oczyszcza je, oblicza statystyki, tworzy wizualizacje i generuje dopracowany raport — wszystko za pomocą iteracyjnego generowania i wykonywania kodu. To jedno z najbardziej praktycznych zastosowań agentów kodu, bezpośrednio odwzorowujące pracę analityka danych, ale bez konieczności angażowania człowieka.

Ogólna architektura agenta

Agent do analizy danych ma cztery fazy koncepcyjne: Eksploracja (zrozumienie struktury, typów i jakości danych), Czyszczenie (obsługa brakujących wartości, wartości odstających i konwersji typów), Analiza (obliczenie metryk i statystyk odpowiadających na pytanie) oraz Raportowanie (generowanie wykresów i podsumowanie ustaleń w formie tekstowej). Każda faza obejmuje od 1 do 5 iteracji wykonywania kodu.

DATA_AGENT_SYSTEM_PROMPT = '''
You are a data analysis agent. Given a CSV file and a question, answer it through iterative Python code.

Phases to follow:
1. EXPLORE: Load the data, print shape, dtypes, head(), describe(), and check for nulls.
2. CLEAN: Handle missing values, fix dtypes, remove outliers.
3. ANALYZE: Compute statistics, groupbys, correlations - whatever answers the question.
4. REPORT: Generate a matplotlib chart saved to /workspace/chart.png and write a text summary.

Rules:
- Write code in ```python ... ``` blocks.
- Save intermediate results to /workspace/ for use in later steps.
- Print key findings after each computation so you can observe them.
- When all phases are done, say TASK COMPLETE and summarize the answer.
'''

Faza 1: kod eksploracji danych

W fazie eksploracji dane są wczytywane, a następnie natychmiast wyświetlane są wszystkie informacje potrzebne do zaplanowania analizy: wymiary, nazwy i typy kolumn, przykładowe wiersze, statystyki podsumowujące oraz liczba wartości null. LLM odczytuje te dane wyjściowe i wykorzystuje je do podejmowania świadomych decyzji dotyczących czyszczenia i analizy w kolejnych iteracjach.

import pandas as pd
import numpy as np

# Load dataset
df = pd.read_csv('/workspace/data.csv')

# Basic exploration
print('=== SHAPE ===' )
print(df.shape)

print('\n=== DTYPES ===')
print(df.dtypes)

print('\n=== HEAD ===')
print(df.head())

print('\n=== DESCRIBE ===')
print(df.describe(include='all'))

print('\n=== NULL COUNTS ===')
print(df.isnull().sum())

print('\n=== UNIQUE VALUES (categorical) ===')
for col in df.select_dtypes(include='object').columns:
    print(f'{col}: {df[col].nunique()} unique values: {df[col].unique()[:5]}')

# Save for next iteration
df.to_parquet('/workspace/raw.parquet')
print('\nData saved to workspace.')

Faza 2: czyszczenie danych

Po eksploracji agent zapisuje ukierunkowany kod czyszczenia na podstawie poczynionych obserwacji. Strategia czyszczenia jest dynamiczna — jeśli LLM zauważy 15% wartości null w kolumnie, decyduje, czy je usunąć, czy uzupełnić. Jeśli wykryje ujemne wartości w kolumnie, która powinna zawierać wyłącznie wartości nieujemne, filtruje je. To adaptacyjne czyszczenie oparte na obserwacjach sprawia, że agent jest naprawdę użyteczny, zamiast jedynie uruchamiać ustalony potok przetwarzania.

import pandas as pd
import numpy as np

# Load from previous iteration
df = pd.read_parquet('/workspace/raw.parquet')

# Fill numeric nulls with median (robust to outliers)
for col in df.select_dtypes(include='number').columns:
    if df[col].isnull().sum() > 0:
        median_val = df[col].median()
        df[col] = df[col].fillna(median_val)
        print(f'Filled nulls in {col} with median {median_val:.2f}')

# Drop rows where categorical key columns are null
df = df.dropna(subset=['category', 'date'])

# Fix date column type
df['date'] = pd.to_datetime(df['date'], errors='coerce')
df = df.dropna(subset=['date'])  # drop unparseable dates

# Remove clear outliers: revenue > 3 std deviations from mean
if 'revenue' in df.columns:
    z_scores = (df['revenue'] - df['revenue'].mean()) / df['revenue'].std()
    df = df[z_scores.abs() < 3]
    print(f'Removed outliers, rows remaining: {len(df)}')

df.to_parquet('/workspace/cleaned.parquet')
print('Cleaning complete:', df.shape)

Faza 3: odpowiadanie na pytanie

W fazie analizy agent koncentruje się na obliczeniu konkretnej odpowiedzi na pytanie użytkownika. Jeśli pytanie brzmi: „która kategoria produktów przyniosła największy przychód w ostatnim kwartale?”, agent zapisuje kod filtrujący dane według daty, grupujący je według kategorii, sumujący przychody i sortujący wyniki. Kod analizy jest generowany od podstaw na podstawie zarówno pytania, jak i obserwacji poczynionych podczas eksploracji — nie jest ogólnym szablonem.

import pandas as pd
import matplotlib
matplotlib.use('Agg')  # non-interactive backend for server use
import matplotlib.pyplot as plt

df = pd.read_parquet('/workspace/cleaned.parquet')

# Analysis: revenue by category for last quarter
df['date'] = pd.to_datetime(df['date'])
last_quarter = df[df['date'] >= '2024-10-01']

revenue_by_category = (
    last_quarter
    .groupby('category')['revenue']
    .sum()
    .sort_values(ascending=False)
)
print('Revenue by category (last quarter):')
print(revenue_by_category)
print(f'\nTop category: {revenue_by_category.index[0]} (${revenue_by_category.iloc[0]:,.0f})')

# Save analysis result
revenue_by_category.to_json('/workspace/analysis_result.json')

Faza 4: generowanie wykresów

Wizualizacje sprawiają, że ustalenia analityczne stają się jasne i przekonujące. Agent do analizy danych generuje wykresy matplotlib i zapisuje je jako pliki PNG w przestrzeni roboczej. Najważniejsze decyzje dotyczące projektu wykresu — jego typ, paleta kolorów, etykiety osi, tytuł i adnotacje — są podejmowane przez LLM na podstawie charakteru danych. Agent zawsze zapisuje wykresy w /workspace/, aby można je było uwzględnić w raporcie końcowym.

import pandas as pd
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import json

with open('/workspace/analysis_result.json') as f:
    data = json.load(f)

categories = list(data.keys())
values = [data[k] / 1e6 for k in categories]  # convert to millions

fig, ax = plt.subplots(figsize=(10, 6))
bars = ax.barh(categories, values, color='steelblue', edgecolor='white')

# Add value labels on bars
for bar, val in zip(bars, values):
    ax.text(bar.get_width() + 0.05, bar.get_y() + bar.get_height()/2,
            f'${val:.1f}M', va='center', fontsize=11)

ax.set_xlabel('Revenue ($ Millions)', fontsize=12)
ax.set_title('Revenue by Product Category - Q4 2024', fontsize=14, fontweight='bold')
ax.invert_yaxis()  # highest on top
plt.tight_layout()
plt.savefig('/workspace/chart.png', dpi=150, bbox_inches='tight')
print('Chart saved to /workspace/chart.png')

Generowanie raportu tekstowego

W ostatniej iteracji powstaje pisemne podsumowanie. LLM odczytuje wyniki analizy i opis wykresu, a następnie tworzy zwięzłą, dokładną narrację, która odpowiada na pierwotne pytanie, podając konkretne liczby. Raport zawiera odwołanie do wykresu oraz najważniejszy wniosek, dane potwierdzające i rekomendację lub konsekwencje dla firmy.

import json

with open('/workspace/analysis_result.json') as f:
    revenue_data = json.load(f)

top_category = max(revenue_data, key=revenue_data.get)
top_revenue = revenue_data[top_category]
total_revenue = sum(revenue_data.values())
share = top_revenue / total_revenue * 100

report = f'''# Q4 2024 Revenue Analysis

## Answer
The **{top_category}** category generated the highest revenue in Q4 2024:
**${top_revenue:,.0f}** ({share:.1f}% of total Q4 revenue).

## Key Findings
- Total Q4 revenue: ${total_revenue:,.0f}
- Top 3 categories: {list(revenue_data.items())[:3]}
- The top category outperformed the average by {top_revenue / (total_revenue / len(revenue_data)):.1f}x

## Chart
See chart.png for the full breakdown by category.

## Recommendation
Consider reallocating marketing budget toward {top_category} to
capitalize on its demonstrated strong performance.
'''

with open('/workspace/report.md', 'w') as f:
    f.write(report)
print('TASK COMPLETE')
print(report)

Tworzenie orkiestratora agenta

Orkiestrator łączy wszystkie fazy: inicjalizuje przestrzeń roboczą, kopiuje wejściowy plik CSV, uruchamia pętlę wykonywania kodu, monitoruje sygnał TASK COMPLETE, a następnie zbiera pliki wynikowe (report.md, chart.png). Orkiestrator obsługuje również błędy i ponowienia oraz końcowe usuwanie plików pośrednich.

import shutil
from pathlib import Path

def run_data_analysis_agent(csv_path: str, question: str) -> dict:
    workspace = setup_workspace()
    shutil.copy(csv_path, workspace / 'data.csv')
    
    messages = [
        {'role': 'system', 'content': DATA_AGENT_SYSTEM_PROMPT},
        {'role': 'user', 'content': f'File: /workspace/data.csv\nQuestion: {question}'}
    ]
    
    state = ExecutionState(task=question)
    
    for iteration in range(15):  # max 15 iterations
        response = llm.complete(messages)
        code = extract_code_block(response)
        
        if not code or 'TASK COMPLETE' in response:
            break
        
        stdout, stderr = execute_in_docker(code, workspace=workspace)
        observation = format_observation(stdout, stderr)
        messages += [
            {'role': 'assistant', 'content': response},
            {'role': 'user', 'content': observation}
        ]
        state.after_execution(stdout, f'iteration_{iteration}')
    
    return {
        'report': (workspace / 'report.md').read_text() if (workspace / 'report.md').exists() else '',
        'chart_path': str(workspace / 'chart.png'),
        'iterations': state.iteration
    }

Obsługa niejednoznacznych pytań

Użytkownicy często zadają niejednoznaczne pytania, takie jak „które produkty radzą sobie dobrze?”. Solidny agent do analizy danych wyjaśnia niejednoznaczności przed rozpoczęciem pracy: najpierw bada dane, ustala dostępne metryki, a następnie albo wybiera najbardziej sensowną interpretację, albo prosi użytkownika o doprecyzowanie. Ten etap refleksji zapobiega generowaniu odpowiedzi poprawnej technicznie, lecz bezużytecznej w praktyce.

def handle_ambiguous_question(question: str, df_summary: dict) -> str:
    clarification_prompt = f'''The user asked: '{question}'

Available data:
- Columns: {df_summary['columns']}
- Date range: {df_summary['date_range']}
- Metrics available: {df_summary['numeric_columns']}

Is the question clear enough to answer definitively?
If yes, restate the specific interpretation you will use.
If no, list the 2-3 clarifications needed to proceed.'''
    
    response = llm.complete([{'role': 'user', 'content': clarification_prompt}])
    return response

Kontrola jakości wyników agenta

Po zakończeniu działania agenta należy zweryfikować jakość jego wyniku. Proszę sprawdzić, czy plik raportu rzeczywiście został utworzony, czy wykres PNG jest prawidłowym plikiem obrazu, czy liczby w raporcie odpowiadają danym w pliku analysis_result.json oraz czy raport faktycznie odpowiada na pierwotne pytanie. Zautomatyzowany etap kontroli jakości z użyciem drugiego wywołania LLM może wykryć sytuacje, w których agent przeszedł całą pętlę, ale wygenerował słabą odpowiedź.

def validate_analysis_output(workspace: str, question: str, report: str) -> dict:
    validation_prompt = f'''Original question: {question}

Agent report:
{report[:2000]}

Rate this analysis on a scale of 1-5 for:
1. Does it directly answer the question? (1=No, 5=Yes)
2. Are specific numbers cited? (1=No, 5=Yes)
3. Is the conclusion clearly stated? (1=No, 5=Yes)

Return JSON: {{"question_answered": N, "numbers_cited": N, "clear_conclusion": N, "overall": N}}'''
    
    result = llm.complete([{'role': 'user', 'content': validation_prompt}],
                          response_format={'type': 'json_object'})
    scores = json.loads(result)
    passed = scores['overall'] >= 4
    return {'scores': scores, 'passed': passed}

Rozszerzanie agenta o narzędzia domenowe

Podstawowy agent kodujący staje się jeszcze bardziej zaawansowany po rozszerzeniu go o narzędzia specyficzne dla danej domeny. W przypadku agenta pracującego z danymi finansowymi można dodać funkcje pobierające bieżące ceny akcji. Agentowi do analizy danych marketingowych można zapewnić dostęp do Google Analytics API. W przypadku agenta sprzedażowego można dodać zapytania do Salesforce. Narzędzia te udostępnia się LLM za pomocą definicji funkcji w promptcie systemowym lub dekoratora @tool biblioteki LangChain.

Szybki sprawdzian

Sprawdź swoje rozumienie agenta do analizy danych omówionego w tej lekcji.

Podsumowanie lekcji

W tej lekcji nauczyłeś się, że agent do analizy danych działa w czterech fazach — eksploracji, czyszczenia, analizy i raportowania — z których każda jest realizowana za pomocą iteracyjnego generowania i wykonywania kodu; generowanie wykresów za pomocą matplotlib oraz utrwalanie stanu w plikach łączą te fazy w spójny przepływ pracy; a walidacja wyniku gwarantuje, że końcowa odpowiedź agenta rzeczywiście odnosi się do pierwotnego pytania. Następnie zajmiemy się obserwowalnością i śledzeniem działania LLM.

Często zadawane pytania

Czy lekcja „Budowanie agenta do analizy danych” jest bezpłatna?

Tak — pełny tekst „Budowanie agenta do analizy danych” 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 „Budowanie agenta do analizy danych”?

Utwórz kompleksowego agenta do analizy danych, który przyjmuje plik CSV i pytanie w języku naturalnym, iteracyjnie tworzy kod pandas i matplotlib oraz generuje dopracowany raport. Ć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 4 z 4.

Ile czasu zajmuje lekcja „Budowanie agenta do analizy danych”?

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