NL-363, Toolformer: Language Models Can Teach Themselves to Use Tools, NeruIPS 2023
이 논문은 Toolformer: Language Models Can Teach Themselves to Use Tools (Schick et al., 2023)입니다. 지금 흔히 말하는 LLM + Tool Use / Agent / Function Calling 계열의 대표적인 초기 논문 중 하나입니다.
핵심 아이디어는 의외로 단순합니다.
LLM이 언제 도구를 호출해야 하는지 사람이 라벨링하지 말고,
“그 도구의 결과를 받았을 때 다음 토큰 예측이 더 쉬워지는가?”를 이용해서 스스로 학습 데이터를 만들자.
이게 논문의 거의 전부라고 보면 됩니다.
1. 무슨 문제를 풀려고 하나?
LLM은 많은 것을 알지만 분명한 약점이 있습니다.
예를 들어:
정확한 계산
최신 정보
특정 factual knowledge
날짜 계산
번역
검색
같은 문제입니다.
예를 들어
Out of 1400 participants, 400 passed the test. This is ___%.
라고 하면 LM 내부에서 계산하게 하지 말고,
Out of 1400 participants, 400
[Calculator(400 / 1400) → 0.29]
29% passed the test.
처럼 calculator를 호출하면 됩니다.
문제는 여기서 생깁니다.
언제 calculator를 불러야 하지?
그리고
Calculator?
Search?
QA?
Translation?
중 어떤 tool을 불러야 하지?
또 tool을 호출한다면
무슨 query를 보내야 하지?
Toolformer는 이것들을 전부 LM 자체에게 학습시키려고 합니다.
2. Toolformer가 사용하는 Tool
논문에서는 5개를 사용합니다.
| Tool | 역할 |
|---|---|
| Question Answering | factual question에 답함 |
| Wikipedia Search | Wikipedia 검색 |
| Calculator | 계산 |
| Calendar | 현재 날짜 |
| Machine Translation | 다른 언어 → 영어 번역 |
예를 들어 모델이
The name derives from "la tortuga",
the Spanish word for
까지 생성했다면,
[MT("tortuga") → turtle]
을 호출하고
turtle
을 이어서 생성할 수 있습니다.
3. 가장 중요한 부분: Tool 사용 데이터를 어떻게 만드나?
보통 생각하면 이런 데이터가 필요합니다.
문장 A → 여기서는 search 사용
문장 B → 여기서는 calculator 사용
문장 C → tool 사용하지 않음
그런데 이런 데이터를 사람이 수십만 개 labeling하면 비용이 큽니다.
Toolformer의 핵심은 LLM 스스로 이 데이터를 만든다는 것입니다.
전체 과정은 크게:
① API call 후보 생성 → ② 실제 Tool 실행 → ③ 도움이 되는 call만 filtering → ④ 그 데이터로 LM fine-tuning
입니다.
4. Step 1. LM에게 Tool call 후보를 만들어보라고 한다
원래 데이터가 있다고 합시다.
Pittsburgh is also known as the Steel City.
먼저 GPT-J에게 few-shot prompt를 줍니다.
대략:
문장 안에 QA API를 필요한 위치에 삽입해라.
Example:
Joe Biden was born in
[QA("Where was Joe Biden born?")]
Scranton, Pennsylvania.
...
Input:
Pittsburgh is also known as the Steel City.
그러면 LM이 여러 API call을 생성합니다.
예:
Pittsburgh is
[QA("What other name is Pittsburgh known by?")]
also known as the Steel City.
또는
Pittsburgh is
[QA("Which country is Pittsburgh in?")]
also known as the Steel City.
여기까지는 그냥 LM이 후보를 막 생성하는 단계입니다.
그래서 당연히 쓰레기 query도 많이 생깁니다.
5. 어디에 Tool call을 넣을지도 LM이 결정한다
여기서 재미있는 점이 있습니다.
문장의 각 위치 (i)에서
[
p_i
p_M(\texttt{} \mid P(x),x_{1:i-1})
]
를 계산합니다.
즉,
"지금 이 위치에서 API call을 시작할 확률"
을 LM 자체의 next-token probability로 봅니다.
예를 들어
The population of France is ...
까지 왔을 때
<API>
token probability가 높다면,
여기가 tool을 사용할 후보 위치가 됩니다.
따로 tool router classifier를 학습하는 게 아닙니다.
6. 그런데 LM이 생성한 Tool call이 진짜 좋은지는 어떻게 아나?
여기가 Toolformer의 진짜 핵심입니다.
예를 들어 LM이 다음 call을 만들었다고 합시다.
[QA("What other name is Pittsburgh known by?")]
실제로 QA API를 실행합니다.
결과:
Steel City
그러면 원래 문장:
Pittsburgh is also known as the Steel City.
을 예측할 때
Tool 없이
Pittsburgh is ...
만 보고
also known as the Steel City
를 예측하는 것과,
Tool을 넣고
Pittsburgh is
[QA(...) → Steel City]
를 본 다음
also known as the Steel City
를 예측하는 것을 비교합니다.
7. Loss가 줄었는지를 본다
논문의 핵심 수식입니다.
API call 위치를 (i)라고 하면 이후 token에 대한 weighted LM loss를:
[
L_i(z)
-\sum_{j=i}^{n}
w_{j-i}
\log p_M(x_j \mid z,x_{1:j-1})
]
로 정의합니다.
쉽게 말하면:
API 결과 (z)를 알려줬을 때 이후 원래 문장을 얼마나 잘 예측할 수 있나?
입니다.
Tool 결과까지 제공했을 때:
[
L_i^+ = L_i(e(c_i,r_i))
]
여기서
(c_i): API call
(r_i): API 결과
입니다.
예를 들어
c_i = QA("What other name is Pittsburgh known by?")
r_i = Steel City
입니다.
8. 비교 대상 (L_i^-)
논문에서는 그냥 tool을 안 사용한 것과만 비교하지 않습니다.
[
L_i^-
\min
\left(
L_i(\epsilon),
L_i(e(c_i,\epsilon))
\right)
]
입니다.
두 가지와 비교합니다.
A. 아무 Tool call도 없음
Pittsburgh is ...
B. Tool query만 있고 결과 없음
Pittsburgh is
[QA("What other name is Pittsburgh known by?")]
...
즉,
단순히 query text 자체가 hint를 줘서 loss가 내려간 건지,
실제로 API 결과가 도움이 된 건지
구별하려는 겁니다.
9. 최종 filtering
다음 조건을 만족할 때만 API call을 남깁니다.
[
L_i^- - L_i^+ \ge \tau_f
]
즉,
API 결과를 넣었더니 이후 token prediction loss가 충분히 감소했는가?
입니다.
감소했다면:
좋은 API call
감소하지 않았다면:
쓸모없는 API call → 버림
10. 예를 들어 보면 훨씬 쉽다
원문:
The Nile has an approximate length of 6,650 km.
LM이 다음 API call을 생성했다고 해봅시다.
후보 A
QA("What is the approximate length of the Nile?")
→ 6,650 km
그러면 이후
6,650 km
예측이 엄청 쉬워집니다.
따라서
[
L^- - L^+ \gg 0
]
이므로 데이터를 남깁니다.
반면 후보 B:
QA("Where is the Nile?")
→ Africa
이라고 했다면,
6,650 km
를 예측하는 데 별 도움이 안 됩니다.
따라서 loss가 거의 줄지 않습니다.
→ training data에서 제거됩니다.
11. 그래서 만들어지는 학습 데이터
원래 CCNet 문서가
The Nile has an approximate length of 6,650 km.
였다면 최종적으로
The Nile has an approximate length of
[QA("What is the approximate length of the Nile?")
→ 6,650 km]
6,650 km.
가 됩니다.
이런 데이터들을 대량으로 만들어서 GPT-J를 일반적인 language modeling objective로 fine-tuning합니다.
별도의 tool-use loss가 있는 것도 아닙니다.
그냥:
[
-\log P(x_t|x_{<t})
]
입니다.
12. 그러면 모델이 무엇을 배우게 되나?
이 데이터로 학습하면 모델은 자연스럽게 세 가지를 배웁니다.
① 언제 Tool을 사용할지
... 400 out of 1400 participants ...
→ Calculator 필요
② 어떤 Tool을 사용할지
Spanish word "tortuga"
→ Translation
③ Tool에 어떤 argument를 넣을지
Calculator(400 / 1400)
그리고 추가로
④ 결과를 어떻게 이어서 사용할지
Calculator(...) → 0.29
이후
29%
를 생성합니다.
따라서 별도의
Tool Router
Query Generator
Result Integrator
를 만드는 게 아니라 하나의 autoregressive LM 안에서 전부 처리합니다.
13. Inference는 어떻게 하나?
Inference 때는 평범하게 token generation을 합니다.
예:
Out of 1400 participants, 400 (
그러다가 모델이
<API>
Calculator(400 / 1400)
→
를 생성하면 inference를 잠깐 중단합니다.
시스템이 calculator를 실제 실행합니다.
0.29
그 값을 context에 삽입합니다.
<API>
Calculator(400 / 1400)
→ 0.29
</API>
그리고 다시 generation:
29%) passed the test.
이런 구조입니다.
현재의 function calling과 굉장히 비슷하죠.
14. "언제 검색할지"를 어떻게 아는가?
이 부분이 특히 중요합니다.
Toolformer에는 명시적인
[
P(\text{need search})
]
classifier가 없습니다.
대신 LM이 그냥 next-token distribution에서
<API>
를 생성할지를 학습합니다.
즉
일반 token
일반 token
일반 token
<API>
자체가 검색 여부 decision입니다.
학습 데이터가
질문 → Tool이 도움 됨 → <API>가 삽입되어 있음
형태이므로 LM이
이런 context에서는
<API>를 생성하는 게 좋구나
를 language modeling을 통해 배우는 것입니다.
15. 사용한 모델과 데이터
기본 LM은 GPT-J 6.7B입니다.
그리고 CCNet 문서를 이용해 self-supervised tool-use 데이터를 만듭니다.
예를 들어 filtering threshold (\tau_f=1.0)일 때 논문에서 남은 tool call example 수는 대략:
| Tool | Examples |
|---|---|
| Wikipedia Search | 60,974 |
| Calendar | 20,587 |
| Question Answering | 18,526 |
| Machine Translation | 1,034 |
| Calculator | 994 |
입니다.
중요한 건 사람이 저 10만 개 가까운 call을 annotation한 게 아니라는 것입니다.
사람이 준비한 건 각 API 사용법을 보여주는 몇 개의 demonstration 정도입니다.
16. 성능은?
Tool을 사용할 수 있게 하자 여러 분야에서 크게 좋아집니다.
예를 들어 LAMA T-REx:
| Model | T-REx |
|---|---|
| GPT-J 6.7B | 31.9 |
| Toolformer, tool disabled | 34.9 |
| Toolformer | 53.5 |
| GPT-3 175B | 39.8 |
Tool을 실제로 쓰는 Toolformer가 53.5까지 갑니다.
6.7B 모델인데 GPT-3 175B보다도 높은 결과입니다.
계산 문제에서는 차이가 더 큽니다.
| Model | ASDiv | SVAMP | MAWPS |
|---|---|---|---|
| GPT-J | 7.5 | 5.2 | 9.9 |
| Toolformer disabled | 14.8 | 6.3 | 15.0 |
| Toolformer | 40.4 | 29.4 | 44.0 |
| GPT-3 175B | 14.0 | 10.0 | 19.8 |
Calculator 하나 붙였을 뿐인데 엄청난 차이가 생깁니다.
이 결과는 사실 자연스럽습니다.
LLM에게
197 × 43 계산해
라고 시키는 것보다 calculator에게 맡기는 게 훨씬 안정적이니까요.
17. 재미있는 baseline: Toolformer (disabled)
논문이 이 baseline을 넣은 이유도 중요합니다.
Toolformer를 학습시켜 놓은 다음 inference에서 tool 호출을 금지합니다.
그게
Toolformer (disabled)
입니다.
이를 통해
성능 향상이 tool-use fine-tuning 자체 때문인가?
아니면 실제로 external tool을 사용해서인가?
를 나눠볼 수 있습니다.
그리고 많은 task에서
Toolformer
>>
Toolformer disabled
입니다.
즉 실제 tool 결과가 상당한 역할을 합니다.
18. 일반적인 LM 능력을 망치지는 않나?
저자들도 이걸 확인합니다.
Tool call이 들어간 데이터로 fine-tuning하면
모델이 모든 곳에서 API를 호출한다거나,
일반 language modeling 능력이 망가질 수 있지 않나?
라는 문제가 있기 때문입니다.
WikiText와 CCNet perplexity를 봤는데, Toolformer에서 tool을 disable했을 때 일반 LM perplexity가 거의 악화되지 않았습니다.
즉 저자들의 주장은:
Tool-use capability를 추가하면서 기본 language modeling 능력은 거의 유지된다.
입니다.
19. 굉장히 중요한 한계: Toolformer는 "필요하면 검색"을 완벽하게 학습한 것인가?
부분적으로는 맞지만, 오늘날 우리가 생각하는 sophisticated한 uncertainty-based routing은 아닙니다.
Toolformer의 학습 신호는:
[
\boxed{
\text{Tool 결과가 future-token LM loss를 얼마나 줄여주는가}
}
]
입니다.
즉 모델이
"나는 이 사실을 모르니까 검색해야겠다."
라는 explicit uncertainty objective를 학습하는 것은 아닙니다.
대신
이 context에서 Tool을 사용하면 원래 문장을 더 잘 예측할 수 있었음
이라는 데이터를 만들어놓고,
그 pattern을 imitation합니다.
그래서 개념적으로는
[
\text{Knowledge uncertainty}
\rightarrow
\text{Retrieve?}
]
라기보다는
[
\text{Context}
\rightarrow
\texttt{}
]
를 language modeling으로 학습하는 방식입니다.
이 차이가 꽤 중요합니다.
20. RAG와 비교하면?
보통 vanilla RAG는 대충:
[
Question
\rightarrow
Retriever
\rightarrow
Documents
\rightarrow
LLM
]
입니다.
즉 항상 retrieval을 수행하는 구조가 흔합니다.
Toolformer는:
[
Question
\rightarrow
LM
]
그리고 LM이 필요하다고 판단하면
[
\rightarrow \text{Search API}
]
입니다.
그래서
[
\boxed{\text{Selective Retrieval}}
]
의 초기 형태라고 볼 수도 있습니다.
다만 검색만 있는 게 아니라 calculator, translation, calendar 등 모두 포함하므로 더 일반적으로는 Selective Tool Use입니다.
21. 그런데 중요한 약점도 있다
Toolformer는 지금 기준으로 보면 제한이 꽤 큽니다.
첫째, 논문 실험에서는 한 input에 최대 한 번의 API call만 허용합니다.
그래서
현재 날짜 확인
↓
그 날짜를 이용해서 검색
↓
검색 결과 보고 계산
같은 multi-step tool use가 안 됩니다.
저자들도 temporal benchmark에서 이것을 명시적으로 한계로 이야기합니다.
즉 ReAct나 현재 agent처럼
[
Tool_1
\rightarrow Reason
\rightarrow Tool_2
\rightarrow Reason
\rightarrow Tool_3
]
를 하는 모델은 아닙니다.
둘째, query reformulation도 어렵습니다.
예를 들어:
Search("Apple")
→ 이상한 결과
가 나왔을 때
별로네.
Search("Apple Inc revenue 2022")
처럼 다시 검색하는 구조가 아닙니다.
셋째, 작은 모델에서는 Tool use 자체가 잘 학습되지 않습니다.
GPT-2 계열로 scaling experiment를 해보니 tool을 제대로 활용하는 능력이 대략 775M parameter 부근부터 나타나기 시작했다고 저자들은 보고합니다.
즉
Tool만 달아준다고 작은 LM이 무조건 좋아지는 건 아니다.
라는 결과도 흥미롭습니다.
22. 이 논문의 가장 중요한 아이디어를 한 문장으로 압축하면
저라면 이렇게 정리하겠습니다.
[
\boxed{
\text{Tool 결과가 LM의 future-token loss를 줄이는지를 이용하여
tool-use training data를 자동 생성한다.}
}
]
그 이후는 그냥 일반 LM fine-tuning입니다.
즉 Toolformer가 특별한 이유는 새로운 agent architecture 때문이 아니라,
"어떤 tool call이 유용한지를 LM 자신의 loss로 labeling한다"
는 데이터 생성 방식 때문입니다.
23. 전체 흐름을 그림으로 보면
원래 corpus
│
▼
"Pittsburgh is also known
as the Steel City."
│
▼
LM이 API 후보 생성
│
┌──────────┴───────────┐
▼ ▼
QA("other name?") QA("which country?")
│ │
▼ ▼
"Steel City" "USA"
│ │
▼ ▼
future token loss ↓↓↓ future token loss 거의 동일
│ │
▼ X
KEEP DROP
│
▼
"Pittsburgh is
[QA(...) → Steel City]
also known as the Steel City."
│
▼
일반 LM objective로 Fine-tuning
│
▼
Toolformer
│
▼
inference 중 필요할 때
<API> token을 스스로 생성
이 논문을 최근의 "모를 때만 검색" 연구와 연결해서 보면
Toolformer는 분명 항상 검색하는 시스템은 아닙니다. inference 때 LM이 <API>를 생성한 경우에만 tool을 호출합니다.
하지만 "모르는가/아는가"를 직접 측정해서 검색 여부를 결정하는 시스템도 아닙니다.
학습 과정은:
[
\text{API 결과가 future-token loss를 줄이는 example}
\Rightarrow
\text{Tool-use positive training example}
]
이고, inference에서는 그 패턴을 학습한 LM이 <API>를 생성합니다.
따라서 최근 uncertainty-aware RAG 관점으로 표현하면:
Toolformer는 uncertainty detector를 명시적으로 만들지는 않고, tool의 utility를 LM loss reduction으로 정의하여 selective tool-use behavior를 distill한 방법
이라고 보는 게 가장 정확합니다.
이 포인트가 Toolformer를 이해할 때 가장 중요합니다.
Reference
댓글
댓글 쓰기