昨天介紹了 Deep Agents 和 harness engineering。
今天再往下一層,看 Agent 裡面真正和 LLM 溝通的 component:ChatModel。
不管上層是 Deep Agents、LangGraph,還是其他 Agent framework,最後都還是需要一個 model 來完成 reasoning、tool calling,以及產生 response。
這一篇主要看幾個建立 Agent 時最常用到的能力:
ChatModel 可以先理解成:
Agent
↓
ChatModel
↓
LLM Provider
LangChain 提供一個比較統一的 interface,讓我們可以用類似的方式呼叫不同 provider 的 models。
例如:

最基本的 usage:
from langchain.chat_models import init_chat_model
model = init_chat_model(
"anthropic:claude-sonnet-4-6",
temperature=0,
)
response = model.invoke("What's your name?")
到這裡,它還只是一個普通的 LLM call。
真正讓它適合拿來建立 Agent 的,是下面這些能力。
如果沒有 streaming,使用者通常要等 model 完整產生 response 之後,才能看到結果。
有 streaming 之後,可以一邊產生、一邊把 output 傳回去。
例如:
for chunk in model.stream("Analyze this dataset"):
print(chunk.text, end="")
概念上從:
User
↓
wait...
wait...
wait...
↓
Complete Response
變成:
User
↓
Partial Output
↓
More Output
↓
Complete Response
這對 Agent 特別重要,因為一個 task 可能包含多個 steps,整體 execution time 會比單純聊天長很多。
Tool calling 是 Agent system 最重要的能力之一。
如果沒有 tools,model 基本上只能 reasoning 和產生文字。
有了 tools 之後,model 才能真正和外部 system 互動。
例如前幾天做的 datasource tools:
tools = [
read_file,
query_database,
]
Model 可以決定:
Need data
↓
Call read_file()
↓
Receive result
↓
Continue reasoning
這樣 Agent 就不只是說:
我應該讀這份資料。
而是真的可以執行:
read_file(...)
Tool design 本身也會直接影響 Agent 的表現。
例如:
都會影響 model 是否能正確選擇和使用 tool。
因為 LLM 的原理是機率模型,如果用一串文字當作決定下一個步驟的 routing 會非常不穩定,所以我們會希望模型輸出一個固定格式讓後續的步驟好執行。
例如:
I think we should ask the user for more information.
對流程來說,更好處理的是:
{
"action": "clarify",
"reason": "The metric is ambiguous."
}
這就是 structured output。
我們可以先用 Pydantic 或 TypeDict 來定義 schema,我習慣用 Pydantic 因為可以檢查型別:
from typing import Literal
from pydantic import BaseModel
class AgentDecision(BaseModel):
action: Literal["continue", "clarify"]
reason: str
然後要求 model 的 output 符合這個結構。
例如:
User Request
↓
LLM
↓
Structured Decision
↓
┌──────────────┬──────────────┐
│ continue │ clarify │
└──────────────┴──────────────┘
這樣 downstream code 不需要再從自然語言中猜 model 到底想做什麼。
但有一點很重要:
structured output 只能保證格式比較 predictable,不代表內容一定正確。
此時剛好有一個新模型 Jev 在這類 classification workload 上表現很驚人:相較於一般 LLM,inference speed 最快可以快到 200 倍,成本則可以低到 1/400,參考:What is Jev, TypeSafe AI's System One model?
這兩個能力很容易混在一起,但用途不太一樣。
可以先簡單理解成:
Tool Calling
→ Model decides to DO something
Structured Output
→ Model returns a structured DECISION
例如:
Need to inspect data
↓
Tool Calling
↓
read_file()
而:
Enough information?
↓
Structured Output
↓
continue / clarify
兩個通常會一起出現在 Agent system 裡,但解決的是不同問題。
除了基本 capabilities 之外,不同 model provider 通常還會提供很多 configuration。
例如:
這些設定會直接影響:
這個系列不會把每個 configuration 都講一遍。
目前只挑一個 Agent application 裡很實用的例子:prompt caching。
Agent 很常會反覆帶著相同的 context 呼叫 model。
例如:
System Prompt
Tool Definitions
Project Instructions
Conversation Context
New User Message
其中很多內容其實每次都一樣。
如果每次都重新處理:
Large Static Context + User Message 1
Large Static Context + User Message 2
Large Static Context + User Message 3
就會增加 token cost 和 latency。
如果 model provider 支援 prompt caching,就可以 reuse 一部分重複 context。
例如 Anthropic:
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage, SystemMessage
llm = init_chat_model("anthropic:claude-sonnet-4-6")
messages = [
SystemMessage(
content=[
{
"type": "text",
"text": "You are a data analysis agent..."
},
{
"cache_control": {
"type": "ephemeral"
}
}
]
),
HumanMessage(
content="Analyze the first dataset."
),
]
response = llm.invoke(messages)
對 Agent system 來說,prompt caching 特別有價值,因為:
所以即使只是 model configuration,也可能直接影響整個 system 的成本和 latency。
到這裡,可以把今天的內容串起來:
ChatModel
↓
Streaming
Tool Calling
Structured Output
Configuration
Caching
這些能力不是獨立存在的 feature。
它們最後會一起支撐 Agent 的 behavior。
例如一個 Agent request 可能是:
User Request
↓
Model decides what to do
↓
Tool Calling
↓
read_file()
↓
Model receives result
↓
Structured Output
↓
continue / clarify
↓
Streaming response to user
而 Deep Agents 做的事情,就是把這些 capabilities 放進更完整的 Agent harness 裡。