1.配置持久化后端
在《深度智能体—智能体加强版》中说明有四种持久化后端,可以在创建智能体时使用backend参数配置使用哪一种后端。
1.1 基于状态的持久化后端
调用create_deep_agent时如果未指定持久化后端,则缺省使用基于状态的持久化后端,基于状态的持久化是线程级的,数据保存线程状态中。
基于状态的持久化后端作为智能体的缓存可用于保存中间结果,可以对大量中间结果进行整理并根据需要从后端读取。
1.2基于文件系统的持久化后端
如下代码在创建智能体时指定使用基于文件系统的持久化后端:
from deepagents.backends import FilesystemBackend
"""
root_dir:指定文件系统路径
virtual_mode: 指定是否为虚拟化模式,如果为True则使用沙箱隔离
"""
agent = create_deep_agent(
model=llm,
backend=FilesystemBackend(root_dir=".", virtual_mode=True)
)
1.3基于store的持久化后端
如下代码在创建深度智能体指定基于store的持久化后端:
from langgraph.store.memory import InMemoryStore
from deepagents.backends import StoreBackendagent = create_deep_agent(
model=llm,
backend=(lambda rt: StoreBackend(rt)),
store=InMemoryStore()
)
1.4混合持久化后端
如下代码在创建深度智能体指定使用混合持久化后端:
from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend, StateBackend, FilesystemBackend#创建混合持久化后端。缺省为基于状态的后端,另外一个是基于文件系统的后端
composite_backend = lambda rt: CompositeBackend(
default=StateBackend(rt),"""
基于文件系统后端通过root_dir指定具体的路径。/memories/是路由,所有以/memories
开头的路径均指向基于文件系统的后端,非/memories开头的路径指向缺省的持久化后端
"""
routes={
"/memories/": FilesystemBackend(root_dir="/deepagents/myagent", virtual_mode=True),
},
)agent = create_deep_agent(
model=llm,
backend=composite_backend)
2.自定义持久化后端
以上四种是标准的持久化后端,还可以基于其他的存储,比如数据库创建持久化后端。自定义持久化后端时要集成BackendProtocol,并重载ls_info、read、write、edit、glob_info和grep_raw方法,其中:
1)ls_info:至少要包含path,is_dir,size和modified
2)read:返回从指定偏移开始的指定数量的内容,如果文件不存在,则必须返回"Error: File '/x' not found"
3)write:针对仅允许创建的场景。如果对指定文件写,则返回WriteResult(error=...)。写成功后,WriteResult要包括path=...,如果是基于状态的持久化后端需要包括files_update={...},如果是外部持久化后端(比如数据库),则要包含files_update=None
4)edit:同linux sed命令。替换指定字符串,可以全局替换,也可以仅仅替换第一个。
5)glob_info:同linux find命令。返回匹配的文件列表。
6)grep_raw:同linux grep命令。查找与指定模式匹配的行。如果正则表达式错误,则返回"Invalid regex pattern: ..."
如下代码基于PostgresSQL构建持久化后端:
(path text primary key, content text, created_at timestamptz, modified_at timestamptz)
from deepagents.backends.protocol import BackendProtocol, WriteResult, EditResult
from deepagents.backends.utils import FileInfo, GrepMatchclass PgBackend(BackendProtocol):
def ls_info(self, path: str) -> list[FileInfo]:
"""使用 WHERE path LIKE $1 || '%'查询数据库,然后每一行构建一个FileInfo,
返回FileInfo列表
"""
def read(self, file_path: str, offset: int = 0, limit: int = 2000) -> str:
"""使用WHERE path=$1查询数据库获取content,然后根据从offset开始提取数据,
最多2000个字符, 实现逻辑如下:
count = min(limit, len(content))
return content[offset:count]"""
def grep_raw(self, pattern: str, path: str | None = None, glob: str | None = None) -> list[GrepMatch] | str:
"""使用where根据glob查找符号条件的记录,然后遍历每条记录content,使用
正则表达式查找content中与pattern模式匹配的行,每个匹配组装成一个GrepMathch,
最后返回GrepMatch列表
"""
def glob_info(self, pattern: str, path: str = "/") -> list[FileInfo]:
"""使用where从数据库查找路径以path参数开头的并且与pattern匹配的记录,
最后返回FileInfo列表
"""
def write(self, file_path: str, content: str) -> WriteResult:
"""在数据库中查询一条新的记录,或者如果已经存在则直接覆盖其中的内容。
该方法可以仅支持增加文件信息。在返回的结果中WriteResult(path=file_path,
files_update=None)
"""
def edit(self, file_path: str, old_string: str, new_string: str, replace_all: bool = False) -> EditResult:
"""
针对指定的文件,获取其content,然后用re.sub执行替换操作
(用new_string替换old_string),再使用update用更新文件内容。
返回结果中包含替换次数
replace_all如果为False则仅替换old_string第一次出现的地方,否则全文替换。
"""
3.后端过滤器
正如在web应用中通过过滤器实现一些额外处理,比如防SQL,XSS攻击一样。也可以在可以对持久化后端做进一步封装,制作自己的过滤器,在过滤器中实现用户自己的业务规则,比如限制对某些目录的读写。
实现后端过滤器,可以直接继承标准后端,比如StateBackend或者FileSystemBackend,也可以继承BackendProtocol。如下代码继承后者,实现对于部分路径下文件访问保护,比如仅允许读,不允许写。
from deepagents.backends.protocol import BackendProtocol, WriteResult, EditResult
from deepagents.backends.utils import FileInfo, GrepMatch"""
所有的读操作均直接调用实际的持久化后端,所有的写操作,需要先判断是否允许写,
如果允许写,则调用实际的持久化后端执行写操作,否则返回错误。
"""
class PolicyWrapper(BackendProtocol):
def __init__(self, inner: BackendProtocol, deny_prefixes: list[str] | None = None):#inner一般是自定义的持久化后端,比如上面的PgBckend
self.inner = inner#deny_prefixes是一个目录列表。这些目录下的文件仅能读,不能写。
self.deny_prefixes = [p if p.endswith("/") else p + "/" for p in (deny_prefixes or [])]def _deny(self, path: str) -> bool:
return any(path.startswith(p) for p in self.deny_prefixes)def ls_info(self, path: str) -> list[FileInfo]:
return self.inner.ls_info(path)
def read(self, file_path: str, offset: int = 0, limit: int = 2000) -> str:
return self.inner.read(file_path, offset=offset, limit=limit)
def grep_raw(self, pattern: str, path: str | None = None, glob: str | None = None) -> list[GrepMatch] | str:
return self.inner.grep_raw(pattern, path, glob)
def glob_info(self, pattern: str, path: str = "/") -> list[FileInfo]:
return self.inner.glob_info(pattern, path)
def write(self, file_path: str, content: str) -> WriteResult:
if self._deny(file_path):
return WriteResult(error=f"Writes are not allowed under {file_path}")
return self.inner.write(file_path, content)
def edit(self, file_path: str, old_string: str, new_string: str, replace_all: bool = False) -> EditResult:
if self._deny(file_path):
return EditResult(error=f"Edits are not allowed under {file_path}")
return self.inner.edit(file_path, old_string, new_string, replace_all)
1245

被折叠的 条评论
为什么被折叠?



