一句話理解
Agent 讓 LLM 自己決定「要不要呼叫工具、呼叫哪個、用什麼參數」,而不是你寫死流程;適合不確定步驟的複雜任務。
Agent vs Chain
| Chain | Agent |
|---|
| 流程 | 你定義好的固定步驟 | LLM 自主決定 |
| 適合 | 步驟確定的任務 | 步驟不確定的任務 |
| 可預測性 | 高 | 低 |
| 彈性 | 低 | 高 |
內建工具
from langchain_community.tools import WikipediaQueryRun, DuckDuckGoSearchRun
from langchain_community.utilities import WikipediaAPIWrapper
search = DuckDuckGoSearchRun()
wiki = WikipediaQueryRun(api_wrapper=WikipediaAPIWrapper())
# 手動測試工具
print(search.invoke("LangChain 最新版本"))
print(wiki.invoke("Python programming language"))
自訂工具
from langchain_core.tools import tool
# 用 @tool decorator 定義
@tool
def get_product_price(product_name: str) -> str:
"""查詢商品價格,輸入商品名稱"""
# 這裡可以呼叫你的資料庫或 API
prices = {"iPhone": "NT$ 32,900", "MacBook": "NT$ 39,900"}
return prices.get(product_name, "找不到此商品")
@tool
def calculate_discount(price: float, discount_rate: float) -> str:
"""計算折扣後價格,輸入原價和折扣率(0-1)"""
final = price * (1 - discount_rate)
return f"折扣後價格:NT$ {final:.0f}"
# 查看工具的 schema(LLM 就是看這個決定怎麼呼叫)
print(get_product_price.name)
print(get_product_price.description)
print(get_product_price.args_schema.schema())
建立 Agent(ReAct)
from langchain_openai import ChatOpenAI
from langchain.agents import create_react_agent, AgentExecutor
from langchain import hub
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
tools = [get_product_price, calculate_discount, DuckDuckGoSearchRun()]
# 載入 ReAct prompt
prompt = hub.pull("hwchase17/react")
# 建立 agent
agent = create_react_agent(llm, tools, prompt)
executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True, # 印出思考過程
max_iterations=5 # 最多執行 5 步(防止無限迴圈)
)
# 執行
result = executor.invoke({"input": "iPhone 打 8 折是多少?"})
print(result["output"])
from langchain.agents import create_tool_calling_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
prompt = ChatPromptTemplate.from_messages([
("system", "你是一個購物助理,可以查詢商品價格和計算折扣。"),
MessagesPlaceholder(variable_name="chat_history"),
("human", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"), # agent 思考過程
])
agent = create_tool_calling_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
result = executor.invoke({
"input": "幫我查 iPhone 的折扣後價格(打 9 折)",
"chat_history": []
})
Agent 思考過程(ReAct)
問題:iPhone 打 8 折是多少?
Thought: 我需要先查 iPhone 的價格
Action: get_product_price
Action Input: "iPhone"
Observation: NT$ 32,900
Thought: 現在我有價格了,來計算 8 折
Action: calculate_discount
Action Input: {"price": 32900, "discount_rate": 0.2}
Observation: 折扣後價格:NT$ 26,320
Thought: 我有答案了
Final Answer: iPhone 打 8 折後是 NT$ 26,320
帶記憶的 Agent
from langchain_core.chat_history import InMemoryChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
store = {}
def get_session_history(session_id):
if session_id not in store:
store[session_id] = InMemoryChatMessageHistory()
return store[session_id]
agent_with_memory = RunnableWithMessageHistory(
executor,
get_session_history,
input_messages_key="input",
history_messages_key="chat_history"
)
config = {"configurable": {"session_id": "user_001"}}
agent_with_memory.invoke({"input": "我想買 iPhone"}, config=config)
agent_with_memory.invoke({"input": "它折扣後多少錢?"}, config=config) # 記得上文
常見錯誤
| 錯誤 | 原因 | 解法 |
|---|
| Agent 無限迴圈 | LLM 一直呼叫工具找不到答案 | 設 max_iterations=5 |
| Tool 參數格式錯 | docstring 不清楚 | 寫清楚 docstring,加上範例 |
| 工具沒被呼叫 | 工具 description 沒說清楚用途 | 改寫 description |
相關筆記