Wu Xianzhi APIตัวอย่างโค้ด
ตัวอย่างการเรียก API AI แบบไม่เซ็นเซอร์: Python, Node.js และ cURL โค้ดแบบเต็ม
คู่มือการเรียก API AI แบบไม่เซ็นเซอร์สำหรับนักพัฒนา API รองรับ Chat Completions ของ OpenAI ดังนั้น SDK ทางการของ openai ที่คุณคุ้นเคยจึงสามารถใช้งานได้โดยเปลี่ยนการตั้งค่าเพียงสองบรรทัด บทความนี้ครอบคลุมการใช้งานที่พบบ่อยที่สุด: คำขอพื้นฐาน, สตรีมมิง, การเรียกใช้ฟังก์ชัน, การจัดการข้อผิดพลาดและการรีทรี, การควบคุมต้นทุนด้วย max_tokens และการรักษาบริบทในการสนทนาหลายรอบ โค้ดทั้งหมดสามารถคัดลอกและรันได้ทันที โดยคีย์จะถูกอ่านจากตัวแปรสภาพแวดล้อม
อัปเดตเมื่อ
ประเด็นสำคัญ
- เปลี่ยน base_url เป็น https://api.wuxianzhiapi.com/v1,模型名写 uncensored SDK ทางการของ openai ไม่ต้องแก้ไขอื่นใด
- บล็อกสุดท้ายของสตรีมคือสถิติการใช้งาน โดย choices เป็นอาร์เรย์ว่าง ต้องตรวจสอบก่อนอ่าน
- ทำ exponential backoff สำหรับ 429 และ 503 เท่านั้น การรีทรีสำหรับ 400/401/402/403 ไม่มีความหมาย
- API是无状态 ต้องส่งประวัติเอง ใช้ max_tokens และตัดทอนเพื่อควบคุมต้นทุน
ข้อมูลพื้นฐานของ API และตัวแปรสภาพแวดล้อม
จดพารามิเตอร์คงที่ไว้ก่อน เพราะตัวอย่างทั้งหมดจะใช้ค่าเหล่านี้ Base URL คือ https://api.wuxianzhiapi.com/v1 ชื่อโมเดลคงที่คือ uncensored วิธีการตรวจสอบสิทธิ์คือหัวคำขอ Authorization: Bearer <คีย์ API> มีเพียงสองเอนด์พอยต์: POST /v1/chat/completions สำหรับแชท และ GET /v1/models เพื่อตรวจสอบความพร้อมของโมเดล รูปแบบคำขอและตอบกลับสอดคล้องกับ Chat Completions ของ OpenAI ดังนั้น SDK ทางการ openai จึงเพียงเปลี่ยน base_url และคีย์ API โดยโค้ดธุรกิจแทบไม่ต้องแก้ไข
คีย์ API จะแสดงทันทีหลังลงทะเบียนที่ /get-api-key/ โดยใช้เพียงอีเมลและรหัสผ่าน บัญชีใหม่มีเครดิตทดลองใช้ฟรี $0.50 ใช้ได้ภายใน 7 วัน ไม่ต้องผูกบัตร ตัวอย่างทั้งหมดในบทความนี้จะอ่านคีย์ API จากตัวแปรสิ่งแวดล้อม WUXIANZHI_API_KEY อย่าใส่คีย์ API ลงในที่เก็บโค้ดหรือหน้าเว็บ ข้อจำกัดบางประการ: หน้าต่างบริบท 100,000 โทเคน (รวมพรอมต์และผลลัพธ์) ขนาดคำขอไม่เกิน 8 MB และแต่ละคีย์ API ทำคำขอได้ 300 ครั้งต่อนาที
export WUXIANZHI_API_KEY="把你的密钥放这里"
# 确认连通性,应返回包含 uncensored 的模型列表
curl https://api.wuxianzhiapi.com/v1/models \
-H "Authorization: Bearer $WUXIANZHI_API_KEY"หากขั้นตอนนี้อนุญาต 401 แสดงว่าคีย์ API ผิดหรือตัวแปรสภาพแวดล้อมไม่ได้ผล ให้ตรวจสอบจุดนี้ก่อนแล้วจึงดูโค้ดต่อ รายละเอียดพารามิเตอร์ครบถ้วนดูที่ เอกสาร API
cURL: คำขอขั้นต่ำที่ใช้งานได้
ไม่ว่าคุณจะเลือกภาษาใด แนะนำให้ใช้ cURL ทดสอบให้ผ่านก่อน เพื่อแยกปัญหาสามประเภท: "เครือข่าย", "คีย์ API" และ "รูปแบบคำขอ" ออกจากโค้ดธุรกิจของคุณ นี่คือคำขอทั่วไปที่มี max_tokens JSON ที่คืนค่ามี choices[0].message.content เป็นเนื้อหาการตอบกลับ และ usage มีจำนวนโทเคนอินพุตและเอาต์พุตที่ใช้ ซึ่งการคิดเงินจะคำนวณจากตัวเลขสองนี้
curl https://api.wuxianzhiapi.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $WUXIANZHI_API_KEY" \
-d '{
"model": "uncensored",
"messages": [
{"role": "system", "content": "你是一个直来直去的写作助手。"},
{"role": "user", "content": "用三句话描述一场暴雨前的小镇。"}
],
"max_tokens": 300
}'หมายเหตุ: ไม่ต้อง escape ภาษาจีนใน JSON ด้วยตนเอง เพียงแค่ประกาศ JSON ที่รองรับ UTF-8 ในหัวคำขอ เทอร์มินัลส่วนใหญ่สามารถวางข้อความได้โดยตรง หากกำลังดีบักใน PowerShell ของ Windows การจัดการเครื่องหมายคำพูดอาจซับซ้อน แนะนำให้เก็บคำขอในไฟล์ body.json แล้วส่งด้วย -d @body.json
การเรียกใช้แบบเต็มใน Python และ Node.js
Python ใช้แพ็กเกจ openai ทางการ (v1 ขึ้นไป) โดย pip install openai ก่อน เมื่อสร้างไคลเอนต์ให้ส่ง base_url และ api_key เข้าไป การเรียกใช้หลังจากนั้นจะเหมือนกับเรียกใช้ OpenAI ทุกประการ สคริปต์ด้านล่างสามารถบันทึกเป็น chat.py แล้วรันได้เลย
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.wuxianzhiapi.com/v1",
api_key=os.environ["WUXIANZHI_API_KEY"],
)
resp = client.chat.completions.create(
model="uncensored",
messages=[
{"role": "system", "content": "你是一个直来直去的写作助手。"},
{"role": "user", "content": "用三句话描述一场暴雨前的小镇。"},
],
max_tokens=300,
)
print(resp.choices[0].message.content)
print("输入 tokens:", resp.usage.prompt_tokens, "输出 tokens:", resp.usage.completion_tokens)Node.js ใช้แพ็กเกจ npm ของ openai (v4 ขึ้นไป) โดย npm install openai การเขียนโค้ดด้านล่างใช้ await ระดับท็อปเลเวล ดังนั้นไฟล์ต้องบันทึกเป็น chat.mjs หรือตั้งค่า "type": "module" ใน package.json
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.wuxianzhiapi.com/v1",
apiKey: process.env.WUXIANZHI_API_KEY,
});
const resp = await client.chat.completions.create({
model: "uncensored",
messages: [
{ role: "system", content: "你是一个直来直去的写作助手。" },
{ role: "user", content: "用三句话描述一场暴雨前的小镇。" },
],
max_tokens: 300,
});
console.log(resp.choices[0].message.content);
console.log("用量:", resp.usage);โครงสร้างของโค้ดทั้งสองชุดเหมือนกัน ความแตกต่างมีเพียงไวยากรณ์ หากโปรเจกต์ของคุณมีการเรียกใช้ OpenAI อยู่แล้ว โดยทั่วไปคุณเพียงเปลี่ยนบรรทัดเริ่มต้นไคลเอนต์เหล่านั้นและเปลี่ยนชื่อโมเดลเป็น uncensored ขั้นตอนการย้ายจาก API อื่นทั้งหมดดูที่ คู่มือการย้าย
วิธีอ่านสตรีมมิง (SSE)
เมื่อเขียนข้อความยาวหรือสร้างอินเทอร์เฟซแชท ต้องใช้สตรีมมิง มิฉะนั้นผู้ใช้ต้องรอจนกว่าการสร้างข้อความทั้งหมดจะเสร็จจึงจะเห็นตัวอักษรแรก เมื่อตั้งค่า stream: true เซิร์ฟเวอร์จะส่งข้อมูลแบบ SSE (Server-Sent Events) ทีละบล็อก แต่ละบล็อกคือบรรทัด data: {...} และลงท้ายด้วย data: [DONE] SDK ทางการได้ parse ให้แล้ว คุณเพียงต้องวนลูปอ่านข้อมูล
มีจุดหนึ่งที่ต้องระวัง: บล็อกข้อมูลสุดท้ายของสตรีมจะมี usage เพิ่มมาโดยอัตโนมัติ และ choices ในบล็อกนั้นจะเป็นอาร์เรย์ว่าง คุณไม่ต้องส่งพารามิเตอร์เพิ่มเพื่อเปิดใช้งาน แต่ในโค้ดไม่ควรสมมติว่าสามารถดึง chunk.choices[0] ได้โดยตรง ต้องตรวจสอบว่าอาร์เรย์ว่างหรือไม่ มิฉะนั้นเมื่อสตรีมใกล้จะจบจะเกิดข้อผิดพลาดดัชนีเกินขอบเขต
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.wuxianzhiapi.com/v1",
api_key=os.environ["WUXIANZHI_API_KEY"],
)
stream = client.chat.completions.create(
model="uncensored",
messages=[{"role": "user", "content": "写一段 200 字左右的悬疑小说开头。"}],
max_tokens=600,
stream=True,
)
usage = None
for chunk in stream:
if chunk.usage: # 最后一块:用量统计
usage = chunk.usage
if not chunk.choices: # 用量块没有 choices
continue
delta = chunk.choices[0].delta.content
if delta:
print(delta, end="", flush=True)
print()
if usage:
print("输入", usage.prompt_tokens, "输出", usage.completion_tokens)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.wuxianzhiapi.com/v1",
apiKey: process.env.WUXIANZHI_API_KEY,
});
const stream = await client.chat.completions.create({
model: "uncensored",
messages: [{ role: "user", content: "写一段 200 字左右的悬疑小说开头。" }],
max_tokens: 600,
stream: true,
});
let usage = null;
for await (const chunk of stream) {
if (chunk.usage) usage = chunk.usage;
const delta = chunk.choices?.[0]?.delta?.content;
if (delta) process.stdout.write(delta);
}
console.log("\n用量:", usage);หากต้องการดูข้อมูล SSE ดิบ ให้ใช้ cURL พร้อมพารามิเตอร์ -N เพื่อปิดการบัฟเฟอร์เอาท์พุต ทำให้แต่ละบล็อกที่เข้ามาจะถูกพิมพ์ทันที ซึ่งมีประโยชน์ในการดีบักว่าพร็อกซีหรือเกทเวย์กำลังตัดการตอบสนองแบบสตรีมมิงหรือไม่
curl -N https://api.wuxianzhiapi.com/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $WUXIANZHI_API_KEY" \
-d '{"model":"uncensored","stream":true,"max_tokens":100,
"messages":[{"role":"user","content":"数到五。"}]}'หากคุณกำลังส่งต่อสตรีมผ่าน reverse proxy เช่น Nginx อย่าลืมปิดการบัฟเฟอร์การตอบกลับสำหรับเส้นทางนั้น มิฉะนั้นผู้ใช้ปลายทางจะเห็นการส่งข้อมูลแบบก้อนเดียวแทนที่จะเป็นตัวอักษรทีละตัว
การเรียกใช้ฟังก์ชัน: tools และการส่งกลับผลลัพธ์
การเรียกใช้ฟังก์ชันใช้รูปแบบของ OpenAI: ในคำขอให้ประกาศชื่อฟังก์ชัน คำอธิบาย และพารามิเตอร์ JSON Schema ผ่าน tools เมื่อโมเดลตัดสินใจเรียกใช้ ฟังก์ชันและพารามิเตอร์ในรูปแบบสตริง JSON จะปรากฏใน message.tool_calls ของคำตอบ โค้ดของคุณต้องทำหน้าที่เรียกใช้ฟังก์ชันจริง แล้วส่งผลลัพธ์กลับในรูปแบบข้อความ role: "tool" จากนั้นส่งคำขออีกครั้ง โมเดลจึงจะเขียนคำตอบสุดท้ายจากผลลัพธ์นั้น
tool_choice มีค่าเริ่มต้นเป็น "auto" ให้โมเดลตัดสินใจเอง; เมื่อต้องการบังคับเรียกใช้ฟังก์ชันเฉพาะ ให้ส่ง {"type": "function", "function": {"name": "get_weather"}}; ส่ง "none" เพื่อปิดการใช้งาน ตัวอย่างด้านล่างแสดงขั้นตอนครบวงจร: คำขอแรกได้ tool_calls เรียกใช้ฟังก์ชันในเครื่อง แล้วส่งคำขอครั้งที่สองพร้อมผลลัพธ์ของเครื่องมือ
import json, os
from openai import OpenAI
client = OpenAI(
base_url="https://api.wuxianzhiapi.com/v1",
api_key=os.environ["WUXIANZHI_API_KEY"],
)
def get_weather(city: str) -> dict:
# 这里用假数据代替真实的天气接口
return {"city": city, "temp_c": 18, "condition": "多云"}
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": "查询指定城市的当前天气",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string", "description": "城市名"}},
"required": ["city"],
},
},
}]
messages = [{"role": "user", "content": "杭州现在天气怎么样?"}]
first = client.chat.completions.create(
model="uncensored", messages=messages, tools=tools, tool_choice="auto", max_tokens=500
)
msg = first.choices[0].message
if msg.tool_calls:
messages.append(msg) # 必须把带 tool_calls 的 assistant 消息原样放回历史
for call in msg.tool_calls:
args = json.loads(call.function.arguments)
result = get_weather(**args)
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": json.dumps(result, ensure_ascii=False),
})
final = client.chat.completions.create(
model="uncensored", messages=messages, tools=tools, max_tokens=500
)
print(final.choices[0].message.content)
else:
print(msg.content)ข้อผิดพลาดทั่วไปสามประการ: อย่างแรกคือลืมนำข้อความ tool_calls ของ assistant กลับไปใส่ในประวัติ แล้วต่อด้วยข้อความ tool โดยตรง ทำให้รูปแบบคำขอไม่ถูกต้อง; อย่างที่สองคือ tool_call_id ไม่ตรงกัน; อย่างที่สามคือพารามิเตอร์ที่โมเดลให้มาเป็นสตริง ต้อง json.loads ก่อน และต้องเตรียมการดักจับเมื่อการแยกวิเคราะห์ล้มเหลว อย่าเอาเอาต์พุตของโมเดลไปต่อกับคำสั่งหรือ SQL โดยตรง ขั้นตอนของ Node.js เหมือนกันทุกประการ นี่คือรูปแบบที่เทียบเท่า
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.wuxianzhiapi.com/v1",
apiKey: process.env.WUXIANZHI_API_KEY,
});
const getWeather = (city) => ({ city, temp_c: 18, condition: "多云" });
const tools = [{
type: "function",
function: {
name: "get_weather",
description: "查询指定城市的当前天气",
parameters: {
type: "object",
properties: { city: { type: "string", description: "城市名" } },
required: ["city"],
},
},
}];
const messages = [{ role: "user", content: "杭州现在天气怎么样?" }];
const first = await client.chat.completions.create({
model: "uncensored", messages, tools, tool_choice: "auto", max_tokens: 500,
});
const msg = first.choices[0].message;
if (msg.tool_calls?.length) {
messages.push(msg);
for (const call of msg.tool_calls) {
const args = JSON.parse(call.function.arguments);
messages.push({
role: "tool",
tool_call_id: call.id,
content: JSON.stringify(getWeather(args.city)),
});
}
const final = await client.chat.completions.create({
model: "uncensored", messages, tools, max_tokens: 500,
});
console.log(final.choices[0].message.content);
} else {
console.log(msg.content);
}
การจัดการข้อผิดพลาดและการรีทรี: วิธีทำ exponential backoff สำหรับ 429 และ 503
ข้อผิดพลาดทั้งหมดส่งคืน JSON รูปแบบเดียวกัน: {"error":{"code":...,"message":...}} ในโค้ด มีเพียงสองประเภทที่ต้องลองใหม่: 429 (เกินขีดจำกัด 300 ครั้งต่อนาที) และ 503 (upstream_busy โมเดลกำลังยุ่งชั่วคราว ลองใหม่ในไม่กี่วินาที) การเชื่อมต่อ timeout ที่ชั้นเครือข่ายก็ควรลองใหม่เช่นกัน ข้อผิดพลาดอื่นๆ ไม่คุ้มค่าที่จะลองใหม่: 400 คือคำขอมีปัญหา (เช่น พรอมต์เกิน max_tokens 100k), 401 คือคีย์ไม่ถูกต้อง, 402 no_credit คือเงินหมดหรือเครดิตทดลองใช้หมดอายุ, 403 content_blocked คือเนื้อหาถูกบล็อก ส่งซ้ำร้อยครั้งผลลัพธ์ก็เหมือนเดิม
กลยุทธ์การหน่วงเวลาแบบ exponential backoff พร้อม random jitter: ครั้งแรกรอประมาณ 1 วินาที, ครั้งที่ 2 รอประมาณ 2 วินาที, ครั้งที่ 3 รอประมาณ 4 วินาที กำหนดค่าสูงสุดและจำนวนครั้งสูงสุด เพื่อหลีกเลี่ยงการที่งานหลายงานที่ทำงานแบบ parallel requests ลองใหม่พร้อมกันในช่วงเวลาเดียวกัน ทำให้ขีดจำกัดอัตราถูกชนหนักขึ้น SDK ทางการมี max_retries ในตัว โดยค่าเริ่มต้นจะลองใหม่สำหรับ 429 และ 5xx เพียงเล็กน้อย กรณีง่ายๆ เพียงแค่ปรับค่าให้สูงขึ้น; หากต้องการ log, circuit breaker หรือกำหนดเวลาหน่วงเอง ให้เขียน loop เอง
import os, random, time
import openai
from openai import OpenAI
# max_retries=0:关闭 SDK 自带重试,完全由下面的函数控制
client = OpenAI(
base_url="https://api.wuxianzhiapi.com/v1",
api_key=os.environ["WUXIANZHI_API_KEY"],
max_retries=0,
timeout=60,
)
def chat_with_retry(messages, max_attempts=5, **kwargs):
for attempt in range(max_attempts):
try:
return client.chat.completions.create(
model="uncensored", messages=messages, **kwargs
)
except (openai.RateLimitError, openai.InternalServerError,
openai.APIConnectionError, openai.APITimeoutError) as e:
if attempt == max_attempts - 1:
raise
wait = min(30, 2 ** attempt) + random.uniform(0, 1)
print(f"{type(e).__name__},{wait:.1f} 秒后重试(第 {attempt + 1} 次)")
time.sleep(wait)
except openai.APIStatusError as e:
# 400 / 401 / 402 / 403 / 404:重试无效,直接交给上层处理
print("不可重试:", e.status_code, e.response.text)
raise
resp = chat_with_retry([{"role": "user", "content": "你好"}], max_tokens=100)
print(resp.choices[0].message.content)ใน Node.js คุณสามารถเพิ่ม maxRetries ได้โดยตรง SDK จะจัดการ 429 และ 5xx ตามกลยุทธ์การรีไทร์แบบ exponential backoff หากต้องการแยกแยะข้อผิดพลาด ให้ใช้ error.status เพื่อตรวจสอบ
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.wuxianzhiapi.com/v1",
apiKey: process.env.WUXIANZHI_API_KEY,
maxRetries: 5,
timeout: 60_000,
});
try {
const resp = await client.chat.completions.create({
model: "uncensored",
messages: [{ role: "user", content: "你好" }],
max_tokens: 100,
});
console.log(resp.choices[0].message.content);
} catch (err) {
if (err instanceof OpenAI.APIError) {
if (err.status === 402) console.error("余额不足,请充值后再试");
else if (err.status === 403) console.error("内容被拦截:", err.message);
else console.error("请求失败:", err.status, err.message);
} else {
throw err;
}
}อีกอย่างหนึ่งเตือนไว้: หากการเชื่อมต่อคำขอแบบสตรีมมิงขาดระหว่างทาง เนื้อหาที่ได้รับแล้วต้องบันทึกไว้เอง การรีไทร์จะเริ่มสร้างใหม่ตั้งแต่ต้นและคิดค่าใช้จ่ายใหม่ ดังนั้นคำแนะนำสำหรับข้อความยาวคือใช้คำขอแบบแบ่งคำขอเป็นช่วงๆ แทนที่จะขอเนื้อหาปริมาณมากในครั้งเดียว
ควบคุมต้นทุนและความยาวด้วย max_tokens
กฎการคิดเงินตรงไปตรงมา: อินพุต $0.25 / ล้านโทเคน, เอาต์พุต $1.00 / ล้านโทเคน, ยอดเงินเติมเงินล่วงหน้า ไม่มีค่าสมาชิก ยอดเงินไม่หมดอายุ ราคาต่อหน่วยของเอาต์พุตคือ 4 เท่าของอินพุต ดังนั้นจุดที่ประหยัดเงินได้จริงคือเอาต์พุต max_tokens ค่าเริ่มต้นคือ 2048 ค่าสูงสุดต่อครั้งคือ 32,000 หากสถานการณ์ของคุณต้องการเพียงคำตอบสั้นๆ ให้ตั้งค่าเป็น 200 หรือ 300 เพื่อป้องกันโมเดลพูดมากและจำกัดค่าใช้จ่ายสูงสุดต่อคำขอ
ลองคำนวณดู: คำขอหนึ่งครั้งตั้งค่า max_tokens เป็น 1,000 ค่าใช้จ่ายเอาต์พุตในกรณีเลวร้ายที่สุดคือ $0.001; ตั้งเป็นค่าสูงสุด 32,000 ค่าใช้จ่ายในกรณีเลวร้ายที่สุดคือ $0.016 เครดิตทดลองใช้ฟรี $0.50 คิดเป็นประมาณ 500,000 โทเคนเอาต์พุต หรือ 2,000,000 โทเคนอินพุต เพียงพอสำหรับการรันตัวอย่างทั้งหมดในบทความนี้หลายรอบ หมายเหตุว่าผลรวมของพรอมต์และ max_tokens ต้องไม่เกิน 100,000 มิฉะนั้นจะตอบกลับด้วย 400 ทันที ดังนั้นเมื่ออินพุยยาวให้ลดขีดจำกัดเอาต์พุตลงพร้อมกัน รายละเอียดราคาเพิ่มเติมนั้นอยู่ที่ หน้าราคา
รายละเอียดอีกอย่าง: หากการตอบกลับถูกตัดขาด finish_reason ในคำตอบจะเป็น "length" ซึ่งหมายถึง max_tokens ไม่เพียงพอ ไม่ใช่โมเดลเขียนเสร็จเอง เมื่อเขียนบทความยาวๆ สามารถตรวจสอบฟิลด์นี้เพื่อตัดสินใจว่าจะทำการเขียนต่อหรือไม่
การสนทนาหลายรอบ: รักษาบริบทด้วยตนเอง
API เป็นแบบ stateless เซิร์ฟเวอร์จะไม่จำคำขอครั้งก่อน เพื่อให้โมเดลสนทนาต่อ คุณต้องส่งข้อความประวัติทั้งหมดตามลำดับใหม่ทุกครั้ง: เริ่มจาก system จากนั้น user และ assistant สลับกัน ซึ่งหมายความว่ายิ่งสนทนาหลายรอบ จำนวนโทเคนอินพุตก็จะเพิ่มขึ้นเรื่อยๆ และต้นทุนก็สะสม เมื่อสนทนาไปเรื่อยๆ ค่าใช้จ่ายอินพุตของแต่ละรอบจะสูงกว่ารอบก่อนหน้า
ปริมาณ context ทั้งหมดถูกจำกัดไว้ที่ 100,000 tokens (รวมถึงการตอบกลับนี้) ดังนั้นการสนทนาที่ยาวนานจำเป็นต้องมีการตัดทอน วิธีที่ง่ายที่สุดคือการเก็บข้อความ system และรอบการสนทนาล่าสุดไว้; หากซับซ้อนขึ้น คุณสามารถใช้คำขอหนึ่งครั้งเพื่อสรุปเนื้อหาเก่าให้เป็นบทสรุปสั้นๆ แล้วใส่ลงในข้อความ system คลาสด้านล่างนี้บรรจุตรรกะในการบันทึกประวัติและการตัดทอนตามจำนวนข้อความ คุณสามารถนำไปใช้กับบริการแชทของคุณได้โดยตรง
import os
from openai import OpenAI
client = OpenAI(
base_url="https://api.wuxianzhiapi.com/v1",
api_key=os.environ["WUXIANZHI_API_KEY"],
)
class Chat:
def __init__(self, system: str, keep_last: int = 20):
self.system = {"role": "system", "content": system}
self.history = [] # 只存 user / assistant 消息
self.keep_last = keep_last
def say(self, text: str, max_tokens: int = 500) -> str:
self.history.append({"role": "user", "content": text})
recent = self.history[-self.keep_last:]
resp = client.chat.completions.create(
model="uncensored",
messages=[self.system] + recent,
max_tokens=max_tokens,
)
reply = resp.choices[0].message.content
self.history.append({"role": "assistant", "content": reply})
return reply
bot = Chat("你是一位说话简短的旅行顾问。")
print(bot.say("我想去云南玩五天,有什么建议?"))
print(bot.say("刚才说的第二个地方,适合带老人吗?")) # 能接上上一轮การตัดตามจำนวนข้อความเพียงพอแต่ไม่แม่นยำ เพราะความยาวของแต่ละข้อความแตกต่างกันมาก หากคุณต้องการควบคุมอย่างเคร่งครัด ให้ใช้ usage.prompt_tokens จากคำตอบเป็นข้อมูลอ้างอิงปริมาณการใช้งานจริง: เมื่อเข้าใกล้ 50,000 ให้ทำการบีบอัดประวัติด้วยตนเอง หากต้องการสร้างผลิตภัณฑ์แบบเพื่อนคู่สนทนาระยะยาว สามารถดูตัวอย่างการออกแบบหน้าต่างบริบทใน กรณีการใช้งาน ได้เพิ่มเติม
คำถามที่พบบ่อย
ทำไมบล็อกข้อมูลสตรีมมิงบล็อกสุดท้ายถึงไม่มีเนื้อหา?
นั่นคือบล็อกสถิติการใช้งานที่เพิ่มเข้ามาอัตโนมัติ โดย choices เป็นอาร์เรย์ว่างและมีจำนวน token ใน usage เพียงตรวจสอบว่า choices ว่างหรือไม่ก่อน แล้วดึง delta ออกมา ก็เพียงพอแล้ว ไม่ต้องส่งพารามิเตอร์เพิ่มเพื่อเปิดใช้งาน
ต้อง retry ทั้ง 429 และ 503 หรือไม่? ควรรอเป็นเวลานานแค่ไหน?
ควรทำการรีไทร์ทั้งหมด 429 คือเกินขีดจำกัด 300 ครั้งต่อนาที 503 คือ upstream_busy โมเดลกำลังยุ่งชั่วคราว แนะนำกลยุทธ์การรีไทร์แบบ exponential backoff พร้อมเพิ่มค่าสุ่ม เริ่มต้นที่ 1 วินาที กำหนดจำนวนครั้งสูงสุด อย่าทำการรีไทร์แบบไม่มีที่สิ้นสุด
เมื่อเรียกใช้ฟังก์ชันแล้วโมเดลไม่ส่ง tool_calls กลับมา จะทำอย่างไร?
หากโมเดลตัดสินใจว่าไม่จำเป็นต้องเรียกใช้ฟังก์ชัน ค่า message.content จะเป็นคำตอบสุดท้าย หากจำเป็นต้องเรียกใช้ สามารถกำหนด tool_choice เป็นฟังก์ชันเฉพาะ และตรวจสอบว่าคำอธิบายฟังก์ชันและ Schema ของพารามิเตอร์นั้นชัดเจนดีแล้วหรือไม่
การสนทนาหลายรอบจะทำให้ค่าใช้จ่ายแพงขึ้นเรื่อยๆ หรือไม่?
ใช่ อินเทอร์เฟซไม่มีสถานะ (stateless) จึงต้องส่งประวัติการสนทนาใหม่ทุกครั้ง ทำให้จำนวน input token สะสมตามจำนวนรอบ สามารถเก็บเฉพาะรอบล่าสุดไว้ หรือบีบอัดเนื้อหาเก่าให้เป็นบทสรุป พร้อมจำกัดจำนวน output ด้วย max_tokens ได้
กรอกแบบฟอร์มเพื่อรับคีย์ API
สร้างบัญชี คัดลอกคีย์ แล้วแก้ไข Base URL การตั้งค่าก็ง่ายเพียงเท่านี้
รับคีย์ API