0Pricing
AI Engineering Academy · Урок

Создание агента для анализа данных

Создайте полноценного агента для анализа данных, который принимает CSV-файл и вопрос на естественном языке, итеративно пишет код на pandas и matplotlib и создаёт оформленный отчёт.

«Создание агента для анализа данных» — бесплатный урок AI Engineering Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения AI Engineering Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс AI Engineering Academy содержит 4 уроков всего.

Замысел агента анализа данных

Агент анализа данных принимает файл CSV и вопрос на естественном языке, затем самостоятельно исследует данные, очищает их, вычисляет статистические показатели, создаёт визуализации и формирует оформленный отчёт — всё это посредством итеративного создания и выполнения кода. Это одно из наиболее практичных применений агентов, работающих с кодом, напрямую воспроизводящее рабочий процесс аналитика данных, но без участия человека.

Общая архитектура агента

Агент анализа данных состоит из четырёх концептуальных этапов: исследование (понимание структуры, типов и качества данных), очистка (обработка пропущенных значений, выбросов и преобразование типов), анализ (вычисление показателей и статистик, отвечающих на вопрос) и подготовка отчёта (создание диаграмм и изложение результатов в текстовой форме). Каждому этапу соответствуют от 1 до 5 итераций выполнения кода.

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.
'''

Этап 1: код исследования данных

На этапе исследования данные загружаются, после чего сразу выводится вся информация, необходимая для планирования анализа: форма набора данных, имена и типы столбцов, примеры строк, сводные статистики и количество пустых значений. LLM читает этот вывод и использует его для обоснованных решений об очистке и анализе на последующих итерациях.

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.')

Этап 2: очистка данных

После исследования агент пишет целевой код очистки на основе обнаруженных особенностей. Стратегия очистки является динамической: если LLM обнаружила в столбце 15% пустых значений, она решает, удалить их или заполнить. Если в столбце, где должны быть только неотрицательные значения, обнаружены отрицательные, агент фильтрует их. Именно такая адаптивная очистка на основе наблюдений делает агента действительно полезным, а не просто запускающим фиксированный конвейер.

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)

Этап 3: ответ на вопрос

На этапе анализа агент сосредотачивается на вычислении конкретного ответа на вопрос пользователя. Если вопрос звучит так: «В какой категории товаров в прошлом квартале была самая высокая выручка?», агент пишет код для фильтрации по дате, группировки по категории, суммирования выручки и сортировки. Код анализа создаётся заново с учётом и вопроса, и результатов исследования — это не универсальный шаблон.

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

Этап 4: создание диаграмм

Визуализации делают аналитические выводы понятными и убедительными. Агент анализа данных создаёт диаграммы matplotlib и сохраняет их как файлы PNG в рабочем пространстве. Ключевые решения по оформлению диаграммы — тип, цветовая палитра, подписи осей, заголовок и аннотации — LLM принимает с учётом особенностей данных. Агент всегда сохраняет диаграммы в /workspace/, чтобы их можно было включить в итоговый отчёт.

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

Подготовка текстового отчёта

На последней итерации создаётся итоговый текстовый отчёт. LLM читает результаты анализа и описание диаграммы, а затем пишет краткое и точное изложение, отвечающее на исходный вопрос с конкретными числами. В отчёте упоминается диаграмма, а также приводятся основной вывод, подтверждающие данные и рекомендация или возможные последствия для бизнеса.

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)

Сборка оркестратора агента

Оркестратор объединяет все этапы: инициализирует рабочее пространство, копирует входной CSV, запускает цикл выполнения кода, отслеживает сигнал TASK COMPLETE, а затем собирает выходные файлы (report.md, chart.png). Оркестратор также обрабатывает ошибки, повторные попытки и финальную очистку промежуточных файлов.

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
    }

Работа с неоднозначными вопросами

Пользователи часто задают неоднозначные вопросы, например: «Какие товары хорошо продаются?». Надёжный агент анализа данных устраняет неоднозначность до начала работы: сначала исследует данные, определяет доступные показатели, а затем либо выводит наиболее разумную интерпретацию, либо просит пользователя уточнить вопрос. Этот этап обдумывания не позволяет агенту выдать технически правильный, но практически бесполезный ответ.

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

Проверка качества результата агента

После завершения работы агента оцените качество его результата. Убедитесь, что файл отчёта действительно создан, PNG-файл с диаграммой является корректным файлом изображения, числа в отчёте совпадают с данными в analysis_result.json, а сам отчёт действительно отвечает на исходный вопрос. Автоматизированный этап QA с использованием второго вызова LLM может выявить случаи, когда агент завершил весь цикл, но выдал неудовлетворительный ответ.

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}

Расширение агента предметными инструментами

Базовый агент для работы с кодом становится ещё мощнее после расширения предметными инструментами. Для агента, работающего с финансовыми данными, добавьте функции получения актуальных котировок акций. Для агента, работающего с маркетинговыми данными, добавьте доступ к API Google Analytics. Для агента отдела продаж добавьте запросы к Salesforce. Эти инструменты становятся доступными LLM через определения функций в системном запросе или декоратор LangChain @tool.

Быстрая проверка

Проверьте, насколько хорошо Вы поняли материал об агенте анализа данных из этого урока.

Итоги урока

В этом уроке Вы узнали, что агент анализа данных проходит четыре этапа — исследование, очистку, анализ и подготовку отчёта, каждый из которых реализуется посредством итеративной генерации и выполнения кода; создание диаграмм с помощью matplotlib и сохранение состояния в файлах объединяют эти этапы в единый рабочий процесс; а проверка результата гарантирует, что итоговый ответ агента действительно отвечает на исходный вопрос. Далее мы рассмотрим наблюдаемость и трассировку LLM.

Часто задаваемые вопросы

Урок «Создание агента для анализа данных» бесплатный?

Да — полный текст урока «Создание агента для анализа данных» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс AI Engineering Academy, подпишись на CoddyKit PRO. Курс AI Engineering Academy содержит 4 уроков всего.

Чему я научусь в уроке «Создание агента для анализа данных»?

Создайте полноценного агента для анализа данных, который принимает CSV-файл и вопрос на естественном языке, итеративно пишет код на pandas и matplotlib и создаёт оформленный отчёт. Ты практикуешь AI Engineering Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать AI Engineering Academy?

Предыдущий опыт не требуется. AI Engineering Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Создание агента для анализа данных»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке AI Engineering Academy?

Да. Каждый урок AI Engineering Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Цикл выполнения кода
  2. Изоляция с Docker и RestrictedPython
  3. Управление состоянием между этапами выполнения
  4. Создание агента для анализа данных
← Назад к AI Engineering Academy