Jobsuche: Berufsbezeichnungen steuern die Suche, nicht mehr Faehigkeiten

Der Feinschliff schlug per KI Technologien vor ("Proxmox", "Rechenzentrum")
und verbot Rollenbezeichnungen ausdruecklich - die sollte die Suche selbst
aus dem Lebenslauf ableiten. Das war schief: Welche Anzeigen ueberhaupt
gefunden werden, entscheidet die Suchanfrage, also der Stellentitel.
Technologien gewichten nur, was schon da ist. Damit schlug die KI genau das
vor, was der Such-Agent ohnehin selbst ableitet, waehrend die eine Sache,
die der Nutzer weder sieht noch steuern kann - unter welchen Titeln gesucht
wird -, bei jedem Lauf neu improvisiert wurde. Faellt "Fachinformatiker
Systemintegration" weg, merkt das niemand; es kommt nur wenig zurueck.

- Neues Profilfeld berufsbezeichnungen: die KI schlaegt es vor, der Nutzer
  editiert es, der Such-Agent fragt jeden Titel einzeln ab.
- zusatz_begriffe bleibt, aber als Kontext (Branche, Umfeld, Arbeitszeit),
  nicht als Stellentitel; ausschluesse unveraendert.
- Leeres Feld = altes Verhalten (Titel aus dem Lebenslauf), niemandes
  Profil aendert sich durch das Update.
- Spalte wird fuer bestehende Installationen nachgezogen.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 12:27:06 +02:00
co-authored by Claude Opus 4.8
parent 67b8e5735f
commit 090228479a
5 changed files with 86 additions and 25 deletions
+13 -5
View File
@@ -2103,10 +2103,11 @@ async function generateEmailReply({
const FEINSCHLIFF_SCHEMA = {
type: 'object',
properties: {
berufsbezeichnungen: { type: 'array', items: { type: 'string' } },
zusatz_begriffe: { type: 'array', items: { type: 'string' } },
ausschluesse: { type: 'array', items: { type: 'string' } },
},
required: ['zusatz_begriffe', 'ausschluesse'],
required: ['berufsbezeichnungen', 'zusatz_begriffe', 'ausschluesse'],
};
// How many terms per field we keep. The two lists end up verbatim in the search
@@ -2139,10 +2140,16 @@ async function generateFeinschliff({ unterlagen, profil = {}, prompts = null })
`Suchmodus: ${modusText}\n` +
(staedte ? `Städte: ${staedte}\n` : '') +
`\n# Aufgabe\n` +
`Schlage die beiden Leitplanken der Stellensuche vor:\n` +
`- "zusatz_begriffe": Begriffe, die die Suche zusätzlich berücksichtigen soll - Technologien, ` +
`Branchen, Arbeitsumfelder oder Arbeitszeitmodelle, die aus den Unterlagen belegbar sind ` +
`(z. B. "Rechenzentrum", "Systemhaus"). KEINE Rollen-/Stellenbezeichnungen.\n` +
`Schlage die drei Listen der Stellensuche vor:\n` +
`- "berufsbezeichnungen": die Stellentitel, unter denen der Bewerber suchen sollte - das sind die ` +
`Suchanfragen und damit das Wichtigste. Nimm die Titel, unter denen SEINE Tätigkeit real ` +
`ausgeschrieben wird, und decke die üblichen Varianten derselben Rolle ab (z. B. ` +
`"Systemadministrator", "IT-Administrator", "Fachinformatiker Systemintegration"). Bleib bei dem, ` +
`was sein Erfahrungsniveau hergibt - keine Titel, für die er erkennbar zu wenig oder zu viel ` +
`Erfahrung hat, und keine reinen Technologie-Wörter.\n` +
`- "zusatz_begriffe": KEINE Stellentitel, sondern Kontext, der einen Treffer zusätzlich attraktiv ` +
`macht und aus den Unterlagen belegbar ist - Branchen, Arbeitsumfelder, Arbeitszeitmodelle ` +
`(z. B. "Rechenzentrum", "Systemhaus", "Teilzeit").\n` +
`- "ausschluesse": Kriterien, bei denen ein Treffer verworfen werden soll (z. B. Anstellungsformen ` +
`oder Rollen, die erkennbar nicht zum Profil passen).\n` +
`Höchstens ${FEINSCHLIFF_MAX} Einträge je Liste, nach Wichtigkeit sortiert. Jeder Eintrag ist ein ` +
@@ -2170,6 +2177,7 @@ async function generateFeinschliff({ unterlagen, profil = {}, prompts = null })
};
return {
berufsbezeichnungen: liste(['berufsbezeichnungen', 'berufsbezeichnung', 'stellentitel', 'rollen', 'jobtitel', 'titel']),
zusatz_begriffe: liste(['zusatz_begriffe', 'zusatzbegriffe', 'zusatz', 'begriffe', 'einschluesse']),
ausschluesse: liste(['ausschluesse', 'ausschlüsse', 'ausschlusskriterien', 'exclude', 'ausschluss']),
};
+12 -10
View File
@@ -92,20 +92,22 @@ const DEFAULTS = [
key: 'jobsuche_feinschliff',
titel: 'Jobsuche: Feinschliff vorschlagen',
beschreibung:
'Rolle für den KI-Vorschlag der Leitplanken deiner Jobsuche (zusätzlich berücksichtigen / ' +
'Rolle für den KI-Vorschlag deiner Jobsuche (Berufsbezeichnungen / zusätzlich berücksichtigen / ' +
'ausschließen). Grundlage sind deine Basis-Unterlagen oben.',
platzhalter: [],
inhalt:
'Du bist ein erfahrener Recruiter und stellst die Leitplanken für die automatische ' +
'Du bist ein erfahrener Recruiter und stellst die Suchkriterien für die automatische ' +
'Stellensuche eines Bewerbers auf. Du liest seine Basis-Unterlagen (Lebenslauf, Kurzprofil, ' +
'Anschreiben) und leitest daraus ab, welche Zusatzbegriffe eine Stellensuche treffsicherer ' +
'machen und welche Treffer von vornherein verworfen werden sollten. Du erfindest nichts: ' +
'Jeder Zusatzbegriff muss sich aus den Unterlagen belegen lassen (nachgewiesene Technologien, ' +
'Branchen, Umfelder, Arbeitszeitmodelle). Ausschlüsse leitest du aus dem ab, was erkennbar ' +
'nicht zum Bewerber passt - etwa Stellen weit unter oder weit über seinem Erfahrungsniveau, ' +
'fachfremde Rollen oder Anstellungsformen, die er offensichtlich nicht sucht. Keine ' +
'Rollenbezeichnungen als Zusatzbegriffe: die leitet die Suche ohnehin selbst aus dem ' +
'Lebenslauf ab. Antworte auf Deutsch im lateinischen Alphabet.',
'Anschreiben). Das Wichtigste sind die Berufsbezeichnungen: unter welchen Stellentiteln seine ' +
'Tätigkeit real ausgeschrieben wird - denn danach wird gesucht, und was hier fehlt, findet die ' +
'Suche nie. Dieselbe Arbeit läuft je nach Firma unter verschiedenen Titeln; decke diese ' +
'Varianten ab, aber bleib bei dem, was sein Erfahrungsniveau hergibt. Zusatzbegriffe sind ' +
'KEINE Stellentitel, sondern belegbarer Kontext (Technologien, Branchen, Umfelder, ' +
'Arbeitszeitmodelle). Ausschlüsse leitest du aus dem ab, was erkennbar nicht zum Bewerber ' +
'passt - etwa Stellen weit unter oder weit über seinem Erfahrungsniveau, fachfremde Rollen ' +
'oder Anstellungsformen, die er offensichtlich nicht sucht. Du erfindest nichts: Jeder ' +
'Vorschlag muss sich aus den Unterlagen belegen lassen. Antworte auf Deutsch im lateinischen ' +
'Alphabet.',
},
];
+30 -3
View File
@@ -34,6 +34,7 @@ const DEFAULTS = {
aktiv: 0,
modus: 'regional',
staedte: [],
berufsbezeichnungen: '',
zusatz_begriffe: '',
ausschluesse: 'Zeitarbeit / Arbeitnehmerüberlassung, Personalvermittler / Headhunter',
zeitplan_tage: '1,2,3,4,5',
@@ -91,6 +92,7 @@ function fromRow(row) {
aktiv: r.aktiv ? 1 : 0,
modus,
staedte: parseStaedte(r.staedte),
berufsbezeichnungen: r.berufsbezeichnungen || '',
zusatz_begriffe: r.zusatz_begriffe || '',
ausschluesse: r.ausschluesse != null ? r.ausschluesse : DEFAULTS.ausschluesse,
zeitplan_tage: parseTage(r.zeitplan_tage != null ? r.zeitplan_tage : DEFAULTS.zeitplan_tage),
@@ -108,6 +110,7 @@ function fromForm(body, sanitize = (v) => v) {
aktiv: (b.aktiv === '1' || b.aktiv === 'on' || b.aktiv === true) ? 1 : 0,
modus,
staedte: parseStaedte(b.staedte).map((s) => sanitize(s)),
berufsbezeichnungen: sanitize(String(b.berufsbezeichnungen || '').trim()),
zusatz_begriffe: sanitize(String(b.zusatz_begriffe || '').trim()),
ausschluesse: sanitize(String(b.ausschluesse || '').trim()),
zeitplan_tage: parseTage(tage.join(',')),
@@ -121,6 +124,7 @@ function toRow(profil) {
aktiv: profil.aktiv ? 1 : 0,
modus: profil.modus,
staedte: JSON.stringify(profil.staedte || []),
berufsbezeichnungen: profil.berufsbezeichnungen || '',
zusatz_begriffe: profil.zusatz_begriffe || '',
ausschluesse: profil.ausschluesse || '',
zeitplan_tage: (profil.zeitplan_tage || []).join(','),
@@ -203,14 +207,37 @@ function buildPrompt(profil, profilText) {
);
}
// Die Berufsbezeichnungen sind die eigentlichen Suchanfragen — sie entscheiden,
// welche Anzeigen überhaupt gefunden werden. Sind sie gesetzt, sucht der Agent
// danach, statt sich die Titel bei jedem Lauf neu aus dem Lebenslauf zu
// improvisieren (was der Nutzer weder sieht noch steuern kann). Das Profil
// liefert dann nur noch die Technologien zur Gewichtung.
if (profil.berufsbezeichnungen) {
teile.push(
`Suche gezielt nach Stellen mit diesen Berufsbezeichnungen (das sind deine Suchanfragen, jede einzeln ` +
`abfragen): ${profil.berufsbezeichnungen}. Nahe Schreibweisen und gängige Varianten desselben Titels ` +
`(m/w/d, "IT-" davor, Singular/Plural, englische Entsprechung) darfst du ergänzen; auf fachfremde Rollen ` +
`ausweichen darfst du NICHT.`
);
}
if (profilText && profilText.trim()) {
teile.push(
'Leite Rollenbezeichnungen (Query-Varianten) und Technologie-Buzzwords AUS DEM FOLGENDEN PROFIL DES ' +
'BEWERBERS ab — fasse die Rolle breit (dieselbe Tätigkeit läuft je nach Firma unter vielen Titeln) und ' +
'gewichte Treffer höher, je mehr aus dem Profil passt:\n\n--- PROFIL ---\n' +
(profil.berufsbezeichnungen
? 'Technologie-Buzzwords und die Gewichtung der Treffer leitest du AUS DEM FOLGENDEN PROFIL DES ' +
'BEWERBERS ab (die Suchtitel stehen oben und gelten) — gewichte Treffer höher, je mehr aus dem ' +
'Profil passt:'
: 'Leite Rollenbezeichnungen (Query-Varianten) und Technologie-Buzzwords AUS DEM FOLGENDEN PROFIL DES ' +
'BEWERBERS ab — fasse die Rolle breit (dieselbe Tätigkeit läuft je nach Firma unter vielen Titeln) und ' +
'gewichte Treffer höher, je mehr aus dem Profil passt:') +
'\n\n--- PROFIL ---\n' +
profilText.trim().slice(0, 6000) +
'\n--- ENDE PROFIL ---'
);
} else if (profil.berufsbezeichnungen) {
teile.push(
'Es ist kein Lebenslauf/Profil hinterlegt — halte dich strikt an die oben genannten Berufsbezeichnungen.'
);
} else {
teile.push(
'ACHTUNG: Es ist kein Lebenslauf/Profil hinterlegt. Leite Rollen und Suchbegriffe aus den bereits ' +