Eine Antwort zu Ihren Dokumenten ist nur so gut wie der Text, aus dem sie erstellt wurde, und wenn Sie ganze Dateien in einen Chat einfügen, können Sie nicht erkennen, welchen Teil das Modell tatsächlich verwendet hat. GroupDocs.Search.Mcp, das lokal in Docker läuft, gibt Claude Desktop, Cursor oder Copilot ein anderes Primitive: get_text_fragments gibt nur die Passagen zurück, die zu einer Abfrage passen, mit ein paar Wörtern Kontext und der Datei, aus der sie stammen, sodass der Agent aus Zitaten antwortet:

Was sagen meine Verträge über Strafen? Zitieren Sie die Passagen, mit genügend Kontext, um jede zu verstehen.

Die schrittweise Version mit Konfiguration und Fehlersuche finden Sie in der Dokumentation: How to get the matching passages instead of reading whole files.

Warum weichen Antworten von den Dokumenten ab?

Da das Kontextfenster ein Budget ist und ganze Dokumente es schlecht ausnutzen. Eine Frage zu Strafen benötigt vielleicht drei Sätze aus fünfzig Seiten. Fügen Sie die fünfzig Seiten ein und das Modell muss die drei Sätze selbst finden, zwischen all dem anderen, und sie dann behalten, während es schreibt. Lange Kontexte werden zusammengefasst, frühes Material verliert Gewicht, und die Antwort stützt sich eher auf das allgemeine Verständnis des Modells davon, was Verträge üblicherweise sagen, als auf das, was Ihre sagen. Die Branche nennt die Disziplin, dies zu verwalten, context engineering; die einfachste Form davon ist, keinen Text zu laden, den Sie nicht benötigen.

Wie sieht ein Fragment aus?

Der Index enthält bereits den Text jedes Dokuments, sodass der Server die Passage um jede Übereinstimmung herum ausschneiden kann. Dies sind echte Antworten aus unserem Test, gegen fünf synthetische Verträge. Die Vorgaben, acht Wörter auf jeder Seite, ergeben einen Ausdruck:

-> get_text_fragments {"query":"penalty","indexName":"contracts"}
<- === contracts/acme-master-services-agreement.pdf (1 occurrence(s)) ===
     [content] …before the end of the Term, a termination penalty of
   three monthly fees applies, payable within 30…

Zwanzig Wörter auf jeder Seite geben die gesamte Klausel:

-> get_text_fragments {"query":"penalty","indexName":"contracts",
     "termsBefore":20,"termsAfter":20,"maxFragmentsPerDocument":1}
<- === contracts/acme-master-services-agreement.pdf (1 occurrence(s)) ===
     …convenience on 90 days written notice.
   12.3 If the Client terminates before the end of the Term, a termination
   penalty of three monthly fees applies, payable within 30 days of the
   termination date.
   14.2 Force majeure: neither party is…

termsBefore und termsAfter sind ein Regler: klein für „welche Dateien und ungefähr wo“, groß für „zitiere mir die Klausel“. maxFragmentsPerDocument und maxDocuments begrenzen die Größe der Antwort, sodass ein Wort, das zweihundertmal vorkommt, den Kontext nicht überflutet.

Das Budget, nebeneinander

Reading the files                        Searching the index
-------------------------------------    -------------------------------------
agent opens every document               search: which files match (JSON)
  context grows with the corpus          get_text_fragments: the passages
  long files crowd out the question        (~8 words either side, per file)
  repeated for every question            answer cites file + passage
                                         the index is reused next time

Der Unterschied wächst mit dem Korpus. Bei drei kurzen Dateien spielt es kaum eine Rolle. Für einen Ordner mit langen Verträgen, Berichten und E-Mails sind die Fragmente für eine Frage einige hundert Wörter, im Vergleich zum Volltext jedes Kandidatendokuments.

Wenn die Wörter unterschiedlich sind

Die Volltextsuche stimmt Wörter überein, was ein Merkmal für Verankerung (jeder Treffer ist erklärbar) und eine Grenze für die Trefferquote (ein Synonym ist ein Fehlgriff) ist. Die Aufgabe des Agenten ist es, Varianten zu versuchen, und er kann sehen, was jede Variante tatsächlich getroffen hat:

-> search {"query":"renewal OR renews","indexName":"contracts"}
<- umbrella-office-lease.pdf, terms ["renewal", "renews"]

-> search {"query":"renewl","indexName":"contracts","fuzzy":true}
<- umbrella-office-lease.pdf, terms ["renewal", "renews", "rent"]

Fuzzy-Matching rettete einen Rechtschreibfehler und zog auch rent ein. Da die Antwort die Begriffe auflistet, die sie getroffen hat, kann ein Agent oder Sie sehen, wo die Übertreffung liegt, anstatt ihr zu vertrauen. Diese Transparenz ist das, was „verankert“ bedeuten sollte: nicht nur „die Antwort zitiert eine Quelle“, sondern „Sie können sehen, wie die Quelle gefunden wurde“.

Wie eine verankerte Antwort aussieht

Bitten Sie um Zitate, und die Antwort kommt in einer Form, die Sie auf einen Blick überprüfen können:

Zwei Verträge enthalten eine Kündigungsstrafe. Acme MSA, Klausel 12.3: „eine Kündigungsstrafe von drei Monatsgebühren gilt, zahlbar innerhalb von 30 Tagen nach dem Kündigungsdatum.“ Globex Beratungsvertrag, Abschnitt 9: „der Kunde zahlt 50 Prozent der noch ausstehenden Gebühren für die aktuelle Phase.“ Der Initech NDA erwähnt Kündigung und Strafe, stellt jedoch fest, dass keine Strafe besteht.

Wenn eine Zusammenfassung ein Zitat falsch interpretiert, steht die Fehlinterpretation direkt neben dem Zitat.

Ehrliche Grenzen

  • Im Evaluationsmodus enthält ein Index höchstens 100 Dokumente und eine Suche liefert höchstens 10 Ergebnisse. Der Evaluationsmodus fügt außerdem eine Zeile „Evaluation only…“ zum indizierten Text einiger Formate hinzu, die in Fragmenten erscheinen kann; lizenzieren Sie den Server und bauen Sie den Index neu, um sie zu entfernen. Rufen Sie zuerst get_license_status auf.
  • Der Fragmentkontext wird in Wörtern, nicht in Sätzen, gezählt, sodass eine Passage mitten im Satz beginnen kann; erhöhen Sie termsBefore, wenn es wichtig ist.
  • Kein OCR: Scans ohne Textebene haben keine Passagen zum Zurückgeben.
  • Nur Docker; unter Linux fügen Sie --user "$(id -u):$(id -g)" hinzu.

FAQ

Wie bringe ich Claude dazu, Quellen aus meinen Dokumenten zu zitieren?
Gebt ihm ein Werkzeug, das den Quelltext zusammen mit dem Dateinamen zurückgibt. get_text_fragments tut genau das, und eine Anweisung wie „zitiere die Passage und ihre Datei“ macht es zur Gewohnheit.

Reduziert das den Tokenverbrauch?
Es vermeidet das Laden ganzer Dokumente, um eine Frage zu beantworten: Der Agent liest nur die passenden Passagen. Wie viel das spart, hängt von der Größe Ihrer Dateien ab.

Kann der Agent immer noch eine ganze Datei lesen, wenn es nötig ist?
Ja, mit seinen eigenen Dateitools. Fragmente dienen dem Finden und Zitieren; lesen Sie die ganze Datei, wenn die Passage nicht ausreicht.

Tiefer einsteigen