Startseite / Artikel

Tiefere Agenten mit SKILL.md: Ein LangChain-Orchestrator, der Skills lädt.

Erstelle einen generischen tiefen Agenten mit LangChain, der ein Skills-Verzeichnis durchsucht, anhand von SKILL.md-Beschreibungen leitet, das AGENTS.md-Gedächtnis teilt und ohne Codeänderungen neue Fähigkeiten erlangt.

Verlag: REACTAPP.TOP8 Min. Lesezeit1811 Wörter

Quellen: Building Deep Agents + SKILL.md with Langchain

Was wäre, wenn ein Agent keine feste Liste an Fähigkeiten hätte und erst durch Erkundung herausfinden könnte, was er tun kann? Genau dieser Ansatz wird hier verfolgt: ein funktionsfähiger tiefer Agent in LangChain, der SKILL.md-Dateien nach Bedarf lädt, um Anfragen zu beantworten. Es gibt weder fest programmierte Abläufe noch einen benutzerdefinierten Router – nur ein allgemeiner Orchestrierer, eine Ordnerstruktur mit Fähigkeiten sowie die deepagents-Bibliothek, die die schwierigen Aufgaben übernimmt.

Das Problem mit festen Werkzeugsets

Die meisten LangChain-Tutorials zeigen denselben Ablauf: Man definiert einige Werkzeuge, bindet sie an ein Modell, erstellt ein Graphen – und schon ist es fertig. Das Ergebnis ist ein flacher Agent mit einer in seinem Code festgelegten Fähigkeitsliste.

Die Alternative ist ein Orchesterator, der nicht weiß, was er tun kann, bevor er nachschaut. Während des Laufs scannt er ein skills/-Verzeichnis, liest zunächst nur die Metadaten und lädt vollständige Anweisungen herunter, sobald eine Fähigkeit zur Anfrage passt. Anstatt „dieser Agent recherchiert und schreibt“ festzuschreiben, legen Sie research/SKILL.md und writer/SKILL.md in ein Verzeichnis – der Agent erledigt den Rest. Morgen können Sie eine code-reviewer-Fähigkeit hinzufügen, und sie wird ohne dass eine Zeile Code angepasst werden muss erkannt. Das ist das SKILL.md-Muster in LangChain angewandt.

Wie die Komponenten zusammenpassen

Vier Konzepte steuern den Ablauf von agent.py:

  1. Zuerst kommt die Planung. Der Orchesterator erstellt stets einen Plan, indem er das allgemeine Ziel des Benutzers in konkrete technische Schritte umwandelt.
  • Die Delegation bleibt allgemein. Anstelle von auf bestimmte Rollen spezialisierten Experten wird die Arbeit an einen allgemein einsetzbaren Unteragenten delegiert, der über dieselben Werkzeuge sowie denselben Zugriff auf die Fähigkeitsbibliothek verfügt.
  • Das Wissen wird auf Anfrage bereitgestellt. Weder der Orchesterator noch der Unteragent kennen bei Start die spezialisierten Arbeitsabläufe. Sie finden diese über SkillsMiddleware, das die Fähigkeiten schrittweise freigibt, und laden die vollständige Dokumentation erst dann herunter, wenn sie benötigt wird.
  • Der Arbeitsbereich ist festgelegt. Werkzeuge sowie fähigkeitsbasierte Aktionen werden zur Langzeitverfügbarkeit im Verzeichnis ./workspace/ abgelegt, während das Wurzelverzeichnis weiterhin für Konfigurationen und Fähigkeiten sichtbar bleibt.
  • Das gesamte Projekt ist kompakt, und drei Dateien erledigen die eigentliche Arbeit.

    Schritt 1: Projekt einrichten

    Abhängigkeiten befinden sich in pyproject.toml:

    # pyproject.toml
    [project]
    name = "deep-agents-langchain"
    version = "0.1.0"
    requires-python = ">=3.12"
    dependencies = [
        "deepagents>=0.4.12",
        "langchain-anthropic>=1.4.0",
        "langchain-openai>=1.1.12",
        "python-dotenv>=1.2.2",
        "streamlit>=1.55.0",
        "tavily-python>=0.7.23",
    ]
    

    Die wichtigste ist deepagents, die Open-Source-Bibliothek von LangChain, die das Deep-Agent-Muster formalisiert. Aus der Box heraus bietet sie Planungsfunktionen über write_todos, Tools für das Dateisystem, Erstellung von Unteragenten über task, Komprimierung des Kontexts sowie, was besonders wichtig ist, das Laden von Fähigkeiten.

    Schritt 2: Die Tools definieren

    In agent.py ist das einzige benutzerdefinierte Tool ein Standard-Wrapper für Suchanfragen bei Tavily:

    import os
    from typing import Literal
    from dotenv import load_dotenv
    from langchain_anthropic import ChatAnthropic
    from langchain_openai import ChatOpenAI
    from tavily import TavilyClient
    from deepagents import create_deep_agent
    from deepagents.backends import FilesystemBackend
    load_dotenv()
    # --- Generic Tools ---
    tavily = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
    def internet_search(
        query: str,
        max_results: int = 5,
        topic: Literal["general", "news", "finance"] = "general",
    ):
        """Search the web for current information."""
        return tavily.search(query, max_results=max_results, topic=topic)
    

    Alles andere, also Planung, Datei-Eingabe/Ausgabe, Unteragenten sowie Ladevorgang von Fähigkeiten, stammt aus deepagents.

    Schritt 3: die Agentenfabrik

    Hier kommt alles zusammen:

    def get_deep_agent():
        model = ChatAnthropic(
            model="claude-3-5-sonnet-20240620",
            temperature=0,
        )
    return create_deep_agent(
            model=model,
            system_prompt="""You are a generic Deep Agent orchestrator.
    1. Use `write_todos` to plan complex requests.
    2. You have access to skills in the `skills/` directory.
       - You ONLY see names and descriptions initially.
       - For specialized tasks, load the matching SKILL.md first.
    3. Use the `task` tool to delegate to subagents.
    4. ALL outputs go to `./workspace/` exclusively.""",
            tools=[internet_search],
            skills=["./skills"],          # <-- This is the magic line
            memory=["./AGENTS.md"],
            backend=FilesystemBackend(root_dir="."),
            name="generic_deep_agent",
        )
    

    Drei Parameter verdienen eine genaue Betrachtung.

    skills=[„./skills“] weist deepagents an, diesen Ordner zu durchsuchen, das YAML-Frontmatter jedes gefundenen SKILL.md-Dateis zu analysieren und den Fähigkeitskatalog in die Systemanweisung aufzunehmen. Der Agent erhält etwas in der Art davon:

    Available Skills:
    - research: "Conducts comprehensive web research on any topic..."
    - writer: "Specialized in writing high-quality content..."
    

    Für zwei Fähigkeiten kostet das etwa 200 Tokens. Der Agent liest den Katalog und entscheidet, welche Fähigkeit für die Anfrage geladen werden soll. Es handelt sich dabei um reine LLM-Routeierung, ohne Klassifikatoren, Embeddings oder reguläre Ausdrücke.

    memory=[„./AGENTS.md“] lädt die projektbezogenen Konventionen in den Systemprompt. Er dient als gemeinsamer Kontext für den Hauptagenten und jeden Unteragenten – eine Art „Wie wir hier vorgehen“-Seite für das Team.

    backend=FilesystemBackend(root_dir=„.“) stellt dem Agenten Dateifunktionen (read_file, write_file, edit_file) zur Verfügung, wobei das Projektverzeichnis als Wurzel dient; dadurch wird das Dateisystem zum dauerhaften Arbeitsbereich des Agenten.

    Schritt 4: Die Fähigkeiten schreiben

    Eine absichtlich einfache Forschungsfähigkeit:

    ---
    name: research
    description: >
      Conducts comprehensive web research on any topic using search APIs
      and web scraping. Use when the user asks for research, information
      gathering, competitive analysis, or needs current data from the web.
    license: MIT
    compatibility: Requires internet access and Tavily API key
    allowed-tools: internet_search Read Write
    ---
    # Web Research Skill
    ## Instructions
    1. Parse the research query to identify key topics.
    2. Use the `internet_search` tool to gather initial results.
    3. If results are insufficient, try alternative search queries.
    4. Synthesize findings into a structured summary.
    5. Save detailed findings to `./workspace/` as a markdown file.
    

    Und eine Schreibfähigkeit:

    ---
    name: writer
    description: >
      Specialized in writing high-quality, creative, and technical content.
      Use when the user needs a blog post, report, technical guide,
      or any form of structured writing.
    license: MIT
    ---
    # Creative Writer Skill
    ## Instructions
    1. Review the input notes or research data provided.
    2. Define an outline (Introduction, Body, Conclusion).
    3. Use a tone appropriate for the target audience.
    4. Ensure all claims are backed by provided data.
    5. Save the final draft to `./workspace/`.
    

    Jedes Datei enthält YAML-Frontmatter, das als Identifikationskarte der Fähigkeit dient, gefolgt von einem Markdown-Körper, der als Handlungsanleitung fungiert. Der Agent sieht das Frontmatter auf Ebene 1 und den Körper nur auf Ebene 2. Dies entspricht der Spezifikation, die auf agentskills.io veröffentlicht wurde.

    Schritt 5: gemeinsamer Speicher in AGENTS.md

    Diese Datei wird stets geladen. Sie gibt jedem Agenten an, wer was tut und wie das Team arbeitet:

    # Project Context: Deep Agents Demo
    ## Conventions
    - Skills are stored as directories under `skills/`.
    - Every skill must have a `SKILL.md` file.
    - Subagents should be used for complex, multi-step tasks.
    - All intermediate work goes to `./workspace/`.
    ## Known Entities
    - **Main Agent**: The orchestrator who plans and delegates.
    - **Researcher**: Specialized in web search and data aggregation.
    - **Writer**: Specialized in formatting and synthesizing information.
    

    Wie das Routing tatsächlich funktioniert

    Es gibt weder einen Router noch einen Klassifikator, denn das LLM übernimmt selbst das Routing. Wenn die Bibliothek den Systemprompt erstellt, fügt sie Texte in dieser Art hinzu:

    You have access to a library of skills in the `skills/` directory.
    You ONLY see names and descriptions initially.
    For any specialized task, look for matching skills and use
    `read_file` to load the SKILL.md before executing.
    Available skills:
    - research: "Conducts comprehensive web research..."
    - writer: "Specialized in writing high-quality content..."
    

    Das Modell liest die Nachricht des Benutzers sowie die Beschreibungen der Fähigkeiten und entscheidet anschließend, ob es read_file("skills/research/SKILL.md") aufruft oder nichts tut. Die gesamte Entscheidung erfolgt innerhalb des Forward-Passes des Transformers, ohne externe Logik. Mit anderen Worten: Die Beschreibung der Fähigkeit dient als Routing-Engine – ein gut geschriebener Text mit Auslösewörtern und negativen Grenzen reicht aus.

    Die Streamlit-Oberfläche

    app.py umschließt alles in einer Streamlit-Schnittstelle, die das Denken des Agenten in Echtzeit anzeigt. LangGraphs stream("updates") erzeugt ein Ereignis für jede Knotenausführung, und die Anwendung wandelt diese in Toolaufrufe, Indikatoren zum Laden von Fähigkeiten, Planaktualisierungen sowie die endgültige Antwort um.

    Hinzufügen einer Fähigkeit ohne Codeänderungen

    Nehmen wir an, Sie möchten eine Fähigkeit für Code-Reviews. Erstellen Sie dazu einen Ordner neben den anderen:

    skills/
    ├── research/
    │   └── SKILL.md
    ├── writer/
    │   └── SKILL.md
    └── code-reviewer/
        └── SKILL.md
    

    Dann schreiben Sie dessen SKILL.md:

    ---
    name: code-reviewer
    description: >
      Reviews code for bugs, security issues, and best practices.
      Use when the user asks for a code review, security audit,
      or wants feedback on code quality. Do NOT use for writing
      new code or debugging runtime errors.
    license: MIT
    allowed-tools: Read Write
    ---
    # Code Review Skill
    ## Instructions
    1. Read the target file using `read_file`.
    2. Analyze for: bugs, security issues, performance, readability.
    3. Write a structured review to `./workspace/review.md`.
    

    Starten Sie die App erneut – dann weiß der Agent, wie er Code überprüfen soll. agent.py wurde unverändert gelassen, genauso wie der Systemprompt. Sie haben lediglich einen Ordner hinzugefügt, nichts weiter. Der gleiche Ansatz führt zu ausgefeilteren Deep-Agents.

    Lektionen, die daraus hervorgingen

    • Skill-Beschreibungen sind wichtiger als Skill-Anweisungen. Wenn die Beschreibung ungenau ist, wird die Fähigkeit niemals aktiviert. Die Anpassung des description-Feldes mit seinen Auslösewörtern sowie negativen Grenzen wie „Verwenden Sie nicht für...“ dauerte länger als das Schreiben des eigentlichen Skill-Textes, da dieser die Routing-Logik enthält.
    • Das Dateisystem wird unterschätzt. Viele Agent-Tutorials speichern alles im Nachrichtenverlauf – das eignet sich für einfache Anwendungen, funktioniert aber nicht bei mehrstufigen Aufgaben. Das Speichern von Zwischenergebnissen in ./workspace/ und das Erlauben, dass Sub-Agents sie lesen, sorgt dafür, dass alle Komponenten richtig zusammenwirken.
  • AGENTS.md verbindet alles miteinander. Ohne dieses Dokument arbeiten der Orchestrator sowie seine Unteragenten jeweils eigenständig. Mit ihm teilen sie Konventionen, kennen die Projektstruktur und vermeiden doppelte Arbeit – ein kleines Datei mit großer Wirkung.
  • Beginnen Sie mit einer allgemeinen Struktur und spezialisieren Sie sich durch Fähigkeiten. Es ist verlockend, Fachwissen direkt in den Systemprompt einzubauen, doch wenn der Orchestrator allgemein bleibt und jede Spezialisierung in SKILL.md-Dateien abgelegt wird, wird das System modular und testbar. Fähigkeiten können ausgetauscht werden, ohne den Agenten anzufassen.
  • Was eine Produktionsversion hinzufügen würde

    Diese App ist absichtlich minimal gestaltet. Eine echte Implementierung würde voraussichtlich persistente Speicherung über LangMem für episodisches und semantisches Abrufen zwischen Sitzungen beinhalten, Integration von MCP für Unternehmenswerkzeuge wie Slack, Jira und Datenbanken, Kontrollpunkte mit menschlicher Beteiligung mithilfe des Unterbrechungsmechanismus von LangGraph, Komprimierung des Kontexts für lange Forschungsarbeiten – und natürlich weitere Fähigkeiten, wobei jede lediglich ein Ordner mit einer SKILL.md-Datei ist.

    Die Richtung der Entwicklung scheint klar zu sein. Beim Erstellen von Agenten geht es weniger darum, mehr Code zu schreiben, sondern vielmehr darum, bessere SKILL.md-Dateien zu erstellen. Das Framework kümmert sich um die technischen Aspekte, die Fähigkeiten tragen das Fachwissen und der LLM entscheidet, wann welche verwendet werden soll.