การเรียกใช้เครื่องมือ (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 ขั้นตอนหลัก:
- กำหนดเครื่องมือของคุณ
- ติดตั้งเครื่องมือให้กับ LLM ของคุณ
- รับข้อความเรียกใช้เครื่องมือ
- ใช้เครื่องมือ
- ส่งผลลัพธ์ของเครื่องมือกลับไปยัง LLM
ดังที่คุณเห็น LLM จะถูกเรียกใช้อย่างน้อยสองครั้ง ครั้งแรกเพื่อรับข้อความเรียกใช้เครื่องมือและอีกครั้งเพื่อสร้างการตอบสนองสุดท้ายสำหรับผู้ใช้หลังจากได้รับผลลัพธ์ของเครื่องมือ
การรวมระบบ
OpenAI
โค้ดทั้งหมด
from openai import OpenAIimport 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].messagemessages.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 ChatOpenAIfrom langchain_core.messages import SystemMessage, HumanMessage, AIMessage, ToolMessagefrom 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 ของคุณที่นี่