0%

Agent 系统中的 Input Token 治理

在本文中,我们将简要讨论 Agent 系统 input token 失控的问题与治理方法。对于一个 Agent 系统,缺乏有效的 token 治理会导致成本飙升、模型注意力稀释等问题,因此,合理的治理可以给系统带来极大的增益。

问题背景

Anthropic 在 Building Effective Agents 中把 Agent 定义为模型自主驱动的决策过程,即执行过程中每一步都要从环境拿到 ground truth(工具调用结果或代码执行输出)来评估进展,并需要停止条件(最大迭代次数之类)维持控制,这就是当前主流Agent Loop 的本质。而更加具体一些,譬如 Lilian Weng 总结的 ReAct 范式,给出了 推理(thought)→ 行动(action)→ 观察(observation) 的循环结构。

因此,Agent 系统与单次 LLM 调用不同,它在一个循环里反复向模型发起请求:识别意图、调用工具、观察结果、再决定下一步。每一次请求都不是孤立的,系统提示词、工具定义、历史对话、记忆检索结果和工具返回的 observation 都会随请求一并发送,作为模型决策的依据。任务越复杂,循环轮次越多,请求承载的内容就越重。以一个涉及文件读取、代码执行和多轮修正的任务为例,可能在多轮以后,历史与 observation 已经占据请求的主体,而真正影响当前决策的信息只占一小部分。

这种膨胀并非某一条 prompt 设计不当所致,而是多类上下文来源叠加累积的结果。工具规模随注册数量增长,历史随对话轮次增长,工具返回随数据规模增长,每一类来源都有独立的增长动力,共同推高输入规模。若各模块均可向请求追加内容而缺乏统一约束,input token 便随任务推进持续膨胀,成本、延迟和模型注意力随之恶化。

在前段时间测试 OpenGIS 项目(指路文章《Agent驱动的GIS客户端OpenGIS:harness的架构升级》)时,发现 OpenGIS 每次任务耗费 token 惊人的高而 cache 命中率惊人的低,譬如一个简单的地图操控任务,其输入 token 可达约50k,但 cache 命中率仅约 10%-20%,这回导致使用成本相当昂贵!分析下来,我总结出下面三个问题:

  • 架构差;context构成不稳定,没有实现尽量大范围的稳定前缀
  • tool 过多;OpenGIS 由于包含了基础的 tool 与大量地图操作 tool,以及一些面向特殊内置功能的tool,一次性暴露所有tool以及相关prompt会导致使用大量token
  • 任务面广;相对于Code、OpenCode等面向code的agent,OpenGIS多出包含大量地图相关操作,这导致任务面更广更难管理。

其中,第三点显然是设计意图导致的必有缺陷,因此,我们需要考虑的是升级架构、优化暴露面以降低使用成本,最终的结果是,OpenGIS的简单地图操控任务可以压缩到10-20k,cache 命中率不同的任务场景浮动很大,但是在30%-70%的范围内浮动,整体使用成本降低至了原先的 1/5 甚至更多,但是仍然和主流 Agent 存在差异,还在继续优化。

本文是对优化工作一些内容的总结凝练,以及对主流相关工作的整理。闲言少叙,我们先来了解一些前置知识。在前文中,我们提到了请求承载的内容膨胀的问题,那么要优化这个问题,必须了解其构成,通常意义上一次 provider request 里的输入可以拆成:

Tinput=Tsystem+Ttools+Thistory+Tmemory+Tretrieval+Tobservation+TscratchpadT_{\text{input}} = T_{\text{system}} + T_{\text{tools}} + T_{\text{history}} + T_{\text{memory}} + T_{\text{retrieval}} + T_{\text{observation}} + T_{\text{scratchpad}}

对应到工程对象,就是:

系统提示词+工具 Schema+历史对话+长短期记忆+检索内容+工具返回结果+Agent 中间轨迹\text{系统提示词} + \text{工具 Schema} + \text{历史对话} + \text{长短期记忆} + \text{检索内容} + \text{工具返回结果} + \text{Agent 中间轨迹}

我们必须首先明确一个事实:模型看到的上下文是系统组装出来的产物。如果每个模块都可以往 request 里追加内容,input token 会随着任务轮次、工具数量、文件大小和日志长度一起增长。因此,我们的优化对象不应该只是 prompt 文字,而是更加总体的对象: provider request 编排

从 Prompt Engineering 转向 Context Engineering

我们需要知道,Prompt EngineeringContext Engineering 是两个层次的问题,其中 Prompt 是发送给模型的一段静态文本,Prompt Engineering 处理的是这段文本本身,包括措辞、示例、指令结构等。Context 则是模型在每一轮实际看到的所有内容,包括系统指令、工具定义、历史对话、检索结果和工具返回。

Anthropic 在 2025 年的工程实践中给出了更完整的定义:Context Engineering 是从不断演化的可能信息集合中,策展出进入有限上下文窗口的内容。与写 prompt 的一次性任务不同,策展发生在每一次决定传给模型什么的时候,是循环中反复执行的动作。

传统 Agent 实现倾向于 Full Context,即每轮都把系统指令、全部工具、完整历史、所有检索文档和完整工具结果塞进请求,这种方式在任务稍长的背景下就会暴露三个问题:

  • 成本。请求规模随轮次线性增长,一个多轮任务(譬如10轮以上),历史与工具返回的重复传输很有可能占掉大部分 token,成本随任务长度持续攀升。
  • 注意力稀释。模型的注意力预算有限,每个新 token 都会消耗预算,上下文越长边际收益越低。Liu 等人2023年的研究认为,模型对长上下文中间位置信息的利用显著弱于开头和结尾。把低价值内容堆进上下文不仅会浪费 token,还可能会主动恶化模型对关键信息的提取。
  • 缓存失效。Prompt caching 依赖稳定前缀,任何每轮变化的内容插进前缀都会让缓存整体失效,可以说,动态内容越多,命中率越低,成本优化空间越小。

Context Engineering 的目标是把 Agent 从 Full Context 变成 Context-on-Demand,对于后者来说,每次请求的流程可以依次加入:

当前任务需要的规则
当前任务需要的工具
当前任务状态摘要
重排后的少量证据
工具结果摘要
+ 证据指针

从工程实现看,上下文不是静态 prompt,而是每轮根据任务目标、工具状态、历史依赖、检索结果和预算约束生成的 request。这意味着上下文治理不能只靠写好一段 prompt,而要把组装动作本身做成系统的一部分,在介绍完总体的内容后,我们将在下面的章节中介绍具体方法。

构成一:Token Budget Manager

要让 Context-on-Demand 真正落地,系统需要一个显式的 Token Budget Manager。它负责为每一类上下文分配预算上限(譬如分配系统提示词、工具 schema、历史对话、检索内容这些部分各自给多少预算),并在请求组装过程中执行这些约束,请求组装过程中的每一步取舍都由这个管理器来裁决。

一个常见的请求组装流程是:

用户请求
任务识别
工具选择
记忆检索
文档检索
工具结果压缩
历史状态压缩
组装 Provider Request

在组装之前,每一步都受预算约束,譬如说下表展示的预算比例(当然,这只是一个例子,具体的构成与比例还需要按照需求定夺):

上下文部分 建议预算
System Prompt 5% 到 10%
Tool Schema 5% 到 15%
当前用户任务 5%
结构化任务状态 10% 到 20%
RAG 检索内容 30% 到 50%
工具 observation 10% 到 20%
输出空间 单独预留

这些比例不是固定配置,而是 admission control(准入控制)的输入

以一个 RAG 任务为例:系统按照用户提问召回 50 篇文档,压缩后准备注入 top-5,但此时预算只够满足 top-3,同时这一轮的历史对话和工具返回也超了。这时候压缩就要按优先级进行:

  • 将工具返回替换为摘要与证据指针
  • 检索内容从 top-5 减少 top-3
  • 历史只保留最近几轮和任务状态摘要

构成二:Agent 上下文压缩

在长任务中,历史对话、工具返回、中间轨迹都会持续累积,上下文不可能无限增长,所以压缩是绕不开的环节。但我们需要明确一点:压缩不能只按时间截断,不能简单粗暴地"只保留最近 N 轮"。原因在于 Agent context 的信息价值不由时间顺序决定,而由任务依赖关系决定。

基于这个原则,需要保留的信息通常包括:

  • 当前目标
  • 用户明确约束
  • 已确认事实
  • 最新计划
  • 当前阻塞点
  • 关键证据
  • 高风险决策依据

可以压缩或删除的信息通常包括:

  • 失败的无关尝试
  • 重复 observation
  • 长篇工具日志
  • 过时计划
  • 已经写入结构化状态的历史对话

确定了保留什么、删除什么之后,接下来是怎么压缩的问题。常用的手段有四种,各自适合不同的内容:

  • 摘要。把一段历史交给 LLM 压成几句话。需要注意的是摘要最好带上上一轮的摘要一起合并(锚定合并),否则多轮压缩之后摘要会越滚越大,或者丢失早期信息。
  • 截断。直接删除超龄消息。实现简单,但风险是可能删掉后面还在引用的内容,比如一个工具结果被删了,模型后续却还在讨论它。
  • 结构化投影。把自然语言对话转成结构化 task state,比如当前目标、已确认事实、约束、阻塞点。这个手段信息密度最高,后面章节会专门展开。
  • 占位符替换。旧工具结果只保留元信息(哪个工具、调用 id、时间戳),正文删除,模型需要时再通过 pointer 读取原始内容。

实际系统中这几种手段通常组合使用,譬如对历史对话采用摘要加结构化,对工具结果采用占位符,将日志直接截断

压缩的时机也需要考虑。比较好的做法是触发式压缩,即当 token 估算超过某个阈值,或者工具结果在上下文中占比过高时,才执行压缩。压缩时还需要保护最近的一小段消息,它们是当前决策的直接上下文,不应该被压掉。

构成三:工具按需注入

工具 schema 是 Agent 系统里最容易被低估的 token 来源。工具数量上来以后,每轮注入几十个甚至上百个完整 schema,会让简单任务也背上很重的上下文。

但"按需注入"不能理解成每轮都去检索一次工具,更常见的形态是把工具分成三层:

  • 核心工具:永远注入。文件读写、代码执行这类基础能力几乎所有任务都用得上,不值得为它们做检索。
  • 领域工具包:按任务类型成组注入。地图操作、栅格处理、样式调整这类能力,一个任务通常只涉及其中一组。
  • 扩展工具:按需读取。低频、重型或特殊能力,schema 不常驻,模型需要时通过 tool docs 或 skill 读取详细说明。

按需注入有两种实现路线,适用场景不同:

  • 确定性路由:先做任务识别,再按规则或关键词选中对应的工具包。好处是可预测、稳定,工具集合的构成每轮都是确定的;代价是依赖任务分类的质量,识别错了工具就带错。
  • 语义检索:把工具描述向量化,用 embedding 检索当前任务相关的工具。好处是灵活,能覆盖规则想不到的组合;代价是每次请求多一次检索开销,而且检索结果有随机性,工具集合不稳定。

一个常见的流程是:

用户任务
任务类型识别
检索相关工具
注入 Tool Schema
按需读取 Tool Docs / Skill

这里有一个容易被忽略的权衡:按需注入的目的是减少 schema 数量,但工具集合如果每轮都在变,prompt 前缀的缓存就会频繁失效。所以注入的粒度很关键。按工具包粒度路由,集合粗、变化少,缓存稳定;按单个工具粒度检索,集合细、每轮都可能不同,缓存命中率会受影响。因此,还需要在实践中进行调整。

工具 schema 本身也需要压缩。schema 只描述接口,不承载业务文档。推荐形态:

1
2
3
4
5
6
7
8
9
{
"name": "search_code",
"description": "Search project code by symbol or text.",
"parameters": {
"query": {"type": "string"},
"path": {"type": "string"}
},
"required": ["query"]
}

当然,在 schema 里放大量背景、示例、异常分支和业务说明是不合适的。这些内容应该移到工具内部、工具文档、skill 或 operation contract 中。模型需要时再读取,不需要时不进入 request。

构成四:历史对话转结构化状态

在多轮对话中,如果每轮都把全部 messages 发给模型,token 会线性增长。因此,替代方案是把历史对话投影成结构化 task state,比如下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"goal": "修复角色攻击动画播放但没有伤害的问题",
"confirmed_facts": [
"引擎:Unity",
"角色:Knight_01",
"技能 ID:skill_1024",
"现象:动画播放但未触发伤害"
],
"constraints": [
"不能修改公共伤害公式",
"优先检查配置表和动画事件"
],
"current_hypothesis": "skill_1024 的 damageEvent 配置可能缺失",
"last_action": "已读取 SkillConfig.json",
"open_questions": [
"是否只在联机模式复现"
]
}

一段多轮自然语言对话压缩成这样的结构通常只要几百 token,却也保留了决策所需的事实和约束。为了做到这一点,我们需要一个投影机制,常用的做法有两种:

  • 增量更新:保留上一轮的 task state,让 LLM 只读本轮新增的对话,更新 goal、confirmed_facts、constraints 这些字段。这样做会大大降低成本,且历史不会重复处理,代价是状态可能会导致缓慢漂移,比如某个早期事实被错误覆盖。
  • 全量重建:每轮把全部历史重新过一遍,重新生成 task state。准确,但每次都付出重读历史的成本,省下的 token 又花回去了。

在实践中,我们更倾向增量更新,这和前面讲的锚定合并(摘要带上上一轮摘要)是同一个思路,即旧状态是基底,新对话只做增量修补。并且在结构化之后,最近几轮应该保留原文,因为模型经常需要看细节,比如用户的原话、具体的代码片段;更早的轮次才转成 task state。

不可避免的,task state 必然会丢信息。用户原话的精确措辞("不要用 X 方法"和"尽量避免 X"语义不同)、长代码片段、日志这类内容都不适合塞进结构化状态。所以当状态里出现矛盾或者模型对某个事实不确定时,应该需要回退到原始对话。

一个较完整的记忆分层可以是:

内容 是否每轮注入
Working Memory 当前任务目标、约束、阻塞点、最近动作
Episodic Memory 历史任务经验、失败模式、修复记录 按需检索
Semantic Memory 长期知识、项目事实、数据集说明 按需检索
Procedural Memory 可复用流程、工具用法、操作规范 按需读取
Artifact Store 文件、日志、图片、代码输出、大数据 只传引用

这样,「完整历史」可以被拆成多个可检索、可替换、可裁剪的对象。

构成五:Observation Compression

工具返回结果是另一个 token 黑洞。例如代码搜索返回多个文件,而每个文件可能存在几百行,如果全部进入上下文无疑会大大增加模型的压力与噪声。因此工具结果也需要压缩,但压缩发生在哪一层,决定了整个系统的形态。

相比工具侧压缩,现阶段在实践中更推荐的做法是运行时统一处理,即工具照常返回完整结果,由统一的 observation normalizer 转成标准结构,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"summary": "skill_1024 未配置 damageEvent,可能导致动画播放但无伤害。",
"evidence": [
{
"file": "Config/SkillConfig.json",
"line": 903,
"field": "damageEvent",
"value": null
},
{
"file": "Combat/SkillExecutor.cs",
"line": 128,
"snippet": "if (config.damageEvent != null) TriggerDamageEvent();"
}
],
"next_step": "确认该技能是否应该配置 damageEvent。"
}

这个结构中的字段可以包括:

  • summary:给模型看的结论
  • evidence:是支撑结论的关键证据(文件、行号、片段)
  • next_step:提示下一步动作。
  • 完整内容落盘,模型需要时再通过 artifact id、文件路径、行号读取。

压缩的时机有两层。第一层是工具结果进入上下文之前,先压成 summary 加 evidence;第二层是进入上下文之后,按预算触发式再次压缩,旧的 observation 退化成占位符,只保留工具名和调用 id,对应前文所说的触发式压缩。

构成六:如果你需要 RAG 检索,那请多召回少注入

RAG Agent 容易把 top-n chunk 直接送进模型,但检索是廉价的,注入是昂贵的。召回阶段多取几篇文档几乎不花什么代价,但多注入多注入的 chunk 会占用模型的注意力,因此,正确的关系应该是召回阶段尽量多,注入阶段尽量少

一个典型的流程是:

用户问题
Query Rewrite /
Decomposition
Recall
Top-20 / Top-50
Rerank
Select
Top-3 / Top-5
Chunk
Compression
注入最终证据

中间的每一步都有它的作用:

  • Query Rewrite 把模糊的用户问题改写成适合检索的形式
  • Rerank 把召回结果按相关性重排
  • Chunk Compression 把选中的 chunk 压成摘要

最终进入 request 的不是文档堆,而是压缩后的证据对象:

1
2
3
4
5
6
{
"evidence_id": "doc_142_p3_chunk_2",
"summary": "该文档规定技能伤害必须通过 damageEvent 触发。",
"quote": "damageEvent is required for damage-triggering animation events.",
"source": "CombatDesign.md#L120-L135"
}

每个证据对象都带 source 引用,模型引用时有据可查。这样既降低了 token,也提高了可追溯性。

构成七:Prompt Compression 与 Context Compression 模型

Prompt Compression 可以用于历史对话、长文档、工具 observation、日志、搜索结果和 Agent 轨迹。它的目标不是把句子统一缩短,而是删除低信息量 token,保留对决策有意义的实体和约束。

适合保留的内容:

  • 文件路径
  • 函数名
  • 类名
  • 字段名
  • 错误码
  • 数值
  • 配置 ID
  • 用户硬性约束
  • 安全限制

适合压缩的内容:

  • 解释性长句
  • 重复日志
  • 已经验证失败的路径
  • 中间推理过程
  • 非关键输出样本

压缩前:

1
这个函数主要用于在玩家点击攻击按钮之后,根据当前角色状态、技能冷却状态、资源消耗情况以及目标选择结果,最终决定是否可以释放技能。

压缩后:

1
2
函数:判断玩家点击后是否可释放技能。
依赖:角色状态、CD、资源、目标。

可以注意到,压缩后保留的全是实体(函数、依赖项),删掉的都是修饰和解释。执行压缩的方式有多种,譬如规则提取实体,或者使用专门的压缩模型,抑或直接让主 LLM 完成,三者成本和质量不同,需要开发者按场景选择。

构成八:Agent 轨迹压缩

ReAct 类 Agent 每一步都会产生一组:

  • Thought
  • Action
  • Observation
  • Thought
  • Action
  • Observation

长任务里,这样的三元组会累积几十上百组,是上下文里膨胀最快的部分之一。轨迹的保留策略需要分级:

  • 最近 N 步保留原始轨迹
  • 更早轨迹压缩为任务状态
  • 失败尝试只保留结论
  • 关键证据保留引用

例如,一段十几步的排查过程可以压缩成:

1
2
3
4
5
6
7
8
9
10
{
"investigation_summary": "当前证据指向 skill_1024 的 damageEvent 配置缺失。",
"evidence": [
"SkillConfig.json: skill_1024.damageEvent = null",
"SkillExecutor.cs: damageEvent 为空时不触发伤害"
],
"discarded_paths": [
"已检查技能 ID 存在,不是 ID 错误"
]
}

discarded_paths 是这段压缩的关键,它把模型"查过但无关"的路径也记录下来,模型后续不会重复排查。这类压缩比删除旧消息更可靠,因为它保留了当前决策仍然依赖的证据,也保留了已经排除的可能。

构成九:大文件使用 Artifact Pointer

代码、日志、PDF、表格、图片和地理数据不应该直接进入 prompt,它们应该作为 artifact 存储,上下文里只放必要摘要和引用:

1
2
3
4
5
6
7
{
"artifact_id": "log_2026_06_08_001",
"type": "battle_log",
"summary": "日志中未出现 DamageEvent.Trigger,攻击动画正常播放。",
"time_range": "10:21:00-10:23:00",
"relevant_lines": [1203, 1210, 1224]
}

指针里应当包含两个内容:

  • 摘要(模型判断是否需要看细节的依据)
  • 定位信息(文件、时间范围、相关行号)

模型需要细节时再发起读取:

1
read_artifact_lines(log_2026_06_08_001, 1200, 1230)

大部分轮次模型只需要摘要,只有少数时候需要精读,这样可以按需支付精读的代价。当然,指针同样存在生命周期问题,artifact 落盘后需要约定保留策略,任务结束或不再被引用时清理,否则存储会无限增长。

构成十:多 Agent 只传结构化摘要

多 Agent 系统容易发生 token 乘法级别的增长,试想我们激活了 N 个子 Agent,如果每个都拿到完整上下文,再把完整过程传回主 Agent,上下文不是线性增长,而是乘数增长。实际上,每个子 Agent 的工作过程对主 Agent 并没有价值,主 Agent 只需要结论和关键依据

更合适的通信格式是:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"role": "reviewer",
"result": "fail",
"issues": [
{
"severity": "high",
"file": "SkillExecutor.cs",
"line": 128,
"message": "未处理 damageEvent 为空时的错误提示"
}
],
"suggested_action": "补充配置校验,不直接改伤害公式"
}

也就是每种角色只传自己的产出物:

Research Agent
• Conclusion
• Evidence ID
Planner
• Task Decomposition
• Constraints
Coder
• Code Diff
• Change Summary
Reviewer
• Issue List
• Risk Level
跨 Agent 传递的是接口和摘要,不是完整上下文。这要求每个 Agent 的出口是结构化的 handoff contract,而不是一段对话记录。

构成十一:模型分层

减少 input token 还可以通过模型分层实现,把工作按难度拆给不同规模的模型:

1
2
3
4
5
6
7
8
9
10
11
小模型 / 规则系统:
- 意图识别
- 工具选择
- 文档初筛
- 历史摘要
- 风险判断
大模型:
- 复杂推理
- 代码生成
- 方案设计
- 最终决策

思路是大模型不需要看到所有原始输入,只接收筛选和压缩后的高价值上下文,前置的小模型承担 routing、summarization、filtering、guard 这类低风险任务。
需要说明的是,模型分层不是免费的,即多一层调用就多一次延迟,小模型的选择质量可能影响下游,两个模型的输出一致性也需要维护。它的适用场景是高频、低风险、判定规则明确的任务,比如意图识别和文档初筛;复杂推理和最终决策仍然留给大模型。

构成十二:Prompt Caching 的边界

Prompt Caching 通常降低的是重复前缀的计算成本和延迟,不一定减少发送给 provider 的 input token。它的收益来自前缀复用,所以只对稳定内容有效:

  • 稳定 system prompt
  • 稳定工具 schema 顺序
  • 固定公共规则前缀
  • 动态内容后置
    也就是说,缓存的前提是前缀稳定。如果每轮动态内容插在前缀里,缓存频繁失效,收益就很小。但缓存不能替代上下文治理:即使缓存命中率很高,每轮仍然发送长 system prompt、长工具 schema、长历史和长 observation,系统结构依然臃肿,只是重复部分便宜了一些。
    两者的分工可以这样区分:
1
2
Prompt Caching 解决重复前缀的计算成本。
Context Engineering 解决不该进入 request 的输入。

构成十三:可观测性与评测

Input token 治理必须有观测面,建议至少记录这些指标:

  • 每轮 input tokens、output tokens
  • system / tools / history / memory / retrieval / observation 分项 token
  • 工具 schema 数量与 schema token
  • 最大的若干消息
  • cache hit tokens、miss tokens、provider 是否上报 cache 字段
  • tool observation 被压缩前后的大小
  • artifact pointer 数量
  • auto-final 命中次数
  • request pressure:ok / warm / hot / overflow
    更进一步,可以建立固定的 regression case,把典型任务变成可比较的基准:
Case 目标
简单地图缩放 验证不因全工具和长历史膨胀
图层样式修改 验证 style 工具是否按需暴露
CSV 加载 验证数据样本和字段摘要是否有界
Operation 修复 验证脚本复用和失败轨迹压缩
Worker 启停 验证后台日志不会污染 chat context
RAG 文档问答 验证 retrieve many, feed few

每个 case 记录 total tokens、schema tokens、history tokens、observation tokens、cache hit、LLM call count 等指标,以帮助我们进行量化观测。

参考文章

[1] Anthropic. Building Effective Agents[EB/OL]. (2024-12-19). https://www.anthropic.com/research/building-effective-agents.

[2] Weng L. LLM Powered Autonomous Agents[EB/OL]. (2023-06-23). https://lilianweng.github.io/posts/2023-06-23-agent/.

[3] Anthropic. Effective Context Engineering for AI Agents[EB/OL]. (2025-09-29). https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents.

[4] Liu N F, Lin K, Hewitt J, et al. Lost in the Middle: How Language Models Use Long Contexts[J]. Transactions of the Association for Computational Linguistics, 2024, 12: 157-173. https://arxiv.org/abs/2307.03172.

[5] Yao S, Zhao J, Yu D, et al. ReAct: Synergizing Reasoning and Acting in Language Models[C]. ICLR 2023. https://arxiv.org/abs/2210.03629.

[6] Anthropic. Contextual Retrieval[EB/OL]. (2024-09-19). https://www.anthropic.com/engineering/contextual-retrieval.

[7] Anthropic. Prompt Caching[EB/OL]. (2024-08-07). https://www.anthropic.com/news/prompt-caching.

[8] Jiang H, Wu Q, Lin C, et al. LLMLingua: Compressing Prompts for Accelerated Inference of Large Language Models[C]. EMNLP 2023. https://arxiv.org/abs/2310.05736.

[9] Packer C, Wooders S, Lin K, et al. MemGPT: Towards LLMs as Operating Systems[EB/OL]. (2023-10). https://arxiv.org/abs/2310.08560.

[10] OpenAI. A Practical Guide to Building Agents[EB/OL]. (2024-12). https://openai.com/index/a-practical-guide-to-building-agents/.

[11] Anthropic. Claude Code Best Practices[EB/OL]. (2025-02-21). https://www.anthropic.com/engineering/claude-code-best-practices.

🌙