แนะนำ OctoHub: ประตูหน้าเดียวสำหรับทุก LLM ที่เอเจนต์ของคุณเรียกใช้
เอเจนต์ของคุณเพิ่งรันงานเสร็จ มันเรียกโมเดลไปสี่สิบครั้ง บางครั้งไปที่เครื่อง Ollama ในเครื่อง บางครั้งไป Anthropic และอีกครั้งไป OpenAI เพราะโมเดลในเครื่องสำลักกับคอนเท็กซ์ยาว ๆ งานเสร็จแล้ว ทีนี้ตอบผมสามคำถาม: มันส่งอะไรออกไปกันแน่ ราคาเท่าไร และอัปสตรีมไหนที่ตอบจริง ๆ
ถ้าคุณเป็นเหมือนเราในตอนนั้น คำตอบที่ซื่อสัตย์คือ "ผมคงต้องไปใส่ print แล้วรันใหม่อีกรอบ" แดชบอร์ดของผู้ให้บริการแสดงเฉพาะส่วนของมัน ล็อกของเอเจนต์แสดงเฉพาะส่วนของมัน ไม่มีใครแสดงคำขอทั้งก้อนตามที่มันวิ่งผ่านสายไป พร้อมแท็กว่าคีย์ไหนออกมันและผู้ให้บริการไหนรับไป มุมมองที่มีประโยชน์ที่สุด — ทุกคำขอผ่านหน้าจอเดียว — กลับเป็นสิ่งที่ไม่มีใครให้ เพราะไม่มีจุดเดียวที่คำขอทั้งหมดวิ่งผ่าน
OctoHub คือจุดเดียวนั้น มันคือ LLM proxy แบบ self-hosted ที่คุณวางไว้หน้าเอเจนต์ของคุณ พวกมันคุยกับเอนด์พอยต์เดียว OctoHub คุยกับใครก็ตามที่คุณบอก และจดทุกอย่างที่เกิดขึ้นระหว่างนั้นไว้ วันนี้เราเปิดซอร์สมัน
มันคืออะไร ในแผนภาพเดียว
┌──────────────────┐
agent → │ OctoHub proxy │ → openai
│ (Rust / hyper) │ → anthropic
│ │ → ollama (your GPU)
└──────────────────┘ → openrouter
│
└─→ your DB (SQLite / MySQL / PostgreSQL)
(api_keys, completions, embeddings)
ไบนารี Rust ตัวเดียวที่สร้างบน hyper ไคลเอนต์ยิงเข้าเอนด์พอยต์ HTTP เดียว พรอกซีแปลงชื่อโมเดล เลือกอัปสตรีม ส่งต่อคำเรียกผ่าน octolib — ไลบรารีไคลเอนต์ LLM ของเรา ตัวเดียวกับที่ทุกเครื่องมือของ Muvon ใช้คุยกับโมเดล — แล้วบันทึกคำขอ คำตอบ จำนวนโทเคน และเวลาหน่วงลงไป ตัวพรอกซีเองไม่มีสถานะระหว่างคำขอ สถานะอยู่สองที่: octohub.toml สำหรับการตั้งค่า และฐานข้อมูลสำหรับคีย์ ล็อก และการใช้งาน
มันจงใจ ไม่ใช่ หลายอย่าง มันไม่ใช่ UI แชต — ให้เล็งแอปพลิเคชันของคุณมาที่มัน มันไม่ใช่ตัวเราต์เชิงความหมายที่เลือกโมเดล "ดีที่สุด" สำหรับพรอมป์ต; การเลือกโมเดลเป็นหน้าที่ของผู้เรียก มันไม่ใช่ vector store; embedding วิ่งผ่านและถูกบันทึก แต่ OctoHub ไม่ทำดัชนีให้ มันเพิ่มการยืนยันตัวตน การบันทึก การกระจายโหลด และอินเทอร์เฟซที่เสถียร มันไม่พยายามฉลาดกับสิ่งที่ผู้ให้บริการส่งกลับมา — ทุกฟิลด์ที่มีความหมายกลับไปหาไคลเอนต์ตามเดิมเป๊ะ
ทำไมเราถึงสร้างมัน
เราไม่ได้ตั้งใจจะสร้างพรอกซี เรากำลังรัน Octomind รันไทม์เอเจนต์ของเรา บนโมเดลผสม ๆ กัน — มีฟลีตแบบ self-hosted บน GPU ของเราเองสำหรับงานปริมาณมากราคาถูก และ API ระดับแนวหน้าสำหรับงานยาก ตัวระบบทำงานได้ สิ่งที่ทำไม่ได้คือการ มองเห็น มัน
ทันทีที่คุณมีโมเดลมากกว่าหนึ่งตัวอยู่หลังแอปพลิเคชันเดียว คุณก็เสียหน้าจอเดียวนั้นไป ผู้ให้บริการแต่ละรายมีแดชบอร์ดของตัวเอง มีการนับโทเคนของตัวเอง มีนิยามของ "คำขอ" ของตัวเอง เอเจนต์ของคุณก็มีล็อกของมันเอง ซึ่งบอกสิ่งที่มัน คิดว่า มันส่งออกไป เวลารันหนึ่งครั้งแพงกว่าที่คาด หรือโมเดลเริ่มคืนขยะออกมา คุณก็ต้องเย็บเรื่องราวที่ไม่ครบสามชิ้นเข้าด้วยกัน แล้วเดาตรงรอยต่อ
เราเขียนถึงความเจ็บปวดเฉพาะจุดนี้ไว้มากกว่านี้ — การอยากเห็นว่าเอเจนต์ทำอะไรจริง ๆ ไม่ใช่สิ่งที่มันอ้าง — ใน observability ที่เราต้องการ OctoHub คือคำตอบเชิงโครงสร้างพื้นฐานต่อมัน วางพรอกซีหนึ่งตัวไว้บนเส้นทาง แล้วหน้าจอเดียวก็เกิดขึ้นโดยการออกแบบ: มันมีจุดเดียวจริง ๆ ที่ทุกคำขอวิ่งผ่าน ดังนั้นจึงมีจุดเดียวที่จะบันทึกมันได้
เหตุผลที่สองคือการกระจายโหลด เราก็ รันเอเจนต์เดียวข้ามหลายโมเดล ด้วยมืออยู่แล้ว — สลับคอนฟิก ตั้งตัวแปรสภาพแวดล้อม เปลี่ยนชื่อโมเดลทุกครั้งที่รัน เราต้องการ alias ของโมเดลที่หมายความว่า "อันไหนก็ได้ในอัปสตรีมพวกนี้ แล้วแต่เธอเลือก" และมีลิมิตการทำงานพร้อมกัน เพื่อไม่ให้คำเรียกของเอเจนต์ที่พรั่งพรูเข้ามาเผาเครื่อง GPU ในเครื่อง ทั้งสองอย่างควรอยู่ในพรอกซี ไม่ใช่กระจัดกระจายอยู่ในทุกไคลเอนต์
คำขอไหลผ่านมันอย่างไร
ลองดู POST /v1/completions นี่คือสิ่งที่ OctoHub ทำกับมัน:
- ยืนยันตัวตน โทเคน
Authorization: Bearerคือคีย์ API ของไคลเอนต์จากตารางapi_keysOctoHub ค้นหามัน ตรวจว่ายังใช้งานได้ แล้วแท็กคำขอด้วย ID ของคีย์ (ถ้าคุณสตาร์ทเซิร์ฟเวอร์โดยไม่มี master key จะปิดเฉพาะ admin API เท่านั้น — มีคำเตือนพิมพ์ออกมาตอนสตาร์ท ส่วนการเรียก completion และ embedding ยังต้องใช้คีย์ไคลเอนต์ที่ใช้งานได้) - ตรวจ allow-list คีย์ไคลเอนต์จำกัดให้ใช้เฉพาะชุดโมเดลได้ คีย์ที่ถูกจำกัดไว้ที่
["gpt", "anthropic:claude-haiku-4-5"]แล้วขออย่างอื่นจะได้403 - แปลงโมเดล ถ้าฟิลด์
modelเป็น alias จาก[models]OctoHub จะขยายมันเป็นสตริงprovider:modelถ้ามันเป็นprovider:modelเปล่า ๆ อยู่แล้ว ก็ผ่านตรงไป alias ที่แมปไปยัง รายการ จะเริ่มจากตำแหน่งสุ่มแล้วเลือกผู้ให้บริการแรกที่รับได้ — นั่นคือการกระจายโหลด - ขอ permit ของผู้ให้บริการ ถ้าคุณตั้งลิมิตการทำงานพร้อมกันของผู้ให้บริการนั้นไว้ คำขอจะรอช่องว่าง ไม่มีช่องก็ไม่มี
429— การเชื่อมต่อ HTTP จะค้างเปิดไว้จนกว่าจะมีช่องว่าง — นานสุดตามไทม์เอาต์ของคิว (ค่าเริ่มต้น 60 วินาที) จากนั้นจะได้503เป็นการคุมอัตราโดยตั้งใจ บันทึกเป็นเวลารอในคิว - เรียกอัปสตรีม ผ่าน octolib พร้อมเส้นตายของการดำเนินการที่ตั้งค่าได้
- บันทึกและตอบกลับ คำขอทั้งก้อน คำตอบ จำนวนโทเคน ต้นทุน ผู้ให้บริการที่แปลงได้ และเวลาหน่วง ลงตาราง
completionsไคลเอนต์ได้คำตอบของอัปสตรีมตามเดิม พร้อมเฮดเดอร์X-Request-Id
เจ้า X-Request-Id นั่นคือคีย์สำหรับเชื่อมข้อมูล มันคือค่าที่คุณส่งเข้ามา (ตรวจสอบแล้ว ส่งกลับ) หรือ ULID ตัวใหม่ มันปรากฏเป็น req_id ในทุกบรรทัดล็อกของคำขอนั้น หยิบคำตอบที่เป็น error คว้าเฮดเดอร์ grep ในล็อกของคุณ — คุณก็ได้เรื่องราวทั้งหมด
Alias ของโมเดลและการกระจายโหลด
ส่วน [models] คือที่ที่ชื่อเดียวแผ่ออกไปสู่อัปสตรีมหลายตัว:
[models]
# หนึ่ง alias หนึ่งอัปสตรีม
"sonnet" = ["anthropic:claude-sonnet-5"]
# หนึ่ง alias หลายอัปสตรีม — OctoHub สุ่มเลือกหนึ่งตัวต่อคำขอ
"workhorse" = ["ollama:kimi-k2.6", "ollama:minimax-m3", "openrouter:google/gemini-3.1-pro-preview"]
[embedding_models]
"voyage" = ["voyage:voyage-4"]
ไคลเอนต์ที่ขอ workhorse จะได้หนึ่งในสามตัว — OctoHub เริ่มจากตำแหน่งสุ่มแล้วเลือกผู้ให้บริการแรกที่หน้าต่างอัตรารับคำขอได้ นั่นคือโมเดลการกระจายโหลดทั้งหมด — เรียบง่าย คาดเดาได้ และพอดีพอที่จะกระจายทราฟฟิกของเอเจนต์ข้ามฟลีตหรือข้ามคีย์ได้โดยไม่ต้องมีตัวเราต์แยก วันนี้ยังไม่มีการเราต์แบบถ่วงน้ำหนัก; ผู้ให้บริการที่อยู่ในช่วงคูลดาวน์จากข้อผิดพลาดจะถูกลดลำดับไปอยู่หลังผู้ให้บริการที่ปกติ และคำขอที่ต่อเชนจะยึดผู้ให้บริการที่รับเทิร์นก่อนหน้า เราอยากปล่อยเวอร์ชันซื่อสัตย์ของมันมากกว่าที่จะบอกใบ้ถึงตัวจัดคิวที่ฉลาดเกินกว่าที่มีอยู่จริง
ไคลเอนต์ยังข้าม alias ไปเลยก็ได้ และส่ง provider:model เปล่า ๆ อย่าง openai:gpt-5.5 ตาราง alias เป็นความสะดวก ไม่ใช่ด่าน — ด่านคือ allow-list ต่อคีย์
โมเดล auto: บอกว่าทำไม ไม่ใช่ว่าตัวไหน
ตั้งแต่เวอร์ชัน 0.6.0 มีวิธีเลือกโมเดลอีกแบบ และเป็นวิธีที่เอเจนต์ของเราเองใช้มากที่สุด แทนที่จะระบุชื่อโมเดล ไคลเอนต์ส่ง "model": "auto" พร้อมเฮดเดอร์ X-Model-Purpose — สตริงอะไรก็ได้ตามใจ — แล้ว OctoHub จะแปลงวัตถุประสงค์นั้นเป็น alias:
[auto]
default = "workhorse"
compression = "cheap"
supervisor = "sonnet"
วัตถุประสงค์เป็นแบบลำดับชั้น แยกด้วย -: supervisor-gate จะ fallback ไปที่ supervisor แล้วไปที่ default แถว supervisor เพียงแถวเดียวครอบคลุมทุกวัตถุประสงค์ supervisor-* จนกว่าคุณจะปักหมุดตัวเฉพาะ — คุณนิยามแถวเท่าที่คุณมีความเห็นเท่านั้น วัตถุประสงค์ที่หายไปหรือพิมพ์ผิดจะเดเกรดไปที่ default ไม่เคยล้มเหลว
ทำไมต้องทำ? เพราะผู้เรียกมักรู้ว่า กำลังทำคำเรียกแบบไหน — รอบบีบอัด การตรวจเกต ลูปหลัก — ส่วนผู้ดูแลรู้ว่าคำเรียกแบบนั้นสมควรอยู่เทียร์ไหน การเราต์ตามวัตถุประสงค์ย้ายการตัดสินใจนั้นไปไว้ในคอนฟิกของพรอกซี (หรือในแผนที่ override ต่อเจ้าของผ่าน PUT /v1/admin/owners/:owner/auto ซึ่งชนะพื้นฐานจากคอนฟิกทั้งหมด) แทนที่จะฝังชื่อโมเดลไว้ในเอเจนต์ Octomind ส่ง main, compression และตระกูล supervisor-* มาให้ตั้งแต่แรก
การทำงานพร้อมกันต่อผู้ให้บริการ
API ระดับแนวหน้าของคุณรับสามสิบสองคำขอพร้อมกันได้แบบไม่กระพริบตา เครื่อง GPU เดียวของคุณที่รัน Ollama รับไม่ไหว ดังนั้น OctoHub จึงจำกัดจำนวนคำขอที่กำลังวิ่งต่อผู้ให้บริการ:
[providers.ollama]
concurrency = 5
[providers.openai]
concurrency = 32
คำขอที่เกินลิมิตจะเข้าคิว ภายในโปรเซสของ OctoHub — การเชื่อมต่อของไคลเอนต์ถูกบล็อกจนกว่าจะมีช่องว่าง ผู้ให้บริการที่คุณไม่ได้ระบุไว้จะรันโดยไม่จำกัด ตัวจำกัดเป็นแบบ process-local และนับ completions กับ embeddings รวมกัน เพราะทั้งคู่ไหลผ่านการเชื่อมต่ออัปสตรีมเดียวกัน มันคือ semaphore หนึ่งตัวต่อผู้ให้บริการ ไม่มีอะไรพิสดาร แต่หมายความว่าเอเจนต์ที่กระจายสี่สิบคำเรียกออกไปจะไม่ล้มเซิร์ฟเวอร์โมเดลที่คำเรียกพวกนั้นไปลง
การทำงานพร้อมกันไม่ใช่ปุ่มเดียว ผู้ให้บริการแต่ละรายยังรับลิมิตอัตราแบบหน้าต่างคงที่ — requests_per_minute, tokens_per_minute, requests_per_day, tokens_per_day — และ alias ที่มีหลายอัปสตรีมจะหมุนไปยังตัวเลือกถัดไปเมื่อหน้าต่างเต็ม นั่นคือ "หน้าต่างอัตรา" ที่ตัวเลือก alias ตรวจสอบ: ผู้ให้บริการรายหนึ่งใช้งบโทเท็นรายวันหมดไม่ได้ทำให้คำขอล้มเหลว แค่ย้ายทราฟฟิกไปยังอัปสตรีมถัดไปที่ยังมีที่ว่าง
observability ที่คุณได้จริง ๆ
นี่คือส่วนที่เราสร้าง OctoHub ขึ้นมาเพื่อมัน มันจึงมีสองพื้นผิว
ล็อกแบบมีโครงสร้าง บน stdout — สวยถ้าคุณอยู่บน TTY ไม่งั้นเป็น JSON ทุกคำขอที่เสร็จจะปล่อยออกมาหนึ่งบรรทัด:
{
"level": "INFO",
"message": "request completed",
"req_id": "01HMQGSB3R",
"route": "/v1/completions",
"status": 200,
"dur_ms": 1523,
"api_key_id": 1,
"model": "workhorse",
"provider": "ollama",
"queued_ms": 0,
"tok_in": 56,
"tok_out": 120
}
คุณเห็นคีย์ที่ออกมัน ชื่อโมเดลที่ไคลเอนต์ขอ ผู้ให้บริการที่ตอบจริง มันเข้าคิวนานเท่าไร ใช้เวลาเท่าไร และโทเคนเข้าและออก ฟิลด์ provider คือคำตอบของ "การสุ่มเลือกไปลงที่อัปสตรีมไหน" — โดยไม่ต้องรันอะไรซ้ำ
เมตริก Prometheus บนพอร์ตแยก (ค่าเริ่มต้น 127.0.0.1:9090, GET /metrics) ทุกตัวมีคำนำหน้า octohub_:
| เมตริก | บอกอะไรคุณ |
|---|---|
octohub_requests_total |
ปริมาณคำขอตาม route, method, status |
octohub_request_duration_seconds |
ฮิสโตแกรมเวลาหน่วงปลายถึงปลาย |
octohub_completions_total |
ปริมาณ completion ตาม model, provider, status |
octohub_completion_tokens_total |
โทเคนเข้า/ออกตาม model และ provider |
octohub_provider_queue_wait_seconds |
เวลารอ permit การทำงานพร้อมกัน |
octohub_provider_in_flight |
คำขอที่กำลังทำงานในแต่ละ provider ตอนนี้ |
ฮิสโตแกรมเวลารอในคิวคือตัวบ่งชี้ล่วงหน้าของความอิ่มตัว — เมื่อ P99 ไต่ขึ้น ฟลีตของคุณกลายเป็นคอขวดก่อนที่คำขอใดจะหมดเวลา PromQL ไม่กี่บรรทัดให้อัตราข้อผิดพลาดตามโมเดลและโทเคนออกต่อวินาทีตามผู้ให้บริการ เปิด per_key = true แล้วเมตริก completion จะได้ป้าย api_key_id เพิ่ม เพื่อให้คุณคิดเงินหรือปันต้นทุนต่อไคลเอนต์ได้ (ระวังคาร์ดินาลิตีถ้าคุณออกคีย์เป็นพัน ๆ ใบ)
สำหรับบันทึกฉบับเต็ม — ไม่ใช่ค่ารวม แต่เป็นไบต์จริงของพรอมป์ตและคำตอบ — admin API เสิร์ฟประวัติ completions ดิบ ๆ ตรงจากฐานข้อมูล
คีย์แบบหลายผู้เช่าและ admin API
OctoHub มีชั้นยืนยันตัวตนสองชั้น master key (ตั้งใน octohub.toml) ปกป้อง admin API คีย์ไคลเอนต์ — ออกผ่าน admin API นั้น เก็บในฐานข้อมูล — ยืนยันตัวตนเอนด์พอยต์ completion และ embedding ทุก completion ถูกแท็กด้วยคีย์ที่ออกมัน ซึ่งเป็นสิ่งที่ทำให้การติดตามการใช้งานต่อผู้เช่าทำงานได้
มี shell wrapper ชื่อ octohub-admin.sh สำหรับงานประจำวัน:
export OCTOHUB_MASTER_KEY=your-master-secret
# ออกคีย์ไคลเอนต์ จำกัดที่สองโมเดล
./octohub-admin.sh keys create ci-pipeline --allowed-models gpt,anthropic:claude-haiku-4-5
# การใช้งานรายวันของคีย์ 1 และ 2
./octohub-admin.sh usage --bucket day --key 1,2
# ดึง completions ดิบ 20 รายการล่าสุด — input และ output ฉบับเต็ม
./octohub-admin.sh completions --limit 20
คีย์ถูกเพิกถอน ไม่เคยถูกลบ — บันทึกการใช้งานผูกกับ ID ของคีย์ ประวัติจึงอยู่รอด การใช้งานถูกรวมยอดตาม hour, day, week หรือ month กรองตามคีย์และช่วงเวลาได้ ข้อมูลเดียวกันใช้ผ่าน HTTP ธรรมดาได้ถ้าคุณไม่อยากใช้สคริปต์
ยังมีพื้นผิวด้านการดูแลระบบอีกสองอย่างที่ควรรู้ GET /v1/admin/status รายงานสุขภาพต่อโมเดลที่สังเกตจากทราฟฟิกจริง — ไม่ใช่โพรบจำลอง ดังนั้นสะดุดครั้งเดียวจะไม่วาดไฟแดงบนแดชบอร์ดของคุณ และการส่ง SIGHUP ให้โปรเซสจะรีโหลด octohub.toml ทันที — alias ใหม่ ลิมิตใหม่ โดยไม่ต้องรีสตาร์ท
รันมันใน 5 นาที
OctoHub คือไบนารีตัวเดียว สร้างมัน เขียนคอนฟิก สตาร์ทมัน ออกคีย์
# 1. สร้างจากซอร์ส
git clone https://github.com/Muvon/octohub
cd octohub && cargo build --release
เขียน octohub.toml แบบน้อยที่สุด:
[server]
host = "127.0.0.1"
port = 8080
api_key = "your-master-secret" # เปิด auth + admin API
db_url = "sqlite://octohub.db" # สร้างสคีมาอัตโนมัติตอนรันครั้งแรก
[models]
"workhorse" = ["ollama:kimi-k2.6", "openrouter:google/gemini-3.1-pro-preview"]
[metrics]
enabled = true
bind = "127.0.0.1:9090"
[providers.ollama]
concurrency = 5
สตาร์ทมันแล้วสร้างคีย์ไคลเอนต์:
# 2. สตาร์ทเซิร์ฟเวอร์ (ชี้คอนฟิกด้วย -c ถ้าไม่ได้อยู่ใน cwd)
./target/release/octohub
# 3. ออกคีย์ไคลเอนต์
curl -X POST http://127.0.0.1:8080/v1/admin/keys \
-H "Authorization: Bearer your-master-secret" \
-H "Content-Type: application/json" \
-d '{"name": "my-app"}'
# → {"id": 1, "key": "abc...xyz", ...} ← เก็บไว้ มันแสดงแค่ครั้งเดียว
# 4. ทำ completion ผ่านพรอกซี
curl -X POST http://127.0.0.1:8080/v1/completions \
-H "Authorization: Bearer abc...xyz" \
-H "Content-Type: application/json" \
-d '{"model": "workhorse", "input": "Explain Rust in one sentence."}'
ฐานข้อมูลเริ่มต้นเป็น SQLite — ไม่ต้องตั้งค่าอะไร ชี้ db_url ไปที่ MySQL หรือ PostgreSQL เมื่อคุณโตเกินมัน; สคีมาถูกสร้างอัตโนมัติตอนเชื่อมต่อครั้งแรก คีย์ API ของผู้ให้บริการ (OPENAI_API_KEY, ANTHROPIC_API_KEY และพวกพ้อง) อยู่ในสภาพแวดล้อม อ่านโดย octolib ตรงตามที่ผู้ให้บริการคาดหวัง
OctoHub ยังพูด OpenAI Chat Completions แบบดั้งเดิมที่ POST /v1/chat/completions ด้วย ดังนั้น SDK หรือเครื่องมือใด ๆ ที่เข้ากันได้กับ OpenAI ก็ชี้มาที่มันเป็น base URL แบบสลับใช้แทนกันได้ทันที (ข้อแม้ที่ซื่อสัตย์: ยังไม่รองรับ streaming — คำขอที่มี "stream": true จะได้ 501)
ชี้ Octomind มาที่มัน
OctoHub และ Octomind ถูกสร้างมาเพื่อกันและกัน และ octolib ก็มาพร้อมผู้ให้บริการ octohub: แบบเนทีฟ — ไม่ใช่ shim เข้ากันได้กับ OpenAI แต่พูด Responses API ของ OctoHub โดยตรง ตัวแปรสภาพแวดล้อมสองตัวเชื่อมพวกมันเข้าด้วยกัน:
export OCTOHUB_API_URL=http://127.0.0.1:8080 # เซิร์ฟเวอร์ OctoHub ของคุณ
export OCTOHUB_API_KEY=abc...xyz # คีย์ไคลเอนต์ที่คุณออก
ตอนนี้การอ้างอิงโมเดลใด ๆ ใน Octomind ในรูปแบบ octohub:<alias> จะเราต์ผ่านพรอกซี:
octomind run --model octohub:workhorse developer:general
เอเจนต์คิดว่ามันกำลังคุยกับผู้ให้บริการเดียว แต่หลังพรอกซี workhorse แผ่ออกไปทั่วฟลีตของคุณ ทุกคำเรียกถูกบันทึกพร้อมต้นทุนและอัปสตรีมที่ตอบ และลิมิตการทำงานพร้อมกันก็ช่วยให้เครื่อง GPU ยืนได้ เอเจนต์ยังเรียบง่าย ส่วนการมองเห็นอยู่ที่ ๆ คำขอวิ่งข้ามสายจริง ๆ
และนี่ไม่ใช่การทดลองในห้องแล็บ Octomind Cloud — รันไทม์เอเจนต์แบบมีผู้จัดการของเรา — รันเอเจนต์ของลูกค้าทุกตัวผ่าน OctoHub บนโปรดักชัน คำเรียกมาพร้อมแท็กวัตถุประสงค์ (main, compression, supervisor-gate) โมเดล auto จะเราต์แต่ละคำเรียกไปยังเทียร์ที่เหมาะ และทุกคำขอลงในบันทึกพร้อมต้นทุนและอัปสตรีมที่ตอบ ไบนารีตัวเดียวกับที่คุณโคลนได้คือตัวที่ยืนอยู่หน้าฟลีตของเรา
โอเพนซอร์ส Rust Apache-2.0
OctoHub อยู่ บน GitHub ภายใต้ Apache-2.0 มันคือไบนารี Rust ตัวเดียวที่สร้างบน hyper — เล็ก เร็ว และพึ่งพาน้อย ใช้ SQLite เป็นค่าเริ่มต้นจึงไม่มีอะไรต้องตั้ง มี MySQL และ PostgreSQL เมื่อคุณต้องการ การตั้งค่าคือไฟล์ TOML หนึ่งไฟล์บวกกับ override สภาพแวดล้อม OCTOHUB_* อีกหยิบมือสำหรับสิ่งที่คุณปรับต่อการดีพลอย (OCTOHUB_DB_URL, OCTOHUB_LOG_FORMAT, OCTOHUB_METRICS_BIND)
มันยังเป็นช่วงต้น — เวอร์ชัน 0.6.4 ตัวเลขที่ซื่อสัตย์ มันทำตามที่บอก: ประตูหน้าเดียว alias ของโมเดล การเราต์ auto ตามวัตถุประสงค์ การกระจายโหลดพร้อม failover และคูลดาวน์ การทำงานพร้อมกันและลิมิตอัตราต่อผู้ให้บริการ การตรวจ modality ที่ข้ามผู้ให้บริการที่รับรูปหรือวิดีโอของคุณไม่ไหว คีย์แบบหลายผู้เช่า การบันทึกคำขอฉบับเต็ม และเอนด์พอยต์ Prometheus การรองรับผู้ให้บริการยังโตเรื่อย ๆ — Google Studio มาในเวอร์ชัน 0.6.2 เพิ่มจากยี่สิบกว่าตัวที่มีอยู่ มันยังไม่ทำ streaming หรือการเราต์แบบถ่วงน้ำหนัก และผมอยากบอกคุณตรง ๆ ดีกว่าให้คุณไปรู้เอาตอนอยู่บนโปรดักชัน
ถ้าคุณรันโมเดลมากกว่าหนึ่งตัวหลังแอปพลิเคชันเดียว — และถ้าคุณกำลังสร้างเอเจนต์ คุณก็รัน — OctoHub ให้หน้าจอเดียวที่สแต็กส่วนที่เหลือแอบสันนิษฐานว่ามีอยู่ โคลนมัน ชี้เอเจนต์มาที่มัน แล้วดูรันหนึ่งครั้งวิ่งผ่านไปพร้อมต้นทุนแนบมาด้วย
— Don
OctoHub เป็นโอเพนซอร์สภายใต้ Apache-2.0 พัฒนาโดย Muvon Un Limited รับมันได้ที่ GitHub — ยินดีรับ issues และ pull requests



