Du trenger ikke et «intelligent nyhetsmiljø» for å holde deg oppdatert. Du trenger åtte kilder du stoler på, en jobb som henter dem, og et sammendrag som kan leses på ti minutter. Alt utover det er som oftest et nytt sted å logge inn.
Poenget med en research-radar er ikke at maskinen skal vite hva som er viktig. Poenget er at den fjerner det kjedelige: å åpne tolv faner, se den samme saken fem ganger og miste lenken til originalen. Det som kommer ut, er en leseliste. Ikke en artikkel, ikke en post, ikke noe som publiseres uten at du har lest det.
Hele designet på ett skjermbilde #
Radaren har fem steg, og ingen av dem krever en plattform:
- Hent nye oppføringer fra noen få RSS- eller Atom-feeder.
- Rens URL-ene og fjern duplikater.
- Filtrer bort det som ikke angår deg.
- Lagre rådata med kilde, lenke og tidspunkt, slik at alt kan etterprøves.
- Oppsummer én gang per uke eller dag, med strenge regler for hva modellen får og ikke får gjøre.
Det er en liten databasefil, ett skript og én AI-jobb. Hvis du tenker «det der kan jeg bygge på en kveld», har du tenkt riktig.
Steg 1–4: hent, rens, filtrer, lagre #
De fleste feeder støtter betingede forespørsler. Tjeneren sender en ETag eller Last-Modified, du sender den tilbake neste gang, og får 304 Not Modified hvis ingenting har endret seg. Feedparser-dokumentasjonen anbefaler å støtte begge og advarer om at du ellers kan laste ned det samme om og om igjen og risikere å bli utestengt. Det er høflig, og det er gratis.
Duplikater kommer i to former. Den ene er samme lenke med forskjellig sporingshale (utm_source og venner). Den andre er ulike lenker til samme sak, for eksempel en pressemelding gjengitt av fire medier. Det første løser du i kode ved å normalisere URL-en. Det andre løser du ikke ved å be en modell om å «se bort fra duplikater». Det løser du ved å huske hvem som sa hva, og det kommer vi tilbake til.
Her er en minimal versjon. Den er illustrativ og ikke produksjonsklar: ingen feilhåndtering utover det nødvendige, og du må installere feedparser selv (pip install feedparser).
import hashlib, re, sqlite3, time
from urllib.parse import urlsplit, urlunsplit, parse_qsl, urlencode
import feedparser
FEEDS = [
"https://example.com/feed.xml", # bytt ut med dine egne kilder
]
TRACKING = {"utm_source", "utm_medium", "utm_campaign", "utm_term",
"utm_content", "fbclid", "gclid"}
KEYWORDS = ["rss", "automatisering", "api"] # tomt = ta alt
def canon(url: str) -> str:
p = urlsplit(url)
query = [(k, v) for k, v in parse_qsl(p.query) if k not in TRACKING]
path = p.path.rstrip("/") or "/"
return urlunsplit((p.scheme, p.netloc.lower(), path, urlencode(query), ""))
db = sqlite3.connect("radar.db")
db.executescript("""
CREATE TABLE IF NOT EXISTS feeds (url TEXT PRIMARY KEY, etag TEXT, modified TEXT);
CREATE TABLE IF NOT EXISTS items (
id TEXT PRIMARY KEY, source TEXT, title TEXT, url TEXT,
summary TEXT, published TEXT, fetched_at TEXT);
""")
for feed_url in FEEDS:
row = db.execute("SELECT etag, modified FROM feeds WHERE url=?", (feed_url,)).fetchone()
etag, modified = row if row else (None, None)
d = feedparser.parse(feed_url, etag=etag, modified=modified)
if d.get("status") == 304:
continue
db.execute("INSERT OR REPLACE INTO feeds VALUES (?,?,?)",
(feed_url, d.get("etag"), d.get("modified")))
for e in d.entries:
link = canon(e.get("link", ""))
text = (e.get("title", "") + " " + e.get("summary", "")).lower()
if not link or (KEYWORDS and not any(k in text for k in KEYWORDS)):
continue
item_id = hashlib.sha256(link.encode()).hexdigest()[:16]
db.execute("INSERT OR IGNORE INTO items VALUES (?,?,?,?,?,?,?)", (
item_id, d.feed.get("title", feed_url), e.get("title", ""), link,
re.sub(r"<[^>]+>", "", e.get("summary", ""))[:500],
e.get("published", ""), time.strftime("%Y-%m-%d %H:%M:%S")))
db.commit() Legg merke til hva som bevares: kilde, original-URL, tittel, et kort utdrag og når du hentet det. Ingenting blir skrevet om. Det du lagrer er det kilden faktisk sa, ikke det en modell mener at kilden sa.
Steg 5: la AI foreslå, ikke påstå #
Her går de fleste radarer av skinnene. Modellen får femti oppføringer og beskjed om å «finne trendene». Resultatet er selvsikre avsnitt om utviklingstrekk som delvis er oppfunnet, uten lenker du kan sjekke.
Hold i stedet to ting strengt adskilt i det du leverer til leseren:
- Fra kildene: tittel, kilde, dato og original-lenke. Dette settes inn av koden, ikke av modellen.
- Forslag: modellens vurdering av hva som kan være verdt å lese, merket som forslag.
Gi modellen oppføringene som nummererte ID-er, og sett reglene i prompten:
Du får en liste med oppføringer, hver med en ID, kilde, tittel og kort utdrag.
Regler:
- Foreslå maks fem temaer for en leseliste.
- Hvert tema må oppgi ID-ene det bygger på. Ingen ID-er, ingen tema.
- Bruk bare informasjon fra utdragene. Ikke legg til fakta, tall eller datoer.
- Skriv hvorfor temaet kan være verdt å lese, i én setning, som et forslag.
- Hvis oppføringene ikke gir grunnlag for et tema, skriv "ingen forslag". Så sjekker koden svaret. Alle ID-er modellen oppgir, må finnes i uttrekket. Alle lenker i sluttresultatet hentes fra databasen via ID. Hvis modellen refererer til en ID som ikke finnes, kaster du svaret og kjører på nytt. Det er ti linjer kode, og det er forskjellen på en radar og en rykteflyt.
Slik unngår du falske trender #
En «trend» er ofte bare ett utspill som er gjengitt mange ganger. Tre forsvar, alle deterministiske:
- Tell uavhengige kilder, ikke oppføringer. Fire medier som siterer samme pressemelding er én kilde med megafon. Grupper på opprinnelig kilde der du kan, og krev minst to virkelig ulike kilder før noe får kalles et tema.
- La koden tallfeste, ikke modellen. Hvis leselisten sier «seks kilder skrev om dette», skal tallet komme fra en telling i databasen. Modeller er gode på språk og dårlige på å telle det de ikke har sett.
- Lenk alltid til originalen. Hvert forslag skal kunne etterprøves med ett klikk. Klarer du ikke å følge et forslag tilbake til en kilde, skal det ikke inn.
Legg til et fjerde, helt analogt tiltak: sett et tak på alder. En oppføring som er tre uker gammel, er sjelden «nytt» uansett hvor mange som har tatt den opp.
Hva du bevisst ikke bygger #
Ingen auto-publisering. Ingen dashboard. Ingen vektorbase. Ingen «agent» som bestemmer hva du skal mene. Resultatet er en Markdown-fil eller en e-post med ti–femten lenker, gruppert i et par forslag, som du leser med kaffe. Hvis noe av det er verdt å skrive om, skriver du det selv, med de originale kildene åpne.
Når radaren har gjort jobben sin i noen uker, får du et ærlig svar på om du trenger mer. Sannsynligvis ikke. Sannsynligvis trengte du bare å slippe å åpne tolv faner.
