Qwen3.5 llama-cpp tool calling fails when function has "strict": true
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 3-5 ngày
- Mức phù hợp với người mới
- 52/100
- Loại issue
- Lỗi
- Độ rõ ràng
- Đặc tả rõ ràng
- Mức độ hoạt động
- Sôi nổi
- Công nghệ
- go
- Lĩnh vực
- api, backend-api-design
Hướng nghiên cứu
Bắt đầu tại entry point /v1/chat/completions và theo dõi cách backend llama-cpp xử lý function tools khi có và không có strict: true. Tái hiện hai request từ issue bằng model qwen3.5-9b-glm5.1-distill-v1, sau đó xác minh rằng request strict trả về một tool call thay vì response rỗng và vòng lặp retry.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
LocalAI version:
LocalAI version: v4.9.0
Commit:
f7ad3f70eb5d8a0ddf80e08557f0d7df28cf032e
Container image:
localai/localai:latest-gpu-nvidia-cuda-12
LocalAI is running as a Kubernetes deployment.
Environment, CPU architecture, OS, and Version:
LocalAI is running in Kubernetes.
Uname:
Linux k8scp 5.14.0-611.47.1.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Apr 8 12:18:23 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
Model:
qwen3.5-9b-glm5.1-distill-v1
Model file:
Qwen3.5-9B-GLM5.1-Distill-v1-Q4_K_M.gguf
Backend:
llama-cpp
Effective runtime settings reported by LocalAI:
context=2048
n_batch=512
n_gpu_layers=0
parallel="1"
flash_attention="auto"
f16=false
The model is therefore running CPU-only for this reproduction
(n_gpu_layers=0).
CPU is an Intel Core i7-3770 @ 3.40 GHz.
Client testing was performed using the OpenAI-compatible
/v1/chat/completions endpoint.
The issue was originally discovered using OpenAI Agents Python SDK
0.22.0, but it can be reproduced independently of the Agents SDK
using a normal OpenAI-compatible Chat Completions request.
Describe the bug
OpenAI-compatible function/tool calling works with the
qwen3.5-9b-glm5.1-distill-v1 model using the llama-cpp backend, but
adding:
"strict": true
to the function definition causes tool calling to fail.
Without strict: true, the model correctly returns:
finish_reason: tool_calls
tool_calls: transfer_to_customer_retention_agent
With strict: true, the same request instead returns:
finish_reason: stop
content: ''
tool_calls: None
reasoning: None
LocalAI returns HTTP 200 in both cases.
The LocalAI logs show repeated:
Backend returned empty response, retrying
for the failing request.
This was initially noticed because OpenAI Agents SDK handoffs are
represented as strict function tools, which prevents native Agents SDK
handoffs from working with this LocalAI/model combination.
The issue can, however, be reproduced without using the Agents SDK.
To Reproduce
Use the following model:
qwen3.5-9b-glm5.1-distill-v1
with the llama-cpp backend.
1. Tool without strict: true - works
Send:
curl http://<LOCALAI_HOST>:8080/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "qwen3.5-9b-glm5.1-distill-v1",
"messages": [
{
"role": "system",
"content": "You are a customer service agent. If the customer wants to close or cancel their account, you must call transfer_to_customer_retention_agent."
},
{
"role": "user",
"content": "I want to cancel my order and account. You delayed my order for the 3rd time!"
}
],
"tools": [
{
"type": "function",
"function": {
"name": "transfer_to_customer_retention_agent",
"description": "Transfer the conversation to the customer retention specialist.",
"parameters": {
"type": "object",
"properties": {},
"required": [],
"additionalProperties": false
}
}
}
],
"tool_choice": "auto",
"max_tokens": 1500,
"reasoning_effort": "none"
}'
This correctly results in an OpenAI-compatible tool call.
Using the OpenAI Python client, the relevant response is:
finish_reason: tool_calls
content: ''
tool_calls:
[
ChatCompletionMessageFunctionToolCall(
function=Function(
arguments='{}',
name='transfer_to_customer_retention_agent'
),
type='function'
)
]
2. Add only strict: true - fails
Repeat the same request but change the function definition to:
{
"type": "function",
"function": {
"name": "transfer_to_customer_retention_agent",
"description": "Transfer the conversation to the customer retention specialist.",
"parameters": {
"type": "object",
"properties": {},
"required": [],
"additionalProperties": false
},
"strict": true
}
}
The resulting response using the OpenAI Python client is:
ChatCompletion(
choices=[
Choice(
finish_reason='stop',
message=ChatCompletionMessage(
content='',
role='assistant',
function_call=None,
tool_calls=None
)
)
]
)
finish_reason: stop
content: ''
tool_calls: None
reasoning: None
Usage for one of the failing requests:
completion_tokens=19
prompt_tokens=63
total_tokens=82
Therefore the significant A/B difference appears to be:
Tool without "strict": true
|
+--> finish_reason = tool_calls
tool call generated successfully
Tool with "strict": true
|
+--> finish_reason = stop
content = ""
tool_calls = None
Expected behavior
Adding:
"strict": true
to an otherwise working OpenAI-compatible function definition should
not prevent the model from making the tool call.
I would expect a response equivalent to:
{
"finish_reason": "tool_calls",
"message": {
"tool_calls": [
{
"type": "function",
"function": {
"name": "transfer_to_customer_retention_agent",
"arguments": "{}"
}
}
]
}
}
The function arguments in this example already conform to the supplied
JSON schema.
Logs
LocalAI starts the model with:
INFO BackendLoader starting
modelID="qwen3.5-9b-glm5.1-distill-v1"
backend="llama-cpp"
model="llama-cpp/models/qwen3.5-9b-glm5.1-distill-v1/Qwen3.5-9B-GLM5.1-Distill-v1-Q4_K_M.gguf"
The effective runtime configuration is:
context=2048
n_batch=512
n_gpu_layers=0
parallel="1"
flash_attention="auto"
f16=false
During failing requests LocalAI repeatedly reports:
WARN Backend returned empty response, retrying attempt=1 maxRetries=5
WARN Backend returned empty response, retrying attempt=2 maxRetries=5
WARN Backend returned empty response, retrying attempt=3 maxRetries=5
WARN Backend returned empty response, retrying attempt=4 maxRetries=5
WARN Backend returned empty response, retrying attempt=5 maxRetries=5
WARN Backend produced reasoning without actionable content, retrying reasoning_len=0 attempt=6
The HTTP request nevertheless completes with:
POST /v1/chat/completions status=200
LocalAI version from the startup log:
INFO Using forced capability from environment variable
capability="nvidia"
env="LOCALAI_FORCE_META_BACKEND_CAPABILITY"
INFO LocalAI version
version="v4.9.0 (f7ad3f70eb5d8a0ddf80e08557f0d7df28cf032e)"
Additional context
The problem was originally discovered while testing LocalAI with the
OpenAI Agents Python SDK version 0.22.0.
An Agents SDK handoff is exposed to the model as a function tool similar
to:
Tool name:
transfer_to_customer_retention_agent
Schema:
{
"additionalProperties": false,
"type": "object",
"properties": {},
"required": []
}
Strict:
True
When this is sent through LocalAI, the Agents SDK receives an empty
model output and therefore cannot perform the handoff:
ModelResponse(
output=[],
usage=Usage(
requests=1,
input_tokens=100,
output_tokens=23,
total_tokens=123
)
)
As a workaround I replaced the native handoff with an ordinary Agents
SDK function tool declared with:
@function_tool(strict_mode=False)
def request_handoff(target_agent: str, reason: str) -> str:
...
The same Qwen model then successfully determines that a handoff is
required and calls the tool:
[TOOL] request_handoff called
[TOOL] target_agent = Customer Retention Agent
[TOOL] reason = Customer wants to cancel their order and account after experiencing repeated order delays.
Python can then perform the actual agent transfer.
This suggests that the model is capable of the required tool selection
and function call, and that the failure is specifically associated with
the strict: true tool definition.
Summary of observed behaviour:
| Test | Result |
|---|---|
| Normal chat completion | Works |
Function tool without strict |
Works |
Function tool with "strict": true |
Fails with empty response |
| OpenAI Agents SDK native handoff | Fails |
Agents SDK strict_mode=False function tool |
Works |
- Ngôn ngữ chính
- Go
- Star
- 49.8k
- Fork
- 4.5k
- Merge trung bình
- 19 giờ 42 phút
- Pull request đã merge (30 ngày)
- 354
Chuẩn bị môi trường
Khởi chạy dev container của dự án ngay trên trình duyệt, bằng tài khoản GitHub của bạn.
- Có Dockerfile hoặc tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của mudler/LocalAI
-
[Bug] Qwen3.8-27b Uncensored Fails to Download due to 404Có thể làm lại được Pull request cho issue này đã bị đóng mà không được merge. Đang mởbug unconfirmed
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 70/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Realtime: ASR EOU language tags leak into the LLM conversation (unintended reply-language switching)Có thể đã có người làm @nexxtmobile đã nhận 9 ngày trước. Đang mởarea/api bug unconfirmed
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Open Responses API doesn't accept "output_text" as an input ItemCó thể đã có người làm @localai-org-maint-bot đã nhận 28 ngày trước. Đang mởbug unconfirmed
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
mudler/LocalAI#12337 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Gallery model audio-cpp-sortformer-diarization fails to install: SHA mismatch, reproducible across retriesCó thể làm lại được Pull request cho issue này đã bị đóng mà không được merge. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 76/100
mudler/LocalAI#11995 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Agent pool Postgres DSN is logged in cleartext, including the password, while the auth DSN is redactedCó thể đã có người làm @localai-org-maint-bot đã nhận 44 ngày trước. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 75/100
mudler/LocalAI#11991 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của mudler/LocalAI
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
area/docs theme/deployer
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 74/100
Maintainer thường phản hồi trong vòng 1 ngày
-
area/orchestration area/website kind/bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
vllm-project/aibrix#3317 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
documentation ready
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 88/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Needs Triage
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 90/100