griptape — 本课题摘录
读了哪几篇: 05-memory-and-artifacts(记忆与制品)、02-prompt-task-agent-loop(智能体循环)。
其余四篇(结构与任务图、驱动层、工具机制、引擎与配置)本轮没读。
这一家在本课题里的位置:它是"工具结果太大怎么回填"这一问唯一给了完整答案的一家。
它对本课题回答了什么
决定三:结果太大怎么回填 —— 别让大象钻进提示词
它先把问题说清楚。 一个工具读了 50MB 的网页、或查出一张含敏感字段的表,直 接塞回提示词的后果:
| 后果 | 说的是什么 |
|---|---|
| token 爆掉或烧钱 | 一次就把窗口填满 |
| 敏感内容白白发出去 | 原文进了发往模型厂商的请求 |
| 模型注意力被噪声淹没 | 有用的那两行淹在五万行里 |
(依据:前沿库 · Griptape · 记忆与制品:对话记忆、off-prompt 任务记忆、Artifact 类型系统 —— 把大块工具输出直接塞回提示词的三个后果是 token 爆掉/烧钱、敏感内容进了发往模型厂商的请求、模型注意力被无关噪声淹没)
它的解法:把大象留在框架里,只递给模型一张取件号。
工具产出一大坨结果
│
├──► 存进框架侧的任务记忆,拿到一个「存在哪」的坐标
│
└──► 提示词里只出现一句:「它存到 <某处> 了」
│
后续别的工具想用 ──► 报上坐标去把它取回来
│
模型全程没见过原文
(依据:前沿库 · Griptape · 记忆与制品:对话记忆、off-prompt 任务记忆、Artifact 类型系统 —— off-prompt 把工具大块输出存进 Task Memory,提示词里只出现「它存到 memory_name/artifact_namespace 了」,后续工具凭名字取回,模型全程没见过原文)
这条是本课题"决定三"里最重要的一个发现。 cline / semantic-kernel / haystack 都默认"工具结果整个回填",只有它明确回答了"结果太大怎么办"。 chrome-devtools-mcp 的"超标自动落盘"是同一思路的另一实现。
决定三补充:按数据类型分派到不同存储
任务记忆的核心是一张**"数据类型 → 存哪"的分派表**:
| 类型 | 存到哪 |
|---|---|
| 文本 | 向量库(于是能被检索) |
| 二进制 | 内存字典 |
(依据:前沿库 · Griptape · 记忆与制品:对话记忆、off-prompt 任务记忆、Artifact 类型系统 —— TaskMemory 的核心是「Artifact 类型 → storage」的分派表,文本进向量库、二进制进内存字典,并用 namespace_storage 记住每个名字用了哪个存储)
文本进向量库这一步很关键: 它让"取件"不必是精确取回全文,而可以是"按问题检索这坨结果里相关的几段"。大结果因此变成了一个可查询的小 RAG。
决定三再补充:所有数据都装在带类型的信封里
部件之间传的从来不是裸的字符串或字节,而是一个信封:裹着真数据、名字、附加信息,并保证有一个"变成给模型看的文字"的方法。 (依据:前沿库 · Griptape · 记忆与制品:对话记忆、off-prompt 任务记忆、Artifact 类型系统 —— 部件间传的是 Artifact 信封而非裸 str/bytes,它裹着 value/name/meta 并保证有 to_text() 能变成给 LLM 看的文本)
为什么要有信封,它讲得很清楚:整条流水线要能统一处理任意数据。
- 记忆要能判断"这是文本还是二进制,该存哪";
- 任务要能把上游产物变成文字拼进提示词;
- 工具要能把结果打包回传。
有了统一契约,这些部件就不用关心里面到底是什么。
这条对我们有直接用处。 我们的最小循环里,"工具返回什么"如果一开始就定成裸字符串,后面想加"返回一张图""返回一个文件"就得改所有地方。 一开始就用信封,成本几乎为零。
决定一:三种记忆分工
| 记忆 | 记什么 | 类比 |
|---|---|---|
| 对话记忆 | 每一轮的"你问 / 它答" | 聊天记录本 |
| 任务记忆 | 工具吐出的大块或敏感结果 | 后台文件柜(只给别人递取件号) |
| 元记忆 | 跨任务共享的零碎元数据 | 便利贴 |
(依据:前沿库 · Griptape · 记忆与制品:对话记忆、off-prompt 任务记忆、Artifact 类型系统 —— 三种记忆分别是 ConversationMemory(每轮问答)、TaskMemory(大块/敏感工具输出)、MetaMemory(跨任务元数据),职责完全不同)
对话记忆有一个"超过多少轮就用模型压成摘要"的变体。
元记忆存的东西值得注意: 它记的是一次 ReAct 子任务的思考、动作、经记忆处理后的回答。于是下游不仅能凭取件号取回原物,还能读到"当初是哪一步、基于什么思考产生的它"。 (依据:前沿库 · Griptape · 记忆与制品:对话记忆、off-prompt 任务记忆、Artifact 类型系统 —— MetaMemory 主要存 ActionSubtaskMetaEntry,记一次 ReAct 子任务的 thought/actions/answer,于是下游能读到「当初是哪一步、基于什么思考产 生的它」)
决定二/四:循环本身
它的循环是经典 ReAct:靠一个提示词栈组装上下文、靠一个"动作子任务"解析并执行工具动作、再把结果回灌,直到出现"最终答案"。 (依据:前沿库 · Griptape · PromptTask 智能体循环:提示词组装与 ReAct 子任务 —— PromptTask 靠 prompt_stack 组装上下文、靠 ActionsSubtask 解析并执行工具动作、再把结果回灌 LLM,如此循环直到出现 Answer)
它没回答什么
- 循环怎么停得优雅——它靠"出现最终答案",没有轮数熔断、连错熔断这类护栏的细节。
- 不用原生工具调用怎么办——它走的是自己的动作格式,但这两篇没讲解析细节。
- 状态怎么存、崩了怎么续——没有这一层。
坑与代价
- "只回引用"的代价是模型看不见内容,就没法基于内容推理。 如果模型需要"看一眼结果再决定下一步",取件号帮不了它——它得先调一个"从记忆里取回来"的工具,这就多了 一轮往返。
判断(无锚): 这条应该做成按大小自动切换:结果小于某个阈值直接回填,超过才转存并回引用。 如果错,会错在: 如果结果里含敏感字段,那跟大小无关——再小也不该进提示词。所以阈值之外还得有一条"这个工具的输出一律不进提示词"的标记。
- 二进制存在内存字典里。 这是个明显的最小实现,进程一停就没了。
- 它把 RAG 拉进了循环。 大结果进向量库意味着最小原型也得有嵌入模型和向量库——对我们第一版是过重的。