最近的熱門的話題是 Jev model,它的設計非常適合 automation。因為 automation 的工作其實很單純,主要是 routing:走 A / B / C / D、做 classification,或判斷下一步該做什麼。
現在的 frontier model,例如 GPT-5.6 Sol、Luna 或 Claude Opus,雖然能力很強,但對這類 automation task 來說,很多時候能力其實超過需求,反而增加 latency、cost,以及整個 pipeline 的複雜度。
如果這個系列後面還有時間,會嘗試把 Jev 和整個 Pipeline 整合,看看對整體效益變化的影響是什麼。
回到今天的主題,我們已經對 Deep Agents 有基本理解,今天來把這些東西組裝起來,看一下這個 ReAct — Reasoning and Acting system 實際上是怎麼運作的。
整篇文章我們都會用同一個問題來測試:
Which video category gets the most views?
看起來很簡單,但其實 dataset 裡面藏了一個坑。
最基本的 Deep Agent,只需要 model 和 system prompt:
from deepagents import create_deep_agent
agent = create_deep_agent(
model=cfg.agent.model,
system_prompt=SYSTEM_PROMPT,
)
Deep Agents 本身就已經提供了一個 ReAct loop:
Reason
↓
Act
↓
Observe
↓
Repeat
不過這時候 Agent 還沒有辦法存取我們的資料。
我們可以把用一個 tool 讓 Agent 可以讀到資料庫:
@tool
async def query_database(sql: str) -> str:
"""Run one read-only PostgreSQL query and return rows as JSON."""
...
接著把它放進 Agent:
agent = create_deep_agent(
model=cfg.agent.model,
tools=[query_database],
system_prompt=SYSTEM_PROMPT,
)
這樣 Agent 就真的可以查詢 dataset 了。
這裡有一個我覺得很實用的設計:database error 不要直接讓整個 Agent run crash,而是把 error 當成 tool result 回傳。
例如:
ERROR: column "view" does not exist
Agent 可以看到這個錯誤,修改 SQL,然後再試一次。
這正是 ReAct 裡面 Observe 這一步的用途。
對 Agent 來說,tool 不只是一個 function。
Model 在決定要不要呼叫 tool 時,也會看到:
例如:
@tool
async def query_database(sql: str) -> str:
"""Run one read-only PostgreSQL query and return rows as JSON.
Aggregate in SQL instead of fetching unnecessary raw rows.
"""
這個 docstring 其實也會成為 Agent context 的一部分。
所以工具的設計會直接影響 Agent 的什麼時候呼喚他跟放進什麼內容當 input。
回到剛才的問題:
Which video category gets the most views?
這個 dataset 有一個很重要的特性:
一筆 row 代表的是某支 video 在某一天進入 trending。
所以同一支 video 可能會出現很多次。
如果很直覺地寫:
SELECT
category_name,
SUM(views)
FROM videos
GROUP BY category_name;
那同一支 video 的 views 就會被重複計算。 我們可以看到程式可以正常執行, SQL 也沒問題,只是結果是不對的。
這個 dataset 裡面有:
40,949 rows
6,351 distinct videos
所以這其實不是 SQL syntax 的問題,而是 對 dataset 的 domain knowledge。
透過 skills 我們可以把一些細節告訴 Agent , 但不可能把所有相關知識全部塞進同一個 skill,這只會浪費很多錢以及效能下降,所以通常我會把它拆成兩層:
skills/
├── query_database/
│ └── SKILL.md
└── youtube-trending/
└── SKILL.md
query_database 是 database tool 的 general skill,裡面可以索引其他細節的 skill。
youtube-trending 則放這個特定 dataset 的 domain knowledge。
核心概念是:
Tool
→ Agent 能做什麼
General skill
→ 這個 capability 應該怎麼使用
Domain skill
→ 這份資料實際代表什麼
query_database 這個 skill 也可以同時作為一個簡單的 routing index。
例如:
---
name: query_database
description: Guidance for querying the database safely and correctly.
---
# Querying the database
Before writing SQL:
- inspect the relevant schema
- avoid assuming what one row represents
- avoid unnecessary `SELECT *`
- aggregate in SQL when possible
- check whether there is datasource-specific guidance for the data you are using
## Datasource-specific guidance
### videos
For analysis involving the `videos` table, read:
`/skills/youtube-trending/SKILL.md`
It contains:
- row semantics
- counting rules
- aggregation guidance
這樣預期的 flow 就會變成:
query_database
↓
read general database skill
↓
找到 relevant domain skill
↓
read youtube-trending skill
↓
write SQL
這樣 query_database skill 本身可以保持 general,同時也能引導 Agent 找到正確的 domain knowledge。
接著 youtube-trending/SKILL.md 就只需要專注在這個 dataset 本身:
---
name: youtube-trending
description: Domain rules for the YouTube trending dataset.
---
One row is one video on one trending day.
For per-video analysis:
- collapse to one row per video first
- use MAX(views)
- do not use COUNT(*) as the number of videos
- prefer median when comparing typical video performance
這樣責任就很清楚。
Database skill 處理的是:
how to query
Dataset skill 處理的是:
how to interpret the data
Agent 不需要一開始就把所有 skill 的完整內容都塞進 context。
而是可以先看到:
Skill name + description
↓
Agent 判斷是否 relevant
↓
read_file(SKILL.md)
↓
完整 skill 進入 context
這樣即使未來 skill 數量變多,也不需要一開始就把所有 instruction 都放進 prompt。
而 routing index 也提供了一條路徑,讓 Agent 可以從 general capability,一路找到更 specific 的 domain knowledge。
現在我們可以用同一個問題,比較不同階段的 Agent:
Bare Agent
↓
+ query_database
↓
+ database skill
↓
+ youtube-trending skill
每個階段都可以觀察:
這部分的細節會在之後的 Agent performance evaluation 談到。
這次的實驗可以整理成很簡單的分工:
Tool
→ capability
General skill
→ usage guidance + routing
Domain skill
→ dataset-specific knowledge
這樣的結構之後要加入更多 table,或不同 datasource,也比較容易擴充。
但這也帶出另一個問題:
我們要怎麼確保 Agent 會在正確的時間讀到正確的 skill?
把 skill 放在那裡,不代表 Agent 一定會去讀。
而如果 skill 裡面放的是重要的 domain knowledge,跳過它之後,Agent 很可能產生一個完全合法、但意義錯誤的 tool call。
如果某個 skill 在使用 tool 之前是必讀的,那我們需要的就不只是 prompt。
下一篇會來嘗試處理這個問題。