Zum Hauptinhalt springen

Syntax

Der Block

Veröffentlichungsdatum

22. September 2026

TippIn einem Satz

Ein Block ist eine Quarto-Fence der Sprache famulus: YAML-Präambel, Trenner ---, danach die Instruktion als Freitext.

Die Präambel ist vollständig. Der Block liest keinen Kontext, den weder die Präambel noch die Paketdatei famulus.yml nennt. Ein Schlüssel in der Präambel ersetzt denselben Schlüssel der Paketdatei. Listen werden ersetzt, nicht aneinandergereiht.

Die YAML-Präambel der .fam-Datei bleibt die Quarto-Präambel des Dokuments; ihr Schlüssel famulus trägt id, uses und chapters (siehe Projekt).

Pflicht id, und genau eines von subtask und partiturs

```{famulus}
---
id: <eindeutig im Paket>
# Identität, Scope, Datenzugriff, Plan, Artefakte, Prüfung
---
Instruktion als Freitext. Platzhalter {{ref:<id>.<name>}} werden vor dem Lauf ersetzt.
```

1 Identität und Ausführung

Attribut Typ Pflicht Vorgabe Abbildung
id Zeichenkette, eindeutig im Paket ja — RunRequest.goal_id; Name des Log-Ordners
client Modell-Tag nein default_model() RunRequest.model
depends_on Liste von Block-id oder Verweisen nein leere Liste Reihenfolge; ein Verweis mit Version macht den Block von dieser Version abhängig (Referenzen)
rerun if-missing, always, never nein if-missing Adapter, vor dem Lauf
rerun if-stale, always, never nein if-stale wann der Runner den Block ausführt (Projekt)

default_model() liest die Umgebungsvariable ORCH_PROVIDER und sonst ollama:glm-5.3:cloud. Query-Blöcke setzen client auf ein Modell der Allowlist. Der Default der Query-Pipeline ist gemini-3.5-flash-lite.

depends_on verlangt, dass jeder genannte Block ein manifest.json hat. Fehlt es, bricht der Adapter ab und schreibt kein Artefakt. rerun: if-missing überspringt den Lauf, wenn manifest.json schon vorliegt und seine Eingaben gleich geblieben sind: Präambel, Instruktion und Größe und Änderungszeit jeder Datei, die der Block liest (duckdb-Anhänge, Pfade in read_json_auto(…), read_parquet(…), read_csv(…), bei LWgrammar-Schritten der Regelspeicher). always spielt den Block neu. never verlangt das vorhandene Log und bricht ab, wenn es fehlt. famulus-notebook run --force spielt alle Blöcke eines Pakets neu, etwa nach einer Änderung am Code einer Fachkraft, die keine Datei des Blocks berührt.

2 Formulierung und Sprachinstitution

Attribut Typ Pflicht Vorgabe Abbildung
guard {task, lang, author, family, text, evidence} nein keine Prüfung LWgrammar lw_evaluate nach dem Oracle
partiturs[].id: lwgrammar:<werkzeug> Werkzeug der Sprachinstitution nein — MCP-Aufruf an Port 5116

guard stellt den Text, den ein Block erzeugt, unter eine Auftragsform der Sprachinstitution (notebook-text als Vorgabe, synthesize-answer für die Antwort der Abfrage-Pipeline). text nennt das Feld; Vorgabe ist die Antwort, die die Ergebniskarte zeigt. Zahlen und Zitate des Textes müssen in seinen Belegen stehen; Belege sind die Zeilen und Messwerte des Blocks, sofern evidence sie nicht ersetzt. Ein nicht bestandener Befund macht aus pass das Urteil fail; ist die Sprachinstitution nicht erreichbar, endet der Block als Fehler, und der Text bleibt als ungeprüft markiert. Ein Block ohne erzeugten Text vermerkt das, statt als geprüft zu gelten. Der Viewer zeigt das Ergebnis als Leiste unter dem Urteil.

Ein Schritt lwgrammar:<werkzeug> ruft ein Werkzeug der Sprachinstitution als Partitur-Schritt, etwa lwgrammar:lw_evaluate, lwgrammar:lw_sense_history oder lwgrammar:lw_situate_specimen. text_from: <spalte> setzt als text die Zeilen dieser Spalte aus dem vorigen Schritt; rows_from: <schlüssel> zeigt diese Liste der Antwort als Tabelle. Skalare Felder der Antwort und die Längen ihrer Listen (n_<schlüssel>) sind Messwerte für das Oracle. Beispiele: LWgrammar: Formulierungsprüfung, Kepler: anima und vis.

3 Scope

Diese Schlüssel werden zum Setting (ai_query.setting.Setting) und, soweit das Setting sie nicht trägt, zu inputs.

Attribut Typ Pflicht Vorgabe Abbildung
collections Liste von Sammlungsnamen nein aus famulus.yml Setting.collections
locked Boolesch nein false Setting.locked
reading_doc doc_id oder leer nein leer Setting.reading_doc
documents Liste von doc_id nein alle Dokumente der Sammlungen inputs.documents
evidence grounding, secondary, both nein grounding inputs.evidence
language la, de, en, fr oder Liste nein keine Sprachfilterung Filter auf stz_sentences.lang
years {from, to} nein offen inputs.years; bei Briefregistern date_when
persons Liste kanonischer Namen nein leer inputs.persons, nur über ent_canonical
lemmata Liste von Lemmata nein leer inputs.lemmata
counting_mode canonical, family, family+adj bei Lemma-Zählung ja — inputs.counting_mode
person_id Zeichenkette nein leer Setting.person_id
project Zeichenkette nein leer Setting.project

locked: true lässt die genannten Sammlungen über einen Anker im Fragetext gewinnen. Eine Einzelsammlungs-Arbeit setzt es.

evidence: grounding liest die in collections genannten Primärsammlungen. secondary liest die Geschwisterordner mit dem Suffix -sec. both liest beide und hält die Belege auseinander: Grounding Evidence aus den Primärdokumenten, Sekundärevidenz aus der Sekundärliteratur. Die Primärsammlung Pirckheimer heißt pirckheimer, die Sekundärsammlung pirckheimer-sec. Kepler heißt kepler-prim und kepler-sec.

WarnungPersonen und Lemmata

Personennamen stehen in persons und werden über ent_canonical und die Schreibvarianten der Entitätenregistrierung aufgelöst. Sie gehören nicht in lemmata. Ein Lemma-Zählblock nennt counting_mode. canonical zählt das Lemma. family nimmt registrierte Varianten hinzu. family+adj nimmt zusätzlich adjektivische Lemmata hinzu. naturalis ist ein eigenes Adjektivlemma und keine Variante von natura.

Die Satzidentität in allen Filtern ist das Tripel (doc_id, pidx, sent_idx). sent_idx beginnt auf jeder Seite neu.

4 Datenzugriff

duckdb ist eine Liste von Anhängen. Jeder Eintrag hat alias, path und read_only. read_only ist true. Der Adapter öffnet die Verbindung für die Lesung und schließt sie danach.

duckdb:
  - alias: main
    path: $PDAI_COLLECTIONS/pirckheimer/pirckheimer.duckdb
    read_only: true
  - alias: stz
    path: $PDAI_COLLECTIONS/pirckheimer/pirckheimer_stanza.duckdb
    read_only: true
  - alias: lemma
    path: $PDAI_COLLECTIONS/kepler-prim/lemma_index.parquet
    read_only: true

$PDAI_COLLECTIONS ist die Sammlungswurzel, Vorgabe /Volumes/PDAI-1/pdai-collections. Ein Parquet-Pfad wird als read_parquet gelesen, eine DuckDB-Datei mit ATTACH … (READ_ONLY).

Datei unter <coll>/ Inhalt, den ein Block lesen darf
<coll>_stanza.duckdb stz_sentences(doc_id, pidx, sent_idx, lang, text), stz_tokens mit tid, stz_entities
lemma_index.parquet lemma, upos, doc_id, pidx, sent_idx, tid
<coll>.duckdb letters_resolved, ent_canonical(ent_id, canonical, kind), letter_pages
status.json overall, artifacts, gaps
assessment/grounding_index.duckdb collection_capabilities, person_registry, letter_pairs, collection_aliases

Der letzte Pfad liegt im ai-query-Arbeitsverzeichnis, nicht in der Sammlung. Die Präambel nennt ihn mit absolutem Pfad, wenn ein Block ihn braucht.

5 Plan

Genau eines von subtask und partiturs.

subtask wählt die Partitur ai-query-phase1. Die Instruktion wird RunRequest.goal und inputs.instruction. Der Subtask-Name wird inputs.subtask.

subtask: correspondence-count

Registrierte Werte, Tabelle subtasks in agent_memory.duckdb:

subtask Frageform Typisches Artefakt
correspondence-count Anzahl der Briefpartner oder Briefe report
correspondence-roster Liste der Briefpartner roster-table
letter-subject Gegenstand der Briefe markdown
mention-in-letters Wer nennt eine Person in Briefen an wen roster-table
terminology-find Belege eines Lemmas oder Terminus kwic
concept-statements Aussagen über einen Begriff markdown
statement-mention Alias von concept-statements markdown
source-attestation Belegstelle einer Quelle citation-list
sentence-mention Sätze, die eine Zeichenkette enthalten kwic
cooccurrence Sätze mit mehreren Lemmata kwic
manuscript-inventory Manuskripte: Datum, Umfang, Titel roster-table
register-inventory Bestand eines Registers roster-table
entity-mention-count Anzahl der Nennungen einer Entität report

attestation kommt in expected_route des Golden-Manifests vor und ist kein Wert von subtask. Lemma-Belege dieser Route schreiben die Blöcke als terminology-find oder cooccurrence.

partiturs ist eine Liste. Jeder Eintrag ist ein eigener Lauf, in Listenreihenfolge. Der nächste Lauf beginnt, nachdem das Artefakt des vorigen im Log steht. Erreicht ein Lauf das Ziel nicht, endet die Kette.

Schlüssel Typ Pflicht Abbildung
id Register-Id, goal_path, oder adapter-lokaler Schritt ja partitur_path oder Adapter-Schritt
setting Pfad einer Setting-Datei nein RunRequest.setting
input Abbildung von Namen auf Werte nein RunRequest.inputs
artefact name aus artefacts nein Zieldatei dieses Laufs

Ein Wert in input darf ein Querverweis sein: {ref: <id>.<name>}. Die Auflösung steht in der Projektbeschreibung.

partiturs:
  - id: query/historical/stage-one
    setting: settings/pirckheimer-1520-1530.setting.yaml
    input:
      subtask: correspondence-roster
    artefact: roster

Zwei Ids interpretiert der Adapter selbst. Sie stehen nicht im Register.

Id Verhalten
duckdb-read Führt input.sql auf den Anhängen aus duckdb aus. $PDAI_COLLECTIONS wird auch in input.sql ersetzt. Nur lesend, Verbindung kurzlebig. Schreibt eine Tabelle.
artifact:<kind> Ruft den Builder dieses kind in ai_query.pipeline.artifact auf. Eingabe ist input. Kein Conductor-Lauf.

6 Zielentfaltung

Ein Block mit ziel: entfalten wird nicht als Partitur gespielt, sondern als Ziel entfaltet (Protokoll famulus-zielentfaltung): der Evidenzraum wird gefiltert und bewiesen, die Fundlage gelesen, das Ziel normalisiert, dann öffnet ein Planer Teilziele nach Befund, Anfrageform und Budget, und das Urteil ist graduiert. Die Schlüssel des Vorspanns:

Schlüssel Werte Pflicht Standard Wirkung
ziel entfalten ja — wählt die Entfaltung
form erwaehnung, korrespondenz, eponym, thema nein aus der Frage gelesen die Anfrageform: Slots, Teilziele, kritische Fragen (famulus_proof/entfaltung/rules/formen.yaml)
slots {verfasser: …, erwaehnte_person: …, zeitraum: …} nein aus der Frage Werte der Slots vom Eigentümer; mit form braucht der Filter keinen Modellaufruf
bind {slot: ind_id} nein Register Bindung eines Namens an ein Einzelding
lesart {schluessel: Art} nein — die Lesung des Eigentümers für einen Kandidaten (geht Regel, Cache und Modell vor)
verfeinerung {streng: b2}, {offen: b2}, {knoten: …, wert: …} nein — die Antwort auf eine Rückfrage des Filters
budget {zeit_s, modellaufrufe, kandidaten_max} nein 300 s, 200, 1000 was die Entfaltung ausgeben darf; was nicht passt, wird zurückgestellt und zählt als Rest
rest_max Zahl 0–1 nein 0.05 der Anteil offener Kandidaten, den validiert-mit-rest noch trägt
annahmegrad_verfasser schwach, mittel, stark, gewiss nein mittel wie sicher der Verfasser eines Belegs belegt sein muss (Leiter: Register gewiss, Rohangabe stark, Mappe und Randsatz mittel, Regest und Bestand schwach); darunter bleibt der Kandidat im Rest
abgeschaltet Liste von Teilzielen nein leer Teilziele, die dieser Lauf nicht spielt
erwartung Pfad einer YAML-Datei nein — das Gate: Slots, Bedingungen, Kanäle, urteil: {in: […]}, grad_min, rest_max, Recall und Präzision gegen eine Referenzsuche

Das Urteil ist validiert, validiert-mit-rest, Lücke, nicht validiert oder Rückfrage. Das Oracle vergleicht validiert (nur das exakte Urteil), validiert_mit_rest (beide gültigen Urteile), grad, rest_quote, n_rest, n_zurueckgestellt, rueckfrage, n_belege, n_unaccounted, gate_match. Ein Block mit dem Status Rückfrage nennt die Frage des Filters; die Antwort steht im Vorspann (verfeinerung: oder form: mit slots:).

Die Abschnitte des Protokolls (artifact:entfaltung-teil, teil:): ziel, evidenzbasis, trichter, kanaele, entfaltung, planung, ausschluss, urteil, rest.

7 Prüfungen

Ein Block mit pruefen: satz lässt einen Satz eines Aufsatzes vom Lektor prüfen (satz: {paper, hash, text}), ein Block mit pruefen: messwert eine Messaussage gegen einen registrierten Messkörper (aussage: {koerper, objekt, groesse, methode, wert, toleranz}); beide legen ihr Urteil als Bericht famulus-enfolding/1 ab (Sachliche Validität).

8 Artefakte

artefacts ist eine Liste von {name, kind, file}. name ist der Name im Querverweis. file liegt unter artefacts/ der jeweiligen Version (_famulus/store/<notebook>/<id>/vNNNN/). report.json schreibt der Adapter bei jedem Lauf zusätzlich in denselben Versionsordner, auch wenn die Liste es nicht nennt.

kind Builder heute data
report _build_report question, answer, verdict, method, counts, findings, by_document, specification, provenance
roster-table _build_roster_table entries mit name, canonical, variants, kind, count, n_docs, doc_ids
kwic _build_kwic rows mit doc_id, page, text, url
citation-list _build_citation_list rows mit doc_id, collection, n_sentences, excerpts, url
d3-graph _build_d3_graph nodes, edges; Kraftlayout
proof-structure _build_proof_structure nodes, edges, verdict, synthesis
markdown direkt aus der Synthesis content
table adapter-lokal aus duckdb-read Zeilen und Spaltennamen
json adapter-lokal, das Vertragsergebnis unverändert Objekt
figure Datei, die ein Lauf als Abbildung schreibt Pfad der Abbildung
timeline keiner Wahl fällt in artifact.py auf markdown

Ein Befund in report.json trägt kind, collection, doc_id, pidx, sent_idx, page, text, url. page ist pidx + 1. Die Viewer-URL hat die Form <basis>/<collection>/<doc_id>?p=<page>. Ein Absatzindex ist in diesem Schema nicht vorhanden.

artefacts:
  - name: roster
    kind: roster-table
    file: roster.json
  - name: netz
    kind: d3-graph
    file: netz.json

9 Prüfung

golden nennt eine golden_id aus agent_memory.duckdb, Tabelle golden_ground. oracle nennt die erwartete Antwort an Ort und Stelle, in denselben Formen wie expected_answer. Verglichen wird nur mit oracle: golden ist ein Verweis auf die Zeile und lädt deren Erwartung nicht. famulus-notebook goldens überträgt die Erwartung beim Erzeugen in oracle; ein von Hand geschriebener Block trägt sie selbst. Der Vergleich steht in verdict.json der Version.

Form Beispiel Vergleich
Ganze Zahl n_correspondents: 75 Gleichheit
Spanne n_sentences: {min: 15} Wert liegt in der Spanne
Teilzeichenkette subject_contains: saphea Die Antwort enthält die Zeichenkette
Liste terms: [saphea, horologium] Überlappung mit der Ergebnisliste

Schlüssel note und status im gespeicherten Oracle werden beim Vergleich übersprungen, wie in golden.py.

golden: golden-c782fab71c
oracle:
  n_correspondents: 75

verdict.json hat die Schlüssel id, golden, status, oracle, observed. status ist pass, fail, gap oder error. gap gilt, wenn die Golden-Zeile eine anerkannte Fähigkeitslücke ist und der Lauf diese Lücke meldet. Ein stilles leeres Ergebnis ist error.

10 Instruktion

Der Text nach der schließenden --- ist die Handlungsanweisung. Er wird RunRequest.goal. Platzhalter {{ref:<id>.<name>}} ersetzt der Adapter vor dem Aufruf durch den absoluten Pfad der Artefaktdatei. Ein Platzhalter ohne Logeintrag ist ein unaufgelöster Verweis.

11 Fehler

Der Adapter bricht vor dem Conductor ab, schreibt verdict.json mit status: error und kein Artefakt.

Lage Meldung
id fehlt oder ist im Paket doppelt Name der Präambel
subtask und partiturs beide gesetzt oder beide leer die Ausschlussregel
subtask steht nicht in der Registrierung der unbekannte Name
ref oder der Platzhalter {{ref:…}} hat kein Artefakt die unaufgelöste Id und der Name
$PDAI_COLLECTIONS oder eine genannte Datei ist nicht da der Pfad
counting_mode fehlt bei einer Lemma-Zählung der Block-id
Eine erforderliche Partitur-Eingabe bleibt ungebunden der Eingabename

Ein Lauf, der das im Vertrag beschriebene Ergebnis nicht erreicht, beendet die Kette an dieser Stelle. Die Trace bleibt im Log. Ein Artefakt dieses Laufs entsteht nicht.