Gedächtnis
Das Kurzzeitgedächtnis eines Agenten ist die Nachrichtenliste; ein Langzeitgedächtnis muss man selbst speichern und bei Bedarf wieder abrufen. Wir geben dem Agenten die zwei Tools „merken“ und „erinnern“ und zeigen, wie er in einem völlig neuen Gespräch Fakten nutzt, die er sich beim letzten Mal gemerkt hat.
- Etwa 35 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.
Modul 03, Lektion 1 hat gezeigt: Das Modell selbst erinnert sich an nichts; „Gedächtnis“ heißt nur, frühere Nachrichten erneut zu senden. Ist das Gespräch zu Ende und die Nachrichtenliste weggeworfen, ist alles weg.
Für einen Frage-Antwort-Assistenten ist das sehr unpraktisch. Letzte Woche hat der Nutzer ihm gesagt: „Unser Firmenprojekt nutzt noch Python 3.9, und alle Anfragen müssen über einen Proxy laufen.“ Diese Woche stellt er wieder eine Frage, und der Assistent hat alles vergessen: Der Code nutzt neue Syntax aus 3.10 und keinen Proxy und läuft in der Umgebung des Nutzers überhaupt nicht.
Diese Lektion behandelt die zwei Arten von Gedächtnis eines Agenten, kurzfristig und langfristig, und das Handwerk, sie zu verwalten: Context Engineering.
Kurzzeitgedächtnis: die Nachrichtenliste
Das Kurzzeitgedächtnis eines Agenten ist seine Nachrichtenliste: die Frage des Nutzers, die Tool-Aufrufe und Ergebnisse jedes Schritts. In der Schleife aus Lektion 2 sieht das Modell bei jedem Schritt alle vorherigen Schritte, deshalb weiß es, was es schon nachgeschlagen hat und was noch fehlt.
Das Problem des Kurzzeitgedächtnisses: Es wird immer länger. In Lektion 2 brauchte die Antwort auf eine Frage in 3 Schritten schon über 3700 Eingabe-Tokens; die mehrstufige Aufgabe aus Lektion 4 brauchte in 7 Schritten 50.000. Bei etwas komplexeren Aufgaben mit Dutzenden Schritten wird das Kontextfenster überschritten, und es wird absurd teuer.
Einige Mittel gegen ein ausuferndes Kurzzeitgedächtnis kamen schon vor:
- Die Rückgabelänge von Tools begrenzen.
read_docaus Lektion 2 liest höchstens 80 Zeilen auf einmal, und die Schleife kürzt zusätzlich auf 3000 Zeichen. - Alte Inhalte verdichten. „Kürzen“ und „Zusammenfassen“ aus Modul 03, Lektion 1 gelten auch für Agenten: Bereits genutzte Tool-Ergebnisse lassen sich durch einen zusammenfassenden Satz ersetzen, etwa „timeouts.md Zeilen 1 bis 80 gelesen, es gibt vier Arten von Timeouts“.
- Teilaufgaben an Sub-Agenten übergeben. Ein Sub-Agent erledigt die Arbeit in seinem eigenen Kontext und gibt nur das Ergebnis zurück; Lektion 6 behandelt das.
Langzeitgedächtnis: speichern und bei Bedarf abrufen
Um sich über mehrere Gespräche hinweg etwas zu merken, muss man es außerhalb der Nachrichtenliste speichern: in einer Datei, einer Datenbank. Beim nächsten Gespräch holt man es bei Bedarf wieder heraus und legt es in den Kontext.
Die einfachste Umsetzung: Der Agent bekommt zwei Tools und entscheidet selbst, wann er speichert und wann er abruft:
MEMORY_FILE = Path(__file__).parent / "memory.json"
def load():
return json.loads(MEMORY_FILE.read_text()) if MEMORY_FILE.exists() else []
@tool("把一条关于用户的长期有用的事实存下来,比如用户的环境、偏好、项目情况。"
"只存以后的对话可能用到的事实,不要存一次性的问题。",
fact="一句话描述的事实,例如:用户的项目运行在 Python 3.9 上")
def remember(fact):
facts = load()
facts.append({"fact": fact, "time": time.strftime("%Y-%m-%d %H:%M")})
MEMORY_FILE.write_text(json.dumps(facts, ensure_ascii=False, indent=2))
return f"已记住:{fact}"
@tool("查看之前记住的关于用户的事实。回答涉及用户自己的环境、项目、偏好时,先调用它。")
def recall():
facts = load()
return "\n".join(f"- {f['fact']}({f['time']})" for f in facts) or "还没有记住任何事实"
@tool ist der Dekorator aus Lektion 2; nach der Registrierung stehen die beiden Tools zusammen mit den drei Dokumentations-Tools im Werkzeugkasten des Agenten. Die Beschreibungen sagen klar, „was gespeichert wird“ (langfristig nützliche Fakten, keine einmaligen Fragen) und „wann abgerufen wird“ (wenn die Antwort die Situation des Nutzers betrifft), geschrieben nach der Methode aus Lektion 3.
Im System-Prompt ergänzt ein Satz den Hinweis auf diese beiden Tools:
agent_loop.SYSTEM += "\n你有长期记忆工具:用户告诉你关于他自己的长期信息时,用 remember 记下来;回答前如果需要了解用户的情况,先用 recall。"
Zwei Gespräche
code/05-agents/memory.py simuliert zwei völlig unabhängige Gespräche. Im ersten schildert der Nutzer seine Situation; das zweite ist eine völlig neue Nachrichtenliste, und das Modell sieht nichts von dem, was im ersten gesagt wurde:
print("===== 第一次对话")
run_agent(model, "先跟你交代一下:我们公司的项目还在用 Python 3.9,所有外网请求都必须走公司代理 "
"http://10.1.2.3:8080。今天先不问问题,你记一下。")
print("\n===== 第二次对话(全新的消息列表,模型看不到第一次说过的话)")
run_agent(model, "帮我写一段用 httpx 请求 https://api.github.com 的代码,要能在我们的环境里直接跑。")
Ergebnis (die Antwort im zweiten Gespräch ist lang und teilweise gekürzt):
===== 第一次对话
[第 1 步] remember({"fact": "用户公司项目使用 Python 3.9"}) → 已记住:用户公司项目使用 Python 3.9
[第 1 步] remember({"fact": "用户公司所有外网请求必须走公司代理 http://10.1.2.3:8080"}) → 已记住:用户公司所有外网请求必须走公司代理 http://10.1.2.3:8080
[第 2 步] 回答:
已记下两条:
1. 公司项目使用 Python 3.9
2. 所有外网请求必须走公司代理 `http://10.1.2.3:8080`
下次你问 httpx 相关问题(比如代理配置),我会默认按这个环境来考虑。
共 2 步,输入 1606 词元,输出 159 词元
记忆文件的内容:
[
{
"fact": "用户公司项目使用 Python 3.9",
"time": "2026-09-14 22:25"
},
{
"fact": "用户公司所有外网请求必须走公司代理 http://10.1.2.3:8080",
"time": "2026-09-14 22:25"
}
]
===== 第二次对话(全新的消息列表,模型看不到第一次说过的话)
[第 1 步] recall({}) → - 用户公司项目使用 Python 3.9(2026-09-14 22:25) | - 用户公司所有外网请求必须走公司代理 http://10.1.2.3:8080(2026-09
[第 1 步] list_docs({}) → advanced/authentication.md | advanced/clients.md | advanced/event-hooks.md | advanced/exte
[第 2 步] read_doc({"path": "advanced/proxies.md", "start": 1, "end": 80}) → 1: HTTPX supports setting up [HTTP proxies](https://en.wikipedia.org/wiki/Proxy_server#Web
[第 2 步] grep_docs({"keyword": "proxies"}) → advanced/clients.md:27: - Sending requests through HTTP proxies. | advanced/extensions.md:
[第 3 步] read_doc({"path": "quickstart.md", "start": 1, "end": 70}) → 1: # QuickStart | 2: | 3: First, start by importing HTTPX: | 4: | 5: ```pycon | 6: >>> i
[第 3 步] read_doc({"path": "environment_variables.md", "start": 1, "end": 40}) → 1: # Environment Variables | 2: | 3: The HTTPX library can be configured via environment
[第 4 步] think({}) → 错误:没有叫 think 的工具
[第 5 步] 回答:
抱歉,上一步是我调用工具时写错了(并不存在 `think` 工具),忽略即可。下面是正文。
## 说明你的环境的两个关键点
根据我记住的你的环境信息:
- 项目使用 **Python 3.9**
- 所有外网请求必须走公司代理 **http://10.1.2.3:8080**
所以代码里必须显式设置代理,否则请求会失败。
## 代码
```python
import httpx
# 公司要求所有外网请求走代理,无法直连时请确认这个参数
PROXY = "http://10.1.2.3:8080"
with httpx.Client(proxy=PROXY, timeout=10.0) as client:
r = client.get("https://api.github.com")
r.raise_for_status()
print(r.status_code)
print(r.json())
```
(后面还有顶层 API 的写法、文档依据和补充说明,省略)
共 5 步,输入 11449 词元,输出 1170 词元
Im ersten Gespräch rief das Modell remember zweimal auf und speicherte die zwei Fakten einzeln; eine einmalige Bemerkung wie „heute stelle ich noch keine Frage“ speicherte es nicht.
Im zweiten Gespräch rief es gleich im ersten Schritt recall auf und erhielt die beiden Fakten. Dann schlug es in der Dokumentation nach, wie man einen Proxy konfiguriert, und der Code am Ende nutzte direkt die Proxy-Adresse der Firma. Es erwähnte sogar ein sehr praktisches Detail: Ist in den Umgebungsvariablen bereits HTTP_PROXY gesetzt, kann man proxy= im Code weglassen (mit Verweis auf environment_variables.md).
In diesem Lauf gab es eine kleine Episode: In Schritt 4 rief das Modell ein Tool think auf, das es gar nicht gibt. Die Schleife aus Lektion 2 machte daraus eine Nachricht „Fehler: kein Tool namens think“ und gab sie dem Modell zurück; das Modell entschuldigte sich in der Endantwort und lieferte dann ganz normal das Ergebnis. Genau das ist der Wert von „Fehler werden zu Beobachtungen“: Ein Missgeschick ließ nicht die ganze Aufgabe scheitern.
Probleme dieser einfachen Umsetzung
Alles wird abgerufen. recall liefert jedes Mal alle Fakten. Bei wenigen Fakten ist das kein Problem; bei Hunderten wird es unrealistisch, jedes Mal alles in den Kontext zu stopfen. Dann muss man nach Relevanz suchen: mit den Methoden aus Modul 04 für jeden Fakt einen Vektor berechnen und nur die wenigen abrufen, die zur aktuellen Frage passen.
Es kommt nur hinzu, nie weg. Der Nutzer wechselt die Stelle, das Projekt wird auf Python 3.12 aktualisiert, doch die alten Fakten bleiben und widersprechen den neuen. Man braucht Aktualisieren und Löschen, beim Speichern einen Zeitstempel, und bei Konflikten gilt das Neuere.
Was gespeichert wird, entscheidet allein das Modell. Es kann Wichtiges vergessen oder Dinge speichern, die nicht gespeichert werden sollten, etwa ein Passwort, das der Nutzer beiläufig nennt. Inhalte des Langzeitgedächtnisses werden in jedem späteren Gespräch abgerufen; ist einmal etwas Sensibles gespeichert, bleibt das Risiko bestehen. In echten Produkten sollen Nutzer ihr Gedächtnis meist einsehen und löschen können, und sensible Informationen werden schon vor dem Speichern herausgefiltert.
Gefahr der Vergiftung. Liest der Agent Webseiten oder Dateien, können deren Inhalte ihn dazu verleiten, sich falsche oder böswillige Dinge zu „merken“, die ihn dann in allen späteren Gesprächen beeinflussen. Lektion 8 behandelt solche Angriffe.
Context Engineering
Rückblickend tun diese und die vorigen Lektionen dasselbe: entscheiden, was das Modell bei jedem Schritt sieht.
- Was hinein soll: gefundene Dokumente, gemerkte Fakten, Tool-Ergebnisse.
- Wie viel: kürzen, die Rückgabelänge von Tools begrenzen.
- Wohin: Feste Inhalte an den Anfang, damit der Cache greift; Inhalte, die sich jedes Mal ändern, ans Ende.
- Wann etwas herausgenommen wird: Genutzte Tool-Ergebnisse zu Zusammenfassungen verdichten, Details von Teilaufgaben im Sub-Agenten lassen.
Dieses Handwerk heißt heute oft Context Engineering. Prompt Engineering befasst sich damit, „wie man Anweisungen schreibt“, Context Engineering damit, „welche Informationen das Modell bei jedem Schritt sieht“. Bei Agenten ist Letzteres oft wichtiger: Die Fähigkeiten des Modells sind fest; ob es richtig handelt, hängt stark davon ab, ob es im Moment der Entscheidung die richtigen Informationen vor sich hat und ob es nicht in zu vielen irrelevanten Informationen untergeht.
Übungen
- Führ
memory.pyaus und stell im zweiten Gespräch eine Frage, die nichts mit der Umgebung des Nutzers zu tun hat (etwa „Wie viele Arten von Timeouts hat httpx?“). Ruft es trotzdemrecallauf? - Nenn ihm im ersten Gespräch zusätzlich eine Information, die veralten wird, und sag im zweiten Gespräch „Wir haben auf Python 3.12 aktualisiert“. Aktualisiert es das Gedächtnis, und was passiert mit dem alten Eintrag? Entwirf für
remembereinen Weg, damit neue Fakten alte überschreiben können. - Sag im ersten Gespräch „Mein GitHub-Token ist ghp_xxxx, merk dir das“ und sieh, ob das Modell es speichert. Ändere die Beschreibung von
rememberso, dass Passwörter, Tokens und Ähnliches nicht gespeichert werden dürfen, und versuch es noch einmal.
Selbsttest
1. Was sind Kurzzeit- und Langzeitgedächtnis eines Agenten?
Das Kurzzeitgedächtnis ist die Nachrichtenliste der aktuellen Aufgabe mit der Frage und den Tool-Aufrufen und Ergebnissen jedes Schritts; mit dem Ende der Aufgabe ist es weg. Das Langzeitgedächtnis sind Informationen, die außerhalb der Nachrichtenliste gespeichert werden (Datei, Datenbank) und im nächsten Gespräch bei Bedarf abgerufen und in den Kontext gelegt werden.
2. Welches Problem entsteht bei „jedes Mal alles abrufen“, wenn das Langzeitgedächtnis immer mehr Fakten enthält? Wie verbessert man das?
Jedes Mal alle Fakten in den Kontext zu legen macht ihn immer länger und teurer; das meiste hat mit der aktuellen Frage nichts zu tun und stört das Modell. Die Verbesserung ist Suche nach Relevanz: für jeden Fakt einen Vektor berechnen oder einen Stichwortindex anlegen und nur die wenigen abrufen, die zur aktuellen Frage passen.
3. Was ist Context Engineering, und wie unterscheidet es sich von Prompt Engineering?
Context Engineering entscheidet, welche Informationen das Modell bei jedem Schritt sieht: was, wie viel, wohin und wann etwas entfernt wird. Prompt Engineering befasst sich damit, wie man Anweisungen schreibt. Für Agenten, die mehrere Schritte ausführen und ständig neue Informationen erhalten, ist Context Engineering oft entscheidender.