Zhangzhe's Blog

The projection of my life.

0%

URL

TL;DR

  • 本文提出了 RT-1 模型,本质是一个输入连续 6 帧图像 + 一句语言指令,输出是 11 维动作空间的 VLA 模型,控制一个有可移动底座和一个手臂的机器人,也就是说,RT-1 实际上是一个 小脑模型(执行控制模型,输入是相对简单的指令,输出是精细动作控制信号)
  • RT-1 首次证明大规模 Transformer 模型在机器人控制的可行性:通过​​任务无关训练​​、​​高效架构设计​​及​​异构数据融合​​,实现 700+任务的 97% 成功率及显著零样本泛化能力
  • 整个模型非常轻量,只有 35M 的参数

Algorithm

网络结构

rt1_2.png

  • 模型大概由四部分组成:
​​模块​​ ​​输入形状​​ ​​输出形状​​ ​​关键说明​​
Universal Sentence Encoder 文本字符串 512维向量 语言语义编码
FiLM EfficientNet-B3 6×300×300×3(图像) + 512 486×512 每帧生成81个视觉Token
TokenLearner 486×512 48×512 压缩至8 Token/帧
Transformer 48×512(+位置编码) 11×256 输出离散化动作分布

模型输出

  • 输出 11 维动作空间,每个动作空间都是离散的 256 个值
  • 11 个动作空间分别表示:
    • 1 个离散维度用于控制模式切换:
      • 控制底座
      • 控制手臂
      • 终止
    • 7 个维度控制机械臂:
      • 末端位置:x, y, z
      • 末端姿态:roll, pitch, yaw
      • 抓夹:开合度
    • 3 个维度控制底座:
      • 位置:x, y
      • 旋转角度:yaw

数据集

Thoughts

  • 模型很简单,数据很简单,训练范式也很简单,但泛化能力很强
  • RT-1 数据开源,推动具身智能社区发展

URL

TL;DR

  • 这篇论文构建了一个单一的通用智能体 Gato,它具有多模态、多任务、多实施方式能力,是一个纯端到端的智能体,甚至可以直接给出机械臂动作控制指令。
  • 模型就是 1.2B 参数的 decoder only Transformer 架构,只用一份权重可以玩 Atari 游戏、给图片加字幕、控制机械手臂堆叠积木等 604 个任务。

Algorithm

Gato.png

编码方案

Gato 将所有模态的输入和输出都编码为整数序列,输出除了不能输出图像之外,其他模态都可以输出。

  • 文本:通过 SentencePiece 方式编码,共 32000 个子单词编码为整数范围 [0, 32000)
  • 图像:按照 ViT 的编码方式,切成不重叠的 16x16patches
  • 离散值:存储为 [0, 1024) 的整数序列
  • 连续值: 离散化为 1024 个箱子,并移到 [32000, 33024) 的范围

训练和部署方案

  1. 使用 decoder only Transformer 架构,做自回归训练,图像切成 16x16patches 后,归一化到 [-1, 1] 之间,再用 Resnet 将图像编码成多个特征向量和其他模态的特征向量拼接起来,作为输入。
  2. 什么参与自回归训练?什么不参与?
    • 参与自回归训练的:文本符元、离散和连续值以及动作
    • 不参与自回归训练的:图像、智能体观测到的非文本信息(比如机械臂的关节参数等)
  3. 训练结束后,模型能做什么?
    • 训练时候没有屏蔽什么,训练收敛的模型就能做什么。
  4. 训练时固定上下文长度为 1024,超过 1024 的数据会被随机截取 1024
  5. 推理时不限制上下文长度
    gato2.png

实验结果

  • 604 项任务中,有 450 项任务能够达到专家分数的 50%
  • 论文中有每个任务类型的详细结果,可以参考论文

Thought

  • 把这么多种任务抽象成一种编码,然后用一个 1.2B 参数的模型来处理,这个想法很厉害
  • 编码方式有点复杂,可以对比下将图片之外的模态转成文本,然后用 tokenizer 编码的最终效果

URL

TL;DR

  • 本文证明传统 SFT 过程常用的 Cross Entropy Loss 的梯度等价于 Reinforcement Learning 中策略梯度更新,但隐含一个病态的奖励结构:稀疏奖励和逆概率权重结合,导致 模型对低概率样本过拟合
  • 解决方案特别简单:在每个 token 的损失前乘当前 token 的概率作为权重

Algorithm

公式角度

  • 传统 SFT 过程的损失函数:

θLSFT(θ)=Ex,yπθ[1πθ(yx)逆概率权重1[y=y]稀疏奖励θlogπθ(yx)]\nabla_{\boldsymbol{\theta}}\mathcal{L}_{\mathrm{SFT}}(\boldsymbol{\theta}) = - \mathbb{E}_{x,y \sim \pi_{\boldsymbol{\theta}}} \left[ \underbrace{\frac{1}{\pi_{\boldsymbol{\theta}}(y \mid x)}}_{\text{逆概率权重}} \cdot \underbrace{\mathbb{1}[y = y^{*}]}_{\text{稀疏奖励}} \cdot \nabla_{\boldsymbol{\theta}} \log \pi_{\boldsymbol{\theta}}(y \mid x) \right]

  • DFT 损失函数:

LDFT=E(x,y)Dt=1ysg(πθ(yty<t,x))logπθ(yty<t,x)\mathcal{L}_{\mathrm{DFT}} = - E_{\left(x, y^{*}\right)\sim\mathcal{D}} \sum_{t=1}^{\left|y^{*}\right|} \mathrm{sg}\left(\pi_{\theta}\left(y_{t}^{*}\mid y_{<t}^{*},x\right)\right) \log\pi_{\theta}\left(y_{t}^{*}\mid y_{<t}^{*},x\right)

  • 注意:这里的 sgstop gradient 操作,即不计算梯度 对应 pytorch 中常用的 .detach() 操作

代码角度

 2025-08-10 154116.png

  • a 表示预测序列中某个位置的的 logits
  • b 表示对应位置的 GT
  • cross entropy loss 就是 -log(softmax(a))[b]
  • DFT 损失函数就是 -(softmax(a) * log(softmax(a)))[b],但注意要 stop gradientsoftmax(a) 只作为系数,反向传播不优化。

函数角度

dft2.png

  • 蓝色是标准 SFT 过程的损失函数(交叉熵)
  • 红色是本文提出的 DFT 损失函数
  • 绿色是我自己脑补的 DFT 函数扩展之后的损失函数,优点是比 DFT 对称性更好,效果怎么样不知道…
  • 从函数角度看,SFT 在某个位置 GT 非常冷门的情况下,-log(softmax(a)) 会趋向于 inf,导致模型对这个冷门的 token 做了过大的参数更新,这是不合理的(因为模型已经经过了预训练,用非常低的概率预测 GT 说明这个 GT 可能是噪声)。
  • DFT 的函数可以看出,模型 优先关注不过分难或过分简单的 token,太难的可能是数据噪声,太简单的本身就没什么好学的。

Thoughts

  • 从函数角度看:太难的我不学,因为太难;太简单的我不学,因为太简单。
  • 郭德纲:我有四不吃…😂😂😂

URL

TL;DR

  • langchainSemi-structured RAGdemo,包含 PDF 的 解析 -> 向量化 -> 存储 -> 检索 -> 回答 的全流程
  • 来自 langchain 官方的 cookbook,值得参考

总体流程

langchain_rag_demo.png

  1. 解析 PDF 文件。用 partition_pdf 工具,将 PDF 文件解析为 chunks,分成文本和表格两种
  2. 总结 chunks。用大模型 API 总结 chunks,得到 summary,用哪家的模型都行
  3. 向量化 summary。调用 embedding 模型 APIsummary 进行向量化,作为索引的 keyvalue 是原始文本/表格),存到 Chroma 数据库中
  4. 问答时自动检索。在问答时,会自动根据问题向量在 Chroma 数据库中检索出最相似的 summary,将 summary 向量对应的原始文本/表格作为 prompt 中的 context 域传给大模型,得到回答

具体实现代码

1. 解析 PDF 文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from typing import Any

from pydantic import BaseModel
from unstructured.partition.pdf import partition_pdf

path = "/Users/rlm/Desktop/Papers/LLaMA2/"
# Get elements
raw_pdf_elements = partition_pdf(
filename=path + "LLaMA2.pdf",
# Unstructured first finds embedded image blocks
extract_images_in_pdf=False,
# Use layout model (YOLOX) to get bounding boxes (for tables) and find titles
# Titles are any sub-section of the document
infer_table_structure=True,
# Post processing to aggregate text once we have the title
chunking_strategy="by_title",
# Chunking params to aggregate text blocks
# Attempt to create a new chunk 3800 chars
# Attempt to keep chunks > 2000 chars
max_characters=4000,
new_after_n_chars=3800,
combine_text_under_n_chars=2000,
image_output_dir_path=path,
)

2. 总结 chunks 得到 summary

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

# Prompt
prompt_text = """You are an assistant tasked with summarizing tables and text. \
Give a concise summary of the table or text. Table or text chunk: {element} """
prompt = ChatPromptTemplate.from_template(prompt_text)

# Summary chain
model = ChatOpenAI(temperature=0, model="gpt-4")
summarize_chain = {"element": lambda x: x} | prompt | model | StrOutputParser()

# Apply to tables
tables = [i.text for i in table_elements]
table_summaries = summarize_chain.batch(tables, {"max_concurrency": 5})

# Apply to texts
texts = [i.text for i in text_elements]
text_summaries = summarize_chain.batch(texts, {"max_concurrency": 5})

langchain| 符号就可以把多个工具串成一个 chain,非常方便

3. 向量化 summary 并存到 Chroma 数据库中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import uuid

from langchain.retrievers.multi_vector import MultiVectorRetriever
from langchain.storage import InMemoryStore
from langchain_chroma import Chroma
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings

# The vectorstore to use to index the child chunks
vectorstore = Chroma(collection_name="summaries", embedding_function=OpenAIEmbeddings())

# The storage layer for the parent documents
store = InMemoryStore()
id_key = "doc_id"

# The retriever (empty to start)
retriever = MultiVectorRetriever(
vectorstore=vectorstore,
docstore=store,
id_key=id_key,
)

# Add texts
doc_ids = [str(uuid.uuid4()) for _ in texts]
summary_texts = [
Document(page_content=s, metadata={id_key: doc_ids[i]})
for i, s in enumerate(text_summaries)
]
retriever.vectorstore.add_documents(summary_texts)
retriever.docstore.mset(list(zip(doc_ids, texts)))

# Add tables
table_ids = [str(uuid.uuid4()) for _ in tables]
summary_tables = [
Document(page_content=s, metadata={id_key: table_ids[i]})
for i, s in enumerate(table_summaries)
]
retriever.vectorstore.add_documents(summary_tables)
retriever.docstore.mset(list(zip(table_ids, tables)))

4. 问答时自动检索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from langchain_core.runnables import RunnablePassthrough

# Prompt template
template = """Answer the question based only on the following context, which can include text and tables:
{context}
Question: {question}
"""
prompt = ChatPromptTemplate.from_template(template)

# LLM
model = ChatOpenAI(temperature=0, model="gpt-4")

# RAG pipeline
chain = (
{"context": retriever, "question": RunnablePassthrough()}
| prompt
| model
| StrOutputParser()
)

# run the chain
chain.invoke("What is the number of training tokens for LLaMA2?")

总结

  1. langchain 做了非常多的工具,并给出一种将这些工具非常容易组合使用的方法
  2. 更重要的是,langsmith 提供了非常方便的 trace 功能,可以非常方便地追踪一次问答过程中经过了哪些模型/工具/行为,以及这些模型/工具/行为的 input / output / 耗时等,非常方便

URL

TL;DR

  • Qwen2.5-VLQwen 团队推出的一个多模态大模型,在 Qwen2.5 的基础上,增加了视觉模态的支持,输入支持 textimagevideo 的混合输入,输出为 text

Algorithm

qwen2.5-vl.png

模型架构

  • 视觉编码器(Vision Encoder):基于重新设计的 Vision TransformerViT),处理原生分辨率的图像和视频输入
  • 语言模型(Large Language ModelLLM):基于 Qwen2.5 LLM,负责文本理解和生成,初始化时预训练权重被微调以支持多模态任务
  • 视觉-语言合并器(Vision-Language Merger):一个 MLP-based 模块,压缩视觉特征以匹配文本嵌入维度,减少计算开销

三阶段训练

第一阶段

  • 随机初始化 Vision Encoder 开始训练
  • 使用的 (text, image) 数据如下:
    • Image captions:图像和对应的文本描述
    • Visual knowledge: 涵盖名人、地标、动植物等识别数据,帮助模型积累视觉常识
    • OCR 数据:从图像中提取的文本信息
  • 用了 CLIP 作为优化目标,对齐 ViTQwen2.5text 模态
  • token 长度为 8k,数据规模为 1.5T tokens

第二阶段

  • ViTQwen2.5 的联合预训练
  • token 长度为 8k,数据规模为 2T tokens

第三阶段

  • 长上下文优化,目标是视频/文档序列理解
  • token 长度为 32k,数据规模为 0.6T tokens

关键技术解析

1. 动态 ViT 架构

  • 输入尺寸自适应:图像按 14×14 分块,尺寸调整为 28 的倍数
  • 窗口注意力:32 层中仅 4 层用全局注意力,其余用 112×112 窗口注意力(计算复杂度从 O(n²) 降至 O(n)
  • 位置编码:2D 旋转位置嵌入(RoPE)保留空间关系

2. 多模态动态处理

  • 空间维度:
    • 原生分辨率坐标:直接使用图像实际尺寸表示物体位置(非相对坐标)
    • 支持 JSON/XML 格式输出,兼容开放词汇检测(10,000+ 类别)
  • 时间维度:
    • 动态帧率采样:适应不同速度的视频内容
    • 绝对时间对齐:RoPE 时间 ID 与时间戳直接绑定,理解事件节奏(图1机制)

3. 多模态位置编码(MRoPE)​

  • 三维分解:时间、高度、宽度独立位置 ID
  • 视频处理:时间 ID 按帧递增,空间 ID 与静态图像一致
  • 升级点:时间 ID 关联绝对时间戳,解决 Qwen2-VL 的时序理解局限

性能

  • 共有 3B / 7B / 72B 三个尺寸
    qwen2.5-vl_2.png

Thoughts

  • VLM 将视觉信息融入语言模态,重点还是 LM

URL

TL;DR

  • 标题是 “用于端到端分层序列建模的动态分块” ,实际上包含了不少信息量:
    • “端到端”:意味着 token free,真正的端到端语言模型,输入输出都是字节流,不需要 tokenization 过程
    • “分层”:意味着 H-Net 模型结构是 递归 的,H-Net 模型由 encoder + main network + decoder 组成,其中 main network 还可以是 H-Net 模型
    • “动态分块”:意味着 H-Net 模型可以动态地调整 chunk 的大小,可以理解为维护了一个隐式的动态 tokenizer,模型会在学习过程中找到最优的隐式分词方法
  • 本质是一个基于 SSM + Transformer 结构的大模型,抛弃了 tokenization 过程,直接在字节流上进行训练和推理

Algorithm

H-Net 总体结构

hnet.png

现有的分词机制的缺陷

  • 当前主流语言模型(如 ChatGPT )依赖预定义的分词器(如 BPE ),存在以下问题:
    • 语义割裂​​:分词器基于统计规则,无法根据上下文动态调整边界(如将 “product” 错误拆分为 “pro-duct” )
    • 跨语言/模态适配性差​​:在中文、代码或 DNA 序列等缺乏显式分隔符的领域表现不佳
  • 直接字节级建模(如 MambaByte ),计算开销巨大,且性能低于分词模型
  • 一些启发式分块规则(如 MegaByteSpaceByte)依赖​​启发式分块规则​​(如固定步长或空格分隔),无法学习数据驱动的分块策略,限制了模型对复杂信息的表达能力

H-Net 的解决方案

层级化处理架构(U-Net 式设计)​​

  • 三级模块
    • 编码器(E)​​:处理原始字节(小规模 SSM 层,高效捕获细粒度特征)
    • 主网络(M)​​:处理压缩后的语义块(大规模 Transformer 层,学习高层抽象)
    • 解码器(D)​​:恢复原始分辨率(SSM 层)
  • 递归扩展​​:主网络可嵌套 H-Net 自身,形成多级抽象(如字符 → 词 → 短语)

Encoder Network

  1. 路由模块(Routing Module
    • 用相邻向量的余弦相似度判断是否需要分块
    • pt=12(1sim(qt,kt1))p_t=\frac{1}{2}(1-sim(q_t,k_{t-1}))
      • tt 表示 position
      • qq 表示 query
      • kk 表示 key
      • simsim 表示余弦相似度
      • ptp_t 表示当前位置分块概率
    • 当相邻向量语义变化大时,ptp_t 会趋近于 1,表示需要分块
  2. 下采样模块(Downsampler
    • 将上一步分块的序列下采样
    • 具体使用的下采样方式是 只保留路由模块选定的边界向量,其他向量直接丢弃

Main Network

  • 一个最常见的 Transformer 结构
  • 输入是 Encoder Network 输出的下采样后的向量
  • 输出和输入的 shape 相同

Decoder Network

  1. 平滑模块(Smoothing Module
    • 用指数移动平均法解决离散决策的梯度不可导问题
    • zˉt=Pz^t1+(1Pt)zˉt1\bar z_t=P\cdot \hat z_{t-1}+(1-P_t)\cdot \bar z_{t-1}
      • PtP_t 表示当前位置分块概率
      • z^t\hat z_t 表示主网络输出的压缩向量
      • zˉt1\bar z_{t-1} 表示上一步平滑后的向量
      • zˉt\bar z_t 表示平滑后的向量
  2. 上采样模块(Upsampler

    ct={ptif bt=11ptif bt=0c_t=\left\{ \begin{array}{l} p_t & \text{if}\ b_t=1 \\ 1- p_t & \text{if}\ b_t=0 \end{array} \right.

    Upsamplert=STE(ct)z~t\text{Upsampler}_t = STE(c_t)\cdot \tilde z_t

    • btb_t 表示当前位置是否分块,bt=1b_t=1 表示分块,bt=0b_t=0 表示不分块
    • ptp_t 表示当前位置分块概率
    • ctc_t 表示当前位置 main network 输出的置信度
    • z~t\tilde z_t 表示当前位置 main network 输出的向量 复制到原始分辨率

效果

  • 效果比 tokenization 更好
  • 在语言、代码、DNA等异构数据中验证普适性,为多模态基础模型提供新范式

Thoughts

  • 能看出 SSM 模型已经开始改变战略,从正面和 Transformer 硬刚到 曲线救国
  • STE 真是个万金油,哪哪都有它

URL

TL;DR

  • 本文提出一种新的缓存利用机制 CacheBlend,旨在解决 RAG 系统中知识 KV Cache 的可用性,通过一种稀疏近似的方式平衡速度和准确性。

Algorithm

知识注入的两种常见方式

1. 微调

  • 收集知识库中的文档数据,微调模型,使其能够在生成文本时利用这些知识。
  • 优点:推理时不会有额外的延迟。
  • 缺点:
    1. 动态更新困难
    2. 模块化困难(无法要求模型使用哪些知识,不用哪些知识)

2. 知识检索

  • 在推理时,检索相关文档并将其作为上下文输入到模型中。
  • 优点:动态更新知识库,模块化。
  • 缺点:推理时需要额外的延迟,一是因为检索本身的延迟,二是因为模型需要计算额外的上下文注意力。

如何同时解决模块化和速度的问题?

  • 如果在知识检索技术的基础上,检索系统提前缓存了 知识库中文档对应的 KV Cache,那么就可以在推理时直接使用这些 KV Cache 无需计算这部分的注意力(只需要检索延迟)。

这样做有什么问题?

  • 一个很重要的问题是:优于现如今绝大多数 LLMdecoder only 架构,缓存的知识库的 KV Cache 必须作为 prefix 注入到模型中,且只能用一个,否则模型无法利用这些知识。
  • 例如:
    • 记检索到的文档的 KV CacheA,历史对话信息和用户输入为 B
    • 那么模型的输入应该是 A + B,而不是 B + A
    • 因为 KV Cache 位置 i 的值依赖于 0 ~ i-1 位置的值,如果不作为 prefix 注入,那么模型无法利用这些知识。

cacheblend_2.png
cacheblend_3.png

CacheBlend 想要解决的问题

  • CacheBlend 目的就是为了 解决 RAG 系统中知识 KV Cache 只能作为 prefix 注入的问题
  • CacheBlend 做不到和完全重新计算数学上等价,只能是近似
  • 原理本质上讲是平衡,即 在完全重新计算 KV Cache 和完全使用缓存的 KV Cache 之间进行平衡,如下图:

cacheblend.png

CacheBlend 的解决方案

cacheblend_4.png

  • CacheBlend 通过 稀疏近似 的方式,平衡速度和准确性,具体来说,对非 prefixKV Cache,做:
    1. 1 层​​:计算所有 TokenKV 偏差,选择 Top 20% 作为候选 HKVD (High-KV-Deviation) Token
    2. ​后续层​​:仅对前一层的 HKVD Token 计算偏差,从中选择 Top ri% (ri<ri1)Top\ r_i\%\ (r_i < r_{i-1}) 作为当前层 HKVD Token
    3. ​​终止​​:最终每层仅更新约 10-15% Token,偏差显著降低
  • 总体上就是用逐层用新的 KV Cache 替换旧的 KV Cache,替换依据是 KV 偏差,偏差越大的 Token 替换的优先级越高。

CacheBlend 的优势

  • 质量保障​​:仅更新 10-15% Token 即可达到 Full KV Recompute 的质量(F1/Rouge-L 偏差 <0.02
  • ​​延迟隐藏​​:KV 重新计算与 KV 缓存加载流水线并行,使额外延迟近乎为零
  • 提速​​:TTFT (Time To First Token) 降低 2.2 ~ 3.3 倍,吞吐量提升 2.8 ~ 5

Thoughts

  • 稀疏无处不在

URL

TL;DR

  • 大模型并不是全能的,大模型 + 工具可以更好地解决问题,本文提出一种新的训练方法,让大模型可以自我学习使用如何工具。
  • 本文的主要贡献是提出了一种新的训练方法,包括通过大模型构造工具调用数据集、清洗数据集、使用工具调用数据集微调大模型。

Algorithm

ToolFormer 的意义

  1. 众所周知,大模型在很多任务上表现出色,但它们并不是全能的,比如去数 “strawberry” 这个单词中有多少个 “r”。
  2. 工具可以帮助大模型更好地解决问题,比如计算器、日历、知识库等。
  3. 一种常见的大模型和工具结合的方式是:通过 Agent 多角色(user / llm / function)多轮对话 形式调用,简单来说就是:
    1. 大模型在需要调用工具的时候,输出一段特定格式的文本
    2. 外部程序解析这段文本,调用相应的工具,调用得到结果
    3. 新的结果作为 Function 角色的输入,继续和大模型对话
  4. ToolFormer 采用的方式和 Agent 有相似之处,也有不同的地方:
    • 相似点:
      1. 都需要大模型输出一段特定格式的文本来调用工具
      2. 都需要一段 endless loop 程序来解析大模型的输出,调用工具
    • 不同点:
      1. ToolFormer 不是通过 多角色多轮对话 的方式调用工具,而是通过 单角色单轮对话 的方式调用工具
      2. ToolFormer 需要对大模型进行 微调,而 Agent 不需要
  5. ToolFormer 可以将存在确定答案的 专用 任务转化为工具调用任务(例如:计算、翻译、问答等),让大模型可以更专注在 通用 任务上(例如:上下文理解、常识知识运用等)。

ToolFormer 的工作方式

  1. ToolFormer 是经过工具调用微调的大模型,知道有哪些工具可以调用,也知道如何调用这些工具。
  2. 假设模型输入的问题是:
    1
    Pittsburgh is also known as
  3. 这个时候,模型会意识到这个问题可以通过调用 Question Answering 工具来解决,于是模型会续写:
    1
    Pittsburgh is also known as <API>QA(Pittsburgh is also known as)</API>
  4. 输出 </API> 之后,推理进程会暂停推理模型,等待外部监听程序的调用结束。
  5. 外部监听程序会解析模型输出文本中的工具调用指令(通过 <API> </API> 格式),然后调用 Question Answering 工具,得到结果:
    1
    the Steel City
  6. 推理程序将工具调用结果和模型的历史输出(去掉调用相关信息)拼接起来,继续推理模型:
    1
    Pittsburgh is also known as the Steel City.

应该怎么得到 ToolFormer

  1. 假设上面提到的 ToolFormer 工作方式是一个愿景,那么接下来就是考虑应该如何得到一个这样的模型。
  2. 显然,直接拿一个预训练或经过微调的大模型来使用是行不通的,因为它并不知道哪些工具可以用,以及如何调用。
  3. 那么需要做的事就是:通过微调,让大模型自己学习如何使用工具
  4. 最困难的部分就是:如何构造工具调用数据集,因为不存在现成的工具调用数据集,需要自己构造。
  5. 这篇论文花了很大的篇幅就在讲一件事:如何用大模型来构造工具调用数据集

如何构造工具调用数据集

toolformer_1.png

上面这张图展示了如何用大模型来构造工具调用数据集的流程。

  1. 首先,还是用预训练数据做为基础,假设一条预训练数据是:
    1
    Pittsburgh is also known as the Steel City.
  2. 然后,使用大模型(例如:GPT-3)来在数据中找到可以调用工具的位置和工具类型,并给出调用工具的参数,例如:
    1
    Pittsburgh is also known as <API>QA(What other name is Pittsburgh known by?) -> Steel City</API> the Steel City.
    1
    Pittsburgh is also known as <API>QA(Which country is Pittsburgh in?) -> United States</API> the Steel City.
  3. 计算调用工具带来的损失收益,剔除负收益的数据,保留正收益的数据。
    • 损失的计算方式(离调用工具位置越远,损失权重 wjiw_{j-i} 越小):

    Li(z)=j=inwjilogpM(xjz,xi;j1)L_i(z) = -\sum_{j=i}^n w_{j-i}\cdot \log p_M(x_j|z,x_{i;j-1})

    • 调用工具的损失:

    Li+=Li(e(ci,ri))L_i^+=L_i(e(c_i,r_i))

    • 不调用工具 / 调用工具没有返回的损失:

    Li=min(Li(ϵ),Li(e(ci,ϵ)))L_i^- = \min(L_i(\epsilon),L_i(e(c_i,\epsilon)))

    • 只保留调用工具损失收益大于阈值的样本:

    LiLi+>τfL_i^- - L_i^+ > \tau_f

  4. 用筛选后的数据来微调大模型,得到 ToolFormer

toolformer_2.png

  • 上图展示了 ToolFormer 支持的五种工具类型:
    1. Question Answering:问答工具
    2. Wikipedia Search:维基百科搜索工具
    3. Calculator:计算器工具
    4. Calendar:日历工具
    5. Machine Translation:机器翻译工具

Thoughts

  • ToolFormer 这种通过大模型自我学习使用工具的方式感觉挺好的,但似乎在实际使用中没有得到大范围推广,目前主流外挂工具的方式基本还是 Agent 的多角色多轮对话方式。
  • 可能是因为 ToolFormer 的方式需要对大模型进行微调,而 Agent 的方式不需要微调,直接使用预训练模型就可以。

URL

TL;DR

  • 人类通过语言推理(分解目标、调整计划)与行动(获取外部信息)的​​协同机制​​高效完成任务(如烹饪时动态调整步骤)。
  • 受到人类智能启发,本文提出一种 ReasoningActing 相结合的框架,称为 ReAct,这种新的推理范式可以使语言模型在复杂任务中表现更好。
  • 主要优势包括:
    • 事实性:减少模型幻觉(虚构信息)。
    • 决策鲁棒性:增强模型在复杂环境中的泛化能力。
    • 可解释性:人类可以追踪模型的推理轨迹。

Algorithm

ReAct 框架

ReACT.png

  • 纯推理模型(如 Chain-of-Thought)​​:易产生事实幻觉(如虚构信息)和错误传播(如算术推理错误),缺乏实时环境交互能力(图 1b)。
  • ​​纯行动模型(如 WebGPT)​​:缺乏高层规划能力,难以处理多步决策(图1c)。
  • ReAct 模型:交替进行推理和行动,能够在复杂任务中表现更好(图 1d)。

核心贡献​​

  • 首提协同框架​​:统一推理与行动,解决静态推理与无规划行动的缺陷。
  • 实践价值​​:
    • 提升模型​​事实性​​(减少幻觉)与​​决策鲁棒性​​(复杂环境泛化)。
    • 增强​​可解释性​​:人类可追踪推理轨迹。

Thoughts

  • 论文提出的算法一眼开门,非常符合直觉,从哲学角度讲,一个事物的超集一般都优于其本身,因为最差的情况就是超集退化为本身(因此常见的一个情况是:新的论文称一篇老的论文是其某个参数设置下的一个特例)。
  • 这些所有的 ReasoningActingAgent 功能,都建立在大模型超长上下文的基础上,因此模型支持超长上下文长度是模型是否具有高级智能潜质的先决条件(至少现有范式是这样)。

URL

TL;DR

  • 本文是 Google Research 团队发表的一篇论文,这篇论文是在已开源的 非推理 模型上,不做微调,而是通过 Chain-of-Thought Prompting 的方式来引导模型进行推理,取得了很好的效果。
  • 具体来说,就是在输入 prompt 中加入少量的 输入-思维链-输出 三元组示例,引导模型生成中间推理步骤,最终给出答案。
  • 在算术、常识和符号推理等任务上,Chain-of-Thought Prompting 的效果都非常好,比直接给出答案的效果好很多。
  • Chain-of-Thought Prompting 是在模型规模达到一定程度(>= 100B)后,才涌现出的能力,小模型没有这个能力。

论文详情

1. 核心方法:思维链提示(Chain-of-Thought Prompting)

  • 论文提出一种简单方法:在提示(prompt)中提供 输入-思维链-输出 的三元组示例,引导大型语言模型生成一系列中间推理步骤(称为 “思维链”),再得出最终答案。
  • 思维链类似于人类逐步推理的过程(例如,解决数学题时先分解步骤:“先计算A,再计算B,最后得出答案”)。

2. 关键优势

  • 提升复杂推理能力:在算术(如数学题 GSM8K)、常识(如 CSQA)和符号推理(如字母拼接游戏)任务上,思维链提示显著优于标准提示(standard prompting)。
  • GSM8K 数学题基准上,PaLM 540B 模型使用思维链提示后,准确率从 17.9% 提升至 56.9%,甚至超过微调的 GPT-3 模型。
  • 在常识推理任务(如 StrategyQA)上,准确率从 68.6% 提升至 77.8%
  • 模型规模涌现特性:思维链推理是大型模型(约 100B 参数以上)的 “涌现能力” —— 小模型无法生成逻辑思维链,但足够大的模型(如 GPT-3 175BPaLM 540B)能自然学习此模式。
  • 无需微调:仅需在提示中添加少量示例(如 8 个),即可激发模型能力,无需额外训练或数据标注。
  • 可解释性与泛化性:思维链提供透明推理路径,便于调试;且适用于多种任务(数学、常识、符号等),甚至能泛化到更长序列。

3. 实验验证

  • 任务覆盖:
    • 算术推理:在 GSM8KSVAMP 等数据集上,思维链提示将性能提升高达 39%PaLM 540B)。
    • 常识推理:在 StrategyQADate Understanding 等任务上,模型表现接近或超越人类水平。
    • 符号推理:在硬币翻转(coin flip)和字母拼接(last letter concatenation)任务中,模型能处理未见过的长序列。
  • 鲁棒性:不同注释者编写的思维链示例均有效,且对示例顺序、数量变化不敏感。

4. 局限性与启示

  • 模型规模依赖:思维链仅在大型模型(≥100B 参数)中有效,小模型生成逻辑混乱。
  • 潜在错误:生成的推理路径可能不准确(如算术计算错误或语义误解),需外部验证(如添加计算器)。
  • 应用意义:该方法拓展了提示技术的边界,证明大型模型能通过自然语言示例学习复杂推理,减少对标注数据的依赖。

论文核心贡献

  • 思维链提示是一种低成本、高效的方法,通过模拟人类逐步推理过程,释放大型语言模型在复杂任务上的潜力。论文强调,这是 “模型规模涌现” 的典型例子——推理能力随模型增大而自然出现,为未来 AI 推理研究提供了新方向。

Thoughts

  • 一定要注意,这篇论文讨论的对象 不是 Reasoning 模型(这个论文出来的时候还没有 Reasoning 模型的概念),而是普通的 LLM 模型。
  • 本质是一种通过 prompt 引导模型通过增加推理计算预算的方式,来提升模型的推理能力的方法。
  • 依托于 LLM 恐怖的指令遵循和上下文学习能力。