ai-forever / ai-forever/langchain-gigachat
[Bug]: `with_structured_output` returns only first element of `list[str]` field
- Ngôn ngữ chính
- Python
- Star
- 50
- Fork
- 13
- Chỉ số merge pull request
- Không có pull request nào được merge trong 30 ngày
Mô tả
### Description
When using `GigaChat.with_structured_output()` with a Pydantic model that contains a `list[str]` field, the model consistently returns only the **first element** of the array, even when the prompt explicitly requests multiple items.
The same request sent via plain `client.invoke()` (without function calling) returns the full list correctly.
The issue is **not** related to the schema stripping bug from [#55](https://github.com/ai-forever/langchain-gigachat/issues/55) (fixed in `0.5.0`). The generated JSON schema is correct and contains `type: array` with `items: {type: string}`. Despite the valid schema, the GigaChat model fills the array with only the first element when responding via function calling. This can be confirmed by inspecting `result["raw"].additional_kwargs["function_call"]["arguments"]` — the truncated array is already present there, before any LangChain parsing.
### Steps to Reproduce
1. Define a Pydantic model with a `list[str]` field
2. Call `client.with_structured_output(MyModel)`
3. Invoke with a prompt that should produce multiple items
4. Observe that only the first element is returned
### Expected Behavior
```python
items = ["один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять", "десять"]
```
### Actual Behavior
```shell
{
"name": "NumberList",
"description": "List of numbers from one to ten",
"parameters": {
"type": "object",
"properties": {
"items": {
"type": "array",
"items": { "type": "string" },
"description": "List of strings"
}
}
}
}
But `function_call.arguments` returned by the model contains only one element:
{
"name": "NumberList",
"arguments": {
"items": ["один"]
}
}
Final parsed result:
items = ["один"] # 1 element instead of 10
Plain `invoke` with the same prompt returns the full list correctly:
items = ["один", "два", "три", "четыре", "пять", "шесть", "семь", "восемь", "девять", "десять"]
```
### Code Example
```python
from __future__ import annotations
import json
from langchain_core.messages import AIMessage, HumanMessage
from langchain_gigachat import GigaChat
from langchain_gigachat.utils.function_calling import convert_to_gigachat_function
from pydantic import BaseModel, Field
class NumberList(BaseModel):
"""List of numbers from one to ten"""
items: list[str] = Field(description="List of strings")
# Print the function schema that gets sent to the API
print(json.dumps(convert_to_gigachat_function(NumberList), ensure_ascii=False, indent=2))
client = GigaChat(
base_url="...", # your endpoint
verify_ssl_certs=False,
profanity_check=False,
)
PROMPT = "Write all numbers from one to ten as words. Return JSON with key 'items'. Only JSON."
# Method A: with_structured_output — BROKEN
structured_llm = client.with_structured_output(NumberList, include_raw=True)
result_A = structured_llm.invoke(PROMPT)
raw: AIMessage = result_A["raw"]
print("function_call.arguments:", raw.additional_kwargs.get("function_call"))
print("tool_calls:", raw.tool_calls)
print(f"Method A items ({len(result_A['parsed'].items)}): {result_A['parsed'].items}")
# Method B: plain invoke — WORKS
response_B = client.invoke([HumanMessage(content=PROMPT)])
data_B = json.loads(response_B.content.strip())
print(f"Method B items ({len(data_B['items'])}): {data_B['items']}")
```
### langchain-gigachat Version
0.5.0
### Python Version
3.13
### Operating System
Linux
### Environment Details
| Package | Version |
|---|---|
| `langchain-gigachat` | `0.5.0` |
| `gigachat` | `0.2.0` |
| `langchain-core` | `1.3.0` |
| `pydantic` | `2.12.5` |
| Model | `GigaChat-2-Max`, `GigaChat-2-Max-Preview` , `GigaChat-2-Lite`, `GigaChat-2-Pro` |
### Additional Context
## Additional Context
- Both `GigaChat-2-Max` and `GigaChat-2-Max-Preview` exhibit the same behavior.
- The issue reproduces with any `list[str]` field regardless of field name or description.
- Workaround: use plain `client.invoke()` and parse JSON manually from `response.content`.
- Previously worked with an older code version that used plain invoke. The regression was introduced when the codebase switched to `with_structured_output`.
### Pre-submission Checklist
- [x] I have searched existing issues to ensure this is not a duplicate
- [x] I have provided all requested information above
- [x] I am using a supported Python version (3.10–3.13). (CI also runs 3.14 as experimental.)
Hướng dẫn đóng góp
Đánh giá
Issue này chưa được đánh giá.