Ich habe neulich per AnythingLLM eine Docker Chroma Instanz verwendet.

Dazu wollte ich dann Daten abfragen. Das war erst mal nicht ganz so einfach, bis ich die YAML dazu gefunden habe (das YAML ist am Ende dieser Seite bzw unter http://localhost:8000/docs).
Das Ganze sieht in swagger.io formatiert so aus

So kannst du die DB Abfragen
Ist die DB überhaupt erreichbar / Heartbeat
http://127.0.0.1:8000/api/v1/heartbeat
Ausgabe irgendwas wie: {„nanosecond heartbeat“:1717134488888233555}
Collections auflisten
http://127.0.0.1:8000/api/v1/collections
Es findet sich der CollectionName der zum Workspace passt.

Dort habe ich mehrere Dokumente eingestellt

obige URL gibt also die Collections aus, in dem falle die „drei“, also den Namen des Workspaces.. Hätte ich das gewusst, hätte ichs anders benamst 😉

Beim Einfügen von Daten sieht man das übrigens schön in Docker

Anzahl der Embeddings auflisten
Dazu nutzen wir die (UU)id von „drei“ (siehe Screenshot vorher)
http://127.0.0.1:8000/api/v1/collections/734cb4ec-0b72-43d0-8e2c-d23680b7b2c8/count
Das entspricht auch der Ausgabe in AnythingLLM

Das Gleiche in python
pip install chromadb-client
ist installiert:
import chromadb # Example setup of the client to connect to your chroma server client = chromadb.HttpClient(host='localhost', port=8000) collection = client.get_collection(name="drei") print("-----------------------"); print(collection.peek()) # returns a list of the first 10 items in the collection print("-----------------------"); print(collection.count()) # returns the number of items in the collection print("-----------------------");
Wie kommen wir nun an die Daten / query?
Dazu müssen wir erst mal verstehen, welches Embedding-Modell genutzt wurde.
AnythingLLM hat im Standard sein „eigenes“ Modell
https://docs.useanything.com/features/embedding-models
und das verweist auf https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2
Dann erstellen wir mal einen einfachen python Client dazu:
import chromadb from chromadb.config import Settings from transformers import AutoTokenizer, AutoModel import torch import json # Verbinde dich mit der ChromaDB client = chromadb.HttpClient(host='localhost', port=8000) # Definiere den Namen der Collection collection_name = "drei" # Hole oder erstelle die Collection collection = client.get_or_create_collection(name=collection_name) # Lade ein vortrainiertes Modell und Tokenizer von Hugging Face tokenizer = AutoTokenizer.from_pretrained("sentence-transformers/all-MiniLM-L6-v2") model = AutoModel.from_pretrained("sentence-transformers/all-MiniLM-L6-v2") # Definiere eine Einbettungsfunktion def embed_text(texts): inputs = tokenizer(texts, padding=True, truncation=True, return_tensors="pt") with torch.no_grad(): embeddings = model(**inputs) return embeddings.last_hidden_state.mean(dim=1).numpy() # Führe eine Query aus query_text = ["Frithjof Bergmann"] query_embeddings = embed_text(query_text) results = collection.query( query_embeddings=query_embeddings.tolist(), # Nutze die Einbettungen für die Abfrage n_results=5 ) print("-----RESULTS-----"); # print(results); # Formatiert ausgeben formatted_data = json.dumps(results, indent=4, ensure_ascii=False) print(formatted_data) ## Zeige die Ergebnisse an #for result in results: ## print(result)
und klappt:

Zusammenfassung
(Folgende Antworten sind von der KI generiert)
Hier ist ein schematisches Diagramm, das den Aufbau und die Interaktion der Komponenten im beschriebenen System darstellt:
- Einbettungsfunktion: Dies ist der Teil, in dem du mit einem vortrainierten Modell (z.B. von Hugging Face) Texte in numerische Vektoren (Embeddings) umwandelst.
- ChromaDB: Dies ist die Datenbank, die in SQLite gespeichert ist und die Dokumente sowie ihre zugehörigen Embeddings speichert.
- Abfrage: Der Teil, in dem du die Embeddings von Abfragetexten berechnest und diese Embeddings dann zur Abfrage der Datenbank verwendest, um ähnliche Dokumente zu finden.
Erläuterungen:
- Benutzer-Anwendung: Hier beginnt der Prozess. Der Benutzer sendet einen Text (z.B. Dokumente oder Abfragen).
- Einbettungsfunktion: Diese Komponente verwendet ein vortrainiertes Modell, um Texte in Embeddings (numerische Vektoren) zu transformieren.
- Embeddings: Die generierten Embeddings werden entweder in die Datenbank eingefügt (für neue Dokumente) oder für Abfragen verwendet.
- ChromaDB: Eine SQLite-basierte Datenbank, die die Dokumente und ihre Embeddings speichert.
- Abfrageverarbeitung: Bei einer Abfrage werden die Embeddings des Abfragetextes mit den gespeicherten Embeddings in der Datenbank verglichen, um ähnliche Dokumente zu finden.
- Abfrageergebnisse: Die Ergebnisse der Abfrage (ähnliche Dokumente) werden an die Benutzer-Anwendung zurückgegeben.
Wie funktioniert die Abfrage?
1) Wieso muss der Text in einen Vektor eingebettet werden?
In der maschinellen Verarbeitung von Sprache (Natural Language Processing, NLP) sind Maschinen nicht in der Lage, Text direkt zu verstehen. Sie benötigen eine numerische Darstellung des Textes, die sie verarbeiten können. Diese numerische Darstellung wird als „Einbettung“ (Embedding) bezeichnet und ist ein Vektor, der den Text in einem kontinuierlichen Zahlenraum repräsentiert.
Einbettungen haben folgende Vorteile:
- Semantische Ähnlichkeit: Ähnliche Texte erhalten ähnliche Vektoren. Das bedeutet, dass die Abstände zwischen Vektoren semantische Ähnlichkeiten widerspiegeln.
- Effizienz: Vektoroperationen sind effizient und ermöglichen schnelle Berechnungen und Vergleiche.
- Universelle Darstellung: Einbettungen können universell für verschiedene Aufgaben verwendet werden, z.B. für Klassifikation, Clustering oder Suche.
2) Wie formuliere ich den Text richtig? Wird dieser 1:1 gesucht oder sollte man eine Frage stellen oder wie funktioniert das?
Der Text wird nicht 1:1 gesucht wie bei einer einfachen Textsuche, sondern die Einbettung des Textes wird mit den Einbettungen der in der Datenbank gespeicherten Texte verglichen. Daher ist es wichtig, den Text so zu formulieren, dass er den gewünschten Inhalt oder Kontext gut wiedergibt.
Hier sind einige Hinweise zur Formulierung des Textes:
- Klarheit und Präzision: Verwende klare und präzise Formulierungen, um den gewünschten Kontext oder die Bedeutung zu vermitteln.
- Natürliche Sprache: Du kannst den Text in natürlicher Sprache schreiben, da das Einbettungsmodell in der Lage ist, den semantischen Gehalt zu erfassen.
- Fragen stellen: Das Stellen von Fragen kann hilfreich sein, wenn du nach spezifischen Informationen suchst. Zum Beispiel: „Was ist die Philosophie von Frithjof Bergmann?“ anstatt nur „Frithjof Bergmann“.
3) Wird hier das KI-Modell irgendwie genutzt?
Ja, das KI-Modell wird in mehreren Schritten genutzt:
- Text-Einbettung: Das Modell
sentence-transformers/all-MiniLM-L6-v2
, das auf der Hugging Face-Plattform bereitgestellt wird, ist ein vortrainiertes Transformationsmodell, das dazu dient, Texte in Vektoren (Einbettungen) umzuwandeln. Hier wird der Text durch den Tokenizer und das Modell verarbeitet, um seine numerische Darstellung zu erhalten. - Ähnlichkeitsabfrage: Die erhaltenen Einbettungen werden dann genutzt, um semantische Ähnlichkeiten zwischen dem Abfragetext und den in der Datenbank gespeicherten Texten zu berechnen. Das KI-Modell hilft dabei, die Bedeutung des Textes zu erfassen und vergleichbare Inhalte in der Datenbank zu finden.
Hier ein genauerer Ablauf:
- Der Text „Frithjof Bergmann“ wird tokenisiert und durch das Modell geführt, das eine Einbettung (Vektor) erstellt.
- Diese Einbettung wird mit den Einbettungen der Texte in der Datenbank verglichen.
- Die Ähnlichkeit wird berechnet, und die am besten passenden Einträge werden zurückgegeben.
Das vortrainierte Modell sorgt dafür, dass die Einbettungen die semantische Bedeutung des Textes widerspiegeln, wodurch ähnliche Inhalte gefunden werden können, selbst wenn die exakten Wörter nicht übereinstimmen.
4) Kann man das nur für Suche nutzen oder könnte man zB zu Fragen so auch Antworten hinterlegen und diese nutzen?
a, du kannst verschiedene Dokumenttypen in der Datenbank hinterlegen und sicherstellen, dass nur bestimmte Typen bei einer Abfrage berücksichtigt werden. Hier sind einige Strategien, wie du dies erreichen kannst:
1. Dokumenttyp kennzeichnen:
Du kannst jedes Dokument mit einem Typ-Tag versehen, z.B. „Frage“ oder „Antwort“. Diese Tags werden bei der Abfrage berücksichtigt, um sicherzustellen, dass nur die relevanten Dokumente zurückgegeben werden.
2. Sammlung in verschiedene Kategorien unterteilen:
Du könntest mehrere Sammlungen erstellen, z.B. eine Sammlung für „Fragen“ und eine andere für „Antworten“. Bei einer Abfrage auf die Sammlung „Antworten“ wird sichergestellt, dass nur Antworten zurückgegeben werden.
3. Filter in der Abfrage verwenden:
Wenn du alle Dokumente in einer einzigen Sammlung behältst, kannst du zusätzliche Metadaten verwenden, um den Typ zu kennzeichnen und dann bei der Abfrage einen Filter anzuwenden.
Beispielimplementierung:
Hier ein Beispiel, wie du die Dokumenttypen in einer ChromaDB-Sammlung kennzeichnen und filtern kannst:
- Dokumente hinzufügen mit Typ-Tag:
# Beispiel-Dokumente hinzufügen
documents = [ {"text": "Was ist die Philosophie von Frithjof Bergmann?", "type": "Frage"}, {"text": "Die Philosophie von Frithjof Bergmann betont die Bedeutung der Arbeit.", "type": "Antwort"} ]
for doc in documents: embedding = embed_text([doc["text"]]) collection.add({ "text": doc["text"], "type": doc["type"], "embedding": embedding.tolist() })
- Abfrage mit Typ-Filter:
# Beispiel-Abfrage
query_text = ["Was ist die Philosophie von Frithjof Bergmann?"]
query_embedding = embed_text(query_text)
results = collection.query( query_embeddings=query_embedding.tolist(), n_results=5, filter={"type": "Antwort"} # Nur Antworten zurückgeben )
print("-----RESULTS-----")
formatted_data = json.dumps(results, indent=4, ensure_ascii=False)
print(formatted_data)
Erweiterte Filterung:
Falls ChromaDB erweiterte Filterung unterstützt, kannst du auch komplexere Filterkriterien anwenden, um gezielt nach Antworten zu suchen.
Nutzung mehrerer Sammlungen:
Eine alternative Methode besteht darin, separate Sammlungen für Fragen und Antworten zu verwenden. Hier ein Beispiel:
- Erstellen von Sammlungen für Fragen und Antworten:
# Sammlungen erstellen questions_collection = client.get_or_create_collection(name="questions") answers_collection = client.get_or_create_collection(name="answers")
# Dokumente hinzufügen
questions_collection.add({ "text": "Was ist die Philosophie von Frithjof Bergmann?", "embedding": embed_text(["Was ist die Philosophie von Frithjof Bergmann?"]).tolist() })
answers_collection.add({ "text": "Die Philosophie von Frithjof Bergmann betont die Bedeutung der Arbeit.", "embedding": embed_text(["Die Philosophie von Frithjof Bergmann betont die Bedeutung der Arbeit."]).tolist() })
- Abfrage nur in der Antworten-Sammlung:
# Beispiel-Abfrage nur in der Antworten-Sammlung
query_text = ["Was ist die Philosophie von Frithjof Bergmann?"]
query_embedding = embed_text(query_text)
results = answers_collection.query( query_embeddings=query_embedding.tolist(), n_results=5 )
print("-----RESULTS-----")
formatted_data = json.dumps(results, indent=4, ensure_ascii=False)
print(formatted_data)
Fazit:
Durch das Kennzeichnen von Dokumenttypen und die Anwendung von Filtern bei der Abfrage kannst du sicherstellen, dass nur relevante Dokumente zurückgegeben werden, z.B. nur Antworten auf gestellte Fragen. Dies bietet eine flexible und effektive Methode, um unterschiedliche Dokumenttypen in einer einzigen Datenbank zu verwalten und abzufragen.
Hier das oben erwähnte Yaml für ChromaDB
openapi: 3.0.2 info: title: FastAPI version: 0.1.0 paths: /api/v1: get: summary: Root operationId: root responses: '200': description: Successful Response content: application/json: schema: additionalProperties: type: integer type: object title: Response Root Api V1 Get /api/v1/reset: post: summary: Reset operationId: reset responses: '200': description: Successful Response content: application/json: schema: type: boolean title: Response Reset Api V1 Reset Post /api/v1/version: get: summary: Version operationId: version responses: '200': description: Successful Response content: application/json: schema: type: string title: Response Version Api V1 Version Get /api/v1/heartbeat: get: summary: Heartbeat operationId: heartbeat responses: '200': description: Successful Response content: application/json: schema: additionalProperties: type: integer type: object title: Response Heartbeat Api V1 Heartbeat Get /api/v1/collections: get: summary: List Collections operationId: list_collections responses: '200': description: Successful Response content: application/json: schema: items: $ref: '#/components/schemas/Collection' type: array title: Response List Collections Api V1 Collections Get post: summary: Create Collection operationId: create_collection requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateCollection' required: true responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Collection' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/v1/collections/{collection_id}/add: post: summary: Add operationId: add parameters: - required: true schema: type: string title: Collection Id name: collection_id in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/AddEmbedding' required: true responses: '201': description: Successful Response content: application/json: schema: type: boolean title: Response Add Api V1 Collections Collection Id Add Post '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/v1/collections/{collection_id}/update: post: summary: Update operationId: update parameters: - required: true schema: type: string title: Collection Id name: collection_id in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateEmbedding' required: true responses: '200': description: Successful Response content: application/json: schema: type: boolean title: Response Update Api V1 Collections Collection Id Update Post '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/v1/collections/{collection_id}/upsert: post: summary: Upsert operationId: upsert parameters: - required: true schema: type: string title: Collection Id name: collection_id in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/AddEmbedding' required: true responses: '200': description: Successful Response content: application/json: schema: type: boolean title: Response Upsert Api V1 Collections Collection Id Upsert Post '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/v1/collections/{collection_id}/get: post: summary: Get operationId: get parameters: - required: true schema: type: string title: Collection Id name: collection_id in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/GetEmbedding' required: true responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/GetResult' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/v1/collections/{collection_id}/delete: post: summary: Delete operationId: delete parameters: - required: true schema: type: string title: Collection Id name: collection_id in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/DeleteEmbedding' required: true responses: '200': description: Successful Response content: application/json: schema: items: type: string format: uuid type: array title: Response Delete Api V1 Collections Collection Id Delete Post '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/v1/collections/{collection_id}/count: get: summary: Count operationId: count parameters: - required: true schema: type: string title: Collection Id name: collection_id in: path responses: '200': description: Successful Response content: application/json: schema: type: integer title: Response Count Api V1 Collections Collection Id Count Get '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/v1/collections/{collection_id}/query: post: summary: Get Nearest Neighbors operationId: get_nearest_neighbors parameters: - required: true schema: type: string title: Collection Id name: collection_id in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/QueryEmbedding' required: true responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/QueryResult' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/v1/collections/{collection_name}: get: summary: Get Collection operationId: get_collection parameters: - required: true schema: type: string title: Collection Name name: collection_name in: path responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Collection' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' delete: summary: Delete Collection operationId: delete_collection parameters: - required: true schema: type: string title: Collection Name name: collection_name in: path responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Collection' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' /api/v1/collections/{collection_id}: put: summary: Update Collection operationId: update_collection parameters: - required: true schema: type: string title: Collection Id name: collection_id in: path requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateCollection' required: true responses: '200': description: Successful Response content: application/json: schema: $ref: '#/components/schemas/Collection' '422': description: Validation Error content: application/json: schema: $ref: '#/components/schemas/HTTPValidationError' components: schemas: AddEmbedding: properties: metadatas: items: additionalProperties: type: string type: object embeddings: items: items: type: number format: float type: array type: object required: - ids title: AddEmbedding Collection: properties: name: type: string id: type: string format: uuid metadatas: additionalProperties: type: string type: object type: object required: - name - id title: Collection CreateCollection: properties: metadata: additionalProperties: type: string type: object type: object required: - name title: CreateCollection DeleteEmbedding: properties: ids: items: type: string type: array where: additionalProperties: type: string type: object where_document: additionalProperties: type: string type: object type: object title: DeleteEmbedding GetEmbedding: properties: ids: items: type: string type: array limit: type: integer offset: type: integer sort: type: string where: additionalProperties: type: string type: object where_document: additionalProperties: type: string type: object type: object title: GetEmbedding GetResult: properties: ids: items: type: string type: array title: Ids embeddings: items: anyOf: - items: type: number type: array - items: type: integer type: array type: array title: Embeddings documents: items: type: string type: array title: Documents metadatas: items: additionalProperties: anyOf: - type: string - type: integer - type: number - type: boolean type: object type: array title: Metadatas type: object required: - ids - embeddings - documents - metadatas title: GetResult HTTPValidationError: properties: detail: items: $ref: '#/components/schemas/ValidationError' type: array title: Detail type: object title: HTTPValidationError QueryEmbedding: properties: where: additionalProperties: type: string type: object where_document: additionalProperties: type: string type: object query_embeddings: items: items: type: number format: float type: array type: array n_results: type: integer include: items: type: string type: array type: object required: - query_embeddings title: QueryEmbedding QueryResult: properties: ids: items: items: type: string type: array type: array title: Ids embeddings: items: items: anyOf: - items: type: number type: array - items: type: integer type: array type: array type: array title: Embeddings documents: items: items: type: string type: array type: array title: Documents metadatas: items: items: additionalProperties: anyOf: - type: string - type: integer - type: number - type: boolean type: object type: array type: array title: Metadatas distances: items: items: type: number type: array type: array title: Distances type: object required: - ids - embeddings - documents - metadatas - distances title: QueryResult UpdateCollection: properties: new_name: type: string new_metadata: additionalProperties: type: string type: object type: object title: UpdateCollection UpdateEmbedding: properties: metadatas: items: additionalProperties: type: string type: object embeddings: items: items: type: number format: float type: array type: object required: - ids title: UpdateEmbedding ValidationError: properties: loc: items: anyOf: - type: string - type: integer type: array title: Location msg: type: string title: Message type: type: string title: Error Type type: object required: - loc - msg - type title: ValidationError