上下文管理器
@animalabs/context-manager 保存 LLM 代理的对话历史,并将其汇编到每个模式调用的信息中,在一个符号预算范围内. 每个消息都存储在 纪事 存储,并且由策略决定每个编译的发送。 自传策略将更古老的历史折叠成由你命名的模型所写的代理自言自语中的摘要,所以一个长期代理自传的消息在存储时会停留在商店里,而每个代理自编自编预算.
属于康乃馨生态系统的一部分 编年史, (中文(简体) ), 膜, (中文(简体) ), 代理框架 财务报告和审定财务报表 连接主机。代理框架打开一个 ContextManager 在其共享的 Chronicle 仓库中, 在命名空间下为每个代理 agents/<name>。它汇编管理器的每个请求和电话 tick() 要运行压缩。 编译的信息是膜的 NormalizedMessages,战略通过膜来撰写摘要.
安装
npm install @animalabs/context-manager
它需要22.12号或以后作为它的 package.json 宣布,并取决于 @animalabs/chronicle 财务报告和审定财务报表 @animalabs/membrane为了压缩自传策略,你将构建一个 Membrane 自己来 安装 @animalabs/membrane 并肩作战.
快开始
import { ContextManager, PassthroughStrategy } from '@animalabs/context-manager';
// Opens the Chronicle store at this path, creating it if it doesn't exist.
const manager = await ContextManager.open({
path: './agent-store',
strategy: new PassthroughStrategy(),
});
manager.addMessage('User', [{ type: 'text', text: 'Hello!' }]);
manager.addMessage('Claude', [{ type: 'text', text: 'Hi. What are we working on?' }]);
const { messages, systemInjections } = await manager.compile({
maxTokens: 100_000, // the whole window, the response included
reserveForResponse: 4_000,
});
// `messages` go into a membrane request. Injections you pass to compile() as
// its second argument with position 'system' come back in `systemInjections`,
// as content blocks for your system prompt.
manager.close();
要使用您的应用程序已持有的存储器, 请通过 store (a) 纪事 JsStore改为 path。然后你的应用程序关闭它。 几位经理可以共用一店. namespace 提供各自背景记录和战略状况,包括摘要,以及 isolate: true 带有 namespace 给它自己的信息.
战略
| 战略 | 编译寄出什么 |
|---|---|
PassthroughStrategy (默认) | 代理窗口中的每条消息:存储的每条消息,直到一个主机呈现行(下). 当它们不都合身时, 最新的那些做. |
WindowedPassthroughStrategy | 从主播开始的每条信息,都不压缩. 主播走在粗糙的跳跃中 当窗口冲出预算,或任何地方 setAnchor 说吧 在移动之间,窗口只在其端部生长,这保持了编译前缀的稳定,供提供者的快速缓存使用,除此之外,它画出超过其活像限制的图像,从窗口取出行(retractRows,一个去除),该去除从行上更改前缀,并编辑了信件(editMessage),它改变其位置的字节。 一旦一个主机呈现出行(从下到下),主机就是一个代理机窗口中的位置,而不是一个序列,所以它之后呈现出一行,无论记录在哪个位置,都是在窗口中. |
AutobiographicalStrategy | 最近的信息,以及作为代理商模型写作摘要的更古老的历史,随着累积而合并到更高层次. |
KnowledgeStrategy | 一个 AutobiographicalStrategy 用于知识采集工作。 它在相位过渡时进行分解,用自己的提示压缩每个相位,并保持各级未解决的线索. |
自传战略
import { Membrane, AnthropicAdapter } from '@animalabs/membrane';
import { ContextManager, AutobiographicalStrategy } from '@animalabs/context-manager';
const manager = await ContextManager.open({
path: './agent-store',
// The strategy writes summaries through this membrane. The adapter reads
// ANTHROPIC_API_KEY unless you pass { apiKey }.
membrane: new Membrane(new AnthropicAdapter()),
strategy: new AutobiographicalStrategy({
// Required: the model whose voice the summaries are in.
compressionModel: 'claude-sonnet-4-5',
}),
});
manager.addMessage('User', [{ type: 'text', text: 'Hello!' }]);
// ...more messages as the conversation goes...
await manager.tick(); // compresses the next waiting chunk or merge, if any
const { messages } = await manager.compile({ maxTokens: 200_000, reserveForResponse: 8_000 });
manager.close();
如何工作,每个选项的默认在括号中:
- 最新的
recentWindowTokens(30,000) 保持生动。 旧消息被切成几块targetChunkTokens(3 000个),信息边界。 给一个预算,其中包含原始窗口和摘要的空间。 无法匹配的编译被拒绝OverBudgetError。 。 。 . - 每个
tick()最多做一个压缩工作:它会压缩下一个等待块,或者运行下一个等待块合并。 在适应性解析后,等待合并将首先释放更多的上下文,而不是下一个块的总结,因为块将被发送;其最后尝试失败的合并将让一个块先进行,然后再次竞争,等待被搁置的合并将保留它的位置. 所以经常打电话,比如说每次转弯之后。 对于一个块,策略问compressionModel通过膜,它从那部分谈话中回想。 答案是一级摘要,在编译的上下文中取而代之。 设定autoTickOnNewMessage: true(假) 每行进入或离开代理窗口时, 在背景中开始一个勾选, 而不是调用tick()自己:在窗口为记录的每条新消息中,一旦有主机出现,则每条信息presentRows和每一次接通的电话retractRows,一个删除,retractRemoved, (中文(简体) ),retractAbsentRows; 见 一个记录,每个代理商一个窗口) (中文(简体) ). compressionModel没有默认。 没有它,策略就拒绝写摘要,因为代理声音中的替代模型会腐蚀唱片. 没有膜,tick()只记录一个警告.- 作为简短的交换,摘要说明其信息在何处:a
Context Manager以标题转出, 如[Recall L1-3],并随摘要从summaryParticipant(单位:千美元)Claude) (中文(简体) ). 以适应性分辨率(下)Context Manager转弯summaryContextLabel("你以前记得什么?")取而代之。 任何一种都可以命名摘要所代表的回合中要求使用的工具{tools}(见summaryContextLabel) (中文(简体) ). - 摘要合并到一个级别上一次
mergeThreshold(6) 其中,在某一级别的最新一端,它们坐在一起,如果只留下一个摘要,则减少一个(整个运行,减少一个是一组,起点为2)。 更古老的跑步无法生长,被一个洞所切断,比如总结者拒绝的块,一旦它持有了两个,就合并在一起,甚至连一个组都不放过它。 与hierarchical假的,他们只停留在一等. headWindowTokens(0) 使对话的开始也保持生动,以便指示保持逐字记录.- 与
adaptiveResolution: true(false),每个编译选择如何深入折叠历史的每个部分以适应预算.foldingStrategy命名解析器 :flat-profile(默认),oldest-first, (中文(简体) ),kv-stable或者说kv-unified。 。 。 .kv-unified需要明确kvUnified政策.
有了支持他们的策略,就像这个策略一样,经理还提出:
pinRange财务报告和审定财务报表markDocument将信息保存在对话中的位置,默认为原始信息。 摆出一针level或者说maxLevel将信息放在这一级别上,或者说没有比它更深的层次,只有adaptiveResolution编辑kv-stable或者说kv-unified解会者. 只有在压缩和合并后才会达到一个关卡,kv-unified上面有一个最深层的信息, 上面有一个摘要,当没有信息时提供原始信息, 并且记录它的信息, 除非对信息的另一个限制, 如另一个层次的锁, 系统改变的讯息 不论针头是什么 都不要动 在其他解子下,而没有适应性解析度,被取出针能保持活性. 在适应性分辨率下,存储在部分的长信息的任何部分上的一个指针或标记会覆盖整个信息,在代理发送的内容中,在压缩中,在总结器的快取中都一样,少了被锁定的部分lockChunk除去其标识名称之外。 与任何针一样,一个块在保存其消息之前被记录,因此压缩仍然可以概括这些部分,而代理则被生发. 下kv-stable,针与level(无)maxLevel)将它到达的每份摘要完整地保存起来,所以一个被锁上的部分,与部分的被子盖共用一个摘要,使被子在平平平平平平平平平平平平平平平平. 一个预算无法支撑 原始针头的编译器OverBudgetError适应计划的中间部分 超过预算,它的信息和diagnostics.rawPins上面写着每个针头 中间有原始的标志.listPins财务报告和审定财务报表unpin管理针头.holdCompression将信件不压缩到releaseCompression,或直到可选timeoutMs通过,内容 您仍然会编辑。 Holds活在记忆中,所以一个重新开放的经理从没有开始,一个从未释放出摊位的控股会压缩之后的一切.searchSummaries, (中文(简体) ),getSummary财务报告和审定财务报表getSummariesInRange阅读摘要,对于内存工具,代理人可以调用.setToolDefinitions财务报告和审定财务报表setSystemPrompt给汇总器的电话 代理器自己的工具和系统提示。 其信息持有工具调用或结果的块等待工具定义设定后再被压缩.getRenderStats报告上一次汇编中有多少是原始的,多少是摘要,并列出一级至三级的计数。 这是null直到一个活编译运行 从战略加载它的分支, 开店,setStrategy()并且每个都有一个分支切换器;干编译或预览留下它原样. 每个编译结果都带有以下特性:renderStats,故作干编译(dryRun) 显示它所构建的不发送请求的构成. 鉴于请求的间接费用作为汇编requestOverhead选项({ system, tools }),提供的数据还报告除上下文之外请求的内容,因为request: 间接费用和信息位置注入,单位:total。管理费的系统提示是请求发送的提示,系统位置的注入传递给同一编译器:编译器的回放没有改变,价格没有改变。 编译器选取了无论有无的相同内容,并拒绝一个在选择任何东西之前不能被串行为JSON的工具定义的间接费用. 校正数据中的每一条ceiling,是该战略适用的最大乘数.
对于一个把每个签名的思维块 绑在请求上的模型, 它被铸成,通过 { thinkingBinding: { binds: true, dropBlock, participant }, identity } 作为编译的第三个参数 participant 该模型本身的答复被存储在下面和下面 identity 关于请求的系统文本,工具,模型和其余头部的文摘. 编译之后,不考虑这种模型不再能承受的思考, 与分支发送的最后一次请求的每个分支记录相对应, 并说出它最近留下的 thinkingStrip。一旦分行有记录,只有在主机注意到后,复函才会在编译中保持其思维 noteRequestSent(rows, identity, compileId)名称 provenance.compileId 编译时,它的溪流是建自: 当它发送一个溪流的后一轮, 存储信件的id, 请求在编译后所携带, 每一回合到目前为止,顺序, 一旦溪流结束, 这些和它最后的答复 { unstored: true } 对于一行,它不能担保 被携带或返回作为存储。 一个不称它的主机在被存储后会失去在编译时的每个回覆的思考,并且永远不会被拒绝. 虽然一个分支的请求仍在流出,但为该分支编译 binds 仅使用 dryRun: 承诺编译 binds 使溪流的后期笔记无任何保证(见 SelectOptions.thinkingBinding 内 src/types/strategy.ts) (中文(简体) ).
每个选项都记录在 AutobiographicalConfig 内 src/types/strategy.ts。 。 。 .
一个记录,每个代理商一个窗口
多个管理者可以读取一个记录:共享未命名消息槽的代理,或者一个将另一个消息槽与 auxiliaryMessageViews记录按顺序排列 每个管理器也有一个窗口,其代理的行按显示顺序显示,其策略和编译读取此. 直到第一个主持人 presentRows (单位:千美元)presentRows([]) (列入)或a retractRows 写着一行的名字 经理的窗口是记录本身 一如既往 一旦一个主机呼叫 presentRows(ids),窗口只通过演示文稿来增长:一个主机在写作时会呈现一个代理的自有行,另一个编剧在代理的回合起始或工具边界上,所以每个编译都发送代理请求所携带的命令. 第一个呼叫将窗口写下来; 主机在启动时启动每个代理窗口 presentRows([])。写下来是一张唱片,每行都是 presentRows 呼唤和每个墓碑 retractRows 调用( 遗留模式 a) retractRows 将窗口写在下面,作为它自己的记录。 几件物品的书写通过编年史上印有身份标记的分批附件(appendManyToStateJsonWithIdentity,0.6.0上,上下文管理需要:一个管理者在商店的手柄之上,没有它,在任何记录更改前被拒绝),并通过单表写出一个项目。 店里保存着或丢失了整个记录 所以 branchAt 数行 a presentRows 整个调用后在下行显示剪接(一行所输入的下行按自己的顺序被剪接,一行存放在上行的shard's,一行窗口不按自己的顺序被扣:见分行;第一批分行记录将商店移动到编年史的MANIFEST 第2版,较老的编年史发布拒绝打开(见更改日志). retractRows 取出行出( 在遗留模式下, 它先写出窗口, 除非它没有命名) , getUnpresentedMessages 列出已到达和未显示的行( 与 { afterSequence }只有那些储存在序列之后, ordinalOf 给一行在窗口中的位置, 它永远不会移动 windowStatusOf 说一行的位置: 'in' 窗户, 'out' 这件事情, 'undone',或 'absent' 从记录。 无法通过另一个经理删除: retractRemoved(ids) 把它从窗外取出 retractAbsentRows() 取出窗口所持有的不再保存的每行记录,为主机的出舱口;每行都告诉这个管理器的策略,所以一个折叠的读取器会像删除器的策略那样将被删除的行展开. 策略在进入窗口时会听到行 onPresented: 在窗口为记录时,每加一个 presentRows 一旦一个主机呈现, 所以自传性策略 块并压缩 它的代理显示。 它听到一行人离开 onRetracted时间: retractRows,当一个主机送来, 和 retractRemoved 财务报告和审定财务报表 retractAbsentRows,在一行中,商店不再持有 仅通过它的id(info.ids)),因此自传策略将摘要从被撤销的倒转行和被取走的行和被再次折叠的行上丢出,再重做后每行一次. 如果策略永远不会听到一行去(在窗口的墓碑和策略本身的写作之间停止了过程),或者一个策略没有的经理 onRetracted 接下来,一旦主办方送来礼物,将修复它所保存的(不是在 auditOnly 打开; 仅降级 topologyPolicy: 'reject',默认值):它放出仍然从窗口外出一行所覆盖的东西,并降下一个摘要,即一行所呈现的新位置再次留下了非相接的,而不是拒绝商店. 见 src/window-index.ts。 。 。 .
分支
"纪事"保留了商店的历史,因此对话可以分支. branchAt(messageId) 创建一个分支作为信息 switchBranch(name) 移动它. fork() 在当前头部创建一个分支并切换到它。 策略的状态,摘要包括,跟随分支,每个窗口也是如此:一个分支从其分支点的窗口起步. 一旦一个主持人呈现一行, branchAt 切出一行 窗口所持的 写它, 从来没有在它的身体 最后一个shard 自己的序列, 所以新分支的窗口 持有行 及其记录 整个身体; branchSequenceOf(messageId) 给它切掉的序列而不做分枝 窗口的一行没有,包括一个被收回的一行,是按它自己的顺序被剪去的,而不是按照它之前呈现的一行,因为每行都处于遗产模式. 窗口自下而上所持的一行是自下而上自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出自出 被收存为硬体的一具被写入所输入的被剪切为上个硬体,不过,遗留模式被剪切为被命名为"硬体"的被剪切为上个硬体,比如第一个. derive() 带着窗子,不管战略的衍生名称 内容 atSequence 被切成给定的,所以一旦一个主机呈现,就给它一个显示边界,例如 currentSequence() 读取于 presentRows:从窗子被写出后存储的一行的自序被切出一行从孩子的窗外取出. 一行被从自己写入窗口的写出之前所储存的一行,因此取出一行的剪接会让孩子处于遗产模式下,其出道的出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道出道来.
检查和修理仓库
除其他工具外, scripts/ 持有用于检查和修理仓库的物品。 譬如说, inspect-store.ts 写出商店的讯息、摘要树和分辨率, audit-topology.ts 检查每个摘要是否包含一系列相接的信息,以及 repair-topology.ts 计划修复一个没有, 它适用于 --apply打开一个商店可以打开锁,可以写给它, 所以运行在停止的代理商店或复制品上. scripts/README.md 显示如何编译脚本并描述其中的几个.
设计说明
docs/ 坚持战略背后的设计. 这些都是很好的起点:
adaptive-resolution-design.md:适应性分辨率及其解决者.kv-stable-context-control.md页:1kv-stable解会者.unified-solve-design.md页:1kv-unified解会者.compression-recall-curve-fallback-spec.md:当模型拒绝请求时压缩会做什么.memory-tools-design.md: 代理机的内存工具.
发展
npm ci
npm test # builds, then runs the compiled tests in dist/
npm run typecheck
捐款额 包括改变土地、拉动请求应包含什么、改变日志碎片和释放. 变动情况 列出每次发布更改的内容.
许可证
麻省理工学院,作为 package.json 声明.