|
@@ -1,25 +1,42 @@
|
|
|
# 第九章 上下文工程
|
|
# 第九章 上下文工程
|
|
|
|
|
|
|
|
-在前面的章节中,我们已经为智能体引入了记忆系统与检索增强生成(RAG),并在后续章节中学习了通信协议以拓展外部能力。然而,要让智能体在真实复杂场景中稳定地“思考”与“行动”,仅有记忆与检索还不够——我们需要一套工程化方法,持续、系统地为模型构造恰当的“上下文”。这就是本章的主题:上下文工程(Context Engineering)。它关注的是“在每一次模型调用前,如何以可复用、可度量、可演进的方式,拼装并优化输入上下文”,从而提升正确性、鲁棒性与效率<sup>[1][2]</sup>。
|
|
|
|
|
|
|
+在前面的章节中,我们已经为智能体引入了记忆系统与RAG。然而,要让智能体在真实复杂场景中稳定地“思考”与“行动”,仅有记忆与检索还不够——我们需要一套工程化方法,持续、系统地为模型构造恰当的“上下文”。这就是本章的主题:上下文工程(Context Engineering)。它关注的是“在每一次模型调用前,如何以可复用、可度量、可演进的方式,拼装并优化输入上下文”,从而提升正确性、鲁棒性与效率<sup>[1][2]</sup>。
|
|
|
|
|
+
|
|
|
|
|
+为了让读者能够快速体验本章的完整功能,我们提供了可直接安装的Python包。你可以通过以下命令安装本章对应的版本:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+pip install hello-agents[all]==0.2.6
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+本章主要介绍上下文工程的核心概念与实践,并在HelloAgents框架中新增了两个工具:
|
|
|
|
|
+
|
|
|
|
|
+- **NoteTool** (`hello_agents/tools/builtin/note_tool.py`):结构化笔记工具,支持智能体进行持久化记忆管理
|
|
|
|
|
+- **TerminalTool** (`hello_agents/tools/builtin/terminal_tool.py`):终端工具,支持智能体进行文件系统操作和即时上下文检索
|
|
|
|
|
+
|
|
|
|
|
+这两个工具是实现长时程任务管理和智能体式搜索的关键组件,将在后续章节中详细介绍。
|
|
|
|
|
+
|
|
|
|
|
+除了安装框架外,还需要在`.env`配置LLM的API。本章示例主要使用大语言模型进行上下文管理和智能决策。
|
|
|
|
|
+
|
|
|
|
|
+配置完成后,即可开始本章的学习之旅!
|
|
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
|
|
## 9.1 什么是上下文工程
|
|
## 9.1 什么是上下文工程
|
|
|
|
|
|
|
|
-在经历了数年“提示工程(Prompt Engineering)”成为应用型AI的焦点之后,一个新的术语开始走到台前:<strong>上下文工程(Context Engineering)</strong>。如今,用语言模型构建系统不再只是找对提示词里的句式和措辞,而是要回答一个更宏观的问题:<strong>什么样的上下文配置,最有可能让模型产出我们期望的行为?</strong>
|
|
|
|
|
|
|
+在经历了数年提示工程(Prompt Engineering)成为应用型AI的焦点之后,一个新的术语开始走到台前:<strong>上下文工程(Context Engineering)</strong>。如今,用语言模型构建系统不再只是找对提示词里的句式和措辞,而是要回答一个更宏观的问题:<strong>什么样的上下文配置,最有可能让模型产出我们期望的行为?</strong>
|
|
|
|
|
|
|
|
所谓“上下文”,是指在对大语言模型(LLM)进行采样时所包含的那组 tokens。手头的工程问题,是在 LLM 的固有约束之下,<strong>优化这些 tokens 的效用</strong>,以便稳定地得到预期结果。想要有效驾驭 LLM,往往需要“在上下文中思考”——也就是说:在任何一次调用时,都要审视 LLM 可见的整体状态,并预判这种状态可能诱发的行为。
|
|
所谓“上下文”,是指在对大语言模型(LLM)进行采样时所包含的那组 tokens。手头的工程问题,是在 LLM 的固有约束之下,<strong>优化这些 tokens 的效用</strong>,以便稳定地得到预期结果。想要有效驾驭 LLM,往往需要“在上下文中思考”——也就是说:在任何一次调用时,都要审视 LLM 可见的整体状态,并预判这种状态可能诱发的行为。
|
|
|
|
|
|
|
|
<div align="center">
|
|
<div align="center">
|
|
|
- <img src="https://www.anthropic.com/_next/image?url=https%3A%2F%2Fwww-cdn.anthropic.com%2Fimages%2F4zrzovbb%2Fwebsite%2Ffaa261102e46c7f090a2402a49000ffae18c5dd6-2292x1290.png&w=3840&q=75" alt="Prompt engineering vs Context engineering" width="90%"/>
|
|
|
|
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/Hello-Agents/main/docs/images/9-figures/9-1.webp" alt="" width="85%"/>
|
|
|
<p>图 9.1 Prompt engineering vs Context engineering</p>
|
|
<p>图 9.1 Prompt engineering vs Context engineering</p>
|
|
|
-
|
|
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
本节将探讨正在兴起的上下文工程,并给出一个用于构建<strong>可调控、有效</strong>智能体的精炼心智模型。
|
|
本节将探讨正在兴起的上下文工程,并给出一个用于构建<strong>可调控、有效</strong>智能体的精炼心智模型。
|
|
|
|
|
|
|
|
<strong>上下文工程 vs. 提示工程</strong>
|
|
<strong>上下文工程 vs. 提示工程</strong>
|
|
|
|
|
|
|
|
-在现在前沿模型厂商的视角中,上下文工程是提示工程的自然演进。提示工程关注如何编写与组织 LLM 的指令以获得更优结果(例如系统提示的写法与结构化策略);而上下文工程则是<strong>在推理阶段,如何策划与维护“最优的信息集合(tokens)”</strong>,其中不仅包含提示本身,还包含其他会进入上下文窗口的一切信息。
|
|
|
|
|
|
|
+如图9.1所示,在现在前沿模型厂商的视角中,上下文工程是提示工程的自然演进。提示工程关注如何编写与组织 LLM 的指令以获得更优结果(例如系统提示的写法与结构化策略);而上下文工程则是<strong>在推理阶段,如何策划与维护“最优的信息集合(tokens)”</strong>,其中不仅包含提示本身,还包含其他会进入上下文窗口的一切信息。
|
|
|
|
|
|
|
|
在 LLM 工程的早期阶段,提示往往是主要工作,因为大多数用例(除日常聊天外)都需要针对单轮分类或文本生成做精调式的提示优化。顾名思义,提示工程的核心是“如何写出有效提示”,尤其是系统提示。然而,随着我们开始工程化地构建更强的智能体,它们在更长的时间范围内、跨多次推理轮次地工作,我们就需要能管理<strong>整个上下文状态</strong>的策略——其中包括系统指令、工具、MCP(Model Context Protocol)、外部数据、消息历史等。
|
|
在 LLM 工程的早期阶段,提示往往是主要工作,因为大多数用例(除日常聊天外)都需要针对单轮分类或文本生成做精调式的提示优化。顾名思义,提示工程的核心是“如何写出有效提示”,尤其是系统提示。然而,随着我们开始工程化地构建更强的智能体,它们在更长的时间范围内、跨多次推理轮次地工作,我们就需要能管理<strong>整个上下文状态</strong>的策略——其中包括系统指令、工具、MCP(Model Context Protocol)、外部数据、消息历史等。
|
|
|
|
|
|
|
@@ -54,14 +71,14 @@
|
|
|
|
|
|
|
|
- <strong>示例(Few-shot)</strong>:始终推荐提供示例,但不建议把“所有边界条件”的罗列一股脑塞进提示。请精挑细选一组<strong>多样且典型</strong>的示例,直接画像“期望行为”。对 LLM 而言,<strong>好的示例胜过千言万语</strong>。
|
|
- <strong>示例(Few-shot)</strong>:始终推荐提供示例,但不建议把“所有边界条件”的罗列一股脑塞进提示。请精挑细选一组<strong>多样且典型</strong>的示例,直接画像“期望行为”。对 LLM 而言,<strong>好的示例胜过千言万语</strong>。
|
|
|
|
|
|
|
|
-总的指导思想是:<strong>信息充分但紧致</strong>。下面进入运行时的动态检索。
|
|
|
|
|
|
|
+总的指导思想是:<strong>信息充分但紧致</strong>。如图9.2所示,是进入运行时的动态检索。
|
|
|
|
|
|
|
|
<div align="center">
|
|
<div align="center">
|
|
|
- <img src="https://www.anthropic.com/_next/image?url=https%3A%2F%2Fwww-cdn.anthropic.com%2Fimages%2F4zrzovbb%2Fwebsite%2F0442fe138158e84ffce92bed1624dd09f37ac46f-2292x1288.png&w=3840&q=75" alt="Calibrating the system prompt" width="90%"/>
|
|
|
|
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/Hello-Agents/main/docs/images/9-figures/9-2.webp" alt="" width="85%"/>
|
|
|
<p>图 9.2 Calibrating the system prompt</p>
|
|
<p>图 9.2 Calibrating the system prompt</p>
|
|
|
-
|
|
|
|
|
</div>
|
|
</div>
|
|
|
|
|
|
|
|
|
|
+
|
|
|
### 9.2.2 上下文检索与智能体式搜索
|
|
### 9.2.2 上下文检索与智能体式搜索
|
|
|
|
|
|
|
|
一个简洁的定义:<strong>智能体 = 在循环中自主调用工具的 LLM</strong>。随着底层模型能力增强,智能体的自治水平便可提升:更能独立探索复杂问题空间,并从错误中恢复。
|
|
一个简洁的定义:<strong>智能体 = 在循环中自主调用工具的 LLM</strong>。随着底层模型能力增强,智能体的自治水平便可提升:更能独立探索复杂问题空间,并从错误中恢复。
|
|
@@ -106,15 +123,15 @@
|
|
|
|
|
|
|
|
## 9.3 在 Hello-Agents 中的实践:ContextBuilder
|
|
## 9.3 在 Hello-Agents 中的实践:ContextBuilder
|
|
|
|
|
|
|
|
-本节将详细介绍 HelloAgents 框架中的上下文工程实践。我们将从设计动机、核心数据结构、实现细节到完整案例,逐步展示如何构建一个生产级的上下文管理系统。ContextBuilder 的设计理念是"简单高效",去除不必要的复杂性,统一以"相关性+新近性"的分数进行选择,符合 Agent 模块化与可维护性的工程取向。
|
|
|
|
|
|
|
+本节将详细介绍 HelloAgents 框架中的上下文工程实践。我们将从设计动机、核心数据结构、实现细节到完整案例,逐步展示如何构建一个生产级的上下文管理系统。ContextBuilder 的设计理念是"简单高效",去除不必要的复杂性,统一以"相关性+新近性"的分数进行选择,符合 Agent 模块化与可维护性的工程取向。
|
|
|
|
|
|
|
|
### 9.3.1 设计动机与目标
|
|
### 9.3.1 设计动机与目标
|
|
|
|
|
|
|
|
-在构建 ContextBuilder 之前,我们首先需要明确其设计目标和核心价值。一个优秀的上下文管理系统应该解决以下几个关键问题:
|
|
|
|
|
|
|
+在构建 ContextBuilder 之前,我们首先需要明确其设计目标和核心价值。一个优秀的上下文管理系统应该解决以下几个关键问题:
|
|
|
|
|
|
|
|
-1. <strong>统一入口</strong>:将"获取(Gather)- 选择(Select)- 结构化(Structure)- 压缩(Compress)"抽象为可复用流水线,减少在 Agent 实现中的重复模板代码。这种统一的接口设计让开发者无需在每个 Agent 中重复编写上下文管理逻辑。
|
|
|
|
|
|
|
+1. <strong>统一入口</strong>:将"获取(Gather)- 选择(Select)- 结构化(Structure)- 压缩(Compress)"抽象为可复用流水线,减少在 Agent 实现中的重复模板代码。这种统一的接口设计让开发者无需在每个 Agent 中重复编写上下文管理逻辑。
|
|
|
|
|
|
|
|
-2. <strong>稳定形态</strong>:输出固定骨架的上下文模板,便于调试、A/B 测试与评估。我们采用了分区组织的模板结构:
|
|
|
|
|
|
|
+2. <strong>稳定形态</strong>:输出固定骨架的上下文模板,便于调试、A/B 测试与评估。我们采用了分区组织的模板结构:
|
|
|
- `[Role & Policies]`:明确 Agent 的角色定位和行为准则
|
|
- `[Role & Policies]`:明确 Agent 的角色定位和行为准则
|
|
|
- `[Task]`:当前需要完成的具体任务
|
|
- `[Task]`:当前需要完成的具体任务
|
|
|
- `[State]`:Agent 的当前状态和上下文信息
|
|
- `[State]`:Agent 的当前状态和上下文信息
|
|
@@ -122,13 +139,13 @@
|
|
|
- `[Context]`:历史对话和相关记忆
|
|
- `[Context]`:历史对话和相关记忆
|
|
|
- `[Output]`:期望的输出格式和要求
|
|
- `[Output]`:期望的输出格式和要求
|
|
|
|
|
|
|
|
-3. <strong>预算守护</strong>:在 token 预算内尽量保留高价值信息,对超限上下文提供兜底压缩策略。这确保了即使在信息量巨大的场景下,系统也能稳定运行。
|
|
|
|
|
|
|
+3. <strong>预算守护</strong>:在 token 预算内尽量保留高价值信息,对超限上下文提供兜底压缩策略。这确保了即使在信息量巨大的场景下,系统也能稳定运行。
|
|
|
|
|
|
|
|
-4. <strong>最小规则</strong>:不引入来源/优先级等分类维度,避免复杂度增长。实践表明,基于相关性和新近性的简单评分机制,在大多数场景下已经足够有效。
|
|
|
|
|
|
|
+4. <strong>最小规则</strong>:不引入来源/优先级等分类维度,避免复杂度增长。实践表明,基于相关性和新近性的简单评分机制,在大多数场景下已经足够有效。
|
|
|
|
|
|
|
|
### 9.3.2 核心数据结构
|
|
### 9.3.2 核心数据结构
|
|
|
|
|
|
|
|
-ContextBuilder 的实现依赖两个核心数据结构,它们定义了系统的配置和信息单元。
|
|
|
|
|
|
|
+ContextBuilder 的实现依赖两个核心数据结构,它们定义了系统的配置和信息单元。
|
|
|
|
|
|
|
|
(1)ContextPacket:候选信息包
|
|
(1)ContextPacket:候选信息包
|
|
|
|
|
|
|
@@ -162,7 +179,7 @@ class ContextPacket:
|
|
|
self.relevance_score = max(0.0, min(1.0, self.relevance_score))
|
|
self.relevance_score = max(0.0, min(1.0, self.relevance_score))
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-`ContextPacket` 是系统中信息的基本单元。每个候选信息都会被封装为一个 ContextPacket,包含内容、时间戳、token 数量和相关性分数等核心属性。这种统一的数据结构简化了后续的选择和排序逻辑。
|
|
|
|
|
|
|
+`ContextPacket` 是系统中信息的基本单元。每个候选信息都会被封装为一个 ContextPacket,包含内容、时间戳、token 数量和相关性分数等核心属性。这种统一的数据结构简化了后续的选择和排序逻辑。
|
|
|
|
|
|
|
|
(2)ContextConfig:配置管理
|
|
(2)ContextConfig:配置管理
|
|
|
|
|
|
|
@@ -194,11 +211,11 @@ class ContextConfig:
|
|
|
"recency_weight + relevance_weight 必须等于 1.0"
|
|
"recency_weight + relevance_weight 必须等于 1.0"
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-`ContextConfig` 封装了所有可配置的参数,使得系统行为可以灵活调整。特别值得注意的是 `reserve_ratio` 参数,它确保系统指令等关键信息始终有足够的空间,不会被其他信息挤占。
|
|
|
|
|
|
|
+`ContextConfig` 封装了所有可配置的参数,使得系统行为可以灵活调整。特别值得注意的是 `reserve_ratio` 参数,它确保系统指令等关键信息始终有足够的空间,不会被其他信息挤占。
|
|
|
|
|
|
|
|
### 9.3.3 GSSC 流水线详解
|
|
### 9.3.3 GSSC 流水线详解
|
|
|
|
|
|
|
|
-ContextBuilder 的核心是 GSSC(Gather-Select-Structure-Compress)流水线,它将上下文构建过程分解为四个清晰的阶段。让我们深入了解每个阶段的实现细节。
|
|
|
|
|
|
|
+ContextBuilder 的核心是 GSSC(Gather-Select-Structure-Compress)流水线,它将上下文构建过程分解为四个清晰的阶段。让我们深入了解每个阶段的实现细节。
|
|
|
|
|
|
|
|
(1)Gather:多源信息汇集
|
|
(1)Gather:多源信息汇集
|
|
|
|
|
|
|
@@ -287,13 +304,13 @@ def _gather(
|
|
|
|
|
|
|
|
这个实现展示了几个重要的设计考虑:
|
|
这个实现展示了几个重要的设计考虑:
|
|
|
|
|
|
|
|
-- <strong>容错机制</strong>:每个外部数据源的调用都被 try-except 包裹,确保单个源的失败不会影响整体流程
|
|
|
|
|
-- <strong>优先级处理</strong>:系统指令被标记为高优先级,确保始终被保留
|
|
|
|
|
-- <strong>历史限制</strong>:对话历史只保留最近的几条,避免上下文窗口被历史信息占据
|
|
|
|
|
|
|
+- <strong>容错机制</strong>:每个外部数据源的调用都被 try-except 包裹,确保单个源的失败不会影响整体流程
|
|
|
|
|
+- <strong>优先级处理</strong>:系统指令被标记为高优先级,确保始终被保留
|
|
|
|
|
+- <strong>历史限制</strong>:对话历史只保留最近的几条,避免上下文窗口被历史信息占据
|
|
|
|
|
|
|
|
(2)Select:智能信息选择
|
|
(2)Select:智能信息选择
|
|
|
|
|
|
|
|
-第二阶段是根据相关性和新近性对候选信息进行评分和选择。这是整个流水线的核心,直接决定了最终上下文的质量。
|
|
|
|
|
|
|
+第二阶段是根据相关性和新近性对候选信息进行评分和选择。这是整个流水线的核心,直接决定了最终上下文的质量。
|
|
|
|
|
|
|
|
```python
|
|
```python
|
|
|
def _select(
|
|
def _select(
|
|
@@ -412,8 +429,8 @@ def _calculate_recency(self, timestamp: datetime) -> float:
|
|
|
|
|
|
|
|
选择阶段的核心算法体现了几个重要的工程考量:
|
|
选择阶段的核心算法体现了几个重要的工程考量:
|
|
|
|
|
|
|
|
-- <strong>评分机制</strong>:采用相关性和新近性的加权组合,权重可配置
|
|
|
|
|
-- <strong>贪心算法</strong>:按分数从高到低填充,确保在有限预算内选择最有价值的信息
|
|
|
|
|
|
|
+- <strong>评分机制</strong>:采用相关性和新近性的加权组合,权重可配置
|
|
|
|
|
+- <strong>贪心算法</strong>:按分数从高到低填充,确保在有限预算内选择最有价值的信息
|
|
|
- <strong>过滤机制</strong>:通过 `min_relevance` 参数过滤低质量信息
|
|
- <strong>过滤机制</strong>:通过 `min_relevance` 参数过滤低质量信息
|
|
|
|
|
|
|
|
(3)Structure:结构化输出
|
|
(3)Structure:结构化输出
|
|
@@ -470,10 +487,10 @@ def _structure(self, selected_packets: List[ContextPacket], user_query: str) ->
|
|
|
return "\n\n".join(sections)
|
|
return "\n\n".join(sections)
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-结构化阶段将散乱的信息包组织成清晰的分区,这种设计有几个优势:
|
|
|
|
|
|
|
+结构化阶段将散乱的信息包组织成清晰的分区,这种设计有几个优势:
|
|
|
|
|
|
|
|
- <strong>可读性</strong>:清晰的分区让人类和模型都更容易理解上下文结构
|
|
- <strong>可读性</strong>:清晰的分区让人类和模型都更容易理解上下文结构
|
|
|
-- <strong>可调试性</strong>:问题定位更容易,可以快速识别哪个区域的信息有问题
|
|
|
|
|
|
|
+- <strong>可调试性</strong>:问题定位更容易,可以快速识别哪个区域的信息有问题
|
|
|
- <strong>可扩展性</strong>:添加新的信息源只需要创建新的分区
|
|
- <strong>可扩展性</strong>:添加新的信息源只需要创建新的分区
|
|
|
|
|
|
|
|
(4)Compress:兜底压缩
|
|
(4)Compress:兜底压缩
|
|
@@ -559,11 +576,11 @@ def _count_tokens(self, text: str) -> int:
|
|
|
return int(chinese_chars + english_words * 1.3)
|
|
return int(chinese_chars + english_words * 1.3)
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-压缩阶段的设计体现了"保持结构完整性"的原则,即使在 token 预算紧张的情况下,也要尽量保留每个分区的关键信息。
|
|
|
|
|
|
|
+压缩阶段的设计体现了"保持结构完整性"的原则,即使在 token 预算紧张的情况下,也要尽量保留每个分区的关键信息。
|
|
|
|
|
|
|
|
### 9.3.4 完整使用示例
|
|
### 9.3.4 完整使用示例
|
|
|
|
|
|
|
|
-现在让我们通过一个完整的示例,展示如何在实际项目中使用 ContextBuilder。
|
|
|
|
|
|
|
+现在让我们通过一个完整的示例,展示如何在实际项目中使用 ContextBuilder。
|
|
|
|
|
|
|
|
(1)基础使用
|
|
(1)基础使用
|
|
|
|
|
|
|
@@ -630,7 +647,7 @@ print("=" * 80)
|
|
|
|
|
|
|
|
(2)运行效果展示
|
|
(2)运行效果展示
|
|
|
|
|
|
|
|
-运行上述代码后,您将看到如下结构化的上下文输出:
|
|
|
|
|
|
|
+运行上述代码后,您将看到如下结构化的上下文输出:
|
|
|
|
|
|
|
|
```
|
|
```
|
|
|
================================================================================
|
|
================================================================================
|
|
@@ -668,12 +685,12 @@ assistant: 不错的选择!Pandas在数据处理方面非常强大。接下来
|
|
|
- <strong>[Role & Policies]</strong>:明确了 AI 的角色和回答要求
|
|
- <strong>[Role & Policies]</strong>:明确了 AI 的角色和回答要求
|
|
|
- <strong>[Task]</strong>:清晰地表达了用户的问题
|
|
- <strong>[Task]</strong>:清晰地表达了用户的问题
|
|
|
- <strong>[Evidence]</strong>:从 RAG 系统检索的相关知识
|
|
- <strong>[Evidence]</strong>:从 RAG 系统检索的相关知识
|
|
|
-- <strong>[Context]</strong>:对话历史和相关记忆,提供了充分的背景信息
|
|
|
|
|
|
|
+- <strong>[Context]</strong>:对话历史和相关记忆,提供了充分的背景信息
|
|
|
- <strong>[Output]</strong>:指导 LLM 如何组织回答
|
|
- <strong>[Output]</strong>:指导 LLM 如何组织回答
|
|
|
|
|
|
|
|
(3)与 Agent 集成
|
|
(3)与 Agent 集成
|
|
|
|
|
|
|
|
-最后,让我们展示如何将 ContextBuilder 集成到 Agent 中:
|
|
|
|
|
|
|
+最后,让我们展示如何将 ContextBuilder 集成到 Agent 中:
|
|
|
|
|
|
|
|
```python
|
|
```python
|
|
|
from hello_agents import SimpleAgent, HelloAgentsLLM, ToolRegistry
|
|
from hello_agents import SimpleAgent, HelloAgentsLLM, ToolRegistry
|
|
@@ -744,42 +761,42 @@ response = agent.run("如何优化Pandas的内存占用?")
|
|
|
print(response)
|
|
print(response)
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-通过这种方式,ContextBuilder 成为了 Agent 的"上下文管理大脑",自动处理信息的收集、筛选和组织,让 Agent 始终能够在最优的上下文下进行推理和生成。
|
|
|
|
|
|
|
+通过这种方式,ContextBuilder 成为了 Agent 的"上下文管理大脑",自动处理信息的收集、筛选和组织,让 Agent 始终能够在最优的上下文下进行推理和生成。
|
|
|
|
|
|
|
|
### 9.3.5 最佳实践与优化建议
|
|
### 9.3.5 最佳实践与优化建议
|
|
|
|
|
|
|
|
-在实际应用 ContextBuilder 时,以下几点最佳实践值得注意:
|
|
|
|
|
|
|
+在实际应用 ContextBuilder 时,以下几点最佳实践值得注意:
|
|
|
|
|
|
|
|
-1. <strong>动态调整 token 预算</strong>:根据任务复杂度动态调整 `max_tokens`,简单任务使用较小预算,复杂任务增加预算。
|
|
|
|
|
|
|
+1. <strong>动态调整 token 预算</strong>:根据任务复杂度动态调整 `max_tokens`,简单任务使用较小预算,复杂任务增加预算。
|
|
|
|
|
|
|
|
-2. <strong>相关性计算优化</strong>:在生产环境中,将简单的关键词重叠替换为向量相似度计算,提升检索质量。
|
|
|
|
|
|
|
+2. <strong>相关性计算优化</strong>:在生产环境中,将简单的关键词重叠替换为向量相似度计算,提升检索质量。
|
|
|
|
|
|
|
|
-3. <strong>缓存机制</strong>:对于不变的系统指令和知识库内容,可以实现缓存机制,避免重复计算。
|
|
|
|
|
|
|
+3. <strong>缓存机制</strong>:对于不变的系统指令和知识库内容,可以实现缓存机制,避免重复计算。
|
|
|
|
|
|
|
|
-4. <strong>监控与日志</strong>:记录每次上下文构建的统计信息(选中信息数量、token 使用率等),便于后续优化。
|
|
|
|
|
|
|
+4. <strong>监控与日志</strong>:记录每次上下文构建的统计信息(选中信息数量、token 使用率等),便于后续优化。
|
|
|
|
|
|
|
|
-5. <strong>A/B 测试</strong>:对于关键参数(如相关性权重、新近性权重),通过 A/B 测试找到最优配置。
|
|
|
|
|
|
|
+5. <strong>A/B 测试</strong>:对于关键参数(如相关性权重、新近性权重),通过 A/B 测试找到最优配置。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## 9.4 NoteTool:结构化笔记
|
|
## 9.4 NoteTool:结构化笔记
|
|
|
|
|
|
|
|
-NoteTool 是为"长时程任务"提供的结构化外部记忆组件。它以 Markdown 文件作为载体,头部使用 YAML 前置元数据记录关键信息,正文用于记录状态、结论、阻塞与行动项等内容。这种设计结合了人类可读性、版本控制友好性和易于回注上下文的特性,是构建长时程智能体的重要工具。
|
|
|
|
|
|
|
+NoteTool 是为"长时程任务"提供的结构化外部记忆组件。它以 Markdown 文件作为载体,头部使用 YAML 前置元数据记录关键信息,正文用于记录状态、结论、阻塞与行动项等内容。这种设计结合了人类可读性、版本控制友好性和易于回注上下文的特性,是构建长时程智能体的重要工具。
|
|
|
|
|
|
|
|
### 9.4.1 设计理念与应用场景
|
|
### 9.4.1 设计理念与应用场景
|
|
|
|
|
|
|
|
-在深入实现细节之前,让我们首先理解 NoteTool 的设计理念和典型应用场景。
|
|
|
|
|
|
|
+在深入实现细节之前,让我们首先理解 NoteTool 的设计理念和典型应用场景。
|
|
|
|
|
|
|
|
(1)为什么需要 NoteTool?
|
|
(1)为什么需要 NoteTool?
|
|
|
|
|
|
|
|
-在第八章中,我们介绍了 MemoryTool,它提供了强大的记忆管理能力。然而,MemoryTool 主要关注<strong>对话式记忆</strong>——短期工作记忆、情景记忆和语义记忆。对于需要长期追踪、结构化管理的<strong>项目式任务</strong>,我们需要一种更轻量、更人类友好的记录方式。
|
|
|
|
|
|
|
+在第八章中,我们介绍了 MemoryTool,它提供了强大的记忆管理能力。然而,MemoryTool 主要关注<strong>对话式记忆</strong>——短期工作记忆、情景记忆和语义记忆。对于需要长期追踪、结构化管理的<strong>项目式任务</strong>,我们需要一种更轻量、更人类友好的记录方式。
|
|
|
|
|
|
|
|
-NoteTool 填补了这个gap,它提供了:
|
|
|
|
|
|
|
+NoteTool 填补了这个gap,它提供了:
|
|
|
|
|
|
|
|
-- <strong>结构化记录</strong>:使用 Markdown + YAML 格式,既适合机器解析,也方便人类阅读和编辑
|
|
|
|
|
-- <strong>版本友好</strong>:纯文本格式,天然支持 Git 等版本控制系统
|
|
|
|
|
-- <strong>低开销</strong>:无需复杂的数据库操作,适合轻量级的状态追踪
|
|
|
|
|
-- <strong>灵活分类</strong>:通过 `type` 和 `tags` 灵活组织笔记,支持多维度检索
|
|
|
|
|
|
|
+- <strong>结构化记录</strong>:使用 Markdown + YAML 格式,既适合机器解析,也方便人类阅读和编辑
|
|
|
|
|
+- <strong>版本友好</strong>:纯文本格式,天然支持 Git 等版本控制系统
|
|
|
|
|
+- <strong>低开销</strong>:无需复杂的数据库操作,适合轻量级的状态追踪
|
|
|
|
|
+- <strong>灵活分类</strong>:通过 `type` 和 `tags` 灵活组织笔记,支持多维度检索
|
|
|
|
|
|
|
|
(2)典型应用场景
|
|
(2)典型应用场景
|
|
|
|
|
|
|
@@ -787,7 +804,7 @@ NoteTool 特别适合以下场景:
|
|
|
|
|
|
|
|
<strong>场景1:长期项目追踪</strong>
|
|
<strong>场景1:长期项目追踪</strong>
|
|
|
|
|
|
|
|
-想象一个智能体正在协助完成一个大型代码库的重构任务,这可能需要几天甚至几周。NoteTool 可以记录:
|
|
|
|
|
|
|
+想象一个智能体正在协助完成一个大型代码库的重构任务,这可能需要几天甚至几周。NoteTool 可以记录:
|
|
|
|
|
|
|
|
- `task_state`:当前阶段的任务状态和进度
|
|
- `task_state`:当前阶段的任务状态和进度
|
|
|
- `conclusion`:每个阶段结束后的关键结论
|
|
- `conclusion`:每个阶段结束后的关键结论
|
|
@@ -816,7 +833,7 @@ notes.run({
|
|
|
|
|
|
|
|
<strong>场景2:研究任务管理</strong>
|
|
<strong>场景2:研究任务管理</strong>
|
|
|
|
|
|
|
|
-一个智能研究助手在进行文献综述时,可以使用 NoteTool 记录:
|
|
|
|
|
|
|
+一个智能研究助手在进行文献综述时,可以使用 NoteTool 记录:
|
|
|
|
|
|
|
|
- 每篇论文的核心观点(`conclusion`)
|
|
- 每篇论文的核心观点(`conclusion`)
|
|
|
- 待深入调研的主题(`action`)
|
|
- 待深入调研的主题(`action`)
|
|
@@ -824,7 +841,7 @@ notes.run({
|
|
|
|
|
|
|
|
<strong>场景3:与 ContextBuilder 配合</strong>
|
|
<strong>场景3:与 ContextBuilder 配合</strong>
|
|
|
|
|
|
|
|
-在每轮对话前,Agent 可以通过 `search` 或 `list` 操作检索相关笔记,并将其注入到上下文中:
|
|
|
|
|
|
|
+在每轮对话前,Agent 可以通过 `search` 或 `list` 操作检索相关笔记,并将其注入到上下文中:
|
|
|
|
|
|
|
|
```python
|
|
```python
|
|
|
# 在 Agent 的 run 方法中
|
|
# 在 Agent 的 run 方法中
|
|
@@ -857,11 +874,11 @@ def run(self, user_input: str) -> str:
|
|
|
|
|
|
|
|
### 9.4.2 存储格式详解
|
|
### 9.4.2 存储格式详解
|
|
|
|
|
|
|
|
-NoteTool 采用了 Markdown + YAML 的混合格式,这种设计兼顾了结构化和可读性。
|
|
|
|
|
|
|
+NoteTool 采用了 Markdown + YAML 的混合格式,这种设计兼顾了结构化和可读性。
|
|
|
|
|
|
|
|
(1)笔记文件格式
|
|
(1)笔记文件格式
|
|
|
|
|
|
|
|
-每个笔记都是一个独立的 `.md` 文件,格式如下:
|
|
|
|
|
|
|
+每个笔记都是一个独立的 `.md` 文件,格式如下:
|
|
|
|
|
|
|
|
```markdown
|
|
```markdown
|
|
|
---
|
|
---
|
|
@@ -897,13 +914,13 @@ updated_at: 2025-01-19T15:30:00
|
|
|
|
|
|
|
|
这种格式的优势:
|
|
这种格式的优势:
|
|
|
|
|
|
|
|
-- <strong>YAML 元数据</strong>:机器可解析,支持精确的字段提取和检索
|
|
|
|
|
-- <strong>Markdown 正文</strong>:人类可读,支持丰富的格式化(标题、列表、代码块等)
|
|
|
|
|
-- <strong>文件名即 ID</strong>:简化管理,每个笔记的文件名就是其唯一标识
|
|
|
|
|
|
|
+- <strong>YAML 元数据</strong>:机器可解析,支持精确的字段提取和检索
|
|
|
|
|
+- <strong>Markdown 正文</strong>:人类可读,支持丰富的格式化(标题、列表、代码块等)
|
|
|
|
|
+- <strong>文件名即 ID</strong>:简化管理,每个笔记的文件名就是其唯一标识
|
|
|
|
|
|
|
|
(2)索引文件
|
|
(2)索引文件
|
|
|
|
|
|
|
|
-NoteTool 维护一个 `notes_index.json` 文件,用于快速检索和管理笔记:
|
|
|
|
|
|
|
+NoteTool 维护一个 `notes_index.json` 文件,用于快速检索和管理笔记:
|
|
|
|
|
|
|
|
```json
|
|
```json
|
|
|
{
|
|
{
|
|
@@ -921,13 +938,13 @@ NoteTool 维护一个 `notes_index.json` 文件,用于快速检索和管理笔
|
|
|
|
|
|
|
|
这个索引文件的作用:
|
|
这个索引文件的作用:
|
|
|
|
|
|
|
|
-- <strong>快速检索</strong>:无需打开每个文件,直接从索引中查找
|
|
|
|
|
|
|
+- <strong>快速检索</strong>:无需打开每个文件,直接从索引中查找
|
|
|
- <strong>元数据管理</strong>:集中管理所有笔记的元数据
|
|
- <strong>元数据管理</strong>:集中管理所有笔记的元数据
|
|
|
- <strong>完整性校验</strong>:可以检测文件缺失或损坏
|
|
- <strong>完整性校验</strong>:可以检测文件缺失或损坏
|
|
|
|
|
|
|
|
### 9.4.3 核心操作详解
|
|
### 9.4.3 核心操作详解
|
|
|
|
|
|
|
|
-NoteTool 提供了七个核心操作,覆盖了笔记的完整生命周期管理。
|
|
|
|
|
|
|
+NoteTool 提供了七个核心操作,覆盖了笔记的完整生命周期管理。
|
|
|
|
|
|
|
|
(1)create:创建笔记
|
|
(1)create:创建笔记
|
|
|
|
|
|
|
@@ -1296,11 +1313,11 @@ NoteTool 的真正威力在于与 ContextBuilder 的配合使用。让我们通
|
|
|
|
|
|
|
|
(1)场景设定
|
|
(1)场景设定
|
|
|
|
|
|
|
|
-假设我们正在构建一个长期项目助手,它需要:
|
|
|
|
|
|
|
+假设我们正在构建一个长期项目助手,它需要:
|
|
|
|
|
|
|
|
1. 记录项目的阶段性进展
|
|
1. 记录项目的阶段性进展
|
|
|
2. 追踪待解决的问题
|
|
2. 追踪待解决的问题
|
|
|
-3. 在每次对话时,自动回顾相关笔记
|
|
|
|
|
|
|
+3. 在每次对话时,自动回顾相关笔记
|
|
|
4. 基于历史笔记提供连贯的建议
|
|
4. 基于历史笔记提供连贯的建议
|
|
|
|
|
|
|
|
(2)实现示例
|
|
(2)实现示例
|
|
@@ -1530,29 +1547,29 @@ print(summary)
|
|
|
|
|
|
|
|
### 9.4.5 最佳实践
|
|
### 9.4.5 最佳实践
|
|
|
|
|
|
|
|
-在实际使用 NoteTool 时,以下最佳实践能帮助您构建更强大的长时程智能体:
|
|
|
|
|
|
|
+在实际使用 NoteTool 时,以下最佳实践能帮助您构建更强大的长时程智能体:
|
|
|
|
|
|
|
|
1. <strong>合理的笔记分类</strong>:
|
|
1. <strong>合理的笔记分类</strong>:
|
|
|
- `task_state`:记录阶段性进展和状态
|
|
- `task_state`:记录阶段性进展和状态
|
|
|
- `conclusion`:记录重要的结论和发现
|
|
- `conclusion`:记录重要的结论和发现
|
|
|
- - `blocker`:记录阻塞问题,优先级最高
|
|
|
|
|
|
|
+ - `blocker`:记录阻塞问题,优先级最高
|
|
|
- `action`:记录下一步行动计划
|
|
- `action`:记录下一步行动计划
|
|
|
- `reference`:记录重要的参考资料
|
|
- `reference`:记录重要的参考资料
|
|
|
|
|
|
|
|
2. <strong>定期清理和归档</strong>:
|
|
2. <strong>定期清理和归档</strong>:
|
|
|
- - 对于已解决的 blocker,更新为 conclusion
|
|
|
|
|
- - 对于过时的 action,及时删除或更新
|
|
|
|
|
- - 使用 tags 进行版本管理,如 `["v1.0", "completed"]`
|
|
|
|
|
|
|
+ - 对于已解决的 blocker,更新为 conclusion
|
|
|
|
|
+ - 对于过时的 action,及时删除或更新
|
|
|
|
|
+ - 使用 tags 进行版本管理,如 `["v1.0", "completed"]`
|
|
|
|
|
|
|
|
3. <strong>与 ContextBuilder 的配合</strong>:
|
|
3. <strong>与 ContextBuilder 的配合</strong>:
|
|
|
- 在每轮对话前检索相关笔记
|
|
- 在每轮对话前检索相关笔记
|
|
|
- 根据笔记类型设置不同的相关性分数(blocker > action > conclusion)
|
|
- 根据笔记类型设置不同的相关性分数(blocker > action > conclusion)
|
|
|
- - 限制笔记数量,避免上下文过载
|
|
|
|
|
|
|
+ - 限制笔记数量,避免上下文过载
|
|
|
|
|
|
|
|
4. <strong>人机协作</strong>:
|
|
4. <strong>人机协作</strong>:
|
|
|
- - 笔记是人类可读的 Markdown 格式,支持手动编辑
|
|
|
|
|
- - 使用 Git 进行版本控制,追踪笔记的演化
|
|
|
|
|
- - 在关键阶段,人工审核 Agent 生成的笔记
|
|
|
|
|
|
|
+ - 笔记是人类可读的 Markdown 格式,支持手动编辑
|
|
|
|
|
+ - 使用 Git 进行版本控制,追踪笔记的演化
|
|
|
|
|
+ - 在关键阶段,人工审核 Agent 生成的笔记
|
|
|
|
|
|
|
|
5. <strong>自动化工作流</strong>:
|
|
5. <strong>自动化工作流</strong>:
|
|
|
- 定期生成笔记摘要报告
|
|
- 定期生成笔记摘要报告
|
|
@@ -1561,15 +1578,15 @@ print(summary)
|
|
|
|
|
|
|
|
## 9.5 TerminalTool:即时文件系统访问
|
|
## 9.5 TerminalTool:即时文件系统访问
|
|
|
|
|
|
|
|
-在前面的章节中,我们介绍了 MemoryTool 和 RAGTool,它们分别提供了对话记忆和知识检索能力。然而,在许多实际场景中,智能体需要<strong>即时访问和探索文件系统</strong>——查看日志文件、分析代码库结构、检索配置文件等。这就是 TerminalTool 的用武之地。
|
|
|
|
|
|
|
+在前面的章节中,我们介绍了 MemoryTool 和 RAGTool,它们分别提供了对话记忆和知识检索能力。然而,在许多实际场景中,智能体需要<strong>即时访问和探索文件系统</strong>——查看日志文件、分析代码库结构、检索配置文件等。这就是 TerminalTool 的用武之地。
|
|
|
|
|
|
|
|
-TerminalTool 为智能体提供了<strong>安全的命令行执行能力</strong>,支持常用的文件系统和文本处理命令,同时通过多层安全机制确保系统安全。这种设计实现了 9.2.2 节提到的"即时(Just-in-time, JIT)上下文"理念——智能体不需要预先加载所有文件,而是按需探索和检索。
|
|
|
|
|
|
|
+TerminalTool 为智能体提供了<strong>安全的命令行执行能力</strong>,支持常用的文件系统和文本处理命令,同时通过多层安全机制确保系统安全。这种设计实现了 9.2.2 节提到的"即时(Just-in-time, JIT)上下文"理念——智能体不需要预先加载所有文件,而是按需探索和检索。
|
|
|
|
|
|
|
|
### 9.5.1 设计理念与安全机制
|
|
### 9.5.1 设计理念与安全机制
|
|
|
|
|
|
|
|
(1)为什么需要 TerminalTool?
|
|
(1)为什么需要 TerminalTool?
|
|
|
|
|
|
|
|
-在构建长程智能体时,我们经常遇到以下场景:
|
|
|
|
|
|
|
+在构建长程智能体时,我们经常遇到以下场景:
|
|
|
|
|
|
|
|
<strong>场景1:代码库探索</strong>
|
|
<strong>场景1:代码库探索</strong>
|
|
|
|
|
|
|
@@ -1615,7 +1632,7 @@ terminal.run({"command": "wc -l data/*.csv"})
|
|
|
terminal.run({"command": "head -n 1 data/sales.csv | tr ',' '\n'"})
|
|
terminal.run({"command": "head -n 1 data/sales.csv | tr ',' '\n'"})
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-这些场景的共同特点是:<strong>需要实时、轻量级的文件系统访问,而不是预先索引和向量化</strong>。TerminalTool 正是为这种"探索式"工作流设计的。
|
|
|
|
|
|
|
+这些场景的共同特点是:<strong>需要实时、轻量级的文件系统访问,而不是预先索引和向量化</strong>。TerminalTool 正是为这种"探索式"工作流设计的。
|
|
|
|
|
|
|
|
(2)安全机制详解
|
|
(2)安全机制详解
|
|
|
|
|
|
|
@@ -1623,7 +1640,7 @@ terminal.run({"command": "head -n 1 data/sales.csv | tr ',' '\n'"})
|
|
|
|
|
|
|
|
<strong>第一层:命令白名单</strong>
|
|
<strong>第一层:命令白名单</strong>
|
|
|
|
|
|
|
|
-只允许安全的只读命令,完全禁止任何可能修改系统的操作:
|
|
|
|
|
|
|
+只允许安全的只读命令,完全禁止任何可能修改系统的操作:
|
|
|
|
|
|
|
|
```python
|
|
```python
|
|
|
ALLOWED_COMMANDS = {
|
|
ALLOWED_COMMANDS = {
|
|
@@ -1644,7 +1661,7 @@ ALLOWED_COMMANDS = {
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-如果智能体尝试执行白名单外的命令,会立即被拒绝:
|
|
|
|
|
|
|
+如果智能体尝试执行白名单外的命令,会立即被拒绝:
|
|
|
|
|
|
|
|
```python
|
|
```python
|
|
|
terminal.run({"command": "rm -rf /"})
|
|
terminal.run({"command": "rm -rf /"})
|
|
@@ -1654,7 +1671,7 @@ terminal.run({"command": "rm -rf /"})
|
|
|
|
|
|
|
|
<strong>第二层:工作目录限制(沙箱)</strong>
|
|
<strong>第二层:工作目录限制(沙箱)</strong>
|
|
|
|
|
|
|
|
-TerminalTool 只能访问指定的工作目录及其子目录,无法访问系统其他部分:
|
|
|
|
|
|
|
+TerminalTool 只能访问指定的工作目录及其子目录,无法访问系统其他部分:
|
|
|
|
|
|
|
|
```python
|
|
```python
|
|
|
# 初始化时指定工作目录
|
|
# 初始化时指定工作目录
|
|
@@ -1670,11 +1687,11 @@ terminal.run({"command": "cat /etc/passwd"}) # ❌ 不允许访问工作目录
|
|
|
terminal.run({"command": "cd ../../../etc"}) # ❌ 不允许访问工作目录外的路径
|
|
terminal.run({"command": "cd ../../../etc"}) # ❌ 不允许访问工作目录外的路径
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-这种沙箱机制确保了即使智能体的行为出现异常,也无法影响系统其他部分。
|
|
|
|
|
|
|
+这种沙箱机制确保了即使智能体的行为出现异常,也无法影响系统其他部分。
|
|
|
|
|
|
|
|
<strong>第三层:超时控制</strong>
|
|
<strong>第三层:超时控制</strong>
|
|
|
|
|
|
|
|
-每个命令都有执行时间限制,防止无限循环或资源耗尽:
|
|
|
|
|
|
|
+每个命令都有执行时间限制,防止无限循环或资源耗尽:
|
|
|
|
|
|
|
|
```python
|
|
```python
|
|
|
terminal = TerminalTool(
|
|
terminal = TerminalTool(
|
|
@@ -1689,7 +1706,7 @@ terminal.run({"command": "find / -name '*.log'"})
|
|
|
|
|
|
|
|
<strong>第四层:输出大小限制</strong>
|
|
<strong>第四层:输出大小限制</strong>
|
|
|
|
|
|
|
|
-限制命令输出的大小,防止内存溢出:
|
|
|
|
|
|
|
+限制命令输出的大小,防止内存溢出:
|
|
|
|
|
|
|
|
```python
|
|
```python
|
|
|
terminal = TerminalTool(
|
|
terminal = TerminalTool(
|
|
@@ -1703,7 +1720,7 @@ terminal.run({"command": "cat huge_file.log"})
|
|
|
# ⚠️ 输出被截断(超过 10485760 字节)
|
|
# ⚠️ 输出被截断(超过 10485760 字节)
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-通过这四层安全机制,TerminalTool 在提供强大能力的同时,最大程度地保证了系统安全。
|
|
|
|
|
|
|
+通过这四层安全机制,TerminalTool 在提供强大能力的同时,最大程度地保证了系统安全。
|
|
|
|
|
|
|
|
### 9.5.2 核心功能详解
|
|
### 9.5.2 核心功能详解
|
|
|
|
|
|
|
@@ -1753,9 +1770,9 @@ def _execute_command(self, command: str) -> str:
|
|
|
这个实现的关键点:
|
|
这个实现的关键点:
|
|
|
|
|
|
|
|
- <strong>当前目录感知</strong>:使用 `cwd` 参数在正确的目录下执行命令
|
|
- <strong>当前目录感知</strong>:使用 `cwd` 参数在正确的目录下执行命令
|
|
|
-- <strong>错误处理</strong>:捕获并合并标准错误,提供完整的诊断信息
|
|
|
|
|
|
|
+- <strong>错误处理</strong>:捕获并合并标准错误,提供完整的诊断信息
|
|
|
- <strong>返回码检查</strong>:非零返回码会被标记为警告
|
|
- <strong>返回码检查</strong>:非零返回码会被标记为警告
|
|
|
-- <strong>容错设计</strong>:超时和异常都会被妥善处理,不会导致智能体崩溃
|
|
|
|
|
|
|
+- <strong>容错设计</strong>:超时和异常都会被妥善处理,不会导致智能体崩溃
|
|
|
|
|
|
|
|
(2)目录导航
|
|
(2)目录导航
|
|
|
|
|
|
|
@@ -1886,7 +1903,7 @@ print(terminal.run({"command": "tail -n +2 sales_2024.csv | cut -d',' -f2 | sort
|
|
|
|
|
|
|
|
(3)日志文件分析
|
|
(3)日志文件分析
|
|
|
|
|
|
|
|
-实时分析应用日志,快速定位问题:
|
|
|
|
|
|
|
+实时分析应用日志,快速定位问题:
|
|
|
|
|
|
|
|
```python
|
|
```python
|
|
|
terminal = TerminalTool(workspace="/var/log")
|
|
terminal = TerminalTool(workspace="/var/log")
|
|
@@ -2006,7 +2023,7 @@ context = context_builder.build(
|
|
|
|
|
|
|
|
## 9.6 长程智能体实战:代码库维护助手
|
|
## 9.6 长程智能体实战:代码库维护助手
|
|
|
|
|
|
|
|
-现在,让我们将 ContextBuilder、NoteTool 和 TerminalTool 整合起来,构建一个完整的长程智能体——<strong>代码库维护助手</strong>。这个助手能够:
|
|
|
|
|
|
|
+现在,让我们将 ContextBuilder、NoteTool 和 TerminalTool 整合起来,构建一个完整的长程智能体——<strong>代码库维护助手</strong>。这个助手能够:
|
|
|
|
|
|
|
|
1. 探索和理解代码库结构
|
|
1. 探索和理解代码库结构
|
|
|
2. 记录发现的问题和改进点
|
|
2. 记录发现的问题和改进点
|
|
@@ -2017,7 +2034,7 @@ context = context_builder.build(
|
|
|
|
|
|
|
|
(1)业务场景
|
|
(1)业务场景
|
|
|
|
|
|
|
|
-假设我们正在维护一个中型 Python Web 应用,代码库包含:
|
|
|
|
|
|
|
+假设我们正在维护一个中型 Python Web 应用,代码库包含:
|
|
|
|
|
|
|
|
- 约 50 个 Python 文件
|
|
- 约 50 个 Python 文件
|
|
|
- 使用 Flask 框架
|
|
- 使用 Flask 框架
|
|
@@ -2029,7 +2046,7 @@ context = context_builder.build(
|
|
|
- <strong>探索代码库</strong>:理解项目结构、依赖关系、代码风格
|
|
- <strong>探索代码库</strong>:理解项目结构、依赖关系、代码风格
|
|
|
- <strong>识别问题</strong>:发现代码重复、复杂度高、缺少测试等问题
|
|
- <strong>识别问题</strong>:发现代码重复、复杂度高、缺少测试等问题
|
|
|
- <strong>追踪任务</strong>:记录待办事项、已完成工作、遇到的阻塞
|
|
- <strong>追踪任务</strong>:记录待办事项、已完成工作、遇到的阻塞
|
|
|
-- <strong>提供建议</strong>:基于历史上下文,提供连贯的重构建议
|
|
|
|
|
|
|
+- <strong>提供建议</strong>:基于历史上下文,提供连贯的重构建议
|
|
|
|
|
|
|
|
(2)挑战与解决方案
|
|
(2)挑战与解决方案
|
|
|
|
|
|
|
@@ -2037,64 +2054,38 @@ context = context_builder.build(
|
|
|
|
|
|
|
|
<strong>挑战1:信息量超出上下文窗口</strong>
|
|
<strong>挑战1:信息量超出上下文窗口</strong>
|
|
|
|
|
|
|
|
-整个代码库可能包含数万行代码,无法一次性放入上下文窗口。
|
|
|
|
|
|
|
+整个代码库可能包含数万行代码,无法一次性放入上下文窗口。
|
|
|
|
|
|
|
|
-<strong>解决方案</strong>:使用 TerminalTool 进行即时、按需的代码探索,只在需要时查看具体文件。
|
|
|
|
|
|
|
+<strong>解决方案</strong>:使用 TerminalTool 进行即时、按需的代码探索,只在需要时查看具体文件。
|
|
|
|
|
|
|
|
<strong>挑战2:跨会话的状态管理</strong>
|
|
<strong>挑战2:跨会话的状态管理</strong>
|
|
|
|
|
|
|
|
-重构任务可能持续数天,需要跨多个会话保持进度。
|
|
|
|
|
|
|
+重构任务可能持续数天,需要跨多个会话保持进度。
|
|
|
|
|
|
|
|
<strong>解决方案</strong>:使用 NoteTool 记录阶段性进展、待办事项和关键决策。
|
|
<strong>解决方案</strong>:使用 NoteTool 记录阶段性进展、待办事项和关键决策。
|
|
|
|
|
|
|
|
<strong>挑战3:上下文质量与相关性</strong>
|
|
<strong>挑战3:上下文质量与相关性</strong>
|
|
|
|
|
|
|
|
-每次对话需要回顾相关的历史信息,但不能被无关信息淹没。
|
|
|
|
|
|
|
+每次对话需要回顾相关的历史信息,但不能被无关信息淹没。
|
|
|
|
|
|
|
|
-<strong>解决方案</strong>:使用 ContextBuilder 智能筛选和组织上下文,确保高信号密度。
|
|
|
|
|
|
|
+<strong>解决方案</strong>:使用 ContextBuilder 智能筛选和组织上下文,确保高信号密度。
|
|
|
|
|
|
|
|
### 9.6.2 系统架构设计
|
|
### 9.6.2 系统架构设计
|
|
|
|
|
|
|
|
-我们的代码库维护助手采用三层架构:
|
|
|
|
|
|
|
+我们的代码库维护助手采用三层架构,如图9.3所示:
|
|
|
|
|
+
|
|
|
|
|
+<div align="center">
|
|
|
|
|
+ <img src="https://raw.githubusercontent.com/datawhalechina/Hello-Agents/main/docs/images/9-figures/9-3.png" alt="" width="85%"/>
|
|
|
|
|
+ <p>图 9.3 代码库维护助手三层架构</p>
|
|
|
|
|
+</div>
|
|
|
|
|
|
|
|
-```
|
|
|
|
|
-┌─────────────────────────────────────────────────────────┐
|
|
|
|
|
-│ CodebaseMaintainer │
|
|
|
|
|
-│ (长程智能体主控类) │
|
|
|
|
|
-├─────────────────────────────────────────────────────────┤
|
|
|
|
|
-│ • 会话管理 │
|
|
|
|
|
-│ • 任务协调 │
|
|
|
|
|
-│ • 决策逻辑 │
|
|
|
|
|
-└─────────────────────────────────────────────────────────┘
|
|
|
|
|
- ▼
|
|
|
|
|
-┌─────────────────────────────────────────────────────────┐
|
|
|
|
|
-│ ContextBuilder │
|
|
|
|
|
-│ (上下文管理层) │
|
|
|
|
|
-├─────────────────────────────────────────────────────────┤
|
|
|
|
|
-│ GSSC Pipeline: │
|
|
|
|
|
-│ • Gather: 汇集笔记、记忆、终端输出 │
|
|
|
|
|
-│ • Select: 基于相关性和新近性筛选 │
|
|
|
|
|
-│ • Structure: 组织为标准模板 │
|
|
|
|
|
-│ • Compress: 超限压缩 │
|
|
|
|
|
-└─────────────────────────────────────────────────────────┘
|
|
|
|
|
- ▼
|
|
|
|
|
-┌───────────────┬───────────────────┬─────────────────────┐
|
|
|
|
|
-│ NoteTool │ TerminalTool │ MemoryTool │
|
|
|
|
|
-│ (持久化笔记) │ (即时文件访问) │ (对话记忆) │
|
|
|
|
|
-├───────────────┼───────────────────┼─────────────────────┤
|
|
|
|
|
-│• 任务状态 │ • ls, cat, grep │ • 工作记忆 │
|
|
|
|
|
-│• 发现的问题 │ • find, head │ • 情景记忆 │
|
|
|
|
|
-│• 重构计划 │ • wc, sort │ • 语义记忆 │
|
|
|
|
|
-│• 关键决策 │ • 目录导航 │ │
|
|
|
|
|
-└───────────────┴───────────────────┴─────────────────────┘
|
|
|
|
|
-```
|
|
|
|
|
|
|
|
|
|
### 9.6.3 核心实现
|
|
### 9.6.3 核心实现
|
|
|
|
|
|
|
|
现在让我们实现这个系统的核心类:
|
|
现在让我们实现这个系统的核心类:
|
|
|
|
|
|
|
|
```python
|
|
```python
|
|
|
-from typing import Dict, Any, List, Optional
|
|
|
|
|
|
|
+from typing import Dict, Any, List, Optional
|
|
|
from datetime import datetime
|
|
from datetime import datetime
|
|
|
import json
|
|
import json
|
|
|
|
|
|
|
@@ -2501,7 +2492,7 @@ class CodebaseMaintainer:
|
|
|
|
|
|
|
|
### 9.6.4 完整使用示例
|
|
### 9.6.4 完整使用示例
|
|
|
|
|
|
|
|
-现在让我们通过一个完整的使用场景,展示这个长程智能体的工作流程:
|
|
|
|
|
|
|
+现在让我们通过一个完整的使用场景,展示这个长程智能体的工作流程:
|
|
|
|
|
|
|
|
```python
|
|
```python
|
|
|
# ========== 初始化助手 ==========
|
|
# ========== 初始化助手 ==========
|
|
@@ -2516,11 +2507,6 @@ maintainer = CodebaseMaintainer(
|
|
|
|
|
|
|
|
|
|
|
|
|
# ========== 第一天:探索代码库 ==========
|
|
# ========== 第一天:探索代码库 ==========
|
|
|
-
|
|
|
|
|
-print("\n" + "="*80)
|
|
|
|
|
-print("第一天:探索代码库")
|
|
|
|
|
-print("="*80 + "\n")
|
|
|
|
|
-
|
|
|
|
|
# 1. 初步探索
|
|
# 1. 初步探索
|
|
|
response = maintainer.explore()
|
|
response = maintainer.explore()
|
|
|
"""
|
|
"""
|
|
@@ -2577,10 +2563,6 @@ response = maintainer.run("请分析 app/models/ 目录下的数据模型设计"
|
|
|
|
|
|
|
|
# ========== 第二天:分析代码质量 ==========
|
|
# ========== 第二天:分析代码质量 ==========
|
|
|
|
|
|
|
|
-print("\n" + "="*80)
|
|
|
|
|
-print("第二天:分析代码质量")
|
|
|
|
|
-print("="*80 + "\n")
|
|
|
|
|
-
|
|
|
|
|
# 1. 整体质量分析
|
|
# 1. 整体质量分析
|
|
|
response = maintainer.analyze()
|
|
response = maintainer.analyze()
|
|
|
"""
|
|
"""
|
|
@@ -2621,7 +2603,7 @@ response = maintainer.run("请查看 order_service.py 的 process_order 方法,
|
|
|
"""
|
|
"""
|
|
|
🤖 助手: 我查看了 process_order 方法的代码:
|
|
🤖 助手: 我查看了 process_order 方法的代码:
|
|
|
|
|
|
|
|
-```python
|
|
|
|
|
|
|
+【原始代码】
|
|
|
def process_order(self, order_id):
|
|
def process_order(self, order_id):
|
|
|
order = Order.query.get(order_id)
|
|
order = Order.query.get(order_id)
|
|
|
if order:
|
|
if order:
|
|
@@ -2630,15 +2612,13 @@ def process_order(self, order_id):
|
|
|
if product:
|
|
if product:
|
|
|
if product.stock >= order.quantity:
|
|
if product.stock >= order.quantity:
|
|
|
# ... 8 层嵌套继续 ...
|
|
# ... 8 层嵌套继续 ...
|
|
|
-```
|
|
|
|
|
|
|
|
|
|
-问题分析:
|
|
|
|
|
|
|
+【问题分析】
|
|
|
1. 过深的嵌套导致可读性差
|
|
1. 过深的嵌套导致可读性差
|
|
|
2. 缺少错误处理
|
|
2. 缺少错误处理
|
|
|
3. 业务逻辑与数据访问混在一起
|
|
3. 业务逻辑与数据访问混在一起
|
|
|
|
|
|
|
|
-重构建议:
|
|
|
|
|
-```python
|
|
|
|
|
|
|
+【重构建议】
|
|
|
def process_order(self, order_id):
|
|
def process_order(self, order_id):
|
|
|
# 1. 早返回模式,减少嵌套
|
|
# 1. 早返回模式,减少嵌套
|
|
|
order = self._get_order(order_id)
|
|
order = self._get_order(order_id)
|
|
@@ -2655,9 +2635,8 @@ def process_order(self, order_id):
|
|
|
self._update_order_status(order, 'processing')
|
|
self._update_order_status(order, 'processing')
|
|
|
|
|
|
|
|
return True
|
|
return True
|
|
|
-```
|
|
|
|
|
|
|
|
|
|
-下一步:
|
|
|
|
|
|
|
+【下一步】
|
|
|
1. 我已创建重构计划笔记
|
|
1. 我已创建重构计划笔记
|
|
|
2. 建议先编写测试用例
|
|
2. 建议先编写测试用例
|
|
|
3. 逐步重构,保持功能不变
|
|
3. 逐步重构,保持功能不变
|
|
@@ -2667,10 +2646,6 @@ def process_order(self, order_id):
|
|
|
|
|
|
|
|
# ========== 第三天:规划重构任务 ==========
|
|
# ========== 第三天:规划重构任务 ==========
|
|
|
|
|
|
|
|
-print("\n" + "="*80)
|
|
|
|
|
-print("第三天:规划重构任务")
|
|
|
|
|
-print("="*80 + "\n")
|
|
|
|
|
-
|
|
|
|
|
# 1. 回顾进度
|
|
# 1. 回顾进度
|
|
|
response = maintainer.plan_next_steps()
|
|
response = maintainer.plan_next_steps()
|
|
|
"""
|
|
"""
|
|
@@ -2740,10 +2715,6 @@ print("✅ 已创建详细的重构计划")
|
|
|
|
|
|
|
|
# ========== 一周后:检查进度 ==========
|
|
# ========== 一周后:检查进度 ==========
|
|
|
|
|
|
|
|
-print("\n" + "="*80)
|
|
|
|
|
-print("一周后:检查进度")
|
|
|
|
|
-print("="*80 + "\n")
|
|
|
|
|
-
|
|
|
|
|
# 查看笔记摘要
|
|
# 查看笔记摘要
|
|
|
summary = maintainer.note_tool.run({"action": "summary"})
|
|
summary = maintainer.note_tool.run({"action": "summary"})
|
|
|
print("📊 笔记摘要:")
|
|
print("📊 笔记摘要:")
|
|
@@ -2792,15 +2763,15 @@ print(json.dumps(report, indent=2, ensure_ascii=False))
|
|
|
|
|
|
|
|
### 9.6.5 运行效果分析
|
|
### 9.6.5 运行效果分析
|
|
|
|
|
|
|
|
-通过这个完整的案例,我们可以看到长程智能体的几个关键特性:
|
|
|
|
|
|
|
+通过这个完整的案例,我们可以看到长程智能体的几个关键特性:
|
|
|
|
|
|
|
|
(1)跨会话的连贯性
|
|
(1)跨会话的连贯性
|
|
|
|
|
|
|
|
智能体通过 NoteTool 保持了跨多天、多个会话的任务连贯性:
|
|
智能体通过 NoteTool 保持了跨多天、多个会话的任务连贯性:
|
|
|
|
|
|
|
|
-- 第一天探索的问题,在第二天分析时被自动考虑
|
|
|
|
|
-- 第三天规划时,能够综合前两天的所有发现
|
|
|
|
|
-- 一周后检查时,完整的历史都被保留
|
|
|
|
|
|
|
+- 第一天探索的问题,在第二天分析时被自动考虑
|
|
|
|
|
+- 第三天规划时,能够综合前两天的所有发现
|
|
|
|
|
+- 一周后检查时,完整的历史都被保留
|
|
|
|
|
|
|
|
(2)智能的上下文管理
|
|
(2)智能的上下文管理
|
|
|
|
|
|
|
@@ -2816,7 +2787,7 @@ TerminalTool 支持灵活的代码探索:
|
|
|
|
|
|
|
|
- 无需预先索引整个代码库
|
|
- 无需预先索引整个代码库
|
|
|
- 可以即时查看具体文件内容
|
|
- 可以即时查看具体文件内容
|
|
|
-- 支持复杂的文本处理(grep, awk等)
|
|
|
|
|
|
|
+- 支持复杂的文本处理(grep, awk等)
|
|
|
|
|
|
|
|
(4)自动化的知识管理
|
|
(4)自动化的知识管理
|
|
|
|
|
|
|
@@ -2834,60 +2805,30 @@ TerminalTool 支持灵活的代码探索:
|
|
|
- 人类可以通过笔记系统进行干预和指导
|
|
- 人类可以通过笔记系统进行干预和指导
|
|
|
- 支持手动创建详细的计划笔记
|
|
- 支持手动创建详细的计划笔记
|
|
|
|
|
|
|
|
-### 9.6.6 最佳实践与扩展方向
|
|
|
|
|
-
|
|
|
|
|
-基于这个案例,我们总结一些构建长程智能体的最佳实践:
|
|
|
|
|
-
|
|
|
|
|
-(1)分层的信息管理
|
|
|
|
|
-
|
|
|
|
|
-- <strong>即时层</strong>:TerminalTool 提供实时、按需的文件访问
|
|
|
|
|
-- <strong>会话层</strong>:MemoryTool 管理单次会话的对话记忆
|
|
|
|
|
-- <strong>持久层</strong>:NoteTool 存储跨会话的结构化知识
|
|
|
|
|
-
|
|
|
|
|
-(2)主动的上下文优化
|
|
|
|
|
-
|
|
|
|
|
-- 根据任务类型(探索/分析/规划)动态调整上下文策略
|
|
|
|
|
-- 使用不同的相关性分数区分信息重要性
|
|
|
|
|
-- 实施智能的历史对话限制
|
|
|
|
|
-
|
|
|
|
|
-(3)自动化与可控性的平衡
|
|
|
|
|
-
|
|
|
|
|
-- 自动创建笔记提升效率
|
|
|
|
|
-- 但保留人工编辑和管理的能力
|
|
|
|
|
-- 使用标签系统实现灵活的分类
|
|
|
|
|
-
|
|
|
|
|
-(4)可观测性
|
|
|
|
|
-
|
|
|
|
|
-- 详细的统计信息(命令执行次数、笔记数量等)
|
|
|
|
|
-- 可导出的会话报告
|
|
|
|
|
-- 清晰的日志输出
|
|
|
|
|
-
|
|
|
|
|
-(5)扩展方向
|
|
|
|
|
-
|
|
|
|
|
这个基础框架可以进一步扩展:
|
|
这个基础框架可以进一步扩展:
|
|
|
|
|
|
|
|
-- <strong>集成 RAGTool</strong>:为代码库建立向量索引,结合语义检索
|
|
|
|
|
|
|
+- <strong>集成 RAGTool</strong>:为代码库建立向量索引,结合语义检索
|
|
|
- <strong>多智能体协作</strong>:拆分为专门的探索者、分析者、规划者
|
|
- <strong>多智能体协作</strong>:拆分为专门的探索者、分析者、规划者
|
|
|
-- <strong>自动化测试</strong>:集成测试工具,自动验证重构结果
|
|
|
|
|
-- <strong>版本控制集成</strong>:通过 TerminalTool 执行 git 命令,追踪代码变更
|
|
|
|
|
|
|
+- <strong>自动化测试</strong>:集成测试工具,自动验证重构结果
|
|
|
|
|
+- <strong>版本控制集成</strong>:通过 TerminalTool 执行 git 命令,追踪代码变更
|
|
|
- <strong>可视化界面</strong>:使用 Gradio/Streamlit 构建 Web 界面
|
|
- <strong>可视化界面</strong>:使用 Gradio/Streamlit 构建 Web 界面
|
|
|
|
|
|
|
|
## 9.7 本章总结
|
|
## 9.7 本章总结
|
|
|
|
|
|
|
|
-在本章中,我们深入探讨了上下文工程的理论基础和工程实践:
|
|
|
|
|
|
|
+在本章中,我们深入探讨了上下文工程的理论基础和工程实践:
|
|
|
|
|
|
|
|
### 理论层面
|
|
### 理论层面
|
|
|
|
|
|
|
|
-1. <strong>上下文工程的本质</strong>:从"提示工程"到"上下文工程"的演进,核心是管理有限的注意力预算
|
|
|
|
|
-2. <strong>上下文腐蚀</strong>:理解长上下文带来的性能下降,认识到上下文是稀缺资源
|
|
|
|
|
|
|
+1. <strong>上下文工程的本质</strong>:从"提示工程"到"上下文工程"的演进,核心是管理有限的注意力预算
|
|
|
|
|
+2. <strong>上下文腐蚀</strong>:理解长上下文带来的性能下降,认识到上下文是稀缺资源
|
|
|
3. <strong>三大策略</strong>:压缩整合、结构化笔记、子代理架构
|
|
3. <strong>三大策略</strong>:压缩整合、结构化笔记、子代理架构
|
|
|
|
|
|
|
|
### 工程实践
|
|
### 工程实践
|
|
|
|
|
|
|
|
-1. <strong>ContextBuilder</strong>:实现了 GSSC 流水线,提供统一的上下文管理接口
|
|
|
|
|
-2. <strong>NoteTool</strong>:Markdown+YAML 的混合格式,支持结构化的长期记忆
|
|
|
|
|
-3. <strong>TerminalTool</strong>:安全的命令行工具,支持即时的文件系统访问
|
|
|
|
|
-4. <strong>长程智能体</strong>:整合三大工具,构建了跨会话的代码库维护助手
|
|
|
|
|
|
|
+1. <strong>ContextBuilder</strong>:实现了 GSSC 流水线,提供统一的上下文管理接口
|
|
|
|
|
+2. <strong>NoteTool</strong>:Markdown+YAML 的混合格式,支持结构化的长期记忆
|
|
|
|
|
+3. <strong>TerminalTool</strong>:安全的命令行工具,支持即时的文件系统访问
|
|
|
|
|
+4. <strong>长程智能体</strong>:整合三大工具,构建了跨会话的代码库维护助手
|
|
|
|
|
|
|
|
### 核心收获
|
|
### 核心收获
|
|
|
|
|
|
|
@@ -2896,9 +2837,9 @@ TerminalTool 支持灵活的代码探索:
|
|
|
- <strong>安全第一</strong>:多层安全机制确保系统稳定
|
|
- <strong>安全第一</strong>:多层安全机制确保系统稳定
|
|
|
- <strong>人机协作</strong>:自动化与可控性的平衡
|
|
- <strong>人机协作</strong>:自动化与可控性的平衡
|
|
|
|
|
|
|
|
-通过这一章的学习,您不仅掌握了上下文工程的核心技术,更重要的是理解了如何构建能够在长时间跨度内保持连贯性和有效性的智能体系统。这些技能将成为您构建生产级智能体应用的重要基础。
|
|
|
|
|
|
|
+通过这一章的学习,您不仅掌握了上下文工程的核心技术,更重要的是理解了如何构建能够在长时间跨度内保持连贯性和有效性的智能体系统。这些技能将成为您构建生产级智能体应用的重要基础。
|
|
|
|
|
|
|
|
-在下一章中,我们将探讨智能体通信协议(MCP),学习如何让智能体与外部世界进行更广泛的交互。
|
|
|
|
|
|
|
+在下一章中,我们将探讨智能体通信协议,学习如何让智能体与外部世界进行更广泛的交互。
|
|
|
|
|
|
|
|
## 参考文献
|
|
## 参考文献
|
|
|
|
|
|