Antworten mit Quellenangaben
Dem Modell die gefundenen Chunks nummeriert geben, verlangen, dass jeder Satz seine Quelle nennt und fehlende Informationen als fehlend benannt werden. Dann per Programm prüfen, ob die Zitate gültig sind, und sehen, ob es bei einer Frage, die die Dokumentation nicht beantwortet, etwas erfindet.
- Etwa 35 Minuten
- Niveau: Fortgeschritten
- Getestet: 2026-09-14 deepseek-flash, multilingual-e5-small
Code und Programmausgaben stehen genau so da, wie sie gelaufen sind – Kommentare und Ausgaben sind daher auf Chinesisch.
Die Suche steht; nun müssen die gefundenen Unterlagen an das Modell. Wie man sie übergibt und was man danach verlangt, entscheidet, ob die endgültige Antwort verlässlich ist.
Diese Lektion hat drei Ziele: Das Modell antwortet nur anhand der Unterlagen, nennt bei jedem Satz, auf welchen Abschnitt er sich stützt, und sagt ehrlich, wenn die Unterlagen die Antwort nicht enthalten. Dann schreiben wir ein Programm, das automatisch prüft, ob es das getan hat.
Die Unterlagen nummerieren
Gesucht wird mit der besten Methode der letzten Lektion, „Umformulieren + hybride RRF“, und man nimmt die Top 5. Jeder Chunk wird in einen Tag mit Nummer und Quelle eingepackt:
def build_context(results):
parts = []
for i, (_, file, text) in enumerate(results, 1):
parts.append(f'<doc id="{i}" source="{file}">\n{text}\n</doc>')
return "<docs>\n" + "\n".join(parts) + "\n</docs>"
Im Prompt sieht das so aus (Inhalt ausgelassen):
<docs>
<doc id="1" source="compatibility.md">
## Redirects
Unlike `requests`, HTTPX does **not follow redirects by default**. ……
</doc>
<doc id="2" source="compatibility.md">
……
</doc>
……
</docs>
问题:httpx 默认会自动跟随重定向吗?怎么开启?
Die Nummer dient dem Modell zum Zitieren, source dem Modell zur Orientierung und dem Programm, um sie am Ende dem Nutzer zu zeigen. Modul 02, Lektion 1 hat gezeigt, wie man Material und Anweisungen mit Tags trennt; der Tag <doc> hat hier noch eine Aufgabe: Er markiert klar die Grenzen jedes Abschnitts, damit das Modell nicht zwei Abschnitte zu einem vermischt.
Der Prompt
SYSTEM = """你是 httpx 的答疑助手。只根据 <docs> 里的文档片段回答用户的问题。
规则:
- 每句话后面用 [编号] 注明依据的是哪个片段,可以同时引用多个,如 [1][3]。
- 片段里没有的信息不要写,哪怕你自己知道。
- 如果这些片段不足以回答问题,就直接说"文档里没有找到相关说明",不要猜。
- 用中文回答,简洁,代码保持原样。"""
Wichtig in Regel zwei ist „auch wenn du es selbst weißt“. Das Modell weiß ohnehin viel über httpx, aber sein Wissen kann falsch sein, etwa dass Weiterleitungen standardmäßig verfolgt werden. Verlangt man, nur die Unterlagen zu nutzen, ersetzt man die Richtigkeit des Modellgedächtnisses durch die Richtigkeit der Unterlagen. Der Preis: Was die Unterlagen zufällig nicht enthalten, das Modell aber eigentlich weiß, darf es auch nicht sagen. Lektion 7 stößt auf so ein Beispiel.
Regel drei gibt dem Modell einen klaren „Ausweg“. Ohne sie füllt das Modell bei unzureichenden Unterlagen die Lücke meist mit eigenem Wissen, und genau das wollen wir vermeiden.
Ergebnisse
Ich habe vier Fragen vorbereitet: zwei mit eindeutiger Antwort in der Dokumentation; eine, die die Dokumentation überhaupt nicht erwähnt (HTTP/3; ich habe die gesamte httpx-Dokumentation durchsucht, es kommt nicht vor); und eine, deren Antwort genaues Lesen der Unterlagen erfordert (hat httpx eingebaute Wiederholungen?). Vollständiger Code in code/04-rag/citations.py, Ergebnis:
问:httpx 默认会自动跟随重定向吗?怎么开启?
检索到:[1] compatibility.md [2] compatibility.md [3] quickstart.md [4] http2.md [5] compatibility.md
答:httpx 默认**不会**自动跟随重定向,所有 HTTP 方法都是如此 [1][3]。
你可以在单个请求上显式开启 [1][3]:
```python
response = client.get(url, follow_redirects=True)
```
或者在创建 `Client` 时就默认开启 [1]:
```python
client = httpx.Client(follow_redirects=True)
```
开启后,可以通过 `response.history` 属性查看被跟随的重定向响应列表,按发生顺序排列 [3]。
检查:引用了 [1, 3],不存在的编号 无,没有引用的句子 0 句(输入 1002 词元)
问:httpx 支持 HTTP/3 吗?
检索到:[1] async.md [2] http2.md [3] advanced/transports.md [4] http2.md [5] advanced/transports.md
答:文档里没有找到相关说明。
检查:引用了 [],不存在的编号 无,没有引用的句子 1 句(输入 1128 词元)
未引用:文档里没有找到相关说明。
问:httpx 自带请求失败自动重试的功能吗?
检索到:[1] third_party_packages.md [2] advanced/transports.md [3] compatibility.md [4] async.md [5] advanced/transports.md
答:httpx 自带连接层面的重试功能,通过直接实例化 transport 来使用:当发生 `httpx.ConnectError` 或 `httpx.ConnectTimeout` 时,请求会按给定的次数重试,从而在链路不稳定的网络下更平滑地运行 [2]。
(代码示例省略)
如果只需要专门的 HTTPX 重试层,可以看 httpx-retries,它是一个 for HTTPX 的 retry layer [1]。若需要其他形式的重试行为(例如处理读/写错误,或针对 `503 Service Unavailable` 做出反应),文档建议考虑 tenacity 这类通用工具 [2]。
检查:引用了 [1, 2, 4],不存在的编号 无,没有引用的句子 0 句(输入 908 词元)
(Auch die Frage zum Abschalten der SSL-Prüfung wurde richtig beantwortet; hier weggelassen.)
Weiterleitungen: richtig, und mit zwei Quellen, denn sowohl compatibility.md als auch quickstart.md behandeln das.
HTTP/3: steht nicht in der Dokumentation, also sagt das Modell genau das und kein Wort mehr. Zum Vergleich: In Modul 01, Lektion 2 erfand dasselbe Modell ohne Unterlagen und ohne Regeln eine nicht existierende CVE-Nummer.
Wiederholungen: die aufschlussreichste Frage. „Hat httpx eingebaute Wiederholungen?“ beantwortet man aus dem Gedächtnis leicht pauschal mit „ja“ oder „nein“. Anhand der Unterlagen gab das Modell eine genaue, abgewogene Antwort: Eingebaut sind nur Wiederholungen bei Verbindungsfehlern; für Lese- und Schreibfehler und 503 braucht es andere Werkzeuge. Genau das meint der Originaltext der httpx-Dokumentation; ich habe denselben Punkt in Modul 01, Lektion 2 in der Dokumentation nachgeprüft.
Zitate per Programm prüfen
Das Modell sagt, es habe [2] zitiert, aber gibt es [2] wirklich? Hat jeder Satz ein Zitat? Das lässt sich per Programm prüfen:
def check_citations(text, n_docs):
"""找出回答里所有的 [数字],检查它们是否都在 1..n_docs 范围内,以及有多少句话没有引用。"""
cited = [int(x) for x in re.findall(r"\[(\d+)\]", text)]
invalid = sorted({c for c in cited if not 1 <= c <= n_docs})
prose = re.sub(r"```.*?```", "", text, flags=re.S) # 代码块是照抄文档的,不要求逐行引用
sentences = [s.strip() for s in re.split(r"(?<=[。!?])|\n+", prose) if len(s.strip()) > 8]
# 以冒号结尾的句子是在引出下面的代码,引用通常写在代码块后面,也不算
uncited = [s for s in sentences if not re.search(r"\[\d+\]", s) and not s.endswith((":", ":"))]
return sorted(set(cited)), invalid, uncited
Es tut zwei Dinge:
- Ob die zitierten Nummern existieren. Gibt man nur 5 Abschnitte, und das Modell zitiert [7], erfindet es eine Quelle. Das kam bei den 4 Fragen kein einziges Mal vor, passiert aber bei vielen Unterlagen und langen Antworten.
- Welche Sätze kein Zitat haben. Sätze ohne Zitat könnten Inhalte sein, die das Modell selbst hinzugefügt hat.
Diesen Prüfer habe ich einmal überarbeitet. Die erste Version hielt jede Codezeile in einem Codeblock für einen „Satz ohne Zitat“ und meldete bei jeder Frage mit Code einen Haufen Fehlalarme. Code wird aus der Dokumentation übernommen und braucht keine zeilenweisen Zitate, also werden Codeblöcke vor der Prüfung entfernt. Jetzt ist der einzige „nicht zitierte“ Satz „在文档里没有找到相关说明“ (in der Dokumentation wurde nichts dazu gefunden), der ohnehin kein Zitat braucht.
Die Prüfung per Programm hat eine offensichtliche Grenze: Sie prüft das Format, nicht den Inhalt. Hat das Modell [2] zitiert, kann das Programm nicht beurteilen, ob [2] den Satz tatsächlich stützt. Das braucht einen Menschen oder ein anderes Modell als Gutachter, und das ist die „Treue“-Bewertung der nächsten Lektion.
Zitate dem Nutzer zeigen
Für Nutzer bedeuten Nummern wie [1] und [3] nichts; man muss sie durch echte Quellen ersetzen. RepoBot v2 macht es so: Nach der Antwort ermittelt es, welche Nummern tatsächlich zitiert wurden, und listet die zugehörigen Dokumente auf:
来源:[1] compatibility.md [2] quickstart.md
Auf einer Webseite kann man die Nummern zu Links machen, die direkt an die passende Stelle der Dokumentation springen. Nutzer können selbst nachprüfen, und bei Fehlern sieht man auf einen Blick, welcher Abschnitt das Modell in die Irre geführt hat.
Mögliche Probleme
Das Modell zitiert nicht oder nur einmal am Ende. Gib im Prompt ein Beispiel, das das gewünschte Zitierformat zeigt.
Es zitiert, aber falsch. Die Antwort gibt Inhalt aus Abschnitt A wieder, markiert aber [B]. Das passiert leicht, wenn Abschnitte inhaltlich ähnlich sind. Man kann verlangen, beim Zitieren den Schlüsselsatz des Originals mit anzuführen, was die Prüfung erleichtert, die Antwort aber länger macht.
Die Unterlagen widersprechen sich. Etwa ein Abschnitt aus einer alten und einer aus einer neuen Version der Dokumentation. Das Modell nimmt vielleicht willkürlich einen oder vermischt beide. Die Lösung liegt auf der Suchseite: Chunks mit Versionsangaben versehen und nur in der aktuellen Version suchen.
Zu vorsichtig. Die Unterlagen enthalten die Antwort eigentlich, nur etwas versteckt, aber das Modell sagt „steht nicht in der Dokumentation“. Das ist eine Nebenwirkung von „nur anhand der Unterlagen“. Man kann im Prompt erklären: „Was die Unterlagen indirekt erwähnen, darf beantwortet werden, aber als Schlussfolgerung gekennzeichnet.“
Übungen
- Füg
citations.pydie Frage hinzu: „Was ist leistungsfähiger, httpx oder requests?“ Die Dokumentation vergleicht die Leistung beider nicht direkt; schau, wie das Modell antwortet. - Lösch aus dem Prompt die Regel „Informationen, die nicht in den Abschnitten stehen, nicht schreiben, auch wenn du sie selbst weißt“, stell die HTTP/3-Frage erneut und schau, ob das Modell aus eigenem Wissen antwortet und ob das Gesagte stimmt.
- Erweitere
check_citationsum eine Prüfung: Zitiert die Antwort einen Abschnitt, sollte darin mindestens einer der Code-Bezeichner aus der Antwort vorkommen (etwafollow_redirects). Das ist eine grobe „Inhaltsprüfung“; überleg, in welchen Fällen sie falsch urteilt.
Selbsttest
1. Warum steht im Prompt „auch wenn du es selbst weißt, schreib nichts, was nicht in den Abschnitten steht“?
Das eigene Wissen des Modells kann falsch sein, etwa wenn es das Standardverhalten von httpx bei Weiterleitungen falsch erinnert. Nur anhand der Unterlagen zu antworten, ersetzt die Richtigkeit des Modellgedächtnisses durch die der Unterlagen und macht jeden Satz belegbar. Der Preis ist, dass Informationen, die zufällig nicht in den Unterlagen stehen, nicht genannt werden können.
2. Die Programmprüfung ist bestanden (alle zitierten Nummern existieren, jeder Satz hat ein Zitat). Ist die Antwort damit verlässlich?
Nein. Das Programm prüft nur das Format: ob Nummern existieren und ob Zitate gesetzt sind. Ob der zitierte Abschnitt den Satz tatsächlich stützt, kann es nicht beurteilen. Die inhaltliche Treue muss ein Mensch prüfen oder ein anderes Modell beurteilen.
3. Warum gibt man dem Modell eine feste Formulierung wie „in der Dokumentation wurde nichts dazu gefunden“?
Ohne klaren Ausweg ergänzt das Modell bei unzureichenden Unterlagen eher mit eigenem Wissen, und genau das kann Fehler einführen. Mit einer festen Formulierung weiß es, dass „weiß ich nicht“ eine akzeptable Antwort ist, und das Programm kann an diesem Satz erkennen, dass die Suche keine Antwort gefunden hat.
Fragen und Diskussion
Hängst du in dieser Lektion fest? Frag hier. Und wenn du die Frage von jemandem beantworten kannst, tu es gern.
Eine Frage bringt 3 Punkte, eine Antwort 6. Beiträge erscheinen nach der Prüfung.
Diskussion wird geladen…