Moin,
leider war ja das Forum neulich "kaputt", dabei ist auch mein Beitrag zu diesem Thema verloren gegangen. Der bitterböse Merksatz: No backup, no mercy" gilt offenbar auch für das tomedo-Forum😮
Im Forum finden sich verschiedene Wege, wie man Dokumente, die per Scan oder drag & drop in die Kartei gekommen sind, mittels KI auswertet. Wie immer gibt es Vor-/Nachteile für verschiedene Wege. Bis es die große "Alles drin"-Lösung (Dokument in allgemeinen Lauschordner, automatische Patientenzuordnung, Auswertung nach KI-Analyse des Dokumententyps, Aktionsketten im direkten Anschluss...) von zollsoft selbst gibt, kann man sich auch mit den bisherigen Elementen einen schönen Work flow bauen.
Mein Ablauf basiert auf folgenden Anforderungen:
1.) Karteieintragtyp DOK mit Anhang (PDF) soll ausgewertet werden, wobei das KI-Ergebnis zusammen mit dem PDF in einem Karteieintrag bleiben soll.
2.) Karteieintragstyp wird von DOK auf passende, andere Typen (A-BRI für Arztberichte, CT, MRT, NUK, A-BEF für Befunde, PRICK für Prick-Test) und das zum Dokument passenden Datum gesetzt werden (CT vom 10.06.2026 soll dieses Datum bekommen).
3.) KI-Auswertequalität muss nahezu 100% verlässlich sein, d.h. 3x KI-Auswertung desselben Dokuments bringt bis auf minimale Unterschiede dasselbe KI-Ergebnis (hängt naturgemäß von der Fragestellung im Prompt ab, ob dies so möglich ist)
Punkt 1 klappt nur, wenn das Ergebnis per "Zurückschreiben" in das Textfeld des DOK-Eintrags geschrieben wird. Da diese Funktion nur in den Eintrag mit dem höchsten (jüngsten) Datum schreiben kann, kann die Analyse nur diesen Eintrag auswerten.
Punkt 2 erlaubt das einfache Auffinden anhand der Dokumententypen in der Kartei. Bei sehr vielen DOK-Einträgen ist das (aus meiner Sicht) essentiell.
Punkt 3 war leider aktuell bei Nutzung der KI-Prompt-Aufrufe nicht immer gegeben, daher nutze ich die von mir früher schon mal gezeigte Methodik des direkten LLM-Aufrufs per AppleScript. Die Qualität der KI-Resultate ist (zumindest derzeit) dadurch massiv besser als per AK-KI-Prompt. Zudem kann (bei geeigneter Hardware) auch ein lokales Modell aufgerufen werden.
Ablauf:
Scan wird als DOK in Kartei abgelegt, OCR-Text erscheint im Textfeld, PDF liegt im selben Karteieintrag als PDF
Aktionskette wird gestartet. Diese ersetzt zunächst für die Verarbeitung in AppleScript potentiell störende Zeichen wie " oder \ aus dem Text. Der gewünschte Prompt wird als Textbaustein vor den auszuwertenden Text in den Karteieintrag geschrieben (Nebenaspekt: Anwender hat dadurch die visuelle Rückmeldung, es tut sich da gerade was...)
AppleScipt wird aufgerufen, welches nur den letzten, nun wie gerade beschrieben veränderten DOK-Eintrag an das im Script definierte LLM (derzeit: Zollsofts gemini-Modell) sendet. Das Ergebnis wird dann in der Zwischenablage abgespeichert, um es so wieder zurück in tomedo zu bekommen.
Jetzt könnten per AK-Bedingungen, beliebige weitere Aktionen gestartet werden. Im gezeigten Beispiel wird ein weiterer Karteieintrag CPAP angelegt, der die zuvor im KI-Resultat aufgeführten CPAP-Parameter übernimmt.
Zum Schluss (leider noch manuell...) muss der Anwender den Karteityp auf den geeigneten Karteityp umstellen und - falls auch gewünscht - das Karteieintragsdatum anpassen. Die nötige Information wird dazu angezeigt.

------------------------------------------------------------
-- Befüllen der Variable prompt, die den Prompt sowie den per KI zu analysierenden Text enthalten soll
-- hier wird der Text aus dem letzten Karteieintrag vom Typ DOK benutzt
set the prompt to "$[x DOK 1 _ _ NJ NJ2N NNNN _ K _]$"
------------------------------------------------------------
-- Angabe der URL-Adresse des tomedo-Servers und des Nutzer-Idents
set tomedo_server_url to "http://tomedo.localnet:8080/tomedo_live/"
set user_ident to "2"
-- Zusammensetzen des vollständiger Endpoints für die Ansprache des LLM:
set llm_endpoint to tomedo_server_url & "llmservice/" & user_ident & "/v1/chat/completions"
------------------------------------------------------------
-- Auswahl des für die KI-Analyse zu verwendenden LLM:
-- Hier muss das gewünschte Standardmodell gesetzt werden, z.B. "gemini-2.5-pro" oder "mistral-medium-2508" oder oder
set selectedModel to "gemini-2.5-pro"
--set selectedModel to "gemini-3.5-flash"
------------------------------------------------------------
-- Aufruf des tomedo-LLM-Services
-- Erstellung des Python-Programms (verwendet nur Python-Standardbibliotheken), welches in der Variable pycode abgelegt wird
set pyCode to "
import os, sys, json, urllib.request, urllib.error
TOMEDO_URL = os.environ.get('LLM_ENDPOINT')
MODEL = os.environ.get('USER_MODEL', 'gemini-2.5-flash')
prompt = os.environ.get('USER_PROMPT', '')
payload = {
'model': MODEL,
'messages': [{'role': 'user', 'content': prompt}],
'stream': False
}
req = urllib.request.Request(
TOMEDO_URL,
data=json.dumps(payload).encode('utf-8'),
headers={'Content-Type': 'application/json'},
method='POST'
)
try:
with urllib.request.urlopen(req, timeout=120) as resp:
data = json.loads(resp.read().decode('utf-8'))
# OpenAI-kompatibles Format: choices[0].message.content
content = ''
try:
choices = data.get('choices') or []
if choices:
msg = choices[0].get('message', {}) or {}
content = (msg.get('content') or '').strip()
except Exception:
pass
# Fallback: Ollama-ähnliches Format data['message']['content']
if not content:
content = (data.get('message', {}) or {}).get('content', '').strip()
# Letzter Fallback: direktes 'content'-Feld
if not content:
content = (data.get('content') or '').strip()
sys.stdout.write(content)
except urllib.error.HTTPError as e:
msg = e.read().decode('utf-8', errors='ignore')
sys.stderr.write(f'HTTPError {e.code}: {msg}\\n')
sys.exit(1)
except Exception as e:
sys.stderr.write(f'ERROR: {e}\\n')
sys.exit(1)
"
------------------------------------------------------------
-- Das Python-Programm wird nun mit dem Prompt, dem ausgewählten LLM-Modell und dem tomedo-LLM-Endpoint zusammengeführt
-- Übergabe an den Python-Prozess via Env-Variablen
set shellCmd to "/usr/bin/env /bin/zsh -lc " & quoted form of ¬
("export USER_PROMPT=" & quoted form of prompt & "; " & ¬
"export USER_MODEL=" & quoted form of selectedModel & "; " & ¬
"export LLM_ENDPOINT=" & quoted form of llm_endpoint & "; " & ¬
"python3 - <<'PY'
" & pyCode & "
PY")
try
set resultText to do shell script shellCmd
on error errmsg number errNum
display dialog ("Fehler beim API-Aufruf:
" & errmsg) buttons {"OK"} with icon stop
return
end try
set the clipboard to resultText
--tell application "Finder" to open location "tomedo://aktionskette?10-1-DOK-KI-Resultat-aus-Zwischenablage->X-KI"
-- ggf. hier direkt aus dem Script heraus Aufruf von Aktionsketten möglich
Hier der Prompt (Textbaustein)
Fasse den folgenden Arztbericht zusammen. Die erste Zeile soll wie folgt formuliert werden: Arztbericht (kurz gefasster Name der Klinik oder Praxis oder Einrichtung, kurze Bezeichnung der Fachdisziplin, Ort, keine Adresse), Aufenthalt von XXX - XXX bzw. am XXXX. Bilde dann Rubriken und beginne jede Rubrik in einer neuen Zeile mit dem Rubriknamen. Nach jeder Rubrik eine Leerzeile. Bilde folgende Rubriken: Diagnosen (jede Diagnose in einer neuen Zeile), Aufnahmeanlass, Diagnostik (kurzgefasst), Therapie, Empfehlung, auffällige Laborwerte (wenn keine Laborwerte genannt wurden, lasse schreibe den Begriff —auffällige Laborwerte— nicht. Wenn eine Schlafapnoe oder OSAS als Diagnose genannt wird, soll in der Diagnostik auch der AHI bzw. Apopne-Hypopnoe-Index (in der Einheit —Anzahl/h—) sowie auch der ESS als —X/24 Punkten— genannt werden. Wenn Beatmungsparameter genannt werden, schreibe diese komplett und unverändert nach dem Begriff —Beatmungsparameter— Benutze keine Formatierungszeichen.
_____________________________________________
Wenn der Arztbericht Informationen über eine OSAS-Therapie (CPAP, BIPAP oder ähnliches) enthält, liste diese passend zu den genannten Bezeichnungen in diesem Format auf, schreibe für jede Bezeichnung eine neue Zeile:
§§CPAP§§Karteidatum§§Bezeichnung§§Ergebnis§§
Achte auch auf die beiden §§ am Ende der Zeile
Nenne bei den Druckwerten nur die Zahl, nicht die Einheit (wie mbar, cm H2O). Schreibe nichts, wenn kein Wert/Inhalt angegeben ist.
Modus (z.B. CPAP, BIPAP-S, BIPAP-ST, ASV)
CPAP-Druck
CPAP-Flex-Stufe (z.B. Softflex, EPR)
APAP-min-Druck (minimaler APAP-Druck)
APAP-max-Druck (maximaler APAP-Druck)
BIPAP-S-IPAP (oberer BIPAP-S-Druck)
BIPAP-S-EPAP (unterer BIPAP-S-Druck)
BIPAP-S-Parameter (weitere Parameter der BIPAP-S-Therapie wie Anstiegszeit, Trigger)
BIPAP-ST-IPAP (oberer BIPAP-ST-Druck)
BIPAP-ST-EPAP (unterer BIPAP-ST-Druck)
BIPAP-ST-Parameter (weitere Parameter der BIPAP-ST-Therapie wie Anstiegszeit, Trigger)
Gerätetyp (z.B. ResMed AirSense S11)
Befeuchtung (ja/nein)
Maskentyp (z.B. Cara nasal)
Maskengröße (z.B. S; M/S; M; M/L; L; XL)
Versorger (z.B. critical care, Löwenstein, ResMed)
Schlaflabor (z.B. Schlaflabor Bremen; Schlaflabor Delmenhorst; Schlaflabor St. Josef-Stift)
TherapieSeit (z.B. 01.01.2025; beschreibt den Beginn der Therapie; wenn nur das Jahr, z.B. 2025, genannt wird, schreibe 01.01.2025; wenn nur der Monat genannt wird, z.B. 04/2025, schreibe 01.04.2025)
Bemerkungen (nenne hier Besonderheiten zur Therapie, z.B. Abbruch bei Intoleranz 2023)
VorherigeTherapie (nenne hier Therapien vor der aktuellen, z.B. CPAP, Unterkieferprotrusionsschiene, Lagetherapie, HNO-OP)
______________________________________________
Wenn der Arztbericht eine Behandlung / Beurteilung beschreibt, bei der es primär um eine Tumorerkrankung geht, füge folgende Informationen im Format §§Bezeichnung§§Ergebnis§§ ein (wenn es keine Information zu einzelnen Bezeichnungen gibt, füge nichts ein):
Tumorformel (TNM)
Metastasen
Histologie
Zytologie
Erstdiagnose
Operative Therapie
Radiatio
Medikamentöse-Tumortherapie
Nenne bei Erstdiagnose bzw. den Therapien (OP, Radiatio, Medikamentös) jeweils das Behandlungsdatum, bzw. den Behandlungszeitraum. Gebe die Daten im Format TT.MM.JJJJ an.
Stelle keine Fragen und mache keine eigenen Vorschläge für das weitere Vorgehen. Wenn keine Informationen im Text enthalten sind, die einem Arztbericht entsprechen, gebe die Information: Der auszuzwertende Text erscheint kein Arztbericht zu sein. Erzeuge keine Informationen, die nicht im zu analysierenden Text enthalten sind.
Schreibe ganz am Ende diesen Text: §§Prompt_Arztbericht§§Karteidatum§§ Dabei soll natürlich der Begriff Karteidatum durch das oben beschriebene Datum ersetzt werden.