Bei der Auswahl eines Modells nach dem Claude-Code sollten Sie „Haiku“ für kleine, überprüfbare Änderungen, „Sonnet“ für die routinemäßige Umsetzung und „Opus“ für Aufgaben mit höherer Mehrdeutigkeit oder höheren Anforderungen an die Argumentation verwenden. Anthropic empfiehlt derzeit Opus 5.5 als allgemeinen Ausgangspunkt; Ihre Aufgabenstellung, Ihr Prüfungsaufwand und Ihr Budget entscheiden darüber, ob ein kleineres Modell besser geeignet ist.
Um das Modell zu wechseln, öffnen Sie /Modell. Presse Eingabe um eine Standardeinstellung zu speichern, oder s um nur die aktuelle Sitzung umzuschalten. Für einen einmaligen Start verwenden Sie claude --Modell: Opus. Da diese Optionen eine unterschiedliche Dauer haben, ist die Entscheidung, wie lange die Umstellung andauern soll, ebenso wichtig wie die Wahl des Modells.
Zur Programmierarbeit gehören auch Recherche, Erläuterungen, Dokumentation und kreative Inhalte. GlobalGPT vereint führende KI-Modelle und zahlreiche KI-Tools in einem kostengünstigen Dashboard, während seine Befehlszeilenschnittstelle (CLI) diese Tools mit Terminal- und Entwicklungsabläufen verbindet. Gestalten Sie Ihren Arbeitsablauf mit GlobalGPT um diese miteinander verbundenen Aufgaben zusammenzuhalten, während Sie von der Idee zum lauffähigen Code gelangen.

Welches Modell sollten Sie im Claude-Code verwenden?
Beginnen Sie mit der Struktur der Arbeit. Eine kurze Funktion mit klar definierten erwarteten Ergebnissen erfordert eine andere Bewertung als ein sporadisch auftretender Fehler, der sich über mehrere Dienste erstreckt. Die entscheidende Frage lautet, ob das Modell mit angemessenem Überprüfungsaufwand und durch Iterationen eine akzeptable Änderung hervorbringen kann.
| Aktuelles Modell | Wofür es vorgesehen ist | Eine praktische Einstiegsaufgabe |
|---|---|---|
| Claude Haiku 4.5 | Schnelles, effizientes Arbeiten mit einem eng gefassten Auftragsumfang | Eine kleine Umstrukturierung, eine sich wiederholende Transformation oder ein einfacher Testfall |
| Claude Sonett 5 | Eine ausgewogene Mischung aus Intelligenz und Geschwindigkeit für das tägliche Programmieren | Eine Funktion mit etablierten Mustern, eine routinemäßige Fehlerbehebung oder eine Erläuterung des Codes |
| Claude Opus 5,5 | Komplexe Schlussfolgerungen und umfangreichere Arbeiten zur agentischen Kodierung | Ein mehrdeutiger Fehler, ein architektonischer Kompromiss oder eine Änderung mit sich gegenseitig beeinflussenden Einschränkungen |
| Claude Fable 5.1 | Die schwierigsten und am längsten andauernden Ermittlungen | Eine Eskalation, bei der schwierige Arbeit immer noch ein höheres Opus-Einsatzniveau übertrumpft |
Haiku ist eine Überlegung wert, wenn Fehler leicht zu erkennen sind und die Änderungen gering sind. Sonnet ist eine sinnvolle Wahl, wenn die alltägliche Umsetzung mehr Kontext und Urteilsvermögen erfordert. Opus sollte in Betracht gezogen werden, wenn das Verständnis des Problems einen wesentlichen Teil der Aufgabe ausmacht. Fable verdient eine gesonderte Entscheidung bei anspruchsvollen Aufgaben; es war nicht Teil unseres Codierungstests mit den drei Modellen.
Dies sind Ausgangspunkte, keine automatischen Qualitätsgarantien. Eine kostengünstigere Lösung kann teuer werden, wenn sie mehrere Überarbeitungen oder eine umfassende Überprüfung erfordert. Umgekehrt kann ein größeres Modell bei einer einfachen Transformation, die Ihre Prüfungen bereits besteht, nur wenig zusätzlichen Nutzen bieten. Für eine breitere Anwendung über den Claude-Code hinaus, Vergleichen Sie die Claude-Modellreihen.

Die Offizielle Modellübersicht Listet Kontextfenster mit einer Größe von 1 Mio. Token für Fable 5.1, Opus 5.5 und Sonnet 5 sowie 200.000 Token für Haiku 4.5 auf. Hierbei handelt es sich um API-Spezifikationen. Ihr Claude-Code-Anbieter, Ihr Konto und Ihre Konfiguration bestimmen, welche Kontextoptionen in einer Sitzung verfügbar sind. Ein großes Fenster ist für den erforderlichen Kontext nützlich; wenn Sie es jedoch mit irrelevanten Inhalten füllen, bedeutet dies dennoch zusätzliche Arbeit für das Modell.
So wechselt man innerhalb einer Sitzung das Modell
Führen Sie innerhalb einer interaktiven Sitzung Folgendes aus: /Modell um die Modellauswahl zu öffnen. Markieren Sie die Modellzeile und drücken Sie s falls es sich um eine einmalige Änderung handelt. Durch Drücken von Eingabe speichert die Auswahl als Ihre Benutzervorauswahl. Durch Eingabe von /Modellsonett In aktuellen Versionen wird es dadurch auch direkt gespeichert.
Wählen Sie den Befehl entsprechend der gewünschten Dauer der Änderung aus
| Dein Ziel | Was tun? | Wurden die Standardänderungen gespeichert? |
|---|---|---|
| Nur diese interaktive Sitzung wechseln | Öffnen Sie /Modell, wählen Sie ein Modell aus, drücken Sie s. | Nein. |
| Ein bevorzugtes Modell speichern | Öffnen Sie /Modell und drücken Sie Eingabe, oder geben Sie Folgendes ein: /Modellsonett. | Ja, wenn die Benutzereinstellungen beschreibbar sind. |
| Eine einzelne Sitzung auf Opus starten | Start claude --Modell: Opus. | Nein. |
| Zurück zur Standard-Laufzeit des Kontos | Verwenden Sie /Standardmodell. | Löscht die Modellüberschreibung; der ermittelte Standardwert kann von den Konto- und Organisationseinstellungen abhängen. |
| Aktives Modell überprüfen | Ausführen /status. | Nein. |
Projekteinstellungen oder verwaltete Einstellungen, Umgebungsüberschreibungen und fortgesetzte Sitzungen können den nächsten Start beeinflussen. Überprüfen Sie das aktive Modell, wenn es auf Reproduzierbarkeit ankommt.
Wählen Sie in einer neuen Terminalsitzung das Modell beim Start aus. Diese Befehle gelten auch, wenn Claude Code im integrierten Terminal von VS Code ausgeführt wird. In den Beispielen wird eine Version explizit ausgewählt:
claude --model claude-opus-5-5
claude --model claude-sonnet-5Führen Sie den Befehl für die gewünschte Sitzung aus; die Beispiele stellen Alternativen dar. Sie können verschiedene Terminals mit unterschiedlichen -Modell Werte, ohne einen gemeinsam genutzten, gespeicherten Standardwert immer wieder ändern zu müssen. Verwenden Sie /status um das aktive Modell zu überprüfen.
Nachnamen wie Opus und Sonett können auf neuere Versionen umgestellt werden. Ihre Auflösung hängt zudem vom Anbieter ab: Die Anthropic-API ordnet sie derzeit Opus 5.5 und Sonnet 5 zu, während die Zuordnungen der Cloud-Anbieter davon abweichen können. Verwenden Sie eine vollständige Modell-ID, wenn Sie einen reproduzierbaren Lauf benötigen, und überprüfen Sie den anbieterspezifischen Namen, falls Ihre Umgebung dies erfordert.
Für Opus 5.5 ist Claude Code v2.1.280 oder höher erforderlich; für Sonnet 5 ist v2.1.197 oder höher erforderlich. Das Dokumentation zur Modellkonfiguration ist die Referenz für aktuelle Aliase, Versionsanforderungen und Anbieterzuordnungen. Die hier aufgeführten Befehle sind Beispiele aus der Dokumentation; in unserem praktischen Abschnitt wird der generierte Code separat ausgewertet.

So legen Sie ein Standardmodell fest
Um eine persönliche Standardeinstellung festzulegen, wählen Sie ein Modell aus /Modell und drücken Sie Eingabe, oder geben Sie eine Auswahl ein, zum Beispiel /Modellsonett. Der Code „Claude“ schreibt die Modell Feld in Ihren Benutzereinstellungen, wenn diese Datei beschreibbar ist. Öffnen Sie eine neue Sitzung und überprüfen Sie deren aktives Modell, um das Ergebnis zu bestätigen.
Eine gespeicherte Voreinstellung hat nicht Vorrang vor allen anderen Einstellungen. Ein Startparameter, ANTHROPIC_MODEL In der Shell, in den Projekteinstellungen, in den verwalteten Einstellungen oder in einer Organisationsvoreinstellung, die so konfiguriert ist, dass sie die Auswahl des Benutzers überschreibt, kann beim Start eine andere Option ausgewählt werden. Eine wieder aufgenommene Sitzung behält möglicherweise auch das Modell aus dem gespeicherten Protokoll bei. Überprüfen Sie die Startinformationen und /status bevor man davon ausging, dass die Wahl verloren war.
/Standardmodell löscht Ihre Modellüberschreibung und kehrt zu den Laufzeitt standardeinstellungen für Ihr Konto und Ihre Konfiguration zurück. Das Wort Standard ist ein Rücksetzwert und nicht der Name eines festen Claude-Modells. Er sollte nicht als reproduzierbare Modellkennung verwendet werden.
Für erweiterte Konfigurationen, ANTHROPIC_DEFAULT_MODEL bietet ab Version 2.1.236 eine Standardauswahl als Ausweichmöglichkeit. Diese befindet sich unterhalb der expliziten Auswahlmöglichkeiten für „Start“, „Umgebung“, „Einstellungen“ und „Organisation“ und ignoriert Werte wie beispielsweise Haiku und opusplan. Bei einer normalen persönlichen Präferenz lässt sich die Auswahl leichter überprüfen. Siehe Claude Code-Einstellungen wenn es sich um eine gemeinsam genutzte Konfiguration handelt.
Was Opusplan eigentlich macht
opusplan Im Planungsmodus wird Opus verwendet, während Sonnet für die Ausführung zum Einsatz kommt. Der Vorteil liegt auf der Hand: Zunächst wird ein leistungsfähigeres Modell zur Argumentation verwendet, um den Lösungsansatz zu erarbeiten, anschließend ein alltägliches Programmiermodell, um diesen Plan umzusetzen.
Opusplan folgt der Arbeitsweise
Dokumentiertes Routing-Verhalten. Die hinter diesen Familiennamen stehenden Versionen hängen von Ihrem Anbieter und Ihrer Konfiguration ab.
Dies ist eine modusabhängige Regel. Es werden nicht alle Eingabeaufforderungen geprüft und automatisch die kostengünstigste geeignete Familie ausgewählt. Anbieterzuordnungen und Zugriffsbeschränkungen gelten weiterhin für die zugrunde liegenden Modelle. Auch der Name garantiert keine Einsparungen: Die Gesamtkosten hängen davon ab, wie viel Planung, Implementierung, Überarbeitung und Kontextverarbeitung die Aufgabe erfordert.
Stellen Sie sich zur Abwechslung einmal vor, dass das Design von einer gründlicheren Analyse profitiert und die Umsetzung einem klaren Plan folgt. Bei einer kleinen Korrektur ist diese zusätzliche Planung möglicherweise überflüssig.
Was zwei Programmieraufgaben gezeigt haben
Um ein konkretes Beispiel für die Modellauswahl zu liefern, haben wir eine kleine Unicode-Umstrukturierung und eine Korrektur des Routenauswahlsystems mit sich gegenseitig beeinflussenden Anforderungen getestet. Dabei stellte sich heraus, dass der Unterschied zwischen einer korrekten Funktion und einer vollständigen, geforderten Umsetzung eine größere Rolle spielte als eine einfache Punktzahl.
Wie wir die Programmierergebnisse getestet haben
Am 28. September 2026 haben wir den Modellen Claude Haiku 4.5, Claude Sonnet 5 und Claude Opus 5.5 über GlobalGPT hinweg dieselben zwei JavaScript-Aufgaben gestellt. Jedes Modell lieferte Quellcode zurück; wir haben den Code überprüft und festgelegte lokale Prüfungen durchgeführt. Die Anweisungen zum Modellwechsel bei Claude an anderer Stelle in diesem Leitfaden stammen aus der offiziellen Dokumentation des Modells.
Jede Anfrage unterlag einer Ausgabebegrenzung von 4.096 Tokens, es standen keine Tools und kein Konversationsverlauf zur Verfügung, und es wurden die Standard-Modelleinstellungen verwendet. Wir haben die erste auswertbare Antwort beibehalten, einschließlich unvollständiger Antworten. Bei einem Dienstfehler im Rahmen der Routing-Aufgabe von Sonnet war ein Wiederholungsversuch zulässig: Sieben Anfragen führten zu sechs Ausgaben.
Diese beiden kleinen Aufgaben dienen der Messung des Rückgabecodes und der Vollständigkeit der Bereitstellung. Sie erfassen weder die Ausführung von Claude Code durch den Agenten noch die Erkundung des Repositorys noch eine gesamte Entwicklungssitzung. Die tatsächlichen Kosten in Dollar wurden nicht angegeben. Eine einzelne Beobachtung pro Aufgabe reicht nicht aus, um eine allgemeine Rangliste hinsichtlich Geschwindigkeit oder Zuverlässigkeit zu erstellen.
Genaue Modell-IDs und Testbedingungen anzeigen
Angeforderte IDs: claude-haiku-4-5-20251001, claude-sonnet-5, und claude-opus-5-5. Die lokalen Tests wurden mit Node.js v24.19.0 durchgeführt. Die Eingabeaufforderungen sind für Node.js 18 und höher vorgesehen; Node.js 18 selbst wurde nicht getestet.
Für die „Slug“-Aufgabe wurden acht Verhaltensgruppen festgelegt, für den „Route Selector“ zwölf. Die Einhaltung des Formats und die vollständige Übergabe werden separat ausgewiesen. Eine spätere Überprüfung im Rahmen der Code-Review wird separat ausgewiesen und hat keinen Einfluss auf diese Zahlen. Wir haben den zurückgesendeten Quellcode nicht bearbeitet, um ihn konform zu machen.
Aufgabe 1: Unicode bei einer kleinen Refaktorisierung des „Slugs“ beibehalten
Die Funktion musste nicht-lateinische Zeichen und Kombinationszeichen beibehalten, zerlegte Akzente normalisieren und das bestehende ASCII-Verhalten beibehalten.
| Modell | Verhaltensüberprüfungen | Antwortformat | Die angeforderte Lieferung abschließen |
|---|---|---|---|
| Claude Haiku 4.5 | 8/8 | Fehler: Markdown-Wrapper | Ja: vollständige Funktion |
| Claude Sonett 5 | 8/8 | Pass: JSON im Rohformat | Ja: vollständige Funktion |
| Claude Opus 5,5 | 8/8 | Pass: JSON im Rohformat | Ja: vollständige Funktion |
Beobachtetes Ergebnis: Alle drei Funktionen haben dieselben acht Gruppen verarbeitet. Sonnet und Opus haben zudem die Anforderung bezüglich der Raw-JSON-Antwort erfüllt. Haiku hat seine Antwort in Markdown verpackt, und in seiner Überprüfungsnotiz wurde NFC fälschlicherweise als „Zerlegung von Zeichen“ beschrieben; der Code hat NFC jedoch korrekt aufgerufen.
Bei dieser gezielten Umgestaltung führte das Upgrade nicht zu einer Verbesserung des Verhaltens der getesteten Funktion. Die Formatvorgaben und die Genauigkeit der dazugehörigen Erläuterung mussten noch überprüft werden.
Den vollständigen gemeinsamen Prompt und den Eingabecode anzeigen
SYSTEM
You are completing a bounded JavaScript coding task. Return only the requested JSON object with complete source files and brief review notes. Do not claim to have edited files, run commands, or used tools. You have no tool access. Do not include hidden reasoning.
USER
Implement the following Node.js 18+ CommonJS function from its current source. Return complete replacement source for src/slugify.js. Do not add dependencies, imports, I/O, or other files.
Required behavior:
1. slugify(value) returns an empty string for every non-string input.
2. Normalize string input to Unicode NFC, then lowercase it using JavaScript toLowerCase().
3. Preserve Unicode letters, numbers, and combining marks. Replace each consecutive run of all other characters with one ASCII hyphen.
4. Trim leading and trailing hyphens. Preserve the CommonJS export { slugify }.
5. Existing ASCII behavior must continue to work. Examples: Hello, World! -> hello-world; two words -> two-words; null -> empty string.
6. Additional examples: Café déjà vu -> café-déjà-vu; decomposed Cafe\u0301 -> café; 中文 测试 42 -> 中文-测试-42; **hi___there** -> hi-there; only punctuation or whitespace -> empty string.
Current src/slugify.js:
```javascript
function slugify(value) {
if (typeof value !== "string") return "";
return value
.trim()
.toLowerCase()
.replace(/[^a-z0-9]+/g, "-")
.replace(/^-+|-+$/g, "");
}
module.exports = { slugify };
```
Return exactly one JSON object with this shape:
{"files":{"src/slugify.js":"complete JavaScript source as a JSON string"},"review_notes":["at most four brief implementation or assumption notes"]}
No Markdown wrapper. You are returning code for someone else to evaluate locally; do not say that tests passed or that you ran them.
Die vollständige Antwort von Claude Haiku 4.5 in der übermittelten Form anzeigen
```json
{
"files": {
"src/slugify.js": "function slugify(value) {\n if (typeof value !== \"string\") return \"\";\n \n // Normalize to NFC and lowercase\n const normalized = value.normalize(\"NFC\").toLowerCase();\n \n // Replace consecutive runs of non-letter, non-number, non-combining-mark characters with a single hyphen\n // Unicode letter categories: L* (Lu, Ll, Lt, Lm, Lo)\n // Unicode number categories: N* (Nd, Nl, No)\n // Unicode combining mark categories: M* (Mn, Mc, Me)\n const slugged = normalized.replace(/[^\\p{L}\\p{N}\\p{M}]+/gu, \"-\");\n \n // Trim leading and trailing hyphens\n return slugged.replace(/^-+|-+$/g, \"\");\n}\n\nmodule.exports = { slugify };"
},
"review_notes": [
"Uses String.prototype.normalize(\"NFC\") to decompose composed characters like é into base+combining mark, then toLowerCase() applies to normalized string",
"Unicode property escapes (\\p{L}, \\p{N}, \\p{M}) with /u flag preserve all Unicode letters, numbers, and combining marks while replacing other consecutive characters with single hyphens",
"Existing ASCII behavior is preserved: punctuation and whitespace are replaced with hyphens, then leading/trailing hyphens are trimmed",
"Non-string inputs return empty string as required; normalized decomposed characters (e.g., Cafe\\u0301) are handled correctly by NFC normalization"
]
}
```Die vollständige Antwort von Claude Sonnet 5 in der übermittelten Form anzeigen
{"files":{"src/slugify.js":"function slugify(value) {\n if (typeof value !== \"string\") return \"\";\n return value\n .normalize(\"NFC\")\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}\\p{M}]+/gu, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nmodule.exports = { slugify };\n"},"review_notes":["Used Unicode property escapes (\\p{L}, \\p{N}, \\p{M}) with the u flag to preserve letters, numbers, and combining marks across scripts.","NFC normalization ensures decomposed sequences like Cafe + combining acute compose to café before lowercasing.","Runs of any other characters (punctuation, whitespace, symbols) collapse to a single hyphen, then leading/trailing hyphens are trimmed."]}Die vollständige Antwort von Claude Opus 5.5 in der übermittelten Form anzeigen
{"files":{"src/slugify.js":"function slugify(value) {\n if (typeof value !== \"string\") return \"\";\n return value\n .normalize(\"NFC\")\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}\\p{M}]+/gu, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nmodule.exports = { slugify };\n"},"review_notes":["The input is normalized to NFC before lowercasing, so decomposed input like Cafe\\u0301 composes to café.","A Unicode property regex with the u flag keeps letters (\\p{L}), numbers (\\p{N}) and combining marks (\\p{M}). Each run of any other characters, including underscores and whitespace, becomes one hyphen.","The explicit trim() was removed because the final step strips leading and trailing hyphens, which covers surrounding whitespace.","Lowercasing happens after NFC normalization, as the spec orders. toLowerCase can occasionally produce non-NFC output for rare characters, and it is not re-normalized here."]}Aufgabe 2: Einen Routenwähler reparieren und dessen Tests zurückgeben
Die Funktion musste Übereinstimmungen mit dem längsten Präfix, die Priorität von Methoden, Segmentgrenzen, fehlerhafte Regeln und unveränderliche Eingaben berücksichtigen. Die angeforderte Antwort enthielt außerdem eine neue Testdatei.
| Modell | Verhaltensüberprüfungen | Antwortformat | Die angeforderte Lieferung abschließen |
|---|---|---|---|
| Claude Haiku 4.5 | 12/12 nur bei der vollständigen Funktion | Fehler: abgeschnittenes JSON | Nr.: Testdatei abgeschnitten |
| Claude Sonett 5 | 12/12 nur bei der vollständigen Funktion | Fehler: abgeschnittenes JSON | Nr.: Testdatei abgeschnitten |
| Claude Opus 5,5 | 12/12 nur bei der vollständigen Funktion | Fehler: abgeschnittenes JSON | Nr.: Testdatei abgeschnitten |
Beobachtetes Ergebnis: Kein Modell hat die angeforderte Antwort mit zwei Dateien innerhalb des vorgegebenen Ausgabelimits fertiggestellt. Alle drei hörten bei 4.096 gemeldeten Abschluss-Tokens auf. Jedes hatte bereits eine vollständige Router-Funktion zurückgegeben, die die zwölf festgelegten Verhaltensgruppen bestanden hatte; die neuen Testdateien waren unvollständig und wurden nicht ausgeführt.
Wir haben ausschließlich die vollständig geschlossenen Quellcode-Strings extrahiert. Die ursprünglichen, abgeschnittenen Antworten sind im Folgenden unverändert wiedergegeben. Eine bestandene Funktionsbewertung bedeutet daher nicht, dass die gesamte Anfrage erfolgreich war.
Weitere Feststellung bei der Code-Review: Gleichstand aufgrund gleicher Wurzelwerte
Nach den festgelegten Überprüfungen stellten wir fest, dass Haiku normalisiert wurde /// zu einer leeren Zeichenkette statt /. Bei einer separaten lokalen Überprüfung wurden zwei GET-Regeln mit den Präfixen /// und /, mit dem Ziel erste und zweite in dieser Reihenfolge. Für /irgendetwas, der Vertrag sieht vor, dass erste.
Haiku ist zurück zweite; Sonnet und Opus sind zurückgekehrt erste. Diese zusätzliche Prüfung ergab sich aus der Code-Review und ist unabhängig von den zwölf Prüfungen, die vor dem Test festgelegt wurden. Sie hat keinen Einfluss auf deren Bewertungen.
Sonnet stieß auf einen Dienstfehler, bevor der zulässige Wiederholungsversuch die angezeigte, verkürzte Antwort lieferte. Dieser Dienstfehler steht in keinem Zusammenhang mit der Codequalität. Kein Modell erhielt eine weitere Gelegenheit, seine Antwort zu verbessern oder zu vervollständigen.
Den vollständigen gemeinsamen Prompt und den Eingabecode anzeigen
SYSTEM
You are completing a bounded JavaScript coding task. Return only the requested JSON object with complete source files and brief review notes. Do not claim to have edited files, run commands, or used tools. You have no tool access. Do not include hidden reasoning.
USER
Repair a Node.js 18+ CommonJS route selector. Return complete replacement src/router.js and an additional test/router-added.test.js using node:test and node:assert/strict. Do not add dependencies or edit existing tests. Do not use I/O other than the test runner, network, child processes, timers, or any files beyond the two requested outputs.
Contract for chooseRoute(request, rules):
1. Invalid request or rules returns null, without throwing. Request must be a non-null, non-array object; method must be a nonempty ASCII-letter string; path must be a string beginning with /. Rules must be an array.
2. Before matching, remove the request path's query and fragment starting at the earliest ? or #. Do not URL-decode or collapse interior slashes.
3. Ignore invalid rules. A valid rule is a non-null, non-array object with method '*' or a nonempty ASCII-letter string, prefix a string starting with / containing neither ? nor #, and target a nonempty string.
4. Compare methods case-insensitively. Prefer any matching exact-method rule over all wildcard-method '*' rules, even if a wildcard has a longer prefix. Use wildcard rules only if no exact-method route matches the path.
5. Remove trailing slashes from a rule prefix, except that an all-slash prefix normalizes to /. A prefix matches the path only at a segment boundary: /api matches /api and /api/users, never /apix. Root / matches every valid request path.
6. Within the chosen method group, choose the longest normalized matching prefix. On equal prefix length, choose the earlier rule in the original input array. Return its target. Return null if none matches.
7. Do not mutate the request, rules array, or rule objects, including order or prefix strings. Preserve module.exports = { chooseRoute }.
8. Add tests for segment boundaries, query/fragment removal, method precedence, ties, malformed inputs and immutability. Existing simple GET /api/users and POST-no-match cases must still pass.
Current src/router.js:
```javascript
function chooseRoute(request, rules) {
if (!request || !Array.isArray(rules)) return null;
for (const rule of rules) {
if (request.method === rule.method && request.path.startsWith(rule.prefix)) {
return rule.target;
}
}
return null;
}
module.exports = { chooseRoute };
```
Existing regression cases (unchanged): rules [{method:'GET',prefix:'/api',target:'api'},{method:'GET',prefix:'/api/admin',target:'admin'}]; GET /api/users returns 'api'; POST /api/users returns null.
Return exactly one JSON object with this shape:
{"files":{"src/router.js":"complete JavaScript source as a JSON string","test/router-added.test.js":"complete JavaScript tests as a JSON string"},"review_notes":["at most four brief implementation or assumption notes"]}
No Markdown wrapper. You are returning code for someone else to evaluate locally; do not say you edited files, ran tests, or observed passing results.
Die vollständige Antwort von Claude Haiku 4.5 in der übermittelten Form anzeigen
Dies ist die gesamte erhaltene Antwort. Sie endet mitten in der Ausgabe, da das Limit erreicht wurde; fehlende Inhalte wurden nicht ergänzt.
```json
{
"files": {
"src/router.js": "function chooseRoute(request, rules) {\n // Validate request\n if (request === null || Array.isArray(request) || typeof request !== 'object') {\n return null;\n }\n if (typeof request.method !== 'string' || request.method.length === 0 || !/^[a-zA-Z]+$/.test(request.method)) {\n return null;\n }\n if (typeof request.path !== 'string' || !request.path.startsWith('/')) {\n return null;\n }\n\n // Validate rules\n if (!Array.isArray(rules)) {\n return null;\n }\n\n // Remove query and fragment from path\n const cleanPath = request.path.split(/[?#]/)[0];\n\n // Filter and validate rules\n const validRules = [];\n for (const rule of rules) {\n if (rule === null || Array.isArray(rule) || typeof rule !== 'object') {\n continue;\n }\n \n const method = rule.method;\n if (typeof method !== 'string' || (method !== '*' && (method.length === 0 || !/^[a-zA-Z]+$/.test(method)))) {\n continue;\n }\n \n const prefix = rule.prefix;\n if (typeof prefix !== 'string' || !prefix.startsWith('/') || prefix.includes('?') || prefix.includes('#')) {\n continue;\n }\n \n const target = rule.target;\n if (typeof target !== 'string' || target.length === 0) {\n continue;\n }\n \n validRules.push(rule);\n }\n\n // Normalize prefixes and partition into exact-method and wildcard groups\n const exactMethodRules = [];\n const wildcardRules = [];\n \n for (const rule of validRules) {\n const normalizedPrefix = rule.prefix === '/' ? '/' : rule.prefix.replace(/\/+$/, '');\n \n const entry = {\n originalRule: rule,\n normalizedPrefix: normalizedPrefix,\n method: rule.method\n };\n \n if (rule.method === '*') {\n wildcardRules.push(entry);\n } else {\n exactMethodRules.push(entry);\n }\n }\n\n const requestMethod = request.method.toUpperCase();\n\n // Helper to check if a prefix matches the path at a segment boundary\n function prefixMatches(prefix, path) {\n if (prefix === '/') {\n return true;\n }\n if (!path.startsWith(prefix)) {\n return false;\n }\n // Check segment boundary: next character must be '/' or end of string\n const nextChar = path[prefix.length];\n return nextChar === undefined || nextChar === '/';\n }\n\n // Try exact-method rules first\n let bestMatch = null;\n let bestLength = -1;\n \n for (const entry of exactMethodRules) {\n if (entry.method.toUpperCase() === requestMethod) {\n if (prefixMatches(entry.normalizedPrefix, cleanPath)) {\n if (entry.normalizedPrefix.length > bestLength) {\n bestMatch = entry.originalRule;\n bestLength = entry.normalizedPrefix.length;\n }\n }\n }\n }\n \n if (bestMatch !== null) {\n return bestMatch.target;\n }\n\n // Try wildcard rules only if no exact-method match\n bestMatch = null;\n bestLength = -1;\n \n for (const entry of wildcardRules) {\n if (prefixMatches(entry.normalizedPrefix, cleanPath)) {\n if (entry.normalizedPrefix.length > bestLength) {\n bestMatch = entry.originalRule;\n bestLength = entry.normalizedPrefix.length;\n }\n }\n }\n \n if (bestMatch !== null) {\n return bestMatch.target;\n }\n\n return null;\n}\n\nmodule.exports = { chooseRoute };",
"test/router-added.test.js": "const test = require('node:test');\nconst assert = require('node:assert/strict');\nconst { chooseRoute } = require('../src/router.js');\n\n// Regression: existing test cases\ntest('GET /api/users matches /api prefix (exact method)', () => {\n const rules = [\n { method: 'GET', prefix: '/api', target: 'api' },\n { method: 'GET', prefix: '/api/admin', target: 'admin' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'api');\n});\n\ntest('POST /api/users returns null (no matching method)', () => {\n const rules = [\n { method: 'GET', prefix: '/api', target: 'api' },\n { method: 'GET', prefix: '/api/admin', target: 'admin' }\n ];\n assert.equal(chooseRoute({ method: 'POST', path: '/api/users' }, rules), null);\n});\n\n// Invalid request handling\ntest('null request returns null', () => {\n assert.equal(chooseRoute(null, []), null);\n});\n\ntest('array request returns null', () => {\n assert.equal(chooseRoute([], []), null);\n});\n\ntest('request with missing method returns null', () => {\n assert.equal(chooseRoute({ path: '/api' }, []), null);\n});\n\ntest('request with empty method returns null', () => {\n assert.equal(chooseRoute({ method: '', path: '/api' }, []), null);\n});\n\ntest('request with non-letter method returns null', () => {\n assert.equal(chooseRoute({ method: 'GET-POST', path: '/api' }, []), null);\n});\n\ntest('request with numeric method returns null', () => {\n assert.equal(chooseRoute({ method: '123', path: '/api' }, []), null);\n});\n\ntest('request with missing path returns null', () => {\n assert.equal(chooseRoute({ method: 'GET' }, []), null);\n});\n\ntest('request with path not starting with / returns null', () => {\n assert.equal(chooseRoute({ method: 'GET', path: 'api' }, []), null);\n});\n\ntest('null rules returns null', () => {\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, null), null);\n});\n\ntest('non-array rules returns null', () => {\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, { method: 'GET' }), null);\n});\n\n// Query and fragment removal\ntest('query string is removed before matching', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users?foo=bar' }, rules), 'found');\n});\n\ntest('fragment is removed before matching', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users#section' }, rules), 'found');\n});\n\ntest('earliest ? or # is used as boundary', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users?foo#bar' }, rules), 'found');\n});\n\ntest('fragment before query is used as boundary', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users#foo?bar' }, rules), 'found');\n});\n\n// Segment boundary matching\ntest('prefix /api matches /api/users at segment boundary', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'found');\n});\n\ntest('prefix /api does not match /apix (no segment boundary)', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/apix' }, rules), null);\n});\n\ntest('prefix /api matches /api exactly at segment boundary', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\ntest('root / matches any valid path', () => {\n const rules = [{ method: 'GET', prefix: '/', target: 'root' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/anything/here' }, rules), 'root');\n});\n\ntest('root / matches /', () => {\n const rules = [{ method: 'GET', prefix: '/', target: 'root' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/' }, rules), 'root');\n});\n\n// Prefix normalization (trailing slash removal)\ntest('trailing slash is removed from prefix', () => {\n const rules = [{ method: 'GET', prefix: '/api/', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'found');\n});\n\ntest('multiple trailing slashes are removed', () => {\n const rules = [{ method: 'GET', prefix: '/api///', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'found');\n});\n\ntest('all-slash prefix normalizes to single /', () => {\n const rules = [{ method: 'GET', prefix: '///', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\n// Method case-insensitivity\ntest('method comparison is case-insensitive', () => {\n const rules = [{ method: 'get', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\ntest('request method case does not affect matching', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'found' }];\n assert.equal(chooseRoute({ method: 'get', path: '/api' }, rules), 'found');\n});\n\n// Exact-method vs wildcard precedence\ntest('exact-method rule preferred over wildcard with longer prefix', () => {\n const rules = [\n { method: '*', prefix: '/api/admin/users', target: 'wildcard' },\n { method: 'GET', prefix: '/api', target: 'exact' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/test' }, rules), 'exact');\n});\n\ntest('wildcard rule used when no exact-method matches', () => {\n const rules = [\n { method: '*', prefix: '/api', target: 'wildcard' },\n { method: 'GET', prefix: '/other', target: 'exact' }\n ];\n assert.equal(chooseRoute({ method: 'POST', path: '/api/users' }, rules), 'wildcard');\n});\n\n// Longest prefix matching\ntest('longest matching prefix is chosen', () => {\n const rules = [\n { method: 'GET', prefix: '/api', target: 'short' },\n { method: 'GET', prefix: '/api/admin', target: 'long' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/admin/users' }, rules), 'long');\n});\n\n// Tie-breaking (first rule wins on equal prefix length)\ntest('first rule wins on equal prefix length', () => {\n const rules = [\n { method: 'GET', prefix: '/api', target: 'first' },\n { method: 'GET', prefix: '/api', target: 'second' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'first');\n});\n\n// Invalid rules are ignored\ntest('null rule is ignored', () => {\n const rules = [\n null,\n { method: 'GET', prefix: '/api', target: 'found' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\ntest('array rule is ignored', () => {\n const rules = [\n [],\n { method: 'GET', prefix: '/api', target: 'found' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'found');\n});\n\ntest('rule with invalid method is ignored', () => {\n const rules = [\n { method: '', prefix: '/api', target: 'invalid' },\n { method: 'GET', prefix: '/api', target: 'valid' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'valid');\n});\n\ntest('rule with non-letter method (if not wildcard) is ignored', () => {\n const rules = [\n { method: 'G3T', prefix: '/api', target: 'invalid' },\n { method: 'GET', prefix: '/api', target: 'valid' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'valid');\n});\n\ntest('rule with prefix not starting with / is ignored', () => {\n const rules = [\n { method: 'GET', prefix: 'api', target: 'invalid' },\n { method: 'GET', prefix: '/api', target: 'valid' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'valid');\n});\n\ntest('rule with query in prefix is ignored', () => {\n const rules = [\n { method: 'GET', prefix: '/api?foo=bar', target: 'invalid' },\n { method: 'GET', prefix: '/api', target: 'valid' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'valid');\n});\n\ntest('rule with fragment in prefix is ignored', () => {\n const rules = [\n { method: 'GET', prefix: '/api#section', target: Die vollständige Antwort von Claude Sonnet 5 in der übermittelten Form anzeigen
Dies ist die gesamte erhaltene Antwort. Sie endet mitten in der Ausgabe, da das Limit erreicht wurde; fehlende Inhalte wurden nicht ergänzt.
{"files":{"src/router.js":"function isValidRequest(request) {\n return (\n request !== null &&\n typeof request === 'object' &&\n !Array.isArray(request) &&\n typeof request.method === 'string' &&\n request.method.length > 0 &&\n /^[A-Za-z]+$/.test(request.method) &&\n typeof request.path === 'string' &&\n request.path.startsWith('/')\n );\n}\n\nfunction isValidRule(rule) {\n if (rule === null || typeof rule !== 'object' || Array.isArray(rule)) {\n return false;\n }\n const { method, prefix, target } = rule;\n\n if (typeof method !== 'string') return false;\n if (method !== '*' && !(method.length > 0 && /^[A-Za-z]+$/.test(method))) {\n return false;\n }\n\n if (\n typeof prefix !== 'string' ||\n !prefix.startsWith('/') ||\n prefix.includes('?') ||\n prefix.includes('#')\n ) {\n return false;\n }\n\n if (typeof target !== 'string' || target.length === 0) return false;\n\n return true;\n}\n\nfunction normalizePrefix(prefix) {\n if (/^\/+$/.test(prefix)) return '/';\n return prefix.replace(/\/+$/, '');\n}\n\nfunction prefixMatches(normalizedPrefix, path) {\n if (normalizedPrefix === '/') return true;\n if (path === normalizedPrefix) return true;\n return path.startsWith(normalizedPrefix + '/');\n}\n\nfunction stripQueryAndFragment(path) {\n let cutIndex = path.length;\n for (let i = 0; i < path.length; i++) {\n const c = path[i];\n if (c === '?' || c === '#') {\n cutIndex = i;\n break;\n }\n }\n return path.slice(0, cutIndex);\n}\n\nfunction chooseRoute(request, rules) {\n if (!isValidRequest(request) || !Array.isArray(rules)) return null;\n\n const path = stripQueryAndFragment(request.path);\n const reqMethodLower = request.method.toLowerCase();\n\n let bestExact = null; // { len, idx, target }\n let bestWildcard = null;\n\n for (let idx = 0; idx < rules.length; idx++) {\n const rule = rules[idx];\n if (!isValidRule(rule)) continue;\n\n const normPrefix = normalizePrefix(rule.prefix);\n if (!prefixMatches(normPrefix, path)) continue;\n\n const len = normPrefix.length;\n\n if (rule.method === '*') {\n if (\n bestWildcard === null ||\n len > bestWildcard.len ||\n (len === bestWildcard.len && idx < bestWildcard.idx)\n ) {\n bestWildcard = { len, idx, target: rule.target };\n }\n } else if (rule.method.toLowerCase() === reqMethodLower) {\n if (\n bestExact === null ||\n len > bestExact.len ||\n (len === bestExact.len && idx < bestExact.idx)\n ) {\n bestExact = { len, idx, target: rule.target };\n }\n }\n }\n\n if (bestExact !== null) return bestExact.target;\n if (bestWildcard !== null) return bestWildcard.target;\n return null;\n}\n\nmodule.exports = { chooseRoute };\n","test/router-added.test.js":"const test = require('node:test');\nconst assert = require('node:assert/strict');\nconst { chooseRoute } = require('../src/router');\n\ntest('segment boundary: prefix matches at slash boundary only', () => {\n const rules = [\n { method: 'GET', prefix: '/api', target: 'api' },\n ];\n assert.equal(\n chooseRoute({ method: 'GET', path: '/api/users' }, rules),\n 'api'\n );\n assert.equal(\n chooseRoute({ method: 'GET', path: '/api' }, rules),\n 'api'\n );\n assert.equal(\n chooseRoute({ method: 'GET', path: '/apix' }, rules),\n null\n );\n});\n\ntest('root prefix matches every valid path', () => {\n const rules = [{ method: 'GET', prefix: '/', target: 'root' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/' }, rules), 'root');\n assert.equal(\n chooseRoute({ method: 'GET', path: '/anything/here' }, rules),\n 'root'\n );\n});\n\ntest('trailing slashes in rule prefix are normalized', () => {\n const rules = [{ method: 'GET', prefix: '/api///', target: 'api' }];\n assert.equal(\n chooseRoute({ method: 'GET', path: '/api/users' }, rules),\n 'api'\n );\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'api');\n});\n\ntest('all-slash prefix normalizes to /', () => {\n const rules = [{ method: 'GET', prefix: '////', target: 'root' }];\n assert.equal(\n chooseRoute({ method: 'GET', path: '/whatever' }, rules),\n 'root'\n );\n});\n\ntest('query and fragment are stripped before matching', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'api' }];\n assert.equal(\n chooseRoute({ method: 'GET', path: '/api/users?x=1&y=2' }, rules),\n 'api'\n );\n assert.equal(\n chooseRoute({ method: 'GET', path: '/api/users#section' }, rules),\n 'api'\n );\n assert.equal(\n chooseRoute({ method: 'GET', path: '/api/users?x=1#frag' }, rules),\n 'api'\n );\n});\n\ntest('query/fragment stripping does not decode or collapse slashes', () => {\n const rules = [{ method: 'GET', prefix: '/a//b', target: 'weird' }];\n assert.equal(\n chooseRoute({ method: 'GET', path: '/a//b?x=1' }, rules),Die vollständige Antwort von Claude Opus 5.5 in der übermittelten Form anzeigen
Dies ist die gesamte erhaltene Antwort. Sie endet mitten in der Ausgabe, da das Limit erreicht wurde; fehlende Inhalte wurden nicht ergänzt.
{"files":{"src/router.js":"'use strict';\n\nconst LETTERS = /^[A-Za-z]+$/;\n\nfunction isPlainObject(value) {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction isMethodName(value) {\n return typeof value === 'string' && value.length > 0 && LETTERS.test(value);\n}\n\nfunction stripQueryAndFragment(path) {\n const q = path.indexOf('?');\n const h = path.indexOf('#');\n let cut = -1;\n if (q !== -1 && h !== -1) cut = Math.min(q, h);\n else if (q !== -1) cut = q;\n else if (h !== -1) cut = h;\n return cut === -1 ? path : path.slice(0, cut);\n}\n\nfunction normalizePrefix(prefix) {\n let end = prefix.length;\n while (end > 0 && prefix[end - 1] === '/') end -= 1;\n return end === 0 ? '/' : prefix.slice(0, end);\n}\n\nfunction prefixMatches(path, prefix) {\n if (prefix === '/') return true;\n return path === prefix || path.startsWith(prefix + '/');\n}\n\nfunction chooseRoute(request, rules) {\n try {\n if (!isPlainObject(request) || !Array.isArray(rules)) return null;\n const method = request.method;\n const rawPath = request.path;\n if (!isMethodName(method)) return null;\n if (typeof rawPath !== 'string' || rawPath[0] !== '/') return null;\n\n const path = stripQueryAndFragment(rawPath);\n const upperMethod = method.toUpperCase();\n\n let bestExact = null;\n let bestWildcard = null;\n\n const count = rules.length;\n for (let i = 0; i < count; i += 1) {\n const rule = rules[i];\n if (!isPlainObject(rule)) continue;\n const ruleMethod = rule.method;\n const prefix = rule.prefix;\n const target = rule.target;\n const isWildcard = ruleMethod === '*';\n if (!isWildcard && !isMethodName(ruleMethod)) continue;\n if (typeof prefix !== 'string' || prefix[0] !== '/') continue;\n if (prefix.indexOf('?') !== -1 || prefix.indexOf('#') !== -1) continue;\n if (typeof target !== 'string' || target.length === 0) continue;\n\n const normalized = normalizePrefix(prefix);\n if (!prefixMatches(path, normalized)) continue;\n\n const candidate = { length: normalized.length, target };\n if (isWildcard) {\n if (bestWildcard === null || candidate.length > bestWildcard.length) bestWildcard = candidate;\n } else if (ruleMethod.toUpperCase() === upperMethod) {\n if (bestExact === null || candidate.length > bestExact.length) bestExact = candidate;\n }\n }\n\n if (bestExact !== null) return bestExact.target;\n if (bestWildcard !== null) return bestWildcard.target;\n return null;\n } catch (err) {\n return null;\n }\n}\n\nmodule.exports = { chooseRoute };\n","test/router-added.test.js":"'use strict';\n\nconst test = require('node:test');\nconst assert = require('node:assert/strict');\nconst { chooseRoute } = require('../src/router.js');\n\nconst baseRules = [\n { method: 'GET', prefix: '/api', target: 'api' },\n { method: 'GET', prefix: '/api/admin', target: 'admin' }\n];\n\ntest('existing regression cases still hold', () => {\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, baseRules), 'api');\n assert.equal(chooseRoute({ method: 'POST', path: '/api/users' }, baseRules), null);\n});\n\ntest('longest prefix wins within method group', () => {\n assert.equal(chooseRoute({ method: 'GET', path: '/api/admin/x' }, baseRules), 'admin');\n assert.equal(chooseRoute({ method: 'GET', path: '/api/admin' }, baseRules), 'admin');\n});\n\ntest('segment boundaries', () => {\n const rules = [{ method: 'GET', prefix: '/api', target: 'api' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'api');\n assert.equal(chooseRoute({ method: 'GET', path: '/api/' }, rules), 'api');\n assert.equal(chooseRoute({ method: 'GET', path: '/api/users' }, rules), 'api');\n assert.equal(chooseRoute({ method: 'GET', path: '/apix' }, rules), null);\n assert.equal(chooseRoute({ method: 'GET', path: '/ap' }, rules), null);\n});\n\ntest('trailing slashes in prefixes are normalized, all-slash is root', () => {\n const rules = [{ method: 'GET', prefix: '/api///', target: 'api' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api' }, rules), 'api');\n assert.equal(chooseRoute({ method: 'GET', path: '/apix' }, rules), null);\n const rootRules = [{ method: 'GET', prefix: '///', target: 'root' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/' }, rootRules), 'root');\n assert.equal(chooseRoute({ method: 'GET', path: '/anything/else' }, rootRules), 'root');\n assert.equal(chooseRoute({ method: 'GET', path: '/x' }, [{ method: 'GET', prefix: '/', target: 'r' }]), 'r');\n});\n\ntest('query and fragment are removed at earliest ? or #', () => {\n assert.equal(chooseRoute({ method: 'GET', path: '/api?next=/api/admin' }, baseRules), 'api');\n assert.equal(chooseRoute({ method: 'GET', path: '/api#/admin' }, baseRules), 'api');\n assert.equal(chooseRoute({ method: 'GET', path: '/apix?/api' }, baseRules), null);\n assert.equal(chooseRoute({ method: 'GET', path: '/api/admin#frag?q' }, baseRules), 'admin');\n assert.equal(chooseRoute({ method: 'GET', path: '/api?q#/admin' }, baseRules), 'api');\n});\n\ntest('no URL decoding and no slash collapsing', () => {\n const rules = [{ method: 'GET', prefix: '/api/admin', target: 'admin' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/api%2Fadmin' }, rules), null);\n assert.equal(chooseRoute({ method: 'GET', path: '/api//admin' }, rules), null);\n assert.equal(chooseRoute({ method: 'GET', path: '/api//admin' }, baseRules), 'api');\n});\n\ntest('methods compare case-insensitively', () => {\n const rules = [{ method: 'get', prefix: '/a', target: 'lower' }];\n assert.equal(chooseRoute({ method: 'GET', path: '/a' }, rules), 'lower');\n assert.equal(chooseRoute({ method: 'gEt', path: '/a/b' }, rules), 'lower');\n});\n\ntest('exact method beats longer wildcard; wildcard used only as fallback', () => {\n const rules = [\n { method: '*', prefix: '/api/admin', target: 'wild-admin' },\n { method: 'GET', prefix: '/', target: 'get-root' },\n { method: 'POST', prefix: '/other', target: 'post-other' },\n { method: '*', prefix: '/api', target: 'wild-api' }\n ];\n assert.equal(chooseRoute({ method: 'GET', path: '/api/admin/x' }, rules), 'get-root');\n assert.equal(chooseRoute({ method: 'POST', path: '/api/admin/x' }, rules), 'wild-admin');\n assert.equal(chooseRoute({ method: 'POST', path: '/api/x' }, rules), 'wild-api');\n assert.equal(chooseRoute({ method: 'POST', path: '/other/1' }, rules), 'post-other');\n assert.equal(chooseRoute({ method: 'PUT', path: '/nothing' }, rules), null);\n});\n\ntest('ties go to earlier rule in input order', () => {\n const rules = [\n { method: 'GET', prefDie Obergrenze von 4.096 Token war das für diesen Test gewählte Ausgabebudget und nicht das dokumentierte Maximum eines bestimmten Modells. Das Routing-Ergebnis legt nahe, vor einer umfangreicheren Anfrage eine praktische Überprüfung durchzuführen: Schätzen Sie den Umfang der Implementierung, der Tests und der Erklärung, die Sie als Rückgabe erwarten. Eine Aufteilung der Ergebnisse oder die Bereitstellung von mehr Ausgabekapazität kann sinnvoll sein; wir haben diese Ausgaben nicht mit anderen Einstellungen erneut ausgeführt.
Beurteilen Sie bei Ihrer eigenen Aufgabe drei Aspekte getrennt voneinander: ob die Antwort vollständig ist, ob der Code nützliche Prüfungen besteht und ob bei der Überprüfung Lücken entdeckt werden, die diese Prüfungen übersehen haben. Das Bestehen von zwölf Funktionsprüfungen machte keine der unvollständigen Antworten aus zwei Dateien zu einer vollständigen Lieferung.
Wie wirkt sich die Wahl des Modells auf die Kosten aus?
„Claude Code“ ist das Codierungstool; „Haiku“, „Sonnet“, „Opus“ und „Fable“ sind Modelloptionen innerhalb der unterstützten Umgebung. Die Art und Weise, wie Sie sich authentifizieren und bezahlen, ist eine weitere Wahlmöglichkeit. Ein Wechsel des Modells wandelt ein Abonnement nicht in ein API-Konto um und hebt auch nicht alle Nutzungsbeschränkungen auf.
| Abrechnungsweg | Was man sich ansehen sollte | Wie ist die Modellwahl zu interpretieren? |
|---|---|---|
| Zugang zum Claude-Abonnement | Im Tarif enthaltene Nutzung sowie etwaige separat freigeschaltete Nutzungskontingente | Die verschiedenen Modelle können die Kontingente unterschiedlich verbrauchen; informieren Sie sich über die verfügbaren Modelle und Beschränkungen des Tarifs. |
| Anthropic-API-Zugriff | Eingabe-/Ausgabe-Token, Zwischenspeicherung und anfallende API-Gebühren | Verwenden Sie die aktuelle Preisliste und die tatsächliche Nutzung und bestätigen Sie anschließend die Gebühren in der Abrechnungskonsole. |
| Cloud-Anbieter oder Gateway | Von Ihrem Anbieter unterstützte IDs, Tarife und Abrechnungsdaten | Ein Beispiel für einen Anthropic-Listenpreis entspricht möglicherweise nicht dem Betrag, den Ihr Anbieter in Rechnung stellt. |
Im Claude-Code, /Verwendung zeigt Informationen zum Sitzungstoken und gegebenenfalls Balken zur Abonnementnutzung an. Der angegebene Dollarbetrag ist eine lokal berechnete Schätzung auf der Grundlage von Listenpreisen oder konfigurierten Tarifen; es handelt sich nicht um eine Rechnung. Für Pro- und Max-Abonnenten bedeutet dieser Sitzungsbetrag nicht, dass dem Abonnement eine zusätzliche API-Rechnung hinzugefügt wurde. Erfahren Sie mehr über Claude – Preisgestaltung und Abrechnungswege wenn Sie sich gerade überlegen, wie Sie bezahlen möchten.
Aktuelle API-Preise und ein Beispiel mit „equal-Token“
Die regulären Grundgebühren von Anthropic pro Million Eingabe-/Ausgabe-Token betragen Haiku 4.5: $1/$5; Sonnet 5: $2/$10; Opus 5.5: $4/$20; Fable 5.1: $10/$50, abgerufen am 28. September 2026. In der folgenden Grafik wird das Token-Volumen konstant gehalten, damit die Zahlen leicht vergleichbar sind.
Gleiche Token-Menge, vier unterschiedliche API-Kosten
Beispiel: 100.000 nicht zwischengespeicherte Eingabetoken + 10.000 Ausgabetoken, basierend auf den regulären API-Listenpreisen von Anthropic, Stand: 28. September 2026.
Preise und Berechnung anzeigen
| Modell | Eingang / 1M | Leistung / 1M | Beispiel-Gesamtsumme |
|---|---|---|---|
| Haiku 4.5 | $1 | $5 | $0.15 |
| Sonett 5 | $2 | $10 | $0.30 |
| Opus 5.5 | $4 | $20 | $0.60 |
| Fable 5.1 | $10 | $50 | $1.50 |
Berechnung: 0,1 × Eingangsrate + 0,01 × Ausgangsrate. Für Opus 5.5: 0,1 × $4 + 0,01 × $20 = $0,60.
Dies ist ein Beispiel mit festen Token-Zahlen. Tatsächliche Aufgaben verbrauchen unterschiedliche Gesamtmengen an Token; Cache-Schreib- und Lesevorgänge, Wiederholungsversuche, Tools, die Abrechnung durch den Anbieter und Abonnement-Limits müssen separat berücksichtigt werden.
Quelle: Preise für die Anthropic-API.

Eine echte Claude-Code-Aufgabe besteht aus einer Abfolge von Anfragen. Frühere Kontextdaten können erneut gesendet werden, ein Modell kann weitere Untersuchungen durchführen, und Tools oder zusätzliche Agenten können weitere Aufgaben erzeugen. Das Caching von Prompts weist zudem unterschiedliche Schreib- und Lesegeschwindigkeiten auf. Der unterste Balken im Beispiel gibt daher nicht die niedrigsten Kosten pro akzeptierter Änderung an.
Fünf Möglichkeiten, die Kosten zu kontrollieren, ohne die Aufgabe zu beeinträchtigen
- Legen Sie die Akzeptanzkriterien fest, bevor Sie sich für ein Modell entscheiden. Geben Sie das erwartete Verhalten, Randfälle und die bestehenden Einschränkungen an. Eine klar definierte, kleine Aufgabe lässt sich kostengünstiger delegieren und leichter überprüfen.
- Geben Sie den entsprechenden Kontext an. Fügen Sie die Dateien und Fehlerdetails bei, die für das Modell benötigt werden. Bei nicht damit zusammenhängenden Aufgaben sollten Sie eine neue Konversation beginnen, anstatt einen langen Verlauf weiterzuführen, nur weil er bereits existiert.
- Unterscheide zwischen Fähigkeit und Anstrengung. Anthropic empfiehlt, zunächst mit dem vom Modell voreingestellten Aufwand zu beginnen. Wenn das Modell den Kontext richtig interpretiert hat und das Problem dennoch nicht lösen konnte, könnte ein leistungsfähigeres Modell Abhilfe schaffen. Falls das Modell das Einlesen oder die Überprüfung übersprungen hat, überprüfen Sie die Aufgabenstellung und die gewählte Aufwandsstufe.
- Budget für die gesamte Antwort. Quellcode, Tests und Erläuterungen benötigen alle Platz. Unsere zweite Aufgabe zeigt, warum eine vollständige Funktion allein noch kein Beweis dafür ist, dass die geforderte Leistung im Rahmen des Budgets liegt.
- Vergleiche anerkannte Arbeiten. Erfassen Sie nützliche Ausgabeergebnisse, Wiederholungsversuche, Überprüfungszeiten und tatsächliche Abrechnungsdaten für repräsentative Aufgaben. Trennen Sie dabei Fehler des Anbieters von Fehlern, die auf die Modellqualität zurückzuführen sind.
Diese Strategien stehen im Einklang mit der Offizieller Kostenleitfaden und Die Leitlinien von Anthropic zu Modell und Aufwand. Ein tarifweites Wochen- oder Sitzungslimit kann auch nach einem Modellwechsel weiterhin gelten; bei einem modellspezifischen Limit verhält es sich anders. Überprüfen Sie das tatsächliche Limit, bevor Sie wiederholt wechseln.
Wenn Ihre Arbeit die Bereiche Programmierung, Forschung, Schreiben und Medien umfasst, vergleichen Sie auch den Workflow, für den Sie bezahlen. Der Multi-Modell-Arbeitsbereich von GlobalGPT vereint diese Funktionen in einem Dashboard mit CLI-Zugriff für Entwicklungsaufgaben. Dieser umfassendere Mehrwert für den Arbeitsablauf sollte im Zusammenhang mit einer volumenabhängigen API-Route berücksichtigt werden; die obige API-Übersicht ist keine Preisliste für GlobalGPT-Abonnements.
Warum das von Ihnen gewählte Modell möglicherweise nicht funktioniert
| Symptom | Wahrscheinliche Überprüfung | Praktischer nächster Schritt |
|---|---|---|
| In der nächsten Sitzung wird das alte Modell verwendet | Die Umschaltung war möglicherweise nur für diese Sitzung gültig | Speichere die Auswahl mit der „Enter“-Aktion des Auswahlwerkzeugs und wähle anschließend eine neue Sitzung aus |
| Die Einstellung wird gespeichert, aber es wird ein anderes Modell gestartet | Eine Einstellung für „Start“, „Shell“, „Projekt“, „Verwaltung“ oder „Organisation“ kann Vorrang haben | Lesen Sie die Informationen zum Systemstart durch und überprüfen Sie die entsprechende Konfiguration gemeinsam mit dem Verantwortlichen. |
| Ein fortgesetztes Gespräch folgt einem anderen Muster | Die gespeicherte Sitzung kann ihr vorheriges Modell wiederherstellen | Überprüfen Sie den Status; wählen Sie für die Wiederaufnahme der Arbeit bewusst das gewünschte Modell aus. |
| Das Modell fehlt oder wurde abgelehnt. | Verfügbarkeit der Anbieter, Organisationsregeln oder eine veraltete Version des Claude-Codes | Überprüfen Sie die unterstützten Modell-IDs, den Kontozugriff und die Versionsanforderungen |
| Derselbe Nachname wird an anderer Stelle anders zugeordnet | Aliase und Provider-Zuordnungen unterscheiden sich | Verwenden Sie die korrekte vollständige ID des Anbieters, wenn eine Version unverändert bleiben muss |
| Durch einen Anbieterwechsel wird ein Nutzungslimit nicht zurückgesetzt | Die Beschränkung kann für den gesamten Plan gelten. | Lesen Sie die Nutzungshinweise und stellen Sie den Zeitraum neu ein, anstatt davon auszugehen, dass ein Familienwechsel ausreicht. |
Wenn der Code „Claude“ Ihre Benutzereinstellungen nicht schreiben kann, kann eine interaktive Auswahl für die aktuelle Sitzung bestehen bleiben, ohne dauerhaft gespeichert zu werden. Bei einer verwalteten oder generierten Einstellungsdatei ist möglicherweise eine Änderung durch den Eigentümer erforderlich, anstatt einen weiteren Auswahlversuch zu unternehmen. Vermeiden Sie es, organisatorische Einschränkungen aufzuheben, nur um eine Option anzuzeigen.
Erstellen Sie mit GlobalGPT einen umfassenderen Arbeitsablauf
Die Modellauswahl ist nur ein Teil des Arbeitsablaufs. Möglicherweise müssen Sie eine Bibliothek recherchieren, eine Funktion entwerfen, einem Teamkollegen eine Änderung erklären, Dokumentation erstellen und visuelle Elemente vorbereiten. GlobalGPT vereint mehrere führende Modelle und KI-Funktionen in einer kostengünstigen Arbeitsumgebung, sodass all diese Aufgaben in ein und demselben Dashboard abgewickelt werden können.

Für die Arbeit am Terminal gilt, dass die GlobalGPT-Befehlszeilenschnittstelle verbindet die Tools der Plattform mit Entwicklungsumgebungen. Die dokumentierte Einrichtung nutzt Ihre Anmeldedaten für das GlobalGPT-Konto und den normalen Kontostand. Die CLI unterstützt einen umfassenderen Workflow für Programmierung und Erstellung, während das eigene Modell von Claude Code durch seine Modellsteuerungen weiterhin eine bewusste Wahl bleibt.
Erstellen und überprüfen Sie beispielsweise einen Implementierungsentwurf, verwenden Sie ein anderes Modell für eine prägnante Erläuterung und erstellen Sie anschließend die Dokumentation oder die Begleitmaterialien für die Veröffentlichung. Befolgen Sie die Anleitung, um GlobalGPT-CLI mit Claude-Code verbinden wenn Sie diese Tool-Integration wünschen. Passen Sie Ihr Claude-Code-Inferenzmodell entsprechend der Kodierungsaufgabe separat an.
Wählen Sie ein Ausgangsmodell, legen Sie die Kriterien fest, die den Erfolg definieren, und gehen Sie einen Schritt weiter, wenn es die Aufgabe erfordert. Überprüfen Sie das gesamte Ergebnis, bevor Sie die Arbeit als abgeschlossen betrachten. Gestalten Sie Ihren Arbeitsablauf mit GlobalGPT wenn Sie Modellauswahl, Recherche, Programmierung und kreative Tools miteinander verknüpfen möchten, um sie in Ihren Arbeitsalltag zu integrieren.
FAQ
Wie ändere ich das Modell im Claude-Code?
Führen Sie den Befehl /model aus, um die Auswahl zu öffnen. Drücken Sie „s“, um nur die aktuelle Sitzung umzustellen, oder die Eingabetaste, um das ausgewählte Modell als Standard zu speichern. Um ein Modell für eine einzelne neue Sitzung auszuwählen, starten Sie das Programm mit dem Befehl claude –model, gefolgt vom Modellnamen.
Ändert /model meine gespeicherte Standardeinstellung?
In den aktuellen interaktiven Versionen wird die Auswahl eines Modells über die Eingabetaste oder die Eingabe von „/model sonnet“ in den Benutzereinstellungen gespeichert, sofern diese beschreibbar sind. Das Drücken der Taste „s“ im Auswahldialog gilt nur für die aktuelle Sitzung. Andere Einstellungen können beim nächsten Start weiterhin Vorrang haben.
Was ist das Standardmodell des Claude-Codes?
Die Standardlaufzeit hängt von Ihrem Konto, Ihrem Anbieter und Ihrer Konfiguration ab. Der Standardwert löscht eine Modellüberschreibung; es handelt sich nicht um eine feste Modell-ID. Überprüfen Sie das aktive Modell mit /status und sehen Sie sich die Auswahlliste an, anstatt davon auszugehen, dass jedes Konto mit derselben Version beginnt.
Was macht Opusplan?
Im Planungsmodus wird Opus verwendet, während der Ausführung Sonnet. Das System orientiert sich am Moduswechsel und wählt nicht automatisch für jede Eingabeaufforderung das kostengünstigste Modell aus. Die tatsächlichen Kosten hängen von der in der jeweiligen Phase geleisteten Arbeit ab.
Warum fehlt ein Modell in der Auswahl?
Die Verfügbarkeit kann von Ihrem Anbieter, Ihrem Konto, den Einschränkungen Ihrer Organisation und der Version des Claude-Codes abhängen. Informieren Sie sich in der Dokumentation zum aktuellen Modell und über die in Ihrer Umgebung zulässigen Modelle. Ein Familienalias kann bei einem anderen Anbieter auch zu einer anderen Version führen.
Macht ein günstigeres Modell eine Aufgabe immer kostengünstiger?
Nein. Der Token-Preis ist nur ein Faktor. Die Gesamtnutzung, unvollständige Antworten, Wiederholungsversuche und der Überprüfungsaufwand beeinflussen die Kosten einer akzeptablen Änderung. Bei unserer kleinen Refaktorisierung wurden alle drei Funktionen bestanden, während alle drei größeren Antworten mit zwei Dateien aufgrund der gemeinsamen Ausgabebegrenzung gekürzt wurden.
Quellen
- Konfiguration des Modells mit dem Code „Claude“ — Modellauswahl, Standardwerte, Aliase, Unterschiede zwischen Anbietern und Opusplan.
- Kosten für den Code Claude — Nutzungsschätzungen, Abonnementkontingente, Zwischenspeicherung und Kostenkontrolle.
- Modellübersicht Anthropic und API-Preise — Aktuelle Modellspezifikationen und Listenpreise.
- Leitfaden zu Modellen und Maßnahmen — praktische Unterschiede zwischen Fähigkeiten, Kontext und Aufwand.
- GlobalGPT CLI-Dokumentation — Terminal-Workflow und kontobasierte Einrichtung.







