Skip to content

LLM API Integration Guide ​

Last updated: October 17, 2026 (Asia/Shanghai)

Related: Help Center · Image Generation · Video Generation · Full Reference

This guide explains how to connect tokenexplore's text chat, image understanding, tool calling, streaming output, and reasoning to your application. To generate images or videos, see Image Generation and Video Generation, respectively.


1. Choose an Endpoint ​

On tokenexplore, new projects should prefer OpenAI Chat Completions (/v1/chat/completions): it offers the best compatibility with Claude, Gemini, Kimi, DeepSeek, GLM, Qwen, and other models, and has the widest third-party tool support.

EndpointPathUse case
OpenAI Chat Completions (recommended first choice)POST https://ai.afp.net/v1/chat/completionsMost applications, SDKs, and third-party clients
OpenAI ResponsesPOST https://ai.afp.net/v1/responsesWhen the target model is confirmed to support Responses; this is a newer protocol, so run a minimal test before integrating
Anthropic MessagesPOST https://ai.afp.net/v1/messagesExisting Anthropic SDK / Claude Code
Gemini nativePOST https://ai.afp.net/v1beta/models/{model}:generateContentExisting Google GenAI SDK / Gemini CLI; also recommended for image generation
Gemini streamingPOST https://ai.afp.net/v1beta/models/{model}:streamGenerateContent?alt=sseGemini native streaming
Model listGET https://ai.afp.net/v1/modelsList models available to the current token

All protocols share the same API key; only the request headers differ:

ProtocolRecommended header
OpenAI-compatibleAuthorization: Bearer sk-xxx
Anthropicx-api-key: sk-xxx + anthropic-version: 2023-06-01 (Bearer also works)
Geminix-goog-api-key: sk-xxx (?key= or Bearer also works)

Warning

API keys are created under "Token Management" in the console. Never put them in frontend code, screenshots, logs, or public repositories.

How to set the Base URL:

ValueTypical users
https://ai.afp.netAnthropic SDK, Claude Code, Google GenAI, Gemini CLI, Cherry Studio
https://ai.afp.net/v1Official OpenAI SDK, Cursor, LangChain, most "OpenAI Compatible" clients
https://ai.afp.net/v1/chat/completionsA few tools that require the full path

If one form returns a 404, try the other two in turn—an extra or missing /v1 is the most common cause.


2. List Models ​

bash
export CIYUAN_BASE_URL="https://ai.afp.net"
export CIYUAN_API_KEY="sk-xxxxxxxx"

curl "$CIYUAN_BASE_URL/v1/models" \
  -H "Authorization: Bearer $CIYUAN_API_KEY"

The response is an OpenAI-format list. Results are limited by the token's available models and token group; rely on what the API actually returns. The Gemini SDK can also use GET https://ai.afp.net/v1beta/models (x-goog-api-key).

Current Models at a Glance (Snapshot) ​

For pricing, refer to "Model Marketplace / Pricing" in the console; this guide does not list unit prices.

Claude ​

Model IDNotes
claude-opus-5-5 / claude-opus-5Opus flagship tier
claude-opus-4-8 / claude-opus-4-7 / claude-opus-4-6Opus 4.x
claude-opus-4-6-thinkingExtended thinking enabled by default
claude-sonnet-5 / claude-sonnet-4-6Sonnet; claude-sonnet-4-6 is commonly used for day-to-day development
claude-sonnet-4-5-20250929Dated fixed snapshot
claude-haiku-4-5 / claude-haiku-4-5-20251001Low latency, low cost
claude-fable-5 / claude-fable-5-1Fable series

Gemini ​

Model IDNotes
gemini-3.1-pro / gemini-3.1-pro-previewPro tier
gemini-3.7-flash / gemini-3.6-flash / gemini-3.5-flashFlash tier
gemini-3.5-flash-lite / gemini-3.1-flash-lite / gemini-2.5-flash-liteLite tier
gemini-2.5-pro2.5 Pro
gemini-3-pro-image / gemini-3.1-flash-imageImage generation / editing, see the Image Generation guide

Other Text Models ​

FamilyModel IDs
Kimikimi-k3, kimi-k3-usd (billing/channel variants; see the console for differences)
DeepSeekdeepseek-v4-pro-0813, deepseek-v4-flash, deepseek-v4-1-flash-260910
GLMglm-5.3, glm-5.3-flash, glm-5.2
Qwenqwen3.8-max, qwen3.8-flash

For video models, see the Video Generation guide. Not every model supports vision, tools, reasoning, or Responses—send one minimal request to the target model before integrating.


POST https://ai.afp.net/v1/chat/completions

Text Request ​

bash
curl "$CIYUAN_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.5-flash",
    "messages": [
      {"role": "system", "content": "You are a concise technical assistant."},
      {"role": "user", "content": "Explain what SSE is"}
    ],
    "temperature": 0.7,
    "max_tokens": 1024
  }'

In the response, choices[0].message.content is the answer and usage reports token usage.

Image Input (Understanding, Not Generation) ​

bash
curl "$CIYUAN_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gemini-3.5-flash",
    "messages": [{
      "role": "user",
      "content": [
        {"type": "text", "text": "Describe this image and extract the text in it"},
        {"type": "image_url", "image_url": {"url": "https://example.com/image.png"}}
      ]
    }]
  }'

For local images, you can use a Data URL: data:image/jpeg;base64,.... The main Claude and Gemini text models generally support vision; for Kimi / Qwen / GLM, refer to the labels in Model Marketplace.

Tool Calling ​

python
# pip install -U openai
import os, json
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["CIYUAN_API_KEY"],
    base_url=os.environ["CIYUAN_BASE_URL"] + "/v1",
)

tools = [{
    "type": "function",
    "function": {
        "name": "get_weather",
        "description": "Get the current weather for a given city",
        "parameters": {
            "type": "object",
            "properties": {
                "city": {"type": "string", "description": "City name, e.g. Beijing"}
            },
            "required": ["city"],
        },
    },
}]

messages = [{"role": "user", "content": "What's the weather in Beijing right now?"}]
resp = client.chat.completions.create(
    model="claude-sonnet-4-6", messages=messages, tools=tools, tool_choice="auto"
)
msg = resp.choices[0].message
messages.append(msg)

if msg.tool_calls:
    for call in msg.tool_calls:
        args = json.loads(call.function.arguments)
        result = {"city": args["city"], "weather": "Sunny", "temp_c": 18}  # Replace with a real implementation
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": json.dumps(result, ensure_ascii=False),
        })
    final = client.chat.completions.create(
        model="claude-sonnet-4-6", messages=messages, tools=tools
    )
    print(final.choices[0].message.content)

tool_choice: "auto" / "none" / "required", or force a specific function name.

Streaming Output ​

bash
curl -N "$CIYUAN_BASE_URL/v1/chat/completions" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-v4-flash",
    "stream": true,
    "stream_options": {"include_usage": true},
    "messages": [{"role": "user", "content": "Write a five-character quatrain about autumn"}]
  }'

Returns an SSE stream: data: {...} lines, terminated by data: [DONE]. Python:

python
stream = client.chat.completions.create(
    model="deepseek-v4-flash",
    messages=[{"role": "user", "content": "Write a five-character quatrain about autumn"}],
    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)

Common Fields ​

FieldNotes
modelRequired
messagesRequired; role can be system / user / assistant / tool
stream / stream_optionsStreaming; include_usage returns usage in the final chunk
max_tokens / max_completion_tokensOutput limit; reasoning also counts against it
temperature / top_pSampling; not supported by some reasoning models
tools / tool_choiceTool calling
response_formate.g. {"type":"json_object"}, depending on the model
reasoning_effortlow / medium / high, supported by some models

finish_reason: stop means normal completion; length means the output limit was reached; tool_calls means a tool call is required; content_filter means the content was filtered.


4. OpenAI Responses ​

POST https://ai.afp.net/v1/responses

The request body uses input instead of messages, and instructions instead of system.

INFO

Whether a model can use Responses depends on the platform's channel configuration. When calling non-OpenAI models such as Claude / Gemini / Kimi, prefer Chat Completions or the vendor's native protocol unless there is a specific reason not to. If you get a 4xx, switch back to Chat Completions.

bash
curl "$CIYUAN_BASE_URL/v1/responses" \
  -H "Authorization: Bearer $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-6",
    "instructions": "You are a concise technical assistant.",
    "input": "Introduce tokenexplore in three sentences",
    "max_output_tokens": 1024
  }'
python
resp = client.responses.create(
    model="claude-sonnet-4-6",
    input="Introduce tokenexplore in three sentences",
)
print(resp.output_text)
FieldNotes
model / inputRequired
instructionsSystem instructions
streamStreaming (semantic SSE events)
max_output_tokensOutput limit
reasoninge.g. {"effort":"high"}
toolsTools in Responses format (flat fields)

Check status for completion: completed is normal; for incomplete, see incomplete_details.reason.

Image input (Responses): use {"type":"input_image","image_url":"..."} in input[].content[].


5. Anthropic Messages ​

POST https://ai.afp.net/v1/messages

bash
curl "$CIYUAN_BASE_URL/v1/messages" \
  -H "x-api-key: $CIYUAN_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-4-8",
    "max_tokens": 1024,
    "system": "You are a senior Go engineer.",
    "messages": [
      {"role": "user", "content": "How do you usually troubleshoot a goroutine leak?"}
    ]
  }'
ItemAnthropicChat Completions
max_tokensRequiredOptional
System promptTop-level systemrole: "system"
Imagestype: "image" + sourcetype: "image_url"
Tool schemainput_schemafunction.parameters
Stop reasonstop_reasonfinish_reason

Image URL example: {"type":"image","source":{"type":"url","url":"https://example.com/a.png"}}; for Base64, use source.type = "base64" with media_type / data.

Tools: when stop_reason: "tool_use", take the tool_use block from content; send tool_result back in the next user message.

If the channel supports prompt caching, add "cache_control": {"type":"ephemeral"} to blocks; on a cache hit, cache-related fields appear in usage.


6. Gemini Native API ​

bash
curl "$CIYUAN_BASE_URL/v1beta/models/gemini-3.1-pro:generateContent" \
  -H "x-goog-api-key: $CIYUAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "systemInstruction": {"parts": [{"text": "You are a concise assistant."}]},
    "contents": [
      {"role": "user", "parts": [{"text": "Why is the sea salty?"}]}
    ],
    "generationConfig": {"temperature": 0.7, "maxOutputTokens": 2048}
  }'
python
# pip install -U google-genai
import os
from google import genai
from google.genai import types

client = genai.Client(
    api_key=os.environ["CIYUAN_API_KEY"],
    http_options=types.HttpOptions(base_url=os.environ["CIYUAN_BASE_URL"]),  # Do not include /v1beta
)
resp = client.models.generate_content(
    model="gemini-3.1-pro",
    contents="Why is the sea salty?",
)
print(resp.text)

Image input: put {"inlineData":{"mimeType":"image/png","data":"<base64>"}} in parts. The platform does not yet support :countTokens (it returns 404); refer to usageMetadata in the response instead.


7. Reasoning / Thinking ​

Thinking consumes tokens (usually billed as output) and counts against max_tokens.

Claude native:

json
{
  "model": "claude-opus-4-8",
  "max_tokens": 16000,
  "thinking": {"type": "enabled", "budget_tokens": 8000},
  "messages": [{"role": "user", "content": "Prove that the square root of 2 is irrational"}]
}
  • budget_tokens must be less than max_tokens, and generally ≥ 1024
  • Once enabled, do not set sampling parameters such as temperature / top_k
  • You can also use claude-opus-4-6-thinking directly; with Chat Completions, reasoning usually appears in reasoning_content

Gemini: With Chat Completions you can pass reasoning_effort; natively you can use generationConfig.thinkingConfig (e.g. thinkingBudget, includeThoughts; the Gemini 3 series also has thinkingLevel).

DeepSeek / Kimi / GLM / Qwen: via Chat Completions; if there is reasoning, it usually appears in reasoning_content.

Common pitfalls: empty content with finish_reason: length → max_tokens is too small and was entirely consumed by reasoning; parameter errors → remove sampling parameters first; slow first token → use streaming.


8. SDK Quick Reference ​

python
# OpenAI SDK — Chat Completions
from openai import OpenAI
client = OpenAI(api_key="sk-xxxxxxxx", base_url="https://ai.afp.net/v1")
print(client.chat.completions.create(
    model="kimi-k3",
    messages=[{"role": "user", "content": "Hello"}],
).choices[0].message.content)
python
# Anthropic SDK — note: base_url must not include /v1
import anthropic
claude = anthropic.Anthropic(api_key="sk-xxxxxxxx", base_url="https://ai.afp.net")
msg = claude.messages.create(
    model="claude-sonnet-4-6", max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}],
)
print(msg.content[0].text)
python
# LangChain
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(model="qwen3.8-max", api_key="sk-xxxxxxxx",
                 base_url="https://ai.afp.net/v1")
print(llm.invoke("Hello").content)

Environment variables:

bash
export OPENAI_API_KEY="sk-xxxxxxxx"
export OPENAI_BASE_URL="https://ai.afp.net/v1"
export ANTHROPIC_API_KEY="sk-xxxxxxxx"
export ANTHROPIC_BASE_URL="https://ai.afp.net"

9. Errors and Troubleshooting (Summary) ​

Status codeCommon cause
400JSON/parameter error; Claude is missing max_tokens; the model does not support a parameter
401Wrong key, missing Bearer , or the token was deleted
403Insufficient balance/token quota, model not authorized, or IP allowlist
404Extra or missing /v1 in the Base URL, or the path does not exist
429Rate limited → retry with exponential backoff
502/503No available channel upstream or in the current group
504Timeout → switch to streaming or increase the timeout

Troubleshooting order: minimal curl → GET /v1/models to verify the model name → remove optional parameters → check "Usage Logs" in the console. When contacting support, provide the time (specify Asia/Shanghai), the model, the path, and the error message; do not send the full key.

For more error codes and details about tokens/groups, see the Full Reference.


10. FAQ for This Page ​

Should a new project use /v1/chat/completions or /v1/responses?
On tokenexplore, prefer Chat Completions. Use Responses only after confirming the model supports it and you need Responses features.

Can I call Claude / Gemini with the OpenAI SDK?
Yes, just set model to the corresponding ID. To use capabilities unique to Claude caching, Gemini native image generation, etc., switch to the native protocol.

How do I pass image parameters?
Responses: input_image; Chat Completions: image_url; Anthropic: image + source; Gemini: inlineData. Either a public URL or a Data URL works.

Why does my image request have no effect?
Confirm the model supports vision; make sure the URL is publicly accessible (otherwise use a Data URL); don't stuff image-generation API parameters into the chat endpoint.

Why does a reasoning model report an unsupported parameter?
First remove temperature, top_p, presence_penalty, frequency_penalty, logprobs, etc., then add them back one by one.

Why can't I JSON.parse a streaming response directly?
It's an SSE event stream; read data: lines one by one and stop at [DONE].

The console shows a balance, but the API says the quota is insufficient?
Check whether the token's own quota limit is exhausted; account balance and token quota are two different things.

Are file uploads, fine-tuning, and Assistants supported?
No; /v1/files, /v1/fine-tunes, etc. may return 501. Extract document content as text or pass it as images.


Previous: Help Center · Next: Image Generation and Editing