Image-Text-to-Text
Transformers
Safetensors
lfm3_vl
feature-extraction
liquid
lfm3
edge
decision
classification
extraction
calibration
system-one
multimodal
decision-model
custom_code
conversational
Instructions to use LiquidAI/d1-2B with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use LiquidAI/d1-2B with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="LiquidAI/d1-2B", trust_remote_code=True) messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("LiquidAI/d1-2B", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use LiquidAI/d1-2B with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "LiquidAI/d1-2B" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "LiquidAI/d1-2B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/LiquidAI/d1-2B
- SGLang
How to use LiquidAI/d1-2B with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "LiquidAI/d1-2B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "LiquidAI/d1-2B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "LiquidAI/d1-2B" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "LiquidAI/d1-2B", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use LiquidAI/d1-2B with Docker Model Runner:
docker model run hf.co/LiquidAI/d1-2B
Download chat_template.jinja from LiquidAI/d1-2B: direct link, hf CLI and curl.
- Browser
- Download file 12.7 kB
-
https://huggingface.co/LiquidAI/d1-2B/resolve/main/chat_template.jinja
- Command line
-
hf download hf://LiquidAI/d1-2B/chat_template.jinja
-
curl -L -o chat_template.jinja https://huggingface.co/LiquidAI/d1-2B/resolve/main/chat_template.jinja
12.7 kB
| {{- bos_token -}} | |
| {%- set preserve_thinking = preserve_thinking | default(false) -%} | |
| {%- set enable_thinking = enable_thinking | default(true) -%} | |
| {%- macro render_value(v) -%} | |
| {%- if v is string -%} | |
| {{- v -}} | |
| {%- elif v is boolean -%} | |
| {{- "true" if v else "false" -}} | |
| {%- elif v is none -%} | |
| {{- "null" -}} | |
| {%- elif v is mapping or (v is sequence and v is not string) -%} | |
| {{- v | tojson -}} | |
| {%- else -%} | |
| {{- v -}} | |
| {%- endif -%} | |
| {%- endmacro -%} | |
| {%- macro parse_content(content) -%} | |
| {%- if content is string -%} | |
| {{- content -}} | |
| {%- elif content is mapping and content.get("type") == "image" -%} | |
| {{- "<|vision_start|><|image|><|vision_end|>" -}} | |
| {%- elif content is mapping and content.get("type") == "video" -%} | |
| {{- "<|vision_start|><|video|><|vision_end|>" -}} | |
| {%- elif content is mapping and content.get("type") == "text" -%} | |
| {{- (content.get("text") or "") | string -}} | |
| {%- elif content is mapping -%} | |
| {{- content | tojson -}} | |
| {%- elif content is iterable -%} | |
| {%- set _ns = namespace(result="") -%} | |
| {%- for item in content -%} | |
| {%- if item is string -%} | |
| {%- set _ns.result = _ns.result + item -%} | |
| {%- elif item is mapping and item.get("type") == "image" -%} | |
| {%- set _ns.result = _ns.result + "<|vision_start|><|image|><|vision_end|>" -%} | |
| {%- elif item is mapping and item.get("type") == "video" -%} | |
| {%- set _ns.result = _ns.result + "<|vision_start|><|video|><|vision_end|>" -%} | |
| {%- elif item is mapping and item.get("type") == "text" -%} | |
| {%- set _ns.result = _ns.result + ((item.get("text") or "") | string) -%} | |
| {%- else -%} | |
| {%- set _ns.result = _ns.result + (item | tojson) -%} | |
| {%- endif -%} | |
| {%- endfor -%} | |
| {{- _ns.result -}} | |
| {%- endif -%} | |
| {%- endmacro -%} | |
| {%- macro render_tool_calls(tool_calls) -%} | |
| {%- for tool_call in tool_calls -%} | |
| {%- if not loop.first -%}{{- "\n\n" -}}{%- endif -%} | |
| {%- set func = tool_call["function"] if "function" in tool_call else tool_call -%} | |
| {%- set func_args = func.get("arguments") -%} | |
| {%- if func_args is string and (func_args | trim) not in ["", "{}", "null"] -%} | |
| {{- raise_exception("Tool call arguments must be a mapping, got a JSON-encoded string: parse arguments with json.loads() before applying the chat template") -}} | |
| {%- endif -%} | |
| {{- "<tool_call>\n<function=" + func["name"] + ">\n" -}} | |
| {%- if func_args is mapping -%} | |
| {%- for arg_name, arg_value in func_args.items() -%} | |
| {{- "<parameter=" + arg_name + ">\n" + render_value(arg_value) + "\n</parameter>\n" -}} | |
| {%- endfor -%} | |
| {%- endif -%} | |
| {{- "</function>\n</tool_call>" -}} | |
| {%- endfor -%} | |
| {%- endmacro -%} | |
| {%- macro tool_to_json(tool) -%} | |
| {%- set fn = tool.function if tool.function is defined else tool -%} | |
| {%- set ns_t = namespace(first=true) -%} | |
| {{- "{" -}} | |
| {%- for k, v in fn.items() -%} | |
| {%- if k != "defer_loading" -%} | |
| {%- if not ns_t.first -%}{{- ", " -}}{%- endif -%} | |
| {%- set ns_t.first = false -%} | |
| {{- k | tojson -}}{{- ": " -}}{{- v | tojson -}} | |
| {%- endif -%} | |
| {%- endfor -%} | |
| {{- "}" -}} | |
| {%- endmacro -%} | |
| {#- a tool_reference content part (vLLM, SGLang) names a tool from `tools`, | |
| usually a deferred one; it renders as that tool's definition -#} | |
| {%- macro is_tool_reference(item) -%} | |
| {{- "1" if item is mapping and item.get("type") == "tool_reference" else "" -}} | |
| {%- endmacro -%} | |
| {%- macro referenced_tool_to_json(name) -%} | |
| {%- set _ns = namespace(found=none) -%} | |
| {%- for tool in tools or [] -%} | |
| {%- set fn = tool.function if tool.function is defined else tool -%} | |
| {%- if fn.name == name -%} | |
| {%- set _ns.found = fn -%} | |
| {%- endif -%} | |
| {%- endfor -%} | |
| {%- if _ns.found is none -%} | |
| {{- raise_exception("tool_reference names a tool that is not in tools: " + name | string) -}} | |
| {%- endif -%} | |
| {{- tool_to_json(_ns.found) -}} | |
| {%- endmacro -%} | |
| {%- macro render_tool_response(content) -%} | |
| {#- content that already carries the tag (pre-formatted by the caller) is | |
| passed through as-is instead of being wrapped a second time -#} | |
| {%- if content is string and "<tool_response>" in content -%} | |
| {{- content -}} | |
| {%- else -%} | |
| {{- "<tool_response>\n" -}} | |
| {%- if content is string -%} | |
| {{- content -}} | |
| {%- elif content is mapping -%} | |
| {{- parse_content(content) -}} | |
| {%- elif content is iterable -%} | |
| {%- for item in content -%} | |
| {%- if not loop.first -%}{{- "\n" -}}{%- endif -%} | |
| {%- if is_tool_reference(item) -%} | |
| {#- consecutive references share one <additional_tools> block -#} | |
| {%- if loop.first or not is_tool_reference(loop.previtem) -%} | |
| {{- "<additional_tools>\n" -}} | |
| {%- endif -%} | |
| {{- referenced_tool_to_json(item.name) -}} | |
| {%- if loop.last or not is_tool_reference(loop.nextitem) -%} | |
| {{- "\n</additional_tools>" -}} | |
| {%- endif -%} | |
| {%- elif item is mapping and item.result is defined and item.result is mapping and item.result.tools is defined -%} | |
| {{- "<additional_tools>\n" -}} | |
| {%- set _tl = item.result.tools -%} | |
| {%- if _tl is string -%} | |
| {{- _tl -}} | |
| {%- elif _tl is mapping -%} | |
| {{- tool_to_json(_tl) -}} | |
| {%- else -%} | |
| {%- for t in _tl -%} | |
| {%- if not loop.first -%}{{- "\n" -}}{%- endif -%} | |
| {{- tool_to_json(t) -}} | |
| {%- endfor -%} | |
| {%- endif -%} | |
| {{- "\n</additional_tools>" -}} | |
| {%- else -%} | |
| {{- parse_content(item) -}} | |
| {%- endif -%} | |
| {%- endfor -%} | |
| {%- endif -%} | |
| {{- "\n</tool_response>" -}} | |
| {%- endif -%} | |
| {%- endmacro -%} | |
| {%- set ns = namespace(system_prompt="", last_user_index=-1) -%} | |
| {%- if messages and messages[0]["role"] == "system" -%} | |
| {%- if messages[0].get("content") -%} | |
| {%- set ns.system_prompt = parse_content(messages[0]["content"]) -%} | |
| {%- endif -%} | |
| {%- set messages = messages[1:] -%} | |
| {%- endif -%} | |
| {%- if tools -%} | |
| {%- set tools_ns = namespace(lines=[]) -%} | |
| {%- for tool in tools -%} | |
| {%- set fn = tool.function if tool.function is defined else tool -%} | |
| {%- set _dyn = (fn.defer_loading is defined and fn.defer_loading) or (tool.defer_loading is defined and tool.defer_loading) -%} | |
| {%- if not _dyn -%} | |
| {%- set tools_ns.lines = tools_ns.lines + [tool_to_json(fn)] -%} | |
| {%- endif -%} | |
| {%- endfor -%} | |
| {%- if tools_ns.lines -%} | |
| {%- set ns.system_prompt = ns.system_prompt + ("\n\n" if ns.system_prompt else "") + "<tools>\n" + (tools_ns.lines | join("\n")) + "\n</tools>" -%} | |
| {%- endif -%} | |
| {%- endif -%} | |
| {%- if ns.system_prompt -%} | |
| {{- "<|im_start|>system\n" + ns.system_prompt + "<|im_end|>\n" -}} | |
| {%- endif -%} | |
| {%- for message in messages -%} | |
| {%- if message["role"] == "user" -%} | |
| {%- set ns.last_user_index = loop.index0 -%} | |
| {%- endif -%} | |
| {%- endfor -%} | |
| {#- vLLM's and SGLang's Anthropic /v1/messages adapters split one tool_result that carries | |
| tool_reference blocks into consecutive tool messages with the same tool_call_id (text first, | |
| references second). Merge such runs into one tool turn so they render exactly like a single | |
| OpenAI-format tool message whose content holds the same items. -#} | |
| {%- set carry = namespace(pending=[]) -%} | |
| {%- for message in messages -%} | |
| {%- set _next = messages[loop.index0 + 1] if not loop.last else none -%} | |
| {%- set _merge = message.role == "tool" and not message.get("additional_tools") | |
| and _next is not none and _next.role == "tool" and not _next.get("additional_tools") | |
| and message.get("tool_call_id") and _next.get("tool_call_id") == message.get("tool_call_id") -%} | |
| {%- set _items = [] -%} | |
| {%- if message.role == "tool" and not message.get("additional_tools") -%} | |
| {%- set _c = message.get("content") -%} | |
| {%- if _c is string -%} | |
| {%- set _items = [{"type": "text", "text": _c}] if _c else [] -%} | |
| {%- elif _c is mapping -%} | |
| {%- set _items = [_c] -%} | |
| {%- elif _c -%} | |
| {%- set _items = _c | list -%} | |
| {%- endif -%} | |
| {%- endif -%} | |
| {%- if _merge -%} | |
| {%- set carry.pending = carry.pending + _items -%} | |
| {%- else -%} | |
| {{- "<|im_start|>" + message.role + "\n" -}} | |
| {%- if message.role == "assistant" -%} | |
| {%- generation -%} | |
| {%- set thinking = message.thinking if message.thinking is defined else message.reasoning if message.reasoning is defined else message.reasoning_content -%} | |
| {%- set keep_thinking = preserve_thinking or loop.index0 > ns.last_user_index -%} | |
| {%- if thinking is defined and keep_thinking -%} | |
| {{- "<think>" + (thinking or "") + "</think>" -}} | |
| {%- endif -%} | |
| {%- set _cfm_tag = "CONTINUE_FINAL_MESSAGE_TAG " -%} | |
| {%- set _has_cfm = false -%} | |
| {%- set content = "" -%} | |
| {%- if message.get("content") -%} | |
| {%- set content = parse_content(message.content) -%} | |
| {%- endif -%} | |
| {%- if not keep_thinking -%} | |
| {%- if "</think>" in content -%} | |
| {%- set content = content.split("</think>")[-1] | trim -%} | |
| {%- endif -%} | |
| {%- set content = "<think></think>" + content -%} | |
| {%- endif -%} | |
| {%- if content.endswith(_cfm_tag) -%} | |
| {%- set _has_cfm = true -%} | |
| {%- set _trunc_len = (content | length) - (_cfm_tag | length) -%} | |
| {%- set content = content[:_trunc_len] -%} | |
| {%- endif -%} | |
| {{- content -}} | |
| {%- if message.tool_calls -%} | |
| {{- render_tool_calls(message.tool_calls) -}} | |
| {%- endif -%} | |
| {%- if _has_cfm -%} | |
| {{- _cfm_tag -}} | |
| {%- endif -%} | |
| {{- "<|im_end|>\n" -}} | |
| {%- endgeneration -%} | |
| {%- elif message.role == "tool" -%} | |
| {%- if message.get("additional_tools") -%} | |
| {%- set _at = message["additional_tools"] -%} | |
| {#- definitions may live in additional_tools itself, or in content | |
| with additional_tools used as a plain truthy flag -#} | |
| {%- if _at is mapping or (_at is sequence and _at is not string) -%} | |
| {%- set _src = _at -%} | |
| {%- else -%} | |
| {%- set _src = message.get("content") -%} | |
| {%- endif -%} | |
| {#- nothing to reveal: skip the wrapper entirely rather than | |
| emitting an empty <additional_tools> block -#} | |
| {%- if _src is string and "<tool_response>" in _src -%} | |
| {{- _src -}} | |
| {%- elif _src is string and "<additional_tools>" in _src -%} | |
| {{- "<tool_response>\n" + _src + "\n</tool_response>" -}} | |
| {%- elif _src -%} | |
| {{- "<tool_response>\n<additional_tools>\n" -}} | |
| {%- if _src is string -%} | |
| {{- _src -}} | |
| {%- elif _src is mapping -%} | |
| {{- tool_to_json(_src) -}} | |
| {%- else -%} | |
| {%- for t in _src -%} | |
| {%- if not loop.first -%}{{- "\n" -}}{%- endif -%} | |
| {{- tool_to_json(t) -}} | |
| {%- endfor -%} | |
| {%- endif -%} | |
| {{- "\n</additional_tools>\n</tool_response>" -}} | |
| {%- endif -%} | |
| {%- elif carry.pending -%} | |
| {{- render_tool_response(carry.pending + _items) -}} | |
| {%- set carry.pending = [] -%} | |
| {%- else -%} | |
| {#- an empty or missing result still gets the wrapper, so every tool turn has the same shape -#} | |
| {{- render_tool_response(message.get("content") or "") -}} | |
| {%- endif -%} | |
| {{- "<|im_end|>\n" -}} | |
| {%- else %} | |
| {%- if message.get("content") -%} | |
| {{- parse_content(message["content"]) -}} | |
| {%- endif -%} | |
| {{- "<|im_end|>\n" -}} | |
| {%- endif %} | |
| {%- endif -%} | |
| {%- endfor -%} | |
| {%- if add_generation_prompt -%} | |
| {{- "<|im_start|>assistant\n" -}} | |
| {%- if enable_thinking -%} | |
| {{- "<think>" -}} | |
| {%- else -%} | |
| {{- "<think></think>" -}} | |
| {%- endif -%} | |
| {%- endif -%} | |