ทุกครั้งที่ Octocode ทำการค้นหาเชิงความหมาย ทุกครั้งที่ Octomind ส่งพรอมต์ไปยังโมเดลที่ถูกต้อง ทุกครั้งที่ผลิตภัณฑ์ตัวใดตัวหนึ่งของเราพูดคุยกับ LLM ทุกอย่างผ่านโค้ดชิ้นเดียวกัน เราดึงมันออกมาจาก Octocode เมื่อปีที่แล้ว ตอนนี้มันขับเคลื่อนทุกอย่าง

มันชื่อว่า Octolib และเราเพิ่งเปิดซอร์สโค้ดของมัน

จากกาวภายในสู่โครงสร้างพื้นฐานที่ใช้ร่วมกัน

Octolib เริ่มต้นเป็นส่วนที่ยุ่งเหยิงของ Octocode ที่ไม่มีใครอยากคิดถึง

Octocode ต้องการ embeddings เพื่อเข้าใจโค้ดเชิงความหมาย ต้องการ LLM เพื่อตอบคำถามเกี่ยวกับโค้ดเบสของคุณ ต้องการ reranking เพื่อแสดงผลลัพธ์ที่สำคัญจริง ๆ ในช่วงแรก นั่นหมายความว่าเรามีไลบรารีไคลเอนต์สามตัวที่แตกต่างกัน รูปแบบการจัดการ error สามแบบที่แตกต่างกัน และวิธีการ parse การใช้ token สามวิธีที่แตกต่างกัน (ผมยังจำได้ตอนเพิ่ม Cohere embeddings และต้องเรียนรู้ SDK ทั้งหมดของพวกเขาเพียงเพื่อให้ได้ vector กลับมา)

การเพิ่ม provider ใหม่หมายถึงการแตะโค้ดในหกที่ เราทำสิ่งที่ทีมส่วนใหญ่ทำ: เราเขียน wrapper บาง ๆ ขึ้นมา

จากนั้น wrapper ก็มีฟีเจอร์เพิ่มขึ้น จากนั้นก็มี providers เพิ่มขึ้น จากนั้นเราก็ตระหนักว่า Octomind ซึ่งเป็นแพลตฟอร์ม AI agent ของเรา ต้องการสิ่งเดียวกันเป๊ะ ๆ Octobrain ก็เช่นกัน

การคัดลอกและวาง wrapper สามครั้งดูโง่เง่า การดึงมันออกมาดูชัดเจน

Octolib คือการดึงออกมานั้น ไลบรารี Rust ที่พึ่งพาตนเองได้สำหรับ LLM inference, embeddings และ reranking ทั่วทุก provider หลัก

หนึ่งสตริง, backend ใดก็ได้

แนวคิดเรียบง่าย หนึ่งสตริง provider:model หนึ่ง API และ backend ใดก็ได้

let provider = ProviderFactory::get_provider_for_model("openai:gpt-5.5")?;
let response = provider.chat_completion(params).await?;

สลับ openai:gpt-5.5 ด้วย anthropic:claude-opus-4-5-20251101, deepseek:deepseek-chat, nvidia:meta/llama-3.3-70b-instruct, หรือ openrouter:anthropic/claude-opus-4.5 โค้ดไม่เปลี่ยน ประเภทของ response ไม่เปลี่ยน การติดตามการใช้ token และต้นทุนยังคงทำงานต่อไป

นี่คือ trait ที่ทำให้สิ่งนี้เป็นไปได้:

#[async_trait]
pub trait AiProvider {
    fn name(&self) -> &str;
    fn supports_model(&self, model: &str) -> bool;
    async fn chat_completion(&self, params: ChatCompletionParams) -> Result<ProviderResponse>;
    fn get_model_pricing(&self, model: &str) -> Option<Pricing>;
}

ทุก provider ใช้ interface เดียวกัน OpenAI มี implementation แบบ native ของตัวเอง NVIDIA NIM, Cerebras, Together, Ollama และ local endpoints ทั้งหมดผ่านเลเยอร์ที่เข้ากันได้กับ OpenAI ร่วมกัน factory จัดการการ parse สตริงโมเดลและส่งต่อไปยัง backend ที่ถูกต้อง

น่าเบื่อโดยจงใจ นั่นคือจุดประสงค์

LLM providers

Provider ประเภท Chat Structured output Caching
OpenAI Native
Anthropic Native
Google (Gemini) Native
DeepSeek Native
Moonshot Native
MiniMax Native
Z.ai Native
OpenRouter OpenAI-compatible
NVIDIA NIM OpenAI-compatible
Cerebras OpenAI-compatible
Together OpenAI-compatible
Cloudflare Workers AI OpenAI-compatible
OctoHub OpenAI-compatible
Ollama OpenAI-compatible
Local endpoints OpenAI-compatible

Embeddings และ reranking

Provider Embeddings Reranking Local
Jina
Voyage
Cohere
OpenAI
Google
FastEmbed

providers ใหม่ ๆ มาในรูปแบบของ pull request หากคุณต้องการอันที่ขาดหายไป template อยู่ที่ src/llm/providers/openai.rs

ส่วนที่ไม่มีใครพูดถึงจนกว่ามันจะพัง

ไลบรารีแบบ multi-provider ไม่ใช่ของหายากอีกต่อไป ความแตกต่างอยู่ที่รายละเอียดที่สำคัญก็ต่อเมื่อคุณรันมันอย่างหนักเท่านั้น

การติดตามต้นทุน ทุก response มีการใช้ token และต้นทุนที่คำนวณแล้ว สำหรับ providers ที่มี native API เราจะดูแลตารางราคาต่อโมเดล สำหรับ proxies และ aggregators ที่ host โมเดล open-weight เราจะ fallback ไปใช้ราคาอ้างอิงที่จับคู่ตามชื่อโมเดล หากต้นทาง API ไม่ส่งฟิลด์ต้นทุนกลับมา เราจะคำนวณเองจากจำนวน token

ฟังดูเล็กน้อย แต่ไม่ใช่ ลองรันคำขอนับพันผ่าน provider ห้ารายแล้วเดาดูว่าเงินของคุณหายไปไหน

Structured output ไม่ใช่ทุก provider ที่รองรับข้อจำกัดของ JSON schema Octolib รู้ว่าตัวไหนรองรับ — OpenAI, Anthropic, DeepSeek, Moonshot, MiniMax — และจัดการความแตกต่างของการจัดรูปแบบคำขอ คุณตั้งค่า response_format แล้วได้ JSON ที่ parse แล้วกลับมา ไม่ต้องทำ prompt engineering ด้วยมือ ไม่ต้องมีลูกเล่น "กรุณาตอบเป็น JSON ที่ถูกต้อง"

Embeddings และ reranking การ abstraction provider แบบเดียวกันใช้กับ generate_embeddings() และ rerank() Jina, Voyage, Cohere, OpenAI, FastEmbed — API เดียวกัน, backend ต่างกัน RAG pipelines สมัยใหม่แตะบริการสามประเภทที่แตกต่างกัน การจัดการ clients แยกต่างหากสำหรับแต่ละตัวเป็นงานยุ่งยากที่คุณไม่ควรต้องทำ

ไม่มี panic, ไม่มี println มันคือไลบรารี ไม่ใช่แอป ทุก public function ส่งคืน Result Errors มี context มาด้วย Debug output ผ่าน tracing ไม่ใช่ stdout เหล่านี้ไม่ใช่ฟีเจอร์ที่น่าตื่นเต้น แต่เป็นความแตกต่างระหว่างไลบรารีที่คุณไว้ใจใน production กับไลบรารีที่ปลุกคุณตอนตี 3

สามผลิตภัณฑ์, หนึ่งไลบรารี

Octolib คือเลเยอร์ AI สำหรับสแตกทั้งหมดของเรา:

  • Octocode — การค้นหาโค้ดเชิงความหมาย, Q&A เกี่ยวกับโค้ดเบส, การสรุป diff
  • Octomind — agent reasoning, tool calling, workflows หลายขั้นตอน
  • Octobrain — การดึงความรู้, การประมวลผลเอกสาร, embedding pipelines

เมื่อเราเพิ่มโมเดลใหม่ — เช่น โมเดล reasoning จาก DeepSeek หรือ Claude เวอร์ชันล่าสุด — เราอัปเดต Octolib ครั้งเดียว ทุกผลิตภัณฑ์ได้รับ เมื่อ OpenAI เปลี่ยนรูปแบบ response ของ API หรือ Anthropic เปิดตัวราคา cache การแก้ไขอยู่ที่เดียว

นี่คือเหตุผลที่เราดึงมันออกมา ไม่ใช่เพราะโค้ด wrapper น่าสนใจ แต่เพราะการดูแลรักษา wrapper สี่เวอร์ชันของอันเดียวกันมีราคาแพง และการทำ provider integrations ผิดพลาดหมายถึงผลิตภัณฑ์เสียหาย

คำถามเรื่อง Rust

เราถูกถามเรื่องนี้บางครั้ง คำตอบสั้น ๆ: เราสร้างโครงสร้างพื้นฐานด้วย Rust และ Octolib คือโครงสร้างพื้นฐาน

คำตอบยาวกว่า: การเรียก LLM เป็น network requests ที่ผูกกับ I/O แต่ pipeline โดยรอบ — การสร้าง embedding, reranking, การนับ token, การ batch requests, การตรวจสอบ structured output — ได้รับประโยชน์จากการผสมผสานของประสิทธิภาพ async และความถูกต้องในเวลา compile ของ Rust เมื่อคุณรัน inference ในระดับที่มิลลิวินาทีมีความสำคัญ คุณไม่ต้องการการหยุดชั่วคราวของ garbage collection หรือ runtime type errors ใน hot path ของคุณ

และ ecosystem ของ Rust สำหรับโครงสร้างพื้นฐาน AI กำลังเติบโตอย่างรวดเร็ว Candle สำหรับ inference ในเครื่อง tokio สำหรับ async serde สำหรับการ parse JSON ที่ไม่มีที่สิ้นสุด ทุกอย่างเข้ากันได้อย่างลงตัว

FAQ

Octolib คืออะไร?

Octolib คือไลบรารี Rust แบบโอเพนซอร์สสำหรับ LLM inference, embeddings และ reranking สตริง API หนึ่งตัว (provider:model) ส่งการเรียกไปยัง OpenAI, Anthropic, Google, DeepSeek, OpenRouter, Ollama และ providers อื่น ๆ มากกว่า 10 ราย มันขับเคลื่อน Octocode, Octomind และ Octobrain

Octolib แตกต่างจาก LiteLLM หรือ LangChain อย่างไร?

Octolib เป็น Rust-native ระดับโครงสร้างพื้นฐาน และมีขอบเขตที่แคบ มันจัดการ provider routing, structured output, การติดตามต้นทุน และ reranking — ไม่มีอะไรอื่น ไม่มี agents, ไม่มี chains, ไม่มี prompt templates หากคุณกำลังสร้างฟีเจอร์ AI ใน Rust และต้องการเลเยอร์ที่บางและคาดเดาได้ระหว่างโค้ดของคุณกับ providers มากกว่า 15 ราย นั่นคือ niche

รองรับ providers อะไรบ้าง?

LLM providers 15 ราย (OpenAI, Anthropic, Google Gemini, DeepSeek, Moonshot, MiniMax, Z.ai, OpenRouter, NVIDIA NIM, Cerebras, Together, Cloudflare Workers AI, OctoHub, Ollama, custom local endpoints) และ embedding/reranking providers 6 ราย (Jina, Voyage, Cohere, OpenAI, Google, FastEmbed)

ใช้กับโมเดลในเครื่องได้ไหม?

ได้ Ollama และ local endpoint ใด ๆ ที่เข้ากันได้กับ OpenAI ทำงานได้ทันที FastEmbed รัน embeddings ในเครื่องโดยไม่ต้องมี API สิ่งเดียวที่เปลี่ยนคือสตริง provider:model

การติดตามต้นทุนทำงานอย่างไร?

ทุก response มีการใช้ token และต้นทุนที่คำนวณแล้ว Native providers ใช้ตารางราคาต่อโมเดล Aggregators fallback ไปใช้ราคาอ้างอิงตามชื่อโมเดล หากต้นทาง API ไม่ส่งฟิลด์ต้นทุนกลับมา Octolib จะคำนวณจากจำนวน token

พร้อมใช้งานใน production ไหม?

มันรันผลิตภัณฑ์สามตัว (Octocode, Octomind, Octobrain) ทุกวัน ไม่มี panic ในโค้ดไลบรารี ทุก public function ส่งคืน Result Debug output ผ่าน tracing License คือ Apache-2.0

โอเพนซอร์ส, ecosystem ที่เปิด

Octolib เป็นชิ้นหนึ่งของภาพที่ใหญ่กว่า Octocode เป็นโอเพนซอร์ส สถาปัตยกรรมของ Octomind ถูกบันทึกเป็นเอกสารต่อสาธารณะ เราสร้างในที่สาธารณะเพราะปัญหาที่เรากำลังแก้ไข — วิธีการพูดคุยกับ AI providers สิบรายที่แตกต่างกันโดยไม่เสียสติ — ไม่ใช่ปัญหาเฉพาะของเรา

ไลบรารีอยู่ บน GitHub มัน compile ได้ด้วย cargo check มันรัน examples ได้โดยไม่ต้องตั้งค่าใด ๆ นอกจาก API key หากคุณกำลังสร้างฟีเจอร์ AI ใน Rust และเหนื่อยกับการเขียน boilerplate ของ provider เดิม ๆ เป็นครั้งที่สาม มันอาจช่วยคุณประหยัดเวลาได้สองสามสัปดาห์

เราเพิ่ม providers เมื่อสิ่งต่าง ๆ พัฒนาขึ้น อันถัดไปอาจอยู่ใน pull request แล้ว