Slack my Documents – AI in der Praxis

Slack My Documents – AI in der Praxis

Avatar von Johann-Peter Hartmann

Dieser Blogpost könnte auch „Slack with Your PDFs“ oder „Chat with Your PPTs“ heißen. Derzeit schießen solche AI-Startups wie Pilze aus dem Boden – es werden AI-Berater, Contentproduzenten und kluge Assistenten im Wochentakt gelaunched.

Meist verkaufen diese Dienste keine große Eigenleistung, sondern bieten nur einfache Adaptionen oder Integration bereits vorhandener Dienste, aufbereitet mit einem modernen Webinterface. Es handelt es sich nur um wenige Zeilen Glue-Code, um bestehendes Wissen mithilfe eines VectorStores in ChatGPT nutzbar zu machen.

Dabei helfen einem Werkzeuge wie LangChain und LlamaIndex, die alles mitbringen, was man dazu braucht. Aber schauen wir uns so eine Real-Life-AI-Anwendung doch mal im Detail an. 

Übrigens: Jeder kann schnell einen Slackbot mit AI entwickeln – wer ihn selbst nutzen möchte, findet ihn auf GitHub.

Werkzeuge

Werfen wir zunächst einmal einen Blick auf die Werkzeuge, die wir einsetzen werden.

OpenAI

Auch wenn die meiste Zeit über von OpenAIs ChatGPT in den Versionen 3.5 und 4 gesprochen wird – und da vor allem über das Chat-Interface – ist das eigentlich spannende das API. Im Gegensatz zum Chat, der sich vor allem an Konsumenten richtet – und dessen Datenschutzbestimmungen auch die Weiterverwertung er Eingaben erlauben – genießt das API Vertraulichkeit der eigenen Daten und bietet mehr Requests und freie Wahl des Modells. 

In der direkten Verwendung des API stand zunächst das Prompt Engineering im Vordergrund, also die Entwicklung passender Eingabeketten, um bestimmte Ergebnisse zu erreichen. Seit zwei Wochen hat sich der Fokus auf Plugins gedreht, mit denen man nicht nur externe und echtzeitige Services einbinden, sondern auch selbst bereitstellen kann. 

Die Technologie dahinter ist nicht ganz neu; solche Plugins und Echtzeit-Integrationen waren mit den bestehenden Tools auch vorher schon möglich. Freundlicherweise sind diese Werkzeuge Open Source, so können wir sie selbst kostenfrei und als Teil eigener Lösungen einsetzen.

LangChain

Wenn ein Entwickler eine Python-Library herausbringt und dann 5 Monate später als Start-up bei einer Bewertung von über 200 Millionen landet, dann spricht das für diese Library. Als einfache Python- bzw. JavaScript-Library gestartet, ist LangChain inzwischen das wichtigste Framework, wenn es um die Entwicklung eigener Lösung auf Basis der großen Sprachmodelle (Large Language Models wie GPT4) geht. 

Folgende Werkzeuge bringt LangChain mit: 

  • Modelle: Hier kann man nicht nur OpenAI ansprechen, sondern auch andere, ebenfalls freie und lokale Modelle einbinden. Es gibt neben den normalen Sprachmodellen auch expliziten Support von Chatmodellen und Embeddings, die man etwa zur Speicherung von Daten in Vektordatenbanken nutzen kann. Im unserem Beispiel setzen wir beides von OpenAI ein. 
  • Prompts: Hierbei handelt es sich um das bekannte Prompt Engineering. Allerdings nicht nur anhand vieler Beispiele und Vorlagen, sondern auch mit der Möglichkeit über Templates, Selektoren für Beispieldaten und Output Parser für die verschiedenen Antworttypen, die durch die Prompts zustande kommen, zum Ziel zu kommen.
  • Indizes: Alles, was eigene Daten angeht. Vom Import praktisch beliebiger Daten über die Speicherung derselben bis zum Herausfischen der relevanten Daten über den nächsten Nachbar oder Supportvektoren. Quasi das Langzeitgedächtnis der eigenen AI-Lösung. In unserem Beispiel setzen wir diese Werkzeuge zum Datenimport und zur Datenspeicherung sowie -recherche ein.
  • Memory: das Kurzzeitgedächtnis. Hier verfolgt man z. B. den Chatverlauf, um bei Rückfragen den bisherigen Kontext weiternutzen zu können.
  • Chains: Hier steckt die eine Hälfte der Magie. Chains erlauben es, verschiedene Anfragen aufeinander aufzubauen. Es gibt eine Vielzahl praktischer Vorlagen; von der Recherche in Dokumenten – wie in unserem Beispiel – bis hin zur Constitutional AI, bei der die AI selbst für die eigene Qualitätssicherung sorgt.
  • Agents: Hier wird die AI nützlich. Agenten erlauben die Kommunikation mit der Außenwelt (bei OpenAI PlugIns genannt), sowie die automatische Wahl von Strategien und Tools. Strategien wie Reason & Act (ReAct) oder MRKL (Modular Reasoning, Knowledge and Language – zu Recht „Miracle“ ausgesprochen) finden sich hier. Die berühmt gewordenen AutoGPT und BabyAGI gehören zu dieser Art von Agenten. Wer das ganze auf LangChain sehen möchte, findet hier ein Beispiel, dass wir auf eine lokale LLM portiert haben. Aber dazu mehr in einem späteren Blogartikel.

LlamaIndex

Bis vor einer Weile nannte sich diese Library noch GPTIndex und man findet noch viele Spuren des alten Namens. Da nun aber nicht mehr alles OpenAI und ChatGPT ist, hat man sich zu Recht entschieden, den Namen auf das neutralere LlamaIndex zu ändern. 

Hier finden sich zusätzlich zu der bereits vorgestellten Mannigfaltigkeit der Schnittstellen bei LangChain noch einmal ein ganzer Fundus von Möglichkeiten in jede Richtung. Um hierfür ein paar Beispiele zu nennen: 

  • Confluence: direkte Seiten oder Spaces aus Confluence als Wissen Integrieren
  • Database: die direkte Integration von Daten aus existierenden SQL-Datenbanken wie PostgreSQL
  • Google Docs: jedwelche Form von Google Dokumenten
  • ZenDesk: Customer-Support-Informationen aus der Zendesk-Plattform
  • Unstructured File: diese Quelle setzen wir in unserem kleinen Beispiel ein, hier kann alles von Word-Dokumenten bis zu Mails, PDFs und Texten in Grafiken importiert werden. 

Mayflower AI Starter Kit

Das AI Starter Kit ist ein von Mayflower entwickeltes Rapid-Prototyping-Framework, mit dem sich kundenindividuelle Lösungen mit kurzer Time-to-Market entwickeln lassen.
Melde Dich gerne bei uns, wenn Du mehr erfahren möchtest.

Unser kleiner AI-Chatbot

Auf GitHub finden Sie den Sourcecode für einen kleinen Chatbot, den wir seit einiger Zeit intern selbst einsetzen. Datenimport und Bot selbst kommen zusammen auf keine 100 Zeilen Code. Die oben genannten Werkzeuge erlauben es, solche kleinen Lösungen in wenigen Stunden selbst zu implementieren. 

Aber werfen wir einen Blick auf die einzelnen Bestandteile:

Datenimport

Damit der Bot auch Dinge weiß, müssen wir sie ihm zunächst beibringen. Das machen wir nicht über OpenAI, sondern über eine eigene kleine lokale Datenbank, aus der wir die Informationen auswählen, die wir der AI zur Orientierung mitgeben. Damit wir wissen, welche Dokumente relevante Inhalte haben, benötigen wir zwei Schritte: Zunächst wandeln wir die Inhalte in hochdimensionale Vektoren und speichern sie in einer Vektordatenbank. Wenn wir jetzt eine Frage erhalten und herausfinden wollen, welche Inhalte für diese passend sein sollten, wandeln wir unsere Frage ebenfalls in Vektoren und schauen, welche Dokumente ähnliche Inhalte anbieten. Und genau diese Inhalte liefern wir OpenAI mit; auf dieser Basis werden die Fragen beantwortet. Glücklicherweise passiert das für uns transparent, es entstehen keine zusätzlichen Aufwände für uns.

LlamaIndex liefert den SimpleDirectoryLoader mit, der es erlaubt, rekursiv alle möglichen Arten von Dokumenten zu lesen und den Inhalt für LLMs nutzbar zu machen. Nachdem diese Inhalte alle in langchain_documents geladen sind, greifen wir auf LangChains RecursiveCharacterTextSplitter zurück, der ihn in kleinere Teile zerlegt, die dann wiederum mithilfe des OpenAIEmbedding-Models, ebenfalls aus LangChain, mit FAISS.from_documents(documents, embeddings) in einen VectorStore geladen werden.

Weil wir es hier mit vergleichsweise wenig Daten zu tun haben, nutzen wir der Einfachheit halber FAISS, eine lokale und offene Vektordatenbank von Facebook. Wer mehr Daten hat oder sie gemeinsam nutzen möchte, kann hier auf eine Vielzahl anderer kommerzieller und offener Lösungen zurückgreifen. 

Und weil FAISS ebenfalls direkt in LangChain zur Verfügung steht, können wir die Daten, nachdem sie von OpenAIEmbeddings zu Vektoren gewandelt wurden, direkt in FAISS laden und direkt aus Python serialisiert per pickle abspeichern.

Der entsprechende Teil in der import.py sieht wie folgt aus:

directory_reader = download_loader("SimpleDirectoryReader")
loader = directory_reader('./data', recursive=True)
raw_documents = loader.load_data()
langchain_documents = [d.to_langchain_format() for d in raw_documents]
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=1000,
    chunk_overlap=200,
)
documents = text_splitter.split_documents(langchain_documents)
embeddings = OpenAIEmbeddings()
vectorstore = FAISS.from_documents(documents, embeddings)
 
# Save vectorstore
with open("embedded_docs.pkl", "wb") as file:
    pickle.dump(vectorstore, file)

Der Bot selbst

Der Bot selbst besteht ebenfalls nur aus wenigen Bestandteilen. 

Die erste Frage ist: wie bringe ich ChatGPT dazu, mit mir Deutsch zu sprechen? Die Antwort ist ganz einfach: Ich spreche selbst Deutsch. Also nutze ich statt der Default-Prompts aus LangChain deren deutsche Übersetzung:

# german template for question prompt
GERMAN_PROMPT = """
Verwende die folgenden Kontextinformationen, um die Frage am Ende zu beantworten.
Wenn du die Antwort nicht weißt, sag einfach, dass du es nicht weißt und versuche nicht, eine Antwort zu erfinden.
 
{context}
 
Frage: {question}
Hilfreiche Antwort:"""
 
qa_prompt = PromptTemplate(
    template=GERMAN_PROMPT, input_variables=["context", "question"]
)

Damit habe ich meinen Question-Answering-Prompt auf Deutsch und weiß, dass es mir auf Deutsch antworten wird. Damit aber meine Gesprächshistorie ebenfalls in der richtigen Sprache zur Verfügung steht, brauche ich den Kontext, der dem Bot mitgegeben wird, ebenfalls auf Deutsch. Dazu nutzen wir einen „condense-prompt“, der sich nur um eines kümmert; aus der letzten Frage und der vorangegangenen Diskussion wieder eine einzige Frage zu machen.

GERMAN_CONDENSE_PROMPT = """
Gegeben die folgende Unterhaltung und eine anschließende Frage,
formuliere die Folgefrage als eigenständige Frage um.
 
Unterhaltung:
{chat_history}
Folgefrage: {question}
Eigenständige Frage:"""
 
condense_prompt = PromptTemplate.from_template(GERMAN_CONDENSE_PROMPT)

Und damit haben wir schon fast alles, was wir für den Chatbot brauchen. 

Wir initialisieren eine LangChain-Chain des Typs ConversationalRetrievalChain, die für solche Dokumentenrecherche genutzt werden soll. Dazu nutzen wir von OpenAI das günstige und schnelle Model gpt-3.5-turbo. Damit wir nicht immer identische Antworten erhalten, nutzen wir das Modell mit einer leichten Varianz, in diesem Kontext temperature genannt, mit 0.1. Bei 1.0 würde jede Antwort der vorhergehenden unähnlich sehen; mit unserem Wert sind die Antworten nahe beieinander, aber nicht ganz identisch.  

Dieser Prompt gibt uns die eigentliche deutsche Anfrage, die mit dem eigentlichen Prompt oben ausgeführt wird. Das macht ConversationalRetrievalChain für uns – und sie bezieht auch den Retriever für den Lookup in der Vektordatenbank mit ein. 

Ein Retriever sorgt dafür, dass wir zu unserer Query die richtigen Daten aus dem Vectorstore mitliefern. Und auch wenn es hierfür vielerlei Strategien gibt, nutzen wir hier die einfache Default-Strategie: wir liefern die Texte mit, die sich im Vectorspace in der Nähe unserer Frage befinden.

qa = ConversationalRetrievalChain.from_llm(
    OpenAI(temperature=0.1,model_name=OPENAI_API_MODEL),
    vectorstore.as_retriever(),
    qa_prompt=qa_prompt,
    condense_question_prompt=condense_prompt)

Last but not least: wir reden mit Slack. Slack unterstützt mit dem Bolt-Framework glücklicherweise auch Slackbots, die per WebSocket aus dem Intranet mit Slack diskutieren können. Somit ist die Integration ebenfalls mit wenigen Zeilen Code möglich.

Der Slack-Bot wird als App autorisiert und hört damit auf jedes Ereignis, in dem das Bot-Keyword genutzt wird. Das wird aus der Frage entfernt, die direkt an die eben kreierte Chain mit der aktuellen Kommunikationshistorie weitergegeben wird und von der wir im Gegenzug noch die Antwort bekommen.

Fertig ist der Slackbot.

Unsere Leistungen im Bereich AI

Installation des AI-Chatbots

Slack-Konfiguration

Zunächst braucht unser kleiner Bot einen Zugriff auf Slack. Dazu nutzen wir das Bolt-Framework in Python, das von Slack selbst zur Verfügung gestellt wird, Bitte folgen Sie der Anleitung auf slack.dev, um einen SLACK_BOT_TOKEN und einen SLACK_APP_TOKEN zu erhalten. Der SLACK_BOT_TOKEN sollte mit xoxb-... beginnen, der SLACK_APP_TOKEN mit xapp-... .

OpenAI-Key

Bitte legen Sie sich einen OpenAI-Account an und erstellen Sie auf platform.openai.com einen API-Key.

Installation

In der aktuellen Fassung kann der Bot von überall aus gestartet und genutzt werden, denn er nutzt die WebSocket-API von Slack. Es ist also auch ein Betrieb vom lokalen Netzwerk aus möglich, ein öffentliches API ist nicht erforderlich.

git clone https://github.com/mayflower/slack_my_documents
cd slack_my_documents
 
conda create -n slackbot python=3.10.9
conda activate slackbot
 
pip install -r requirements.txt

Konfiguration

Bitte kopieren Sie mit cp .env.example .env die Datei .env.example, um eine eigene Konfiguration anzulegen. Tragen Sie jetzt die drei Werte von oben in die .env ein und ergänzen Sie das Keyword, auf das der Bot hören soll.

# cp .env.example .env
# Edit your .env file with your own values
# DON'T COMMIT OR PUSH .env FILE!
 
# API CONFIG
OPENAI_API_KEY=
OPENAI_API_MODEL=gpt-3.5-turbo # Options: gpt-4, gpt-4-32k, gpt-3.5-turbo, text-davinci-003, etc.
SLACK_BOT_TOKEN= # Slack Bot token from , "xoxb-..."
SLACK_BOT_KEYWORD= # Slack Bot keyword - when should be answer?
SLACK_APP_TOKEN= # Slack App token from , "xapp-..."

Daten importieren

Der Bot setzt auf die Bordmittel von Langchain auf. Langchain selbst nutzt im Hintergrund unstructured.io, das eine ganze Reihe von Dokumentenparsern mitbringt:

  • Word-Dokumente (.docx, .doc)
  • Powerpoint (.pptx, .ppt)
  • Mails (.eml, .msg)
  • Ebooks (.rtf, .epub)
  • HTML-Seiten (.html)
  • Acrobat Reader (.pdf)
  • MarkDown (.md)
  • Text (.txt)
  • Text in Grafiken (.png, .jpg)

Bitte kopieren Sie alle benötigten Dateien einfach in den Folder ./data.

Starten Sie danach mit python import.py den Importer. Bitte nutzen Sie dieses Script auch, wenn Sie Ihre Daten aktualisieren wollen … und starten Sie danach den Bot neu, damit er mit den aktuellen Daten arbeitet.

Start

Jetzt können Sie mit python app.py den Bot starten.

Und wie geht es weiter?

Auch wenn diese kleinen Fingerübungen schon verblüffend sind, spannend wird AI erst mit der Übernahme von vollständigen Workflows. Wenn die AI nicht nur im Chat aus PDFs antwortet, sondern den kompletten Supportchat stellt – und dabei Zugriff auf die aktuelle Ausstattung und Konfiguration des Kunden hat. Wenn von Recherche über Pricing die Angebotserstellung automatisch läuft, inklusive individualisiertem Powerpoint-Deck, PDF und E-Mail.

Wenn die AI selbst entscheiden kann, wann sie die Hilfe eines Mitarbeiters braucht.

Falls Sie Interesse haben, diese Chancen für Ihr Unternehmen auszuleuchten, dann melden Sie sich bei mir. Denn genau dafür haben wir mit der Mayflower AI Readiness ein eigenes Angebot.

Johann-Peter Hartmann

Du hast Fragen zu AI ?

Johann ist unser CTO – Chief Tailwind Officer – und beschäftigt sich seit geraumer Zeit mit dem Thema AI. Wenn Du also herausfinden möchtest, welche Möglichkeiten die AI Dir und Deinem Unternehmen bietet, ist er der richtige Ansprechpartner für dich. Wenn Du willst, kannst Du ihn jederzeit Kontaktieren.

Avatar von Johann-Peter Hartmann

Kommentare

2 Antworten zu „Slack My Documents – AI in der Praxis“

  1. Musik Review und generelle Musik Website inkl. automatisiertem Social Media. Hat Spass gemacht ;)

  2. Vielen Dank hierfür!
    Als kompletter Neuling auf dem Gebiet habe ich große Hoffnung in diese Anleitung gesteckt, leider scheitert es beim letzten ausführen der App.py und das System weißt mich daraufhin, dass das chatmodell nicht mehr passt:
    You are trying to use a chat model. This way of initializing it is no longer supported.

    Nun denn, ich probiere mal weiter :)

Schreibe einen Kommentar

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


Für das Handling unseres Newsletters nutzen wir den Dienst HubSpot. Mehr Informationen, insbesondere auch zu Deinem Widerrufsrecht, kannst Du jederzeit unserer Datenschutzerklärung entnehmen.