VI ▾
Lấy khóa API

GLM API Python: Ví dụ về Chat, Streaming và Công cụ

Để làm việc với glm api python, bạn chỉ cần gói openai tiêu chuẩn: trỏ nó vào https://api.glmapi.cc/v1, sử dụng model ID uncensored và các lệnh chat thông thường sẽ hoạt động. Trang này hướng dẫn bạn qua từng mẫu với mã nguồn bạn có thể chạy, từ yêu cầu đầu tiên đến các lô bất đồng bộ và xử lý giới hạn tốc độ.

Điểm chính

  • Cài đặt openai, đặt base_url thành https://api.glmapi.cc/v1 và sử dụng mô hình uncensored.
  • Streaming, chế độ JSON và gọi hàm sử dụng cùng các tham số như API chat của OpenAI.
  • Một khóa đầy đủ cho phép 8 yêu cầu đồng thời và 300 mỗi phút, vì vậy hãy giới hạn worker bất đồng bộ của bạn ở mức 8.
  • Xử lý 429 bằng cách đọc mã lỗi và tiêu đề Retry-After.
Dải ánh sáng dữ liệu streaming từ terminal laptop đến máy chủ đám mây, đại diện cho các lệnh gọi API Python

Cài đặt và yêu cầu đầu tiên

Tạo môi trường ảo và cài đặt SDK. Giả sử phiên bản 1 trở lên của gói openai được sử dụng xuyên suốt.

python -m venv .venv
source .venv/bin/activate
pip install --upgrade openai

Lấy khóa từ trang khóa API; người dùng mới có thể nhận $0.50 tín dụng dùng thử chỉ với một cú nhấp chuột, có hiệu lực trong 7 ngày và không cần thẻ. Giữ khóa trong biến môi trường, sau đó thực hiện lệnh gọi đầu tiên:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.glmapi.cc/v1",
    api_key=os.environ["GLM_API_KEY"],
)

resp = client.chat.completions.create(
    model="uncensored",
    messages=[
        {"role": "system", "content": "You are a concise writing assistant."},
        {"role": "user", "content": "Suggest five titles for a space-western novel."},
    ],
    temperature=0.8,
)

print(resp.choices[0].message.content)
print(resp.usage)

Đó là toàn bộ tích hợp. Dịch vụ là một endpoint tương thích OpenAI độc lập cho một mô hình trọng số mở, nên không phải là API chính thức của nhà cung cấp đằng sau GLM hay bất kỳ ai khác. Chỉ có POST /v1/chat/completions và GET /v1/models. quickstart liệt kê các trường yêu cầu được hỗ trợ.

Hai thói quen nhỏ giúp ích ngay từ đầu. Đầu tiên, gọi client.models.list() một lần trong smoke test: nó gọi GET /v1/models, vì vậy nó chứng minh rằng khóa, base URL và đường dẫn mạng đều hoạt động trước khi bạn tiêu tốn một token cho một lệnh hoàn thành. Thứ hai, in resp.usage trong quá trình phát triển. Số lượng token prompt và hoàn thành cho bạn biết sớm xem prompt hệ thống có lớn hơn bạn nghĩ hay không, và với giá $0.15 cho mỗi 1M token đầu vào và $0.50 cho mỗi 1M token đầu ra, bạn có thể tính toán chi phí một lệnh gọi trong đầu.

Chat đa lượt và cài đặt lấy mẫu

API không có trạng thái, vì vậy bạn tự duy trì danh sách hội thoại và gửi nó mỗi lần. Một lớp nhỏ là đủ:

class Chat:
    def __init__(self, client, system, max_turns=12):
        self.client = client
        self.system = system
        self.max_turns = max_turns
        self.history = []

    def say(self, text):
        self.history.append({"role": "user", "content": text})
        window = self.history[-self.max_turns * 2:]
        resp = self.client.chat.completions.create(
            model="uncensored",
            messages=[{"role": "system", "content": self.system}] + window,
            temperature=0.9,
            top_p=0.95,
            frequency_penalty=0.3,
        )
        reply = resp.choices[0].message.content
        self.history.append({"role": "assistant", "content": reply})
        return reply

Cắt self.history[-self.max_turns * 2:] giữ lại mười hai cặp người dùng và trợ lý cuối cùng. Ứng dụng thực tế có thể ghim vài tin nhắn đầu, như hồ sơ nhân vật hoặc sự kiện quan trọng, và tóm tắt phần giữa. Cắt ngắn 12 lượt cuối giữ chi phí đầu vào ổn định khi hội thoại tăng. Cửa sổ ngữ cảnh là 100.000 token cho prompt và hoàn thành cùng nhau, nên đây là lựa chọn chi phí hơn là bắt buộc. Các tham số temperature, top_p, stop, seed và các tham số penalty được chuyển tiếp. Đặt seed khi bạn muốn chạy lặp lại khi kiểm tra prompt, và bỏ max_tokens trừ khi bạn muốn giới hạn độ dài.

Phản hồi streaming

Streaming sử dụng sự kiện do máy chủ gửi và cung cấp cho bạn token khi chúng được tạo, điều này quan trọng đối với bất kỳ công cụ tương tác nào. Truyền stream=True và lặp qua:

stream = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Describe a harbour at dawn in 120 words."}],
    stream=True,
)

parts = []
for chunk in stream:
    if not chunk.choices:
        continue
    delta = chunk.choices[0].delta.content
    if delta:
        parts.append(delta)
        print(delta, end="", flush=True)

text = "".join(parts)

Phần kiểm tra chunk.choices rất quan trọng vì chunk cuối cùng mang thông tin sử dụng và có thể có danh sách choices trống. Một điểm vận hành: một yêu cầu streaming giữ slot concurrency của nó cho đến khi stream kết thúc. Bao bọc vòng lặp trong một khối try với một mệnh đề finally đóng stream nếu mã của bạn bị lỗi ở giữa, chẳng hạn khi client ngắt kết nối. Luôn kết thúc hoặc đóng stream, nếu không một vòng lặp bỏ rơi stream sẽ đạt giới hạn concurrency trong khi không thực hiện công việc hữu ích nào.

Chế độ JSON

Khi đầu ra cung cấp dữ liệu cho mã khác, hãy yêu cầu một đối tượng JSON. Đề cập đến JSON trong prompt, để mô hình biết hình dạng bạn mong đợi:

import json

resp = client.chat.completions.create(
    model="uncensored",
    response_format={"type": "json_object"},
    messages=[
        {"role": "system", "content": "Reply with a JSON object only."},
        {"role": "user", "content": "Give a character with keys name, age, motto."},
    ],
)

data = json.loads(resp.choices[0].message.content)
print(data["name"])

Vẫn hãy bọc json.loads trong khối try trong mã sản xuất. Chế độ JSON khiến đầu ra hợp lệ là khả năng cao, và một yêu cầu bị cắt bởi stop sequence hoặc giới hạn của bạn vẫn có thể để lại đối tượng bị cắt. Thử lại một lần với cùng đầu vào là cách sửa rẻ, và vì các yêu cầu thất bại không bị tính phí, chi phí của một lần thử lại chỉ là cuộc gọi thành công.

Gọi hàm

Tool calling theo định dạng OpenAI: bạn mô tả các hàm trong tools, mô hình trả về tool_calls, bạn chạy chúng và gửi kết quả lại với vai trò tool. Một vòng lặp đầy đủ:

import json

tools = [{
    "type": "function",
    "function": {
        "name": "roll_dice",
        "description": "Roll a die with the given number of sides.",
        "parameters": {
            "type": "object",
            "properties": {"sides": {"type": "integer"}},
            "required": ["sides"],
        },
    },
}]

messages = [{"role": "user", "content": "Roll a twenty-sided die for me."}]
first = client.chat.completions.create(
    model="uncensored", messages=messages, tools=tools, tool_choice="auto"
)
msg = first.choices[0].message

if msg.tool_calls:
    messages.append(msg)
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = {"value": 17, "sides": args["sides"]}  # replace with real logic
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": json.dumps(result),
        })
    final = client.chat.completions.create(
        model="uncensored", messages=messages, tools=tools
    )
    print(final.choices[0].message.content)
else:
    print(msg.content)

Vòng lặp quan trọng hơn chi tiết của xúc xắc. Mô hình yêu cầu một cuộc gọi, mã của bạn chạy nó, và bạn thêm cả tin nhắn trợ lý và kết quả công cụ trước khi hỏi lại. Nếu bỏ qua tin nhắn trợ lý, tool_call_id trong kết quả sẽ không có gì để khớp, đó là nguyên nhân thường gặp của phản hồi thứ hai bị nhầm lẫn. Với tool_choice đặt thành auto, mô hình quyết định có gọi công cụ hay không, nên luôn xử lý nhánh nơi nó trả lời trực tiếp, như mã ở trên làm. Phản hồi truyền phát có thể mang tool_calls, được giao dưới dạng các mảnh mà bạn nối theo chỉ mục trước khi phân tích cú pháp đối số.

Xác thực các đối số trước khi hành động. Mô hình có thể tạo ra một lệnh gọi bị lỗi, và mã của bạn nên coi các đối số là đầu vào không đáng tin cậy, giống như bất kỳ thứ gì từ người dùng.

Lô bất đồng bộ trong giới hạn

Đối với nhiều prompt cùng lúc, hãy sử dụng AsyncOpenAI với một semaphore khớp với giới hạn concurrency của bạn. Một khóa đầy đủ cho phép 8 yêu cầu đồng thời, một khóa dùng thử cho phép 2:

import asyncio, os
from openai import AsyncOpenAI

client = AsyncOpenAI(
    base_url="https://api.glmapi.cc/v1",
    api_key=os.environ["GLM_API_KEY"],
)
gate = asyncio.Semaphore(8)  # use 2 on a trial key

async def one(prompt):
    async with gate:
        r = await client.chat.completions.create(
            model="uncensored",
            messages=[{"role": "user", "content": prompt}],
        )
        return r.choices[0].message.content

async def main():
    prompts = [f"Write a one-line tagline for product {i}." for i in range(40)]
    results = await asyncio.gather(*(one(p) for p in prompts))
    print(len(results))

asyncio.run(main())

Semaphore xử lý độ đồng thời nhưng không phải giới hạn 300 yêu cầu mỗi phút. Đối với các lô dài, hãy thêm độ trễ nhỏ hoặc bộ giới hạn token-bucket. Ở mức $0.15 cho 1M token đầu vào và $0.50 cho 1M token đầu ra, 40 yêu cầu tạo slogan với khoảng 60 token đầu vào và 25 token đầu ra tốn $0.00036 + $0.0005 = $0.00086 tổng cộng, nên giới hạn, không phải giá, định hình thiết kế lô. Xem trang giá cả để nạp tiền.

Giới hạn tốc độ, thử lại và tiêu đề

Vượt quá giới hạn, API trả về HTTP 429. Mã lỗi là rate_limited cho quá nhiều yêu cầu mỗi phút và concurrency cho quá nhiều cùng lúc. Quá tải tạm thời cũng trả về 429 với tiêu đề Retry-After: 5. SDK tự động thử lại một số lỗi và bạn có thể đặt max_retries trên client, nhưng xử lý rõ ràng hơn:

import time
from openai import RateLimitError

def ask(prompt, tries=4):
    for attempt in range(tries):
        try:
            raw = client.chat.completions.with_raw_response.create(
                model="uncensored",
                messages=[{"role": "user", "content": prompt}],
            )
            print("balance:", raw.headers.get("X-Balance-USD"))
            return raw.parse().choices[0].message.content
        except RateLimitError as e:
            wait = float(e.response.headers.get("Retry-After", 2 ** attempt))
            time.sleep(wait)
    raise RuntimeError("still rate limited")

Ở đây with_raw_response cho phép truy cập vào X-Balance-USD, X-Request-Id và các header giới hạn tốc độ. Ghi lại ID yêu cầu với bất kỳ lỗi nào bạn muốn báo cáo. Không bao giờ đặt khóa trong notebook bạn commit hoặc trong mã front-end.

Kiểm tra mà không tiêu tốn tín dụng và các lỗi phổ biến

Phần lớn tích hợp Python là công cụ hạ tầng, và công cụ hạ tầng không cần mô hình trực tiếp. Giữ lệnh gọi mạng phía sau một hàm, và các bài kiểm tra của bạn có thể thay thế nó. Chỉ với thư viện chuẩn:

from unittest.mock import MagicMock

def reply_text(client, prompt):
    r = client.chat.completions.create(
        model="uncensored",
        messages=[{"role": "user", "content": prompt}],
    )
    return r.choices[0].message.content.strip()

def test_reply_text_strips_whitespace():
    fake = MagicMock()
    fake.chat.completions.create.return_value.choices = [
        MagicMock(message=MagicMock(content="  hello  "))
    ]
    assert reply_text(fake, "hi") == "hello"

Chỉ chạy một vài lệnh gọi thực tế ở các điểm cuối: một smoke test mỗi lần triển khai, cùng với một lần chạy định kỳ bộ prompt đã lưu của bạn. Một smoke test với khoảng 100 token đầu vào và 20 token đầu ra tốn $0.000015 + $0.00001 = $0.000025, điều này không đáng kể, và các yêu cầu thất bại hoàn toàn không bị tính phí. Tín dụng dùng thử $0.50 lớn hơn nhiều so với nhu cầu của một bộ kiểm thử.

Đối với công việc prompt, hãy cố định seed và temperature để bạn có thể so sánh hai phiên bản của một prompt hệ thống trong điều kiện bình đẳng. Thay đổi cả prompt và cài đặt lấy mẫu giữa các lần chạy khiến kết quả khó đọc. Lưu đầu ra của mỗi lần chạy với ID yêu cầu từ tiêu đề X-Request-Id, và bạn có thể truy vết một câu trả lời đáng ngạc nhiên sau này.

Lỗi Python phổ biến

Những điều này gây ra hầu hết các câu hỏi hỗ trợ đến từ người dùng Python:

  • Chỉ truyền khóa dưới dạng OPENAI_API_KEY. Nếu bạn đặt base_url trong mã nhưng quên biến khóa, SDK sẽ gửi khóa trống hoặc sai. Truyền api_key rõ ràng.
  • Quên /v1. Base URL kết thúc bằng /v1. SDK tự thêm /chat/completions.
  • Sử dụng tên mô hình từ dịch vụ khác. Chỉ uncensored là hợp lệ ở đây.
  • Concurrency không giới hạn. asyncio.gather qua hàng nghìn coroutine không có semaphore tạo ra một bức tường lỗi concurrency.
  • Xử lý phản hồi truyền phát như một chuỗi. Nối các delta, và bỏ qua các chunk có danh sách choices trống.
  • Bỏ qua giới hạn ngữ cảnh. Lịch sử cộng với hoàn thành phải vừa trong 100.000 token. Cắt ngắn các lượt cũ trước khi bạn đạt đến nó.

Để nạp tiền và bảng giá hiện tại, hãy xem trang giá cả. Dịch vụ chỉ dành cho văn bản, vì vậy không có lệnh gọi hình ảnh, âm thanh hay embedding để kết nối, và các prompt không được sử dụng để huấn luyện.

Hỏi đáp

Tôi cần gói Python nào?

Gói openai tiêu chuẩn, phiên bản 1 trở lên. Đặt base_url thành https://api.glmapi.cc/v1 và mô hình thành uncensored.

Streaming có hoạt động không?

Có. Truyền stream=True và lặp qua các chunk. Stream kết thúc bằng thông tin sử dụng và chiếm một slot concurrency cho đến khi hoàn tất.

Tôi có thể chạy bao nhiêu yêu cầu đồng thời?

Khóa đầy đủ cho phép 8 yêu cầu đồng thời và 300 mỗi phút. Khóa dùng thử cho phép 2 và 60.

Tôi có thể dùng LangChain hoặc LiteLLM thay thế không?

Cả hai đều có thể gọi đến một endpoint tương thích OpenAI khi bạn cung cấp base URL, khóa API và tên mô hình uncensored. Hãy kiểm tra tài liệu của từng dự án để biết chính xác tên các tham số.

Khóa của bạn chỉ cách một biểu mẫu

Tạo tài khoản, sao chép khóa, thay đổi URL cơ sở. Đó là toàn bộ thiết lập.

Lấy khóa APIĐọc tài liệu