เพิ่ม custom OpenAI-compatible provider ให้ OpenCode
Updated 2026-07-29
OpenCode อ่าน custom provider ตรงจาก opencode.json ประกาศ provider block ด้วย package @ai-sdk/openai-compatible ชี้ options.baseURL ไปที่ https://api.apisrouter.com/v1 แล้วทุกโมเดลที่คุณลิสต์ไว้จะเลือกได้ใน /models picker ภายใต้ key เดียว
คำตอบสั้น ๆ: provider block เดียวใน opencode.json
OpenCode รองรับ custom OpenAI-compatible provider แบบ native เพิ่ม provider entry ใน opencode.json โดยตั้ง npm เป็น "@ai-sdk/openai-compatible" ตั้ง options.baseURL เป็น https://api.apisrouter.com/v1 อ่าน key จาก environment variable ด้วย template {env:...} แล้วลิสต์ model id ที่คุณต้องการไว้ใต้ models จากนั้นตั้งฟิลด์ model ระดับบนสุดเป็น "apisrouter/<model-id>" แล้ว OpenCode จะส่ง agent loop ทั้งหมดผ่าน gateway นี่คือเส้นทาง custom-provider ที่มีเอกสารรองรับใน docs ของ OpenCode ไม่ใช่ wrapper หรือ fork ไฟล์ config อยู่ที่ root ของโปรเจกต์ (opencode.json) หรือแบบ global ที่ ~/.config/opencode/opencode.json ก็ได้ และทั้งสองจะถูก merge เข้าด้วยกัน ดังนั้น provider block ประกาศครั้งเดียวแล้วใช้ซ้ำได้ทุก repo
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"apisrouter": {
"npm": "@ai-sdk/openai-compatible",
"name": "APIsRouter",
"options": {
"baseURL": "https://api.apisrouter.com/v1",
"apiKey": "{env:APISROUTER_API_KEY}"
},
"models": {
"claude-sonnet-4-6": { "name": "Claude Sonnet 4.6" }
}
}
},
"model": "apisrouter/claude-sonnet-4-6"
}OpenCode แก้ปัญหา provider และโมเดลอย่างไร
OpenCode (anomalyco บน GitHub หนึ่งใน terminal coding agent ที่มีดาวมากที่สุด ราว 186K) สร้าง provider layer บน Vercel AI SDK ฟิลด์ npm ใน provider block ระบุว่า package SDK ตัวไหนที่ OpenCode โหลดเพื่อคุยกับ provider นั้น: "@ai-sdk/openai-compatible" พูดโปรโตคอล /v1/chat/completions มาตรฐาน ในขณะที่ "@ai-sdk/openai" พูดโปรโตคอล /v1/responses ของ OpenAI gateway หลายตระกูลเสิร์ฟ chat completions ดังนั้น openai-compatible คือ package ที่ถูกต้อง การเลือก "@ai-sdk/openai" กับ chat-completions endpoint คือวิธีที่การตั้งค่านี้พังบ่อยที่สุด โมเดลถูกอ้างอิงเป็นคู่ provider/model provider id คือ key ใดก็ตามที่คุณเลือกใน provider block ("apisrouter" ข้างบน) และ model id คือ key ในแผนที่ models ดังนั้นโมเดลค่าเริ่มต้นกลายเป็น "apisrouter/claude-sonnet-4-6" ทุกอย่างที่คุณประกาศจะปรากฏใน /models picker ภายใน TUI สลับได้กลาง session พฤติกรรมหนึ่งที่ควรจำไว้: สำหรับ custom provider แผนที่ models คือ allowlist provider ที่มีมาให้มาพร้อมแคตตาล็อกที่รู้จักแล้ว แต่ OpenCode ไม่สามารถ enumerate โมเดลของ custom endpoint ได้เอง ดังนั้นมีแค่ id ที่คุณประกาศไว้ชัดเจนเท่านั้นที่เข้าถึงได้ เมื่อ endpoint หลัง baseURL เสิร์ฟ id ของ Claude, GPT, DeepSeek และ Kimi เคียงข้างกัน การประกาศหนึ่ง entry ต่อโมเดลจะทำให้ picker กลายเป็นสวิตช์บอร์ดข้าม vendor อยู่หลัง key เดียว
ตั้งค่าแบบเต็ม: global config, project config, limit ต่อโมเดล
รูปแบบที่สะอาดคือประกาศ provider ครั้งเดียวใน global config ที่ ~/.config/opencode/opencode.json แล้วเก็บแค่ตัวเลือกต่อ repo (โมเดลไหน, agent ไหน) ไว้ใน opencode.json ของแต่ละโปรเจกต์ OpenCode merge ไฟล์ config เข้าด้วยกันแทนที่จะแทนที่กัน ดังนั้นไฟล์ของโปรเจกต์ยังเล็กและ provider block ไม่ต้องซ้ำกันเลย template {env:APISROUTER_API_KEY} จะถูก resolve ตอนโหลดจาก environment ซึ่งทำให้ key ไม่อยู่ในไฟล์ใด ๆ ที่อาจถูก commit export มันจากไฟล์ profile ของ shell เพื่อให้ terminal session ทุกอันที่เปิด OpenCode เห็นมัน model entry แต่ละตัวยังรับ object limit ที่มี ceiling ของ context และ output token ได้ด้วย การประกาศมันสำคัญกว่าที่ดูเผิน ๆ: OpenCode ใช้ตัวเลข context เพื่อตัดสินว่าเมื่อไหร่ session ต้องการ summarization ดังนั้นโมเดล long-context ที่ประกาศไว้โดยไม่มี limit จะถูกปฏิบัติแบบระมัดระวังเกินความจำเป็น ตั้ง limit.context ให้ตรงกับสิ่งที่โมเดลรองรับจริง แล้ว session ยาว ๆ จะถูกบีบอัดช้าลงแทนที่จะเร็วเกินไป
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"apisrouter": {
"npm": "@ai-sdk/openai-compatible",
"name": "APIsRouter",
"options": {
"baseURL": "https://api.apisrouter.com/v1",
"apiKey": "{env:APISROUTER_API_KEY}"
},
"models": {
"claude-opus-4-7": { "name": "Claude Opus 4.7", "limit": { "context": 200000, "output": 32000 } },
"claude-sonnet-4-6": { "name": "Claude Sonnet 4.6", "limit": { "context": 200000, "output": 64000 } },
"gpt-5.5": { "name": "GPT-5.5" },
"gpt-5.6-sol": { "name": "GPT-5.6 Sol" },
"kimi-k2.7-code": { "name": "Kimi K2.7 Code" }
}
}
},
"model": "apisrouter/claude-sonnet-4-6",
"small_model": "apisrouter/kimi-k2.7-code"
}เลือก model และ small_model
workflow ที่ใช้ได้จริงคือยึดช่อง main ไว้ที่โมเดลที่คุณเชื่อใจสำหรับการแก้ไข แล้วหมุนเวียนตัวเลือกผ่าน session จริงแทนที่จะดูจาก benchmark: บ่ายหนึ่งของ diff จริงบน codebase ของคุณเองบอกอะไรได้มากกว่า leaderboard การ route ผ่าน endpoint เดียวทำให้แต่ละตัวเลือกเป็นแค่การแก้ไขหนึ่งบรรทัด และมุมมอง usage ต่อ key แสดงว่าแต่ละการทดลองเสียเงินไปเท่าไหร่จริง ๆ
- model ขับเคลื่อน agent loop หลัก: อ่านไฟล์ วางแผน edit เขียน diff รัน tool ช่องนี้เห็น context ยาวที่สุดและทำงาน engineering จริง ดังนั้นโมเดลเขียนโค้ดระดับ frontier (claude-sonnet-4-6, claude-opus-4-7, gpt-5.5) ควรอยู่ที่นี่
- small_model จัดการงานเบา ๆ อย่างการสร้างชื่อ session มันทำงานบ่อยแต่ไม่เคยแบกงานเขียนโค้ด ดังนั้น id ที่เร็วและราคาถูกคือรูปทรงที่ถูกต้อง ไม่มีเหตุผลที่จะเผา token ระดับ frontier ไปกับชื่อเรื่อง
- id ที่ปรับจูนมาสำหรับโค้ดอย่าง gpt-5.6-sol และ kimi-k2.7-code คุ้มค่าที่จะประกาศไว้แม้จะไม่ใช่ค่าเริ่มต้นของคุณ: การสลับไปใช้สำหรับ session ที่ refactor หนัก ๆ เป็นแค่การเลือกใน /models ไม่ใช่การแก้ config
- เพราะทั้งสองช่องรับสตริง provider/model กับ provider block เดียวกัน ช่อง main และ small จึงมาจากคนละ vendor ใน session เดียวกันได้ ซึ่ง key ของ vendor เดียวทำไม่ได้
จ่ายตามการใช้งาน · ถูกกว่าราคาทางการ
Selected models are priced below official list prices. Exact input, output, cache, and per-request prices are shown for each model.
| โมเดล | ราคาทางการ | ราคาของเรา |
|---|---|---|
| Claude Sonnet 4.6 | $3.00 / $15.00 per M | $2.40 / $12.00 per M |
| Claude Opus 4.7 | $5.00 / $25.00 per M | $4.00 / $20.00 per M |
| GPT-5.5 | $5.00 / $30.00 per M | $4.00 / $24.00 per M |
| GPT-5.6 Sol | $5.00 / $30.00 per M | $4.00 / $24.00 per M |
| Kimi K2.7 Code | $0.95 / $4.00 per M | $1.00 / $4.00 per M |
รูปแบบความล้มเหลวเฉพาะของ custom provider ใน OpenCode
package SDK ผิด "@ai-sdk/openai" post ไปที่ /v1/responses; gateway แบบ chat-completions จะตอบ route นั้นด้วย error ถ้า request แรกของคุณล้มเหลวด้วย error แบบ protocol หรือ route ผิดแทนที่จะเป็น error ยืนยันตัวตน เช็กว่าฟิลด์ npm เขียนว่า "@ai-sdk/openai-compatible" เป๊ะ ๆ โมเดลหายไปจาก picker โมเดลของ custom provider มีอยู่ก็ต่อเมื่อถูกประกาศไว้ การพิมพ์ผิดใน key ของ models หรือ id ที่คุณคิดว่ามีแต่ไม่เคยเพิ่มไว้ จะไม่ปรากฏใน /models เลย id เป็นสตริงที่ต้องตรงเป๊ะ รวมถึง suffix เวอร์ชัน และรายการ /v1/models ของ gateway คือแหล่งความจริงที่ควรก็อปมา {env:...} ที่ resolve ไม่ได้ template จะ resolve จาก environment ของ process ที่เปิด OpenCode key ที่ export ใน terminal หนึ่งจะไปไม่ถึง OpenCode instance ที่เปิดจาก terminal อื่น หรือจาก desktop launcher ที่ไม่เคย source profile ของคุณ ใส่ export ไว้ในไฟล์ profile ของ shell ไม่ใช่ session แบบครั้งเดียว ความเซอร์ไพรส์จากการ merge config เพราะ global กับ project config ถูก merge เข้าด้วยกัน opencode.json ของโปรเจกต์ที่ตั้ง model เป็น provider อื่นจะ override ค่าเริ่มต้นระดับ global ของคุณแบบเงียบ ๆ และ provider block ที่หลงเหลือจากโปรเจกต์เก่าอาจบดบังสิ่งที่คุณคาดหวังไว้ เมื่อการ route ดูผิดปกติ อ่านทั้งสองไฟล์ก่อนสรุปว่า gateway ทำงานผิดพลาด baseURL ที่ไม่มี /v1 SDK ต่อ path ของ route อย่าง /chat/completions เข้ากับ base ที่คุณให้ ดังนั้น https://api.apisrouter.com/v1 ถูกต้อง ส่วน host เปล่า ๆ ไม่ถูกต้อง การเชื่อมต่อล้มเหลวหรือ 404 บน config ที่ดูถูกต้องทุกอย่างมักเป็นเรื่องนี้เกือบทุกครั้ง
ใครที่ใช้ OpenCode ผ่าน gateway
- นักพัฒนาที่ใช้ชีวิตอยู่ใน TUI ทั้งวันและต้องการ Claude, GPT และ Kimi ใน /models picker เดียว แทนที่จะดูแล credential provider แยกต่อ vendor
- วิศวกรที่เปรียบเทียบโมเดลเขียนโค้ดบนงานจริง แต่ละตัวเลือกเป็นแค่ entry ที่ประกาศไว้และการเลือกใน picker หนึ่งครั้ง การเปรียบเทียบทีละ session ไม่ต้องใช้บัญชีใหม่
- ทีมที่ทำ secret เดียวให้เป็นมาตรฐาน APISROUTER_API_KEY ตัวเดียวใน onboarding docs แทนที่ checklist key ต่อ vendor และ usage ต่อ key แสดงว่าใครใช้จ่ายเท่าไหร่
- ผู้ใช้ที่จับคู่ main model ระดับ frontier กับ small_model ราคาถูกจากคนละ vendor ซึ่ง config vendor เดียวทำไม่ได้
- นักพัฒนาที่ไม่มีทางเข้าถึงระบบเก็บเงินของ vendor รายใดรายหนึ่ง การเข้าถึงแบบเติมเงินโดยไม่ต้องใช้บัตรตัดการพึ่งพาการสมัครต่อ provider ออกไป
ตรวจสอบ endpoint และ debug session แรก
ก่อนเริ่ม session ให้ดูว่า gateway เสิร์ฟอะไรบ้าง id ที่ /v1/models คืนมาคือสตริงเป๊ะ ๆ ที่ key ใน models ของคุณต้องตรงด้วย ความล้มเหลวใน session แรกมีรูปแบบคงที่ 401 หมายความว่า APISROUTER_API_KEY มองไม่เห็นจาก process ของ OpenCode ให้ echo ตัวแปรใน terminal เดียวกับที่คุณเปิดจาก error โมเดลไม่พบจาก gateway หมายความว่า key ที่ประกาศไม่ตรงกับ id ที่เสิร์ฟจริง รวมถึง suffix เวอร์ชัน ถ้า provider ไม่ปรากฏเลย ตรวจสอบความถูกต้องของ JSON เพราะ comma เกินหรือวงเล็บผิดที่ทำให้ทั้งไฟล์อ่านไม่ได้ และ OpenCode จะกลับไปใช้ค่าเริ่มต้น เมื่อ request ไหลลื่นแล้ว console ของ APIsRouter แสดงโมเดลต่อ request, จำนวน token และค่าใช้จ่าย coding agent เป็นงานที่ context ยาวและหลายเทิร์น การเห็นว่า session ไหนและโมเดลไหนกิน token เท่าไหร่คือวิธีตัดสินว่าช่อง main คุ้มค่ากับราคาหรือไม่
curl -s https://api.apisrouter.com/v1/models \
-H "Authorization: Bearer $APISROUTER_API_KEY" | head -50คำถามที่พบบ่อย
OpenCode ใช้โมเดล Claude, GPT และ Kimi ผ่าน custom provider เดียวได้ไหม?
ได้ custom provider เป็นแค่ baseURL บวก allowlist ของ models เมื่อ endpoint เสิร์ฟหลาย vendor ให้ประกาศหนึ่ง entry ต่อ id แล้วทุกโมเดลที่ประกาศไว้จะปรากฏใน /models picker ภายใต้ provider และ key เดียวกัน สลับได้กลาง session
API key ใส่ไว้ที่ไหนใน opencode.json?
ใน options.apiKey ด้วย environment template เช่น "{env:APISROUTER_API_KEY}" template นี้จะ resolve ตอนโหลด ดังนั้น key ตัวจริงจึงไม่อยู่ในไฟล์ config เลย export ตัวแปรจากไฟล์ profile ของ shell เพื่อให้ terminal ทุกอันที่เปิด OpenCode ได้รับค่านี้
provider block ควรอยู่ใน global config หรือ project config?
Global ที่ ~/.config/opencode/opencode.json OpenCode merge ไฟล์ config เข้าด้วยกัน ดังนั้นการประกาศ provider ครั้งเดียวระดับ global แล้วตั้งแค่การเลือกโมเดลต่อโปรเจกต์ ช่วยให้ repo ไม่มีเรื่อง credential มายุ่งและหลีกเลี่ยง block ที่ซ้ำกันและเบี่ยงเบนไปคนละทาง
ทำไมโมเดลของฉันไม่ปรากฏใน /models picker?
โมเดลของ custom provider ต้องประกาศไว้อย่างชัดเจน OpenCode ไม่สามารถ enumerate custom endpoint ได้ เช็กว่าแผนที่ models มี id ตรงเป๊ะ รวมถึง suffix เวอร์ชัน และก็อปปี้ id จาก response ของ /v1/models ของ gateway แทนการพิมพ์จากความจำ
@ai-sdk/openai-compatible กับ @ai-sdk/openai ต่างกันอย่างไรในกรณีนี้?
@ai-sdk/openai-compatible พูด /v1/chat/completions ซึ่งเป็นโปรโตคอลที่ gateway หลาย vendor เสิร์ฟ @ai-sdk/openai พูดโปรโตคอล /v1/responses ของ OpenAI สำหรับ APIsRouter ใช้ @ai-sdk/openai-compatible package อีกตัวจะ post ไปที่ route ที่ gateway ไม่ได้เสิร์ฟไว้เพื่อวัตถุประสงค์นี้
limit context ที่ประกาศไว้มีผลจริงไหม?
มีผลจริง OpenCode ใช้ limit.context เพื่อตัดสินว่าเมื่อไหร่ session ต้อง compaction การไม่ประกาศ limit บนโมเดล long-context ทำให้ session ถูกสรุปเร็วกว่าที่ควร ดังนั้นตั้ง limit.context และ limit.output ให้ตรงกับสิ่งที่โมเดลรองรับจริง