сохранение чекпоинтов в sqlite

This commit is contained in:
Егор Кандрушин 2026-04-28 15:07:04 +03:00
parent b1e10f25b1
commit 42e6723abb
7 changed files with 82 additions and 3 deletions

View file

@ -8,9 +8,13 @@ RUN apt update && apt install make sudo -y
ENV AGENT_USER="agent" ENV AGENT_USER="agent"
ENV WORKSPACE_DIR="/workspace/" ENV WORKSPACE_DIR="/workspace/"
ENV INTERNAL_DATA_DIR="/internal_data/"
RUN useradd --shell /bin/bash $AGENT_USER \ RUN useradd --shell /bin/bash $AGENT_USER \
&& mkdir -p $WORKSPACE_DIR /home/$AGENT_USER \ && mkdir -p $WORKSPACE_DIR /home/$AGENT_USER \
&& chown -R agent:agent $WORKSPACE_DIR /home/$AGENT_USER && chown -R agent:agent $WORKSPACE_DIR /home/$AGENT_USER
RUN mkdir -p $INTERNAL_DATA_DIR \
&& chown -R root:root $INTERNAL_DATA_DIR \
&& chmod o-rwx $INTERNAL_DATA_DIR
FROM base AS builder FROM base AS builder

View file

@ -21,6 +21,7 @@ services:
- ./src:/app/src - ./src:/app/src
- ${AGENT_API_PATH}:/agent_api/ - ${AGENT_API_PATH}:/agent_api/
- ./data/workspace:/workspace/ - ./data/workspace:/workspace/
- ./data/internal:/internal_data/
ports: ports:
- "8000:8000" - "8000:8000"
env_file: env_file:

View file

@ -11,4 +11,6 @@ dependencies = [
"langchain-openai>=1.1.12", "langchain-openai>=1.1.12",
"composio>=0.11.5", "composio>=0.11.5",
"composio-langchain>=0.11.5", "composio-langchain>=0.11.5",
"langgraph-checkpoint-sqlite>=3.0.3",
"aiosqlite>=0.22.1",
] ]

View file

@ -6,8 +6,10 @@ from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph.state import CompiledStateGraph from langgraph.graph.state import CompiledStateGraph
from composio import Composio from composio import Composio
from composio_langchain import LangchainProvider from composio_langchain import LangchainProvider
from langgraph.checkpoint.sqlite import SqliteSaver
from src.agent.tools import send_file, execute_shell from src.agent.tools import send_file, execute_shell
from src.agent.checkpointer import get_active_checkpointer
class Agent(CompiledStateGraph): class Agent(CompiledStateGraph):
@ -38,14 +40,16 @@ def create_agent() -> Agent:
} }
) )
checkpointer = get_active_checkpointer()
# noinspection PyTypeChecker # noinspection PyTypeChecker
# create_deep_agent возвращает CompiledStateGraph, но ниже мы его дополняем так, чтобы он соответствовал сигнатуре Agent # create_deep_agent возвращает CompiledStateGraph, но ниже мы его дополняем так, чтобы он соответствовал сигнатуре Agent
agent: Agent = create_deep_agent( agent: Agent = create_deep_agent(
model=model, model=model,
system_prompt="You are a helpful assistant. Use Composio tools to take action when needed.", system_prompt="You are a helpful assistant. Use Composio tools to take action when needed.",
checkpointer=MemorySaver(),
tools=tools + [send_file, execute_shell], tools=tools + [send_file, execute_shell],
backend=backend, backend=backend,
checkpointer=checkpointer,
permissions=[ permissions=[
FilesystemPermission( FilesystemPermission(
operations=["read", "write"], operations=["read", "write"],

27
src/agent/checkpointer.py Normal file
View file

@ -0,0 +1,27 @@
from contextlib import asynccontextmanager
import os
from typing import AsyncIterable
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
from pathlib import Path
_instance: AsyncSqliteSaver | None = None
def get_active_checkpointer() -> AsyncSqliteSaver:
if not _instance:
raise RuntimeError("Checkpointer not initialized")
return _instance
@asynccontextmanager
async def create_checkpointer() -> AsyncIterable[AsyncSqliteSaver]:
global _instance
internal_data_dir = os.environ["INTERNAL_DATA_DIR"]
filepath = Path(internal_data_dir) / "checkpoint.sqlite"
async with AsyncSqliteSaver.from_conn_string(filepath) as saver:
_instance = saver
yield saver
_instance = None

View file

@ -4,10 +4,12 @@ from fastapi import FastAPI
from src.api.external import router as ws_router from src.api.external import router as ws_router
from src.agent import AgentService from src.agent import AgentService
from src.agent.checkpointer import create_checkpointer
@asynccontextmanager @asynccontextmanager
async def lifespan(app: FastAPI): async def lifespan(app: FastAPI):
async with create_checkpointer():
AgentService() # инициализируем синглтон AgentService() # инициализируем синглтон
yield yield

39
uv.lock generated
View file

@ -7,24 +7,37 @@ name = "agent"
version = "0.1.0" version = "0.1.0"
source = { virtual = "." } source = { virtual = "." }
dependencies = [ dependencies = [
{ name = "aiosqlite" },
{ name = "composio" }, { name = "composio" },
{ name = "composio-langchain" }, { name = "composio-langchain" },
{ name = "deepagents" }, { name = "deepagents" },
{ name = "fastapi" }, { name = "fastapi" },
{ name = "langchain-openai" }, { name = "langchain-openai" },
{ name = "langgraph-checkpoint-sqlite" },
{ name = "uvicorn", extra = ["standard"] }, { name = "uvicorn", extra = ["standard"] },
] ]
[package.metadata] [package.metadata]
requires-dist = [ requires-dist = [
{ name = "aiosqlite", specifier = ">=0.22.1" },
{ name = "composio", specifier = ">=0.11.5" }, { name = "composio", specifier = ">=0.11.5" },
{ name = "composio-langchain", specifier = ">=0.11.5" }, { name = "composio-langchain", specifier = ">=0.11.5" },
{ name = "deepagents", specifier = ">=0.5.0" }, { name = "deepagents", specifier = ">=0.5.0" },
{ name = "fastapi", specifier = ">=0.135.3" }, { name = "fastapi", specifier = ">=0.135.3" },
{ name = "langchain-openai", specifier = ">=1.1.12" }, { name = "langchain-openai", specifier = ">=1.1.12" },
{ name = "langgraph-checkpoint-sqlite", specifier = ">=3.0.3" },
{ name = "uvicorn", extras = ["standard"], specifier = ">=0.34.0" }, { name = "uvicorn", extras = ["standard"], specifier = ">=0.34.0" },
] ]
[[package]]
name = "aiosqlite"
version = "0.22.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/4e/8a/64761f4005f17809769d23e518d915db74e6310474e733e3593cfc854ef1/aiosqlite-0.22.1.tar.gz", hash = "sha256:043e0bd78d32888c0a9ca90fc788b38796843360c855a7262a532813133a0650", size = 14821, upload-time = "2025-12-23T19:25:43.997Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/00/b7/e3bf5133d697a08128598c8d0abc5e16377b51465a33756de24fa7dee953/aiosqlite-0.22.1-py3-none-any.whl", hash = "sha256:21c002eb13823fad740196c5a2e9d8e62f6243bd9e7e4a1f87fb5e44ecb4fceb", size = 17405, upload-time = "2025-12-23T19:25:42.139Z" },
]
[[package]] [[package]]
name = "annotated-doc" name = "annotated-doc"
version = "0.0.4" version = "0.0.4"
@ -632,6 +645,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/65/4c/09a4a0c42f5d2fc38d6c4d67884788eff7fd2cfdf367fdf7033de908b4c0/langgraph_checkpoint-4.0.1-py3-none-any.whl", hash = "sha256:e3adcd7a0e0166f3b48b8cf508ce0ea366e7420b5a73aa81289888727769b034", size = 50453, upload-time = "2026-02-27T21:06:14.293Z" }, { url = "https://files.pythonhosted.org/packages/65/4c/09a4a0c42f5d2fc38d6c4d67884788eff7fd2cfdf367fdf7033de908b4c0/langgraph_checkpoint-4.0.1-py3-none-any.whl", hash = "sha256:e3adcd7a0e0166f3b48b8cf508ce0ea366e7420b5a73aa81289888727769b034", size = 50453, upload-time = "2026-02-27T21:06:14.293Z" },
] ]
[[package]]
name = "langgraph-checkpoint-sqlite"
version = "3.0.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiosqlite" },
{ name = "langgraph-checkpoint" },
{ name = "sqlite-vec" },
]
sdist = { url = "https://files.pythonhosted.org/packages/04/61/40b7f8f29d6de92406e668c35265f409f57064907e31eae84ab3f2a3e3e1/langgraph_checkpoint_sqlite-3.0.3.tar.gz", hash = "sha256:438c234d37dabda979218954c9c6eb1db73bee6492c2f1d3a00552fe23fa34ed", size = 123876, upload-time = "2026-01-19T00:38:44.473Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a3/d8/84ef22ee1cc485c4910df450108fd5e246497379522b3c6cfba896f71bf6/langgraph_checkpoint_sqlite-3.0.3-py3-none-any.whl", hash = "sha256:02eb683a79aa6fcda7cd4de43861062a5d160dbbb990ef8a9fd76c979998a952", size = 33593, upload-time = "2026-01-19T00:38:43.288Z" },
]
[[package]] [[package]]
name = "langgraph-prebuilt" name = "langgraph-prebuilt"
version = "1.0.11" version = "1.0.11"
@ -955,6 +982,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
] ]
[[package]]
name = "sqlite-vec"
version = "0.1.9"
source = { registry = "https://pypi.org/simple" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/68/85/9fad0045d8e7c8df3e0fa5a56c630e8e15ad6e5ca2e6106fceb666aa6638/sqlite_vec-0.1.9-py3-none-macosx_10_6_x86_64.whl", hash = "sha256:1b62a7f0a060d9475575d4e599bbf94a13d85af896bc1ce86ee80d1b5b48e5fb", size = 131171, upload-time = "2026-03-31T08:02:31.717Z" },
{ url = "https://files.pythonhosted.org/packages/a4/3d/3677e0cd2f92e5ebc43cd29fbf565b75582bff1ccfa0b8327c7508e1084f/sqlite_vec-0.1.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:1d52e30513bae4cc9778ddbf6145610434081be4c3afe57cd877893bad9f6b6c", size = 165434, upload-time = "2026-03-31T08:02:32.712Z" },
{ url = "https://files.pythonhosted.org/packages/00/d4/f2b936d3bdc38eadcbd2a87875815db36430fab0363182ba5d12cd8e0b51/sqlite_vec-0.1.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e921e592f24a5f9a18f590b6ddd530eb637e2d474e3b1972f9bbeb773aa3cb9", size = 160076, upload-time = "2026-03-31T08:02:33.796Z" },
{ url = "https://files.pythonhosted.org/packages/6f/ad/6afd073b0f817b3e03f9e37ad626ae341805891f23c74b5292818f49ac63/sqlite_vec-0.1.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux1_x86_64.whl", hash = "sha256:1515727990b49e79bcaf75fdee2ffc7d461f8b66905013231251f1c8938e7786", size = 163388, upload-time = "2026-03-31T08:02:34.888Z" },
{ url = "https://files.pythonhosted.org/packages/42/89/81b2907cda14e566b9bf215e2ad82fc9b349edf07d2010756ffdb902f328/sqlite_vec-0.1.9-py3-none-win_amd64.whl", hash = "sha256:4a28dc12fa4b53d7b1dced22da2488fade444e96b5d16fd2d698cd670675cf32", size = 292804, upload-time = "2026-03-31T08:02:36.035Z" },
]
[[package]] [[package]]
name = "starlette" name = "starlette"
version = "1.0.0" version = "1.0.0"