Files
dobetternorge-tools/korrespond-tech.php
T
daveadmin 29579eae66 Add NO/UK/PL translations to all 6 doc pages
Per-page translation arrays in translations/*.php (EN/NO/UK/PL) for
korrespond-about, korrespond-guide, korrespond-tech, timeline-about,
timeline-guide, and timeline-tech. Generated via Azure gpt-4o-mini;
Norwegian legal/institution terms preserved as-is in all languages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 16:58:15 +02:00

346 lines
18 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/includes/bootstrap.php';
$uiLang = dbnToolsCurrentLanguage();
$isAuthed = dbnToolsIsAuthenticated();
$langPath = '/korrespond-tech.php';
$toolsLogin = 'https://dobetternorge.no/tools-login.php?return=' . urlencode('/korrespond.php');
$registerUrl = 'https://dobetternorge.no/register.php';
$_pt = require __DIR__ . '/translations/korrespond-tech.php';
$t = $_pt[$uiLang] ?? $_pt['en'];
?>
<!doctype html>
<html lang="<?= htmlspecialchars($uiLang) ?>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>How Korrespond works — Hard-RAG, fine-tuned LLM, 3-pass pipeline</title>
<meta name="description" content="Technical deep-dive: how Korrespond uses Hard-RAG retrieval, a QLoRA fine-tuned legal LLM, and a 3-pass pipeline to produce verified Norwegian legal correspondence.">
<meta name="robots" content="index, follow">
<link rel="canonical" href="https://tools.dobetternorge.no/korrespond-tech.php">
<meta property="og:title" content="How Korrespond works — Hard-RAG, fine-tuned LLM, 3-pass pipeline">
<meta property="og:description" content="220K+ passages, 8 corpus slices, Azure gpt-4o, citation verification, and a QLoRA fine-tune on Norwegian legal text.">
<meta name="theme-color" content="#00205B">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Crimson+Pro:wght@400;600;700&family=IBM+Plex+Sans:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap">
<link rel="stylesheet" href="assets/css/tools.css">
</head>
<body class="kdoc-page">
<header class="lt-nav">
<a href="https://dobetternorge.no" class="lt-nav__brand">
<picture>
<source srcset="assets/images/logo-header.webp" type="image/webp">
<img class="lt-nav__logo" src="assets/images/logo-header.png" alt="Do Better Norge" width="140" height="36" loading="eager">
</picture>
<span class="lt-nav__badge">Legal Tools</span>
</a>
<div class="lt-nav__right">
<nav class="shell-lang-switcher" aria-label="Language">
<?php foreach (dbnToolsSupportedLanguages() as $langCode): ?>
<a href="<?= htmlspecialchars($langPath . '?lang=' . $langCode) ?>" class="<?= $langCode === $uiLang ? 'is-active' : '' ?>"><?= htmlspecialchars(dbnToolsLanguageLabel($langCode)) ?></a>
<?php endforeach; ?>
</nav>
<?php if ($isAuthed): ?>
<a href="/korrespond.php" class="lt-nav__cta lt-nav__cta--enter"><?= htmlspecialchars($t['nav_open']) ?></a>
<?php else: ?>
<a href="<?= htmlspecialchars($toolsLogin) ?>" class="lt-nav__cta"><?= htmlspecialchars($t['nav_signin']) ?></a>
<?php endif; ?>
</div>
</header>
<nav class="kdoc-doc-nav" aria-label="Korrespond documentation">
<div class="kdoc-doc-nav__inner">
<a href="/korrespond-about.php"><?= htmlspecialchars($t['nav_about']) ?></a>
<a href="/korrespond-guide.php"><?= htmlspecialchars($t['nav_guide']) ?></a>
<a href="/korrespond-tech.php" class="is-active"><?= htmlspecialchars($t['nav_howit']) ?></a>
<?php if ($isAuthed): ?><a href="/korrespond.php"><?= htmlspecialchars($t['nav_opentool']) ?></a><?php endif; ?>
</div>
</nav>
<!-- Hero -->
<section class="kdoc-hero" style="background: linear-gradient(rgba(5,15,40,0.85),rgba(5,15,40,0.92)), url('assets/images/korrespond/hero-tech.png') center/cover no-repeat;">
<div class="kdoc-hero__inner">
<p class="kdoc-hero__kicker"><?= htmlspecialchars($t['hero_kicker']) ?></p>
<h1 class="kdoc-hero__title"><?= htmlspecialchars($t['hero_title']) ?></h1>
<p class="kdoc-hero__sub"><?= htmlspecialchars($t['hero_sub']) ?></p>
<div class="kdoc-hero__stats">
<div class="kdoc-hero__stat">
<strong>220K+</strong>
<span><?= htmlspecialchars($t['stat1']) ?></span>
</div>
<div class="kdoc-hero__stat">
<strong>8</strong>
<span><?= htmlspecialchars($t['stat2']) ?></span>
</div>
<div class="kdoc-hero__stat">
<strong>3</strong>
<span><?= htmlspecialchars($t['stat3']) ?></span>
</div>
<div class="kdoc-hero__stat">
<strong>gpt-4o</strong>
<span><?= htmlspecialchars($t['stat4']) ?></span>
</div>
</div>
</div>
</section>
<!-- Architecture overview -->
<div class="kdoc-section">
<p class="kdoc-section__eyebrow"><?= htmlspecialchars($t['arch_eyebrow']) ?></p>
<h2 class="kdoc-section__title"><?= htmlspecialchars($t['arch_title']) ?></h2>
<p class="kdoc-section__sub"><?= htmlspecialchars($t['arch_sub']) ?></p>
<div class="kdoc-pipeline">
<div class="kdoc-pipeline__pass">
<span class="kdoc-pipeline__pass-badge kdoc-pipeline__pass-badge--mini">Pass 1 · gpt-4o-mini</span>
<h3 class="kdoc-pipeline__pass-title"><?= htmlspecialchars($t['pass1_title']) ?></h3>
<p class="kdoc-pipeline__pass-body"><?= $t['pass1_p1_html'] ?></p>
<ul>
<li><code>summary</code> — one-sentence case summary</li>
<li><code>parties</code> — identified actors</li>
<li><code>applicable_acts</code> — relevant statute sets</li>
<li><code>missing_facts[]</code> — gaps that would hurt draft quality</li>
<li><code>suggested_goal</code> — inferred goal if none stated</li>
</ul>
<p class="kdoc-pipeline__pass-body" style="margin-top:0.7rem;"><?= $t['pass1_p2_html'] ?></p>
</div>
<div class="kdoc-pipeline__arrow-down" aria-hidden="true">&rarr;</div>
<div class="kdoc-pipeline__pass">
<span class="kdoc-pipeline__pass-badge">Pass 2 · gpt-4o</span>
<h3 class="kdoc-pipeline__pass-title"><?= htmlspecialchars($t['pass2_title']) ?></h3>
<p class="kdoc-pipeline__pass-body"><?= htmlspecialchars($t['pass2_p1']) ?></p>
<ul>
<li><?= $t['pass2_r1_html'] ?></li>
<li><?= $t['pass2_r2_html'] ?></li>
<li><?= $t['pass2_r3_html'] ?></li>
<li><?= $t['pass2_r4_html'] ?></li>
</ul>
</div>
<div class="kdoc-pipeline__arrow-down" aria-hidden="true">&rarr;</div>
<div class="kdoc-pipeline__pass">
<span class="kdoc-pipeline__pass-badge kdoc-pipeline__pass-badge--optional">Pass 3 · optional</span>
<h3 class="kdoc-pipeline__pass-title"><?= htmlspecialchars($t['pass3_title']) ?></h3>
<p class="kdoc-pipeline__pass-body"><?= $t['pass3_p1_html'] ?></p>
<ul>
<li><?= $t['pass3_n1_html'] ?></li>
<li><?= $t['pass3_n2_html'] ?></li>
<li><?= $t['pass3_n3_html'] ?></li>
</ul>
</div>
</div>
</div>
<!-- Hard-RAG retrieval -->
<section class="kdoc-section--alt">
<div class="kdoc-section">
<p class="kdoc-section__eyebrow"><?= htmlspecialchars($t['rag_eyebrow']) ?></p>
<h2 class="kdoc-section__title"><?= htmlspecialchars($t['rag_title']) ?></h2>
<p class="kdoc-section__sub"><?= htmlspecialchars($t['rag_sub']) ?></p>
<div class="kdoc-rag-flow">
<div class="kdoc-rag-row">
<div class="kdoc-rag-box kdoc-rag-box--blue"><?= htmlspecialchars($t['rag_box1']) ?></div>
<span class="kdoc-rag-arrow">&rarr;</span>
<div class="kdoc-rag-box"><?= htmlspecialchars($t['rag_box2']) ?></div>
<span class="kdoc-rag-arrow">&rarr;</span>
<div class="kdoc-rag-box"><?= htmlspecialchars($t['rag_box3']) ?></div>
<span class="kdoc-rag-arrow">&rarr;</span>
<div class="kdoc-rag-box kdoc-rag-box--teal"><?= htmlspecialchars($t['rag_box4']) ?></div>
</div>
<div class="kdoc-rag-row" style="margin-top:8px;">
<div class="kdoc-rag-box kdoc-rag-box--teal"><?= htmlspecialchars($t['rag_box5']) ?></div>
<span class="kdoc-rag-arrow">&rarr;</span>
<div class="kdoc-rag-box"><?= htmlspecialchars($t['rag_box6']) ?></div>
<span class="kdoc-rag-arrow">&rarr;</span>
<div class="kdoc-rag-box"><?= htmlspecialchars($t['rag_box7']) ?></div>
<span class="kdoc-rag-arrow">&rarr;</span>
<div class="kdoc-rag-box kdoc-rag-box--red"><?= htmlspecialchars($t['rag_box8']) ?></div>
</div>
</div>
<p style="font-size:0.9rem; line-height:1.7; margin-top:1.5rem; opacity:0.85;"><?= $t['rag_p1_html'] ?></p>
<h3 style="font-family:'Crimson Pro',serif; font-size:1.2rem; font-weight:700; margin:2rem 0 0.8rem; color:var(--dbn-blue);"><?= htmlspecialchars($t['rag_h2']) ?></h3>
<p style="font-size:0.9rem; line-height:1.7; opacity:0.85;"><?= $t['rag_p2_html'] ?></p>
</div>
</section>
<!-- Knowledge base -->
<div class="kdoc-section">
<p class="kdoc-section__eyebrow"><?= htmlspecialchars($t['kb_eyebrow']) ?></p>
<h2 class="kdoc-section__title"><?= htmlspecialchars($t['kb_title']) ?></h2>
<p class="kdoc-section__sub"><?= htmlspecialchars($t['kb_sub']) ?></p>
<div class="kdoc-kb-stats">
<div class="kdoc-kb-stat">
<strong>220K+</strong>
<span><?= htmlspecialchars($t['kb_s1']) ?></span>
</div>
<div class="kdoc-kb-stat">
<strong>8</strong>
<span><?= htmlspecialchars($t['kb_s2']) ?></span>
</div>
<div class="kdoc-kb-stat">
<strong>1,731</strong>
<span><?= htmlspecialchars($t['kb_s3']) ?></span>
</div>
<div class="kdoc-kb-stat">
<strong>23</strong>
<span><?= htmlspecialchars($t['kb_s4']) ?></span>
</div>
<div class="kdoc-kb-stat">
<strong>Azure</strong>
<span><?= htmlspecialchars($t['kb_s5']) ?></span>
</div>
<div class="kdoc-kb-stat">
<strong>Hybrid</strong>
<span><?= htmlspecialchars($t['kb_s6']) ?></span>
</div>
</div>
<h3 style="font-family:'Crimson Pro',serif; font-size:1.15rem; font-weight:700; margin:2rem 0 0.8rem; color:var(--dbn-blue);"><?= htmlspecialchars($t['kb_h2']) ?></h3>
<div class="kdoc-slice-grid">
<span class="kdoc-slice-chip">child_welfare</span>
<span class="kdoc-slice-chip">echr</span>
<span class="kdoc-slice-chip">family_core</span>
<span class="kdoc-slice-chip">bufdir_guidance</span>
<span class="kdoc-slice-chip">norwegian_courts</span>
<span class="kdoc-slice-chip">broader_legal</span>
<span class="kdoc-slice-chip">dbn_resources</span>
<span class="kdoc-slice-chip">hague</span>
</div>
<h3 style="font-family:'Crimson Pro',serif; font-size:1.15rem; font-weight:700; margin:2rem 0 0.8rem; color:var(--dbn-blue);"><?= htmlspecialchars($t['kb_h3']) ?></h3>
<table class="kdoc-table">
<thead>
<tr><th><?= htmlspecialchars($t['kb_th1']) ?></th><th><?= htmlspecialchars($t['kb_th2']) ?></th></tr>
</thead>
<tbody>
<tr><td>Barnevernet</td><td>child_welfare · echr · family_core</td></tr>
<tr><td>Bufdir</td><td>family_core · echr · bufdir_guidance</td></tr>
<tr><td>NAV</td><td>broader_legal (NAV-loven)</td></tr>
<tr><td>Skole / Barnehage / SFO</td><td>broader_legal (opplæringslova / barnehageloven)</td></tr>
<tr><td>Statsforvalteren</td><td>child_welfare · broader_legal</td></tr>
<tr><td>Trygderetten / Tingretten</td><td>norwegian_courts · broader_legal</td></tr>
</tbody>
</table>
</div>
<!-- Fine-tuned LLM -->
<section class="kdoc-section--alt">
<div class="kdoc-section">
<p class="kdoc-section__eyebrow"><?= htmlspecialchars($t['ft_eyebrow']) ?></p>
<h2 class="kdoc-section__title"><?= htmlspecialchars($t['ft_title']) ?></h2>
<div class="kdoc-finetune">
<span class="kdoc-finetune__badge"><?= htmlspecialchars($t['ft_badge']) ?></span>
<h3 class="kdoc-finetune__title">dbn-legal-agent</h3>
<p class="kdoc-finetune__body"><?= htmlspecialchars($t['ft_p1']) ?></p>
<p class="kdoc-finetune__body" style="margin-top:0.8rem;"><?= htmlspecialchars($t['ft_p2']) ?></p>
<div class="kdoc-finetune__chips">
<span class="kdoc-finetune__chip">QLoRA</span>
<span class="kdoc-finetune__chip">forvaltningsloven</span>
<span class="kdoc-finetune__chip">barnevernsloven</span>
<span class="kdoc-finetune__chip">child-welfare corpus</span>
<span class="kdoc-finetune__chip">Norwegian bokmål output</span>
<span class="kdoc-finetune__chip">gpt-4o co-pipeline</span>
</div>
</div>
<h3 style="font-family:'Crimson Pro',serif; font-size:1.15rem; font-weight:700; margin:2rem 0 0.8rem; color:var(--dbn-blue);">Model responsibilities in the pipeline</h3>
<table class="kdoc-table">
<thead>
<tr><th><?= htmlspecialchars($t['ft_th1']) ?></th><th><?= htmlspecialchars($t['ft_th2']) ?></th><th><?= htmlspecialchars($t['ft_th3']) ?></th></tr>
</thead>
<tbody>
<tr><td>Pass 1 classify</td><td>gpt-4o-mini</td><td><?= htmlspecialchars($t['ft_r1_role']) ?></td></tr>
<tr><td>Pass 1 clarify questions</td><td>gpt-4o-mini + dbn-legal-agent</td><td><?= htmlspecialchars($t['ft_r2_role']) ?></td></tr>
<tr><td>Pass 2 draft</td><td>gpt-4o</td><td><?= htmlspecialchars($t['ft_r3_role']) ?></td></tr>
<tr><td>Pass 2 self-check</td><td>gpt-4o-mini</td><td><?= htmlspecialchars($t['ft_r4_role']) ?></td></tr>
<tr><td>Pass 2 translate</td><td>gpt-4o-mini</td><td><?= htmlspecialchars($t['ft_r5_role']) ?></td></tr>
<tr><td>Pass 3 refine</td><td>gpt-4o</td><td><?= htmlspecialchars($t['ft_r6_role']) ?></td></tr>
</tbody>
</table>
</div>
</section>
<!-- Pass 3 formal citations -->
<div class="kdoc-section">
<p class="kdoc-section__eyebrow"><?= htmlspecialchars($t['p3_eyebrow']) ?></p>
<h2 class="kdoc-section__title"><?= htmlspecialchars($t['p3_title']) ?></h2>
<p class="kdoc-section__sub"><?= htmlspecialchars($t['p3_sub']) ?></p>
<div class="kdoc-features" style="margin-bottom:2rem;">
<div class="kdoc-feature-card">
<span class="kdoc-feature-card__icon">&#127475;&#127476;</span>
<h3 class="kdoc-feature-card__title"><?= htmlspecialchars($t['p3_f1_title']) ?></h3>
<p class="kdoc-feature-card__body"><?= $t['p3_f1_body_html'] ?></p>
</div>
<div class="kdoc-feature-card">
<span class="kdoc-feature-card__icon">&#9878;&#65039;</span>
<h3 class="kdoc-feature-card__title"><?= htmlspecialchars($t['p3_f2_title']) ?></h3>
<p class="kdoc-feature-card__body"><?= $t['p3_f2_body_html'] ?></p>
</div>
</div>
<h3 style="font-family:'Crimson Pro',serif; font-size:1.15rem; font-weight:700; margin:0 0 0.8rem; color:var(--dbn-blue);"><?= htmlspecialchars($t['p3_eg_title']) ?></h3>
<img src="assets/images/korrespond/output-refined.png" alt="Refined output showing formal citations including opplæringslova §9 A-4 and EMK artikkel 8" class="kdoc-screenshot" style="max-width:800px; display:block;" loading="lazy">
<p style="font-size:0.82rem; opacity:0.65; text-align:center; margin-top:0.5rem;"><?= $t['p3_eg_caption_html'] ?></p>
<h3 style="font-family:'Crimson Pro',serif; font-size:1.15rem; font-weight:700; margin:2rem 0 0.8rem; color:var(--dbn-blue);"><?= htmlspecialchars($t['p3_anchor_title']) ?></h3>
<p style="font-size:0.9rem; line-height:1.7; opacity:0.85; margin-bottom:1rem;"><?= htmlspecialchars($t['p3_anchor_intro']) ?></p>
<div class="kdoc-slice-grid">
<span class="kdoc-slice-chip">Strand Lobben m.fl. mot Norge</span>
<span class="kdoc-slice-chip">Johansen mot Norge</span>
<span class="kdoc-slice-chip">K.O. og V.M. mot Norge</span>
<span class="kdoc-slice-chip">Aune mot Norge</span>
<span class="kdoc-slice-chip">EMK Art. 8 family life Norway</span>
<span class="kdoc-slice-chip">EMK Art. 6 fair trial</span>
</div>
</div>
<!-- Privacy by design -->
<section class="kdoc-section--alt">
<div class="kdoc-section">
<p class="kdoc-section__eyebrow"><?= htmlspecialchars($t['priv_eyebrow']) ?></p>
<h2 class="kdoc-section__title"><?= htmlspecialchars($t['priv_title']) ?></h2>
<div class="kdoc-privacy">
<p class="kdoc-privacy__title"><?= htmlspecialchars($t['priv_badge']) ?></p>
<ul>
<li><?= $t['priv_1_html'] ?></li>
<li><?= htmlspecialchars($t['priv_2']) ?></li>
<li><?= $t['priv_3_html'] ?></li>
<li><?= $t['priv_4_html'] ?></li>
<li><?= htmlspecialchars($t['priv_5']) ?></li>
<li><?= $t['priv_6_html'] ?></li>
</ul>
</div>
</div>
</section>
<!-- CTA -->
<section class="kdoc-cta-strip">
<h2 class="kdoc-cta-strip__title"><?= htmlspecialchars($t['cta_title']) ?></h2>
<p class="kdoc-cta-strip__sub"><?= htmlspecialchars($t['cta_sub']) ?></p>
<div class="kdoc-hero__ctas">
<?php if ($isAuthed): ?>
<a href="/korrespond.php" class="kdoc-btn-primary"><?= htmlspecialchars($t['btn_open']) ?></a>
<?php else: ?>
<a href="<?= htmlspecialchars($toolsLogin) ?>" class="kdoc-btn-primary"><?= htmlspecialchars($t['btn_signin_cta']) ?></a>
<a href="<?= htmlspecialchars($registerUrl) ?>" class="kdoc-btn-secondary"><?= htmlspecialchars($t['btn_register']) ?></a>
<?php endif; ?>
<a href="/korrespond-guide.php" class="kdoc-btn-secondary"><?= htmlspecialchars($t['btn_guide']) ?></a>
</div>
</section>
<?php require_once __DIR__ . '/includes/footer.php'; ?>
<script src="assets/js/tools.js" defer></script>
</body>
</html>