Skip to main content

Open AI API compatiable LLM server for Amlogic Device

Project description

AML LLM OpenAI Server

An OpenAI-compatible API server for Amlogic LLM devices, with built-in tool-calling evaluation and Agent capability benchmarking tools.

  • Server: OpenAI-compatible /v1/chat/completions endpoint (ADLA & llama.cpp backends)
  • Tools Evaluation: Measure tool-calling accuracy of local vs cloud models
  • Agent Benchmark: Evaluate LLM agent capabilities on MMLU-Pro, TAU2-Bench, and BFCL

Prerequisites

This project is using uv please use following command or follow the official document to install uv

curl -LsSf https://astral.sh/uv/install.sh | sh

Install the wheel

uv venv --python 3.11
uv pip install amlllm-openai-server -i <index url>

Bootstrap

Use a bootstrap tool

You need Internet connection to use bootstrap scripts to download the models or you can manually put files in folder

  1. List the available model
uv run -m amlllm_openai_server.bootstrap list

You will see the available models as following table

# Name Type Thinking Multimodal Context Tools
0 Qwen3-1.7B Qwen3 Yes No 8192 Yes
1 Qwen3-4B-Instruct-2507 Qwen3 No No 8192 Yes
2 Qwen3-4B Qwen3 Yes No 4096 Yes
  1. Download the model

Replace the model name as your expectation. Here use Qwen3-4B-Instruct-2507 for example.

uv run -m amlllm_openai_server.bootstrap download Qwen3-4B-Instruct-2507

Server Configuration

config/server.yaml

server:
  host: "0.0.0.0"
  port: 8000
  api_key: ""          # optional, set for authentication
  log_level: "info"
  title: "AMLLLM OneAPI Proxy"
  version: "0.2.0"

models:
  root_dir: "../models"
  enabled:
    - default           # model directories under root_dir

# Optional: upstream proxy to a cloud API
# upstream:
#   base_url: "https://api.openai.com"
#   api_key: "sk-..."
#   model: "gpt-4o"
#   force_upstream: false
#   skill_injection: false

models/default/model.json

Example for Qwen3 Seriers:

{
  "id": "amlogic-default",
  "weights": "Qwen3-1.7B-Q4AM_PB32.adla",
  "model_type": "qwen",
  "sampling_mode": "top_p",
  "top_k": 40,
  "top_p": 0.85,
  "temperature": 0.7,
  "repeat_penalty": 1.15,
  "presence_penalty": 10,
  "system_prompt": "You are a helpful assistant.",
  "prompt_prefix": "",
  "prompt_postfix": "",
  "retain_history": true,
  "loglevel": "ERROR",
  "metadata": {
    "family": "default",
    "device": "amlogic"
  },
  "token_pair": { "151657": 151658 },
  "chat_format": "{%- if tools %}\n    {{- '<|im_start|>system\\n' }}\n    {%- if messages[0].role == 'system' %}\n        {{- messages[0].content + '\\n\\n' }}\n    {%- endif %}\n    {{- \"# Tools\\n\\nYou may call one or more functions to assist with the user query.\\n\\nYou are provided with function signatures within <tools></tools> XML tags:\\n<tools>\" }}\n    {%- for tool in tools %}\n        {{- \"\\n\" }}\n        {{- tool | tojson }}\n    {%- endfor %}\n    {{- \"\\n</tools>\\n\\nFor each function call, return a json object with function name and arguments within <tool_call></tool_call> XML tags:\\n<tool_call>\\n{\\\"name\\\": <function-name>, \\\"arguments\\\": <args-json-object>}\\n</tool_call><|im_end|>\\n\" }}\n{%- else %}\n    {%- if messages[0].role == 'system' %}\n        {{- '<|im_start|>system\\n' + messages[0].content + '<|im_end|>\\n' }}\n    {%- endif %}\n{%- endif %}\n{%- set ns = namespace(multi_step_tool=true, last_query_index=messages|length - 1) %}\n{%- for message in messages[::-1] %}\n    {%- set index = (messages|length - 1) - loop.index0 %}\n    {%- if ns.multi_step_tool and message.role == \"user\" and message.content is string and not(message.content.startswith('<tool_response>') and message.content.endswith('</tool_response>')) %}\n        {%- set ns.multi_step_tool = false %}\n        {%- set ns.last_query_index = index %}\n    {%- endif %}\n{%- endfor %}\n{%- for message in messages %}\n    {%- if message.content is string %}\n        {%- set content = message.content %}\n    {%- else %}\n        {%- set content = '' %}\n    {%- endif %}\n    {%- if (message.role == \"user\") or (message.role == \"system\" and not loop.first) %}\n        {{- '<|im_start|>' + message.role + '\\n' + content + '<|im_end|>' + '\\n' }}\n    {%- elif message.role == \"assistant\" %}\n        {%- set reasoning_content = '' %}\n        {%- if message.reasoning_content is string %}\n            {%- set reasoning_content = message.reasoning_content %}\n        {%- else %}\n            {%- if '</think>' in content %}\n                {%- set reasoning_content = content.split('</think>')[0].rstrip('\\n').split('<think>')[-1].lstrip('\\n') %}\n                {%- set content = content.split('</think>')[-1].lstrip('\\n') %}\n            {%- endif %}\n        {%- endif %}\n        {%- if loop.index0 > ns.last_query_index %}\n            {%- if loop.last or (not loop.last and reasoning_content) %}\n                {{- '<|im_start|>' + message.role + '\\n<think>\\n' + reasoning_content.strip('\\n') + '\\n</think>\\n\\n' + content.lstrip('\\n') }}\n            {%- else %}\n                {{- '<|im_start|>' + message.role + '\\n' + content }}\n            {%- endif %}\n        {%- else %}\n            {{- '<|im_start|>' + message.role + '\\n' + content }}\n        {%- endif %}\n        {%- if message.tool_calls %}\n            {%- for tool_call in message.tool_calls %}\n                {%- if (loop.first and content) or (not loop.first) %}\n                    {{- '\\n' }}\n                {%- endif %}\n                {%- if tool_call.function %}\n                    {%- set tool_call = tool_call.function %}\n                {%- endif %}\n                {{- '<tool_call>\\n{\"name\": \"' }}\n                {{- tool_call.name }}\n                {{- '\", \"arguments\": ' }}\n                {%- if tool_call.arguments is string %}\n                    {{- tool_call.arguments }}\n                {%- else %}\n                    {{- tool_call.arguments | tojson }}\n                {%- endif %}\n                {{- '}\\n</tool_call>' }}\n            {%- endfor %}\n        {%- endif %}\n        {{- '<|im_end|>\\n' }}\n    {%- elif message.role == \"tool\" %}\n        {%- if loop.first or (messages[loop.index0 - 1].role != \"tool\") %}\n            {{- '<|im_start|>user' }}\n        {%- endif %}\n        {{- '\\n<tool_response>\\n' }}\n        {{- content }}\n        {{- '\\n</tool_response>' }}\n        {%- if loop.last or (messages[loop.index0 + 1].role != \"tool\") %}\n            {{- '<|im_end|>\\n' }}\n        {%- endif %}\n    {%- endif %}\n{%- endfor %}\n{%- if add_generation_prompt %}\n    {{- '<|im_start|>assistant\\n' }}\n    {%- if enable_thinking is defined and enable_thinking is false %}\n        {{- '<think>\\n\\n</think>\\n\\n' }}\n    {%- endif %}\n{%- endif %}"
}

Model Configuration Parameters

Parameter Type Required Default Description
id string Yes Unique model identifier, used as model in OpenAI API requests
weights string Yes Path to the model weights file (.adla for ADLA, .gguf for llama.cpp)
model_type string Yes Model architecture type: "qwen", "llama", "gemma", etc. Determines chat template and tokenization
sampling_mode string No "top_p" Sampling strategy: "top_p", "top_k", or "greedy"
top_k int No 40 Top-K sampling: keep only the K most likely tokens
top_p float No 0.85 Nucleus sampling: keep tokens with cumulative probability ≥ p
temperature float No 0.7 Controls randomness; higher = more creative, lower = more deterministic
repeat_penalty float No 1.15 Penalizes repeated tokens; > 1.0 discourages repetition
presence_penalty float No 0 ADLA-specific presence penalty for token repetition
system_prompt string No "" Default system prompt prepended to every conversation
prompt_prefix string No "" Custom text prepended before the prompt
prompt_postfix string No "" Custom text appended after the prompt
retain_history bool No true Whether to keep conversation history across turns
loglevel string No "ERROR" ADLA runtime log level: "DEBUG", "INFO", "WARNING", "ERROR"
metadata dict No {} Arbitrary key-value metadata exposed in /v1/models response
token_pair dict No {} Special token ID mapping, e.g. {"151657": 151658} maps <tool_call></tool_call>, the token MUST appear in pair, as 151657 ->xxx -> 151658, otherwise, the generation will be stopped.
chat_format string No "" Jinja2 chat template for formatting messages (see Jinja2 Templates) or Path to tokenizer_config.json
chat_template_kwargs dict No {} Extra parameters passed to chat templates

Jinja2 Chat Templates

The chat_format field uses Jinja2 syntax or tokenizer config to define how messages are formatted into the model's native prompt structure.

  1. Prepare the model tokenizer_config.json
  2. For Qwen series, it is possible to put the Jinja template string directly
  3. For other series, put the path to tokenizer_config.json

Backend values:

  • "adla" — Amlogic ADLA runtime (AARCH64 only)

Running the Server

# Default: reads config/server.yaml
uv run python -m amlllm_openai_server

# Custom config path
uv run python -m amlllm_openai_server --config /path/to/server.yaml

# Override host/port/log-level
uv run python -m amlllm_openai_server --host 0.0.0.0 --port 8000 --log-level debug

Test the endpoint:

curl http://localhost:8000/v1/models
curl http://localhost:8000/healthz

If you want to install PicoClaw

dpkg -i picoclaw_modified_aarch64.deb

Run demo with PicoClaw

  1. Start the AMLLLM server (see above)
  2. Start PicoClaw:
    picoclaw-launcher &
    
  3. Configure PicoClaw model:
    • Provider: openai
    • Model identifier: amlogic-default
    • API Base URL: http://localhost:8000/v1

Tips: The agent work folder is under $HOME/.picoclaw/workspace. If you are using local models with context limitations, it's better to remove AGENTS.md and SOUL.md.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

amlllm_openai_server-0.1.1-cp313-cp313-manylinux_2_34_x86_64.whl (12.5 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.34+ x86-64

amlllm_openai_server-0.1.1-cp313-cp313-manylinux_2_34_aarch64.whl (3.2 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.34+ ARM64

amlllm_openai_server-0.1.1-cp312-cp312-manylinux_2_34_x86_64.whl (12.6 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.34+ x86-64

amlllm_openai_server-0.1.1-cp312-cp312-manylinux_2_34_aarch64.whl (3.2 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.34+ ARM64

amlllm_openai_server-0.1.1-cp311-cp311-manylinux_2_34_x86_64.whl (12.6 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.34+ x86-64

amlllm_openai_server-0.1.1-cp311-cp311-manylinux_2_34_aarch64.whl (2.9 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.34+ ARM64

amlllm_openai_server-0.1.1-cp310-cp310-manylinux_2_34_x86_64.whl (12.0 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.34+ x86-64

File details

Details for the file amlllm_openai_server-0.1.1-cp313-cp313-manylinux_2_34_x86_64.whl.

File metadata

  • Download URL: amlllm_openai_server-0.1.1-cp313-cp313-manylinux_2_34_x86_64.whl
  • Upload date:
  • Size: 12.5 MB
  • Tags: CPython 3.13, manylinux: glibc 2.34+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for amlllm_openai_server-0.1.1-cp313-cp313-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 7c7dea9d2f1a3b8c8362c4783cfc5eac6c168f3fb6e9a3e8dc9ff95f32240c02
MD5 e8e08de8e65e0d15adc1ac326a9bac1a
BLAKE2b-256 1aa75d899c0b04c1e85c4b5ceb9e1a8727cab59a11c58049512782847d0a51a0

See more details on using hashes here.

File details

Details for the file amlllm_openai_server-0.1.1-cp313-cp313-manylinux_2_34_aarch64.whl.

File metadata

  • Download URL: amlllm_openai_server-0.1.1-cp313-cp313-manylinux_2_34_aarch64.whl
  • Upload date:
  • Size: 3.2 MB
  • Tags: CPython 3.13, manylinux: glibc 2.34+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for amlllm_openai_server-0.1.1-cp313-cp313-manylinux_2_34_aarch64.whl
Algorithm Hash digest
SHA256 7143d89d05964b00f8f851fae9913ba3fe071d81a290a8e113ff5bd67e25b95f
MD5 8b1776c59c0ebe348659c427359d56a5
BLAKE2b-256 9541e3898d2df86f5c733c05e8e3f60735992c3b4945b5ba393605af8535f9c0

See more details on using hashes here.

File details

Details for the file amlllm_openai_server-0.1.1-cp312-cp312-manylinux_2_34_x86_64.whl.

File metadata

  • Download URL: amlllm_openai_server-0.1.1-cp312-cp312-manylinux_2_34_x86_64.whl
  • Upload date:
  • Size: 12.6 MB
  • Tags: CPython 3.12, manylinux: glibc 2.34+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for amlllm_openai_server-0.1.1-cp312-cp312-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 94ffd6b24d7a922a8d512e4005c366bdae56bd68a6ae4c95a1cc8ebf5b1b0be2
MD5 9e6d113fefad09ebfb0ccbcc1e8e0e22
BLAKE2b-256 e48365b7b1c522965fa70842f2c2decf27deb8a830f96356e11b940d03241094

See more details on using hashes here.

File details

Details for the file amlllm_openai_server-0.1.1-cp312-cp312-manylinux_2_34_aarch64.whl.

File metadata

  • Download URL: amlllm_openai_server-0.1.1-cp312-cp312-manylinux_2_34_aarch64.whl
  • Upload date:
  • Size: 3.2 MB
  • Tags: CPython 3.12, manylinux: glibc 2.34+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for amlllm_openai_server-0.1.1-cp312-cp312-manylinux_2_34_aarch64.whl
Algorithm Hash digest
SHA256 987c0c4c86f74707742dea9f3fe23bbeaa05b9605b54af78230ce7dc83c2ee60
MD5 056712c499c1c1ccaf739756818d6bb6
BLAKE2b-256 26cb06aebc49e9c14eccd1a7e55b8d7020fb779a75f3a4427cd81dde4e029210

See more details on using hashes here.

File details

Details for the file amlllm_openai_server-0.1.1-cp311-cp311-manylinux_2_34_x86_64.whl.

File metadata

  • Download URL: amlllm_openai_server-0.1.1-cp311-cp311-manylinux_2_34_x86_64.whl
  • Upload date:
  • Size: 12.6 MB
  • Tags: CPython 3.11, manylinux: glibc 2.34+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for amlllm_openai_server-0.1.1-cp311-cp311-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 85b51ac9c6180f06301b9059b774b531aa0f854f62ed7888e9b27310d1090251
MD5 a5a474430e9101d28e658aa99b707e3b
BLAKE2b-256 8b46731feb8cb126d57a7920ad85fa4f430b44e36b04bc34615d96fdb12ec54a

See more details on using hashes here.

File details

Details for the file amlllm_openai_server-0.1.1-cp311-cp311-manylinux_2_34_aarch64.whl.

File metadata

  • Download URL: amlllm_openai_server-0.1.1-cp311-cp311-manylinux_2_34_aarch64.whl
  • Upload date:
  • Size: 2.9 MB
  • Tags: CPython 3.11, manylinux: glibc 2.34+ ARM64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for amlllm_openai_server-0.1.1-cp311-cp311-manylinux_2_34_aarch64.whl
Algorithm Hash digest
SHA256 68c4081338725676db623d53b4cfdbf16c1c7a6c3419aa64e9309e682ad326a0
MD5 9f0ea7fc0b05e0257cdb4d907655ccf7
BLAKE2b-256 c83f423ad3b41c83875691855af37c1cb187b5e25ac3a9798ae4b04a8dcadfa5

See more details on using hashes here.

File details

Details for the file amlllm_openai_server-0.1.1-cp310-cp310-manylinux_2_34_x86_64.whl.

File metadata

  • Download URL: amlllm_openai_server-0.1.1-cp310-cp310-manylinux_2_34_x86_64.whl
  • Upload date:
  • Size: 12.0 MB
  • Tags: CPython 3.10, manylinux: glibc 2.34+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for amlllm_openai_server-0.1.1-cp310-cp310-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 fec81faab1315ab401f7b8e2f5be28eaa4620f0b8c3e854e73011c8e29973454
MD5 9faf7ae8743ec798cfdf14d513dc57fd
BLAKE2b-256 933879717c9bd82a27e0051e9d1f86fbb8920b45fbaa41674fd21e35a9c3f458

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page