Skip to content

3 · Use the structure you have

The podcast feed already contains plenty of useful information as it is: where every chapter starts, what each one is about, and when the episode aired. The pitch "just throw it into the AI" throws all of that away, then pays a model to reconstruct it, less accurately. The cheapest, most reliable work is often the work you don't hand to the model.

What the feed already gives you

The RSS feed ships Podlove chapter markers (a title and a start time per segment) and a publish date, human-authored structure already sitting in the file:

<podcast:chapters>
  <chapter startTime="0"    title="Intro" />
  <chapter startTime="184"  title="Wirecard – der Insolvenzverwalter…" />
  <chapter startTime="1102" title="Govcoins" />
</podcast:chapters>
<pubDate>Mon, 20 Jan 2022 06:00:00 +0100</pubDate>

Read straight from the feed, those become three things the rest of the system leans on:

  • Chunk boundaries. Chapter starts anchor the 90-second, chapter-aligned chunks the relation extractor works over, so a fact's location in the audio is inherited, not guessed.
  • A table of contents. Every chapter title is a human-written summary of a segment.
  • A calendar axis. pubDate, parsed from RFC-822 into a typed Neo4j DateTime across all 463 episodes (2016 → 2026), so questions like "how has coverage of X moved over time" can be answered in a meaningful way.

When a feed carries no chapters, there's a graceful fallback - one [default] chapter spanning the whole episode - and nothing downstream breaks. The lesson generalises well past podcasts: most "unstructured" data isn't, once you look for the filenames, ticket fields, email headers and timestamps wrapped around it.

Metadata as a consistency check

What's great about this metadata is that it can also be used to check our extraction results for consistency. A recurring move in this project is to validate a model's output against a signal drawn straight from the feed, and the recording date is the cleanest example.

Publish date isn't the same as recording date, and for a topical show the gap matters: a claim can be stale before the episode even airs. The host often announces when they're recording ("so, es ist der 18. Januar…"), so a local model extracts that date - but only when the transcript genuinely states it (evidence-gated, no guessing) - and then anchors it to the pubDate from the feed: a recording date has to fall on or before the publish date, and within a few weeks of it, or it's rejected. The surviving gap, pubDate − recordingDate, becomes a staleness window the timeline can flag.

The cross-check earns its keep by catching a real error: on one episode the host announced the wrong year, and the weekday named in the audio plus the publish date together proved the true one, so the extracted date was auto-corrected rather than trusted. A structured signal from the feed turned a model's plausible-but-wrong output into a corrected, defensible one.

The same move shows up one stage over, at speaker attribution: the feed's prose cast list validates who the pipeline thinks is talking, before and after the expensive LLM refinement, which is where the next chapter goes. The real lesson here is not so much cheap versus expensive, but building up independent sources of truth and using their agreement (or disagreement) to either lift a fact's credibility or flag it for a closer look.

How this was made. The pipeline and the articles you're about to read were both created with AI assistance. Responsibility for both, and especially for the statements made in the articles, lies with me. I acknowledge and respect that many people, for ethical or other reasons, will not want to consume content that was created in part or wholly using LLMs. This is your notice. My intent is to inform, not deceive.

Close