Modul 05 · Lektion 4

Planen und Selbstprüfung

Dieselbe mehrstufige Aufgabe, drei Vorgehensweisen im Vergleich – direkt erledigen, erst einen Plan erstellen und dann erledigen, nach dem Erledigen selbst prüfen. Der Plan kostete doppelt so viel bei etwa gleichem Ergebnis; die Selbstprüfung fand tatsächlich zwei Fehler bei den Quellenangaben, kostete aber viermal so viel.

  • Etwa 40 Minuten
  • Niveau: Fortgeschritten
  • Getestet: 2026-09-14 deepseek-flash

Code und Programmausgaben stehen genau so da, wie sie gelaufen sind – Kommentare und Ausgaben sind daher auf Chinesisch.

In Artikeln über Agenten fehlen zwei Techniken fast nie: „Planen“ (planning) und „Reflexion“ (reflection). Erst lässt man das Modell einen Plan machen und dann ausführen; nach der Ausführung lässt man es das eigene Ergebnis prüfen und Probleme beheben. Das klingt vernünftig; auch Menschen gehen komplexe Aufgaben so an.

Aber diese Techniken brauchen alle zusätzliche Modellaufrufe. Wie viel bringen sie wirklich, und ist es das Geld wert? Diese Lektion misst es an einer echten mehrstufigen Aufgabe.

Die Aufgabe

„Vergleiche, ob httpx' Client und AsyncClient bei drei Dingen gleich konfiguriert werden: Timeout, Proxy, HTTP/2. Stelle es als Tabelle dar und gib in jeder Zelle die Quelle in der Dokumentation an (Dateiname und Zeilennummer).“

Diese Aufgabe ist komplexer als die bisherigen Fragen: Drei verschiedene Themen müssen nachgeschlagen werden, bei jedem Thema beide Clients einzeln betrachtet und die Quellen genau festgehalten werden. Verwendet werden wieder der Agent aus Lektion 2 und die drei Dokumentations-Tools.

Vorgehen 1: direkt erledigen

Die Aufgabe geht direkt an den Agenten, der selbst entscheidet, wie er nachschlägt.

Vorgehen 2: erst ein Plan

Zuerst ein Modellaufruf, der nur einen Plan erstellen und keine Tools aufrufen darf. Dann wird der Plan an die Aufgabe angehängt und dem Agenten zur Ausführung übergeben:

def with_plan():
    # 第一步:只列计划,不调用工具
    plan, usage = model([{"role": "system", "content": SYSTEM}, {"role": "user", "content":
                         TASK + "\n\n先不要调用工具。列出你打算怎么查,编号列出每一步要找什么,不超过 6 步。"}], None)
    answer, messages, stats = loop([
        {"role": "system", "content": SYSTEM},
        {"role": "user", "content": TASK + "\n\n按这个计划执行,执行中发现计划不对可以调整:\n" + plan.content},
    ])
    ……

Der Satz „stellst du bei der Ausführung fest, dass der Plan nicht stimmt, darfst du ihn anpassen“ ist wichtig. Der Plan entsteht, bevor irgendetwas nachgeschlagen wurde; hält man sich stur daran, verpasst man Hinweise, die man erst beim Nachschlagen entdeckt.

Vorgehen 3: erledigen, dann prüfen

Erst direkt erledigen; liegt die Antwort vor, bekommt das Modell die Antwort zusammen mit allen Originaltexten, die der Agent unterwegs gefunden hat, und prüft Zelle für Zelle:

def with_reflection():
    answer, messages, stats = plain()
    evidence = "\n\n".join(m["content"] for m in messages if m["role"] == "tool")
    review, usage = model([{"role": "user", "content": f"""下面是一份回答和查到的全部原文。逐格检查回答里的表格:
每一格的说法,原文里有没有依据?注明的出处(文件和行号)对不对?
只列出有问题的格子和原因。全部没问题就只回复"没有问题"。

回答:
{answer}

原文:
{evidence[:20000]}"""}], None)
    if "没有问题" in review.content[:20]:
        return answer, messages, stats
    # 有问题就把检查意见交回给智能体,让它继续查、修改回答
    messages += [{"role": "assistant", "content": answer},
                 {"role": "user", "content": "有人检查了你的回答,意见如下。需要的话继续查文档,然后给出修改后的完整回答。\n\n" + review.content}]
    revised, messages, more = loop(messages)
    ……

Grundlage der Prüfung sind die „gefundenen Originaltexte“, also die Rückgaben der Tools, nicht das Gedächtnis des Modells. Lektion 6 des vorigen Moduls hat gezeigt, dass ein Gutachter, der aus dem Gedächtnis urteilt, sich irrt; deshalb prüft er hier gegen das Material. Gibt es Probleme, gehen die Prüfhinweise an den Agenten zurück, der weiter in der Dokumentation suchen und dann die Antwort überarbeiten kann.

Vollständiger Code in code/05-agents/planning_reflection.py.

Ergebnisse

Jedes Vorgehen einmal ausgeführt (die Antworten sind alle lang; hier nur die Statistik und die wesentlichen Teile):

===== 直接做
  4 次模型调用,9 次工具调用,13155 词元,7 秒
===== 先列计划
  5 次模型调用,13 次工具调用,26086 词元,12 秒
===== 做完再检查
  7 次模型调用,14 次工具调用,50132 词元,17 秒

Direkt erledigen liefert schon eine gute Antwort. In der Zeile HTTP/2 fand es in http2.md, Zeile 50 den Originaltext „HTTP/2 support is available on both Client and AsyncClient“, mit der klaren Aussage „gleich“. Bei Timeout und Proxy sagte es wahrheitsgemäß, dass die Beispiele der Dokumentation nur httpx.Client zeigen und keine Schreibweise für AsyncClient; man könne also nur folgern, dass beide übereinstimmen, „die Belege sind begrenzt“. Das ist gut abgewogen: Eine Schlussfolgerung wird nicht als Tatsache ausgegeben.

Ein kleines Problem: Der erste Satz seiner Antwort war englisch, „Based on the documentation, here is the comparison table“. Nachdem ein Agent viel englische Dokumentation gelesen hat, rutscht die Antwortsprache manchmal ab. Die Anweisung „auf Chinesisch antworten“ im System-Prompt verhindert das.

Erst ein Plan brauchte 1 Modellaufruf mehr, die Tool-Aufrufe stiegen von 9 auf 13, die Tokens verdoppelten sich, und es dauerte 5 Sekunden länger. Der Plan sah so aus:

1. 找 `Client` 的文档,定位它关于超时(timeout)的配置参数与说明。
2. 找 `AsyncClient` 的文档,定位它关于超时(timeout)的配置参数与说明,比对是否一致。
3. 分别在 `Client` 和 `AsyncClient` 文档中找代理(proxy/proxies)相关配置,比对。
4. 分别在 `Client` 和 `AsyncClient` 文档中找 HTTP/2 相关配置(如 http2 参数),比对。
5. 检查两者的基类/继承关系或 API 参考页,确认是否共用同一套初始化参数……

Schritt 5 des Plans brachte etwas Neues: Es sah sich api.md an, stellte fest, dass die Mitgliederlisten der beiden Klassen fast gleich sind, nur close und aclose unterscheiden sich, und stützte damit die Aussage, „beide teilen dieselben Konfigurationsparameter“. Das Endergebnis war aber dasselbe wie beim direkten Erledigen: HTTP/2 klar belegt, Timeout und Proxy nur gefolgert. Doppelt so viel Geld, keine grundlegend andere Aussage.

Erledigen, dann prüfen fand echte Probleme. Die Prüfhinweise nannten zwei falsche Quellenangaben; der Agent schlug weiter nach und vermerkte die Korrekturen in der überarbeiteten Antwort:

### 本次更正的两处(评审意见成立)

1. 原标注 `advanced/timeouts.md:66-68`("`httpx.Timeout` 细调")有误:`:66-68` 只是 `httpx.Timeout(10.0, connect=60.0)` 与 `httpx.Client(timeout=timeout)` 的示例代码。`httpx.Timeout` 的细调说明实际在 `advanced/timeouts.md:41-68`(标题 `## Fine tuning the configuration` 在 `:41`)。……
2. 原标注 `advanced/transports.md:223` 不能作为 `timeout` 构造参数的出处:该行是 `httpx.HTTPTransport(proxy=proxy, **kwargs)`,只涉及 transport 的 `proxy`/`**kwargs`,与客户端 `timeout` 无关。已删除该引用。

Ich habe timeouts.md nachgeprüft: Zeile 41 ist tatsächlich die Überschrift „## Fine tuning the configuration“, die Zeilen 66 bis 68 sind tatsächlich nur Beispielcode. Die erste Korrektur stimmt. Außerdem strich es eine irrelevante Quellenangabe aus der ersten Fassung. Ungenaue Quellenangaben entdecken Leser kaum selbst, und genau darin ist die Prüfung am besten.

Der Preis: 7 Modellaufrufe, 50.000 Tokens, fast das Vierfache des direkten Erledigens. Der Prüfschritt muss alle gefundenen Originaltexte enthalten; das ist der Hauptgrund für die Kosten.

Die überarbeitete Antwort zeigt aber auch eine bemerkenswerte Veränderung: Aus „HTTP/2 gleich, Timeout und Proxy nur gefolgert“ wurde in der Überschrift auffällig „bei allen drei Dingen ist die Konfiguration völlig gleich“. Zwar sagt der Text am Ende noch, dass Timeout und Proxy gefolgert sind, aber der Ton der Überschrift ist stärker als die Belege. Die Prüfung korrigierte die Quellen und machte zugleich die Formulierung der Aussage bestimmter. Auch eine überarbeitete Antwort muss man noch einmal lesen.

Wann es sich lohnt

Ein einzelnes Experiment beweist nichts endgültig, aber zusammen mit diesem Ergebnis ist meine Erfahrung:

Erst ein Plan passt zu Aufgaben mit vielen Schritten, bei denen leicht ein Teil vergessen wird, etwa „diese 10 Dateien alle ändern“. Der Plan hilft dem Modell, sich zu merken, was noch fehlt. Bei Aufgaben wie in dieser Lektion, die in drei bis fünf Schritten erledigt sind, bringt er wenig. Ein weiterer Nutzen: Man kann den Plan zuerst dem Nutzer zeigen und die Richtung bestätigen lassen, bevor ausgeführt wird; das ist viel billiger, als erst nach der Ausführung zu merken, dass die Richtung falsch war.

Erledigen, dann prüfen passt zu Aufgaben, deren Ergebnisse leicht Detailfehler enthalten und bei denen Fehler teuer sind, etwa Quellenangaben, Zahlen, Code. Bei der Prüfung unbedingt das Originalmaterial mitgeben, damit gegen das Material geprüft wird statt aus dem Gedächtnis. Sie ist teuer, also meist nur einmal am Endergebnis, nicht bei jedem Schritt.

Direkt erledigen ist bei den meisten Aufgaben die vernünftige Standardwahl. Erst direkt erledigen, eine Evaluation aufbauen, sehen, wo die Fehler hauptsächlich liegen, und dann gezielt Planen oder Prüfen ergänzen.

Übungen

  1. Füg in planning_reflection.py dem SYSTEM „auf Chinesisch antworten“ hinzu (oder die Sprache deiner Wahl), führ es erneut aus und sieh, ob der erste Satz beim „direkt erledigen“ noch englisch ist.
  2. Ändere den Prompt des Prüfschritts so, dass er keine Originaltexte bekommt, nur die Antwort („prüfe diese Antwort auf Fehler“), und führ es erneut aus. Wie ändert sich die Qualität der Prüfhinweise?
  3. Führ jedes der drei Vorgehen 3-mal aus und notiere jeweils Token-Zahl und Änderungen. Wie stark weicht ein einzelner Lauf vom Durchschnitt mehrerer Läufe ab?

Selbsttest

1. Warum sagt man dem Modell beim „erst planen, dann ausführen“, dass es „den Plan anpassen darf, wenn er nicht stimmt“?

Der Plan entsteht, bevor irgendetwas nachgeschlagen wurde; seine Schritte sind geraten. Informationen, die während der Ausführung gefunden werden, können zeigen, dass der ursprüngliche Plan nicht passt; hält man sich stur daran, geht man in die falsche Richtung.

2. Warum gibt man dem Modell beim Prüfen der eigenen Antwort die gefundenen Originaltexte mit?

Bekommt es nur die Antwort, kann es nur aus dem eigenen Gedächtnis beurteilen, was stimmt, und genau dieses Gedächtnis kann die Fehlerquelle sein; der Gutachter im vorigen Modul hat diesen Fehler gemacht. Mit den Originaltexten kann es Punkt für Punkt vergleichen und konkrete Probleme finden, etwa falsche Quellenangaben oder unbelegte Aussagen.

3. Im Experiment dieser Lektion fand die Selbstprüfung echte Fehler. Sollte man sie also bei jeder Aufgabe einsetzen?

Nicht unbedingt. Die Selbstprüfung kostete in dieser Lektion fast das Vierfache an Geld und mehr als das Doppelte an Zeit. Sie passt zu Aufgaben, bei denen Fehler teuer sind und leicht Detailfehler entstehen, und meist nur einmal am Endergebnis. Außerdem kann eine überarbeitete Antwort neue Probleme einführen, wie in dieser Lektion eine Formulierung, die bestimmter ist als die Belege.

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…