恢复 SQLite 历史记录#
重新打开一个真实的临时数据库,恢复历史记录,对消息分页,更新标题,然后删除会话。
运行示例#
在仓库根目录下:
uv run python docs/_examples/sessions.py
输出包含:
Raw roles: system, user, assistant, system, user, assistant
这个程序使用确定性的离线模型,并在需要时使用临时存储。它不需要 API 密钥,由文档测试套件执行。
可以带入你应用的做法#
为一个对话保留一个稳定的 session_id,并在进程重启时针对同一个数据库打开持久化扩展。示例在创建第二个客户端之前先关闭了第一个连接,因此恢复的历史记录来自 SQLite,而不是内存缓存。
async def main() -> None:
# No demo touches the default database under the user's home directory.
with TemporaryDirectory(prefix="zett-docs-") as directory:
path = Path(directory) / "sessions.sqlite"
session_id = "project-notes"
config = AgentRunConfig(session_id=session_id)
first_storage = SQLiteSessionExtension(path)
try:
first = await create_agent(TurnModel(), config=config, extensions=[first_storage])
print((await first.run("Remember Python", metadata={"origin": "tutorial"})).content)
finally:
await first_storage.close()
restored_storage = SQLiteSessionExtension(path)
try:
restored = await create_agent(TurnModel(), config=config, extensions=[restored_storage])
print((await restored.run("Continue")).content)
rows = await restored_storage.list_raw_messages(session_id)
assert [row.message.role.value for row in rows] == [
"system",
"user",
"assistant",
"system",
"user",
"assistant",
]
assert rows[0].metadata == {"origin": "tutorial"}
assert len(await restored_storage.list_raw_messages(session_id, limit=2, offset=2)) == 2
view = await restored_storage.storage.load(session_id)
assert view.snapshot is None and len(view.raw_tail) == 6
await restored_storage.update_session(session_id, title="Project notes")
renamed = await restored_storage.get_session(session_id)
assert renamed is not None and renamed.title == "Project notes"
assert await restored_storage.delete_session(session_id)
assert await restored_storage.list_raw_messages(session_id) == []
print("Raw roles: system, user, assistant, system, user, assistant")
print("Session restored, renamed, and deleted in a temporary database")
finally:
await restored_storage.close()
示例还会对消息分页、重命名对话并删除它。它只删除临时数据库中的会话。在你的应用中,删除会话会移除历史记录;应把它置于明确的用户操作之后。
完整源码#
1"""Restore a conversation through a new SQLite connection and a new Agent."""
2
3import asyncio
4from collections.abc import AsyncIterator
5from pathlib import Path
6from tempfile import TemporaryDirectory
7
8from zett_agent.agent import AgentRunConfig
9from zett_agent.client import create_agent
10from zett_agent.extensions.sqlite import SQLiteSessionExtension
11from zett_agent.messages import (
12 AssistantMessage,
13 UserMessage,
14)
15from zett_agent.model import (
16 ModelEvent,
17 ModelRequest,
18 ModelResponse,
19 RetryOptions,
20)
21
22
23class TurnModel:
24 retry = RetryOptions(max_retries=0)
25
26 async def stream(self, request: ModelRequest) -> AsyncIterator[ModelEvent]:
27 turn = sum(isinstance(message, UserMessage) for message in request.messages)
28 yield ModelEvent.completed(ModelResponse(AssistantMessage(content=f"Stored turn {turn}")))
29
30
31async def main() -> None:
32 # No demo touches the default database under the user's home directory.
33 with TemporaryDirectory(prefix="zett-docs-") as directory:
34 path = Path(directory) / "sessions.sqlite"
35 session_id = "project-notes"
36 config = AgentRunConfig(session_id=session_id)
37 first_storage = SQLiteSessionExtension(path)
38 try:
39 first = await create_agent(TurnModel(), config=config, extensions=[first_storage])
40 print((await first.run("Remember Python", metadata={"origin": "tutorial"})).content)
41 finally:
42 await first_storage.close()
43
44 restored_storage = SQLiteSessionExtension(path)
45 try:
46 restored = await create_agent(TurnModel(), config=config, extensions=[restored_storage])
47 print((await restored.run("Continue")).content)
48 rows = await restored_storage.list_raw_messages(session_id)
49 assert [row.message.role.value for row in rows] == [
50 "system",
51 "user",
52 "assistant",
53 "system",
54 "user",
55 "assistant",
56 ]
57 assert rows[0].metadata == {"origin": "tutorial"}
58 assert len(await restored_storage.list_raw_messages(session_id, limit=2, offset=2)) == 2
59 view = await restored_storage.storage.load(session_id)
60 assert view.snapshot is None and len(view.raw_tail) == 6
61 await restored_storage.update_session(session_id, title="Project notes")
62 renamed = await restored_storage.get_session(session_id)
63 assert renamed is not None and renamed.title == "Project notes"
64 assert await restored_storage.delete_session(session_id)
65 assert await restored_storage.list_raw_messages(session_id) == []
66 print("Raw roles: system, user, assistant, system, user, assistant")
67 print("Session restored, renamed, and deleted in a temporary database")
68 finally:
69 await restored_storage.close()
70
71
72if __name__ == "__main__":
73 asyncio.run(main())
下一步:阅读保存并恢复对话了解存储选择和资源归属,或阅读压缩而不丢失历史记录了解长对话。