Freue Dich Vor Deinem Ai Agenten Automatische Zeiterfassung Mit Langgraph Und Meta Llama 3 Freue Dich Vor Deinem Ai Agenten Automatische Zeiterfassung Mit Langgraph Und Meta Llama 3

Freue Dich vor Deinem AI-Agenten: Automatische Zeiterfassung mit LangGraph und Meta Llama 3

Als Freelancer ist die Genauigkeit meiner Rechnungsstellung von entscheidender Bedeutung. Dazu gehört die genaue Erfassung meiner Arbeitsstunden. Ich möchte diese täglich erfassen, um meine Aktivitäten so frisch wie möglich zu erfassen.

Trotz meiner besten Absichten führt der tägliche Wirbel der Aufgaben jedoch oft zu Versehen. Dies kann dazu führen, dass ich meinen Tag mühsam rekonstruieren muss, ein Prozess, der nicht nur zeitaufwendig, sondern auch frustrierend ist.

Fasziniert von der Fähigkeit von künstlicher Intelligenz, komplexe Aufgaben zu vereinfachen, habe ich eine AI-getriebene Lösung zur Automatisierung der Stundenregistrierung entwickelt. Dieser Artikel beschreibt meine Bemühungen, meinen täglichen Routineablauf zu optimieren und sicherzustellen, dass keine entscheidende Detail übersehen wird.

Das Ziel ist es, wertvolle Zeit und mentale Energie zu sparen und mich auf das zu konzentrieren, was wirklich zählt: die Arbeit.

Du findest den Quellcode des finalen Agents in diesem öffentlichen GitHub Repository.

Der Registrierungsprozess

Bevor wir uns den Details des Aufbaus des AI-Agents widmen, schaffen wir eine solide Vorstellung davon, wie ich die Stundenregistrierung automatisieren möchte.

Hier ist der Kontextdiagramm der Lösung. Es besteht aus vier Modulen, die jeweils einen Teil der Funktionalität implementieren. Ich werde jede Komponente und deren Rolle beschreiben und wie sie gemeinsam das System bilden, um meine tägliche Zeiterfassung zu optimieren.

Auto Draft

  1. Kundenidentifikation Dieses Modul beginnt damit, den Kunden für die Tagesstundenprotokolle zu identifizieren. Da mein Arbeitsplan bestimmte Tage mit bestimmten Kunden zuordnet, prüft der Agent den aktuellen Wochentag und wählt den entsprechenden Kunden.Diese Zuordnung ist in Python hartcodiert, um unsere anfängliche Einrichtung einfach zu halten. Die Ausgabe ist ein entscheidendes Detail: der Name des Kunden, den wir benötigen, um die folgenden Schritte der Automatisierung fortzusetzen.
  2. Aufgabenabruf Nach der Kundenidentifikation nutzt das zweite Modul den erhaltenen Kundennamen, um die heute abgeschlossenen Aufgaben abzurufen.Mein tägliches Organisationswerkzeug ist Todoist, wo ich meine Aufgaben erstelle. Dieses Modul filtert und extrahiert die Aufgaben, die ich für den identifizierten Kunden als abgeschlossen markiert habe, indem es mit der Todoist API zusammenarbeitet.

    Die Ausgabe ist eine Sammlung von Beschreibungen für jede abgeschlossene Aufgabe, die die Voraussetzung für das darauf folgende Registrierungsmodul bildet.

  3. Erstellung von Aufgabenzusammenfassung mit LLM Das dritte Modul fasst die einzelnen Aufgabenbeschreibungen in eine einheitliche Zusammenfassung zusammen. Mit den Fähigkeiten eines großen Sprachmodells, speziell der Meta Llama 3 8B Variante, generiert es eine umfassende Erzählung der heutigen Erfolge.Das Ergebnis ist eine kurze Textzeichenfolge, die die Essenz der abgeschlossenen Aufgaben kapselt und für den letzten Schritt, die Zeiterfassung, bereit ist.
  4. Zeiterfassung Das letzte Modul ist für die Erfassung der Arbeitsstunden verantwortlich. Um die Einfachheit willen standardisiert es die Zeiteintragung auf acht Stunden pro Tag. Da meine Buchhaltungsanwendung keine API hat, verwendet dieses Modul Selenium WebDriver, um die Web-Schnittstelle zu automatisieren.Es gibt die kohärente Aufgabenzusammenfassung und die festgelegten Stunden in das System ein, was die Tageszeiterfassung abschließt.

Nachdem wir die Stunden erfasst haben, können wir uns anschauen, wie wir den Prozess implementieren werden. Der erste Schritt besteht darin, einen AI-Agenten-Framework auszuwählen.

Welches AI-Agenten-Framework?

Der Markt ist voll mit AI-Frameworks, die jeweils einzigartige Fähigkeiten bieten und ständig neue erscheinen. Ursprünglich habe ich mit Crew AI experimentiert, das in sozialen Medien für Aufsehen gesorgt hat.

Allerdings habe ich Schwierigkeiten gehabt, Standard-Python-Funktionen in den Agenten mit diesem Framework zu integrieren. Obwohl die Crew AI-Dokumentation die Unterstützung für die lokale LLM-Nutzung vorschlägt, benötigte das System stets einen OpenAI-API-Schlüssel, ein Hindernis, das ich nicht überwinden konnte. Ich werde möglicherweise wieder zu Crew AI zurückkehren, aber ich setze meine Suche nach einem anderen Framework vorerst fort.

Meine Suche nach einer anpassungsfähigeren Lösung führte mich zu LangGraph, einer robusten Bibliothek, die dafür konzipiert ist, statusbehaftete, mehrakteure Anwendungen auf LangChain aufzubauen.

Die ersten Tests waren vielversprechend; die Integration von Standard-Python-Funktionen erschien unkompliziert. Meine Vertrautheit mit LangChain legte auch eine solide Grundlage für die effektive Nutzung von LangGraph.

Der Prozess in LangGraph übersetzen

LangGraph ist eine Bibliothek, die dazu konzipiert ist, statusbehaftete, mehrakteure Anwendungen zu erstellen. Man kann sie als eine neue Möglichkeit betrachten, Agenten mit LangChain auszuführen.

In LangGraph erstellen Sie Knoten, die verschiedene Schritte in Ihrem Arbeitsablauf darstellen. Jeder Knoten umschließt in der Regel eine bestimmte Aufgabe oder Funktion. Sie verbinden dann diese Knoten mit Kanten, um ein gerichtetes Diagramm zu bilden, das den Ablauf der Anwendung umschreibt.

Die Kanten bestimmen den Ausführungspfad von einem Knoten zum nächsten, ermöglichenden die Erstellung komplexer Arbeitsabläufe, die eine Vielzahl von Prozessen und Datentransformationen verarbeiten können. Diese Struktur ermöglicht eine dynamische Interaktion zwischen verschiedenen Anwendungsteilen, wie vom in dem Diagramm des Graphen festgelegten Fluss vorgegeben.

Also, um unser funktionales Kontextdiagramm zu übersetzen, müssen wir jedes Modul in eine Python-Funktion umwandeln. Die Kommunikation zwischen diesen Funktionen oder Knoten erfolgt über ein Zustandsobjekt.

Auto Draft

Jeder Knoten wird mit dem Zustand übergeben und kann diesen falls erforderlich ergänzen. Ein Knoten kann, indem er einen Wert aus der Knotenfunktion zurückgibt, etwas im Zustand speichern.

Verständnis des Agent State in LangGraph

Im LangGraph verwaltet und bewahrt das Zustandsobjekt den Kontext über verschiedene Interaktionen und Schritte in einer mehrakteure Anwendung.

Um dies zu veranschaulichen, werfen wir einen Blick auf die AgentState Klasse aus dem Stundenregistrierungsprojekt, die sich mit der Todoist-API verbindet, um Aufgaben zu verwalten. Jede Information, die zwischen den Modulen fließt, ist in der Klasse enthalten.

class AgentState(TypedDict):
    # Der Kundenname, nach dem in der Todoist-API gesucht werden soll
    customer_name: str
    # Die Beschreibungen der abgeschlossenen Aufgaben
    task_descriptions: List[str]
    # Die kombinierte Beschreibung jeder Aufgabenbeschreibung, die vom LLM erstellt wurde
    registration_description: str

Später werden wir uns ansehen, wie dieses Zustandsobjekt in LangGraph integriert wird. Zunächst werfen wir einen Blick auf die Knoten, die unseren Zeiterfassungsagenten bilden.

  1. Kundenidentifikation Der erste Knoten ist der customer_name_node. Wie Sie unten sehen, ist ein Knoten eine normale Python-Funktion.Wenn Sie genau hinschauen, sehen Sie, dass die Funktion einen Zustandsobjekt erhält, jedoch nicht verwendet und den ausgewählten Kunden über return {"customer_name": customer_name} speichert. Diese letzte Anweisung speichert den ausgewählten Kundennamen im Zustand.

    Ich mag die Möglichkeit, normale Python-Funktionen in LangGraph zu integrieren. Die Funktion selbst ist nicht besonders; sie prüft, an welchen Wochentag es ist und gibt basierend darauf den Kundennamen zurück. Beachten Sie, dass zum Schutz der Privatsphäre meiner Kunden ihre Namen in Umgebungsvariablen gespeichert sind.

import datetime
import os
from loguru import logger
def customer_name_node(state):
    CUSTOMER1 = os.getenv("CUSTOMER1")
    CUSTOMER2 = os.getenv("CUSTOMER2")
    weekday = datetime.datetime.now().weekday()
    customer_name = CUSTOMER1 if weekday < 3 else CUSTOMER2
    logger.info(f"Kundenname für heute (Wochentag {weekday}) ist {customer_name}.")
    return {"customer_name": customer_name}
  1. Aufgabenabruf Der zweite Knoten, task_fetcher_node, stellt eine Verbindung zur Todoist-API her und ruft die Aufgaben ab, die ich für diesen Kunden heute abgeschlossen habe. Unten verwendet es den Zustand, um den Kundennamen über customer_name = state["customer_name"] abzurufen.Sobald die task_fetcher_node ihre Funktion ausgeführt hat, speichert sie eine Liste der Aufgabenbeschreibungen im Zustand. Die Funktion selbst, zusammen mit ihren Hilfsfunktionen, ist auf GitHub zur Referenz verfügbar. Der Knoten verwendet das Todoist PyPI-Paket.
def task_fetcher_node(state):
    api = initialize_todoist_api()
    customer_name = state["customer_name"]
    project_id = get_project_id(api, project_name)
    done_section_id = get_done_section(api, project_id)
    tasks = get_sections_tasks(api, done_section_id)
    task_descriptions = [task.content for task in tasks]
    return {"task_descriptions": task_descriptions}
  1. Erstellung von Aufgabenzusammenfassung

Der dritte Knoten verwendet ein entferntes LLM, um die Beschreibungen jeder Aufgabe in eine einheitliche Beschreibung zu kombinieren, die für die Registrierung verwendet werden kann.

Ich verwende das LLAMA 8B Modell von Meta über Groq. Wenn Sie Groq nicht kennen, sollten Sie es sich ansehen! Groq ist ein Unternehmen für generative KI-Lösungen und der Schöpfer des LPU™ Inference Engine. Das ist ein sehr schnelles Inferenzmodul, das auf ihren eigenen benutzerdefinierten Hardware läuft.

Die gute Nachricht ist, dass sie eine API anbieten (derzeit kostenlos), über die Sie mit vier verschiedenen LLMs interagieren können. Sie können sich anmelden und einen API-Schlüssel von ihrem Playground erhalten. Derzeit bieten sie über ihre API folgende Modelle an:

  • Gemma 7B (8K Kontextlänge)
  • Llama 3 8B (8K Kontextlänge)
  • Llama 3 70B (8K Kontextlänge)
  • Mixtral 8x7B SMoE (32K Kontextlänge)

Ich habe das Llama 3 8B Modell gewählt, was mehr als ausreichend ist, um die kombinierte Aufgabenbeschreibung zu generieren.

Unten sehen Sie den time_registration_description_node_llm Knoten. Es verwendet das langchain groq PyPI-Paket, um mit der Groq-API zu interagieren. Sie sehen das bekannte Übergeben des Zustands und das Zurückgeben der von dem LLM generierten Beschreibung.

Sie könnten sich ein paar Dinge anschauen. Erstens können Sie sehen, wie der Prompt aufgebaut ist, um dem LLM die Anweisung zu geben, die Aufgabenbeschreibung zu generieren und das Ergebnis als JSON mit einem Schlüssel namens ‚registration_description‘ zurückzugeben.

Zweitens gibt es den Generator-Aufbau task_combination_generator = task_combination_prompt | GROQ_LLM | JsonOutputParser().

Dies verwendet, was LangChain die LangChain Expression Language (LCEL) nennt. LCEL erleichtert das Erstellen von komplexen Ketten aus grundlegenden Komponenten und unterstützt out-of-the-box-Funktionen wie Streaming, Parallelität und Protokollierung.

In unserem Projekt kombinieren wir den Prompt, das Modell und den JSON-Ausgabeparser.

from langchain.prompts import PromptTemplate
from langchain_groq import ChatGroq
from langchain_core.output_parsers import JsonOutputParser
MODEL_NAME = "Llama3-8b-8192"
REGISTRATION_KEY = "registration_description"
def time_registration_description_node_llm(state):
    GROQ_LLM = ChatGroq(model=MODEL_NAME)
    task_descriptions = state.get("task_descriptions")
    if task_descriptions is None:
        raise ValueError("Fehlender Aufgabenbeschreibungen im Zustand.")
    task_combination_prompt = PromptTemplate(
        template="""\
        system
        Sie sind ein Experte im Schreiben von Aufgabenbeschreibungen für die Registrierung von Arbeitsstunden in der Buchhaltung.
        Ihnen werden mehrere Aufgabenbeschreibungen gegeben, und Sie werden gebeten, sie in eine zusammenhängende Beschreibungszeichenfolge zu kombinieren.
        Gibt nur die generierte Beschreibung mit JSON unter einem Schlüssel namens 'registration_description' zurück.
        Gibt keine anderen Zeichenketten zurück.
        user
        TASK_DESCRIPTIONS: {task_descriptions}
        assistant""",
        input_variables=["task_descriptions"],
    )
    task_combination_generator = task_combination_prompt | GROQ_LLM | JsonOutputParser()
    description_data = task_combination_generator.invoke({"task_descriptions": task_descriptions})
    registration_description = description_data.get(REGISTRATION_KEY)
    if registration_description is None:
        raise ValueError("Fehler beim Erstellen der Registrierungsbeschreibung.")
    return {REGISTRATION_KEY: registration_description}
  1. Zeiterfassung Der letzte Knoten ist der data_entry_node, der für die Registrierung der von dem LLM erstellten kombinierten Beschreibung in meiner Buchhaltungsanwendung verantwortlich ist. Wie zuvor beschrieben, bietet mein Buchhaltungsdienst keine API. Daher verwendet der Knoten den Selenium-Webdriver, um das Eintragen der Zeitregistrierung zu automatisieren.

Ein wichtiges Merkmal davon ist die Implementierung der Zwei-Faktor-Authentifizierung mit TOTP durch die Webanwendung. Ich habe die Eingabe von TOTP-Codes erfolgreich mit dem Pyotp-Paket von PyPi automatisiert. Dafür ist der Zugriff auf das TOTP-Geheimnis, das während der anfänglichen Einrichtung der Zwei-Faktor-Authentifizierung erstellt wurde, unerlässlich.

def data_entry_node(state):
    driver = setup_driver()
    try:
        customer = state["customer_name"]
        description = state["registration_description"]
        login(driver)
        enter_totp_code(driver)
        navigate_to_time_entry_page(driver)
        enter_time_details(driver, customer, description)
    except Exception as e:
        logger.exception(f"Beim Dateneingabeprozess ist ein Fehler aufgetreten. {e}")
    finally:
        driver.quit()
        logger.info("WebDriver wurde geschlossen.")

Ich habe nur die Hauptfunktion gezeigt; wenn Sie an den restlichen Hilfsfunktionen interessiert sind, sehen Sie sich den vollständigen Quellcode des Knotens auf GitHub an.

Mit allen implementierten Knoten sind wir bereit, sie in LangGraph zu kombinieren.

Erstellung des LangGraph-Diagramms

Auto Draft

Zuerst erstellen wir die StateGraph Instanz und übergeben ihr unseren Typ, der unseren Zustand AgentState enthält. Dann fügen wir jeden der Knoten dem Diagramm hinzu. Die Funktion add_node erwartet:

  • key: Eine Zeichenfolge, die den Namen des Knotens darstellt. Dieser muss eindeutig sein.
  • action: Die auszuführende Aktion, wenn dieser Knoten aufgerufen wird. Dies sollte entweder eine Funktion oder ein Laufzeitobjekt sein.
workflow = StateGraph(AgentState)
workflow.add_node("customer_name_node", customer_name_node)
workflow.add_node("task_fetcher_node", task_fetcher_node)
workflow.add_node("time_registration_description_node_llm", time_registration_description_node_llm)
workflow.add_node("data_entry_node", data_entry_node)

Mit den Knoten hinzugefügt, fügen wir sie mit Kanten weiter an. Wir legen zuerst den Eingangspunkt des Diagramms auf den customer_name_node fest. Dann verbinden wir jeden Knoten und beenden mit der Verbindung des data_entry_node zur END-Zeichenfolge. Wir signalisieren LangGraph, dass dies das Ende unseres Diagramms ist.

workflow.set_entry_point("customer_name_node")
workflow.add_edge("customer_name_node", "task_fetcher_node")
workflow.add_edge("task_fetcher_node", "time_registration_description_node_llm")
workflow.add_edge("time_registration_description_node_llm", "data_entry_node")
workflow.add_edge("data_entry_node", END)

Sobald wir das Diagramm erstellt haben, kompilieren wir es mit der compile-Methode. Während der Kompilierung validiert LangGraph das Diagramm; zum Beispiel, wenn Sie einen Knoten vergessen verbinden oder das Diagramm nicht schließen, wird es Ihnen während der Kompilierung sagen.

Schließlich starten wir das Diagramm über die stream-Methode, übergeben ihr eine leere Eingabe.

app = workflow.compile()
for s in app.stream({}):
    print(list(s.values())[0])

Ich verwende die stream-Methode anstelle von invoke, weil Sie dann die von jedem Knoten zurückgegebenen Werte ausgeben kann, was hilfreich für die Ablaufverfolgung ist. Ich verwende auch das loguru PyPi Protokollierungspaket, um zusätzliches Protokollieren in den Knoten für die Ablaufverfolgung hinzuzufügen, wie Sie unten sehen können.

Führen Sie den Agenten aus

Der vollständige Quellcode für diesen Agenten ist auf GitHub verfügbar. Unten finden Sie schrittweise Anweisungen zur Konfiguration und Ausführung des Agents auf Ihrem lokalen Computer. Denken Sie daran, dass das Ausführen des vollständigen Programms möglicherweise nicht gerade einfach ist aufgrund der erforderlichen spezifischen Umgebungseinstellungen, einige davon beinhalten das Erstellen von Konten für den Zugriff auf notwendige APIs.

Umgebungseinrichtung

Der Agent hängt von mehreren Umgebungsvariablen ab, die sicher in einer .env-Datei gespeichert werden sollten. Um sensible Informationen zu schützen, sollte diese Datei nicht in die Quellordnung aufgenommen werden! Das Programm verwendet das dotenv PyPi-Paket, um diese Umgebungsvariablen zu verwalten, welches die Einstellungen aus der .env-Datei lädt, wenn der Agent startet.

Hier sind die wichtigen Umgebungsvariablen, die Sie definieren müssen:

  • CUSTOMER1 und CUSTOMER2: Diese Variablen stellen die Namen der Kunden dar. CUSTOMER1 wird für Montag, Dienstag und Mittwoch verwendet, während CUSTOMER2 für den Rest der Woche gilt.
  • TODOIST_API_KEY: Dieser Schlüssel ermöglicht dem Agent, mit Ihrem Todoist-Konto zu interagieren. Sie können ihn selbst auf der Integrationsseite Ihres Todoist-Kontos generieren.
  • GROQ_API_KEY: Dies ist erforderlich für den Zugriff auf die Dienste von Groq, den Sie erhalten, indem Sie ein Konto bei Groq erstellen und zu ihrem Playground navigieren.
  • LOGIN_URLBASE_TIME_ENTRY_URLEMAILPASSWORDTOTP_SECRET: Diese Einstellungen sind spezifisch für MoneyMonk, eine Software für niederländische Einzelunternehmer (ZZPs). Sie sind für die Funktionalität der Software, insbesondere für Anmelde- und Zeiteintragsfunktionen, von entscheidender Bedeutung.

Installation der Abhängigkeiten

Das Programm verwendet eine Vielzahl von PyPi-Paketen. Diese können über pip oder conda installiert werden, abhängig von Ihren Vorlieben. Führen Sie die folgenden Befehle in Ihrem Terminal aus, um Ihre Umgebung einzurichten:

Für pip-Benutzer:

pip install -r requirements.txt

Für conda-Benutzer:

conda env create -f environment.yml

Führen Sie den Agenten aus

Sobald Sie Ihre Umgebung konfiguriert und alle Abhängigkeiten installiert haben, können Sie den Agenten ausführen, indem Sie das Hauptskript ausführen:

python hour_registration.py

Zusätzliche Tipps

  • Überprüfen Sie das Beispiel für .env: Überprüfen Sie das Repository auf die Beispieldatei .env.example, um sicherzustellen, dass Sie alle erforderlichen Schlüssel und Einstellungen korrekt eingerichtet haben.
  • Überprüfen Sie den API-Zugriff: Bevor Sie den vollständigen Agenten ausführen, stellen Sie sicher, dass Ihre API-Schlüssel aktiv sind und die richtigen Berechtigungen auf externen Plattformen eingerichtet sind.
  • Sicherheitspraktiken: Halten Sie Ihre .env-Datei sicher und teilen Sie sie niemals öffentlich. Zögern Sie nicht, Tools oder Dienste zu verwenden, um Geheimnisse, insbesondere in der Produktion, zu verwalten.

Was kommt als nächstes?

Meine Erforschung von LangGraph und AI-Agents hat gerade erst begonnen, und ich bin aufgeregt über den weiteren Weg.

Sicher, das Programm, das ich entwickelt habe, könnte wahrscheinlich auch mit einer einfachen Python-Funktion gemacht werden – keine fancy AI-Agents nötig. Aber es gibt etwas wirklich Belohnendes daran, in neue Frameworks wie dieses einzutauchen. Sie helfen mir, meine alltäglichen Aufgaben zu optimieren und meine Grenzen als Entwickler herauszufordern.

Derzeit ist der Agent noch nicht perfekt. Er ist noch etwas wackelig und benötigt eine robustere Fehlerbehandlung – zum Beispiel, nicht abstürzen, wenn ich keine täglichen Aufgaben protokolliert habe. Aber ich lebe nach dem Motto:

„Erst funktioniert es, dann richtig und schließlich optimieren.“

Ich freue mich, diese Herausforderungen schrittweise anzugehen.

Eine Funktion, die ich besonders gerne erforschen möchte, sind die bedingten Kanten von LangGraph, die es Ihnen ermöglichen, Knoten dynamisch basierend auf bestimmten Bedingungen zu navigieren. Ich sehe hier viel Potenzial, um meinen täglichen Arbeitsablauf effizienter und intelligenter zu gestalten.

Als ich dieses AI-getriebene Zeiterfassungssystem verfeinere und verbessere, bin ich gespannt auf andere, die ähnlichen Reisen unternehmen oder neugierig sind , damit anzufangen.

Haben Sie Gedanken, Fragen oder Einblicke darüber, wie Sie AI in Ihren täglichen Arbeitsabläufen nutzen? Bitte teilen Sie sie in den Kommentaren – ich freue mich darauf, von Ihren Erfahrungen zu lernen und über neue Möglichkeiten zu diskutieren.

Lassen Sie uns gemeinsam diese aufregenden Technologien erkunden und sehen, wohin sie uns führen können.

Viel Erfolg beim Lernen und Programmieren!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert