10 คะแนน โดย GN⁺ 2025-06-11 | 2 ความคิดเห็น | แชร์ทาง WhatsApp
  • ช่วงหลังมานี้การนำ เอเจนต์ AI มาใช้งานเพิ่มขึ้น ทำให้แนวโน้มการใช้ไฮบริดสแต็กที่อิงกับ ภาษา Go เพิ่มขึ้นตามไปด้วย
  • เอเจนต์มีลักษณะเด่นคือ ใช้เวลารันนาน มี ต้นทุนสูง และมีช่วง รออินพุต/เอาต์พุต บ่อย
  • Go มี goroutine แบบเบา, กลไกการยกเลิกแบบรวมศูนย์, การส่งข้อความผ่าน channel และ โมเดล concurrency ประสิทธิภาพสูง
  • มี standard library ขนาดใหญ่ และใช้เครื่องมือโปรไฟล์อย่าง pprof เพื่อติดตาม หน่วยความจำรั่วและเธรดรั่ว ได้ง่าย
  • อย่างไรก็ดี Go ก็ยังมีข้อจำกัด เช่น ecosystem ด้าน machine learning ที่ยังไม่มาก, ประสิทธิภาพสูงสุดที่ไม่ได้โดดเด่นมาก, และ การรองรับจาก third-party ที่น้อยกว่าภาษาอื่น

เอเจนต์คืออะไร

  • เอเจนต์ทำงานอยู่ในลูปแบบทำซ้ำ และหมายถึง กระบวนการที่สามารถตัดสินใจขั้นตอนถัดไปของการทำงานได้ด้วยตัวเอง
  • ไม่ได้เป็นเส้นทางที่กำหนดไว้ล่วงหน้าแบบ workflow แต่จะตัดสินว่าควรจบการทำงานหรือไม่จากเงื่อนไขต่าง ๆ (เช่น “ทดสอบผ่าน”) หรือจำนวนรอบสูงสุด
  • เมื่อนำไปใช้งานจริง เอเจนต์มัก รันต่อเนื่องยาวนานตั้งแต่ไม่กี่วินาทีถึงหลายชั่วโมง และมี ต้นทุนสูง จากการเรียก LLM หรือการควบคุมเบราว์เซอร์
  • เพราะต้องประมวลผลอินพุตจากผู้ใช้ (หรือจากเอเจนต์ตัวอื่น) จึงมี เวลารอ I/O จำนวนมาก

ทำไมภาษา Go จึงเหมาะกับเอเจนต์

concurrency ประสิทธิภาพสูง

  • goroutine ของ Go ใช้หน่วยความจำเพียง 2KB ก็สามารถรันเธรดแบบเบาได้พร้อมกันตั้งแต่หลักพันถึงหลักหมื่น
  • แต่ละ goroutine ใช้ประโยชน์จาก มัลติคอร์ เพื่อประมวลผลแบบขนาน และรองรับเอเจนต์ที่อยู่ระหว่าง I/O หรือกำลังรอได้โดยไม่เป็นภาระมาก
  • ใช้การสื่อสารผ่าน channel เพื่อซิงโครไนซ์ด้วยการส่งข้อความแทนการแชร์หน่วยความจำ (ลดการใช้ Mutex ให้น้อยที่สุด)
  • เหมาะกับการให้เอเจนต์ส่งข้อความกันแบบอะซิงโครนัสและจัดการสถานะ

กลไกการยกเลิกแบบรวมศูนย์

  • เมื่อใช้ context.Context ของ Go ไลบรารีและ API ส่วนใหญ่รองรับสัญญาณยกเลิกอยู่แล้ว จึง หยุดการทำงานระหว่างรัน ได้ง่ายมาก
  • แม้ Node.js หรือ Python จะมีรูปแบบการยกเลิกหลายแบบปะปนกัน แต่ Go สามารถยกเลิกและคืนทรัพยากรได้อย่างปลอดภัยด้วยวิธีที่สม่ำเสมอ

standard library ที่อุดมสมบูรณ์

  • Go มี standard library ขนาดใหญ่ รองรับแทบทุกด้าน เช่น HTTP/เว็บ, ไฟล์, และ network I/O
  • I/O ทั้งหมดตั้งอยู่บนสมมติฐานของการทำงานแบบบล็อกภายใน goroutine จึงเขียน business logic แบบเส้นตรง (straight-line) ได้
  • ส่วน Python มีรูปแบบ concurrency หลายแบบปะปนกัน ทั้ง asyncio, threading และ process ทำให้ซับซ้อน

เครื่องมือ profiling และการวินิจฉัย

  • Go มีเครื่องมือในตัวอย่าง pprof ที่ช่วยติดตาม memory leak และ goroutine (thread) leak ได้แบบเรียลไทม์
  • จึงโดดเด่นในการวิเคราะห์ปัญหาการรั่วที่อาจเกิดในเอเจนต์ที่รันนานและทำงานพร้อมกันจำนวนมาก

รองรับการเขียนโค้ดด้วย LLM ได้ดี

  • ด้วย ไวยากรณ์ที่เรียบง่าย และ standard library ที่ครบถ้วน Go ทำให้ LLM เขียน โค้ดสไตล์ Go ที่เป็นธรรมชาติ ได้ดี
  • เนื่องจากพึ่งพาเฟรมเวิร์กไม่มาก LLM จึงไม่ต้องกังวลเรื่องเวอร์ชันหรือแพตเทิร์นมากนัก

ข้อจำกัดของ Go

  • ไลบรารี third-party และ ecosystem ยังน้อยกว่า Python และ TypeScript
  • ไม่เหมาะกับการ ทำ machine learning เองโดยตรง (ทั้งด้านประสิทธิภาพและการรองรับยังมีข้อจำกัด)
  • หากต้องการ ประสิทธิภาพสูงสุด Rust และ C++ จะเหมาะกว่า
  • สำหรับนักพัฒนาที่คุ้นกับการจัดการ error handling แบบยืดหยุ่น อาจรู้สึกว่าใช้งานไม่สะดวกนัก

2 ความคิดเห็น

 
codemasterkimc 2025-06-11

Java ดีกว่า แต่ถ้าเทียบกับ Go แล้ว Rust ดีกว่า :)

 
GN⁺ 2025-06-11
ความเห็นจาก Hacker News
  • มีการเน้นว่าปัจจัยที่ทำให้หน่วงที่สุดในระบบเอเจนต์ส่วนใหญ่สุดท้ายก็คือการเรียก LLM ข้อดีที่บทความกล่าวถึงไม่ได้เอื้อกับภาษาใดเป็นพิเศษ และโดยมากคือการรอนาน การใช้ทรัพยากรราคาแพง การรับอินพุตจากผู้ใช้หรือเอเจนต์อื่น และเวลาในการรอ I/O ที่สูง ดังนั้นเมื่อเป็นลักษณะงานแบบนี้ ความได้เปรียบที่สำคัญกว่าความเร็วหรือประสิทธิภาพของเซิร์ฟเวอร์กลับเป็นระบบนิเวศของไลบรารีและการรองรับด้าน AI ที่มหาศาลของภาษาอย่าง Python แม้จะมีคนชี้ว่าใน Python ต้องคอยคิดเรื่อง asyncio หรือไลบรารีมัลติเธรดดิ้ง แต่ในความเป็นจริงการพัฒนาเอเจนต์ไม่ได้ยากมาก และเพราะมีคนเคยสร้างเวิร์กโฟลว์ที่เกี่ยวข้องไว้แล้ว จึงคิดว่าเริ่มต้นได้ค่อนข้างง่าย

    • จากประสบการณ์ การสร้างเอเจนต์ด้วย Go มีข้อดีมากตรงที่รูปแบบการจัดการ concurrency และ backpressure ถูกวางแนวทางไว้ชัดเจน เอเจนต์ส่วนใหญ่มักมีทรานแซกชันกับบริการภายนอกที่ช้า และแพตเทิร์น concurrency ของ Go มีประโยชน์มากกับงานแบบนี้ แน่นอนว่าภาษาไม่ได้สำคัญมากนัก และดูเหมือน JavaScript จะถูกใช้มากที่สุด แต่ถ้าเป็นงานสร้างโค้ด ก็รู้สึกว่าการจับคู่ระหว่าง Go กับ LLM ให้ซินเนอร์จีที่ดี

    • Go มีความแตกต่างจาก Python ตรงที่จัดการ concurrency ได้ยอดเยี่ยมและ deploy ได้ง่าย เพียงแค่แจกจ่าย static binary ก็พอ จึงไม่ต้องเจอปัญหาเรื่อง environment และ dependency แบบ Python

    • เอเจนต์ทำหน้าที่เป็นชั้น orchestration และคิดว่า Go, Erlang, Node เหมาะเป็นพิเศษ ไม่จำเป็นต้องมีไลบรารีด้าน AI จำนวนมากเสมอไป และงานที่มี I/O หนักสามารถซ่อนไว้หลัง tool interface ตามโดเมน แล้วค่อยสร้าง subsystem ด้วยภาษาที่เหมาะสมตามต้องการได้

  • Go แทบไม่ได้มีข้อได้เปรียบมากนักกับเวิร์กโหลดประเภทนี้ เพราะเวลาส่วนใหญ่หมดไปกับการรอ I/O ระบบ type ของ Go ก็มีข้อจำกัด และหลายความสามารถที่ภาษาใหม่ ๆ มีมาให้ในตัว กลับต้องหาทางอ้อมใน Go TypeScript เป็นภาษา glue ที่ยอดเยี่ยมสำหรับงาน AI และมีการรองรับไลบรารีดีมากร่วมกับ Python เหตุผลที่ฉันชอบ TypeScript มากกว่า Python คือระบบ type ที่แข็งแรงและเป็นผู้ใหญ่มากกว่า แม้ Python เองก็กำลังพัฒนาเร็ว ข้ออ้างว่า Node.js และ Python หยุดงาน long-running ได้ยากมากนั้น ดูไม่มีหลักฐานชัดเจน เพราะเครื่องมือส่วนใหญ่รองรับเรื่องนี้อยู่แล้ว และภาษาหลักก็ยังเป็น Python กับ JS

    • ถ้าต้องการประสิทธิภาพจริง ๆ ก็ชอบวิธีเขียน native module ด้วย C++ หรือ Rust ซึ่งเร็วกว่า V8 มากกว่า ไม่จำเป็นต้องไปถึง Go
  • เคยทดลองเฟรมเวิร์กเอเจนต์บน Elixir และ BEAM แล้ว และคิดว่าการจับคู่ BEAM กับ SQLite คือสิ่งที่เหมาะกับเอเจนต์ที่สุดในตอนนี้ สามารถสลับเอเจนต์ได้อย่างปลอดภัยโดยไม่ต้อง redeploy แอปพลิเคชัน และ concurrency ของ BEAM ก็เหลือเฟือสำหรับงานนี้ การทำเอเจนต์แบบมีสถานะหรือแบบชั่วคราวก็ง่ายมาก ต่อไปตั้งใจจะสร้าง base agent ด้วย Python, Typescript, Rust และทำ MCP server เพื่อให้พัฒนาเอเจนต์ที่ซับซ้อนได้ตามความชอบของแต่ละภาษา

    • ขอแนะนำโปรเจกต์ Extism และ Elixir SDK ถ้าใช้ชุดนี้ ก็สามารถทำ core service, routing และ message passing ด้วย Elixir พร้อมใช้ประโยชน์จาก BEAM/OTP ได้ และยังสามารถฝังเอเจนต์ในรูปของ Wasm module ขนาดเล็กน้ำหนักเบาที่เขียนด้วยภาษาอื่นในลักษณะปลั๊กอินได้ด้วย
      Extism
      Elixir SDK

    • อยากรู้ว่ามีเหตุผลอะไรถึงเลือก SQLite แทน mnesia ซึ่งเป็น data store ในตัวของ BEAM
      mnesia docs

  • เวลาส่วนใหญ่ของเอเจนต์ถูกใช้ไปกับการรอคำตอบจาก LLM และการเรียกบริการภายนอกอย่าง API หรือ DB ผลกระทบจากประสิทธิภาพของ language runtime ในทางปฏิบัติจึงแทบไม่มีเลย ถ้าจะมีฟีเจอร์ของภาษาที่สำคัญจริงต่อประสิทธิภาพและความสามารถในการขยายของเอเจนต์ ก็น่าจะเป็นประสิทธิภาพในการ serialize และ deserialize JSON

    • เพราะแบบนั้นจึงคิดว่าการใช้ภาษาอย่าง TypeScript ที่จัดการ JSON ได้โดยกำเนิดน่าจะดีกว่า ระบบ type ของ TypeScript ก็แข็งแรงกว่า Go มากด้วย

    • จากประสบการณ์ นอกเหนือจากการเรียก LLM แล้ว สิ่งที่กินต้นทุนมากที่สุดในเอเจนต์คือการแก้ความขัดแย้งของการแก้ไขแบบอะซิงก์ เช่น merge, diff, patch งานนี้แม้จะโยนให้ไลบรารีระดับล่างจัดการได้ แต่ก็เป็นปัญหาที่ปรับให้เหมาะสมได้ยากพอ ๆ กับการ serialize

  • ทำให้นึกถึง คู่มือสร้างเอเจนต์ของ ampcode.com ใน Python ด้วยคุณสมบัติความเป็นภาษาดีไนมิก การใช้ decorator เพื่อแปลงเมธอดให้เป็น tool call ได้ทันที หรือการสร้างลิสต์ผ่านการวนซ้ำของฟังก์ชันเครื่องมือ รวมถึงการแปลงเป็น JSON schema อย่างรวดเร็ว ล้วนเป็นสิ่งที่ทำได้อย่างเป็นธรรมชาติ ในทางกลับกัน โครงสร้างที่มี external trigger หลายแบบ เช่น อินพุตผู้ใช้ อีเมล Gmail หรือข้อความ Slack เพื่อกระตุ้นให้รันเอเจนต์ใหม่ กลับรู้สึกว่าการใช้ channel กับ switch for loop ของ Go ตรงไปตรงมามากกว่า ใน Python ต้องแยกทำหลายคิวและหลายเธรดจึงซับซ้อนกว่า

  • ถ้าพิจารณาตามตรรกะของบทความ Elixir น่าจะเหมาะกับเอเจนต์อย่างยิ่ง

  • ระบบ type ที่จำกัดและไม่เพียงพอของ Go ทำให้มันไม่เหมาะกับแอปพลิเคชันแทบทุกประเภท จริง ๆ แล้วข้อเสียใหญ่ที่สุดของ Go คือภาษาเอง ส่วนสิ่งนอกตัวภาษาต่างหากที่ทำให้ยังพอยอมใช้ Go ได้

    • เขียนโปรแกรมด้วย Go มาหลายปี และเห็นด้วยว่าปัญหาระบบ type มีอยู่มาก คนในสาย LLM ดูเหมือนจะใช้กันแทบแค่ Python หรือ JavaScript ฉันคิดว่าทุกคนควรย้ายไปใช้ภาษาใหม่กว่า แต่ Go ก็อาจเป็นตัวเลือกที่พอไหวกว่าเมื่อเทียบกับความยุ่งเหยิงของระบบ import และ package ใน Python/JavaScript

    • อยากฟังแบบเจาะจงว่าข้อจำกัดของระบบ type ใน Go เป็นอุปสรรคต่อการสร้างเอเจนต์อย่างไร

    • ความจริงที่ Go มีระบบ static type ก็เพราะมันหาวิธีอื่นไม่เจอในการตอบโจทย์ประสิทธิภาพ จะมองว่ามันถูกใช้งานเหมือนภาษา dynamic typing ก็ถูกกว่า และผลนี้ก็มาจากการเข้าใจเป้าหมายการออกแบบภาษาผิดไป อาจมีคนเถียงได้ว่าภาษา dynamic typing ไม่เหมาะโดยรวม แต่ในความเป็นจริง Python, Erlang, Elixir และภาษา dynamic typing อื่น ๆ ก็ยังถูกใช้งานอย่างแพร่หลาย จึงกลับดูเหมือนว่า dynamic typing เหมาะกับ problem domain นี้มากกว่า

    • รู้สึกว่าค่าที่คืนมาหลายตัวเอาไป compose กันไม่ได้ การรองรับ error แม้จะดีกว่า exception แต่ก็ยืดยาวมาก channel ก็พลาดได้ง่าย และ enum type ก็น่าผิดหวัง ถึงอย่างนั้น interface กลับทำงานได้ดีเกินคาด และระบบ packaging ก็ลื่นไหลพอตัว พอไปเรียน Rust ก็พบว่า file structure ซับซ้อนกว่า Go มาก แถมเพราะตัวภาษาเรียบง่าย จึงสร้าง linter และเครื่องมือ code generation แบบต่าง ๆ ได้สะดวก การดูแลรักษาโค้ด Go ระยะยาวก็น่ากังวลน้อยกว่า Python/JS

    • ถ้ามีภาษาถิ่นของ LISP/Scheme ที่คอมไพล์เป็น Go และยังได้รับการดูแลอย่างดี ก็คงดีมาก

  • สำหรับโปรเซสที่ต้องรอนานและมีต้นทุนการรันสูง ข้อเสียคือถ้าโปรเซสตาย งานทั้งหมดก็หายไปด้วย การ serialize สถานะลงฐานข้อมูลระหว่างรออาจปลอดภัยกว่า แต่ก็ดูเหมือนไม่มีภาษาไหนที่ทำเรื่องนี้ได้ง่ายนัก การเขียน state machine แบบ checkpoint นั้นไม่ง่าย

    • มีการอธิบายว่า state machine แบบ checkpoint คือความสามารถหลักที่แพลตฟอร์มอย่าง Hatchet(hatchet.run) และ Temporal(temporal.io) มอบให้ โดยจะเก็บประวัติการรันฟังก์ชันในเวิร์กโฟลว์ไว้ และเมื่อเกิด interrupt ก็จะ replay ประวัตินั้นโดยอัตโนมัติ พร้อมยืนยันว่าประวัติความคืบหน้าระดับ output มีประสิทธิภาพกว่าการซิงก์หน่วยความจำมาก (ผู้ก่อตั้ง Hatchet)

    • ไม่ว่าจะเป็น goroutine, thread หรือ chain ที่รันยาว สุดท้ายก็ต้องแยกเป็นหน่วยงานแบบ atomic และต้อง serialize สถานะอยู่ดี เพื่อรองรับการกู้คืนจากความล้มเหลว การติดตามข้อผิดพลาด การอ้างอิงผลลัพธ์ย้อนหลัง และการกระจายงานข้ามหลายโหนด เฟรมเวิร์ก Oban(github.com/oban-bg/oban) ของ Elixir ก็ใช้แนวทางนี้ และขอแนะนำ บทความของ Oban ที่เน้นความสำคัญของการทำงานอะซิงก์แบบ persistent ด้วยเช่นกัน (ผู้เขียน Oban)

    • กำลังพัฒนาไลบรารีเอเจนต์บน golang และรู้สึกว่าถ้ามี logging ที่ดีพอ ก็สามารถกู้คืนสถานะของเอเจนต์ได้ตลอดเวลา ถ้ารู้แค่ timestamp กับ parent run ก็สามารถประกอบต้นไม้ของ child/branch run ได้ ใช้ทั้ง map และ DB ในการจัดการ session และสร้างกลับใหม่ได้เมื่อจำเป็น โครงสร้างนี้ไม่ได้ถือ object แต่ละตัวไว้ตรง ๆ แต่ให้ object ที่ไร้สถานะไปค้นด้วย id จาก map แล้วเก็บ action ก่อนหน้า step และ context ไว้ใน state object ส่วนความสอดคล้องของ agent/workflow ก็แก้ด้วยการจัดการผลลัพธ์เป็น hash ตอนนี้เพิ่งทำได้แค่เอเจนต์/ทูลพื้นฐาน ส่วน logic เรื่อง logging การกู้คืน และการยกเลิกยังไม่ได้พัฒนา

    • Temporal ค่อนข้างมีประโยชน์สำหรับ checkpointing ของโปรเซสระยะยาว และเป็นกลางทางภาษา

    • ฉันเองก็ลังเลเรื่อง task queue อยู่เหมือนกัน และกำลังคิดว่าจะทำ rudimentary queue บน Postgres ดีไหม ข้อดีคือกระจายเวิร์กโหลดระหว่างเซิร์ฟเวอร์ได้ ป้องกัน task หายเมื่อโปรเซสจบ และทำให้มองเห็นสถานะได้ดีขึ้น แต่แลกกับความซับซ้อนของโค้ดที่อาจเพิ่มขึ้นมาก จึงรู้สึกว่าออกแบบสถาปัตยกรรมให้เรียบง่ายนั้นยาก

  • วิศวกร AI จำนวนมากไม่ชอบใช้ JavaScript อย่างมาก การยุติ TensorFlow for Swift คือจุดจบของความหลากหลายด้านภาษาในวงการ AI

    • คิดว่าการไม่ชอบ JavaScript ไม่ได้เกิดเฉพาะในหมู่วิศวกร AI เท่านั้น ในฐานะคนที่เขียน JS มากว่า 30 ปี ก็เห็นด้วยเหมือนกัน

    • คิดว่า JS เป็นภาษาที่แย่มาก และการนำมันมาใช้กับแบ็กเอนด์เป็นความผิดพลาด ส่วน TypeScript เองก็ไม่ได้แก้ปัญหาพื้นฐานของ JS ได้จริง เวลาเลือกใช้ก็จะเลี่ยง JS หรือ TS แล้วไปเลือกทางเลือกอื่นอย่าง Go, Rust, Python, Ruby, Elixir, F# แทน

    • สงสัยว่าอะไรทำให้ JS เหมาะกับเอเจนต์เป็นพิเศษ

  • รู้สึกว่าวงการ ML ต้องการโมเดล concurrency ที่ดีกว่านี้ เคยลองทำ ML ด้วย Go แต่แทบเป็นไปไม่ได้ เพราะการรองรับไลบรารีไม่พอ และต้องพึ่งการเรียก gRPC ภายนอกหรือ wrapper เป็นหลัก Python ก็มีข้อจำกัด ส่วน C++ ก็ยืดยาวจนกระทบต่อผลิตภาพมาก