Article
第一章:Letta 概述
1.1 什么是 Letta(MemGPT)
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| Letta(原 MemGPT) | Letta 是一个开源框架,旨在通过模拟操作系统级别的内存管理机制(如核心内存、召回内存、档案内存),解决大语言模型(LLM)在长上下文对话、状态保持和工具调用中的局限性。它允许 LLM 智能体在有限上下文窗口内高效管理长期记忆与外部工具交互。 | Letta 并非 LLM 本身,而是一个运行在 LLM 之上的智能体运行时(Agent Runtime)。需配合 OpenAI、Ollama 或 vLLM 等后端使用。 |
| 智能体(Agent) | 在 Letta 中,智能体是具备自主推理、记忆管理和工具调用能力的 LLM 实例。每个智能体拥有独立的内存空间和行为策略。 | 智能体的状态(如记忆)默认持久化到本地 SQLite 数据库,可配置为远程存储。 |
| 内存分层架构 | Letta 将记忆分为三层:核心内存(Core Memory,始终在上下文中)、召回内存(Recall Memory,按时间检索的历史消息)、档案内存(Archival Memory,长期知识库,支持向量检索)。 | 核心内存大小受 LLM 上下文窗口限制,需谨慎设计其内容结构。 |
1.2 Letta 的核心特性
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| 分层内存系统 | 通过 Core / Recall / Archival 三层内存,实现对长期状态的有效管理,突破 LLM 上下文长度限制。 | Archival Memory 默认使用本地向量数据库(如 FAISS),可替换为 Pinecone、Weaviate 等。 |
| 工具调用(Tool Use) | 支持 LLM 自主调用预定义或自定义函数(如查询数据库、发送邮件、调用 API),并自动解析返回结果。 | 工具必须符合 Letta 的函数签名规范(JSON Schema + Python callable)。 |
| 持久化对话状态 | 所有智能体的交互历史、内存状态自动保存,重启后可恢复上下文。 | 默认使用 SQLite,生产环境建议切换至 PostgreSQL 或其他高可用数据库。 |
| 多后端 LLM 支持 | 原生支持 OpenAI API,同时兼容 Ollama、vLLM、LM Studio 等本地或私有 LLM 推理服务。 | 使用本地模型时需确保其支持 function calling 或通过 shim 层模拟。 |
| 命令行与 SDK 双接口 | 提供 CLI 快速交互,也提供 Python SDK 用于程序化控制智能体生命周期。 | CLI 适合调试,SDK 适合集成到应用系统中。 |
1.3 Letta 与其他 LLM 框架的对比
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| vs LangChain | LangChain 侧重于链式调用和组件拼接,而 Letta 聚焦于智能体的长期记忆与状态管理。LangChain 无内置内存分层机制。 | 二者可互补:Letta 处理状态,LangChain 处理复杂流程编排。 |
| vs LlamaIndex | LlamaIndex 专注于数据索引与检索增强(RAG),Letta 则构建完整智能体运行时,包含 RAG(通过 Archival Memory)但不止于此。 | LlamaIndex 可作为 Letta 的 Archival Memory 后端插件使用。 |
| vs AutoGen | AutoGen 强调多智能体通信与协作,Letta 更关注单个智能体的内部状态管理。两者在多智能体方向有交集。 | Letta 正在开发多智能体支持,未来可能与 AutoGen 功能重叠。 |
| vs Semantic Kernel | Semantic Kernel(微软)提供插件和记忆抽象,但内存模型较简单;Letta 的内存分层更精细,更适合长周期任务。 | Semantic Kernel 与 .NET 生态集成更深,Letta 以 Python 为主。 |
| vs CrewAI | CrewAI 专注任务驱动的多智能体团队,Letta 从单智能体底层状态出发,更适合作为基础运行时。 | 可将 Letta 智能体作为 CrewAI 中的 Agent 实现。 |
第二章:环境搭建与快速上手
2.1 安装 Letta
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 安装 Python 环境 | 确保系统已安装 Python 3.9 或更高版本。可通过 python --version 验证。 | 推荐使用虚拟环境(如 venv 或 conda)隔离依赖。 |
| 通过 pip 安装 Letta | 执行命令:pip install letta | 若需最新开发版,可从 GitHub 安装:pip install git+https://github.com/letta-ai/letta.git |
| 验证安装 | 执行命令:letta --help,应显示 CLI 帮助信息。 | 若提示命令未找到,请检查 PATH 或在虚拟环境中激活后重试。 |
| 可选:安装本地 LLM 支持 | 如需使用 Ollama,先安装 Ollama(https://ollama.com/),再安装额外依赖:`pip install “letta[local]“` | letta[local] 包含 llama-cpp-python 等依赖,编译耗时较长,建议网络稳定时操作。 |
2.2 配置 API 密钥(OpenAI / Local LLM)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 配置 OpenAI API 密钥 | letta configure(交互式)或设置环境变量 OPENAI_API_KEY | 初始化 Letta 运行所需的 LLM 后端凭证 | export OPENAI_API_KEY="sk-xxxx"letta configure# 在提示中选择 "openai" 作为 LLM provider | 若使用代理或非官方 API(如 Azure),需手动编辑 ~/.letta/config 文件。 |
| 配置 Ollama 本地模型 | letta configure,选择 LLM provider 为 ollama,并指定模型名(如 llama3) | 使用本地运行的开源模型,无需联网 | # 假设已运行 ollama serveletta configure# LLM provider: ollama# LLM model name: llama3 | 需提前通过 ollama pull llama3 下载模型;Ollama 默认监听 http://localhost:11434。 |
| 配置 LM Studio 或 vLLM | 在 letta configure 中选择 openai 作为 provider,但将 API base URL 指向本地(如 http://localhost:1234/v1) | 兼容任何 OpenAI-compatible 的本地推理服务器 | # LM Studio 示例API Base URL: http://localhost:1234/v1API Key: not-needed (可填任意字符串) | 必须确保本地服务启用了 function calling 支持,否则工具调用会失败。 |
2.3 创建第一个智能体(Agent)
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 使用 CLI 创建智能体 | letta create | 交互式创建新智能体,设置名称、内存初始值、工具集等 | letta create? Enter a name for your agent: my_first_agent? Select default persona: default? Select default human: default? Select tool presets: send_message, core_memory | 首次运行会自动下载默认 persona/human 配置文件到 ~/.letta/personas/ 和 ~/.letta/humans/。 |
| 使用 Python SDK 创建 | from letta import create_agent; agent = create_agent(name="test", tools=["send_message"]) | 在程序中动态创建智能体 | python\nfrom letta import create_agent\nagent = create_agent(\n name="my_sdk_agent",\n persona="I am a helpful assistant.",\n human="The user is a developer.",\n tools=["send_message", "archival_memory_search"]\n)\n | 需先调用 letta configure 完成全局配置,或通过 LettaConfig 显式传入 LLM 设置。 |
| 查看已有智能体列表 | letta list agents | 列出本地所有已保存的智能体 | letta list agents# 输出:my_first_agent, my_sdk_agent | 智能体元数据存储在 SQLite 数据库 ~/.letta/sqlite.db 中。 |
2.4 与智能体进行交互
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| CLI 交互模式 | letta run --agent <agent_name> | 启动 REPL 会话,与指定智能体实时对话 | letta run --agent my_first_agentUser: Hello!Agent: Hi! How can I help you today? | 输入 /exit 退出会话;输入 /memory 查看当前核心内存。 |
| 发送单条消息(CLI) | letta run --agent <name> --message "<text>" | 非交互式发送一条消息并返回响应 | letta run --agent my_first_agent --message "What's my name?" | 适用于脚本调用或自动化测试。 |
| Python SDK 发送消息 | agent.user_message(message="...") | 在代码中向智能体发送用户消息并获取响应 | python\nresponse = agent.user_message("Summarize today's tasks.")\nprint(response.messages[-1].text)\n | 返回对象包含完整消息流(含函数调用、系统消息等),需解析 .text 获取最终回复。 |
| 查看对话历史 | letta messages --agent <name> | 查看该智能体的所有历史消息(Recall Memory) | letta messages --agent my_first_agent | 输出按时间排序,包含用户、智能体、系统三类消息。 |
第三章:智能体(Agent)核心机制
3.1 智能体的组成结构
| 组件名称 | 说明 | 注意事项 |
|---|---|---|
| Persona | 定义智能体的”性格”和行为准则,通常是一段系统提示(system prompt),如 “I am a helpful, honest assistant.” | 存储在 ~/.letta/personas/ 目录下,支持自定义 YAML 或纯文本格式。 |
| Human | 描述用户角色的上下文信息,用于让智能体理解对话对象,如 “The user is a software engineer working on AI projects.” | 存储在 ~/.letta/humans/,可随用户身份动态切换。 |
| Core Memory | 智能体的核心状态存储区,始终包含在每次 LLM 调用的上下文中,分为 persona 和 human 两个字段。 | 总长度受 LLM 上下文窗口限制(如 8K tokens),需精简内容。 |
| Tools | 智能体可调用的函数集合,包括内置工具(如 send_message)和用户自定义工具。 | 工具必须注册为符合 Letta 规范的 Python 函数 + JSON Schema。 |
| Message Log | 所有历史交互记录(用户消息、智能体回复、函数调用结果等),构成 Recall Memory 的基础。 | 默认持久化到 SQLite,可通过 RecallMemory API 查询。 |
| Agent Config | 包含 LLM 配置、嵌入模型、内存后端等元数据,决定智能体运行时行为。 | 创建时继承全局配置(~/.letta/config),也可覆盖指定参数。 |
3.2 内存模型(Memory Model)详解
| 内存类型 | 说明 | 注意事项 |
|---|---|---|
| Core Memory | 分为 persona 和 human 两部分,始终拼接到 LLM 提示词开头,用于维持智能体身份和用户上下文。 | 修改方式:通过工具(如 core_memory_replace)或 SDK 方法;直接编辑不生效。 |
| Recall Memory | 按时间顺序存储所有消息(包括函数调用),支持分页查询(如最近 N 条)。 | 通过 letta messages --agent <name> 或 agent.get_messages() 访问;不参与向量检索。 |
| Archival Memory | 长期知识库存储,支持通过向量嵌入进行语义检索(RAG),用于补充 Core Memory 容量不足。 | 默认使用 FAISS 本地向量库;可通过 archival_memory_insert 工具写入,archival_memory_search 读取。 |
| Memory Persistence | 所有内存类型默认持久化到 ~/.letta/sqlite.db,重启后状态保留。 | 生产环境建议配置远程数据库(如 PostgreSQL)和向量数据库(如 Pinecone)。 |
| Memory Editing Mechanism | 智能体可通过内置工具(如 core_memory_append)自主修改 Core Memory,实现状态更新。 | 修改操作会触发新上下文生成,确保后续 LLM 调用使用最新状态。 |
3.3 工具调用(Tool Use)机制
| 方法名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 注册自定义工具 | 使用 @letta_tool() 装饰器定义函数,并提供 JSON Schema | 扩展智能体能力,如查询数据库、发送邮件 | python\nfrom letta import letta_tool\n\n@letta_tool(\n name="get_weather",\n description="Get current weather for a city",\n parameters={"type": "object", "properties": {"city": {"type": "string"}}}\n)\ndef get_weather(city: str) -> str:\n return f"Sunny in {city}"\n | 工具函数必须返回字符串;参数类型需与 JSON Schema 一致。 |
| 内置工具:send_message | 无显式调用,由框架自动插入 | 允许智能体主动向用户发送多条消息(突破单次回复限制) | json\n{\n "function": "send_message",\n "arguments": {"message": "Part 1"}\n}\n | 用户无需注册,所有智能体默认可用。 |
| 内置工具:core_memory_replace | core_memory_replace(field="persona", content="...") | 替换 Core Memory 中的 persona 或 human 字段 | json\n{\n "function": "core_memory_replace",\n "arguments": {\n "field": "persona",\n "content": "I am now a financial advisor."\n }\n}\n | field 只能是 “persona” 或 “human”。 |
| 内置工具:archival_memory_insert | archival_memory_insert(content="...") | 向 Archival Memory 添加长期知识片段 | json\n{\n "function": "archival_memory_insert",\n "arguments": {\n "content": "User prefers email over SMS."\n }\n}\n | 内容将被嵌入并向量化存储。 |
| 内置工具:archival_memory_search | archival_memory_search(query="...", page=0, page_size=5) | 从 Archival Memory 中语义检索相关知识 | json\n{\n "function": "archival_memory_search",\n "arguments": {\n "query": "user contact preference"\n }\n}\n | 返回结果按相关性排序,支持分页。 |
3.4 消息流(Message Flow)与上下文管理
| 概念/步骤名称 | 说明 | 注意事项 |
|---|---|---|
| 消息类型 | 包括 user_message(用户输入)、assistant_message(LLM 生成文本)、function_call(LLM 请求调用工具)、function_return(工具执行结果) | 所有消息均带时间戳和来源标识,构成完整对话轨迹。 |
| 上下文构建流程 | 每次 LLM 调用前,Letta 自动组装:1) System prompt(含 Core Memory) 2) 最近 N 条 Recall Memory 消息(不超过 token 限制) 3) 当前用户消息 | 框架自动截断历史消息以适配上下文窗口,优先保留最近和关键消息。 |
| 函数调用循环 | 若 LLM 输出 function_call,Letta 执行对应工具 → 将结果作为 function_return 加入消息流 → 再次调用 LLM,直至输出 assistant_message | 最大循环次数默认为 10,防止无限递归。 |
| Token 预算管理 | Letta 在构建提示时实时计算 token 数量,确保不超过模型上限(如 gpt-4o 为 128K) | 使用 tiktoken 库精确计数;本地模型需手动指定上下文长度。 |
| 消息持久化 | 每条消息在生成后立即写入 SQLite 数据库,确保崩溃后可恢复 | 可通过 agent.get_messages(after=datetime) 实现增量同步。 |
第四章:内存管理(Memory Management)
4.1 核心内存(Core Memory)
| 方法/操作名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 查看 Core Memory | letta memory --agent <name>(CLI)或 agent.core_memory(SDK) | 获取当前智能体的 persona 和 human 内容 | letta memory --agent my_agent# 输出:# persona: I am a helpful assistant.# human: The user is a developer. | CLI 输出为纯文本;SDK 返回 CoreMemory 对象。 |
| 替换 Persona | 调用工具 core_memory_replace(field="persona", content="...") | 更新智能体身份描述 | json\n{\n "function": "core_memory_replace",\n "arguments": {\n "field": "persona",\n "content": "I am now a legal advisor."\n }\n}\n | 操作后,后续所有 LLM 调用将使用新 persona。 |
| 追加 Human 信息 | 调用工具 core_memory_append(field="human", content="...") | 在用户上下文末尾添加新信息 | json\n{\n "function": "core_memory_append",\n "arguments": {\n "field": "human",\n "content": " User works at Alibaba Cloud."\n }\n}\n | 不覆盖原有内容,仅追加;注意避免重复信息膨胀。 |
| SDK 直接读取 | agent.core_memory.get_field("persona") | 在程序中获取指定字段值 | python\npersona = agent.core_memory.get_field("persona")\nprint(persona)\n | 字段名必须为 “persona” 或 “human”。 |
| SDK 直接写入 | agent.core_memory.update_field("human", "New context") | 程序化更新 Core Memory(绕过工具调用) | python\nagent.core_memory.update_field("human", "User prefers Chinese responses.")\n | 仅建议在初始化或调试时使用;生产环境应通过工具保证一致性。 |
4.2 可召回内存(Recall Memory)
| 方法/操作名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 查看全部消息 | letta messages --agent <name> | 列出该智能体所有历史交互记录 | letta messages --agent my_agent# 输出按时间排序的消息列表 | 默认分页显示(每页 10 条),可用 --page 和 --page-size 控制。 |
| SDK 获取消息 | agent.get_messages(start=0, count=20) | 以编程方式获取最近 N 条消息 | python\nmsgs = agent.get_messages(count=5)\nfor m in msgs:\n print(f"[{m.role}] {m.text}")\n | start 为偏移量(从最新往旧),count 为数量。 |
| 按时间范围查询 | agent.get_messages(before=datetime, after=datetime) | 获取特定时间段内的对话记录 | python\nfrom datetime import datetime, timedelta\nyesterday = datetime.now() - timedelta(days=1)\nrecent = agent.get_messages(after=yesterday)\n | 时间基于 UTC;本地测试时注意时区转换。 |
| 消息结构字段 | 每条消息包含:id、role(user/assistant/function)、text、timestamp、tool_calls、tool_return | 用于分析对话行为或调试工具调用 | python\nmsg = agent.get_messages(count=1)[0]\nprint(msg.role, msg.text, msg.timestamp)\n | function 类型消息的 text 通常为空,逻辑在 tool_calls 中。 |
| 清空 Recall Memory | 目前无直接命令;需手动删除数据库记录或重建智能体 | 重置对话历史(谨慎操作) | # 高危操作:rm ~/.letta/sqlite.db# 推荐:letta delete --agent old_agent && letta create ... | 官方暂未提供 clear messages 命令,避免误删。 |
4.3 档案内存(Archival Memory)
| 方法/操作名称 | 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 插入知识片段 | 调用工具 archival_memory_insert(content="...") | 将长期知识存入向量数据库 | json\n{\n "function": "archival_memory_insert",\n "arguments": {\n "content": "User's favorite color is blue."\n }\n}\n | 内容将被嵌入模型编码为向量并存储。 |
| 语义检索 | 调用工具 archival_memory_search(query="...", page=0, page_size=5) | 根据语义相似度查找相关知识 | json\n{\n "function": "archival_memory_search",\n "arguments": {\n "query": "What does the user like?"\n }\n}\n | 返回结果按相似度降序排列;支持分页。 |
| CLI 查看档案 | letta archival --agent <name> --search "<query>" | 在终端中搜索 Archival Memory | letta archival --agent my_agent --search "color" | 若未指定 --search,则列出所有条目(不推荐,性能差)。 |
| SDK 批量插入 | agent.archival_memory.insert(["fact1", "fact2"]) | 程序化导入大量知识 | python\nagent.archival_memory.insert([\n "User has two children.",\n "Prefers morning meetings."\n])\n | 自动批量嵌入,效率高于逐条调用工具。 |
| 更换嵌入模型 | 在 letta configure 中指定 embedding_endpoint 和 embedding_model | 使用自定义或本地嵌入模型(如 BGE) | # 配置示例Embedding endpoint type: hugging-faceEmbedding model: BAAI/bge-small-en-v1.5 | 需确保嵌入维度与向量库一致;FAISS 默认支持任意维度。 |
4.4 内存持久化与检索
| 组件/操作名称 | 说明 | 注意事项 |
|---|---|---|
| 默认存储后端 | SQLite 数据库存储 Core + Recall Memory;FAISS 向量库存储 Archival Memory | 文件位置:~/.letta/sqlite.db 和 ~/.letta/archival_index/ |
| 数据库结构 | agents 表(元数据)、messages 表(Recall)、agent_state(Core Memory 快照) | 可直接用 DB Browser for SQLite 查看,但禁止手动修改运行中数据。 |
| 向量索引格式 | FAISS 的 IndexFlatIP(内积相似度),支持 HNSW 等索引类型(需自定义) | 当前版本不支持动态切换索引类型,需修改源码。 |
| 备份与迁移 | 复制整个 ~/.letta/ 目录即可迁移所有智能体状态 | 跨机器迁移时需确保 LLM 和嵌入模型配置一致。 |
| 远程存储扩展 | 可通过实现 StorageConnector 接口替换默认后端(如 PostgreSQL + Pinecone) | 官方提供示例插件,但需自行部署和测试;非开箱即用。 |
| 检索一致性保障 | 每次 archival_memory_insert 后立即更新向量索引,确保下次 search 可见 | 无事务机制,极端情况下可能丢失最后一条插入。 |
第五章:工具集成(Tool Integration)
5.1 内置工具(Built-in Tools)
| 工具名称 | 语法(JSON 调用格式) | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| send_message | {"function": "send_message", "arguments": {"message": "text"}} | 允许智能体分多次向用户发送消息(突破单次回复限制) | json\n{\n "function": "send_message",\n "arguments": {\n "message": "First part of response."\n }\n}\n | 所有智能体默认启用;返回后用户立即可见。 |
| core_memory_replace | {"function": "core_memory_replace", "arguments": {"field": "persona/human", "content": "..."}} | 替换 Core Memory 中的 persona 或 human 字段 | json\n{\n "function": "core_memory_replace",\n "arguments": {\n "field": "human",\n "content": "User is a data scientist."\n }\n}\n | field 必须为 “persona” 或 “human”;覆盖原内容。 |
| core_memory_append | {"function": "core_memory_append", "arguments": {"field": "persona/human", "content": "..."}} | 在 Core Memory 字段末尾追加文本 | json\n{\n "function": "core_memory_append",\n "arguments": {\n "field": "persona",\n "content": " I specialize in Python."\n }\n}\n | 避免重复追加导致内存膨胀。 |
| archival_memory_insert | {"function": "archival_memory_insert", "arguments": {"content": "..."}} | 将文本存入 Archival Memory(长期知识库) | json\n{\n "function": "archival_memory_insert",\n "arguments": {\n "content": "User prefers email notifications."\n }\n}\n | 内容将被嵌入并向量化存储。 |
| archival_memory_search | {"function": "archival_memory_search", "arguments": {"query": "...", "page": 0, "page_size": 5}} | 从 Archival Memory 中语义检索相关条目 | json\n{\n "function": "archival_memory_search",\n "arguments": {\n "query": "contact preference",\n "page_size": 3\n }\n}\n | 返回结果按相似度排序;支持分页。 |
| pause_heartbeat | {"function": "pause_heartbeat", "arguments": {"minutes": 5}} | 暂停智能体的心跳机制(用于长时间任务) | json\n{\n "function": "pause_heartbeat",\n "arguments": {\n "minutes": 10\n }\n}\n | 实验性功能;部分部署模式下可能无效。 |
5.2 自定义工具开发
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 定义函数逻辑 | 编写标准 Python 函数,接收参数并返回字符串结果 | 函数必须返回 str 类型;不可返回 dict 或 None。 |
| 添加 Letta 装饰器 | 使用 @letta_tool(name=..., description=..., parameters=...) 注册工具 | parameters 必须是符合 OpenAI Function Calling 规范的 JSON Schema。 |
| 参数类型约束 | 支持 string、integer、number、boolean 等基本类型;不支持复杂嵌套对象 | 若需传对象,应序列化为 JSON 字符串并在函数内解析。 |
| 错误处理 | 在函数内部捕获异常并返回错误信息字符串 | 不要抛出未处理异常,否则会中断智能体会话。 |
| 测试工具 | 在独立脚本中调用函数验证逻辑,再集成到 Letta | 可先用 print(get_weather("Beijing")) 测试,再注册。 |
自定义工具完整示例:
| 工具名称 | 语法(装饰器定义) | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| get_current_time | @letta_tool(name="get_current_time", description="Get current UTC time", parameters={"type": "object", "properties": {}}) | 获取当前时间 | python\nfrom letta import letta_tool\nfrom datetime import datetime\n\n@letta_tool(\n name="get_current_time",\n description="Get current UTC time",\n parameters={"type": "object", "properties": {}}\n)\ndef get_current_time() -> str:\n return datetime.utcnow().isoformat() + "Z"\n | 无参数工具需设 properties 为空 dict;返回 ISO 8601 格式便于解析。 |
| query_database | @letta_tool(name="query_database", description="Run SQL query", parameters={"type": "object", "properties": {"sql": {"type": "string"}}}) | 执行安全受限的数据库查询 | python\nimport sqlite3\n\n@letta_tool(\n name="query_database",\n description="Run read-only SQL query on user.db",\n parameters={"type": "object", "properties": {"sql": {"type": "string"}}}\n)\ndef query_database(sql: str) -> str:\n if not sql.strip().lower().startswith("select"):\n return "Error: Only SELECT queries allowed."\n try:\n conn = sqlite3.connect("user.db")\n cur = conn.cursor()\n cur.execute(sql)\n rows = cur.fetchall()\n return str(rows)\n except Exception as e:\n return f"Query failed: {str(e)}"\n | 必须做输入校验和权限控制;避免 SQL 注入。 |
5.3 工具注册与调用流程
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 工具注册(CLI) | 将工具函数放在 ~/.letta/tools/ 目录下的 .py 文件中,Letta 启动时自动加载 | 文件名不能以 _ 开头;需包含至少一个 @letta_tool 装饰的函数。 |
| 工具注册(SDK) | 创建智能体时通过 tools=[...] 参数显式指定工具名列表 | python\nagent = create_agent(name="my_agent", tools=["get_current_time", "query_database"])\n |
| LLM 生成工具调用 | LLM 输出符合 function_call 格式的 JSON,如 {"name": "tool_name", "arguments": {...}} | 依赖 LLM 的 function calling 能力;本地模型需支持或通过 shim 模拟。 |
| 框架执行工具 | Letta 解析 function_call → 查找注册工具 → 执行函数 → 将返回值作为 function_return 加入消息流 | 工具执行在主线程同步进行;耗时操作会阻塞对话。 |
| 结果反馈给 LLM | function_return 消息自动拼接到下一轮提示上下文中,供 LLM 生成最终回复 | 智能体可基于工具结果继续推理或调用其他工具。 |
5.4 异步工具与外部 API 调用
| 方法/策略名称 | 语法 / 实现方式 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 同步封装异步 API | 在工具函数内使用 requests 或 httpx 调用外部服务 | 集成 RESTful API(如天气、支付) | python\nimport requests\n\n@letta_tool(\n name="get_weather",\n description="Get weather by city",\n parameters={"type": "object", "properties": {"city": {"type": "string"}}}\n)\ndef get_weather(city: str) -> str:\n try:\n resp = requests.get(f"https://api.weather.com/v1/{city}", timeout=10)\n return resp.json().get("summary", "Unknown")\n except Exception as e:\n return f"Weather API error: {str(e)}"\n | 设置超时防止卡死;处理网络异常。 |
| 模拟异步(心跳机制) | 工具返回”任务已提交”,后续通过外部系统更新 Archival Memory | 处理长时间运行任务(如训练模型) | python\n@letta_tool(name="start_training", ...)\ndef start_training(config: str) -> str:\n task_id = submit_to_queue(config)\n return f"Training started with ID: {task_id}. Check status later."\n | 需配合外部任务队列和状态轮询机制。 |
| 使用线程(谨慎) | 在工具函数中启动 threading.Thread 执行后台任务 | 非阻塞地触发副作用(如发邮件) | python\nimport threading\n\ndef _send_email_async(to, body):\n # 实际发送逻辑\n pass\n\n@letta_tool(...)\ndef send_email(to: str, body: str) -> str:\n threading.Thread(target=_send_email_async, args=(to, body)).start()\n return "Email sent in background."\n | 仅适用于 fire-and-forget 场景;无法将结果反馈给 LLM。 |
| 异步 SDK(未来) | Letta 计划支持 async/await 工具(尚未正式发布) | 原生支持异步 I/O | 暂无官方示例 | 关注 GitHub 仓库更新;当前版本均为同步执行。 |
第六章:多智能体协作(Multi-Agent Systems)
6.1 多智能体架构概述
| 概念名称 | 说明 | 注意事项 |
|---|---|---|
| 单体智能体模式(当前默认) | 每个 Letta 智能体独立运行,拥有私有内存和工具集,彼此无直接通信能力 | 这是 Letta 当前稳定支持的唯一模式;多智能体需通过外部协调实现。 |
| 中央协调器模式(推荐方案) | 引入一个”协调智能体”(Orchestrator Agent),负责接收用户请求、分解任务、调度其他专业智能体 | 协调器本身也是 Letta 智能体,通过工具调用间接与其他智能体交互。 |
| 消息总线架构(未来方向) | 智能体通过共享消息队列(如 Redis Pub/Sub)发布/订阅消息,实现松耦合通信 | Letta 尚未内置该机制,需自行开发中间件。 |
| 内存隔离性 | 每个智能体的 Core / Recall / Archival Memory 完全独立,无法直接读取其他智能体状态 | 若需共享信息,必须通过工具将数据写入公共存储(如数据库或文件)。 |
| 工具桥接通信 | 利用自定义工具作为”代理”,让智能体 A 调用工具 → 工具向智能体 B 发送消息(通过 SDK) | 是目前最可行的多智能体交互方式,但需手动实现消息路由逻辑。 |
6.2 智能体间通信机制
| 通信方式 | 操作细节 | 注意事项 |
|---|---|---|
| 通过公共 Archival Memory 共享知识 | 智能体 A 调用 archival_memory_insert 写入信息,智能体 B 调用 archival_memory_search 读取 | 需约定命名空间或标签(如 [Team:Research] Findings...)避免冲突。 |
| 协调器调用子智能体(SDK 桥接) | 在协调器的自定义工具中,使用 create_agent / user_message 主动触发子智能体执行 | python\n# 在协调器的工具函数中\nfrom letta import create_agent, send_message_to_agent\n\nsub_agent = create_agent(name="analyzer", tools=["analyze_text"])\nresult = sub_agent.user_message("Analyze this: ...")\nreturn result.messages[-1].text\n |
| 文件或数据库中转 | 智能体将输出写入共享文件或数据库表,其他智能体定期轮询或通过工具读取 | 适用于批处理场景;实时性差,需配合定时心跳。 |
| 模拟消息传递(CLI + 脚本) | 使用 shell 脚本串联多个 letta run --message 命令,将前一个输出作为后一个输入 | bash\noutput1=$(letta run --agent agent1 --message "Summarize X")\nletta run --agent agent2 --message "Critique: $output1"\n |
| 事件驱动回调(高级) | 开发 Webhook 工具,当智能体完成任务时 POST 到指定 URL,触发另一智能体启动 | 需部署 HTTP 服务;适合云原生环境。 |
6.3 角色分工与任务协调
角色类型:
| 角色类型 | 职责说明 | 实现建议 |
|---|---|---|
| 用户接口智能体(UI Agent) | 接收用户自然语言输入,理解意图,分发任务 | 配置通用 persona,启用任务解析工具(如 parse_task_type) |
| 专家智能体(Expert Agent) | 专注特定领域(如数据分析、代码生成、法律咨询) | 使用领域专属 persona 和工具集;限制其直接接触用户 |
| 记忆协调智能体(Memory Agent) | 管理团队共享知识库,统一写入 Archival Memory | 所有成员通过调用其工具提交知识,避免分散存储 |
| 决策智能体(Decision Agent) | 基于多个专家输出进行综合判断或投票 | 输入为结构化报告,输出为最终建议;可集成规则引擎 |
| 监控智能体(Monitor Agent) | 跟踪任务进度、检测异常、触发重试或告警 | 定期查询任务状态表;使用 pause_heartbeat 控制轮询间隔 |
协调策略:
| 协调策略 | 说明 | 注意事项 |
|---|---|---|
| 顺序流水线 | 任务按固定顺序由 A → B → C 执行 | 简单可靠;但任一环节失败导致整体中断 |
| 并行分发 | 协调器同时派发子任务给多个专家,等待全部返回后汇总 | 需在工具中实现并行(如 threading 或 asyncio);注意超时控制 |
| 动态路由 | 根据中间结果决定下一步由谁处理(如”若代码有错误,转交调试专家”) | 协调器需具备条件判断能力;依赖高质量中间输出 |
| 反馈循环 | 专家输出被送回协调器,协调器可要求澄清或细化 | 通过多次 user_message 模拟对话;需防止无限循环 |
6.4 实战:构建协作型智能体团队
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 步骤 1:定义团队角色 | 确定需要哪些智能体(如 Researcher、Writer、Editor)及其职责 | 建议不超过 3–4 个角色,避免复杂度失控 |
| 步骤 2:创建专用 Persona/Human 文件 | 为每个角色编写 ~/.letta/personas/researcher.txt 等 | 内容应体现专业性和行为边界(如 “I only provide facts.”) |
| 步骤 3:开发协调器工具 | 编写工具如 delegate_to_researcher(query),内部调用子智能体 SDK | 工具需处理异常并返回结构化结果 |
| 步骤 4:注册工具并创建协调器 | python\nagent = create_agent(\n name="orchestrator",\n tools=["delegate_to_researcher", "delegate_to_writer"]\n)\n | 确保所有子智能体工具已正确加载 |
| 步骤 5:测试端到端流程 | 用户输入:“Write a report on AI trends in 2025.” → 协调器分发 → 汇总输出 | 使用 letta run --agent orchestrator 交互测试 |
| 步骤 6:持久化共享知识 | 要求所有子智能体将关键结论写入 Archival Memory,带统一前缀 | 便于后续审计或复用 |
最小可运行示例(协调器工具片段):
| 组件 | 代码示例 |
|---|---|
| 协调器工具:delegate_to_researcher | python\nfrom letta import create_agent\n\n@letta_tool(\n name="delegate_to_researcher",\n description="Delegate a research query to the researcher agent",\n parameters={"type": "object", "properties": {"query": {"type": "string"}}}\n)\ndef delegate_to_researcher(query: str) -> str:\n try:\n researcher = create_agent(\n name="temp_researcher",\n persona=open("~/.letta/personas/researcher.txt").read(),\n tools=[]\n )\n response = researcher.user_message(f"Research: {query}")\n result = response.messages[-1].text\n # 可选:存入共享记忆\n # archival_memory_insert(f"[Research Result] {result}")\n return result\n except Exception as e:\n return f"Research failed: {str(e)}"\n |
注意:此示例每次创建临时智能体,生产环境应复用长期存在的智能体实例以节省资源。
第七章:部署与生产化
7.1 本地部署
| 步骤名称 | 操作细节 | 注意事项 |
|---|---|---|
| 安装依赖环境 | 安装 Python ≥3.9、pip、virtualenv;若使用 Ollama,需单独安装 Ollama 并运行 ollama serve | 推荐使用 python -m venv letta-env && source letta-env/bin/activate 隔离环境 |
| 安装 Letta | 执行 pip install letta 或从源码安装 pip install git+https://github.com/letta-ai/letta.git | 若需本地模型支持,追加 pip install "letta[local]" |
| 初始化配置 | 运行 letta configure,选择 LLM provider(如 openai / ollama)、嵌入模型、默认内存后端 | 配置文件保存于 ~/.letta/config,可手动编辑 |
| 启动智能体服务 | 使用 CLI 交互:letta run --agent my_agent;或通过 Python 脚本长期运行 | CLI 适合调试;长期运行建议用 systemd 或 nohup |
| 数据目录结构 | 默认数据存储在 ~/.letta/,包含:config(全局配置)、sqlite.db(消息与状态)、archival_index/(FAISS 向量索引)、personas/、humans/、tools/(自定义组件) | 备份整个 ~/.letta/ 即可迁移状态;避免多进程同时写入 SQLite |
| 权限与安全 | 确保 ~/.letta/ 目录仅对运行用户可读写;API 密钥不应硬编码在脚本中 | 建议使用环境变量或密钥管理工具(如 direnv) |
7.2 云端部署(Docker / Kubernetes)
| 部署方式 | 操作细节 | 注意事项 |
|---|---|---|
| Docker 镜像构建 | 创建 Dockerfile:FROM python:3.10-slim WORKDIR /app COPY requirements.txt . RUN pip install letta COPY . . CMD ["python", "agent_server.py"],其中 agent_server.py 封装 SDK 调用 | 官方暂未提供官方镜像;需自行构建;建议使用多阶段构建减小体积 |
| 挂载数据卷 | 启动容器时挂载 ~/.letta 目录:docker run -v ~/.letta:/root/.letta letta-app | 确保容器内用户有写权限;避免向量索引丢失 |
| 环境变量注入 | 通过 -e OPENAI_API_KEY=... 或 .env 文件传入密钥 | 不要将密钥写入镜像层;使用 Docker secrets(Swarm)或 K8s Secret |
| Kubernetes 部署 | 编写 Deployment + Service YAML:使用 PersistentVolume 挂载 .letta、通过 Secret 注入 API 密钥、设置资源限制(CPU/Memory) | 单实例部署即可;Letta 当前不支持水平扩展(因 SQLite 为单机数据库) |
| 暴露 HTTP 接口(可选) | 开发轻量 Flask/FastAPI 服务,封装 agent.user_message() 为 REST API | 示例端点:POST /chat {"agent": "x", "message": "..."} → 返回响应文本 |
| 健康检查 | 在容器中添加 /health 端点,检查 SQLite 连通性与 LLM 响应 | Kubernetes livenessProbe 可基于此实现自动重启 |
7.3 监控与日志管理
| 监控/日志项 | 实现方式 | 注意事项 |
|---|---|---|
| 标准输出日志 | Letta CLI 和 SDK 默认输出 INFO 级日志到 stdout | 可通过 logging.basicConfig(level=logging.DEBUG) 提高日志级别 |
| 结构化日志记录 | 在自定义工具中主动记录关键事件:import logging; logging.info("Tool X called with args: %s", args) | 建议使用 JSON 格式日志,便于 ELK/Splunk 解析 |
| 消息审计 | 定期导出 messages 表(SQLite)用于合规审查 | bash\nsqlite3 ~/.letta/sqlite.db "SELECT * FROM messages;" > audit.log\n |
| LLM 调用追踪 | 记录每次 LLM 请求的 prompt、response、token 消耗、延迟 | 可通过包装 LLM 客户端实现;OpenAI 支持 usage 字段解析 |
| 异常告警 | 捕获工具执行异常并发送通知(如邮件、Slack) | python\ntry:\n result = risky_tool(...)\nexcept Exception as e:\n send_alert(f"Tool failed: {e}")\n raise\n |
| Prometheus 指标(高级) | 自定义指标:letta_agent_messages_total、llm_token_usage、tool_call_duration_seconds | 需集成 prometheus_client 并暴露 /metrics 端点 |
7.4 性能优化与成本控制
| 优化策略 | 操作细节 | 注意事项 |
|---|---|---|
| 减少 Core Memory 大小 | 精简 persona/human 文本,移除冗余描述 | 每减少 100 tokens,可显著降低每次调用成本(尤其 GPT-4) |
| 控制 Recall Memory 长度 | 在提示构建时限制历史消息数量(Letta 自动截断,但可调整策略) | 通过修改 agent.DEFAULT_MAX_TOKENS 或上下文窗口设置间接控制 |
| 批量插入 Archival Memory | 使用 agent.archival_memory.insert(list) 而非逐条调用工具 | 减少嵌入模型调用次数,提升初始化效率 |
| 本地嵌入模型 | 使用 BAAI/bge-small-en 等小型开源模型替代 OpenAI Embeddings | 需在 letta configure 中指定 HuggingFace 模型;节省 $0.0001/千 tokens |
| 缓存 LLM 响应(谨慎) | 对确定性查询(如”当前时间”)缓存结果,避免重复调用 | 仅适用于无状态、幂等操作;需设置 TTL 防止过期 |
| 选择低成本 LLM | 优先使用 GPT-3.5-Turbo 而非 GPT-4;或本地 Llama3-8B | 本地模型无 token 费用,但需 GPU 资源;综合 TCO 评估 |
| 限制工具调用深度 | 设置最大 function calling 循环次数(默认 10)防止失控 | 可通过 agent.MAX_FUNCTION_CALLS = 5 降低风险 |
| 监控 Token 消耗 | 在每次 LLM 调用后记录 input/output tokens,汇总分析 | OpenAI 返回 usage.total_tokens;本地模型需估算(如 tiktoken) |
第八章:高级主题与扩展
8.1 自定义内存后端(如向量数据库)
| 组件/操作名称 | 说明 / 语法 | 用途 | 代码示例 | 注意事项 |
|---|---|---|---|---|
| 替换 Archival Memory 后端 | 实现 StorageConnector 接口,重写 insert、query、delete 方法 | 将默认 FAISS 替换为 Pinecone、Weaviate、Qdrant 等 | python\nfrom letta.connectors import StorageConnector\n\nclass PineconeArchivalMemory(StorageConnector):\n def __init__(self, index_name):\n self.index = pinecone.Index(index_name)\n\n def insert(self, text: str, embedding: list):\n self.index.upsert([(str(uuid4()), embedding, {"text": text})])\n\n def query(self, query_embedding: list, top_k=5):\n results = self.index.query(vector=query_embedding, top_k=top_k, include_metadata=True)\n return [match["metadata"]["text"] for match in results["matches"]]\n | 需在智能体创建时传入自定义连接器实例;官方暂未提供开箱即用的云向量库插件 |
| 注册自定义连接器 | 在创建智能体时通过 archival_memory_storage_connector 参数注入 | 使智能体使用新后端存储长期记忆 | python\nagent = create_agent(\n name="cloud_mem_agent",\n archival_memory_storage_connector=PineconeArchivalMemory("my-index")\n)\n | 所有 archival_memory_insert/search 工具调用将路由至该连接器 |
| 嵌入模型对接 | 确保嵌入维度与向量数据库索引一致(如 OpenAI 为 1536,BGE-small 为 384) | 避免维度不匹配导致插入/查询失败 | python\n# 若使用 BGE\nembedding_model = "BAAI/bge-small-en-v1.5"\ndim = 384\n# Pinecone 索引需创建为 dim=384\n | 更换嵌入模型需重建向量索引 |
| 数据迁移工具 | 编写脚本从 FAISS 导出数据并导入新后端 | 平滑迁移现有知识库 | python\n# 伪代码\nfaiss_index = load_faiss("~/.letta/archival_index")\nfor text, emb in faiss_index.items():\n pinecone_conn.insert(text, emb)\n | 注意元数据(如时间戳、来源)需一并迁移 |
8.2 支持本地大模型(LLaMA, Mistral 等)
| 集成方式 | 操作细节 | 注意事项 |
|---|---|---|
| 通过 Ollama 集成 | 1. 安装 Ollama 2. 拉取模型: ollama pull llama3:8b3. letta configure 选择 provider 为 ollama,模型名为 llama3:8b | Ollama 自动处理 tokenization 和 function calling shim;支持大部分开源模型 |
| 通过 LM Studio 集成 | 1. 启动 LM Studio 并加载模型 2. 开启 “Local Server”(默认 http://localhost:1234/v1)3. letta configure 选择 provider 为 openai,API base 设为 http://localhost:1234/v1 | 必须启用 “Function Calling” 选项;部分模型需手动开启 |
| 通过 vLLM 集成 | 1. 部署 vLLM 服务:python -m vllm.entrypoints.openai.api_server --model mistralai/Mistral-7B-Instruct-v0.22. 配置 Letta 使用该 endpoint | vLLM 性能高,适合批量推理;需 GPU 资源 |
| Function Calling 兼容性 | 本地模型需支持 OpenAI-style function calling,否则工具调用失效 | Llama3、Mistral Instruct 等新版模型已原生支持;旧模型需提示词工程模拟 |
| 性能调优参数 | 在 letta configure 中设置:Context window(如 8192)、Max tokens per response、Temperature | 错误的上下文长度会导致截断或崩溃;建议参考模型卡(Model Card) |
| 离线运行保障 | 所有组件(LLM、嵌入模型、向量库)均部署在内网 | 完全断网可用;适合金融、政务等高隐私场景 |
8.3 插件系统与生态扩展
| 扩展类型 | 说明 | 注意事项 |
|---|---|---|
| 工具插件(Tools) | 将自定义工具函数放入 ~/.letta/tools/ 目录,Letta 启动时自动加载 | 文件命名如 my_tools.py;每个文件可含多个 @letta_tool 函数 |
| Persona/Human 插件 | 在 ~/.letta/personas/ 和 ~/.letta/humans/ 添加 .txt 文件 | 文件名即为选项名(如 financial_advisor.txt → 创建时可选) |
| 内存后端插件 | 通过实现 StorageConnector 扩展 | 需修改应用代码,非纯配置驱动 |
| 社区插件仓库 | 第三方开发者可发布插件包(如 letta-plugin-slack) | 目前无官方插件市场;需手动安装:pip install letta-plugin-x |
| SDK 扩展点 | 通过继承 Agent 类或替换 LLMClient 实现深度定制 | 适用于企业级二次开发;需熟悉 Letta 源码结构 |
| Web UI 插件(实验性) | 社区项目如 letta-web 提供图形界面 | 非官方维护;功能可能滞后于 CLI |
8.4 安全性与隐私保护
| 安全措施 | 实施方式 | 注意事项 |
|---|---|---|
| API 密钥保护 | 使用环境变量或密钥管理服务(如 HashiCorp Vault),禁止硬编码 | export OPENAI_API_KEY="sk-..." letta run ... |
| 用户数据隔离 | 为不同用户创建独立智能体,确保内存不交叉 | 智能体名称应包含用户 ID(如 agent_user123) |
| 敏感信息过滤 | 在工具函数中对输入/输出进行脱敏(如移除身份证、手机号) | python\nimport re\ndef sanitize(text):\n return re.sub(r"\d{18}", "[REDACTED]", text)\n |
| 本地化部署 | 所有数据(消息、记忆、模型)保留在私有网络 | 满足 GDPR、HIPAA 等合规要求 |
| 工具权限控制 | 限制工具访问范围(如数据库只读、文件系统沙箱) | 示例:SQL 工具仅允许 SELECT,禁止 DROP |
| 审计日志留存 | 记录所有智能体交互、工具调用、内存修改操作 | 日志应包含时间、用户、智能体、操作类型、原始内容 |
| 模型输出审查 | 对 LLM 生成内容进行安全扫描(如暴力、偏见检测) | 可集成 Microsoft Presidio 或自定义规则引擎 |
| 网络访问限制 | 在容器或主机防火墙中限制 Letta 仅访问必要外部服务 | 防止恶意工具发起 SSRF 攻击 |