0Pricing
AI Agents · Lekcja

Generowanie ustrukturyzowanych raportów

Raporty oparte na szablonach: podsumowanie dla kadry zarządzającej, ustalenia, dowody, rekomendacje.

Generowanie ustrukturyzowanych raportów to bezpłatna lekcja AI Agents na CoddyKit. To lekcja 3 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 Agents, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs AI Agents zawiera 4 lekcji w sumie.

Od faktów do czytelnego raportu

Agent badawczy, który wyświetla jedynie listę faktów, jest trudny w użyciu. Osoby podejmujące decyzje potrzebują uporządkowanych raportów: streszczenia zarządczego, sekcji przedstawiającej kontekst, najważniejszych ustaleń, dowodów i zaleceń.

Ta lekcja dotyczy generowania profesjonalnych raportów sekcja po sekcji na podstawie zweryfikowanych faktów.

Szablon raportu

Należy z góry zdefiniować strukturę raportu. LLM tworzy jedną sekcję naraz, dzięki czemu każda sekcja pozostaje skoncentrowana, a powtórzenia są ograniczone.

REPORT_SECTIONS = [
    'executive_summary',
    'background',
    'key_findings',
    'evidence',
    'recommendations',
    'sources'
]

SECTION_PROMPTS = {
    'executive_summary': 'Write a 2-3 sentence executive summary of the key findings. Business audience.',
    'background':        'Provide background context for the research topic (3-5 sentences).',
    'key_findings':      'List 3-5 key findings as bullet points, each with one supporting fact.',
    'evidence':          'Summarize the evidence for each finding with inline source citations.',
    'recommendations':   'Based on the findings, provide 2-4 actionable recommendations.',
    'sources':           'List all sources cited in the report, formatted as numbered URLs.'
}

if __name__ == '__main__':
    print('Report sections:', REPORT_SECTIONS)
    for section in REPORT_SECTIONS:
        print(f'{section}: {SECTION_PROMPTS[section]}')

Generowanie po jednej sekcji

Generowanie całego raportu w jednym promptcie jest zawodne — LLM traci wątek faktów i struktury. Należy generować raport sekcja po sekcji, przekazując wcześniejsze sekcje jako kontekst.

import openai

client = openai.OpenAI(api_key='YOUR_OPENAI_KEY')

def generate_section(section_name: str, question: str,
                     facts: list[dict], prior_sections: dict) -> str:
    facts_text = '\n'.join(
        f'- {f["fact"]} (source: {f["source"]})' for f in facts[:25]
    )
    prior_text = '\n\n'.join(
        f'## {k.replace("_"," ").title()}\n{v}'
        for k, v in prior_sections.items()
    )
    prompt = (
        f'Research question: "{question}"\n\n'
        f'Verified facts:\n{facts_text}\n\n'
        f'Report so far:\n{prior_text}\n\n'
        f'Now write the "{section_name}" section.\n'
        f'Instructions: {SECTION_PROMPTS[section_name]}'
    )
    resp = client.chat.completions.create(
        model='gpt-4o',
        messages=[{'role': 'user', 'content': prompt}]
    )
    return resp.choices[0].message.content

Iteracyjne tworzenie raportu

Należy przejść przez wszystkie sekcje, przekazując narastający kontekst. Każda sekcja uwzględnia wcześniejsze treści, co zapewnia spójność i zapobiega sprzecznościom w raporcie.

def build_report(question: str, facts: list[dict]) -> dict:
    report = {}
    sections_to_generate = [s for s in REPORT_SECTIONS if s != 'sources']

    for section in sections_to_generate:
        print(f'Generating section: {section}...')
        report[section] = generate_section(
            section_name=section,
            question=question,
            facts=facts,
            prior_sections={k: v for k, v in report.items()}
        )

    # Sources section: generate citation list from fact URLs
    unique_sources = list(dict.fromkeys(f['source'] for f in facts))
    report['sources'] = '\n'.join(
        f'{i+1}. {url}' for i, url in enumerate(unique_sources[:20])
    )

    return report

Wstawianie cytowań śródtekstowych

Należy zastąpić odwołania do faktów w wygenerowanych sekcjach numerowanymi cytowaniami prowadzącymi do listy źródeł. Dzięki temu każde twierdzenie można prześledzić.

import re

def inject_citations(section_text: str, facts: list[dict]) -> str:
    source_index = {}  # url -> int
    for i, fact in enumerate(facts):
        url = fact['source']
        if url not in source_index:
            source_index[url] = len(source_index) + 1

    annotated = section_text
    for fact in facts:
        if fact['fact'] in annotated:
            num = source_index[fact['source']]
            annotated = annotated.replace(
                fact['fact'],
                f'{fact["fact"]} [{num}]',
                1  # replace first occurrence only
            )
    return annotated

if __name__ == '__main__':
    demo_text = 'Revenue grew 12% last quarter. The team also launched two new products.'
    demo_facts = [{'fact': 'Revenue grew 12% last quarter', 'source': 'https://example.com/report'}]
    print(inject_citations(demo_text, demo_facts))

Formatowanie w Markdown

Należy renderować sekcje raportu jako Markdown. Dzięki temu wynik można przekonwertować do HTML lub PDF albo wyświetlić bezpośrednio w narzędziach takich jak Notion czy Confluence.

def render_markdown(report: dict, title: str) -> str:
    section_titles = {
        'executive_summary': 'Executive Summary',
        'background':        'Background',
        'key_findings':      'Key Findings',
        'evidence':          'Evidence',
        'recommendations':   'Recommendations',
        'sources':           'Sources'
    }
    lines = [f'# {title}', '']
    for key in REPORT_SECTIONS:
        if key in report:
            lines.append(f'## {section_titles[key]}')
            lines.append('')
            lines.append(report[key])
            lines.append('')
    return '\n'.join(lines)

# Usage:
# md = render_markdown(report, 'Causes of Inflation in 2024')
# with open('report.md', 'w') as f: f.write(md)

Generowanie raportu z odnośnikami do źródeł

Podczas renderowania na potrzeby sieci należy przekształcić adresy URL źródeł w hiperłącza. Należy również dodać blok metadanych zawierający datę wygenerowania raportu, liczbę źródeł i odsetek zweryfikowanych twierdzeń.

from datetime import date

def render_html_report(report: dict, title: str,
                       facts: list[dict], question: str) -> str:
    meta = (
        f'<p><em>Generated: {date.today()} | '
        f'Sources: {len(set(f["source"] for f in facts))} | '
        f'Research question: {question}</em></p>'
    )
    html_parts = [f'<h1>{title}</h1>', meta]
    section_titles = {
        'executive_summary': 'Executive Summary',
        'background':        'Background',
        'key_findings':      'Key Findings',
        'evidence':          'Evidence',
        'recommendations':   'Recommendations',
        'sources':           'Sources'
    }
    for key in REPORT_SECTIONS:
        if key in report:
            content = report[key].replace('\n', '<br>')
            html_parts.append(f'<h2>{section_titles[key]}</h2><p>{content}</p>')
    return '\n'.join(html_parts)

Kontrole jakości przed publikacją

Przed dostarczeniem raportu należy przeprowadzić automatyczne kontrole jakości: minimalna liczba słów w każdej sekcji, co najmniej N cytowań, wszystkie zalecenia sformułowane za pomocą czasowników oznaczających działania oraz brak tekstu zastępczego, takiego jak „[INSERT]”.

def quality_check(report: dict) -> list[str]:
    issues = []

    for section in ['executive_summary', 'background', 'key_findings']:
        word_count = len(report.get(section, '').split())
        if word_count < 30:
            issues.append(f'{section} too short: {word_count} words (min 30)')

    if report.get('sources', '').count('http') < 3:
        issues.append('Less than 3 cited sources')

    if '[INSERT]' in str(report) or 'TODO' in str(report):
        issues.append('Report contains placeholder text')

    recs = report.get('recommendations', '')
    if recs and not any(verb in recs.lower()
                        for verb in ['should', 'recommend', 'consider', 'implement']):
        issues.append('Recommendations may not be actionable')

    return issues

if __name__ == '__main__':
    demo_report = {
        'executive_summary': 'Too short.',
        'background': 'Also short.',
        'key_findings': 'Short too.',
        'sources': 'http://a.com',
        'recommendations': 'Looks fine as is.',
    }
    for issue in quality_check(demo_report):
        print('-', issue)

Streszczenie zarządcze: ścisłe ograniczenia

Streszczenie zarządcze powinno stanowić kompletną całość: osoba, która przeczyta tylko tę sekcję, powinna zrozumieć najważniejsze ustalenie i zalecane działanie. Należy użyć precyzyjnego promptu z limitem liczby słów.

def generate_executive_summary(question: str, facts: list[dict],
                               max_words: int = 80) -> str:
    top_facts = '\n'.join(f'- {f["fact"]}' for f in facts[:10])
    prompt = (
        f'Research question: "{question}"\n\n'
        f'Key facts:\n{top_facts}\n\n'
        f'Write an executive summary in EXACTLY {max_words} words or fewer.\n'
        f'Format: [Main finding]. [Why it matters]. [Recommended action].'
    )
    resp = client.chat.completions.create(
        model='gpt-4o',
        messages=[{'role': 'user', 'content': prompt}]
    )
    return resp.choices[0].message.content

Raporty dla różnych odbiorców

Te same badania mogą wymagać różnych stylów raportu dla różnych odbiorców: technicznego opracowania dla inżynierów, streszczenia zarządczego dla kadry kierowniczej albo wyjaśnienia prostym językiem dla niespecjalistów. Każdy wariant należy wygenerować na podstawie tego samego zestawu faktów.

AUDIENCE_STYLES = {
    'executive':   'Brief, strategic. Avoid jargon. Focus on business impact and decisions.',
    'technical':   'Detailed, precise. Include methodology, caveats, and data sources.',
    'general':     'Plain language. Avoid technical terms. Use analogies where helpful.'
}

def generate_for_audience(facts: list[dict], question: str, audience: str) -> str:
    style = AUDIENCE_STYLES.get(audience, AUDIENCE_STYLES['general'])
    facts_text = '\n'.join(f'- {f["fact"]}' for f in facts[:20])
    prompt = (
        f'Synthesize these facts into a report for a {audience} audience.\n'
        f'Style guide: {style}\n'
        f'Question: "{question}"\n\n'
        f'Facts:\n{facts_text}'
    )
    resp = client.chat.completions.create(
        model='gpt-4o',
        messages=[{'role': 'user', 'content': prompt}]
    )
    return resp.choices[0].message.content

Zapisywanie raportów i zarządzanie ich wersjami

Należy zapisywać raporty wraz ze znacznikiem czasu i hashem pytania badawczego. Umożliwia to porównywanie wersji raportu, jeśli badanie zostanie ponownie przeprowadzone na podstawie zaktualizowanych źródeł.

import hashlib, json, os
from datetime import datetime, timezone

def save_report(report: dict, question: str, output_dir: str = '/tmp/reports'):
    os.makedirs(output_dir, exist_ok=True)
    q_hash = hashlib.md5(question.encode()).hexdigest()[:8]
    timestamp = datetime.now(timezone.utc).strftime('%Y%m%d_%H%M')
    filename = f'{output_dir}/report_{q_hash}_{timestamp}.json'

    with open(filename, 'w') as f:
        json.dump({
            'question':   question,
            'generated':  timestamp,
            'sections':   report
        }, f, indent=2)
    print(f'Report saved: {filename}')
    return filename

if __name__ == '__main__':
    import tempfile
    demo_dir = tempfile.mkdtemp()
    save_report({'executive_summary': 'AI agent adoption grew significantly in 2026.'},
                'What are the key AI agent trends in 2026?', output_dir=demo_dir)

Która sekcja powinna zawsze stanowić samodzielną całość w strukturze raportu?

Struktura raportu jest projektowana tak, aby czytelnicy dysponujący ograniczonym czasem mogli uzyskać najważniejsze informacje bez czytania całego dokumentu. Zrozumienie, która sekcja musi być samodzielna, jest istotne przy projektowaniu raportu.

Podsumowanie generowania uporządkowanych raportów

Raporty należy generować sekcja po sekcji na podstawie ustalonego szablonu (Streszczenie zarządcze → Kontekst → Najważniejsze ustalenia → Dowody → Zalecenia → Źródła). Należy wstawiać cytowania śródtekstowe, przeprowadzać kontrole jakości i obsługiwać różne style dla odbiorców na podstawie tego samego zestawu faktów.

Raporty należy zawsze zapisywać wraz ze znacznikami czasu i hashami pytań, aby umożliwić zarządzanie wersjami.

Często zadawane pytania

Czy lekcja „Generowanie ustrukturyzowanych raportów” jest bezpłatna?

Tak — pełny tekst „Generowanie ustrukturyzowanych raportów” 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 Agents, przejdź na CoddyKit PRO. Kurs AI Agents zawiera 4 lekcji w sumie.

Co nauczysz się w „Generowanie ustrukturyzowanych raportów”?

Raporty oparte na szablonach: podsumowanie dla kadry zarządzającej, ustalenia, dowody, rekomendacje. Ćwiczysz AI Agents 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 Agents?

Nie wymagamy żadnego doświadczenia. AI Agents 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 3 z 4.

Ile czasu zajmuje lekcja „Generowanie ustrukturyzowanych raportów”?

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 Agents?

Tak. Każda lekcja AI Agents 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. Projektowanie pętli wieloetapowego badania
  2. Weryfikacja źródeł i cytowanie
  3. Generowanie ustrukturyzowanych raportów
  4. Weryfikacja faktów i zapobieganie halucynacjom
← Powrót do AI Agents