0Pricing
AI Agents · Lekcja

Weryfikacja źródeł i cytowanie

Porównywanie twierdzeń w wielu źródłach i dołączanie adresów URL źródeł do faktów.

Weryfikacja źródeł i cytowanie to bezpłatna lekcja AI Agents na CoddyKit. To lekcja 2 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.

Dlaczego weryfikacja źródeł ma znaczenie

Agent może pobrać fałszywe twierdzenie ze źródła niskiej jakości i przedstawić je jako fakt. Bez weryfikacji agent badawczy jest tylko zaawansowaną wyszukiwarką pozbawioną filtra jakości.

Weryfikacja dodaje warstwę sprawdzającą, czy twierdzenia są potwierdzone przez wiele niezależnych źródeł.

Reguła dwóch źródeł

Twierdzenie uznaje się za zweryfikowane, gdy występuje w co najmniej dwóch niezależnych źródłach. „Niezależne” oznacza pochodzące z różnych domen — znalezienie tego samego twierdzenia na dwóch stronach, które obie powołują się na ten sam artykuł źródłowy, się nie liczy.

from urllib.parse import urlparse

def extract_domain(url: str) -> str:
    return urlparse(url).netloc.replace('www.', '')

def is_verified(fact: str, all_facts: list[dict]) -> bool:
    matching_domains = set()
    for f in all_facts:
        if fact.lower() in f['fact'].lower() or f['fact'].lower() in fact.lower():
            matching_domains.add(extract_domain(f['source']))
    return len(matching_domains) >= 2

# Example
facts = [
    {'fact': 'Inflation peaked at 9.1% in June 2022', 'source': 'https://bls.gov/cpi'},
    {'fact': 'US inflation hit 9.1% peak in mid-2022',  'source': 'https://reuters.com/article/a'}
]
print(is_verified('inflation peaked at 9.1%', facts))  # True

Semantyczne dopasowywanie z użyciem LLM

Dopasowywanie ciągów znaków nie wykrywa sparafrazowanych twierdzeń. Przed uznaniem dwóch faktów za potwierdzające się źródła należy użyć LLM do oceny, czy są one równoważne semantycznie.

import openai, json

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

def claims_are_equivalent(claim_a: str, claim_b: str) -> bool:
    prompt = (
        f'Are these two statements making the same factual claim?\n'
        f'A: "{claim_a}"\n'
        f'B: "{claim_b}"\n'
        f'Answer JSON: {{"equivalent": true/false}}'
    )
    resp = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'}
    )
    return json.loads(resp.choices[0].message.content).get('equivalent', False)

print(claims_are_equivalent(
    'CPI hit 9.1% in June 2022',
    'US consumer prices rose 9.1 percent year-over-year in June 2022'
))  # True

Ocenianie jakości źródeł

Nie wszystkie źródła są równoważne. Każde źródło należy ocenić na podstawie typu domeny, daty publikacji i znanej wiarygodności. Źródła poziomu 1 (statystyki rządowe, czasopisma recenzowane naukowo) powinny mieć większą wagę niż blogi lub media społecznościowe.

from datetime import datetime, timezone

HIGH_AUTHORITY_DOMAINS = [
    'gov', 'edu', 'nature.com', 'science.org', 'pubmed.ncbi.nlm.nih.gov',
    'reuters.com', 'bbc.com', 'apnews.com', 'who.int'
]

def score_source(url: str, publication_date: str | None) -> float:
    score = 0.5   # baseline
    domain = extract_domain(url)
    tld = domain.split('.')[-1]

    # Domain authority
    if any(ha in domain for ha in HIGH_AUTHORITY_DOMAINS):
        score += 0.3
    elif tld in ('gov', 'edu', 'org'):
        score += 0.1

    # Recency
    if publication_date:
        try:
            pub = datetime.fromisoformat(publication_date)
            days_old = (datetime.now(timezone.utc) - pub.replace(tzinfo=timezone.utc)).days
            if days_old < 365:
                score += 0.1
            elif days_old > 1825:  # 5 years
                score -= 0.1
        except ValueError:
            pass

    return min(1.0, max(0.0, score))

Weryfikowanie twierdzeń względem źródeł

Każde twierdzenie, które agent zamierza umieścić w raporcie końcowym, należy porównać ze wszystkimi pobranymi dokumentami, aby znaleźć najlepiej potwierdzające je źródła.

def cross_reference(claim: str, all_facts: list[dict]) -> list[dict]:
    supporting = []
    seen_domains = set()

    for fact in all_facts:
        if claims_are_equivalent(claim, fact['fact']):
            domain = extract_domain(fact['source'])
            if domain not in seen_domains:  # only one per domain
                seen_domains.add(domain)
                supporting.append({
                    'source': fact['source'],
                    'domain': domain,
                    'fact':   fact['fact'],
                    'score':  score_source(fact['source'], fact.get('publication_date'))
                })

    return sorted(supporting, key=lambda x: x['score'], reverse=True)

Weryfikowanie kwalifikacji autorów

W przypadku twierdzeń naukowych lub medycznych kwalifikacje autorów mają znaczenie. Badanie z podanymi autorami afiliowanymi przy akredytowanych instytucjach ma większą wagę niż anonimowy wpis na blogu. Należy wyodrębnić informacje o autorach i oznaczyć twierdzenia pochodzące z anonimowych źródeł.

def assess_authorship(url: str, page_text: str) -> dict:
    prompt = (
        f'From this webpage text, extract:\n'
        f'1. Author name(s) (or null)\n'
        f'2. Author affiliation/credentials (or null)\n'
        f'3. Publication name (or null)\n'
        f'Return JSON: {{"authors": [], "affiliation": null, "publication": null}}\n\n'
        f'TEXT:\n{page_text[:2000]}'
    )
    resp = client.chat.completions.create(
        model='gpt-4o-mini',
        messages=[{'role': 'user', 'content': prompt}],
        response_format={'type': 'json_object'}
    )
    return json.loads(resp.choices[0].message.content)

Oznaczanie niezweryfikowanych twierdzeń

Twierdzenia, których nie można porównać z dwoma niezależnymi źródłami, należy oznaczyć w wynikach jako niezweryfikowane. W zależności od poziomu ryzyka raportu niezweryfikowane twierdzenia można pominąć albo przedstawić z zastrzeżeniem.

def classify_claims(claims: list[str], all_facts: list[dict]) -> list[dict]:
    classified = []
    for claim in claims:
        support = cross_reference(claim, all_facts)
        classified.append({
            'claim':       claim,
            'verified':    len(support) >= 2,
            'sources':     support[:3],  # top 3 supporting sources
            'confidence':  'high' if len(support) >= 3 else
                           'medium' if len(support) == 2 else
                           'low'
        })
    return classified

Format cytowań: cytowania śródtekstowe i bibliografia

Raporty powinny zawierać cytowania śródtekstowe (numerowane indeksy górne) oraz bibliografię na końcu. Należy wygenerować oba elementy na podstawie zweryfikowanych metadanych źródeł.

def format_citations(classified_claims: list[dict]) -> tuple[list[str], list[str]]:
    ref_list = []
    ref_map = {}   # url -> citation number
    inline_claims = []

    for item in classified_claims:
        nums = []
        for src in item['sources']:
            url = src['source']
            if url not in ref_map:
                ref_map[url] = len(ref_list) + 1
                ref_list.append(f'[{ref_map[url]}] {url}')
            nums.append(f'[{ref_map[url]}]')

        citation_str = ''.join(nums)
        prefix = '' if item['verified'] else '[UNVERIFIED] '
        inline_claims.append(f'{prefix}{item["claim"]} {citation_str}')

    return inline_claims, ref_list

if __name__ == '__main__':
    demo_claims = [
        {'claim': 'Revenue grew 12% year over year', 'verified': True, 'sources': [{'source': 'https://example.com/report'}]},
        {'claim': 'The CEO plans to step down', 'verified': False, 'sources': [{'source': 'https://example.com/rumor'}]},
    ]
    inline, refs = format_citations(demo_claims)
    for line in inline:
        print(line)
    print('References:')
    for r in refs:
        print(' ', r)

Wykrywanie sprzeczności między źródłami

Czasami dwa wiarygodne źródła są ze sobą sprzeczne. Należy wykrywać sprzeczności i przedstawiać oba punkty widzenia zamiast po cichu wybierać jeden z nich. Jest to szczególnie ważne w przypadku spornych twierdzeń empirycznych.

def find_contradictions(claim: str, all_facts: list[dict]) -> list[dict]:
    contradictions = []
    for fact in all_facts:
        if extract_domain(fact['source']) == extract_domain(claim):
            continue
        prompt = (
            f'Does fact B contradict fact A?\n'
            f'A: "{claim}"\nB: "{fact["fact"]}"\n'
            f'JSON: {{"contradicts": true/false}}'
        )
        resp = client.chat.completions.create(
            model='gpt-4o-mini',
            messages=[{'role': 'user', 'content': prompt}],
            response_format={'type': 'json_object'}
        )
        result = json.loads(resp.choices[0].message.content)
        if result.get('contradicts'):
            contradictions.append(fact)
    return contradictions

Raport z weryfikacji

Przed wygenerowaniem raportu końcowego należy przygotować podsumowanie weryfikacji: liczbę zweryfikowanych i niezweryfikowanych twierdzeń, najważniejsze źródła według oceny wiarygodności oraz wykryte sprzeczności.

def verification_report_card(classified: list[dict]) -> dict:
    total     = len(classified)
    verified  = sum(1 for c in classified if c['verified'])
    all_sources = [
        src for c in classified for src in c['sources']
    ]
    top_domains = sorted(
        set(s['domain'] for s in all_sources),
        key=lambda d: max(s['score'] for s in all_sources if s['domain'] == d),
        reverse=True
    )[:5]
    return {
        'total_claims':    total,
        'verified':        verified,
        'unverified':      total - verified,
        'verification_rate': f'{verified/max(total,1)*100:.0f}%',
        'top_sources':     top_domains
    }

if __name__ == '__main__':
    demo_classified = [
        {'verified': True, 'sources': [{'domain': 'docs.python.org', 'score': 1.3}]},
        {'verified': False, 'sources': [{'domain': 'quora.com', 'score': 0.5}]},
    ]
    card = verification_report_card(demo_classified)
    for k, v in card.items():
        print(f'{k}: {v}')

Wynik zależny od poziomu pewności

Przed publikacją należy ustawić minimalny próg weryfikacji. Jeśli zweryfikowano mniej niż 70% twierdzeń, należy zlecić pętli badawczej kolejną iterację ukierunkowaną konkretnie na niezweryfikowane twierdzenia.

MIN_VERIFICATION_RATE = 0.70

def should_run_more_research(classified: list[dict]) -> list[str]:
    unverified = [c for c in classified if not c['verified']]
    total = len(classified)
    if total == 0:
        return []
    rate = (total - len(unverified)) / total
    if rate >= MIN_VERIFICATION_RATE:
        return []  # Sufficient confidence — stop
    # Return search queries to verify remaining claims
    return [f'verify: {c["claim"]}' for c in unverified[:3]]

if __name__ == '__main__':
    demo_classified = [
        {'claim': 'A', 'verified': True},
        {'claim': 'B', 'verified': False},
        {'claim': 'C', 'verified': False},
    ]
    followups = should_run_more_research(demo_classified)
    print('Follow-up queries needed:', followups)

Co oznaczają „niezależne” źródła w regule weryfikacji za pomocą dwóch źródeł?

Kryterium niezależności zapobiega weryfikacji w bańce informacyjnej, w której to samo twierdzenie można prześledzić do jednego źródła pierwotnego cytowanego przez wiele serwisów.

Podsumowanie weryfikacji źródeł

Zweryfikowane badanie wymaga: potwierdzenia w dwóch źródłach z różnych domen, semantycznego dopasowywania z użyciem LLM w celu wykrywania sparafrazowanych odpowiedników, oceniania jakości źródeł (autorytet domeny + aktualność), wykrywania sprzeczności oraz wyniku zależnego od poziomu pewności, który uruchamia dodatkowe badania, jeśli odsetek zweryfikowanych twierdzeń jest zbyt niski.

Często zadawane pytania

Czy lekcja „Weryfikacja źródeł i cytowanie” jest bezpłatna?

Tak — pełny tekst „Weryfikacja źródeł i cytowanie” 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 „Weryfikacja źródeł i cytowanie”?

Porównywanie twierdzeń w wielu źródłach i dołączanie adresów URL źródeł do faktów. Ć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 2 z 4.

Ile czasu zajmuje lekcja „Weryfikacja źródeł i cytowanie”?

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