API Ollama ใน Python และทางเลือกแบบโฮสต์ และทางเลือกแบบโฮสต์
API Ollama ใน Python และทางเลือกแบบโฮสต์ ใช้โค้ดประมาณสิบบรรทัด และโครงสร้างโค้ดเดียวกันนี้ยังใช้งานได้กับเอนด์พอยต์แบบโฮสต์ บทความนี้แสดงทั้งสองวิธีและอธิบายว่าควรเลือกแบบไหน
อัปเดต
ประเด็นสำคัญ
- Ollama ฟังที่พอร์ต 11434 และเสนอ API แบบเนทีฟรวมถึงเอนด์พอยต์สไตล์ OpenAI /v1
- แพ็กเกจ ollama, requests แบบพื้นฐาน และ OpenAI SDK ต่างใช้งานได้; OpenAI SDK เป็นตัวเลือกที่พกพาได้มากที่สุด
- การย้ายไปยัง API แบบโฮสต์หมายถึงการเปลี่ยน base URL, คีย์ และชื่อโมเดล
- แบบในเครื่องดีที่สุดสำหรับงานออฟไลน์และฮาร์ดแวร์ที่ตายตัว; แบบโฮสต์ง่ายกว่าเมื่อคุณไม่มี GPU

สรุปสั้นๆ
หากคุณค้นหา ollama api python คุณมักต้องการสิ่งใดสิ่งหนึ่งจากสามสิ่งนี้: เรียกโมเดลที่ทำงานบนเครื่องของคุณเอง, สตรีมโทเคนจากโมเดลนั้น หรือทำให้สคริปต์เดียวกันทำงานที่อื่น Ollama ให้คุณทำได้ทั้งสามอย่าง มันรันเซิร์ฟเวอร์ในเครื่อง โดยค่าเริ่มต้นที่ http://localhost:11434 และคุณสามารถเข้าถึงมันด้วยแพ็กเกจ Python ollama, HTTP ธรรมดา หรือไคลเอนต์ OpenAI ใดๆ ที่ชี้ไปที่เส้นทาง /v1
จุดที่ต้องระวังคือโมเดลต้องทำงานบนฮาร์ดแวร์ของคุณ แล็ปท็อปที่ไม่มี GPU ที่ดีจะทำงานช้ากับโมเดลขนาดใหญ่ และเซิร์ฟเวอร์ที่ไม่มีก็ไม่ใช่ตัวเลือกที่ดี สำหรับกรณีนั้น API ที่เข้ากันได้กับ OpenAI แบบโฮสต์เป็นเส้นทางที่ง่ายกว่า และเนื่องจากรูปแบบคำขอเหมือนกัน การสลับจึงเสียค่าเพียงสามบรรทัดของการกำหนดค่า ทั้งสองเส้นทางครอบคลุมด้านล่างพร้อมโค้ดที่คุณสามารถวางได้
การเรียกโมเดลในเครื่องด้วยแพ็กเกจ ollama
ติดตั้ง Ollama ดึงโมเดล และตรวจสอบให้แน่ใจว่าเซิร์ฟเวอร์กำลังทำงาน จากนั้นติดตั้งไคลเอนต์ Python:
pip install ollama
ollama pull llama3.2
การเรียกแชทพื้นฐานมีลักษณะดังนี้ ชื่อโมเดลคือชื่อที่คุณดึงมา; llama3.2 เป็นเพียงตัวอย่าง
import ollama
response = ollama.chat(
model="llama3.2",
messages=[{"role": "user", "content": "Explain DNS in two sentences."}],
)
print(response["message"]["content"])
สตรีมมิง
ส่ง stream=True และคุณจะได้ตัววนซ้ำของชิ้นข้อมูลแทนที่จะเป็นการตอบกลับหนึ่งครั้ง แต่ละชิ้นข้อมูลมีชิ้นส่วนของคำตอบใน message.content
import ollama
stream = ollama.chat(
model="llama3.2",
messages=[{"role": "user", "content": "Write a haiku about servers."}],
stream=True,
)
for chunk in stream:
print(chunk["message"]["content"], end="", flush=True)
print()
การชี้ไคลเอนต์ไปยังเครื่องอื่น
หาก Ollama ทำงานบนโฮสต์อื่น ให้สร้างไคลเอนต์ด้วยที่อยู่เฉพาะ เช่น ollama.Client(host="http://192.168.1.20:11434") โดยค่าเริ่มต้น เซิร์ฟเวอร์จะฟังเฉพาะบนเครื่องท้องถิ่นเท่านั้น ดังนั้นการเข้าถึงระยะไกลจึงต้องมีการตั้งค่าโดยเจตนาที่ฝั่งเซิร์ฟเวอร์ อย่าเปิดเผยมันสู่อินเทอร์เน็ตสาธารณะโดยไม่ใช้พร็อกซีและระบบตรวจสอบสิทธิ์ด้านหน้า เพราะ API ดั้งเดิมไม่มีการตรวจสอบคีย์ของตัวเอง
HTTP ธรรมดาด้วย requests
คุณไม่จำเป็นต้องใช้แพ็กเกจเลย เอนด์พอยต์แชทแบบเนทีฟคือ POST /api/chat การสตรีมเป็นค่าเริ่มต้นที่นั่น และสตรีมเป็น JSON ที่คั่นด้วย newline ไม่ใช่ SSE ตั้งค่า "stream": false หากคุณต้องการวัตถุ JSON เดียวกลับคืนมา
import requests
r = requests.post(
"http://localhost:11434/api/chat",
json={
"model": "llama3.2",
"messages": [{"role": "user", "content": "Name three HTTP status codes."}],
"stream": False,
},
timeout=120,
)
r.raise_for_status()
print(r.json()["message"]["content"])
ตั้งค่าเวลาหมดเวลาที่เพียงพอ คำขอครั้งแรกหลังจากการดึงข้อมูลต้องโหลดโมเดลเข้าสู่หน่วยความจำ ซึ่งอาจใช้เวลานานกว่าคำขออื่นๆ มาก
การอ่านสตรีมด้วยตนเองมีเพียงไม่กี่บรรทัดเพิ่มเติม เรียกใช้ requests.post(..., stream=True) วนซ้ำผ่าน r.iter_lines() ข้ามบรรทัดว่าง และเรียกใช้ json.loads บนแต่ละบรรทัด วัตถุแต่ละชิ้นมีชิ้นส่วนของคำตอบ และชิ้นสุดท้ายมี "done": true สิ่งนี้มีประโยชน์ในคอนเทนเนอร์ขั้นต่ำที่คุณอาจไม่ต้องการติดตั้งแพ็กเกจอื่น และทำให้ชัดเจนว่าไลบรารีทำงานให้คุณอย่างไร API แบบโฮสต์สตรีมแตกต่างกัน โดยเป็นบรรทัด SSE ที่ขึ้นต้นด้วย data: ซึ่งเป็นเหตุผลเพิ่มเติมให้ใช้ SDK ของ OpenAI เพื่อแยกวิเคราะห์สตรีมสำหรับโค้ดที่พกพาได้
การใช้ OpenAI SDK กับ Ollama
Ollama ยังเปิดเผยเอนด์พอยต์สไตล์ OpenAI ภายใต้ /v1 นั่นหมายความว่าแพ็กเกจ openai ทางการใช้งานได้ และซอฟต์แวร์ส่วนใหญ่ที่ให้คุณตั้งค่า URL พื้นฐานก็ใช้งานได้เช่นกัน คีย์จำเป็นสำหรับ SDK แต่ถูกละเลยโดย Ollama ในเครื่อง ดังนั้นสตริงใดๆ ก็ใช้ได้
from openai import OpenAI
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
resp = client.chat.completions.create(
model="llama3.2",
messages=[{"role": "user", "content": "Give me a one-line summary of TCP."}],
)
print(resp.choices[0].message.content)
นี่คือรูปแบบที่มีประโยชน์ที่สุด เพราะมันแยกโค้ดของคุณออกจากเซิร์ฟเวอร์ ฟังก์ชันเดียวกันสามารถพูดคุยกับโมเดลในเครื่องในวันนี้และสิ่งอื่นในวันพรุ่งนี้ได้ ซึ่งเป็นหัวข้อถัดไป
โค้ดเดิมที่ทำงานกับ API แบบโฮสต์
ตัวเลือกแบบโฮสต์ที่นี่คือ API ที่เข้ากันได้กับ OpenAI โดยมีโมเดลเดียวคือ uncensored ซึ่งดำเนินการโดยผู้ให้บริการอิสระและปรับแต่งเพื่อตอบโดยไม่มีการปฏิเสธเนื้อหาสำหรับการใช้งานผู้ใหญ่ที่ถูกต้องตามกฎหมาย มีเฉพาะข้อความเท่านั้น URL พื้นฐานคือ https://api.ollamaapi.cc/v1 และคุณตรวจสอบสิทธิ์ด้วยคีย์ Bearer จากหน้าคีย์ API
นี่คือเวอร์ชันที่อ่านเป้าหมายจากตัวแปรสภาพแวดล้อม โดยมีค่าโฮสต์เป็นค่าเริ่มต้น เพื่อกลับไปใช้เซิร์ฟเวอร์ในเครื่องของคุณ ให้ส่งออกตัวแปรสองตัวโดยไม่ต้องเปลี่ยนอย่างอื่น
import os
from openai import OpenAI
client = OpenAI(
base_url=os.getenv("LLM_BASE_URL", "https://api.ollamaapi.cc/v1"),
api_key=os.getenv("LLM_API_KEY", "YOUR_API_KEY"),
)
MODEL = os.getenv("LLM_MODEL", "uncensored")
resp = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": "You are a concise assistant."},
{"role": "user", "content": "List four uses of a message queue."},
],
temperature=0.7,
)
print(resp.choices[0].message.content)
สำหรับการรันในเครื่อง ให้ตั้งค่า LLM_BASE_URL=http://localhost:11434/v1, LLM_API_KEY=ollama และ LLM_MODEL=llama3.2 การเริ่มต้นอย่างรวดเร็ว มีการตั้งค่าเดียวกันใน curl และ Node
สตรีมมิง โหมด JSON และเครื่องมือบนฝั่งโฮสต์
เอนด์พอยต์แบบโฮสต์รองรับการสตรีมผ่าน SSE โหมด JSON การเรียกใช้เครื่องมือ และพารามิเตอร์การสุ่มตัวอย่างทั่วไป (temperature, top_p, stop, seed และค่าปรับ) การสตรีมด้วย SDK คือลูปเดียวกันที่คุณจะเขียนสำหรับเซิร์ฟเวอร์สไตล์ OpenAI ใดๆ:
stream = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "Tell a two-paragraph story about a lighthouse."}],
stream=True,
stream_options={"include_usage": True},
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)
สำหรับผลลัพธ์ที่มีโครงสร้าง ให้ตั้งค่า response_format={"type": "json_object"} และระบุในพรอมต์ว่าคุณต้องการ JSON ควรแยกวิเคราะห์ภายในบล็อก try อยู่ดีเสมอ; โมเดลอาจส่งสิ่งที่คุณไม่ได้คาดหวังกลับมาได้
ความแตกต่างหนึ่งอย่างจากการใช้งานในเครื่องที่ส่งผลต่อโค้ดคือขีดจำกัด คีย์แบบเต็มอนุญาตให้ทำคำขอพร้อมกันได้ 8 คำขอและ 300 คำขอต่อนาที และคำขอแบบสตรีมมิงจะคงสถานะสล็อตไว้จนกว่าการสตรีมมิงจะสิ้นสุด หากคุณใช้เธรดเพื่อกระจายงาน ให้จำกัดพูลไว้ที่ 8 และลองใหม่เมื่อได้รับ HTTP 429 โดยใช้หัวข้อความ Retry-After เมื่อมีอยู่
การสนทนาต่อเนื่อง
ทั้งเอนด์พอยต์แชทในเครื่องและแบบโฮสต์ไม่จำข้อมูลใดๆ ระหว่างการเรียกใช้งาน เซิร์ฟเวอร์เห็นเฉพาะข้อความที่คุณส่ง ดังนั้นแชทบอทจึงเป็นรายการที่คุณเพิ่มเข้าไปแล้วส่งใหม่ รูปแบบเดียวกันนี้ใช้ได้กับทั้งสองเป้าหมาย ซึ่งเป็นเหตุผลเพิ่มเติมที่ทำให้ควรใช้ไคลเอนต์สไตล์ OpenAI เป็นค่าเริ่มต้น
history = [{"role": "system", "content": "You are a helpful assistant."}]
def ask(text):
history.append({"role": "user", "content": text})
resp = client.chat.completions.create(model=MODEL, messages=history)
answer = resp.choices[0].message.content
history.append({"role": "assistant", "content": answer})
return answer
print(ask("Pick a name for a hiking app."))
print(ask("Give me a tagline for it."))
ข้อควรปฏิบัติสองประการ ประการแรก โมเดลในเครื่องมีความยาวของบริบทที่คุณตั้งค่าและหน่วยความจำต้องรองรับ หากประวัติการสนทนายาวเกินกว่านั้น การสนทนาเก่าจะถูกตัดออกหรือการเรียกใช้งานล้มเหลว ขึ้นอยู่กับการตั้งค่า โมเดลแบบโฮสต์รองรับหน้าต่างบริบทขนาด 100,000 โทเคน รวมถึงการตอบกลับ ซึ่งมากกว่าที่แชทส่วนใหญ่ต้องการ แต่ประวัติที่ยาวนานยังคงใช้โทเคนอินพุตในทุกเทิร์น ประการที่สอง เมื่อประวัติการสนทนาเริ่มยาว ให้สรุปเทิร์นเก่าๆ เป็นข้อความสั้นๆ แทนที่จะส่งทั้งหมดอีกครั้ง วิธีนี้จะช่วยรักษาเวลาแฝงและต้นทุนให้คงที่บนทั้งสองระบบ
การลองใหม่อย่างสุภาพ
บน API แบบโฮสต์เมื่อเกิดปัญหาการโอเวอร์โหลดชั่วคราวจะส่ง HTTP 429 พร้อมหัวข้อความ Retry-After: 5 ตัวห่อเล็กๆ จะจัดการเรื่องนี้:
import time
from openai import RateLimitError
def chat_with_retry(messages, tries=4):
for attempt in range(tries):
try:
return client.chat.completions.create(model=MODEL, messages=messages)
except RateLimitError:
time.sleep(5 * (attempt + 1))
raise RuntimeError("still rate limited")
Ollama ในเครื่องไม่กำหนดขีดจำกัดอัตราให้คุณ แต่จะจัดคิวคำขอเมื่อโมเดลกำลังใช้งานอยู่ ดังนั้นการใช้ wrapper เดิมจึงไม่เกิดปัญหาที่นั่น
ในเครื่องหรือแบบโฮสต์: จะตัดสินใจอย่างไร
ไม่มีการเลือกใดที่ดีกว่าในภาพรวม ให้ใช้รายการด้านล่างเป็นรายการตรวจสอบ
- เลือก Ollama ในเครื่อง หากคุณต้องการทำงานแบบออฟไลน์ หากข้อมูลต้องไม่ออกจากเครื่องเลย หากคุณมี GPU ที่เพียงพออยู่แล้ว หรือต้องการลองใช้โมเดลแบบเปิดหลายตัวอย่างรวดเร็ว
- เลือก API แบบโฮสต์ หากคุณไม่มี GPU ทำงานบน VPS ขนาดเล็กหรือใน CI หลายบุคคลหรือบริการใช้แบ็กเอนด์ร่วมกัน หรือต้องการหน้าต่างบริบทที่ยาวนานโดยไม่ต้องจัดการขนาดหน่วยความจำเอง โมเดลแบบโฮสต์รองรับพรอมต์และการตอบกลับรวมกันสูงสุด 100,000 โทเคน
- ใช้ทั้งสองแบบระหว่างการพัฒนา: พัฒนาในเครื่อง จากนั้นเปลี่ยนการผลิตให้ชี้ไปที่ URL แบบโฮสต์ผ่านตัวแปรสภาพแวดล้อม
การใช้งานแบบโฮสต์คิดค่าบริการตามโทเคน ในอัตรา $0.15 ต่อ 1M โทเคนอินพุต และ $0.50 ต่อ 1M โทเคนเอาต์พุต จากเครดิตแบบเติมเงินล่วงหน้า หน้าการกำหนดราคาแสดงจำนวนเงินเติมเงิน และบัญชีใหม่สามารถรับเครดิตทดลองใช้ฟรี $0.50 ได้ด้วยการคลิกหนึ่งครั้ง ไม่ต้องใช้บัตร พรอมต์ไม่ถูกนำไปใช้ในการฝึกโมเดล
ข้อผิดพลาดที่คุณจะพบ
| อาการ | สาเหตุที่เป็นไปได้ | การแก้ไข |
|---|---|---|
| ปฏิเสธการเชื่อมต่อที่พอร์ต 11434 | เซิร์ฟเวอร์ Ollama ยังไม่ทำงาน | เริ่มแอปหรือรัน ollama serve |
| ไม่พบโมเดล | โมเดลไม่เคยถูกดึง หรือชื่อมีตัวพิมพ์ผิด | รัน ollama list จากนั้น ollama pull ชื่อโมเดลที่คุณใช้ |
| การเรียกใช้งานครั้งแรกหมดเวลา | โมเดลยังกำลังโหลด | เพิ่มเวลาหมดเวลา หรือส่งคำขอเพื่อเตรียมความพร้อม |
| ข้อผิดพลาดการตรวจสอบสิทธิ์บน API แบบโฮสต์ | คีย์ Bearer หายไปหรือผิด | ตรวจสอบ LLM_API_KEY และ URL ฐาน |
HTTP 429 พร้อมโค้ดข้อผิดพลาด concurrency | มากกว่า 8 คำขอที่กำลังดำเนินการ (2 สำหรับคีย์ทดลอง) | ลดจำนวน worker |
HTTP 429 พร้อมโค้ดข้อผิดพลาด rate_limited | เกินขีดจำกัดคำขอต่อนาที | ถอยออกและลองใหม่ |
คำขอที่ล้มเหลวหรือถูกปฏิเสธฝั่งผู้ให้บริการจะไม่ถูกคิดเงิน ดังนั้นตรรกะการลองใหม่จึงไม่ทำให้คุณเสียเงินสำหรับคำขอที่ล้มเหลว
คู่มือเพิ่มเติม
ถาม-ตอบ
ที่อยู่ API ของ Ollama โดยค่าเริ่มต้นคืออะไร?
เซิร์ฟเวอร์ Ollama ในเครื่องจะฟังที่ http://localhost:11434 เอนด์พอยต์แบบเนทีฟอยู่ภายใต้ /api เช่น /api/chat และเอนด์พอยต์สไตล์ OpenAI อยู่ภายใต้ /v1
สามารถใช้ OpenAI Python SDK กับ Ollama ได้หรือไม่?
ใช่ ตั้งค่า base_url เป็น http://localhost:11434/v1 และส่งสตริงใดๆ เป็นคีย์ API จากนั้น SDK จะส่งคำขอ chat completion มาตรฐานไปยังโมเดลในเครื่องของคุณ
เปลี่ยนจาก Ollama ไปใช้ API แบบโฮสต์ได้อย่างไร?
เปลี่ยน base URL, คีย์ และชื่อโมเดล หากโค้ดของคุณอ่านค่าเหล่านี้จากตัวแปรสภาพแวดล้อม ไม่จำเป็นต้องแก้ไขโค้ด
API แบบโฮสต์ทำงานได้โดยไม่ต้องใช้ GPU ในฝั่งของฉันหรือไม่?
ใช่ โมเดลทำงานที่ผู้ให้บริการ ดังนั้นสคริปต์ของคุณจึงต้องการเพียงการเชื่อมต่ออินเทอร์เน็ตและคีย์ Bearer คุณจ่ายตามโทเคนจากเครดิตแบบเติมเงินล่วงหน้า
เพียงกรอกแบบฟอร์มเดียวก็ได้รับคีย์ของคุณ
สร้างบัญชี คัดลอกคีย์ และเปลี่ยน base URL นั่นคือการตั้งค่าทั้งหมด