上下文工程:让Agent真正用好记忆与知识

📖 本文是学习 Hello-Agents 项目时整理的笔记与思考。

拥有记忆和检索能力,只是 Agent 智能化的第一步。如何在有限的上下文窗口内,高效地组织、筛选和利用这些信息,才是决定 Agent 实际表现的关键——这正是上下文工程(Context Engineering)所要解决的问题。

文章已同步发布到微信公众号【浪浪山客栈】
https://mp.weixin.qq.com/s/C5qlbeuF2aZm8mjMxnYPJw


什么是上下文工程?

当我们为 Agent 赋予记忆模块(MemoryTool)和知识检索能力(RAG)之后,一个新的挑战随之出现:Agent 可能面对数量庞大、来源各异的候选信息,但 LLM 的上下文窗口是有限的。如何从海量候选中挑选出最有价值的内容,以最紧凑、最清晰的方式送入模型,直接决定了最终回答的质量。

上下文工程,就是系统性地解决"给模型看什么、怎么看"这一问题的方法论。

核心目标

用尽可能少、但高信号密度的 tokens,最大化获得期望结果的概率。

这个目标包含两层含义:

  1. :减少噪声信息、冗余内容对宝贵 token 预算的占用。
  2. :送入上下文的每一个 token,都应对模型的推理和输出产生正向贡献。

主要手段

实现上述目标,通常依赖三类核心手段:

  • 压缩整合:对信息进行摘要、去重,在不损失关键语义的前提下缩短长度。
  • 结构化笔记:以机器可解析、人类可阅读的格式记录任务状态与关键结论,便于后续按需检索。
  • 子代理架构:将复杂任务分解给多个子 Agent,每个子 Agent 只处理与自身任务强相关的上下文,从源头上控制上下文规模。

GSSC:上下文构建的四阶段流水线

GSSC 是一套完整的上下文构建流水线,将上下文的生命周期划分为四个阶段:Gather(汇集)→ Select(选择)→ Structure(结构化)→ Compress(压缩)。每个阶段各司其职,共同保证最终进入模型的上下文既完整又精炼。


第一阶段:Gather(多源信息汇集)

Gather 阶段的目标是广撒网——从所有可能的信息源中汇集候选信息,形成待筛选的信息池。

信息源及其优先级:

优先级 信息源 说明
最高 系统指令 Agent 的角色定义、行为准则,不参与后续评分,直接保留
记忆检索 从 MemoryTool 中检索与当前任务相关的历史记忆
RAG 检索 从知识库中检索相关知识片段
历史对话 近期对话轮次,提供当前任务的对话上下文
自定义信息包 用户或系统注入的额外上下文信息

工程最佳实践:

  • 容错机制:每个外部信息源都应包裹 try-catch,确保单个源失败(如 RAG 服务超时、记忆库连接异常)不会中断整体流程,Agent 可以在信息不完整的情况下降级运行。
  • 优先级处理:系统指令拥有最高优先级,在后续所有阶段中均不被压缩或丢弃。
  • 历史限制:对话历史只保留有限的最近几条(如最近 10 轮),避免长对话将上下文窗口填满,使当前任务相关信息无处安放。

第二阶段:Select(智能信息选择)

Select 是整个流水线的核心,直接决定了最终上下文的信息质量。它的目标是从 Gather 阶段汇集的候选信息中,智能筛选出最有价值的内容

执行步骤:

  1. 分离系统指令:将系统指令从候选池中单独提取,优先保留,不参与评分竞争。
  2. 计算系统指令占用的 token:确认系统指令消耗的预算,得到剩余可分配的 token 上限。
  3. 为其余候选信息计算综合分数:综合相关性与新近性两个维度,为每条候选信息打分。
  4. 按分数降序排序:分数越高,信息越值得被优先纳入。
  5. 贪心填充:按分数从高到低依次选入,直至 token 总量达到预设上限。

工程实践要点:

  • 评分机制:综合分数 = α × 相关性得分 + β × 新近性得分,其中权重 α、β 可针对不同任务场景进行配置。例如,对于需要历史追溯的分析任务,可以适当降低新近性权重;对于实时对话场景,则可提高新近性权重。
  • 贪心算法:贪心策略在实践中被证明是效率与效果的良好平衡点——在不遍历所有组合的前提下,近似找到 token 预算内的最优信息子集。
  • 最低相关性过滤:通过 min_relevance 参数设定相关性阈值,低于阈值的信息即使 token 预算仍有余量,也会被过滤掉,避免噪声信息混入上下文。

第三阶段:Structure(结构化输出)

经过 Select 筛选后,我们手中拥有的是一批高质量的信息碎片。Structure 阶段的任务是将这些碎片组织成结构清晰、模型易于理解的上下文

标准模板结构:

[Role & Policies]
明确 Agent 的角色定位与行为准则。
例如:你是一位专注于代码审查的工程助手,回答时需优先考虑安全性和可维护性。

[Task]
当前轮次需要完成的具体任务描述。
例如:审查以下 Python 函数,指出潜在的性能瓶颈。

[State]
Agent 当前所处的状态与背景信息。
例如:当前处于重构项目第二阶段,已完成数据层改造,正在处理业务逻辑层。

[Evidence]
从外部信息源(RAG、记忆库等)检索到的证据信息。
例如:相关文档片段、过去处理类似问题的记忆等。

[Context]
历史对话记录与相关记忆。
例如:最近 5 轮对话摘要,以及与当前任务相关的历史决策记录。

[Output]
期望的输出格式与要求。
例如:以 Markdown 列表形式输出,每条问题附上严重等级(P0/P1/P2)和修改建议。

结构化的核心优势:

  • 可读性:清晰的分区让模型和人类都能快速定位信息,降低理解成本。
  • 可调试性:当 Agent 输出出现问题时,开发者可以快速定位是哪个分区的信息导致了偏差,大幅降低排查成本。
  • 可扩展性:需要接入新的信息源时,只需在模板中新增对应分区,不影响现有结构,符合”开闭原则”。

第四阶段:Compress(兜底压缩)

在某些极端情况下——例如任务背景极为复杂,或系统指令本身就占用了大量 token——即使经过 Select 的精挑细选,结构化后的上下文依然可能超出模型的 token 上限。此时,Compress 阶段作为兜底机制介入。

设计原则:保持结构完整性

Compress 的压缩不是"一刀切"地截断,而是以分区为单位进行压缩。即使 token 预算极度紧张,也要尽量保留每个分区的核心信息,确保模型对整体任务结构的感知不受损。

优化建议:

  1. 动态调整 token 预算:根据任务复杂度动态调整 max_tokens。简单的问答任务可使用较小预算;涉及多步骤推理或长文档分析的复杂任务,则适当增加预算上限。
  2. 升级相关性计算方式:在生产环境中,将基于关键词重叠的简单相似度计算替换为向量相似度(如使用 Embedding 模型),可以显著提升语义检索质量,使 Select 阶段就能更精准地筛选信息,从而减少对 Compress 的依赖。
  3. 缓存机制:对于内容稳定的系统指令和知识库文档,引入缓存机制(如 Anthropic 的 Prompt Caching),避免每次请求都重复计算 token 占用,同时降低推理成本。
  4. 监控与日志:记录每次上下文构建的关键统计信息(如:命中信息条数、各信息源的 token 占比、被过滤的信息数量、最终 token 使用率等),为后续参数调优提供数据支撑。
  5. A/B 测试:对于关键超参数(如相关性权重 α、新近性权重 β、min_relevance 阈值),通过 A/B 测试在真实任务上寻找最优配置,而非仅凭经验拍定。

NoteTool:长时程任务的结构化外部记忆

对于持续数小时乃至数天的长时程任务——如大型代码重构、持续的研究调研、多阶段项目管理——Agent 需要一种能够跨对话轮次持久化、结构化地记录任务状态和关键结论的机制。这正是 NoteTool 的定位。

设计理念

NoteTool 相比传统的 MemoryTool,是一种更轻量、更人类友好的记录方式。它的核心特点包括:

  • 结构化记录:采用 YAML 头部 + Markdown 正文的混合格式,既适合机器解析,也方便人类直接阅读和编辑。
  • 版本友好:纯文本格式天然支持 Git 等版本控制工具,可以完整追踪笔记内容的演化历史。
  • 低开销:无需依赖复杂的向量数据库或关系型数据库,轻量的文件系统操作即可支撑日常的状态追踪需求。
  • 灵活分类:通过 typetags 字段,支持多维度的笔记组织与检索,满足不同类型任务信息的管理需求。

存储格式

1. 笔记文件格式

每条笔记是一个独立的 Markdown 文件,由 YAML 头部(元数据)和 Markdown 正文(内容)两部分组成:

---
id: note_20250119_153000_0
title: 项目进展 - 第一阶段
type: task_state
tags: [refactoring, phase1, backend]
created_at: 2025-01-19T15:30:00
updated_at: 2025-01-19T15:30:00
---

# 项目进展 - 第一阶段

## 完成情况

已完成数据模型层的重构,主要改动包括:

1. 统一了实体类的命名规范
2. 引入了类型提示,提升代码可维护性
3. 优化了数据库查询性能

## 测试覆盖

- 单元测试覆盖率:85%
- 集成测试覆盖率:70%

## 下一步计划

1. 重构业务逻辑层
2. 解决依赖冲突问题
3. 提升集成测试覆盖率至 85%

2. 索引文件

NoteTool 在本地维护一个 notes_index.json 文件,用于在无需逐一读取文件的情况下快速检索和管理笔记:

{
  "note_20250119_153000_0": {
    "id": "note_20250119_153000_0",
    "title": "项目进展 - 第一阶段",
    "type": "task_state",
    "tags": ["refactoring", "phase1", "backend"],
    "created_at": "2025-01-19T15:30:00",
    "updated_at": "2025-01-19T15:30:00",
    "file_path": "./notes/note_20250119_153000_0.md"
  }
}

索引文件的主要作用包括:

  • 快速检索:按 type、tags、时间范围等条件过滤,无需全量读取笔记内容。
  • 元数据管理:集中管理所有笔记的结构化元数据。
  • 完整性校验:对比索引与实际文件,检测是否存在孤立文件或索引缺失的情况。

核心操作

NoteTool 提供七类核心操作,覆盖笔记的完整生命周期:

操作 说明
create 创建新笔记,生成唯一 ID 并更新索引
read 按 ID 读取笔记的完整内容
update 更新笔记正文或元数据(自动更新 updated_at
search 按关键词、type、tags 等条件检索笔记
list 列出所有笔记或按条件过滤后的笔记列表
summary 对笔记内容进行摘要,生成高层次概览
delete 删除笔记文件并从索引中移除

最佳实践

1. 合理的笔记分类

为笔记选择合适的 type 是高效检索的前提。推荐的笔记类型体系如下:

  • task_state:记录阶段性进展与当前状态,是最常用的类型。
  • conclusion:记录经过验证的重要结论与发现,供后续任务引用。
  • blocker:记录当前阻塞问题,优先级最高,应在上下文构建时优先纳入。
  • action:记录明确的下一步行动计划,驱动任务向前推进。
  • reference:记录重要的参考资料、文档链接或外部信息。

2. 定期清理与归档

笔记不应只增不减,定期维护同样重要:

  • 已解决的 blocker,将其 type 更新为 conclusion,并记录解决方案。
  • 已过期的 action,及时删除或标记为 completed
  • 利用 tags 进行版本管理,如为某个里程碑版本的笔记统一打上 v1.0 标签,完成后加上 archived

3. 与 GSSC 的配合

NoteTool 需要与前述的上下文构建流水线紧密配合,才能发挥最大价值:

  • 在每轮对话的 Gather 阶段,将相关笔记作为一类信息源纳入候选池。
  • 在 Select 阶段,根据笔记类型赋予差异化的优先级分数:blocker > action > conclusion > reference
  • 限制每轮纳入的笔记数量上限,防止历史笔记堆积导致上下文过载。

4. 人机协作

NoteTool 的纯文本格式天然支持人工干预:

  • 笔记是标准 Markdown 格式,开发者或用户可以直接在文本编辑器中手动修改,无需通过 API。
  • 使用 Git 对笔记目录进行版本控制,完整追踪 Agent 的”思维演化”过程,也便于在出现问题时回滚到历史状态。
  • 在关键里程碑节点,安排人工审核 Agent 自动生成的笔记,确保其准确性与完整性。

5. 自动化工作流扩展

NoteTool 作为结构化的持久化存储,可以作为更多自动化工作流的基础:

  • 定期触发 summary 操作,生成项目进度的摘要报告。
  • 基于笔记内容自动生成项目周报或 Release Notes。
  • 将笔记内容同步推送至外部协作工具(如 Notion、Confluence),实现 Agent 工作过程的透明化。

TerminalTool:即时文件访问的安全桥梁

在处理涉及本地文件系统的任务时,Agent 面临一个效率困境:如果将所有相关文件预先加载进上下文,会严重消耗 token 预算;但如果什么都不加载,遇到需要文件内容时又无从下手。

TerminalTool 提供了一种优雅的解决方案——即时(Just-in-Time, JIT)上下文:Agent 不在任务开始时预加载所有文件,而是在需要时按需探索和检索,将文件访问的时机和粒度控制权交还给 Agent 自身。

为什么需要 TerminalTool?

在真实工程场景中,有大量任务需要实时、轻量级地访问文件系统,而又不适合预先建立完整索引:

  • 代码审查与调试:Agent 需要按需查看特定文件的具体内容,而非批量加载整个代码库。
  • 日志分析:实时查看最新的日志片段,而非预加载可能数 GB 的日志文件。
  • 文档撰写:在撰写过程中随时查阅相关配置文件或接口文档的当前内容。

这类场景的共同特点是:访问模式难以预测、所需文件随任务动态变化,这使得预先索引和向量化的方案显得笨重且低效。

多层安全机制

允许 Agent 执行命令是一个强大但潜在危险的能力。TerminalTool 通过四层安全机制将风险控制在可接受范围内:

  1. 命令白名单:只允许执行预定义的安全命令集合(如文件查看、文本搜索、目录导航等),拒绝一切非白名单命令,从根本上杜绝执行高危操作的可能。
  2. 工作目录限制:将命令执行的范围严格限定在预设的工作目录内,防止 Agent 越权访问系统敏感目录(如 /etc/root)。
  3. 超时控制:为每次命令执行设定最大运行时间,避免因意外的长时间运行命令(如误触发大规模文件搜索)导致 Agent 阻塞。
  4. 输出大小限制:对命令输出的大小进行截断,防止巨型文件内容直接撑满上下文窗口,确保 Agent 能够正常处理返回结果。

核心能力

命令执行(_execute_command

TerminalTool 的底层能力,负责在安全机制的约束下执行白名单内的命令,并将标准输出(stdout)和标准错误(stderr)结构化地返回给 Agent。

目录导航(cd

支持 Agent 在工作目录范围内自由切换当前路径,配合 lscatgrep 等常用命令,使 Agent 能够像人类工程师一样探索项目结构、按需查阅文件内容。


总结

上下文工程是 Agent 系统走向生产可用的必经之路。本文介绍的三个核心组件,共同构成了一套完整的上下文管理体系:

  • GSSC 流水线解决了”如何在每一轮对话中动态构建高质量上下文”的问题,通过汇集、选择、结构化、压缩四个阶段,将海量候选信息蒸馏为精炼的模型输入。
  • NoteTool 解决了”如何在跨轮次的长时程任务中持久化和管理关键信息”的问题,以轻量、人类友好的方式为 Agent 提供结构化的外部记忆。
  • TerminalTool 解决了”如何在不预加载所有信息的前提下,安全地按需访问文件系统”的问题,以 JIT 上下文的理念最大化 token 预算的利用效率。

三者相辅相成:NoteTool 产生的结构化笔记,通过 GSSC 的 Gather 和 Select 阶段按需注入上下文;TerminalTool 提供的即时文件访问能力,则补充了静态知识库和记忆检索之外的动态信息维度。将这三者有机整合,才能构建出真正具备长期记忆、实时感知与高效推理能力的生产级 Agent 系统。

暂无评论

发送评论 编辑评论


				
上一篇
下一篇