diff --git a/api/_lib/researchAnalysis.ts b/api/_lib/researchAnalysis.ts index a900792..8b9ef93 100644 --- a/api/_lib/researchAnalysis.ts +++ b/api/_lib/researchAnalysis.ts @@ -90,6 +90,29 @@ function extractJson(text: string): unknown { */ const BATCH_SIZE = 5 +/** + * Welches Modell die Einordnung vornimmt. + * + * Über `LIVIA_RESEARCH_MODEL` umstellbar, ohne den Code anzufassen — die + * Wahl ist eine Kosten- und Qualitätsabwägung und gehört damit dem Betreiber, + * nicht dem Quelltext. + * + * Grössenordnung je Lauf über rund fünfzig Meldungen: + * claude-opus-5 ≈ 0.40 USD stärkstes Urteil + * claude-sonnet-5 ≈ 0.20 USD + * claude-haiku-4-5 ≈ 0.08 USD für eine Ja/Nein-Einordnung meist ausreichend + */ +const MODEL = process.env.LIVIA_RESEARCH_MODEL ?? 'claude-opus-5' + +/** + * Wie viel Artikeltext das Modell zu lesen bekommt. + * + * Ebenfalls umstellbar, weil es der zweite grosse Kostenhebel ist: Der + * Immobilienbezug einer Firmenmeldung steht fast immer im ersten Absatz, und + * jede Halbierung halbiert die Eingabekosten. + */ +const TEXT_LIMIT = Number(process.env.LIVIA_RESEARCH_TEXT_LIMIT ?? 2000) + /** * Wie viele Teilstapel gleichzeitig beurteilt werden. * @@ -116,12 +139,12 @@ async function analyzeBatch( `Quelle: ${it.source}`, `Titel: ${it.title}`, it.publishedAt ? `Publiziert: ${it.publishedAt}` : '', - `Text: ${it.text.slice(0, 2000)}`, + `Text: ${it.text.slice(0, TEXT_LIMIT)}`, ].filter(Boolean).join('\n')) .join('\n\n') const response = await client.messages.create({ - model: 'claude-opus-5', + model: MODEL, max_tokens: 8000, system: SYSTEM_PROMPT, // Einordnen ist bei fünf Einträgen eine Routineaufgabe — die niedrige Stufe