初始化项目,由ModelHub XC社区提供模型
Model: TuwaiqAcademy/AISA-AR-FunctionCall-Think Source: Original Platform
This commit is contained in:
36
.gitattributes
vendored
Normal file
36
.gitattributes
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
*.7z filter=lfs diff=lfs merge=lfs -text
|
||||
*.arrow filter=lfs diff=lfs merge=lfs -text
|
||||
*.bin filter=lfs diff=lfs merge=lfs -text
|
||||
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
||||
*.ftz filter=lfs diff=lfs merge=lfs -text
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
*.h5 filter=lfs diff=lfs merge=lfs -text
|
||||
*.joblib filter=lfs diff=lfs merge=lfs -text
|
||||
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
||||
*.model filter=lfs diff=lfs merge=lfs -text
|
||||
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
||||
*.npy filter=lfs diff=lfs merge=lfs -text
|
||||
*.npz filter=lfs diff=lfs merge=lfs -text
|
||||
*.onnx filter=lfs diff=lfs merge=lfs -text
|
||||
*.ot filter=lfs diff=lfs merge=lfs -text
|
||||
*.parquet filter=lfs diff=lfs merge=lfs -text
|
||||
*.pb filter=lfs diff=lfs merge=lfs -text
|
||||
*.pickle filter=lfs diff=lfs merge=lfs -text
|
||||
*.pkl filter=lfs diff=lfs merge=lfs -text
|
||||
*.pt filter=lfs diff=lfs merge=lfs -text
|
||||
*.pth filter=lfs diff=lfs merge=lfs -text
|
||||
*.rar filter=lfs diff=lfs merge=lfs -text
|
||||
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
||||
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar filter=lfs diff=lfs merge=lfs -text
|
||||
*.tflite filter=lfs diff=lfs merge=lfs -text
|
||||
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||
*.wasm filter=lfs diff=lfs merge=lfs -text
|
||||
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
||||
*.zst filter=lfs diff=lfs merge=lfs -text
|
||||
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
||||
tokenizer.json filter=lfs diff=lfs merge=lfs -text
|
||||
251
README.md
Normal file
251
README.md
Normal file
@@ -0,0 +1,251 @@
|
||||
---
|
||||
license: gemma
|
||||
language:
|
||||
- ar
|
||||
base_model:
|
||||
- google/gemma-3-270m
|
||||
pipeline_tag: text-generation
|
||||
library_name: transformers
|
||||
tags:
|
||||
- function-calling
|
||||
- tool-use
|
||||
- agentic
|
||||
- arabic
|
||||
- reasoning
|
||||
- think
|
||||
- gemma3
|
||||
- shared-task
|
||||
- arabicnlp2026
|
||||
- baseline
|
||||
- dialect
|
||||
datasets:
|
||||
- TuwaiqAcademy/AISA-ArabicFC
|
||||
model-index:
|
||||
- name: AISA-AR-FunctionCall-Think
|
||||
results:
|
||||
- task:
|
||||
type: text-generation
|
||||
name: Arabic Function Calling — Track B (Reasoning-Augmented)
|
||||
dataset:
|
||||
name: AISA-ArabicFC (held-out test)
|
||||
type: TuwaiqAcademy/AISA-ArabicFC
|
||||
metrics:
|
||||
- type: function-name-accuracy
|
||||
value: 0.982
|
||||
name: FnAcc
|
||||
- type: argument-exact-match
|
||||
value: 0.541
|
||||
name: ArgEM
|
||||
- type: think-before-call-rate
|
||||
value: 0.868
|
||||
name: ThinkRate
|
||||
- type: overall
|
||||
value: 0.739
|
||||
name: Overall (Track B, v2)
|
||||
---
|
||||
|
||||
# AISA-AR-FunctionCall-Think
|
||||
|
||||
### 🏷️ Official **Track B baseline** for the [AISA-ArabicFC shared task](https://huggingface.co/spaces/Omartificial-Intelligence-Space/AISA-ArabicFC-Shared-Task) @ **ArabicNLP 2026** (co-located with EMNLP 2026, Budapest)
|
||||
|
||||
> This model is the **organizer-provided baseline** for **Track B — Reasoning-Augmented Function Calling**. It defines the reference score that participating systems are expected to beat. It is released for reproducibility and as a starting point — **it is not a competition entry.**
|
||||
|
||||
A compact (**270M-parameter**) Arabic function-calling model that, given an Arabic user query (in any of 5 dialects) and a set of candidate tools, **writes a short Arabic `<think>` reasoning trace and then emits a structured tool call**. Fine-tuned (LoRA) from **[google/gemma-3-270m](https://huggingface.co/google/gemma-3-270m)** on the AISA-ArabicFC reasoning data.
|
||||
|
||||
For the non-reasoning Track A baseline, see the sibling model **[AISA-AR-FunctionCall-FT](https://huggingface.co/AISA-Framework/AISA-AR-FunctionCall-FT)**.
|
||||
|
||||
---
|
||||
|
||||
## At a glance
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **Role** | Official baseline — Track B (Reasoning-Augmented) |
|
||||
| **Base model** | google/gemma-3-270m (270M params) |
|
||||
| **Adaptation** | LoRA fine-tune (merged), then full causal-LM inference |
|
||||
| **Languages** | Arabic — MSA, Gulf, Egyptian, Levantine, Maghrebi |
|
||||
| **Behaviour** | `<think>` Arabic reasoning → structured function call |
|
||||
| **Training data** | [TuwaiqAcademy/AISA-ArabicFC](https://huggingface.co/datasets/TuwaiqAcademy/AISA-ArabicFC)
|
||||
| **License** | Gemma (see *License* below) |
|
||||
|
||||
---
|
||||
|
||||
## The shared task
|
||||
|
||||
Given an Arabic user query and a set of candidate tool definitions, a system must:
|
||||
|
||||
1. **Decide** whether a function call is required (some queries need no tool),
|
||||
2. **Select** the correct function name,
|
||||
3. **Extract** the structured arguments,
|
||||
4. **(Track B)** **Generate an Arabic reasoning trace** (`<think> … </think>`) *before* the call.
|
||||
|
||||
| Track | Description |
|
||||
|-------|-------------|
|
||||
| **A — Core** | Decide / Select / Extract |
|
||||
| **B — Reasoning-Augmented** ← *this model* | Track A **+** an Arabic `<think>` reasoning trace |
|
||||
| **C — Cross-Dialect Robustness** | Diagnostic: dialect-stratified evaluation of A/B submissions |
|
||||
|
||||
---
|
||||
|
||||
## How it works — input / output format
|
||||
|
||||
This model uses **Gemma 3 chat turns** with a custom function-calling schema (it does **not** emit plain JSON). The exact prompt is the `text` field in the dataset; the structure is:
|
||||
|
||||
```
|
||||
<bos><start_of_turn>developer
|
||||
<system instruction in Arabic>
|
||||
<start_function_declaration>declaration:NAME{description:<escape>…<escape>,parameters:{…}}<end_function_declaration>
|
||||
…one declaration per candidate tool…<end_of_turn>
|
||||
<start_of_turn>developer
|
||||
التاريخ والوقت الحالي …: 2024-04-12T23:05:24
|
||||
اليوم هو الجمعة
|
||||
أنت نموذج يمكنه استدعاء الوظائف التالية<end_of_turn>
|
||||
<start_of_turn>user
|
||||
أريد مقارنة أسعار تلفاز سامسونج في الأردن<end_of_turn>
|
||||
<start_of_turn>model
|
||||
```
|
||||
|
||||
The model then generates:
|
||||
|
||||
```
|
||||
<think>
|
||||
يبدو أن نية المستخدم هي الحصول على مقارنة لأسعار تلفاز سامسونج في الأردن. أداة "compare_prices" هي الأنسب …
|
||||
</think>
|
||||
<start_function_call>call:compare_prices{country:<escape>Jordan<escape>,product_name:<escape>Samsung TV<escape>}<end_function_call>
|
||||
```
|
||||
|
||||
For a query that needs **no tool**, the model omits the `<start_function_call>` block (→ `requires_function = false`).
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```python
|
||||
import re, torch
|
||||
from transformers import AutoTokenizer, AutoModelForCausalLM
|
||||
|
||||
MODEL_ID = "TuwaiqAcademy/AISA-AR-FunctionCall-Think"
|
||||
tok = AutoTokenizer.from_pretrained(MODEL_ID)
|
||||
model = AutoModelForCausalLM.from_pretrained(
|
||||
MODEL_ID, torch_dtype=torch.float32, device_map="auto"
|
||||
).eval()
|
||||
|
||||
def parse_model_output(text: str) -> dict:
|
||||
"""Turn raw generation into the shared-task submission schema."""
|
||||
out = {"requires_function": False, "function_name": "none", "arguments": {}, "think": ""}
|
||||
if (m := re.search(r"<think>\s*(.*?)\s*</think>", text, re.DOTALL)):
|
||||
out["think"] = m.group(1).strip()
|
||||
if (m := re.search(r"<start_function_call>\s*call:(\w+)\{(.*?)\}\s*<end_function_call>", text, re.DOTALL)):
|
||||
out["requires_function"] = True
|
||||
out["function_name"] = m.group(1)
|
||||
for key, str_val, num_val in re.findall(r"(\w+):(?:<escape>(.*?)<escape>|([^,}]+))", m.group(2)):
|
||||
val = str_val if str_val else num_val
|
||||
try:
|
||||
val = float(val) if "." in str(val) else int(val)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
out["arguments"][key] = val
|
||||
return out
|
||||
|
||||
# Easiest path: take the ready-made prompt from the dataset's `text` field and
|
||||
# cut it at the model turn (everything after is what the model should produce).
|
||||
from datasets import load_dataset
|
||||
row = load_dataset("TuwaiqAcademy/AISA-ArabicFC", split="validation")[0]
|
||||
prompt = row["text"].split("<start_of_turn>model\n")[0] + "<start_of_turn>model\n"
|
||||
|
||||
inputs = tok(prompt, return_tensors="pt", add_special_tokens=False).to(model.device)
|
||||
with torch.no_grad():
|
||||
gen = model.generate(**inputs, max_new_tokens=250, do_sample=False) # greedy
|
||||
raw = tok.decode(gen[0][inputs["input_ids"].shape[1]:], skip_special_tokens=False)
|
||||
|
||||
print(parse_model_output(raw))
|
||||
# → {'requires_function': True, 'function_name': 'compare_prices',
|
||||
# 'arguments': {'country': 'Jordan', 'product_name': 'Samsung TV'},
|
||||
# 'think': 'يبدو أن نية المستخدم …'}
|
||||
```
|
||||
|
||||
The parsed dict maps directly onto a **leaderboard submission line**: `{"id", "tool_called", "arguments", "think"}` (use `function_name` → `tool_called`).
|
||||
|
||||
---
|
||||
|
||||
## Evaluation
|
||||
|
||||
Scored on the AISA-ArabicFC **held-out test set** (1,000 positive + negative examples) using the official **v2** metrics:
|
||||
|
||||
- **FnAcc** — function-name accuracy over *all* samples (also penalises hallucinated / missed calls; negatives have gold `none`)
|
||||
- **ArgEM** — strict argument **exact match**, over positives only
|
||||
- **ThinkRate** — fraction of outputs with a non-empty `<think>` trace
|
||||
- **Overall (Track A)** = `0.40·FnAcc + 0.60·ArgEM`
|
||||
- **Overall (Track B)** = `0.30·FnAcc + 0.50·ArgEM + 0.20·ThinkRate`
|
||||
|
||||
### Baseline results
|
||||
|
||||
| System | FnAcc | ArgEM | Overall (A) | Overall (B) |
|
||||
|--------|:-----:|:-----:|:-----------:|:-----------:|
|
||||
| **AISA-AR-FunctionCall-Think (270M) ← this** | **0.982** | **0.541** | **0.717** | **0.739** |
|
||||
| GPT-4o — zero-shot | 0.927 | 0.070 | 0.413 | 0.313 |
|
||||
| GPT-4o — 3-shot | 0.854 | 0.122 | 0.415 | 0.317 |
|
||||
| Random baseline | 0.047 | 0.033 | 0.039 | 0.031 |
|
||||
|
||||
- **Think-Before-Call rate (ThinkRate):** **0.868** for this model; 0.000 for all non-reasoning baselines.
|
||||
- **Hallucination rate:** **0.000** on negative (no-tool) queries.
|
||||
|
||||
**Key takeaways**
|
||||
|
||||
- 🎯 **Argument extraction is the open challenge.** Tool *selection* is largely solved (FnAcc ≈ 0.98), but strict argument **exact match tops out at 0.541** — and GPT-4o reaches only 0.070 zero-shot. This is where the task is won or lost.
|
||||
- 🪶 **A 270M model beats GPT-4o** across every metric here, showing the value of task-specific Arabic training and lowering the compute barrier to entry.
|
||||
- 🗣️ **Cross-dialect gaps remain.** FnAcc varies by roughly 10–15 points across dialects, with **Gulf and Levantine** consistently the hardest and Maghrebi (small sample) the easiest — see the Track C diagnostic in the task overview paper.
|
||||
|
||||
---
|
||||
|
||||
## Training
|
||||
|
||||
- **Base:** `google/gemma-3-270m`
|
||||
- **Method:** LoRA (rank 64), 3 epochs, cosine LR scheduler
|
||||
- **Data:** AISA-ArabicFC training split (~10.5K examples) with 12,000 Arabic reasoning annotations for the `<think>` traces
|
||||
- **Objective:** produce a short Arabic reasoning trace followed by a single structured tool call (or no call for negatives)
|
||||
|
||||
---
|
||||
|
||||
## Intended use & limitations
|
||||
|
||||
**Intended use**
|
||||
- A reference **baseline** to compare against and reproduce for the AISA-ArabicFC shared task.
|
||||
- A lightweight starting point for Arabic tool-use / agentic experiments.
|
||||
|
||||
**Out of scope / limitations**
|
||||
- Trained for the **27-tool, 8-domain AISA-ArabicFC schema** and its prompt format; behaviour on arbitrary tools or free-form chat is undefined.
|
||||
- Single-turn, single-call setting — no multi-tool or multi-turn dialogue.
|
||||
- **Argument extraction is imperfect** (ArgEM 0.541): expect errors in date normalisation, numeric typing, and dialectal argument phrasing.
|
||||
- Uneven dialect coverage (Maghrebi is only ~1.3% of data); robustness varies by dialect.
|
||||
- A 270M model — capacity-limited by design to keep the baseline accessible.
|
||||
|
||||
---
|
||||
|
||||
## Related resources
|
||||
|
||||
- 🏆 **Shared task page:** https://huggingface.co/spaces/Omartificial-Intelligence-Space/AISA-ArabicFC-Shared-Task
|
||||
- 📊 **Leaderboard:** https://huggingface.co/spaces/TuwaiqAcademy/AISA-ArabicFC-SharedTask-Leaderboard
|
||||
- 📚 **Dataset (train + dev):** [TuwaiqAcademy/AISA-ArabicFC](https://huggingface.co/datasets/TuwaiqAcademy/AISA-ArabicFC)
|
||||
|
||||
---
|
||||
|
||||
## Citation
|
||||
|
||||
```bibtex
|
||||
@inproceedings{najar2026aisaarabicfc,
|
||||
title = {AISA-ArabicFC: Arabic Function Calling for Agentic AI Systems},
|
||||
author = {Najar, Omar},
|
||||
booktitle = {Proceedings of the Fourth Arabic Natural Language Processing Conference (ArabicNLP 2026)},
|
||||
year = {2026}
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This model is a derivative of **Gemma 3** and is distributed under the **[Gemma Terms of Use](https://ai.google.dev/gemma/terms)**. By using it you agree to those terms and to the [Gemma Prohibited Use Policy](https://ai.google.dev/gemma/prohibited_use_policy). The AISA-ArabicFC **dataset** is released separately under Apache-2.0.
|
||||
|
||||
## Contact
|
||||
|
||||
Shared-task organizers — **trdc@tuwaiq.edu.sa** · Tuwaiq Academy
|
||||
```
|
||||
4
added_tokens.json
Normal file
4
added_tokens.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"<end_of_image>": 262145,
|
||||
"<image_soft_token>": 262144
|
||||
}
|
||||
282
chat_template.jinja
Normal file
282
chat_template.jinja
Normal file
@@ -0,0 +1,282 @@
|
||||
{%- macro format_parameters(properties, required) -%}
|
||||
{%- set standard_keys = ['description', 'type', 'properties', 'required', 'nullable'] -%}
|
||||
{%- set ns = namespace(found_first=false) -%}
|
||||
{%- for key, value in properties | dictsort -%}
|
||||
{%- if key not in standard_keys -%}
|
||||
{%- if ns.found_first %},{% endif -%}
|
||||
{%- set ns.found_first = true -%}
|
||||
{{- key }}:{description:<escape>{{ value['description'] }}<escape>
|
||||
{%- if value['type'] | upper == 'STRING' -%}
|
||||
{%- if value['enum'] -%}
|
||||
,enum:{{ format_argument(value['enum']) }}
|
||||
{%- endif -%}
|
||||
{%- elif value['type'] | upper == 'OBJECT' -%}
|
||||
,properties:{
|
||||
{%- if value['properties'] is defined and value['properties'] is mapping -%}
|
||||
{{- format_parameters(value['properties'], value['required'] | default([])) -}}
|
||||
{%- elif value is mapping -%}
|
||||
{{- format_parameters(value, value['required'] | default([])) -}}
|
||||
{%- endif -%}
|
||||
}
|
||||
{%- if value['required'] -%}
|
||||
,required:[
|
||||
{%- for item in value['required'] | default([]) -%}
|
||||
<escape>{{- item -}}<escape>
|
||||
{%- if not loop.last %},{% endif -%}
|
||||
{%- endfor -%}
|
||||
]
|
||||
{%- endif -%}
|
||||
{%- elif value['type'] | upper == 'ARRAY' -%}
|
||||
{%- if value['items'] is mapping and value['items'] -%}
|
||||
,items:{
|
||||
{%- set ns_items = namespace(found_first=false) -%}
|
||||
{%- for item_key, item_value in value['items'] | dictsort -%}
|
||||
{%- if item_value is not none -%}
|
||||
{%- if ns_items.found_first %},{% endif -%}
|
||||
{%- set ns_items.found_first = true -%}
|
||||
{%- if item_key == 'properties' -%}
|
||||
properties:{
|
||||
{%- if item_value is mapping -%}
|
||||
{{- format_parameters(item_value, value['items']['required'] | default([])) -}}
|
||||
{%- endif -%}
|
||||
}
|
||||
{%- elif item_key == 'required' -%}
|
||||
required:[
|
||||
{%- for req_item in item_value -%}
|
||||
<escape>{{- req_item -}}<escape>
|
||||
{%- if not loop.last %},{% endif -%}
|
||||
{%- endfor -%}
|
||||
]
|
||||
{%- elif item_key == 'type' -%}
|
||||
{%- if item_value is string -%}
|
||||
type:{{ format_argument(item_value | upper) }}
|
||||
{%- else -%}
|
||||
type:{{ format_argument(item_value | map('upper') | list) }}
|
||||
{%- endif -%}
|
||||
{%- else -%}
|
||||
{{ item_key }}:{{ format_argument(item_value) }}
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
}
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
,type:<escape>{{ value['type'] | upper }}<escape>}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- endmacro -%}
|
||||
{% macro format_function_declaration(tool_data) -%}
|
||||
declaration:{{- tool_data['function']['name'] -}}
|
||||
{description:<escape>{{- tool_data['function']['description'] -}}<escape>
|
||||
{%- set params = tool_data['function']['parameters'] -%}
|
||||
{%- if params -%}
|
||||
,parameters:{
|
||||
{%- if params['properties'] -%}
|
||||
properties:{ {{- format_parameters(params['properties'], params['required']) -}} },
|
||||
{%- endif -%}
|
||||
{%- if params['required'] -%}
|
||||
required:[
|
||||
{%- for item in params['required'] -%}
|
||||
<escape>{{- item -}}<escape>
|
||||
{{- ',' if not loop.last -}}
|
||||
{%- endfor -%}
|
||||
],
|
||||
{%- endif -%}
|
||||
{%- if params['type'] -%}
|
||||
type:<escape>{{- params['type'] | upper -}}<escape>}
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
}
|
||||
{%- endmacro -%}
|
||||
{% macro format_argument(argument, escape_keys=True) -%}
|
||||
{%- if argument is string -%}
|
||||
{{- '<escape>' + argument + '<escape>' -}}
|
||||
{%- elif argument is boolean -%}
|
||||
{%- if argument -%}
|
||||
{{- 'true' -}}
|
||||
{%- else -%}
|
||||
{{- 'false' -}}
|
||||
{%- endif -%}
|
||||
{%- elif argument is mapping -%}
|
||||
{{- '{' -}}
|
||||
{%- set ns = namespace(found_first=false) -%}
|
||||
{%- for key, value in argument | dictsort -%}
|
||||
{%- if ns.found_first %},{% endif -%}
|
||||
{%- set ns.found_first = true -%}
|
||||
{%- if escape_keys -%}
|
||||
{{- '<escape>' + key + '<escape>' -}}
|
||||
{%- else -%}
|
||||
{{- key -}}
|
||||
{%- endif -%}
|
||||
:{{- format_argument(value, escape_keys=escape_keys) -}}
|
||||
{%- endfor -%}
|
||||
{{- '}' -}}
|
||||
{%- elif argument is sequence -%}
|
||||
{{- '[' -}}
|
||||
{%- for item in argument -%}
|
||||
{{- format_argument(item, escape_keys=escape_keys) -}}
|
||||
{%- if not loop.last %},{% endif -%}
|
||||
{%- endfor -%}
|
||||
{{- ']' -}}
|
||||
{%- else -%}
|
||||
{{- argument -}}
|
||||
{%- endif -%}
|
||||
{%- endmacro -%}
|
||||
{{ bos_token }}
|
||||
{%- set ns = namespace(prev_message_type=None) -%}
|
||||
{#- Tool Declarations -#}
|
||||
{%- set loop_messages = messages -%}
|
||||
{%- if tools or messages[0]['role'] == 'system' or messages[0]['role'] == 'developer' -%}
|
||||
{{- '<start_of_turn>developer\n' -}}
|
||||
{%- if messages[0]['role'] == 'system' or messages[0]['role'] == 'developer' -%}
|
||||
{%- if messages[0]['content'] is string -%}
|
||||
{{- messages[0]['content'] | trim -}}
|
||||
{%- elif messages[0]['content'] is sequence -%}
|
||||
{%- for item in messages[0]['content'] -%}
|
||||
{%- if item['type'] == 'text' -%}
|
||||
{{- item['text'] | trim -}}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- endif -%}
|
||||
{%- set loop_messages = messages[1:] -%}
|
||||
{%- else -%}
|
||||
{{- 'You are a model that can do function calling with the following functions' -}}
|
||||
{%- set loop_messages = messages -%}
|
||||
{%- endif -%}
|
||||
{%- if tools -%}
|
||||
{%- for tool in tools %}
|
||||
{{- '<start_function_declaration>' -}}
|
||||
{{- format_function_declaration(tool) | trim }}
|
||||
{{- '<end_function_declaration>' -}}
|
||||
{%- endfor %}
|
||||
{%- endif -%}
|
||||
{{- '<end_of_turn>\n' }}
|
||||
{%- endif %}
|
||||
{#- Loop through messages. -#}
|
||||
{%- for message in loop_messages -%}
|
||||
{%- if (message['role'] == 'assistant') -%}
|
||||
{#- Rename "assistant" to "model". -#}
|
||||
{%- set role = "model" -%}
|
||||
{%- else -%}
|
||||
{%- set role = message['role'] -%}
|
||||
{%- endif -%}
|
||||
{%- if role != 'tool' -%}
|
||||
{%- if ns.prev_message_type != 'tool_response' -%}
|
||||
{{- '<start_of_turn>' + role + '\n' }}
|
||||
{%- endif -%}
|
||||
{%- set ns.prev_message_type = None -%}
|
||||
{%- if 'content' in message and message['content'] is not none -%}
|
||||
{%- if message['content'] is string -%}
|
||||
{{ message['content'] | trim }}
|
||||
{%- elif message['content'] is sequence -%}
|
||||
{%- for item in message['content'] -%}
|
||||
{%- if item['type'] == 'image' -%}
|
||||
{{ '<start_of_image>' }}
|
||||
{%- elif item['type'] == 'text' -%}
|
||||
{{ item['text'] | trim }}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- else -%}
|
||||
{{ raise_exception("Invalid content type in user/assistant message") }}
|
||||
{%- endif -%}
|
||||
{%- set ns.prev_message_type = 'content' -%}
|
||||
{%- endif -%}
|
||||
{%- if 'tool_calls' in message and message['tool_calls'] and message['tool_calls'] is iterable -%}
|
||||
{#- Tool Calls -#}
|
||||
{%- for tool_call in message['tool_calls'] -%}
|
||||
{% set function = tool_call['function'] %}
|
||||
{{- '<start_function_call>call:' + function['name'] + '{' -}}
|
||||
{%- if 'arguments' in function -%}
|
||||
{%- if function['arguments'] is mapping -%}
|
||||
{%- set ns = namespace(found_first=false) -%}
|
||||
{%- for key, value in function['arguments'] | dictsort -%}
|
||||
{%- if ns.found_first %},{% endif -%}
|
||||
{%- set ns.found_first = true -%}
|
||||
{{- key -}}:{{- format_argument(value, escape_keys=False) -}}
|
||||
{%- endfor -%}
|
||||
{%- elif function['arguments'] is string -%}
|
||||
{# This handles string-JSON, just in case #}
|
||||
{{ function['arguments'] }}
|
||||
{%- endif %}
|
||||
{%- endif -%}
|
||||
{{- '}<end_function_call>' -}}
|
||||
{%- endfor -%}
|
||||
{%- if loop.last -%}
|
||||
{{ '<start_function_response>' }}
|
||||
{%- endif -%}
|
||||
{%- set ns.prev_message_type = 'tool_call' -%}
|
||||
{%- endif -%}
|
||||
{%- else -%}
|
||||
{#- Tool Responses -#}
|
||||
{%- if 'content' in message and message['content'] -%}
|
||||
{%- if message['content'] is mapping -%}
|
||||
{%- if 'name' in message['content'] and 'response' in message['content'] -%}
|
||||
{{ '<start_function_response>response:' + message['content']['name'] | trim + '{' }}
|
||||
{%- set response_ns = namespace(found_first=false) -%}
|
||||
{%- for key, value in message['content']['response'] | dictsort -%}
|
||||
{%- if response_ns.found_first %},{% endif -%}
|
||||
{%- set response_ns.found_first = true -%}
|
||||
{{- key -}}:{{- format_argument(value, escape_keys=False) -}}
|
||||
{%- endfor -%}
|
||||
{{- '}<end_function_response>' -}}
|
||||
{%- elif 'name' in message -%}
|
||||
{{ '<start_function_response>response:' + message['name'] | trim + '{' }}
|
||||
{%- set response_ns = namespace(found_first=false) -%}
|
||||
{%- for key, value in message['content'] | dictsort -%}
|
||||
{%- if response_ns.found_first %},{% endif -%}
|
||||
{%- set response_ns.found_first = true -%}
|
||||
{{- key -}}:{{- format_argument(value, escape_keys=False) -}}
|
||||
{%- endfor -%}
|
||||
{{- '}<end_function_response>' -}}
|
||||
{%- else -%}
|
||||
{{ raise_exception("Invalid tool response mapping: must contain 'name' and 'response' keys, or 'name' must be in the message.") }}
|
||||
{%- endif -%}
|
||||
{%- elif message['content'] is string -%}
|
||||
{%- if 'name' in message -%}
|
||||
{{ '<start_function_response>response:' + message['name'] | trim + '{value:' + format_argument(message['content'], escape_keys=False) + '}<end_function_response>' }}
|
||||
{%- else -%}
|
||||
{{ raise_exception("Invalid tool response: 'name' must be provided.") }}
|
||||
{%- endif -%}
|
||||
{%- elif message['content'] is sequence -%}
|
||||
{%- for item in message['content'] -%}
|
||||
{%- if item is mapping -%}
|
||||
{%- if 'name' in item and 'response' in item -%}
|
||||
{{ '<start_function_response>response:' + item['name'] | trim + '{' }}
|
||||
{%- set response_ns = namespace(found_first=false) -%}
|
||||
{%- for key, value in item['response'] | dictsort -%}
|
||||
{%- if response_ns.found_first %},{% endif -%}
|
||||
{%- set response_ns.found_first = true -%}
|
||||
{{- key -}}:{{- format_argument(value, escape_keys=False) -}}
|
||||
{%- endfor -%}
|
||||
{{- '}<end_function_response>' -}}
|
||||
{%- elif 'name' in message -%}
|
||||
{{ '<start_function_response>response:' + message['name'] | trim + '{' }}
|
||||
{%- set response_ns = namespace(found_first=false) -%}
|
||||
{%- for key, value in item | dictsort -%}
|
||||
{%- if response_ns.found_first %},{% endif -%}
|
||||
{%- set response_ns.found_first = true -%}
|
||||
{{- key -}}:{{- format_argument(value, escape_keys=False) -}}
|
||||
{%- endfor -%}
|
||||
{{- '}<end_function_response>' -}}
|
||||
{%- else -%}
|
||||
{{ raise_exception("Invalid tool response mapping: must contain 'name' and 'response' keys, or 'name' must be in the message.") }}
|
||||
{%- endif -%}
|
||||
{%- else -%}
|
||||
{{ raise_exception("Invalid tool response message: multiple responses must all be mappings") }}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- else -%}
|
||||
{{ raise_exception("Invalid content type in tool message: must be mapping, sequence of mappings, or string.") }}
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
{%- set ns.prev_message_type = 'tool_response' -%}
|
||||
{%- endif -%}
|
||||
{%- if ns.prev_message_type not in ['tool_call', 'tool_response'] -%}
|
||||
{{ '<end_of_turn>\n' }}
|
||||
{%- endif -%}
|
||||
{%- endfor -%}
|
||||
{%- if add_generation_prompt -%}
|
||||
{%- if ns.prev_message_type != 'tool_response' -%}
|
||||
{{- '<start_of_turn>model\n' -}}
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
56
config.json
Normal file
56
config.json
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"_sliding_window_pattern": 6,
|
||||
"architectures": [
|
||||
"Gemma3ForCausalLM"
|
||||
],
|
||||
"attention_bias": false,
|
||||
"attention_dropout": 0.0,
|
||||
"attn_logit_softcapping": null,
|
||||
"bos_token_id": 2,
|
||||
"dtype": "bfloat16",
|
||||
"eos_token_id": 106,
|
||||
"final_logit_softcapping": null,
|
||||
"head_dim": 256,
|
||||
"hidden_activation": "gelu_pytorch_tanh",
|
||||
"hidden_size": 640,
|
||||
"initializer_range": 0.02,
|
||||
"intermediate_size": 2048,
|
||||
"layer_types": [
|
||||
"sliding_attention",
|
||||
"sliding_attention",
|
||||
"sliding_attention",
|
||||
"sliding_attention",
|
||||
"sliding_attention",
|
||||
"full_attention",
|
||||
"sliding_attention",
|
||||
"sliding_attention",
|
||||
"sliding_attention",
|
||||
"sliding_attention",
|
||||
"sliding_attention",
|
||||
"full_attention",
|
||||
"sliding_attention",
|
||||
"sliding_attention",
|
||||
"sliding_attention",
|
||||
"sliding_attention",
|
||||
"sliding_attention",
|
||||
"full_attention"
|
||||
],
|
||||
"max_position_embeddings": 32768,
|
||||
"model_type": "gemma3_text",
|
||||
"num_attention_heads": 4,
|
||||
"num_hidden_layers": 18,
|
||||
"num_key_value_heads": 1,
|
||||
"pad_token_id": 0,
|
||||
"query_pre_attn_scalar": 256,
|
||||
"rms_norm_eps": 1e-06,
|
||||
"rope_local_base_freq": 10000.0,
|
||||
"rope_scaling": null,
|
||||
"rope_theta": 1000000.0,
|
||||
"sliding_window": 512,
|
||||
"transformers_version": "4.57.4",
|
||||
"unsloth_fixed": true,
|
||||
"unsloth_version": "2026.2.1",
|
||||
"use_bidirectional_attention": false,
|
||||
"use_cache": true,
|
||||
"vocab_size": 262144
|
||||
}
|
||||
14
generation_config.json
Normal file
14
generation_config.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"bos_token_id": 2,
|
||||
"do_sample": true,
|
||||
"eos_token_id": [
|
||||
1,
|
||||
50,
|
||||
106
|
||||
],
|
||||
"max_length": 32768,
|
||||
"pad_token_id": 0,
|
||||
"top_k": 64,
|
||||
"top_p": 0.95,
|
||||
"transformers_version": "4.57.4"
|
||||
}
|
||||
3
model.safetensors
Normal file
3
model.safetensors
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:744d3bba6c65015853039ff50f984b1a0581df38f4615c71a91ef57d0b7a0011
|
||||
size 536334056
|
||||
34
special_tokens_map.json
Normal file
34
special_tokens_map.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"boi_token": "<start_of_image>",
|
||||
"bos_token": {
|
||||
"content": "<bos>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
},
|
||||
"eoi_token": "<end_of_image>",
|
||||
"eos_token": {
|
||||
"content": "<end_of_turn>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
},
|
||||
"image_token": "<image_soft_token>",
|
||||
"pad_token": {
|
||||
"content": "<pad>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
},
|
||||
"sfr_token": "<start_function_response>",
|
||||
"unk_token": {
|
||||
"content": "<unk>",
|
||||
"lstrip": false,
|
||||
"normalized": false,
|
||||
"rstrip": false,
|
||||
"single_word": false
|
||||
}
|
||||
}
|
||||
3
tokenizer.json
Normal file
3
tokenizer.json
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b6b09a0b4a803ad453063ca4bb49a784540e8120004e2450e025df2b27d41fb2
|
||||
size 33384899
|
||||
3
tokenizer.model
Normal file
3
tokenizer.model
Normal file
@@ -0,0 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:aa009fcbc3589a9904d30d04834094fea4653c2ac6d2de2cd1262d4f7a50ceb3
|
||||
size 4689144
|
||||
51355
tokenizer_config.json
Normal file
51355
tokenizer_config.json
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user