Agent综述

agent综述


前言:理解技术作用的四个层面

在阅读每篇论文时,我们需要明确它的技术创新作用于哪个层面:

层面 说明 典型特征
🔧 LLM 训练 需要修改模型权重,进行微调或预训练 需要 GPU 集群、训练数据、梯度更新
LLM 推理 在模型生成时的策略优化 修改解码策略、采样方式
🎭 Agent 编排 设计智能体的工作流程和架构 定义角色、流程、工具调用逻辑
📝 提示词工程 通过设计 Prompt 引导模型行为 零成本、即插即用、无需训练

第一部分:智能体框架(Agent)

1.1 ReAct: 推理与行动的协同

论文: ReAct: Synergizing Reasoning and Acting in Language Models
技术层面: 📝 提示词工程 + 🎭 Agent 编排

1.1.1 过去的工作是怎么做的?

在 ReAct 之前,研究者主要采用两种独立的方法:

方法一:Chain-of-Thought (CoT) 纯推理方法

CoT 让模型在回答问题前先进行"思考":

问题:小明有5个苹果,给了小红3个,又买了2个,现在有几个?

【CoT 方式】
思考:小明原有5个苹果
思考:给出3个后剩余 5-3=2 个
思考:买入2个后变成 2+2=4 个
答案:4个

局限性:CoT 无法与外部世界交互,遇到需要查询实时信息的问题就束手无策。

方法二:Action-only 纯行动方法

模型直接输出动作序列,依赖强化学习训练:

\[\pi^*(a|s) = \arg\max_{\pi} \mathbb{E}\left[\sum_{t=0}^{T} \gamma^t r_t\right] \]

其中:

  • \(\pi(a|s)\) 是策略函数(给定状态 s,输出动作 a 的概率)
  • \(r_t\) 是时间步 t 获得的奖励
  • \(\gamma\) 是折扣因子

局限性:缺乏显式推理,决策过程不可解释,容易陷入局部最优。

1.1.2 ReAct 是怎么做的?

ReAct 的核心创新是将推理和行动交织在一起,形成 Thought-Action-Observation 循环:

┌─────────────────────────────────────────────────┐
│                  ReAct 循环                      │
│                                                  │
│   Thought ──→ Action ──→ Observation ──┐        │
│      ↑                                  │        │
│      └──────────────────────────────────┘        │
└─────────────────────────────────────────────────┘

具体实现方式(通过 Prompt Engineering)

ReAct 不需要训练模型,只需要设计特定的提示词模板:

REACT_PROMPT = """
你是一个问答助手。请按照以下格式回答问题:

Thought: [分析当前情况,思考下一步该做什么]
Action: [选择一个动作] Search[关键词] 或 Lookup[术语] 或 Finish[答案]
Observation: [动作执行后的结果,由系统提供]

重复上述过程直到得到最终答案。

问题:{question}
"""

数学形式化

给定问题 \(q\) 和上下文 \(c\),ReAct 生成交织序列:

\[y = (t_1, a_1, o_1, t_2, a_2, o_2, ..., t_n, a_n) \]

其中:

  • \(t_i\) 是第 i 步的思考(Thought)
  • \(a_i\) 是第 i 步的动作(Action)
  • \(o_i\) 是第 i 步的观察(Observation,来自环境)

生成过程遵循自回归方式:

\[P(y|q,c) = \prod_{i=1}^{n} P(t_i|q,c,y_{<i}) \cdot P(a_i|q,c,y_{<i},t_i) \]

1.1.3 完整示例

问题:2024年诺贝尔物理学奖获得者的出生地是哪里?

Thought 1: 这个问题需要两步:先找到获奖者是谁,再找出生地。
          让我先搜索2024年诺贝尔物理学奖获得者。
Action 1: Search[2024 Nobel Prize Physics winner]
Observation 1: The 2024 Nobel Prize in Physics was awarded to 
               John Hopfield and Geoffrey Hinton for foundational 
               discoveries in machine learning.

Thought 2: 获奖者是 John Hopfield 和 Geoffrey Hinton,有两位。
          我先查询 Geoffrey Hinton 的出生地。
Action 2: Search[Geoffrey Hinton birthplace]
Observation 2: Geoffrey Hinton was born in Wimbledon, London, England.

Thought 3: Hinton 出生于英国伦敦。再查询 Hopfield 的出生地。
Action 3: Search[John Hopfield birthplace]  
Observation 3: John Hopfield was born in Chicago, Illinois, USA.

Thought 4: 我已经得到了所有信息。
Action 4: Finish[Geoffrey Hinton 出生于英国伦敦,John Hopfield 出生于美国芝加哥]

1.2 Reflexion: 语言智能体的自我反思

论文: Reflexion: Language Agents with Verbal Reinforcement Learning
技术层面: 📝 提示词工程 + 🎭 Agent 编排

1.2.1 过去的工作是怎么做的?

传统强化学习方法

智能体通过试错学习,更新神经网络权重:

\[\theta_{t+1} = \theta_t + \alpha \nabla_\theta J(\theta) \]

其中:

  • \(\theta\) 是模型参数
  • \(\alpha\) 是学习率
  • \(J(\theta)\) 是目标函数(期望累积奖励)

策略梯度的核心公式(REINFORCE):

\[\nabla_\theta J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta}\left[\sum_{t=0}^{T} \nabla_\theta \log \pi_\theta(a_t|s_t) \cdot R_t\right] \]

局限性

  1. 需要大量样本(sample inefficient)
  2. 需要可微的奖励函数
  3. 难以处理稀疏奖励
  4. 不适用于"冻结"的 LLM(如 GPT-4 API)

1.2.2 Reflexion 是怎么做的?

Reflexion 的革命性创新:用自然语言替代梯度更新

┌─────────────────────────────────────────────────────────┐
│                   Reflexion 架构                         │
│                                                          │
│  ┌─────────┐    ┌───────────┐    ┌──────────────────┐   │
│  │  Actor  │───→│ Evaluator │───→│ Self-Reflection  │   │
│  │ (执行者) │    │  (评估器)  │    │   (自我反思器)    │   │
│  └─────────┘    └───────────┘    └──────────────────┘   │
│       ↑                                    │             │
│       │         ┌──────────────┐          │             │
│       └─────────│ Memory (记忆) │←─────────┘             │
│                 └──────────────┘                         │
└─────────────────────────────────────────────────────────┘

核心公式——语言强化学习

传统 RL 更新权重,Reflexion 更新"经验记忆":

\[m_{t+1} = m_t \cup \{r_t\} \]

其中:

  • \(m_t\) 是第 t 次尝试时的记忆集合
  • \(r_t\) 是第 t 次尝试后生成的反思文本

下一次尝试时,策略基于记忆条件生成:

\[a_{t+1} \sim \pi_{LLM}(a|s, m_{t+1}) \]

反思生成的 Prompt 模板

REFLECTION_PROMPT = """
你刚才尝试完成一个任务但失败了。

任务描述:{task}

你的执行轨迹:
{trajectory}

失败原因:{failure_reason}

请反思:
1. 哪里出了问题?
2. 你学到了什么?
3. 下次应该怎么改进?

反思总结(一段话):
"""

1.2.3 完整示例:代码生成任务

第一次尝试

# 任务:实现一个函数,返回列表中第二大的数

def second_largest(nums):
    nums.sort()
    return nums[-2]  # 错误!没考虑重复元素

# 测试失败:second_largest([1, 5, 5]) 返回 5,期望 1

反思生成

反思:我的实现没有考虑到列表中可能有重复的最大值。
当输入 [1, 5, 5] 时,排序后取倒数第二个仍是 5。
下次应该先去重,或者遍历找第二大的不同值。

第二次尝试(基于反思)

def second_largest(nums):
    unique_nums = list(set(nums))  # 去重
    unique_nums.sort()
    return unique_nums[-2]

# 测试通过!

1.2.4 与传统 RL 的对比

维度 传统 RL Reflexion
学习信号 标量奖励 自然语言反思
更新方式 梯度更新权重 追加记忆文本
样本效率 低(需要大量样本) 高(几次尝试)
可解释性 高(反思可阅读)
适用模型 需要可训练 适用于 API 模型

1.3 Tree of Thoughts: 深思熟虑的问题求解

论文: Tree of Thoughts: Deliberate Problem Solving with Large Language Models
技术层面: ⚡ LLM 推理 + 📝 提示词工程

1.3.1 过去的工作是怎么做的?

方法一:标准 Prompting(IO)

直接输入问题,模型一步输出答案:

\[y = \arg\max_y P(y|x) \]

方法二:Chain-of-Thought (CoT)

引导模型逐步推理:

\[y = \arg\max_y P(y|x, z_1, z_2, ..., z_n) \]

其中 \(z_i\) 是中间推理步骤。

方法三:Self-Consistency (CoT-SC)

多次采样,投票选择最一致的答案:

\[y^* = \arg\max_y \sum_{i=1}^{k} \mathbb{1}[y_i = y] \]

所有这些方法的共同局限

  • 只能沿单一路径前进
  • 无法回溯和尝试其他可能性
  • 遇到错误无法纠正

1.3.2 Tree of Thoughts 是怎么做的?

ToT 引入搜索算法的思想,将推理过程组织成树形结构:

                        [问题]
                           │
           ┌───────────────┼───────────────┐
           ▼               ▼               ▼
       [思路A]         [思路B]         [思路C]
       分数:0.8        分数:0.3        分数:0.6
           │               ✗               │
     ┌─────┼─────┐                   ┌─────┼─────┐
     ▼     ▼     ▼                   ▼     ▼     ▼
  [A1]   [A2]   [A3]              [C1]   [C2]   [C3]
  0.9    0.4    0.7               0.5    0.8    0.3
   │      ✗      │                 ✗      │      ✗
   ▼             ▼                        ▼
[答案1]      [答案2]                  [答案3]

核心组件与数学定义

  1. 状态空间 \(S\):所有可能的中间推理状态
  2. 思维生成器 \(G(s, k)\):给定状态 \(s\),生成 \(k\) 个候选后续思维

\[\{t_1, t_2, ..., t_k\} = G(s, k) \]

  1. 状态评估器 \(V(s)\):评估状态 \(s\) 的"前景"(0-1分)

\[V(s) = P(\text{该状态能导向正确答案}) \]

  1. 搜索算法:BFS 或 DFS

BFS(广度优先搜索)算法

def bfs_tot(problem, max_depth, branch_factor):
    # 初始化
    current_level = [problem]  # 当前层的状态
    
    for depth in range(max_depth):
        candidates = []
        
        # 对当前层每个状态生成候选
        for state in current_level:
            thoughts = generate_thoughts(state, k=branch_factor)
            for thought in thoughts:
                new_state = state + thought
                score = evaluate_state(new_state)
                candidates.append((new_state, score))
        
        # 保留分数最高的 b 个状态
        candidates.sort(key=lambda x: x[1], reverse=True)
        current_level = [c[0] for c in candidates[:branch_factor]]
    
    return best_solution(current_level)

1.3.3 经典案例:24点游戏

问题:使用数字 4, 5, 6, 10 和四则运算,得到 24。

ToT 解题过程

输入:4, 5, 6, 10

第一层候选思路:
├─ 10 - 4 = 6  (剩余: 5, 6, 6)  → 评分: 0.7 ✓
├─ 10 - 6 = 4  (剩余: 4, 4, 5)  → 评分: 0.5
├─ 5 + 4 = 9   (剩余: 6, 9, 10) → 评分: 0.6
└─ 6 - 4 = 2   (剩余: 2, 5, 10) → 评分: 0.4

选择最优继续:10 - 4 = 6

第二层候选思路:
├─ 5 + 6 = 11  (剩余: 6, 11)    → 评分: 0.3
├─ 6 - 5 = 1   (剩余: 1, 6)     → 评分: 0.2
└─ 6 / (6-5) = 6  (剩余: 6, 6)  → 评分: 0.8 ✓

选择最优继续:6 / (6-5) = 6

第三层:
└─ 6 + 6 = 12 (✗) 或 6 × 6 = 36 (✗)... 需要回溯

回溯到第一层,尝试其他路径...

最终找到:(10 - 4) × 6 - 5 = 31 (✗)
继续搜索:5 × (10 - 6) + 4 = 24 ✓

1.3.4 评估函数的实现

ToT 使用 LLM 本身作为评估器:

EVALUATION_PROMPT = """
我正在玩24点游戏,需要用四则运算让结果等于24。

当前进度:{current_state}
剩余数字:{remaining_numbers}

请评估这个状态能得到24的可能性:
- sure (确定能)
- likely (可能能)
- impossible (不可能)

你的判断:
"""

def evaluate_state(state):
    response = llm(EVALUATION_PROMPT.format(...))
    if "sure" in response: return 1.0
    if "likely" in response: return 0.5
    return 0.0

1.3.5 不同方法的推理范式对比

IO Prompting:      输入 ────────────────────→ 输出
                    
CoT:               输入 → 思考1 → 思考2 → ... → 输出

CoT-SC:            输入 → 思考1a → 思考2a → 输出a ─┐
                   输入 → 思考1b → 思考2b → 输出b ─┼→ 投票 → 最终输出
                   输入 → 思考1c → 思考2c → 输出c ─┘

ToT:                          ┌─ 思考B1 ──→ ...
                   输入 ──→ 思考A ─┤
                              │   └─ 思考B2 ──→ 输出
                              │
                              └─ 思考C ─── (剪枝)

1.4 AutoGen: 多智能体对话框架

论文: AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation
技术层面: 🎭 Agent 编排

1.4.1 过去的工作是怎么做的?

单智能体模式

一个 LLM 承担所有角色,通过 Prompt 切换"身份":

# 传统方式:一个模型扮演多个角色
response = llm("你是一个程序员,请写一段代码...")
response = llm("你是一个测试工程师,请检查这段代码...")
response = llm("你是一个代码审查员,请评审...")

局限性

  • 上下文窗口被多角色共享,容易混乱
  • 难以实现真正的"辩论"和"协作"
  • 流程控制复杂

1.4.2 AutoGen 是怎么做的?

AutoGen 设计了真正独立的多个智能体,通过对话协议协作:

┌────────────────────────────────────────────────────────────┐
│                    AutoGen 多智能体架构                      │
│                                                             │
│   ┌─────────────┐         ┌─────────────┐                  │
│   │   Agent A   │ ←─────→ │   Agent B   │                  │
│   │ (助手)       │  对话   │ (用户代理)   │                  │
│   └─────────────┘         └─────────────┘                  │
│          ↑                       ↑                         │
│          │                       │                         │
│          ▼                       ▼                         │
│   ┌─────────────┐         ┌─────────────┐                  │
│   │   Agent C   │         │   Agent D   │                  │
│   │ (评审员)     │         │ (执行器)     │                  │
│   └─────────────┘         └─────────────┘                  │
│                                                             │
└────────────────────────────────────────────────────────────┘

核心抽象——ConversableAgent

class ConversableAgent:
    def __init__(self, name, system_message, llm_config):
        self.name = name
        self.system_message = system_message
        self.llm = create_llm(llm_config)
        self.chat_history = []
    
    def receive(self, message, sender):
        """接收来自其他智能体的消息"""
        self.chat_history.append({
            "role": "user",
            "content": f"[{sender.name}]: {message}"
        })
        
    def generate_reply(self):
        """生成回复"""
        response = self.llm(
            system=self.system_message,
            messages=self.chat_history
        )
        return response
    
    def send(self, message, recipient):
        """发送消息给其他智能体"""
        recipient.receive(message, self)

对话流转的数学建模

定义智能体集合 \(\mathcal{A} = \{A_1, A_2, ..., A_n\}\),对话状态为:

\[s_t = (m_1, m_2, ..., m_t) \]

其中 \(m_i = (a_i, c_i)\) 表示智能体 \(a_i\) 发送的内容 \(c_i\)

下一条消息由调度器决定:

\[a_{t+1} = \text{Scheduler}(s_t) \]

\[m_{t+1} = (a_{t+1}, A_{a_{t+1}}.\text{generate}(s_t)) \]

1.4.3 实际代码示例

from autogen import AssistantAgent, UserProxyAgent

# 创建助手智能体(使用 GPT-4)
assistant = AssistantAgent(
    name="程序员小明",
    system_message="你是一个Python专家,擅长写简洁高效的代码。",
    llm_config={"model": "gpt-4"}
)

# 创建用户代理(可执行代码)
user_proxy = UserProxyAgent(
    name="用户代理",
    human_input_mode="NEVER",  # 全自动模式
    code_execution_config={"work_dir": "coding"}
)

# 发起对话
user_proxy.initiate_chat(
    assistant,
    message="请写一个快速排序算法,并用随机数组测试"
)

对话过程

用户代理: 请写一个快速排序算法,并用随机数组测试

程序员小明: 好的,这是快速排序的实现:
```python
import random

def quicksort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quicksort(left) + middle + quicksort(right)

# 测试
test_arr = [random.randint(1, 100) for _ in range(10)]
print(f"原数组: {test_arr}")
print(f"排序后: {quicksort(test_arr)}")

用户代理: [执行代码]
输出:
原数组: [34, 67, 23, 89, 12, 45, 78, 56, 90, 11]
排序后: [11, 12, 23, 34, 45, 56, 67, 78, 89, 90]

用户代理: 代码执行成功!


#### 1.4.4 群聊模式

```python
from autogen import GroupChat, GroupChatManager

# 创建多个专家智能体
coder = AssistantAgent(name="程序员", ...)
reviewer = AssistantAgent(name="代码审查员", ...)
tester = AssistantAgent(name="测试工程师", ...)

# 创建群聊
group_chat = GroupChat(
    agents=[coder, reviewer, tester],
    messages=[],
    max_round=10
)

# 群聊管理器
manager = GroupChatManager(groupchat=group_chat)

# 发起群聊
user_proxy.initiate_chat(
    manager,
    message="请设计并实现一个安全的密码验证函数"
)

第二部分:检索增强生成(RAG)

2.1 Dense Passage Retrieval: 密集检索的基石

论文: Dense Passage Retrieval for Open-Domain Question Answering
技术层面: 🔧 LLM 训练(需要训练编码器)

2.1.1 过去的工作是怎么做的?

稀疏检索方法(BM25/TF-IDF)

TF-IDF 的数学定义:

\[\text{TF-IDF}(t, d, D) = \text{TF}(t, d) \times \text{IDF}(t, D) \]

其中:

  • \(\text{TF}(t, d) = \frac{f_{t,d}}{\sum_{t' \in d} f_{t',d}}\) (词频)
  • \(\text{IDF}(t, D) = \log \frac{|D|}{|\{d \in D: t \in d\}|}\) (逆文档频率)

BM25 改进版:

\[\text{BM25}(q, d) = \sum_{t \in q} \text{IDF}(t) \cdot \frac{f_{t,d} \cdot (k_1 + 1)}{f_{t,d} + k_1 \cdot (1 - b + b \cdot \frac{|d|}{\text{avgdl}})} \]

稀疏检索的局限性

查询:"苹果手机的创始人是谁?"
文档:"乔布斯创立了 iPhone 的制造商。"

词袋匹配:
- "苹果" 不在文档中 ✗
- "手机" 不在文档中 ✗
- "创始人" 不在文档中 ✗

BM25 分数很低,但这是正确答案!

问题本质:词汇鸿沟(Lexical Gap)——同义词、释义无法匹配。

2.1.2 DPR 是怎么做的?

DPR 使用神经网络编码器将文本映射到密集向量空间:

┌──────────────────────────────────────────────────────────┐
│                    DPR 双编码器架构                        │
│                                                           │
│   问题: "苹果手机创始人"          文档: "乔布斯创立了..."     │
│            │                              │               │
│            ▼                              ▼               │
│   ┌─────────────────┐          ┌─────────────────┐       │
│   │  Query Encoder  │          │ Passage Encoder │       │
│   │     (BERT)      │          │     (BERT)      │       │
│   └─────────────────┘          └─────────────────┘       │
│            │                              │               │
│            ▼                              ▼               │
│      [0.2, -0.5, ...]            [0.3, -0.4, ...]        │
│         768维向量                    768维向量             │
│            │                              │               │
│            └───────────┬──────────────────┘               │
│                        ▼                                  │
│                  点积相似度                                │
│            sim(q, p) = q · p = 0.92                       │
└──────────────────────────────────────────────────────────┘

数学定义

给定问题 \(q\) 和段落 \(p\),相似度计算为:

\[\text{sim}(q, p) = E_Q(q)^\top \cdot E_P(p) \]

其中:

  • \(E_Q: \mathbb{R}^{|V|^*} \rightarrow \mathbb{R}^d\) 是问题编码器
  • \(E_P: \mathbb{R}^{|V|^*} \rightarrow \mathbb{R}^d\) 是段落编码器
  • \(d = 768\) 是向量维度

训练目标——对比学习

对于问题 \(q_i\) 及其正确段落 \(p_i^+\),训练目标是最大化:

\[\mathcal{L} = -\log \frac{e^{\text{sim}(q_i, p_i^+)}}{e^{\text{sim}(q_i, p_i^+)} + \sum_{j=1}^{n} e^{\text{sim}(q_i, p_{i,j}^-)}} \]

其中 \(p_{i,j}^-\) 是负样本(不相关的段落)。

负样本策略

类型 来源 效果
Random 随机段落 一般
In-batch 同批次其他问题的正样本
Hard Negative BM25 高分但错误的段落 最好

Hard Negative 的直觉:迫使模型学习更细微的语义差异。

2.1.3 为什么密集检索更好?

向量空间的语义属性

在训练后的向量空间中:
- "苹果手机" 和 "iPhone" 的向量接近
- "创始人" 和 "创立者" 的向量接近
- "乔布斯" 和 "苹果公司CEO" 的向量接近

实验结果

方法 Top-5 准确率 Top-20 准确率 Top-100 准确率
BM25 43.2% 59.1% 73.7%
DPR 67.5% 79.4% 86.0%

提升:Top-20 准确率从 59.1% 提升到 79.4%(+20.3%)


2.2 GraphRAG: 知识图谱增强的检索

资料: Microsoft GraphRAG Project
技术层面: 🎭 Agent 编排 + ⚡ LLM 推理

2.2.1 传统 RAG 的局限性

问题:缺乏全局理解

文档集:
- 文档1: "张三是公司A的CEO"
- 文档2: "公司A收购了公司B"  
- 文档3: "公司B的CTO是李四"
- 文档4: "王五是公司A的董事"

用户问题:"公司A的高管都有谁?"

传统RAG:
1. 向量检索找到文档1和文档4
2. 回答:"张三(CEO)和王五(董事)"

遗漏:李四(因为公司A收购了公司B,李四也是公司A的高管!)

问题本质:传统 RAG 只能进行局部匹配,无法进行多跳推理

2.2.2 GraphRAG 是怎么做的?

GraphRAG 构建知识图谱,将关系显式化:

┌────────────────────────────────────────────────────────────┐
│                    GraphRAG 流程                            │
│                                                             │
│  ┌─────────┐    ┌──────────────┐    ┌─────────────────┐    │
│  │原始文档  │ ─→ │ LLM实体抽取  │ ─→ │  知识图谱构建    │    │
│  └─────────┘    └──────────────┘    └─────────────────┘    │
│                                              │              │
│                                              ▼              │
│                                     ┌─────────────────┐    │
│                                     │  社区检测        │    │
│                                     │ (Leiden算法)     │    │
│                                     └─────────────────┘    │
│                                              │              │
│                                              ▼              │
│                                     ┌─────────────────┐    │
│                                     │  层级摘要生成    │    │
│                                     └─────────────────┘    │
└────────────────────────────────────────────────────────────┘

步骤一:实体和关系抽取

使用 LLM 从文档中提取实体和关系:

EXTRACTION_PROMPT = """
从以下文本中提取所有实体和它们之间的关系。

文本:{text}

输出格式(JSON):
{
  "entities": [
    {"name": "实体名", "type": "类型", "description": "描述"}
  ],
  "relationships": [
    {"source": "实体1", "target": "实体2", "relation": "关系类型"}
  ]
}
"""

步骤二:图结构构建

         ┌─────────────────────────────────────┐
         │              知识图谱                │
         │                                      │
         │    [张三] ──CEO──→ [公司A] ←──董事── [王五]
         │                      │               │
         │                    收购              │
         │                      ▼               │
         │                  [公司B]             │
         │                      ↑               │
         │                    CTO               │
         │                      │               │
         │                   [李四]             │
         └─────────────────────────────────────┘

步骤三:社区检测与摘要

使用 Leiden 算法进行图分区,然后为每个社区生成摘要:

Leiden 算法优化目标(模块度):

\[Q = \frac{1}{2m} \sum_{ij} \left[ A_{ij} - \frac{k_i k_j}{2m} \right] \delta(c_i, c_j) \]

其中:

  • \(A_{ij}\) 是邻接矩阵
  • \(k_i\) 是节点 \(i\) 的度
  • \(m\) 是总边数
  • \(\delta(c_i, c_j)\) 在节点 \(i\)\(j\) 同社区时为 1

两种查询模式

模式 适用场景 实现方式
Local Search 具体实体查询 从实体出发遍历子图
Global Search 全局摘要问题 聚合社区摘要

2.2.3 Global Search 示例

问题:"这家公司的整体组织架构是怎样的?"

GraphRAG Global Search:
1. 获取顶层社区摘要
2. 聚合得到全局视图

回答:
"公司A是一家科技企业,由CEO张三领导,董事王五参与治理。
公司A已收购公司B,其CTO李四现也是公司A的技术负责人。
整体形成了CEO-董事-CTO的三级管理架构..."

2.3 Self-RAG: 自主检索策略规划

论文: Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection
技术层面: 🔧 LLM 训练(需要微调模型)

2.3.1 传统 RAG 的问题

问题一:盲目检索

问题:"1+1等于几?"
传统RAG:还是会去检索,浪费资源

问题二:无法评估检索质量

问题:"量子计算的原理是什么?"
检索结果:一篇不相关的文档
传统RAG:直接基于这篇文档生成,导致幻觉

2.3.2 Self-RAG 是怎么做的?

Self-RAG 训练模型学会自我反思,使用特殊的反思令牌:

┌────────────────────────────────────────────────────────────┐
│                   Self-RAG 反思令牌                         │
│                                                             │
│  [Retrieve] ── 是否需要检索?                               │
│      │         Yes: 需要检索                                │
│      │         No: 不需要                                   │
│      │         Continue: 继续当前生成                        │
│      ▼                                                      │
│  [IsRel] ─── 检索内容是否相关?                              │
│      │       Relevant / Irrelevant                         │
│      ▼                                                      │
│  [IsSup] ─── 生成内容是否有检索支持?                        │
│      │       Fully Supported / Partially / No Support       │
│      ▼                                                      │
│  [IsUse] ─── 生成内容对用户是否有用?                        │
│              Useful(1-5分)                                  │
└────────────────────────────────────────────────────────────┘

生成过程的形式化定义

设输入为 \(x\),输出为 \(y\),检索结果为 \(d\),反思令牌为 \(r\)

\[P(y, r | x, d) = \prod_{t=1}^{T} P(y_t, r_t | x, d, y_{<t}, r_{<t}) \]

训练目标同时优化生成和反思:

\[\mathcal{L} = \mathcal{L}_{\text{generate}} + \lambda \cdot \mathcal{L}_{\text{reflect}} \]

训练数据构建

使用 Critic 模型自动标注:

# Critic 模型标注示例
def annotate_with_critic(query, document, generation):
    # 判断是否相关
    is_relevant = critic_model(
        f"文档与问题是否相关?\n问题:{query}\n文档:{document}"
    )
    
    # 判断是否有支持
    is_supported = critic_model(
        f"回答是否有文档支持?\n回答:{generation}\n文档:{document}"
    )
    
    # 判断是否有用
    is_useful = critic_model(
        f"这个回答对用户有用吗?评分1-5\n问题:{query}\n回答:{generation}"
    )
    
    return is_relevant, is_supported, is_useful

2.3.3 推理时的自适应检索

输入:"法国的首都是哪里?"

步骤1: 模型生成 [Retrieve]
       输出: No (这是常识问题,不需要检索)
       
步骤2: 直接生成答案
       输出: "法国的首都是巴黎。"
       
步骤3: 生成 [IsUse]
       输出: [5] (非常有用)

---

输入:"2024年诺贝尔化学奖得主的研究方向是什么?"

步骤1: 模型生成 [Retrieve]
       输出: Yes (需要实时信息)
       
步骤2: 执行检索,获取文档
       
步骤3: 模型生成 [IsRel]
       输出: Relevant
       
步骤4: 生成答案
       输出: "2024年诺贝尔化学奖授予了..."
       
步骤5: 生成 [IsSup]
       输出: Fully Supported
       
步骤6: 生成 [IsUse]
       输出: [5]

2.3.4 与其他 RAG 变体对比

方法 检索策略 质量评估 训练要求
Naive RAG 总是检索
FLARE 低置信度时检索
Self-RAG 自主判断 多维度评估 需要微调

第三部分:记忆系统(Memory)

3.1 Generative Agents: 生成式智能体的社会行为模拟

论文: Generative Agents: Interactive Simulacra of Human Behavior
技术层面: 🎭 Agent 编排 + 📝 提示词工程

3.1.1 过去 NPC/智能体是怎么做的?

有限状态机(FSM)方法

        ┌──────┐      看到敌人      ┌──────┐
        │ 巡逻  │ ─────────────────→ │ 攻击  │
        └──────┘                    └──────┘
            ↑                           │
            │        敌人死亡           │
            └───────────────────────────┘

行为树(Behavior Tree)方法

                    [根节点]
                       │
         ┌─────────────┼─────────────┐
         ▼             ▼             ▼
    [检查血量]    [检查敌人]     [巡逻]
         │             │
    低于20%?     存在敌人?
         │             │
    [逃跑]        [攻击]

局限性

  • 行为预设、不灵活
  • 无法记忆过去事件
  • 无法进行社交对话
  • 无法展现个性

3.1.2 Generative Agents 是怎么做的?

设计了三大核心机制:观察、反思、规划

┌─────────────────────────────────────────────────────────────┐
│               Generative Agent 认知架构                      │
│                                                              │
│   ┌────────────┐                                            │
│   │  感知环境   │ ──→ 观察事件 ──→ ┌──────────────┐          │
│   └────────────┘                  │              │          │
│                                   │   记忆流     │          │
│   ┌────────────┐                  │  (Memory     │          │
│   │  规划系统   │ ←──────────────→│   Stream)    │          │
│   └────────────┘                  │              │          │
│        │                          └──────────────┘          │
│        │                                 ↓                  │
│        ▼                          ┌──────────────┐          │
│   ┌────────────┐                  │   反思系统    │          │
│   │  执行行动   │                  │ (高层洞察)    │          │
│   └────────────┘                  └──────────────┘          │
│                                                              │
└─────────────────────────────────────────────────────────────┘

(1)记忆流(Memory Stream)

每条记忆包含三个属性:

class Memory:
    description: str      # "Klaus 正在画画"
    timestamp: datetime   # 2024-01-15 14:30
    importance: float     # 重要性评分 (0-10)

重要性评分由 LLM 判断:

IMPORTANCE_PROMPT = """
在1-10的范围内,评估以下事件对于当事人的重要性:
1 = 完全普通(如:早上刷牙)
10 = 极其重要(如:结婚、亲人去世)

事件:{event}

重要性评分:
"""

(2)记忆检索

当智能体需要回忆时,使用综合评分检索相关记忆:

\[\text{Score}(m) = \alpha \cdot \text{Recency}(m) + \beta \cdot \text{Importance}(m) + \gamma \cdot \text{Relevance}(m) \]

其中:

  • 时效性(Recency):指数衰减

\[\text{Recency}(m) = e^{-\lambda \cdot (t_{\text{now}} - t_m)} \]

  • 重要性(Importance):LLM 评分,归一化到 [0, 1]

  • 相关性(Relevance):查询与记忆的余弦相似度

\[\text{Relevance}(m, q) = \frac{E(m) \cdot E(q)}{\|E(m)\| \cdot \|E(q)\|} \]

(3)反思机制

定期从记忆中提取高层次洞察:

REFLECTION_PROMPT = """
以下是 {agent_name} 最近的一些记忆:

{memories}

基于以上记忆,你能得出关于 {agent_name} 的什么高层次结论?
请列出3个洞察,每个洞察一句话。
"""

反思示例

记忆片段:
- "Klaus 早上 8 点开始画画"
- "Klaus 买了新的画笔和颜料"  
- "Klaus 跳过午饭继续画画"
- "Klaus 在画廊待了 3 小时"

反思结果:
1. Klaus 对艺术充满热情,画画是他最重要的事
2. Klaus 愿意为艺术投入时间和金钱
3. Klaus 可能是专业画家或有志成为画家

(4)规划系统

自顶向下分解计划:

日计划 → 小时计划 → 分钟级行动

示例:
日计划:今天要完成油画作品
  └→ 09:00-12:00: 在工作室画画
        └→ 09:00: 准备画具
        └→ 09:30: 绘制轮廓
        └→ 10:00: 上色
        └→ 11:30: 细节修饰
  └→ 12:00-13:00: 午餐
  └→ 13:00-17:00: 继续创作

3.1.3 涌现的社会行为

在 Smallville 实验中(25 个智能体),观察到:

涌现行为 说明
信息传播 一个智能体告诉另一个的消息会口口相传
关系形成 智能体记住过去的对话,形成友谊
协调活动 多个智能体自发组织派对
冲突记忆 智能体记住谁曾经伤害过自己

3.2 MemGPT: 面向无限上下文的记忆管理

论文: MemGPT: Towards LLMs as Operating Systems
技术层面: 🎭 Agent 编排 + 📝 提示词工程

3.2.1 LLM 上下文窗口的问题

问题:固定长度的上下文窗口

GPT-4:         128K tokens
Claude:        200K tokens
Llama 2:       4K tokens

问题1:超长对话会被截断
问题2:重要信息可能被挤出窗口
问题3:无法持久化跨会话记忆

传统解决方案的局限

方案 问题
截断旧消息 丢失重要历史信息
摘要压缩 细节丢失,无法还原
增大窗口 计算成本二次增长 \(O(n^2)\)

3.2.2 MemGPT 是怎么做的?

核心思想:借鉴操作系统的虚拟内存

操作系统虚拟内存                    MemGPT 记忆系统
─────────────────                   ────────────────
CPU 寄存器 (极快)                   核心记忆 (始终在 Prompt)
    ↕                                   ↕
主内存 RAM (快)                     主上下文 (当前对话)
    ↕                                   ↕
硬盘 SSD (慢)                       外部存储 (数据库)

分层记忆架构

┌─────────────────────────────────────────────────────────────┐
│                     主上下文窗口                             │
│  ┌────────────────────────────────────────────────────────┐ │
│  │ System Prompt: 你是一个有记忆的AI助手...               │ │
│  ├────────────────────────────────────────────────────────┤ │
│  │ 核心记忆 (Core Memory):                                │ │
│  │   - 用户偏好: {"name": "小明", "likes": "编程"}       │ │
│  │   - AI人设: {"personality": "友好", "style": "专业"}  │ │
│  ├────────────────────────────────────────────────────────┤ │
│  │ 消息队列 (FIFO Buffer):                                │ │
│  │   - [最近的10条对话消息]                               │ │
│  └────────────────────────────────────────────────────────┘ │
│                            ↑                                 │
│                            │ 函数调用                        │
│                            ↓                                 │
│  ┌────────────────────────────────────────────────────────┐ │
│  │ 外部存储:                                               │ │
│  │   - 对话历史数据库 (全部历史)                          │ │
│  │   - 归档记忆数据库 (长期知识)                          │ │
│  └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘

核心函数定义

# 核心记忆操作
def core_memory_append(key: str, value: str) -> str:
    """向核心记忆追加信息"""
    memory[key] += value
    return f"已添加到 {key}"

def core_memory_replace(key: str, old_value: str, new_value: str) -> str:
    """更新核心记忆中的信息"""
    memory[key] = memory[key].replace(old_value, new_value)
    return f"已更新 {key}"

# 对话历史搜索
def conversation_search(query: str, limit: int = 10) -> List[str]:
    """搜索历史对话"""
    results = vector_db.search(query, limit=limit)
    return [r.content for r in results]

# 归档记忆操作
def archival_memory_insert(content: str) -> str:
    """将信息存入归档记忆"""
    archive_db.insert(content)
    return "已归档"

def archival_memory_search(query: str, limit: int = 10) -> List[str]:
    """搜索归档记忆"""
    results = archive_db.search(query, limit=limit)
    return [r.content for r in results]

自主记忆管理的 Prompt

MEMGPT_SYSTEM_PROMPT = """
你是一个有持久记忆的AI助手。你的记忆分为几个部分:

1. 核心记忆 (Core Memory): 始终可见,存储关键信息
   当前内容:{core_memory}

2. 对话历史 (Recall Storage): 所有历史对话
   使用 conversation_search(query) 搜索

3. 归档记忆 (Archival Storage): 长期知识存储
   使用 archival_memory_search(query) 搜索
   使用 archival_memory_insert(content) 存储

你可以随时调用这些函数来管理记忆。当:
- 用户提到重要信息 → 使用 core_memory_append 保存
- 需要回忆过去对话 → 使用 conversation_search
- 需要长期存储知识 → 使用 archival_memory_insert
"""

3.2.3 实际对话示例

用户:我叫小明,最喜欢Python编程

MemGPT 内部思考:
<function_call>
  core_memory_append(
    key="user_info", 
    value="用户名:小明;爱好:Python编程"
  )
</function_call>

MemGPT:很高兴认识你,小明!Python是一门很棒的语言。

--- 三天后 ---

用户:你还记得我喜欢什么吗?

MemGPT 内部:
(查看核心记忆,发现 user_info 包含信息)

MemGPT:当然记得,小明!你喜欢Python编程。上次我们聊过这个。

--- 用户问了一个复杂问题 ---

用户:我之前问过你一个关于异步编程的问题,具体是什么来着?

MemGPT 内部:
<function_call>
  conversation_search("异步编程")
</function_call>
返回:["2024-01-10: 用户问如何用asyncio处理并发请求..."]

MemGPT:找到了!在1月10日,你问过如何用asyncio处理并发请求...

3.2.4 与传统方法的数学对比

传统 LLM 的上下文限制

\[\text{可用上下文} = \min(L_{\text{model}}, L_{\text{history}}) \]

其中 \(L_{\text{model}}\) 是模型最大上下文长度。

\(L_{\text{history}} > L_{\text{model}}\) 时,必须截断。

MemGPT 的虚拟上下文

\[\text{虚拟上下文} = L_{\text{core}} + f(\text{external storage}) \]

其中:

  • \(L_{\text{core}}\) 是核心记忆大小(固定)
  • \(f(\cdot)\) 是按需检索函数

复杂度分析

方法 空间复杂度 检索复杂度
全量上下文 \(O(n)\) \(O(1)\)
截断 \(O(k)\), \(k\) 固定 \(O(1)\)
MemGPT \(O(k)\) 主存 + \(O(n)\) 外存 \(O(\log n)\) 向量检索

总结:技术层面分类汇总

按技术作用层面分类

论文 🔧 训练 ⚡ 推理 🎭 编排 📝 提示词
ReAct
Reflexion
Tree of Thoughts
AutoGen
DPR
GraphRAG
Self-RAG
Generative Agents
MemGPT

关键洞察

  1. 无需训练的创新:ReAct、Reflexion、ToT、AutoGen、Generative Agents、MemGPT 都不需要修改 LLM 权重,仅通过提示词和编排即可实现强大功能。

  2. 需要训练的创新:DPR(训练编码器)、Self-RAG(微调生成模型)需要训练,但获得了更强的能力。

  3. 融合趋势:现代系统往往融合多种技术,例如:

    • Agent(ReAct) + RAG(DPR) + Memory(MemGPT)

技术演进路线图

2020  ┌─────────────────┐
      │     DPR         │ ← 密集检索基础
      └────────┬────────┘
               │
2022  ┌────────▼────────┐
      │    ReAct        │ ← 推理+行动范式
      └────────┬────────┘
               │
2023  ┌────────▼────────┬───────────────┬───────────────┐
      │   Reflexion     │      ToT      │    AutoGen    │
      │   (自我反思)    │  (搜索+推理)  │  (多智能体)   │
      └────────┬────────┴───────────────┴───────────────┘
               │
      ┌────────▼────────┬───────────────┐
      │ Generative      │    MemGPT     │
      │ Agents (记忆)   │  (分层记忆)   │
      └────────┬────────┴───────────────┘
               │
      ┌────────▼────────┬───────────────┐
      │   GraphRAG      │   Self-RAG    │
      │ (图谱+检索)     │ (自主检索)    │
      └─────────────────┴───────────────┘
               │
2024           ▼
      ┌─────────────────────────────────┐
      │   融合系统:Agent + RAG + Memory │
      └─────────────────────────────────┘

参考文献

  1. Yao, S., et al. (2022). ReAct: Synergizing Reasoning and Acting in Language Models. arXiv:2210.03629
  2. Shinn, N., et al. (2023). Reflexion: Language Agents with Verbal Reinforcement Learning. arXiv:2303.11366
  3. Yao, S., et al. (2023). Tree of Thoughts: Deliberate Problem Solving with Large Language Models. arXiv:2305.10601
  4. Wu, Q., et al. (2023). AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation. arXiv:2308.08155
  5. Karpukhin, V., et al. (2020). Dense Passage Retrieval for Open-Domain Question Answering. arXiv:2004.04906
  6. Microsoft Research. (2024). GraphRAG: A modular graph-based Retrieval-Augmented Generation system.
  7. Asai, A., et al. (2023). Self-RAG: Learning to Retrieve, Generate, and Critique through Self-Reflection. arXiv:2310.11511
  8. Park, J.S., et al. (2023). Generative Agents: Interactive Simulacra of Human Behavior. arXiv:2304.03442
  9. Packer, C., et al. (2023). MemGPT: Towards LLMs as Operating Systems. arXiv:2310.08560
posted @ 2025-12-26 17:27  b1uesk9  阅读(0)  评论(0)    收藏  举报