TH ▾
รับคีย์ API

API Ollama ใน Python และทางเลือกแบบโฮสต์ และทางเลือกแบบโฮสต์

API Ollama ใน Python และทางเลือกแบบโฮสต์ ใช้โค้ดประมาณสิบบรรทัด และโครงสร้างโค้ดเดียวกันนี้ยังใช้งานได้กับเอนด์พอยต์แบบโฮสต์ บทความนี้แสดงทั้งสองวิธีและอธิบายว่าควรเลือกแบบไหน

อัปเดต

ประเด็นสำคัญ

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

สรุปสั้นๆ

หากคุณค้นหา 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 นั่นคือการตั้งค่าทั้งหมด

รับคีย์ API