Gemini API ã® Function Calling æ©èœã§ LLM Agent ãå®è£ ãã
LLM Agent å ¥é
ããŒã¿åŠçãã€ãã©ã€ã³ãš LLM Agent ã®éã
Google Cloud ã® Gemini API ã«ã¯ Function Calling æ©èœãå®è£ ãããŠãããåºç€ã¢ãã«ã® Gemini ã«ãå€éš API ãå©çšããŠåçã«å¿ èŠãªæ å ±ãåéããããšããåäœã远å ã§ããŸããããã§ãã€ã³ãã«ãªãã®ã¯ããã©ã® API ãã©ã®ããã«äœ¿çšããã°åçã«å¿ èŠãªæ å ±ãåŸããããïŒããšããéšåã Gemini èªèº«ã«èãããããšããç¹ã§ãããããå©çšãããšããããã LLM Agent ãå®è£ ã§ããŸãã
éããã¹ãæ å ±ã®çš®é¡ãåŠçã®æé ããããããæ±ºãŸã£ãŠããå Žåã¯ãLLM ã«ããããã¹ãçæãçµã¿èŸŒãã ããŒã¿åŠçãã€ãã©ã€ã³ãå®è£ ããæ¹ãå®å®çã«åäœããïŒæåŸ ããçµæã確å®ã«åŸãããïŒã¯ãã§ãããç¹å®ã®æé ãåæãšããªãæè»ãªåŠçãå®çŸããé㯠LLM Agent ãåããŠããã§ãããã
ããšãã°ãéœéåºçåãéžã¶ãšãã®å°åã®å€©åãçãããã¹ãã«ãŸãšããŠæããŠããããµãŒãã¹ãäœãã®ã§ããã°ã
- éœéåºçåãåãåã
ãâ - ã倩åæ
å ±ãµãŒãã¹ APIãã§è©²åœå°åã®å€©åæ
å ±ãååŸãã
ãâ - åŸãããæ å ±ã LLM ã«æž¡ããŠå€©åç¶æ³ããŸãšããããã¹ããçæãã
ãšããäžé£ã®åŠçããã€ãã©ã€ã³ãšããŠå®è£ ããã°ããã§ãããã
äžæ¹ããæ±äº¬ãšäº¬éœã®çŸåšã®æ°æž©å·®ãç¥ãããããªã©ã倩åã«é¢ããããŸããŸãªè³ªåã«æè»ã«åçããã·ã¹ãã ãäœãå Žåã質åå 容ã«å¿ããŠãAPI ãµãŒãã¹ããååŸããæ å ±ãåãæ¿ããããè€æ°ã® API ãµãŒãã¹ãçµã¿åãããŠå©çšããå¿ èŠããããŸãããããå®çŸããã®ã LLM Agent ã®åœ¹å²ã§ãã
LLM Agent ãæåã§å®çŸããŠã¿ã
LLM Agent ã®åäœãçè§£ããããã«ãã·ã³ã°ã«ã¿ãŒã³ã® LLM ãå©çšããŠããæ±äº¬ãšäº¬éœã®çŸåšã®æ°æž©å·®ãç¥ãããããšãã質åã«çãã LLM Agent ã®åäœãæ¬äŒŒçã«åçŸããŠã¿ãŸãã以äžã¯ãCloud Console ã® Vertex AI Studio ã§ãgemini-1.5-pro-001 ã䜿ã£ãŠå®éã«åŸãããçµæã§ãã
ãŸããæ¬¡ã®ããã³ãããå ¥åããŠãå¿çãåŸãŸããããã³ããå ã§å©çšå¯èœãª API ãµãŒãã¹ãæå®ããŠãå¿ èŠãª API ã LLM ã«éžæãããããšç®è«ãã§ããŸãã
ããã³ãã1
# äŸé Œäºé
質åã«çããŠãã ããã
ããŒã«ã䜿çšããå¿
èŠãããå Žåã¯ãããŒã«åãšå
¥åããŒã¿ãçããŠãã ããã
ãã«ãã¿ãŒã³ã§åçããŸããããŒã«ã¯1床ã«1ã€ãã䜿ããŸããã
[ããŒã«]
ããŒã«åïŒæ°è±¡æ
å ±API
â æ©èœïŒ{location: 'éœåžå', data_type: 'æ°æž©' or '湿床'} ãå
¥åãããšãæå®ããéœåžã®çŸåšã®æ°æž©ããŸãã¯ã湿床ãåŸãããŸãã
ããŒã«åïŒäº€éæ
å ±API
â æ©èœïŒ{location: 'éœåžå'} ãå
¥åãããšãæå®ããéœåžã®çŸåšã®äº€éæ
å ±ãåŸãããŸãã
[質å]
æ±äº¬ãšäº¬éœã®çŸåšã®æ°æž©å·®ãæããŠãã ããã
# ããªãã®åç1
次ã®å¿çãåŸãããŸãããæ°è±¡æ å ± APIããšãäº€éæ å ± APIãããããŸãããæ°è±¡æ å ± APIãæ£ããéžæããããã§ãã
æ±äº¬ãšäº¬éœã®çŸåšã®æ°æž©ãç¥ãå¿
èŠããããŸããã ãŸããæ°è±¡æ
å ±APIã䜿ã£ãŠæ±äº¬ã®æ°æž©ã調ã¹ãŸãããã
䜿ãããŒã«ïŒæ°è±¡æ
å ±API å
¥åããŒã¿ïŒ{location: 'æ±äº¬', data_type: 'æ°æž©'}
ãã ããLLM èªèº«ã¯ãã® API ãµãŒãã¹ãåŒã³åºãããšã¯ã§ããŸããã®ã§ããã®éšåã¯äººéãæäŒããŸããäžèšã®ããŒã¿ {location: 'æ±äº¬', data_type: 'æ°æž©'} ãæ¶ç©ºã®æ°è±¡æ
å ± API ã«å
¥åããŠã{location: 'æ±äº¬', æ°æž©:'32床'} ãšããçµæãåŸããããšããŸãã
ãããŠãå ã»ã©ã®ããã³ããã« LLM ã®å¿çãš API ãµãŒãã¹ããåŸãããçµæãä»ãå ãããã®ãæ°ããããã³ãããšããŠãLLM ã«å ¥åããŸãã
ããã³ãã2
# äŸé Œäºé
質åã«çããŠãã ããã
ããŒã«ã䜿çšããå¿
èŠãããå Žåã¯ãããŒã«åãšå
¥åããŒã¿ãçããŠãã ããã
ãã«ãã¿ãŒã³ã§åçããŸããããŒã«ã¯1床ã«1ã€ãã䜿ããŸããã
[ããŒã«]
ããŒã«åïŒæ°è±¡æ
å ±API
â æ©èœïŒ{location: 'éœåžå', data_type: 'æ°æž©' or '湿床'} ãå
¥åãããšãæå®ããéœåžã®çŸåšã®æ°æž©ããŸãã¯ã湿床ãåŸãããŸãã
ããŒã«åïŒäº€éæ
å ±API
â æ©èœïŒ{location: 'éœåžå'} ãå
¥åãããšãæå®ããéœåžã®çŸåšã®äº€éæ
å ±ãåŸãããŸãã
[質å]
æ±äº¬ãšäº¬éœã®çŸåšã®æ°æž©å·®ãæããŠãã ããã
# ããªãã®åç1
æ±äº¬ãšäº¬éœã®çŸåšã®æ°æž©ãç¥ãå¿
èŠããããŸããã ãŸããæ°è±¡æ
å ±APIã䜿ã£ãŠæ±äº¬ã®æ°æž©ã調ã¹ãŸãããã
䜿ãããŒã«ïŒæ°è±¡æ
å ±API å
¥åããŒã¿ïŒ{location: 'æ±äº¬', data_type: 'æ°æž©'}
# ããŒã«ã®å¿ç1
{location: 'æ±äº¬', æ°æž©:'32床'}
# ããªãã®åç2
LLM ã¯ããã®ããã³ããã«å«ãŸãããããŸã§ã®ãããšããåæ¡ããŠã次ã®ã¹ããããå¿çãšããŠè¿ããŠãããŸãã
æ±äº¬ã®æ°æž©ã¯32床ã§ãããæ¬¡ã«ã京éœã®æ°æž©ã調ã¹ãŸãããã
䜿ãããŒã«: æ°è±¡æ
å ±API å
¥åããŒã¿: {location: '京éœ', data_type: 'æ°æž©'}
å
ã»ã©ãšåæ§ã«ãAPI ãµãŒãã¹ãåŒã³åºãéšåã¯äººéãæäŒããŸããäžèšã®ããŒã¿ {location: '京éœ', data_type: 'æ°æž©'} ãæ¶ç©ºã®æ°è±¡æ
å ± API ã«å
¥åããŠã{location: '京éœ', æ°æž©:'28床'} ãšããçµæãåŸããããšããŸããå
ã»ã©ã®ããã³ããã« LLM ã®å¿çãš API ãµãŒãã¹ã®åºåãããã«ä»ãå ããŠãå床ãLLM ãåŒã³åºããŸãã
ããã³ãã3
# äŸé Œäºé
質åã«çããŠãã ããã
ããŒã«ã䜿çšããå¿
èŠãããå Žåã¯ãããŒã«åãšå
¥åããŒã¿ãçããŠãã ããã
ãã«ãã¿ãŒã³ã§åçããŸããããŒã«ã¯1床ã«1ã€ãã䜿ããŸããã
[ããŒã«]
ããŒã«åïŒæ°è±¡æ
å ±API
â æ©èœïŒ{location: 'éœåžå', data_type: 'æ°æž©' or '湿床'} ãå
¥åãããšãæå®ããéœåžã®çŸåšã®æ°æž©ããŸãã¯ã湿床ãåŸãããŸãã
ããŒã«åïŒäº€éæ
å ±API
â æ©èœïŒ{location: 'éœåžå'} ãå
¥åãããšãæå®ããéœåžã®çŸåšã®äº€éæ
å ±ãåŸãããŸãã
[質å]
æ±äº¬ãšäº¬éœã®çŸåšã®æ°æž©å·®ãæããŠãã ããã
# ããªãã®åç1
æ±äº¬ãšäº¬éœã®çŸåšã®æ°æž©ãç¥ãå¿
èŠããããŸããã ãŸããæ°è±¡æ
å ±APIã䜿ã£ãŠæ±äº¬ã®æ°æž©ã調ã¹ãŸãããã
䜿ãããŒã«ïŒæ°è±¡æ
å ±API å
¥åããŒã¿ïŒ{location: 'æ±äº¬', data_type: 'æ°æž©'}
# ããŒã«ã®å¿ç1
{location: 'æ±äº¬', æ°æž©:'32床'}
# ããªãã®åç2
æ±äº¬ã®æ°æž©ã¯32床ã§ãããæ¬¡ã«ã京éœã®æ°æž©ã調ã¹ãŸãããã
䜿ãããŒã«: æ°è±¡æ
å ±API å
¥åããŒã¿: {location: '京éœ', data_type: 'æ°æž©'}
# ããŒã«ã®å¿ç2
{location: '京éœ', æ°æž©:'28床'}
# ããªãã®åç3
LLM ã®å¿çã¯æ¬¡ã®æ§ã«ãªããŸããç¡äºã«è³ªåã®åçãåŸãããŸããã
æ±äº¬ã®æ°æž©ã¯32床ã京éœã®æ°æž©ã¯28床ãªã®ã§ããã®å·®ã¯4床ã§ãã
æ±äº¬ãšäº¬éœã®çŸåšã®æ°æž©å·®ã¯ 4床 ã§ãã
ãã®äŸã§ã¯ãæ°è±¡æ å ± API ãã䜿ããŸããã§ãããã倩åãšäº€éã®äž¡æ¹ã«é¢ãã質åã§ããã°ãæ°è±¡æ å ± API ãšäº€éæ å ± API ãé çªã«å©çšããæµãã«ãªãããšã¯å®¹æã«æ³åã§ããã§ãããã
ãŸãããã®äŸã§ã¯ãLLM ãæå®ãã API ãµãŒãã¹ãå®è¡ããéšåã¯äººéãæåã§è¡ããŸããããLLM ã®å¿çãããŒã¹ããŠè©²åœã® API ãåŒã³åºãåŠçãèªåå®è¡ããã³ãŒããæžãã®ã¯ããã»ã©é£ããã¯ãªãã§ããããäžèšã®äžé£ã®äœæ¥ãã«ãŒãã§åããŠèªååããããšãã§ããã¯ãã§ãã
ãã ããLLM ã®å¿çãå®å®çã«ããŒã¹ããã«ã¯ãLLM ã®åºå圢åŒãåºå®ããããã®æç€ºãããã³ããã«äœã蟌ãå¿ èŠããããŸãããŸããè€æ°ã® LLM Agent ãäœæã»ã¡ã³ããã³ã¹ããããšãèãããšãããã³ããå ã«ããŒã«ã®æ©èœãèšè¿°ããéã®ãã©ãŒããããæšæºåããå¿ èŠãããããã§ãã
ââ ããã§ç»å Žããã®ã Function Calling ã§ãã
Function Calling ã®åœ¹å²
Function Calling ãå©çšãããšãäž»ã«æ¬¡ã®ããšãå¯èœã«ãªããŸãã
- å©çšãã API ãµãŒãã¹ã®ä»æ§ã OpenAPI 3.0 ã®æšæºãã©ãŒãããã§èšè¿°ãã
- LLM ã®å¿çãããŒã¹ããŠãAPI ãµãŒãã¹ã®äœ¿çšãèŠæ±ããŠãããã©ãããèªåã§å€å¥ãã
- LLM ãæå®ãã API ãµãŒãã¹ãžã®å ¥åããŒã¿ãæ§é åããŒã¿ãšããŠåãåºã
åè¿°ã®äœæ¥ãã«ãŒãã§åãéšå㯠Function Calling ã ãã§ã¯å®çŸã§ããããã®éšåã¯æ®éã«ã³ãŒããšããŠå®è£ ããå¿ èŠããããŸããããããã®æ©èœãããã°ãã³ãŒãã®å®è£ ã¯ããªã楜ã«ãªãããã§ãã
ãŸããå ã»ã©ã®äŸã§ã¯ãããã³ããã«æ°ããå 容ã远å ããŠãããŸããããGemini API ã®ããã£ããããã³ããããå©çšãããšãã®éšåãç°¡åã«ãªããŸãã远å éšåã ããå ¥åããã°ãèªåçã«éå»ã®ããåããèšé²ããããã³ããã«æ°ããå 容ã远å ãããŠãããŸãã
Function Calling ãçšãã LLM Agent ã®å®è£ äŸ
NYC TLC Trips ããŒã¿ã»ããã®æ€çŽ¢ Agent
BigQuery ã®ãªãŒãã³ããŒã¿ã»ããã«å«ãŸãã NYC TLC Trips ããŒã¿ã»ããã䜿ã£ãŠãã¿ã¯ã·ãŒã®å©çšå®¢ã«é¢ãã質åã«çãã LLM Agent ãäœæããŸããNYC TLC Trips ããŒã¿ã»ããã®èª¬æã¯æ¬¡ã®ãšããã§ãããããã§ã¯ã2022 幎㮠Yellow taxi ã«é¢ããæ å ±ã«éå®ããŠäœ¿çšããŸãã
This dataset is collected by the NYC Taxi and Limousine Commission (TLC) and includes trip records from all trips completed in Yellow and Green taxis in NYC, and all trips in for-hire vehicles (FHV) in the last 5 years. Records include fields capturing pick-up and drop-off dates/times, pick-up and drop-off locations, trip distances, itemized fares, rate types, payment types, and driver-reported passenger counts. For detailed information about this dataset, go to TOC Trip Record Data
å®éã®äœ¿çšäŸã¯æ¬¡ã®ããã«ãªããŸãã
Input
question = 'ããããããããããããå Žæã¯ïŒ'
response = ask_bigquery(question)
print('åç\n', response)
Output
** ã¯ãšãª **
SELECT taxi_zone_geom.zone_name, AVG(tip_amount) AS average_tip FROM bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2022 INNER JOIN bigquery-public-data.new_york_taxi_trips.taxi_zone_geom ON tlc_yellow_trips_2022.pickup_location_id = taxi_zone_geom.zone_id GROUP BY taxi_zone_geom.zone_name ORDER BY average_tip DESC LIMIT 1
** æ€çŽ¢çµæ **
[{"zone_name": "Newark Airport", "average_tip": "11.954689339"}]
åç
ããããããããããããå Žæã¯ããã¥ãŒã¢ãŒã¯ç©ºæž¯ã§ããå¹³åãããé¡ã11.95ãã«ã§æãé«ããªã£ãŠããŸããããã¯ã空枯ãžã®éè¿ãé·è·é¢ã§ããããšãå€ããããããé«é¡ã«ãªãåŸåããããããšèããããŸãã
Input
question = 'å¹³åä¹å®¢æ°ãå€ãå°åãšæé垯ã®çµã¿åããã«ã€ããŠãããïŒïŒãæããŠã'
response = ask_bigquery(question)
print('åç\n', response)
Output
** ã¯ãšãª **
SELECT tzpu.zone_name AS pickup_zone,
EXTRACT(HOUR FROM pickup_datetime) AS pickup_hour,
AVG(passenger_count) AS average_passenger_count
FROM `bigquery-public-data`.new_york_taxi_trips.tlc_yellow_trips_2022 AS yellow
JOIN `bigquery-public-data`.new_york_taxi_trips.taxi_zone_geom AS tzpu ON yellow.pickup_location_id = tzpu.zone_id
GROUP BY pickup_zone, pickup_hour
ORDER BY average_passenger_count DESC
LIMIT 10
** æ€çŽ¢çµæ **
[{"pickup_zone": "South Beach/Dongan Hills", "pickup_hour": "3", "average_passenger_count": "5.0"}, {"pickup_zone": "Country Club", "pickup_hour": "4", "average_passenger_count": "4.0"}, {"pickup_zone": "New Dorp/Midland Beach", "pickup_hour": "20", "average_passenger_count": "4.0"}, {"pickup_zone": "Rikers Island", "pickup_hour": "15", "average_passenger_count": "4.0"}, {"pickup_zone": "Ocean Parkway South", "pickup_hour": "2", "average_passenger_count": "3.8571428571428568"}, {"pickup_zone": "Green-Wood Cemetery", "pickup_hour": "14", "average_passenger_count": "3.5"}, {"pickup_zone": "Ocean Parkway South", "pickup_hour": "4", "average_passenger_count": "3.5"}, {"pickup_zone": "East Flushing", "pickup_hour": "18", "average_passenger_count": "3.3333333333333335"}, {"pickup_zone": "Ocean Parkway South", "pickup_hour": "1", "average_passenger_count": "3.3333333333333335"}, {"pickup_zone": "Green-Wood Cemetery", "pickup_hour": "16", "average_passenger_count": "3.0"}]
åç
2022幎ã®ã€ãšããŒã¿ã¯ã·ãŒä¹è»ããŒã¿ã«ãããšãå¹³åä¹å®¢æ°ãæãå€ãå°åãšæé垯ã®çµã¿åããããã10ã¯ä»¥äžã®éãã§ãã
1. South Beach/Dongan Hills, 3æ: å¹³åä¹å®¢æ° 5.0人
2. Country Club, 4æ: å¹³åä¹å®¢æ° 4.0人
3. New Dorp/Midland Beach, 20æ: å¹³åä¹å®¢æ° 4.0人
4. Rikers Island, 15æ: å¹³åä¹å®¢æ° 4.0人
5. Ocean Parkway South, 2æ: å¹³åä¹å®¢æ° 3.86人
6. Green-Wood Cemetery, 14æ: å¹³åä¹å®¢æ° 3.5人
7. Ocean Parkway South, 4æ: å¹³åä¹å®¢æ° 3.5人
8. East Flushing, 18æ: å¹³åä¹å®¢æ° 3.33人
9. Ocean Parkway South, 1æ: å¹³åä¹å®¢æ° 3.33人
10. Green-Wood Cemetery, 16æ: å¹³åä¹å®¢æ° 3.0人
ãªããªãå®çšçã§äŸ¿å©ããã§ãããFunction Calling ã§ã¯ãAPI ãµãŒãã¹ãžã®å ¥åããŒã¿ã LLM èªèº«ãèããŸãããããã§ã¯ãBigQuery ã API ãµãŒãã¹ãšããŠå©çšããŠããããã®å ¥åããŒã¿ãšãªã SQL ã®ã¯ãšãªã LLM èªèº«ãçæããŠããŸãã
å®è£ æé
äºåæºå
ããã§ã¯ãå ·äœçãªå®è£ å 容ã説æããŸããVertex AI Workbench ã®ããŒãããã¯äžã§å®è£ ããã®ã§ãæ°ãããããžã§ã¯ããäœæããããCloud Shell ã®ã³ãã³ã端æ«ãéããŠãVertex AI Workbench ã䜿çšããã®ã«å¿ èŠãª API ãæå¹åããŸããããããŠãBigQuery ã® API ãæå¹åããŠãããŸãã
gcloud services enable \
aiplatform.googleapis.com \
notebooks.googleapis.com \
bigquery.googleapis.com
次ã®ã³ãã³ãã§ Workbench ã€ã³ã¹ã¿ã³ã¹ãäœæããŸãã
PROJECT_ID=$(gcloud config list --format 'value(core.project)')
gcloud workbench instances create agent-development \
--project=$PROJECT_ID \
--location=us-central1-a \
--machine-type=e2-standard-2
ã¯ã©ãŠãã³ã³ãœãŒã«ã®ããã²ãŒã·ã§ã³ã¡ãã¥ãŒãããVertex AIãâãã¯ãŒã¯ãã³ãããéžæãããšãäœæããã€ã³ã¹ã¿ã³ã¹ agent-development ããããŸããã€ã³ã¹ã¿ã³ã¹ã®èµ·åãå®äºããã®ãåŸ
ã£ãŠããJUPYTERLAB ãéãããã¯ãªãã¯ãããããPython 3(ipykernel)ãã®æ°èŠããŒãããã¯ãäœæããŸãã
ãã®åŸã¯ãããŒãããã¯ã®ã»ã«ã§ã³ãŒããå®è¡ããŠãããŸãã
API ãµãŒãã¹ã®å®çŸ©
ãŸãã¯ãå¿ èŠãªã¢ãžã¥ãŒã«ãã€ã³ããŒãããŸãã
import json, vertexai
from google.cloud import bigquery
from vertexai.generative_models import \
FunctionDeclaration, GenerationConfig, GenerativeModel, Part, Tool
ãããŠãOpanAPI ã®ãã©ãŒãããã§ Agent ã䜿çšãã API ãµãŒãã¹ã®ä»æ§ã宣èšããŸãã
sql_query_func = FunctionDeclaration(
name='sql_query',
description='Get factual information from BigQuery using SQL queries',
parameters={
'type': 'object',
'properties': {
'query': {
'type': 'string',
'description': 'SQL query on a single line that will help give quantitative answers'
}
},
'required': ['query']
}
)
ããã§ã¯ããsql_query ãšããåç§°ã®ãµãŒãã¹ããã£ãŠãquery ãã©ã¡ãŒã¿ãŒã« SQL ã®ã¯ãšãªãæååã§äžãããš BigQuery ããæ
å ±ãåŸãããããšããäºå®ã宣èšããŠããŸããFunctionDeclaration ãšããã¯ã©ã¹åãããããããã«ãããã§å®çŸ©ãããã®ã¯ãAPI ãµãŒãã¹ã«éå®ããããã®ã§ã¯ãªããããã©ã¡ãŒã¿ãŒãäžãããšå¿çãåŸãããããšããæåãæåŸ
ããããã®ãã€ãŸããåºãæå³ã§ã®é¢æ°ãšããŠæ¯ãèããã®ã§ããã°ãªãã§ãæ§ããŸããã
LLM ã¯ã䜿çšãã API ãµãŒãã¹ãéžæããéã« description éšåã«æžãããæ
å ±ãåèã«ããŸãã®ã§ããã®éšåã«ã¯ã§ããã ã詳ããæ
å ±ãæžããŠããããšããå§ãããŸããçšæãã API ãµãŒãã¹ã Agent ãæ³å®éãã«å©çšããŠãããªãéã¯ããã®éšåã®èšè¿°ã工倫ããããšã§æ¹åããå ŽåããããŸãã
ã€ã¥ããŠãå®éã«äœ¿çšãã LLM ã¢ãã«ã®ãªããžã§ã¯ããååŸããŸããããã®éã«ã䜿çšå¯èœãªããŒã«ã®æ
å ±ã tools ãªãã·ã§ã³ã§åãæž¡ããŸãã
bq_tool = Tool(
function_declarations=[sql_query_func]
)
model = GenerativeModel(
'gemini-1.5-pro-001',
generation_config=GenerationConfig(temperature=0.4),
tools=[bq_tool]
)
ããã§ã¯ã2 è¡ç®ã§ãå
ã»ã©å®çŸ©ãã sql_query_func ãæå®ããŠããŸããè€æ°ã®ããŒã«ãããå Žåã¯ãã®ãªã¹ãã«è¿œå ããŸãããã®ã¢ãã«ã«ããã³ãããéä¿¡ãããšãããã³ããã§æç€ºçã«æå®ããªããŠããå¿
èŠãªéã¯ããŒã«ã®äœ¿çšãèŠæ±ããå¿çãè¿ãããã«ãªããŸãã
ããã³ãããã³ãã¬ãŒãã®çšæ
ãããŠããã®ã¢ãã«ã«è³ªåãæããããã®ããã³ããã®ãã³ãã¬ãŒããçšæããŸããæåŸã® {} ã®éšåã«å®éã®è³ªåãåã蟌ãã§äœ¿ããŸãã
prompt_template = '''\
You are a data analytics expert. Work on the following tasks.
[task]
A. Answer the question with the reason based on the data you get from BigQuery.
[condition]
A. Use SQL queries to get information from BigQuery using the column definitions in the [table information].
A. The answer and the reason must be based on the quantitative information in tables.
A. Use concrete area names in the answer instead of zone_id or location_id.
[format instruction]
In Japanese. In plain text, no markdowns.
[table information]
columns of the table 'bigquery-public-data.new_york_taxi_trips.taxi_zone_geom'
- zone_id : Unique ID number of each taxi zone. Corresponds with the pickup_location_id and dropoff_location_id in each of the trips tables
- zone_name : Full text name of the taxi zone
columns of the table: 'bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2022'
- pickup_datetime : The date and time when the meter was engaged
- dropoff_datetime : The date and time when the meter was disengaged
- passenger_count : The number of passengers in the vehicle. This is a driver-entered value.
- trip_distance : The elapsed trip distance in miles reported by the taximeter.
- fare_amount : The time-and-distance fare calculated by the meter
- tip_amount : Tip amount. This field is automatically populated for credit card tips. Cash tips are not included.
- tolls_amount : Total amount of all tolls paid in trip.
- total_amount : The total amount charged to passengers. Does not include cash tips.
- pickup_location_id : TLC Taxi Zone in which the taximeter was engaged
- dropoff_location_id : TLC Taxi Zone in which the taximeter was disengaged
[question]
{}
'''
[task] éšåã§ãBigQuery ã®ããŒã¿ã䜿ã£ãŠè³ªåã«çããããã«æç€ºããŠããŸãããŸãã[table information] ã®éšåã«äœ¿çšããããŒãã«ã®æ
å ±ãèšèŒãããŠããŸããããã®éšåã¯ãå®éã®ããŒãã«ã®ã¹ããŒãæ
å ±ããã®ãŸãŸã³ããããŠãããŸããããšãã°ãtaxi_zone_geom ããŒãã«ã®ã¹ããŒãæ
å ±ã¯æ¬¡ã®ããã«å®çŸ©ãããŠããŸãã

taxi_zone_geom ããŒãã«ã®ã¹ããŒãæ
å ±
Agent æ¬äœã®å®è£
ãããŠãããããAgent ã®åŠçãå®è£ ããã¡ã€ã³ããŒãã§ãã
def ask_bigquery(question):
chat = model.start_chat()
client = bigquery.Client()
prompt = prompt_template.format(question)
response = chat.send_message(prompt).candidates[0].content.parts
while True:
api_responses = []
try:
# Throw AttributeError unless function call is required.
# The response may contain multiple funcall call requests.
for _response in response:
function_call = _response.function_call
params = {key: value for key, value in function_call.args.items()}
if function_call.name == 'sql_query':
try:
query = params['query']
print(f'** ã¯ãšãª **\n{query}\n')
query_job = client.query(query)
result = query_job.result()
result = [dict(row) for row in result]
result = [{key: str(value) for key, value in raw.items()} for raw in result]
api_response = json.dumps(result)
except Exception as e:
api_response = json.dumps({'error message': f'{str(e)}'})
print(f'** æ€çŽ¢çµæ **\n{api_response}\n')
api_responses.append(api_response)
_api_response = [
Part.from_function_response(
name=function_call.name,
response={'content': api_response}
) for api_response in api_responses
]
response = chat.send_message(_api_response).candidates[0].content.parts
except AttributeError:
break
return response[0].text
ããã§ã¯ãGemini API ã®ãã£ããããã³ããã䜿çšããŠããŸããchat = model.start_chat() ã§çšæãããªããžã§ã¯ãã« chat.send_message() ã§ããã³ãããç¹°ãè¿ãéä¿¡ãããšãLLM ã¯ãéå»ã®ããã³ãããšãã®å¿çã®å±¥æŽã«ãæ°ããæå®ããããã³ããã远å ããå
容ããåãåã£ããã®ãšããŠå¿çãè¿ããŸãã
while True: ã®ã«ãŒããå§ãŸãçŽåã®éšåã§ã¯ãå
ã»ã©çšæãããã³ãã¬ãŒãã«åŒæ° question ã§åãåã£ã質åãåã蟌ãã ãã®ãæåã®ããã³ãããšããŠéä¿¡ããŠããã®å¿çãåãåã£ãŠããŸãã
次ã«ãwhile True: ã®å
éšã§ã¯ãLLM ããã®å¿çã API ãµãŒãã¹ïŒããŒã«ïŒã®å®è¡ãèŠæ±ããŠãããã倿ããŠåŠçãåå²ããŸãã
- API ãµãŒãã¹ã®å®è¡ãèŠæ±ããŠããå Žåã¯ãèŠæ±éãã«å®è¡ããŠããã®çµæãããã³ãããšããŠéä¿¡ãããïŒã«ãŒãã®å é ã«æ»ãïŒ
- API ãµãŒãã¹ã®å®è¡ãèŠæ±ããŠããªãå Žåã¯ãæçµã®åçãåŸããããã®ãšããŠããããè¿åŽãããïŒã«ãŒããæããŠçµäºããïŒ
å šäœãšããŠã次ã®ãããªã«ãŒããåãããšã«ãªããŸãã

Function Calling ã䜿çšãã Agent ã®åäœ
ããã§ã¯ãäž»èŠãªã¹ãããã®å®è£ ã詳ãã説æããŠãããŸãã
ãŸããã«ãŒãã®å
é ã§ã¯ãå¿çã«å«ãŸãã _response.function_call èŠçŽ ã倿° function_call ã«ä¿åããŠããŸããããã®èŠçŽ ã¯ãLLM ã API ãµãŒãã¹ã®å®è¡ãèŠæ±ããŠããå Žåã«ã®ã¿ååšããŸãããã®ãããAPI ãµãŒãã¹ã®å®è¡ãèŠæ±ããŠããªãå Žåã¯ãããã§äŸå€ãçºçããŠãexcept AttributeError: ã«åŠçãé£ãã§ã«ãŒããçµäºããŸãã
ãã®èŠçŽ ãååšããå Žåãfunction_call.name ã¯ã䜿çšãã API ãµãŒãã¹ã®åç§°ïŒäºåã«å®çŸ©ããå
容ã«å«ãŸãã name èŠçŽ ïŒã衚ãã®ã§ããã®å€ãèŠãŠã察å¿ãã API ãµãŒãã¹ãã³ãŒãããå®è¡ããŸãããã®äŸã§ã¯ãsql_query ã®äžæã«ãªããŸããAPI ãµãŒãã¹ã«éä¿¡ããã¹ããã©ã¡ãŒã¿ãŒã¯ãfunction_call.args.items ããååŸããŸãã
ãããŠããã®äŸã§ã¯ãBigQuery ã®ã¯ã©ã€ã¢ã³ã SDK ã䜿ã£ãŠã¯ãšãªãå®è¡ããåŸãåŸãããçµæãæ¬¡ã®æé ã§ JSON æååã«å€æããŠããŸãã
- åã¬ã³ãŒãããã£ã¯ã·ã§ããªã«å€æãããã®ãéãããªã¹ããäœã
ãâ - ãªã¹ãå
ã®ãã£ã¯ã·ã§ããªã®åã
ã®ããªã¥ãŒãæåååã«å€æãã
ãâ - åŸãããçµæã JSON æååã«å€æãã
ããã¯ãFunction Calling ã®ãçŽæã§ãAPI ãµãŒãã¹ããã®å¿ç㯠JSON æååã§åãæž¡ãããšã«ãªã£ãŠããããã§ãããŸããã¯ãšãªã®çµæããšã©ãŒã«ãªã£ãå Žåã¯ããšã©ãŒã¡ãã»ãŒãžãå¿çãšããŠè¿ããŸããããã¯éèŠãªãã€ã³ãã§ãLLM ãçšæããã¯ãšãªãééã£ãŠããå ŽåãLLM ã¯ãšã©ãŒã¡ãã»ãŒãžãåèã«ããŠãååºŠãæ°ããã¯ãšãªãææ¡ãããšããåäœãè¡ããŸãã
æåŸã«ãAPI ãµãŒãã¹ããã®å¿çãããã³ãããšããŠéä¿¡ããäžèšã®éšåã«ã€ããŠè£è¶³ããŸãã
_api_response = [
Part.from_function_response(
name=function_call.name,
response={'content': api_response}
) for api_response in api_responses
]
response = chat.send_message(_api_response).candidates[0].content.parts
ãã®éšåã¯ãFunction Calling ã®ãäœæ³ã«åŸã£ãŠã䜿çšãã API ãµãŒãã¹ã®åå function_call.name ãšå®è¡çµæ api_response ã Part.from_function_response() ã¡ãœããã§ Part ãªããžã§ã¯ãã«å€æãããã®ãéä¿¡ããŠããŸãããçŸåšã®å®è£
ã§ã¯ãããã¯å¿
é ã§ã¯ãããŸãããæ¬¡ã®æ§ã«ãã¬ã€ã³ããã¹ãã§éä¿¡ããŠããåçã®çµæãåŸãããŸãã
_api_response = [
Part.from_function_response(
name=function_call.name,
response={'content': api_response}
) for api_response in api_responses
]
response = chat.send_message(
f'[response from {function_call.name}]\n{_api_response}'
).candidates[0].content.parts
LLM Agent ã®å®è¡
ããã§ LLM Agent ã宿ããŸããã颿° ask_bigquery() ã«è³ªåãæãããšåçãåŸãããŸãã
question = 'ä¹å®¢æ°ãšãããã®å¹³åé¡ã衚ã«ããŠãä¹å®¢æ°ãšãããã®é¡ã«é¢é£æ§ãããã調ã¹ãŠã'
response = ask_bigquery(question)
print('åç\n', response)
å®è¡çµæ
** ã¯ãšãª **
SELECT passenger_count, AVG(tip_amount) AS average_tip_amount FROM bigquery-public-data.new_york_taxi_trips.tlc_yellow_trips_2022 GROUP BY passenger_count
** æ€çŽ¢çµæ **
[{"passenger_count": "5", "average_tip_amount": "2.682891441"}, {"passenger_count": "7", "average_tip_amount": "7.887932692"}, {"passenger_count": "3", "average_tip_amount": "2.732784987"}, {"passenger_count": "2", "average_tip_amount": "2.878064225"}, {"passenger_count": "6", "average_tip_amount": "2.702456693"}, {"passenger_count": "9", "average_tip_amount": "9.481282051"}, {"passenger_count": "1", "average_tip_amount": "2.64627696"}, {"passenger_count": "4", "average_tip_amount": "2.749474037"}, {"passenger_count": "None", "average_tip_amount": "3.718722887"}, {"passenger_count": "8", "average_tip_amount": "8.517593985"}, {"passenger_count": "0", "average_tip_amount": "2.437039335"}]
åç
ä¹å®¢æ°ãšãããã®å¹³åé¡ã¯ä»¥äžã®éãã§ãã
| ä¹å®¢æ° | ãããã®å¹³åé¡ |
|---|---|
| 0 | 2.44 |
| 1 | 2.65 |
| 2 | 2.88 |
| 3 | 2.73 |
| 4 | 2.75 |
| 5 | 2.68 |
| 6 | 2.70 |
| 7 | 7.89 |
| 8 | 8.52 |
| 9 | 9.48 |
ãã®ããŒã¿ãèŠããšãä¹å®¢æ°ã7人以äžã®å Žåã«ãããã®å¹³åé¡ã倧ããå¢å ããŠããããšãããããŸããã€ãŸããä¹å®¢æ°ãšãããã®é¡ã«ã¯ããçšåºŠã®é¢é£æ§ããããšèšããã§ãããã
ãŸãšã
å®è£ äŸã䜿çšããæ§åãèŠããšãã·ã³ãã«ãªå®è£ ãªããå®çšæ§ã®é«ã LLM Agent ãå®çŸã§ããŠããããšãããããŸãã宿¥åã§äœ¿ãéã¯ãLLM ãçæããã¯ãšãªãééã£ãŠããªããããã§ãã¯ã§ããçšåºŠã®ãªãã©ã·ãŒã¯å©çšè ã«å¿ èŠãããããŸãããã調ã¹ããå 容ã«ããããŠèªåã§ã¯ãšãªãèããããã¯ãã»ã©é«éã«èª¿ã¹ç©ãé²ã¿ããã§ãã
ä»åã®å®è£ äŸãããããããã«ãå€éšã® API ãµãŒãã¹ãåŒã³åºãåŠçã¯ãPython ã®ã³ãŒãã§æ®éã«å®è¡ããŠããŸãã®ã§ãåŒã³åºãã«å¿ èŠãªãã©ã¡ãŒã¿ãŒããæ±ºãŸãã°ãä»»æã®ããŒã«ãå©çšããããšãã§ããŸããä»ã® LLM Agent ãå€éš API ãµãŒãã¹ãšããŠå©çšãã倿®µæ§æã容æã«å®çŸã§ããã§ãããã
ãŸããäžè¬ã«ããšãŒãžã§ã³ãããšãããšãå€éšã·ã¹ãã ããæ å ±ãåéããã ãã§ã¯ãªãããŠãŒã¶ãŒã®ä»£ããã«å€éšã·ã¹ãã ãæäœããä»çµã¿ãæ³åããæ¹ãããããç¥ããŸãããä»åå®è£ ããã·ã¹ãã ãå¿çšããã°ããããç°¡åã«å®çŸã§ããŸããããšãã°ãéšå±ã®ãšã¢ã³ã³ãæäœãã API ãµãŒãã¹ãäœã£ãŠãããFunction Calling ã§ãã® API ãµãŒãã¹ã®æ å ±ãç»é²ãã LLM ãçšæããŸãããã® LLM ã«ãéšå±ãæããããªããšãããŠããšãããšããšã¢ã³ã³ã®èšå®æž©åºŠãäžãããªã¯ãšã¹ããå¿çãšããŠè¿ã£ãŠããŸããããšã¯ãå ã»ã©ãšåæ§ã®ã³ãŒãã§ããã®ãªã¯ãšã¹ããå®éã® API ãµãŒãã¹ã«æããã° OK ã§ãã
Discussion