Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Agents bauen mit Mastra – BASTA! Mainz 2026

Agents bauen mit Mastra – BASTA! Mainz 2026

KI-Agents in TypeScript mit Mastra, vom ersten Tool-Call bis zum Durable Agent. Live gebaut: ein Agent, der GitHub-Issues triagiert, in sieben Steps – Agent und Tools, Working Memory, Workflow mit Parallelität und Verzweigung, Human-in-the-Loop, MCP-Server, Evals und Tracing, Durable Agents.

Demo-Code (sieben Steps als Git-Tags): https://github.com/danielsogl/basta-mastra-issue-triage

Avatar for Daniel Sogl

Daniel Sogl PRO

September 29, 2026

More Decks by Daniel Sogl

Other Decks in Programming

Transcript

  1. Modell Agents bauen mit Mastra In TypeScript: vom ersten Tool-Call

    bis zum Durable Agent Daniel Sogl Bereichsleiter AI Engineering · SHI GmbH · Microsoft MVP Agent Ergebnis Tool-Call BASTA! Mainz 2026
  2. Daniel Sogl Bereichsleiter AI Engineering · SHI GmbH · Microsoft

    MVP Entwickle seit 2015 beruflich Enterprise-Web- und Mobile-Apps Seit drei Jahren fast nur noch KI-gestützte Entwicklung Baue bei SHI den Bereich AI Engineering auf [email protected] daniel-sogl danielsogl Folien & Code Agents bauen mit Mastra BASTA! Mainz · 2026 2 / 40
  3. Agenda Agents bauen mit Mastra BASTA! Mainz · 2026 01

    Was ist ein Agent? Theorie 02 Mastra im Überblick Theorie 03 Live: Issue-Triage in sieben Steps Praxis 04 Ausblick & Takeaways Q&A 3 / 40
  4. Ein LLM-Agent führt Tools in einer Schleife aus, um ein

    Ziel zu erreichen. Simon Willison, 2025
  5. Gehirn und Körper eines Agenten „Ein Agent ist ein System,

    das ein KI-Modell nutzt, um mit seiner Umgebung zu interagieren und ein vom Nutzer vorgegebenes Ziel zu erreichen.“ Hugging Face Agents Course wählt Tool handelt Gehirn Körper Umgebung Das Modell plant und entscheidet Die Tools legen fest, was geht Die Welt, die sich ändert claude-sonnet-5 getIssue searchIssues acme/shop-api postComment Beobachtung fließt zurück ins Gehirn Agents bauen mit Mastra BASTA! Mainz · 2026 6 / 40
  6. Ein Agent arbeitet in einer Schleife 1. Das Modell bekommt

    das Ziel und die ToolBeschreibungen Modell entscheidet 2. Es wählt ein Tool und die Argumente 3. Dein Code führt das Tool aus 4. Das Ergebnis geht zurück ans Modell, bis es fertig ist Ziel Ergebnis Tool-Call Budget bewusst setzen Mastra begrenzt die Schleife standardmäßig auf 5 Schritte ( maxSteps ). Jeder Schritt ist ein Modellaufruf und kostet Tokens. Agents bauen mit Mastra BASTA! Mainz · 2026 7 / 40
  7. Workflow oder Agent? Anthropic unterscheidet in „Building effective agents“ zwei

    Arten agentischer Systeme: Workflow Laden Agent LLM Freigabe LLM Tool? Ergebnis bis das Ziel erreicht ist Der Code gibt den Pfad vor Das Modell entscheidet über Pfad und Tools Vorhersagbar und gut testbar Flexibel, aber teurer und schwerer vorherzusagen Beispiel: Issue klassifizieren, Antwort entwerfen Beispiel: „Warum hängt der Login?“ In der Demo: beides Ein Workflow gibt den Pfad vor, einzelne Schritte rufen den Agenten auf. Agents bauen mit Mastra BASTA! Mainz · 2026 8 / 40
  8. Was dir ein Framework abnehmen sollte Modelle Tools & Schemas

    Memory Provider wechseln, ohne Code umzubauen. Typsichere Ein- und Ausgaben, validiert zur Laufzeit. Threads, Nutzerwissen, lange Konversationen. Persistenz Observability Evals Pausieren, fortsetzen, Neustarts überleben. Jeder Modellaufruf und Tool-Call nachvollziehbar. Qualität prüfen, bevor Nutzer Fehler finden. Agents bauen mit Mastra BASTA! Mainz · 2026 9 / 40
  9. Agenda Agents bauen mit Mastra BASTA! Mainz · 2026 01

    Was ist ein Agent? Theorie 02 Mastra im Überblick Theorie 03 Live: Issue-Triage in sieben Steps Praxis 04 Ausblick & Takeaways Q&A 10 / 40
  10. Mastra in einem Satz Ein TypeScript-Framework für Agents, Workflows, Memory,

    Evals und Observability, inklusive lokaler Entwicklungsumgebung. TypeScript-first Server oder eingebettet Studio Zod-Schemas, Typinferenz über Läuft eigenständig oder in Next.js, Lokale UI zum Chatten, Debuggen Workflow-Schritte hinweg. Hono, Express und ServerlessFunktionen. und Tracen. Agents bauen mit Mastra BASTA! Mainz · 2026 11 / 40
  11. Die Bausteine Zugang Studio REST-API & Client Orchestrierung Agents Tools

    Workflows Qualität Tracing Evals Guardrails Modelle & Storage Model Router Zugriff von außen Agents bauen mit Mastra BASTA! Mainz · 2026 MCP & A2A Channels Memory Storage 12 / 40
  12. Model Router: ein String statt eines SDKs // import {

    Agent } from '@mastra/core/agent' export const agent = new Agent({ id: 'triage-agent', name: 'Triage Agent', instructions: 'Du triagierst GitHub-Issues …', model: 'anthropic/claude-sonnet-5', }) Provider am Präfix Andere Modelle Mastra liest den passenden Key aus der Umgebung openai/gpt-5.4-mini , google/gemini-3.8-flash ( ANTHROPIC_API_KEY , OPENAI_API_KEY , …). Ein oder ein lokales Modell über eine OpenAI- Provider-Paket brauchst du nicht. kompatible URL. In der Demo steht das Modell in .env . Agents bauen mit Mastra BASTA! Mainz · 2026 13 / 40
  13. Zwei Befehle bis zum laufenden Studio npm create mastra@latest npx

    mastra dev # Studio: localhost:4111 Agents und Workflows Hot Reload bei Änderungen unter src/mastra/ src/mastra/ agents/ tools/ workflows/ scorers/ index.ts mastra dev startet Studio und eine REST-API für alle Für Coding-Agents npx skills add mastra-ai/skills und ← registriert alles mastra.ai/llms.txt geben deinem Coding- Agenten die aktuelle API, denn seine Trainingsdaten sind oft veraltet. Agents bauen mit Mastra BASTA! Mainz · 2026 14 / 40
  14. Neu seit Mastra 1.0 Observational Memory Channels Background Tasks Hintergrund-Agent

    verdichtet lange Threads zu Beobachtungen. Agents direkt in Slack, Teams, Discord, GitHub, WhatsApp. Tools und Subagents laufen im Hintergrund weiter. Code Mode Goals & Signals Durable Agents Der Agent schreibt Code, der die Tools aufruft. Beta Agents verfolgen lange Ziele und nehmen unterwegs Nachrichten an. Die Agent-Schleife übersteht Verbindungsabbrüche und Beta Agents bauen mit Mastra BASTA! Mainz · 2026 Neustarts. Beta 15 / 40
  15. Agenda Agents bauen mit Mastra BASTA! Mainz · 2026 01

    Was ist ein Agent? Theorie 02 Mastra im Überblick Theorie 03 Live: Issue-Triage in sieben Steps Praxis 04 Ausblick & Takeaways Q&A 16 / 40
  16. Ich ertrinke in Issues Ich bin Maintainer von acme/shop-api .

    Klassifizieren Issue laden ja Als Duplikat schließen Duplikat? Duplikate suchen Mensch gibt frei nein Kommentar posten Antwort entwerfen Die Issues kommen aus einer JSON-Datei, das läuft offline und ohne Token. Für ein echtes Repo tauschst du nur execute() aus. Agents bauen mit Mastra BASTA! Mainz · 2026 18 / 40
  17. Sieben Steps, sieben Git-Tags 1 Agent + Tools 5 Erster

    Agent mit zwei Tools 2 Memory Der Agent in Claude Code 6 Team-Konventionen merken 3 Workflow 4 Evals & Tracing Checks in Vitest, Traces im Studio 7 Fester Pfad mit Parallelität und Verzweigung MCP-Server Durable Agents Runs überstehen Verbindungsabbrüche Human-in-the-Loop suspend() und requireApproval Zum Mitnehmen git checkout step-03 springt zu jedem Stand, git diff step-02 step-03 zeigt, was dazukam. Agents bauen mit Mastra BASTA! Mainz · 2026 19 / 40
  18. Step 1 · Ein Tool import { createTool } from

    '@mastra/core/tools' export const getIssue = createTool({ id: 'getIssue', description: 'Lädt ein GitHub-Issue anhand seiner Nummer', inputSchema: z.object({ number: z.number().describe('Issue-Nummer, z. B. 101') }), outputSchema: issueSchema, execute: async ({ number }) => { const issue = issues.find(i => i.number === number) if (!issue) throw new Error(`Issue #${number} nicht gefunden`) return issueSchema.parse(issue) // Laufzeitvalidierung }, }) description und .describe() sind Teil des Prompts. Daran entscheidet das Modell, ob und wie es das Tool nutzt. Agents bauen mit Mastra BASTA! Mainz · 2026 20 / 40
  19. Step 1 · Der Agent import { Agent } from

    '@mastra/core/agent' export const triageAgent = new Agent({ id: 'triage-agent', name: 'Triage Agent', instructions: ` Du bist Maintainer von "acme/shop-api" und triagierst GitHub-Issues. Lade das Issue mit getIssue, suche mit searchIssues nach Duplikaten, bestimme Typ, Priorität und Labels. Produktionsausfälle oder Geldverlust sind immer "critical". `, model: process.env.MODEL ?? 'anthropic/claude-sonnet-5', tools: { getIssue, searchIssues }, }) export const mastra = new Mastra({ agents: { triageAgent }, storage, observability }) Agents bauen mit Mastra BASTA! Mainz · 2026 21 / 40
  20. Step 2 · Team-Konventionen merken Message History memory: new Memory({

    options: { // gilt über alle Threads eines Nutzers workingMemory: { enabled: true, Verlauf im Thread Working Memory Dauerhafte Notizen, in der scope: 'resource', template: '# Team-Konventionen\n- Labels:\n- Zuständigkeiten:', Demo Semantic Recall Suche im Verlauf }, }, Observational Memory }), Verdichtet lange Threads Memory braucht einen Storage, lokal reicht LibSQL. Observational Memory verlangt im Standard-Scope thread bei jedem Aufruf eine threadId . Agents bauen mit Mastra BASTA! Mainz · 2026 23 / 40
  21. Step 3 · Der Workflow gibt den Pfad vor const

    fetchIssue = createStep(getIssue) // Tool als Schritt const triageWorkflow = createWorkflow({ id: 'triage-workflow', inputSchema, outputSchema }) .map(async ({ inputData }) => ({ number: inputData.issueNumber })) .then(fetchIssue) .parallel([classify, findDuplicates]) // zwei LLM-Aufrufe gleichzeitig .map(async ({ inputData, getStepResult }) => ({ issue: getStepResult(fetchIssue), classification: inputData.classify, duplicate: inputData['find-duplicates'], })) .branch([ [async ({ inputData }) => inputData.duplicate.duplicateOf !== null, closeAsDuplicate], [async ({ inputData }) => inputData.duplicate.duplicateOf === null, draftReply], ]) .map(pickResult).then(humanReview).then(publish).commit() // Step 4: Mensch gibt frei Agents bauen mit Mastra BASTA! Mainz · 2026 24 / 40
  22. Step 3 · Ein Schritt mit Structured Output const classificationSchema

    = z.object({ type: z.enum(['bug', 'feature', 'question']), priority: z.enum(['low', 'medium', 'high', 'critical']), labels: z.array(z.string()).max(3), }) const classify = createStep({ id: 'classify', inputSchema: issueSchema, outputSchema: classificationSchema, execute: async ({ inputData, mastra }) => { const agent = mastra.getAgentById('triage-agent') const res = await agent.generate(`Klassifiziere: ${inputData.title} …`, { structuredOutput: { schema: classificationSchema }, toolChoice: 'none', // nur klassifizieren, keine Tools }) return res.object // typisiert und validiert }, }) Agents bauen mit Mastra BASTA! Mainz · 2026 25 / 40
  23. Nicht jeder Schritt braucht ein LLM const closeAsDuplicate = createStep({

    id: 'close-as-duplicate', inputSchema: triageSchema, outputSchema: resultSchema, execute: async ({ inputData }) => ({ issueNumber: inputData.issue.number, 0 Modellaufrufe Template statt LLM Workflows mischen LLM- action: 'close-as-duplicate', labels: [...inputData.classification.labels, 'duplicate'], Schritte und gewöhnlichen comment: `Danke! Das Thema läuft bereits in #${ inputData.duplicate.duplicateOf}.`, schneller, kostet nichts und }), lässt sich wie jede Funktion testen. }) Agents bauen mit Mastra Code. Ein Template ist BASTA! Mainz · 2026 26 / 40
  24. Step 4 · Human-in-the-Loop const humanReview = createStep({ id: 'human-review',

    inputSchema: resultSchema, outputSchema: resultSchema.extend({ approved: z.boolean() }), suspendSchema: resultSchema, // was der Mensch zu sehen bekommt resumeSchema: z.object({ approved: z.boolean(), comment: z.string().optional() }), execute: async ({ inputData, resumeData, suspend }) => { if (!resumeData) return await suspend(inputData) // pausiert, Snapshot in die DB const comment = resumeData.comment ?? inputData.comment // Mensch darf umformulieren return { ...inputData, comment, approved: resumeData.approved } }, }) Im Agenten reicht eine Zeile Mit requireApproval: true am Tool postComment fragt Studio vor jedem Aufruf nach Approve oder Decline. Agents bauen mit Mastra BASTA! Mainz · 2026 27 / 40
  25. Step 3 + 4 · Der Run wartet auf dich

    Grün: erledigte Schritte Duplikat erkannt: close-as-duplicate lief, draft-reply nicht human-review (orange) steht auf Needs input Formular aus dem resumeSchema , ein Klick auf Resume Echter Run mit Issue #105 im Studio, genau so sieht es gleich live aus. Agents bauen mit Mastra BASTA! Mainz · 2026 28 / 40
  26. Step 4 · Fortsetzen, auch Tage später const run =

    await mastra.getWorkflow('triageWorkflow').createRun() let result = await run.start({ inputData: { issueNumber: 104 } }) if (result.status === 'suspended') { const draft = result.steps['human-review'].suspendPayload const approved = await askHuman(draft) result = await run.resume({ step: 'human-review', resumeData: { approved } }) } Snapshot im Storage Beim suspend() landet der Workflow-Zustand in der Datenbank. resume() funktioniert nach einem Neustart, aus einem HTTP-Handler oder per Slack-Button. Agents bauen mit Mastra BASTA! Mainz · 2026 29 / 40
  27. Step 5 · Ein Agent, jeder Client Claude Code MCP

    über HTTP Mastra-Server ask_triageAgent Tools oder Cursor, VS Code /api/mcp/triage/mcp mastra dev Agent als Tool getIssue, searchIssues Rausgeben Reinholen MCPServer stellt Agents, Tools und Workflows für MCPClient bindet fremde MCP-Server als Tools in jeden MCP-Client bereit. deinen Agenten ein. $ claude > Nutze triage, um Issue #104 zu bewerten ⏺ triage - ask_triageAgent (MCP) Agents bauen mit Mastra BASTA! Mainz · 2026 30 / 40
  28. Step 5 · Agent als MCP-Server import { MCPServer }

    from '@mastra/mcp' Jeder MCP-Client kann den Agenten export const triageMcpServer = new MCPServer({ id: 'triage', name: 'Issue Triage', version: '1.0.0', nutzen, etwa Claude Code agents: { triageAgent }, // → ask_triageAgent tools: { getIssue, searchIssues }, @mastra/mcp 2.x spricht die zustandslose MCP-Revision 2026-07-28, ältere Clients }) brauchen 1.x new Mastra({ mcpServers: { triageMcpServer }, … }) Workflows stellt der Server als Tool run_<name> bereit // .mcp.json (Claude Code) { "mcpServers": { "triage": { "type": "http", "url": "http://localhost:4111/api/mcp/triage/mcp" } } } Umgekehrt holt MCPClient fremde MCPTools in deinen Agenten Antworten fremder MCP-Server sind externer Input und damit nicht vertrauenswürdig. Agents bauen mit Mastra BASTA! Mainz · 2026 31 / 40
  29. Step 6 · Evals als Tests import { checks }

    from '@mastra/evals/checks' import { expectEval } from '@mastra/evals/vitest' const triageAgent = mastra.getAgentById('triage-agent') // mit Storage & Tracing test('Doppelte Abbuchung ist critical', async () => { await expectEval({ target: triageAgent, data: { input: 'Triagiere Issue #104' }, gates: [checks.calledTool('getIssue'), checks.includes('critical'), checks.noToolErrors()], }).toPass() }) Quick Checks brauchen keinen zusätzlichen Modellaufruf. Für Tonalität oder Faktentreue gibt es LLM-Scorer, für die CI runEvals mit Datasets. Agents bauen mit Mastra BASTA! Mainz · 2026 32 / 40
  30. Step 6 · Jeder Aufruf im Trace sichtbar Studio zeigt

    für jeden Run: Modellaufrufe mit Prompt, Tokens und Latenz Tool-Calls mit Ein- und Ausgabe Workflow-Schritte als Spans Die Traces lassen sich u. a. nach Langfuse, LangSmith, Datadog, Sentry oder OpenTelemetry exportieren. Für Traces brauchst du Observability und einen Storage, in der Demo DuckDB. Agents bauen mit Mastra BASTA! Mainz · 2026 33 / 40
  31. Step 7 · Runs überstehen Crashes export const durableTriageAgent =

    createDurableAgent({ agent: triageAgent, id: 'durable-triage-agent', }) // Client A startet einen Run und verliert die Verbindung … const { runId, output } = await durableTriageAgent.stream('Triagiere Issue #104') // … ein anderer Client hängt sich an und bekommt alle Chunks ab Offset 0 const { output: replay } = await durableTriageAgent.observe(runId, { offset: 0 }) new Mastra({ recovery: { durableAgents: 'auto' }, … }) // Runs nach Crash fortsetzen Beta Recovery führt die Schleife ab dem letzten Snapshot erneut aus, inklusive Tool-Calls: Tools müssen idempotent sein. Über mehrere Prozesse hinweg brauchst du ein verteiltes PubSub wie Redis. Agents bauen mit Mastra BASTA! Mainz · 2026 34 / 40
  32. Agenda Agents bauen mit Mastra BASTA! Mainz · 2026 01

    Was ist ein Agent? Theorie 02 Mastra im Überblick Theorie 03 Live: Issue-Triage in sieben Steps Praxis 04 Ausblick & Takeaways Q&A 35 / 40
  33. Was ich nicht gezeigt habe Subagents Guardrails Time Travel Ein

    Supervisor verteilt Aufgaben an spezialisierte Agents. Processors filtern Ein- und Ausgaben, z. B. PII oder Prompt Einen Workflow ab einem beliebigen Schritt neu starten. Injection. A2A Frontends Deployment Agents verschiedener Systeme AI SDK UI, Assistant UI, CopilotKit. mastra build erzeugt einen Node- sprechen miteinander. Server. Deployer u. a. für Vercel, Cloudflare und Netlify. Agents bauen mit Mastra BASTA! Mainz · 2026 36 / 40
  34. Von der Demo zur Produktion Tools pro Aufruf begrenzen Öfter

    als einmal testen Mit allen Tools hat der Agent im Workflow-Schritt in jedem Ein grüner Run beweist wenig. Solche Fehler zeigen sich zweiten Run selbst postComment aufgerufen. erst, wenn derselbe Fall zehnmal läuft. activeTools und toolChoice verhindern das. Aufrufer mitdenken Tools idempotent bauen Workflows, Evals und MCP rufen den Agenten ohne Thread Retries und Recovery führen Tool-Calls erneut aus. Ein auf. Memory, das eine threadId braucht, scheitert dort. Kommentar darf dann nicht zweimal erscheinen. Agents bauen mit Mastra BASTA! Mainz · 2026 37 / 40
  35. Takeaways 1 Workflow vor Agent So viel Workflow wie möglich,

    so viel Agent wie nötig. 2 Schemas überall Zod an Tools, Workflow-Schritten und Outputs macht LLM-Ergebnisse zu normalen Daten. 3 Menschen an die riskanten Stellen suspend() und requireApproval kosten wenige Zeilen. 4 Von Anfang an messen Traces ab Tag 1, Evals als Tests in der CI. Agents bauen mit Mastra BASTA! Mainz · 2026 38 / 40
  36. Links Folien & Kontakt Demo-Code Mastra linktr.ee/daniel_sogl github.com/danielsogl/basta- mastra.ai/docs Folien

    zum Nachlesen und Kontakt mastra-issue-triage mastra.ai/llms.txt für Coding- zu mir. Sieben Steps als Git-Tags, README Agents mit Anleitung. npx skills add mastraai/skills Agents bauen mit Mastra BASTA! Mainz · 2026 39 / 40
  37. Vielen Dank! Fragen? Immer her damit. Folien, Demo-Code und Kontakt:

    linktr.ee/daniel_sogl Daniel Sogl Bereichsleiter AI Engineering · Microsoft MVP [email protected] linkedin.com/in/daniel-sogl Folien, Code & Kontakt SHI GmbH Konrad-Adenauer-Allee 15 86150 Augsburg shi-gmbh.com