Mit der Retrieval API kannst du deine Daten mit einer semantischen Suche durchsuchen. Dieses Verfahren liefert inhaltlich ähnliche Ergebnisse, selbst wenn nur wenige oder gar keine Schlüsselwörter übereinstimmen. Der Informationsabruf ist schon für sich genommen nützlich. Besonders leistungsfähig wird er in Kombination mit unseren Modellen, die aus den Ergebnissen Antworten formulieren.
Die Retrieval API basiert auf Vektorspeichern, die als Indizes für deine Daten dienen. In diesem Leitfaden erfährst du, wie du eine semantische Suche durchführst und wie Vektorspeicher im Detail funktionieren.
Schnellstart
Erstelle einen Vektorspeicher und lade Dateien hoch.
1
2
3
4
5require "openai"client = OpenAI::Client.newresults = client.vector_stores.search("vs_123", query: "What is the return policy?")puts(results.data&.first&.content)
Wie du die Ergebnisse mit unseren Modellen verwendest, erfährst du im Abschnitt Antworten
formulieren.
Semantische Suche
Die semantische Suche nutzt Vektor-Embeddings, um inhaltlich relevante Ergebnisse zu finden. Dazu gehören insbesondere auch Ergebnisse mit wenigen oder gar keinen gemeinsamen Schlüsselwörtern, die klassische Suchverfahren möglicherweise übersehen.
Sehen wir uns als Beispiel mögliche Ergebnisse für "When did we go to the moon?" an:
Text
Schlüsselwortähnlichkeit
Semantische Ähnlichkeit
Die erste Mondlandung fand im Juli 1969 statt.
0 %
65 %
Der erste Mensch auf dem Mond war Neil Armstrong.
27 %
43 %
Der Mondkuchen, den ich gegessen habe, war köstlich.
Beachte, dass das relevanteste Ergebnis keines der Wörter aus der Suchanfrage enthält. Diese Flexibilität macht die semantische Suche zu einem leistungsfähigen Verfahren, um Wissensdatenbanken jeder Größe zu durchsuchen.
Die semantische Suche basiert auf Vektorspeichern, auf die wir später in diesem Leitfaden näher eingehen. Dieser Abschnitt konzentriert sich auf die Funktionsweise der semantischen Suche.
Semantische Suche durchführen
Du kannst einen Vektorspeicher mit der Funktion search durchsuchen, indem du für query eine Anfrage in natürlicher Sprache angibst. Du erhältst eine Ergebnisliste, in der jedes Ergebnis die relevanten Textabschnitte, Ähnlichkeitswerte und die zugehörige Quelldatei enthält.
Suchanfrage
Python
1
2
3const results = await client.vectorStores.search(vector_store.id, { query: "How many woodchucks are allowed per passenger?",});
1
2
3
4results = client.vector_stores.search(vector_store_id=vector_store.id,query="How many woodchucks are allowed per passenger?",)
1
2
3
4
5
6
7
8require "openai"client = OpenAI::Client.newresults = client.vector_stores.search( "vs_123", query: "How many woodchucks are allowed per passenger?")puts(results.data&.first&.content)
Ergebnisse
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42{"object": "vector_store.search_results.page","search_query": "How many woodchucks are allowed per passenger?","data": [ {"file_id": "file-12345","filename": "woodchuck_policy.txt","score": 0.85,"attributes": {"region": "North America","author": "Wildlife Department" },"content": [ {"type": "text","text": "According to the latest regulations, each passenger is allowed to carry up to two woodchucks." }, {"type": "text","text": "Ensure that the woodchucks are properly contained during transport." } ] }, {"file_id": "file-67890","filename": "transport_guidelines.txt","score": 0.75,"attributes": {"region": "North America","author": "Transport Authority" },"content": [ {"type": "text","text": "Passengers must adhere to the guidelines set forth by the Transport Authority regarding the transport of woodchucks." } ] } ],"has_more": false,"next_page": null}
Standardmäßig enthält eine Antwort höchstens 10 Ergebnisse. Mit dem Parameter max_num_results kannst du die Höchstzahl auf bis zu 50 erhöhen.
Suchanfragen umformulieren
Bestimmte Formulierungen liefern bessere Suchergebnisse. Deshalb gibt es eine Einstellung, mit der deine Suchanfragen automatisch umformuliert werden, um optimale Ergebnisse zu erzielen. Aktiviere diese Funktion, indem du beim Aufruf von search die Einstellung rewrite_query=true angibst.
Die umformulierte Suchanfrage findest du im Feld search_query des Ergebnisses.
Original
Umformuliert
Ich möchte wissen, wie hoch das Hauptbürogebäude ist.
Höhe Hauptbürogebäude
Welche Sicherheitsvorschriften gelten für den Transport von Gefahrstoffen?
Sicherheitsvorschriften für Gefahrstoffe
Wie reiche ich eine Beschwerde über ein Serviceproblem ein?
Ablauf zum Einreichen einer Servicebeschwerde
Nach Attributen filtern
Mit Attributfiltern kannst du die Ergebnisse anhand bestimmter Kriterien eingrenzen, etwa indem du die Suche auf einen bestimmten Zeitraum beschränkst. In attribute_filter kannst du Kriterien definieren und kombinieren, um Dateien vor der semantischen Suche anhand ihrer Attribute auszuwählen.
Verwende Vergleichsfilter , um einen bestimmten key in den attributes einer Datei mit einem vorgegebenen value zu vergleichen. Mit zusammengesetzten Filtern kannst du mehrere Filter über and und or kombinieren.
Vergleichsfilter
1
2
3
4
5{"type": "eq"|"ne"|"gt"|"gte"|"lt"|"lte"|"in"|"nin", // comparison operators"key": "attributes_key", // attributes key"value": "target_value"// value to compare against}
Wenn die Ergebnisse deiner Dateisuche nicht relevant genug sind, kannst du ranking_options anpassen, um die Qualität der Antworten zu verbessern. Dazu kannst du für ranker beispielsweise auto oder default-2024-08-21 angeben und score_threshold auf einen Wert zwischen 0,0 und 1,0 setzen. Ein höherer Wert für score_threshold beschränkt die Ergebnisse auf relevantere Textabschnitte, kann dabei aber auch potenziell nützliche Abschnitte ausschließen. Wenn ranking_options.hybrid_search angegeben ist, kannst du außerdem hybrid_search.embedding_weight (rrf_embedding_weight) und hybrid_search.text_weight (rrf_text_weight) anpassen. Damit steuerst du, wie Reciprocal Rank Fusion semantische Embedding-Treffer gegenüber Treffern der Sparse-Schlagwortsuche gewichtet. Erhöhe den ersten Wert, um semantische Ähnlichkeit stärker zu gewichten, oder den zweiten, um textliche Übereinstimmungen stärker zu gewichten. Stelle sicher, dass mindestens eines der Gewichte größer als null ist.
Vektorspeicher
Vektorspeicher sind Container, die die semantische Suche für die Retrieval API und das Tool zur Dateisuche ermöglichen. Wenn du einem Vektorspeicher eine Datei hinzufügst, wird sie automatisch in Abschnitte aufgeteilt, in Embeddings umgewandelt und indexiert.
Vektorspeicher enthalten vector_store_file-Objekte, denen jeweils ein file-Objekt zugrunde liegt.
Objekttyp
Beschreibung
file
Stellt Inhalte dar, die über die Files API hochgeladen wurden. Wird häufig mit Vektorspeichern verwendet, aber auch für Fine-Tuning und andere Anwendungsfälle.
vector_store
Container für durchsuchbare Dateien.
vector_store.file
Wrapper-Typ, der ein file-Objekt darstellt, das in Abschnitte aufgeteilt, in Embeddings umgewandelt und einem vector_store zugeordnet wurde. Enthält eine attributes-Map zum Filtern.
Preise
Die Abrechnung richtet sich nach dem insgesamt belegten Speicherplatz in all deinen Vektorspeichern. Dieser ergibt sich aus der Größe der geparsten Abschnitte und der zugehörigen Embeddings.
Speicherplatz
Kosten
Bis zu 1 GB (über alle Speicher hinweg)
Kostenlos
Über 1 GB hinaus
0,10 USD/GB/Tag
Unter Ablaufrichtlinien erfährst du, wie du die Kosten minimieren kannst.
Einige Vorgänge, etwa create für vector_store.file, werden asynchron ausgeführt und können etwas Zeit in Anspruch nehmen. Verwende unsere Hilfsfunktionen wie create_and_poll, um die weitere Ausführung bis zum Abschluss des Vorgangs zu blockieren. Alternativ kannst du den Status abfragen. Beim Entfernen von Dateien aus einem Vektorspeicher wird die Konsistenz erst mit Verzögerung hergestellt. Suchergebnisse können daher noch kurzzeitig Inhalte aus einer entfernten Datei enthalten.
Beim Erstellen eines Stapels kannst du entweder file_ids mit optionalen Angaben für attributes und/oder chunking_strategy angeben oder über das Array files Objekte übergeben, die für jede Datei eine file_id sowie optional attributes und chunking_strategy enthalten. Die beiden Optionen schließen sich gegenseitig aus. So kannst du gezielt festlegen, ob alle Dateien dieselben Einstellungen verwenden oder einzelne Dateien abweichende Einstellungen benötigen.
Für einen höheren Durchsatz beim Import in einen einzelnen Vektorspeicher empfehlen wir, Dateien möglichst stapelweise anzulegen. Ein Stapel kann bis zu 500 Dateien in einer Anfrage enthalten. Das verringert in der Regel die Konkurrenz um Ressourcen und senkt die Ende-zu-Ende-Latenz gegenüber vielen einzelnen Anfragen zum Anlegen je einer Datei.
Attribute
Jedem vector_store.file können attributes zugeordnet werden. Dieses Dictionary enthält Werte, auf die du bei der semantischen Suche mit Attributfiltern zugreifen kannst. Das Dictionary kann höchstens 16 Schlüssel mit jeweils maximal 256 Zeichen enthalten.
Mit expires_after kannst du eine Ablaufrichtlinie für vector_store-Objekte festlegen. Sobald ein Vektorspeicher abläuft, werden alle zugehörigen vector_store.file-Objekte gelöscht und dir nicht mehr in Rechnung gestellt.
Die maximale Dateigröße beträgt 512 MB. Jede Datei sollte höchstens 5.000.000 Token enthalten. Die Anzahl wird automatisch berechnet, wenn du eine Datei anhängst.
Aufteilung in Chunks
Standardmäßig ist max_chunk_size_tokens auf 800 und chunk_overlap_tokens auf 400 gesetzt. Jede Datei wird zur Indexierung also in Chunks mit jeweils 800 Token aufgeteilt, wobei sich aufeinanderfolgende Chunks um 400 Token überlappen.
Du kannst dies anpassen, indem du beim Hinzufügen von Dateien zum Vektorspeicher chunking_strategy festlegst. Für die Strategie gelten bestimmte Einschränkungen:
max_chunk_size_tokens muss zwischen 100 und 4096 liegen, einschließlich beider Grenzwerte.
chunk_overlap_tokens darf nicht negativ sein und sollte max_chunk_size_tokens / 2 nicht überschreiten.
Für MIME-Typen mit text/ muss die Kodierung utf-8, utf-16 oder ascii sein.
Nach einer Abfrage möchtest du vielleicht aus den Ergebnissen eine Antwort erstellen. Dazu kannst du unseren Modellen die Ergebnisse und die ursprüngliche Anfrage übergeben. Du erhältst dann eine Antwort, die sich auf diese Ergebnisse stützt.
Suchanfrage ausführen, um Ergebnisse zu erhalten
Python
1
2
3
4
5
6
7
8
9import OpenAI from "openai";const client = new OpenAI();const userQuery = "What is the return policy?";const results = await client.vectorStores.search(vector_store.id, { query: userQuery,});
1
2
3
4
5
6
7
8require "openai"client = OpenAI::Client.newresults = client.vector_stores.search( "vs_123", query: "What is the return policy?")puts(results.data)
Antwort auf Grundlage der Ergebnisse erstellen
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22const formattedResults = formatResults(results.data);// Join the text content of all resultsconst textSources = results.data .map((result) => result.content.map((c) => c.text).join("\n")) .join("\n");const completion = await client.chat.completions.create({ model: "gpt-6-astra", messages: [ { role: "developer", content: "Produce a concise answer to the query based on the provided sources.", }, { role: "user", content: `Sources: ${formattedResults}\n\nQuery: '${userQuery}'`, }, ],});console.log(completion.choices[0].message.content);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20# Use results and user_query from the preceding search step.formatted_results = format_results(results.data)"\n".join("\n".join(c.text for c in result.content) for result in results.data)completion = client.chat.completions.create(model="gpt-6-astra",messages=[ {"role": "developer","content": "Produce a concise answer to the query based on the provided sources.", }, {"role": "user","content": f"Sources: {formatted_results}\n\nQuery: '{user_query}'", }, ],)print(completion.choices[0].message.content)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46package mainimport ( "context" "fmt" "strings" "github.com/openai/openai-go/v3")func main() { client := openai.NewClient() userQuery := "What is the return policy?" results, err := client.VectorStores.Search(context.Background(), "vs_123", openai.VectorStoreSearchParams{ Query: openai.VectorStoreSearchParamsQueryUnion{OfString: openai.String(userQuery)}, }) if err != nil { panic(err) } completion, err := client.Chat.Completions.New(context.Background(), openai.ChatCompletionNewParams{ Model: "gpt-6-astra", Messages: []openai.ChatCompletionMessageParamUnion{ openai.DeveloperMessage("Produce a concise answer to the query based on the provided sources."), openai.UserMessage(fmt.Sprintf("Sources: %s\n\nQuery: %q", formatResults(results.Data), userQuery)), }, }) if err != nil { panic(err) } fmt.Println(completion.Choices[0].Message.Content)}func formatResults(results []openai.VectorStoreSearchResponse) string { var sources strings.Builder sources.WriteString("<sources>") for _, result := range results { fmt.Fprintf(&sources, "<result file_id=%q file_name=%q>", result.FileID, result.Filename) for _, content := range result.Content { fmt.Fprintf(&sources, "<content>%s</content>", content.Text) } sources.WriteString("</result>") } sources.WriteString("</sources>") return sources.String()}