Skip to content

การเรียกใช้เครื่องมือ (Tool Calling)

บทนำ

Tool Calling คืออะไร?

หากคุณถาม LLM คำถามเช่น รากที่สองของ 15129 คือเท่าไร? หรือ เปรียบเทียบราคาหุ้นของ Nvidia และ AMD LLM อาจให้คำตอบที่ไม่ถูกต้อง เนื่องจากโดยพื้นฐานแล้ว LLM เป็นแบบจำลองภาษาไม่ใช่เครื่องคิดเลขหรือผู้ให้ข้อมูลแบบเรียลไทม์

นี่คือเหตุผลที่ Tool Calling มีความสำคัญ Tool Calling ช่วยให้ LLM สามารถโต้ตอบกับเครื่องมือภายนอก เช่น เครื่องคิดเลขหรือ API เพื่อจัดการกับงานที่เกินความสามารถโดยธรรมชาติของมัน

ตัวอย่างของเครื่องมือ ได้แก่:

  • เครื่องมือที่ค้นหาข้อมูลบนอินเทอร์เน็ต
  • เครื่องมือที่ส่งอีเมลหรือ SMS
  • เครื่องมือที่แปลงเงินเป็นสกุลเงินอื่น
  • เครื่องมือที่ดึงวิดีโอจาก YouTube

มันทำงานอย่างไร?

LLM ไม่ได้ใช้เครื่องมือโดยตรง ในความเป็นจริง LLM สร้างการตอบสนองที่มีข้อมูลที่เครื่องมือต้องการ เรียกว่าข้อความเรียกใช้เครื่องมือ (tool call message) เครื่องมือจะประมวลผลข้อความและส่งคืนผลลัพธ์ตามกรณีการใช้งานเฉพาะของคุณ จากนั้นผลลัพธ์จะถูกส่งกลับไปยัง LLM ซึ่งจะสร้างคำตอบให้กับคำถามที่ถาม วิธีนี้ช่วยให้ LLM สามารถมุ่งเน้นไปที่การสร้างคำตอบภาษาธรรมชาติ ในขณะที่เครื่องมือจัดการกับการคำนวณจริงๆ เบื้องหลัง

โดยสรุป การรวม Tool Calling กับ LLM ประกอบด้วย 5 ขั้นตอนหลัก:

  1. กำหนดเครื่องมือของคุณ
  2. ติดตั้งเครื่องมือให้กับ LLM ของคุณ
  3. รับข้อความเรียกใช้เครื่องมือ
  4. ใช้เครื่องมือ
  5. ส่งผลลัพธ์ของเครื่องมือกลับไปยัง LLM

ดังที่คุณเห็น LLM จะถูกเรียกใช้อย่างน้อยสองครั้ง ครั้งแรกเพื่อรับข้อความเรียกใช้เครื่องมือและอีกครั้งเพื่อสร้างการตอบสนองสุดท้ายสำหรับผู้ใช้หลังจากได้รับผลลัพธ์ของเครื่องมือ

การรวมระบบ

  1. OpenAI
  2. LangChain

OpenAI

โค้ดทั้งหมด

from openai import OpenAI
import json
llm = OpenAI(
api_key=TYPHOON_API_KEY, # ใส่ API key ของคุณที่นี่
base_url='https://api.opentyphoon.ai/v1' # ใช้ URL นี้เพื่อเข้าถึงแบบจำลอง Typhoon
)
def get_color(
day: str
)-> dict:
outfit_colors = {
"Monday": {
"เสริมเสน่ห์" : ["สีขาว","สีครีม","สีเหลือง","สีชมพู"],
"การงาน" : ["สีเขียว"],
"การเงิน" : ["สีส้ม","สีน้ำตาล"],
"โชคดี" : ["สีดำ","สีเทา","สีม่วง"],
"สีต้องห้าม" : ["สีแดง"]
},
"Tuesday": {
"เสริมเสน่ห์" : ["สีชมพู"],
"การงาน" : ["สีม่วง","สีเทา"],
"การเงิน" : ["สีเงิน","สีทอง"],
"โชคดี" : ["สีส้ม","สีน้ำตาล"],
"สีต้องห้าม" : ["สีเหลือง","สีครีม"]
}
}
return outfit_colors.get(day)
dailyColor = {
"type": "function",
"function": {
"name": "daily_color",
"description": "Retrieve the traditional color of the outfit to wear for a specific day of the week based on Thai cultural beliefs, along with the symbolic meaning behind the color.",
"parameters": {
"type": "object",
"properties": {
"day": {
"type": "string",
"description": "The name of the day of the week e.g. Monday Tuesday.",
}
},
"required": ["day"],
"additionalProperties": False,
},
}
}
messages = [
{"role": "system", "content": "You are an expert at composing functions named Typhoon"},
{"role": "user", "content": "วันอังคารควรใส่เสื้อสีอะไร"},
]
response = llm.chat.completions.create(
model="typhoon-v2-8b-instruct", # แบบจำลอง Typhoon ที่เลือก
messages=messages, # ประวัติข้อความ
tools=[dailyColor], # เครื่องมือ
)
llm_response = response.choices[0].message
messages.append(llm_response)
for tool_call in llm_response.tool_calls:
name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)
day = arguments.get("day")
result = get_color(day)
tool_result = {
"role" : "tool",
"content" : json.dumps({
"name": name,
"arguments": arguments,
"results": result
}, indent=4, ensure_ascii=False),
}
messages.append(tool_result)
final_response = llm.chat.completions.create(
model="typhoon-v2-8b-instruct", # แบบจำลอง Typhoon ที่เลือก
messages=messages # ประวัติข้อความ
)
print(messages[1]["content"])
print(final_response.choices[0].message.content)

การแบ่งโค้ด

1. เตรียม LLM ของคุณ
from openai import OpenAI
llm = OpenAI(
api_key=TYPHOON_API_KEY, # ใส่ API key ของคุณที่นี่
base_url='https://api.opentyphoon.ai/v1' # ใช้ URL นี้เพื่อเข้าถึงแบบจำลอง Typhoon
)

มาดูว่า LLM ของคุณทำงานหรือไม่

response = llm.chat.completions.create(
model="typhoon-v2-8b-instruct", # แบบจำลอง Typhoon ที่เลือก
messages=[{"role": "user", "content": "สวัสดี คุณเป็นอย่างไรบ้างวันนี้?"}]
)
print(response.choices[0].message.content)

หากคุณได้รับการตอบสนอง แสดงว่าคุณพร้อมที่จะไปยังขั้นตอนถัดไปแล้ว

2. กำหนดเครื่องมือของคุณ

คำอธิบายเครื่องมือที่ใช้กับไคลเอนต์ OpenAI ต้องเป็นไปตามรูปแบบเฉพาะ

tool_1 = {
"type": "function",
"function": {
"name": tool_name,
"description": tool_description,
"parameters": {
"type": "object",
"properties": {
tool_input_1: {
"type": tool_input_1_datatype,
"description": tool_input_1_description,
},
tool_input_2: {
"type": tool_input_2_datatype,
"description": tool_input_2_description,
},
......
},
"required": [tool_input_1,tool_input_2, ....],
"additionalProperties": False,
},
}
}

นี่คือตัวอย่างเครื่องมือบางอย่าง

dailyColor = {
"type": "function",
"function": {
"name": "daily_color",
"description": "Retrieve the traditional color of the outfit to wear for a specific day of the week based on Thai cultural beliefs, along with the symbolic meaning behind the color.",
"parameters": {
"type": "object",
"properties": {
"day": {
"type": "string",
"description": "The name of the day of the week e.g. Monday Tuesday.",
},
"aspect": {
"type": "string",
"description": "The aspect of life to focus on when choosing the outfit color.",
},
},
"required": ["day"],
"additionalProperties": False,
},
}
}
searchInternet = {
"type": "function",
"function": {
"name": "search_internet",
"description": "Searh the internet to obtain information.",
"parameters": {
"type": "object",
"properties": {
"keywords": {
"type": "array",
"items": {
"type": "string"
},
"description": "List of keywords to search the internet.",
},
},
"required": ["keywords"],
"additionalProperties": False,
},
}
}
ฟังก์ชันของเครื่องมือ daily_color
def get_color(
day: str
)-> dict:
outfit_colors = {
"Monday": {
"เสริมเสน่ห์" : ["สีขาว","สีครีม","สีเหลือง","สีชมพู"],
"การงาน" : ["สีเขียว"],
"การเงิน" : ["สีส้ม","สีน้ำตาล"],
"โชคดี" : ["สีดำ","สีเทา","สีม่วง"],
"สีต้องห้าม" : ["สีแดง"]
},
"Tuesday": {
"เสริมเสน่ห์" : ["สีชมพู"],
"การงาน" : ["สีม่วง","สีเทา"],
"การเงิน" : ["สีเงิน","สีทอง"],
"โชคดี" : ["สีส้ม","สีน้ำตาล"],
"สีต้องห้าม" : ["สีเหลือง","สีครีม"]
}
}
return outfit_colors.get(day)

เตรียมเครื่องมือโดยเก็บไว้ในรายการเครื่องมือ

# รายการเครื่องมือที่เรามี
tools = [
searchInternet,
dailyColor,
]
3. รับข้อความเรียกใช้เครื่องมือ

สมมติว่าเราต้องการทราบว่าควรใส่เสื้อสีอะไรในวันจันทร์

messages = [
{"role": "system", "content": "You are an expert at composing functions named Typhoon"},
{"role": "user", "content": "วันจันทร์ควรใส่เสื้อสีอะไรดี"},
]
response = llm.chat.completions.create(
model="typhoon-v2-8b-instruct", # แบบจำลอง Typhoon ที่เลือก
messages=messages, # ประวัติข้อความ
tools=tools, # เครื่องมือ
)
llm_response = response.choices[0].message
# llm_response.tool_calls
[
ChatCompletionMessageToolCall(
id='2e2996eb-4347-43a7-b46c-e082c7d6fe55',
function=Function(
arguments='{"day": "Tuesday"}',
name='daily_color'
),
type='function'
)
]

llm_response.tool_calls ให้รายการข้อความเรียกใช้เครื่องมือ

มาดูว่าแต่ละค่าหมายถึงอะไร

  • id : ID ข้อความเรียกใช้เครื่องมือ ใช้เพื่อติดตามข้อความเรียกใช้เครื่องมือและผลลัพธ์ของเครื่องมือ
  • function : เนื้อหาการเรียกใช้เครื่องมือ ซึ่งระบุ:
    • name : ชื่อของเครื่องมือที่จะใช้
    • arguments : อาร์กิวเมนต์สำหรับเครื่องมือ
  • type : ประเภทของข้อความ มันจะเป็น function เสมอสำหรับข้อความเรียกใช้เครื่องมือ
4. ใช้เครื่องมือ

แยกชื่อเครื่องมือและอาร์กิวเมนต์ แล้วส่งไปยังฟังก์ชันเครื่องมือ

อาร์กิวเมนต์อยู่ในรูปแบบ string ดังนั้นเราต้องแปลงเป็น json

for tool_call in llm_response.tool_calls:
# รับชื่อและอาร์กิวเมนต์จากข้อความเรียกใช้เครื่องมือ
name = tool_call.function.name
arguments = json.loads(tool_call.function.arguments)
day = arguments.get("day") # Monday
# ใช้เครื่องมือ
tool_result = get_color(day,aspect)
# tool_result
{
"เสริมเสน่ห์" : ["สีขาว","สีครีม","สีเหลือง","สีชมพู"],
"การงาน" : ["สีเขียว"],
"การเงิน" : ["สีส้ม","สีน้ำตาล"],
"โชคดี" : ["สีดำ","สีเทา","สีม่วง"],
"สีต้องห้าม" : ["สีแดง"]
}

หลังจากได้รับผลลัพธ์ของเครื่องมือ คุณต้องแปลงเป็นข้อความเครื่องมือก่อนส่งไปยัง LLM มิฉะนั้นจะเกิดข้อผิดพลาด

# .....
# tool_result = get_color(day,aspect)
tool_result = {
"role" : "tool",
# แปลงเป็นสตริง
"content" : json.dumps({
"name": name,
"arguments": arguments,
"results": tool_result
},
# สิ่งนี้จำเป็นเพราะผลลัพธ์ของเครื่องมือเป็นภาษาไทย
indent=4, ensure_ascii=False
)
}
# เพิ่มผลลัพธ์ของเครื่องมือไปยังข้อความ
messages.append(tool_result)
# tool_result
{
'role': 'tool',
'content': {
"เสริมเสน่ห์" : ["สีขาว","สีครีม","สีเหลือง","สีชมพู"],
"การงาน" : ["สีเขียว"],
"การเงิน" : ["สีส้ม","สีน้ำตาล"],
"โชคดี" : ["สีดำ","สีเทา","สีม่วง"],
"สีต้องห้าม" : ["สีแดง"]
}
'tool_call_id': '91704bde-a78f-4298-98d4-fe9882da6eee'
}
5. ส่งผลลัพธ์ของเครื่องมือกลับไปยัง LLM

หากคุณพิมพ์ messages คุณจะเห็นประวัติการแชท

# messages
[
{'role': 'system', 'content': ..., # System prompt
{'role': 'user', 'content': ..., # Input message
ChatCompletionMessage(content=....), # LLM response including tool call message
{'role': 'tool', 'content': ... # Result from tool
]

หากข้อความใดข้อความหนึ่งหายไป LLM อาจไม่สามารถสร้างการตอบสนองสุดท้ายได้

โปรดทราบว่า tools=tools ไม่จำเป็นในกรณีนี้

final_response = llm.chat.completions.create(
model="typhoon-v2-8b-instruct", # แบบจำลอง Typhoon ที่เลือก
messages=messages, # ประวัติข้อความ
tools=tools, # เครื่องมือ
)
# messages[1]["content"]
วันอังคารควรใส่เสื้อสีอะไร
# final_response.choices[0].message.content
วันอังคารควรใส่เสื้อสีชมพูเพื่อเสริมเสน่ห์ สีม่วงหรือสีเทาสำหรับการงาน สีเงินหรือสีทองสำหรับการเงิน และสีส้มหรือน้ำตาลเพื่อโชคดี สีเหลืองและสีครีมเป็นสีต้องห้ามในวันนี้

LangChain

โค้ดทั้งหมด

from langchain_openai import ChatOpenAI
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage, ToolMessage
from pydantic import BaseModel, Field
llm = ChatOpenAI(
model='typhoon-v2-8b-instruct', # แบบจำลอง Typhoon ที่เลือก
base_url='https://api.opentyphoon.ai/v1', # ใช้ URL นี้เพื่อเข้าถึงแบบจำลอง Typhoon
api_key=TYPHOON_API_KEY) # ใส่ API key ของคุณที่นี่
class convert_currency(BaseModel):
"""Convert money from one currency to another currency."""
amount: float = Field(..., description="the amount of money to convert")
from_currency: str = Field(..., description="the old currency code to convert from eg. THB USD")
to_currency: str = Field(..., description="the new currency code to convert to eg. THB USD")
def invoke(tool_call) -> dict:
args = tool_call.get("args")
amount = args.get("amount")
from_currency = args.get("from_currency")
to_currency = args.get("to_currency")
# rate = 0.03 # USD
rate = 0.046 # AUD
to_amount = amount * rate
return {
"from_amount": amount,
"from_currency": from_currency,
"to_amount": to_amount,
"to_currency": to_currency,
}
llm = llm.bind_tools([convert_currency])
messages = [
SystemMessage(content="You are an expert at composing functions named Typhoon"),
# HumanMessage(content="เดือนหน้าจะไปเที่ยวอเมริกา มีอยู่ 100000 บาทแลกได้กี่ดอลลาร์"),
HumanMessage(content="เดือนหน้าจะไปเที่ยวออสเตรเลีย มีอยู่ 100000 บาทแลกได้กี่ดอลลาร์"),
]
llm_response = llm.invoke(messages)
messages.append(llm_response)
for tool_call in llm_response.tool_calls:
tool_result = convert_currency.invoke(tool_call)
tool_msg = ToolMessage(content=tool_result,
name=tool_call["name"],
tool_call_id=tool_call["id"])
messages.append(tool_msg)
final_response = llm.invoke(messages)
print(messages[1].content)
print(final_response.content)
เดือนหน้าจะไปเที่ยวออสเตรเลีย มีอยู่ 100000 บาทแลกได้กี่ดอลลาร์
คุณมีเงินประมาณ 4600 ดอลลาร์ออสเตรเลียสำหรับการเดินทางของคุณในออสเตรเลีย

การแบ่งโค้ด

1. เตรียม LLM ของคุณ

มาเริ่มด้วยการเตรียม LLM ของคุณให้พร้อมใช้งานก่อน

from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model='typhoon-v2-8b-instruct', # แบบจำลอง Typhoon ที่เลือก
base_url='https://api.opentyphoon.ai/v1', # ใช้ URL นี้เพื่อเข้าถึงแบบจำลอง Typhoon
api_key=TYPHOON_API_KEY) # ใส่ API key ของคุณที่นี่