ทำ Authentication ให้ LLM API ด้วย APISIX

Jittagornp
Lotus’s IT
Published in
8 min readAug 11, 2024

สวัสดีครับ ผมเดียร์จากทีม LSE (Lotus’s Store Engineering) นะครับ วันนี้จะมาแชร์ประสบการณ์ในการใช้ APISIX ช่วยทำ Authentication ให้กับ LLM API

หลายเดือนที่ผ่านมาเทรน AI (Artificial Intelligence) มาแรงมาก โดยเฉพาะเรื่อง LLM (Large Language Model) อย่าง ChatGPT

ตัวผมเองมีความสนใจและเริ่มเรียนรู้ LLM มาได้สักระยะนึงแล้ว ได้ Follow คนเก่ง ๆ ในวงการนี้ ได้ตามอ่านบทความต่าง ๆ ที่เพื่อน ๆ และคนเก่ง ๆ ในวงการ AI เค้าแชร์กันบนอินเตอร์เน็ต ทำให้พอมีความรู้เรื่อง LLM อยู่บ้างในระดับนึง (จริง ๆ แค่นิดนึง)

เนื่องจากมีความสนใจเรื่อง AI ด้าน LLM ทำให้ที่ผ่านมามีโอกาสได้ไปมีส่วนร่วมในการช่วย Research & Develop AI Project ของบริษัท เลยจะมาแชร์ความรู้บางส่วนที่ผมได้เข้าไปช่วยในงานนี้ให้เพื่อน ๆ ได้อ่านกันครับ

โจทย์

เราอยากที่จะ Host LLM Model ด้วย Inference Engine สักตัว ที่ Inference Engine นั้น Support การทำ Authentication แบบ Mutiple API Keys

Inference Engine คืออะไร?

Inference Engine คือ เครื่องมือที่เอามาใช้สำหรับ Host LLM Model

มีหลายตัวให้เลือกใช้ เช่น SGLang, vLLM, LMDeploy, TensorRT-LLM, MLC-LLM และอื่น ๆ ถ้าเปรียบเทียบกับฝั่ง Web Development ก็น่าจะเปรียบเทียบได้ว่ามันคือ Web Server ที่เราเอาไว้มา Host Website ของเรา เพียงแต่ Inference Engine เค้าเอาไว้ Host LLM Model ก็เท่านั้นเอง และ Inference Engine เหล่านี้ยัง Support API ในรูปแบบของ OpenAI ด้วย (OpenAI Compatible) ก็คือ เราสามารถใช้ OpenAI Library เขียน Code เชื่อมต่อมาที่ LLM ที่เรา Manual Host เองได้เลย

จากที่ทีมช่วยกันหาข้อมูลมา ก็เจอว่า Inference Engine ส่วนใหญ่ไม่ Support การทำ Authentication แบบ Mutiple API Keys คือ มันทำ Authentication ได้นะ แต่มันใส่ได้แค่ API Key เดียว และเราเองก็ไม่อยากที่จะเอา Feature นี้มาเป็นตัวเลือกหลักในการเลือกเอา Inference Engine นั้น ๆ มาใช้ในการ Host Model

ทำให้เราต้องมองหา Tool ตัวอื่นมาช่วยในเรื่องนี้แทน และ Tool ตัวนั้นก็น่าจะเป็นอะไรไปไม่ได้นอกซะจาก API Gateway

เหตุผลที่ต้อง Support Mutiple API Keys

เนื่องจากเราต้องการแยก API Keys สำหรับแต่ละ Service หรือ Client ที่ต้องการมาใช้งาน LLM Service ของเรา

APISIX คืออะไร?

APISIX มีชื่อเต็ม ๆ ว่า Apache APISIX เป็น Open source API Gateway ตัวนึงที่คนเริ่มให้ความสนใจกันมากขึ้น เนื่องจากมีจุดเด่นในหลาย ๆ ด้าน เช่น

  • มี Performance ที่ดี เนื่องจาก APISIX Build on top Nginx (คนในวงการจะรู้อยู่แล้วว่า Nginx นั้นเร็ว)
  • สามารถทำ Config แบบ Dynamic ผ่าน API ได้
  • มี Web UI (User Interface) ให้ใช้
  • มี Plugin ให้เลือกใช้งานค่อยข้างเยอะ
  • Support หลาย Protocol เช่น Http(s), gRPC, WebSocket, TPC, UDP เป็นต้น
  • ออกแบบมาเพื่อให้ทำงานร่วมกับ Cloud-Native Application ได้ เช่น Kubernetes, Docker เป็นต้น
  • อยู่ภายใต้การดูแลของ Apache Foundation
  • อื่น ๆ

อันนี้เป็นข้อมูลที่ APISIX นำเสนอ ว่าตัวเองดีกว่า API Gateways เจ้าอื่น ๆ ยังไง

ในบนความนี้ เราจะพาทุกคนไปใช้งานแค่บางอย่างใน APISIX เท่านั้น นั่นก็คือ การทำ Authenication ด้วย API Key

แต่ก่อนที่จะเริ่มทำ Authentication กัน เรามารู้จักกับคำศัพท์ 3 คำนี้ก่อน

  1. Upstream
  2. Routing
  3. Consumer

Upstream

เป็นกลุ่มของ Server หรือ Backend service ที่ต้องการให้ Client เข้าถึง ซึ่งอยู่หลัง APISIX ถ้าตามรูปนี้ ก็คือ Inference Engine ต่าง ๆ ที่ Host LLM Model อยู่

Routing

คือ วิธีการ Route หรือการกำหนดเส้นทางไปยัง Upstream ที่กำหนด เช่น เราอาจจะ Config ไว้ว่า ถ้ามีการเรียกใช้ Path นี้

/llm/neuralmagic/Meta-Llama-3.1–70B-Instruct-FP8/*

ให้ไปใช้งาน Inference Engine Service ที่ Host LLM Model Meta-Llama-3.1–70B-Instruct-FP8 อยู่

Consumer

คือ Client หรือ Service ที่ต้องการใช้งาน Service ต่าง ๆ ที่อยู่หลัง APISIX แต่ละ Consumer เราสามารถกำหนด ID และข้อมูลการ Authen ให้ Consumer นั้น ๆ ได้ เช่น

  • กำหนดให้ Consumer นี้ใช้ Username/Password เป็นอะไร
  • กำหนดให้ Consumer นี้มี API Key เป็นอะไร
  • เป็นต้น

การติดตั้ง APISIX

ในบทความนี้เราจะใช้ Docker Compose ช่วยในการติดตั้ง สามารถไป Clone repository นี้ลงมา แล้วทำตามได้เลย https://github.com/jittagornp/llm-setup

เมื่อ Clone ลงมาแล้ว ให้ run

cd apisix
docker compose up -d

เพื่อ Create และ Start Container

เราจะเห็นว่ามี Container 3 ตัวถูก Created ขึ้นมาดังนี้

  1. etcd — เป็น Key-value data store ที่เอาไว้เก็บค่า Configuration ต่าง ๆ ของ APISIX เมื่อเรามีการแก้ไขค่าอะไรต่าง ๆ ค่า Config นั้นจะถูกนำมาเก็บไว้ใน etcd
  2. apisix — เป็น API Gateway
  3. apisix-dashboard — เป็น Web UI ให้เราสามารถเข้าไป Config APISIX ได้ง่ายขึ้น

ลองเข้า http://localhost:7000/

จากนั้นลอง Login ด้วย username/password — admin/password ดู ก็จะเข้าสู่หน้า Dashboard ของ APISIX แบบนี้

การ Host LLM Model

ในหัวข้อนี้ จะเป็นการ Host LLM Model ขึ้นมาสักตัว เพื่อทดสอบร่วมกับ APISIX ซึ่งถ้าหากว่าเราไม่มีเครื่อง Computer ที่มี GPU แรง ๆ ให้ลองทดสอบ ก็อาจจะ Run Nginx web server ขึ้นมาง่าย ๆ สัก 1 Container แบบนี้ก็ได้

docker run -d \
-p 4001:80 \
--network ai \
--restart always \
--name sglang-neuralmagic-Meta-Llama-3.1-70B-Instruct-FP8 \
nginx

ลองเข้า http://localhost:4001 เราก็จะได้ Mock LLM API ขึ้นมา 1 ตัว

แต่ถ้าเรามีเครื่อง Computer ที่มี GPU แรง ๆ ก็สามารถทำตามนี้ได้เลย อันนี้เรา Host บนเครื่องที่มี GPU H100 2 ใบนะ

การ Host LLM Model บน GPU Nvidia ให้ run Command นี้

docker run -d --runtime nvidia --gpus all \
-p 4001:30000 \
-v /data/models/.cache/huggingface:/root/.cache/huggingface \
-e "HF_TOKEN=<YOUR_HUGGING_FACE_TOKEN>" \
--ipc=host \
--network ai \
--restart always \
--name sglang-neuralmagic-Meta-Llama-3.1-70B-Instruct-FP8 \
lmsysorg/sglang:latest \
python3 -m sglang.launch_server \
--model-path neuralmagic/Meta-Llama-3.1-70B-Instruct-FP8 \
--host 0.0.0.0 --port 30000 \
--mem-fraction-static 0.5 \
--tp 2

จาก Command ด้านบน เราใช้ SGLang (Inference Engine ตัวนึง) ในการช่วย Host LLM Model neuralmagic/Meta-Llama-3.1–70B-Instruct-FP8 ซึ่ง Model เราเอามาจาก Hugging Face อาจจะลองเปลี่ยนเป็น Model อื่น ๆ ดูก็ได้

อย่าลืมเปลี่ยน Environment variable ตรงนี้นะ ***

HF_TOKEN=<YOUR_HUGGING_FACE_TOKEN>

อันนี้ต้องไปสร้าง Token ใน Hugging Face ก่อน

หากตัว Docker image ของ SGLang ที่ใช้ run มีปัญหา เราอาจจะต้อง Custom Docker image กันนิดนึง โดยการเขียน Dockerfile แล้ว build Docker image ใหม่ดังนี้

Dockerfile

FROM lmsysorg/sglang:latest

# Install python-multipart
RUN pip install python-multipart

Build Docker image command

docker build -t lotuss/sglang .

จากนั้นก็ใช้ Command เดิม แต่เปลี่ยน image จาก lmsysorg/sglang -> lotuss/sglang

ถ้า Host ขึ้น ก็จะขึ้น logs แบบนี้

ดู logs ใช้ Command

docker logs -f sglang-neuralmagic-Meta-Llama-3.1-70B-Instruct-FP8

ตอนนี้ LLM service เราก็พร้อมใช้งานแล้ว

การ Setup APISIX ให้ Route ไปยัง Upstream ที่กำหนด

จากภาพด้านบน เราต้องการกำหนดให้ ถ้ามีการเรียกใช้ API ด้วย Path /llm/neuralmagic/Meta-Llama-3.1–70B-Instruct-FP8/* ให้ไปที่ LLM Model Meta-Llama-3.1–70B-Instruct-FP8 เราสามารถ Config APISIX ได้ดังนี้

  1. ไปที่ Menu Upstream แล้วคลิกที่ปุ่ม Create เพื่อกรอกข้อมูล Upstream ลงไป

ระบุข้อมูลของ Upstream ลงไป

เพิ่มแค่นี้

  • Name: sglang-neuralmagic-Meta-Llama-3.1–70B-Instruct-FP8
  • Host: sglang-neuralmagic-Meta-Llama-3.1–70B-Instruct-FP8
  • Port: 30000
  • Send Timeout: 60s
  • Read Timeout: 60s
  • อื่น ๆ เป็นค่า Default ทั้งหมด

จากนั้นก็ Next และ Submit

หมายเหตุ

ที่ต้องเป็น Port 30000 เนื่องจาก LLM ใน Container เราใช้ Port เป็น 30000 และ APISIX + LLM เราใช้ Network เดียวกัน ( — network ai) ก็เลย Reference ถึงกันด้วย Container name + Application Port

ถ้าหากเรา Mock LLM Model ด้วย Nginx web server ก็ต้องเปลี่ยนจาก Port จาก 30000 -> 80

เราสามารถ Create Upstream อื่น ๆ เพิ่มเติมได้ ตามรูป

2. ไปที่ Menu Route แล้วคลิกที่ปุ่ม Create เพื่อทำการ Create Routing ให้ Map ไปยัง Upstream ที่กำหนด

ระบุข้อมูลของ Route ลงไป

(1) Define API Request

เพิ่มแค่นี้

  • Name: neuralmagic-Meta-Llama-3.1–70B-Instruct-FP8
  • Path: /llm/neuralmagic/Meta-Llama-3.1–70B-Instruct-FP8/*
  • URI Override: Regex
  • Regexp: /llm/neuralmagic/Meta-Llama-3.1–70B-Instruct-FP8
  • Template: (Empty string)
  • อื่น ๆ เป็นค่า Default ทั้งหมด

จากนั้นก็ Next

(2) Define API Backend Server

เพิ่มแค่นี้

  • Upstream: sglang-neuralmagic-Meta-Llama-3.1–70B-Instruct-FP8 (เลือกจาก Dropdown)

จากนั้นก็ Next

(3) Plugin Config

*** อันนี้ยังไม่ต้อง Config อะไร กด Next ไปก่อน ***

(4) Preview

กด Submit ได้เลย

เราสามารถ Create Route อื่น ๆ เพิ่มเติมได้ ตามรูป

ลอง Call LLM API ผ่าน APISIX ดู

curl http://localhost/llm/neuralmagic/Meta-Llama-3.1-70B-Instruct-FP8/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "neuralmagic/Meta-Llama-3.1-70B-Instruct-FP8",
"prompt": "What is the LLM?",
"temperature": 0.7
}'

จะเห็นว่าเราสามารถ Call ไปที่ LLM API ของเราผ่าน APISIX ได้

แต่ถ้าเรา Mock ด้วย Nginx web server ตอนทดสอบก็อาจจะ Call แค่

curl http://localhost/llm/neuralmagic/Meta-Llama-3.1-70B-Instruct-FP8

การ Setup API Key

ที่ผ่านมา เรายังไม่ได้ทำการกำหนด API Key ให้แต่ละ Client ที่จะมาเรียกใช้ LLM API ของเรา ทำให้เวลาที่แต่ละ Client มีการเรียกใช้ LLM API ก็จะสามารถเรียกใช้โดยตรงได้เลย โดยไม่ต้องส่ง API Key มา ซึ่งอาจจะดูไม่ปลอดภัยในมุมของการใช้งานสักเท่าไหร่

เรามาเริ่ม Set API Key กัน

  1. ไปที่ Menu Consumer แล้วคลิกที่ปุ่ม Create เพื่อทำการสร้าง Client และกำหนด API Key ให้ Client นั้น ๆ

ระบุชื่อ Consumer หรือ Client ลงไป เช่น

(1) Basic Information

  • Name: service1

จากนั้นคลิกที่ปุ่ม Next

(2) Plugin Config

ให้ Enable Plugin ที่ชื่อว่า key-auth

จากนั้นกำหนด Config เป็น

{
"key": "Bearer 1234"
}

หมายเหตุ

ที่ต้องกำหนด key ให้ขึ้นต้นด้วยคำว่า Bearer เนื่องจาก เราต้องการให้ API Key อยู่ในรูปแบบของ Bearer Token ก็คือ เวลาส่ง API Key มา ให้ส่งมาในรูปแบบ Http Header แบบนี้

"Authorization": "Bearer 1234"

จากนั้นคลิก Submit

(3) Preview

คลิก Next เพื่อ Preview แล้วคลิก Submit อีกครั้ง

เราก็จะได้ Consumer ขึ้นมาแบบนี้

เราสามารถเพิ่ม Consumer อื่น ๆ อีกได้

2. กลับไปที่ Menu Route เพื่อเปิดใช้งาน API Key

เลือก Route Name ที่ต้องการ

Next ไปเรื่อย ๆ จนถึง Tab Plugin Config

จากนั้น ให้ Enable Plugin ที่ชื่อว่า key-auth ขึ้นมา เพื่อผูก (Bind) Plugin เข้ากับ Routing นี้

จากนั้นกำหนด Config เป็น

{
"header": "Authorization"
}

จากนั้นคลิก Submit

คลิก Next และ Submit อีกครั้ง

จากนั้นลองทดสอบ Call LLM API อีกครั้ง

จะพบว่า มันมี Error Missing API Key found in request เกิดขึ้นตามรูป

ลอง Call LLM API โดยใส่ API Key ในรูปแบบ Bearer Token ลงไป

curl http://localhost/llm/neuralmagic/Meta-Llama-3.1-70B-Instruct-FP8/v1/completions \
-H "Content-Type: application/json" \
-d '{
"model": "neuralmagic/Meta-Llama-3.1-70B-Instruct-FP8",
"prompt": "What is the LLM?",
"temperature": 0.7
}' -H "Authorization: Bearer 1234"

เพิ่ม -H “Authorization: Bearer 1234”

จะพบว่า สามารถ Call LLM API ได้แล้ว

ลองเชื่อมต่อ LLM ของเราด้วย OpenAI Library

อันนี้เป็นตัวอย่าง Code Python ง่าย ๆ ที่เราใช้เชื่อมต่อไปยัง LLM API ของเรา

from openai import OpenAI

ai_server="http://localhost"
api_key="1234"
model_id = "neuralmagic/Meta-Llama-3.1-70B-Instruct-FP8"

client = OpenAI(
api_key=api_key,
base_url=f"{ai_server}/llm/{model_id}/v1"
)
response = client.chat.completions.create(
model=f"{model_id}",
messages=[
{"role": "system", "content": "You are a helpful assistant."},
{"role": "user", "content": "Who are you?"},
],
temperature=0.8,
top_p=0.8
)
print(response.choices[0].message)

แค่นี้ เราก็มี LLM service ให้คนอื่นสามารถเรียกใช้งานได้อย่างปลอดภัยแล้ว

--

--

Jittagornp
Lotus’s IT

วิศกรซอฟต์แวร์ ที่หลงรักการเขียนซอฟต์แวร์ และมีความสุขกับการได้อยู่กับครอบครัว