แนะนำ 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 ทำกับมัน:

  1. ยืนยันตัวตน โทเคน Authorization: Bearer คือคีย์ API ของไคลเอนต์จากตาราง api_keys OctoHub ค้นหามัน ตรวจว่ายังใช้งานได้ แล้วแท็กคำขอด้วย ID ของคีย์ (ถ้าคุณสตาร์ทเซิร์ฟเวอร์โดยไม่มี master key จะปิดเฉพาะ admin API เท่านั้น — มีคำเตือนพิมพ์ออกมาตอนสตาร์ท ส่วนการเรียก completion และ embedding ยังต้องใช้คีย์ไคลเอนต์ที่ใช้งานได้)
  2. ตรวจ allow-list คีย์ไคลเอนต์จำกัดให้ใช้เฉพาะชุดโมเดลได้ คีย์ที่ถูกจำกัดไว้ที่ ["gpt", "anthropic:claude-haiku-4-5"] แล้วขออย่างอื่นจะได้ 403
  3. แปลงโมเดล ถ้าฟิลด์ model เป็น alias จาก [models] OctoHub จะขยายมันเป็นสตริง provider:model ถ้ามันเป็น provider:model เปล่า ๆ อยู่แล้ว ก็ผ่านตรงไป alias ที่แมปไปยัง รายการ จะเริ่มจากตำแหน่งสุ่มแล้วเลือกผู้ให้บริการแรกที่รับได้ — นั่นคือการกระจายโหลด
  4. ขอ permit ของผู้ให้บริการ ถ้าคุณตั้งลิมิตการทำงานพร้อมกันของผู้ให้บริการนั้นไว้ คำขอจะรอช่องว่าง ไม่มีช่องก็ไม่มี 429 — การเชื่อมต่อ HTTP จะค้างเปิดไว้จนกว่าจะมีช่องว่าง — นานสุดตามไทม์เอาต์ของคิว (ค่าเริ่มต้น 60 วินาที) จากนั้นจะได้ 503 เป็นการคุมอัตราโดยตั้งใจ บันทึกเป็นเวลารอในคิว
  5. เรียกอัปสตรีม ผ่าน octolib พร้อมเส้นตายของการดำเนินการที่ตั้งค่าได้
  6. บันทึกและตอบกลับ คำขอทั้งก้อน คำตอบ จำนวนโทเคน ต้นทุน ผู้ให้บริการที่แปลงได้ และเวลาหน่วง ลงตาราง 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