Skip to main content

langchain-qwq

LangChain chat models for Alibaba Cloud Model Studio (DashScope) and compatible Qwen endpoints. The package provides ChatQwQ and ChatQwen, with synchronous and asynchronous calls, streaming, tool calls, structured output, and access to provider-returned reasoning content. Available features depend on the model and endpoint you select.

Upgrading to 0.4.0

Alibaba retired qwq-plus in the Beijing and Singapore regions on October 10, 2026. Calls to that model can now return HTTP 404 model_not_found. See the retirement notice.

The package name and imports are unchanged. To keep using ChatQwQ, explicitly select a supported model and enable its thinking mode:

from langchain_qwq import ChatQwQ

model = ChatQwQ(
    model="qwen-plus-latest",
    extra_body={"enable_thinking": True},
)

This configuration is covered by the live integration tests. The ChatQwQ constructor still defaults to qwq-plus, so do not omit model when using DashScope. The release does not silently redirect requests to a different model. For first-class enable_thinking and thinking_budget arguments, use ChatQwen as shown below. Check model availability in your account and region; a model identifier supported by one provider may not be supported by another.

Version 0.4.0 also fixes fragmented tool-call arguments in ChatQwQ. Tool-call arguments are buffered until completion, then valid JSON is preserved and repairable malformed JSON is repaired. Text and reasoning continue to stream without waiting for the tool call. See CHANGELOG.md for the release details.

Installation and configuration

Requires Python 3.10 or newer.

pip install -U langchain-qwq

Set DASHSCOPE_API_KEY to your real DashScope API key in your environment before running the examples. DASHSCOPE_API_BASE optionally overrides the base URL; the package default is:

https://dashscope-intl.aliyuncs.com/compatible-mode/v1

Use the endpoint and credentials for your region. For a different provider or self-hosted server, pass its base_url and api_key explicitly. Model access, thinking controls, tool calling, and image inputs must be supported by that endpoint.

Quickstart

This is a complete synchronous example after configuring your API key:

from langchain_qwq import ChatQwQ

model = ChatQwQ(
    model="qwen-plus-latest",
    extra_body={"enable_thinking": True},
)
response = model.invoke("What is 17 multiplied by 19?")
print(response.content)
print(response.additional_kwargs.get("reasoning_content", ""))

Alternatively, use ChatQwen to configure thinking directly:

from langchain_qwq import ChatQwen

model = ChatQwen(model="qwen-plus-latest", enable_thinking=True)
response = model.invoke("What is 17 multiplied by 19?")
print(response.content)

Choosing a wrapper

Behavior ChatQwQ ChatQwen
Model selection Explicitly select an active model; default remains retired qwq-plus Explicitly select a model; default is qwen3-32b
Thinking controls Provider parameters through extra_body enable_thinking, thinking_budget, and extra_body
Transport for invoke / ainvoke Always streams internally and assembles the response Automatically enables streaming for detected thinking models on DashScope endpoints
Tool-argument streaming Buffers and repairs complete arguments Uses the underlying streaming behavior
Structured output Function calling; other method names are converted to function calling Function calling or JSON mode, subject to model support
Reasoning content additional_kwargs["reasoning_content"] when returned Same; also maps supported OpenRouter reasoning responses

Neither wrapper makes every feature available on every Qwen model. Use a model with the capabilities your application needs.

Reasoning and content blocks

The answer is in response.content. When the provider returns reasoning, it is available separately:

reasoning = response.additional_kwargs.get("reasoning_content", "")
print(reasoning)
print(response.content)
print(response.content_blocks)

content_blocks is LangChain's normalized view of the response and can include reasoning and text blocks. Accessing that property does not mean this package supports output_version="v1"; that output mode is not supported here. Reasoning is present only when the selected model and request produce it.

Streaming and async calls

The following continues with model from the ChatQwQ quickstart:

for chunk in model.stream("What is 17 multiplied by 19?"):
    reasoning = chunk.additional_kwargs.get("reasoning_content", "")
    if reasoning:
        print(reasoning, end="", flush=True)
    if chunk.content:
        print(chunk.content, end="", flush=True)
print()

A complete asynchronous example:

import asyncio

from langchain_qwq import ChatQwQ


async def main() -> None:
    model = ChatQwQ(
        model="qwen-plus-latest",
        extra_body={"enable_thinking": True},
    )
    response = await model.ainvoke("What is 17 multiplied by 19?")
    print(response.content)

    async for chunk in model.astream("Explain the calculation briefly."):
        reasoning = chunk.additional_kwargs.get("reasoning_content", "")
        if reasoning:
            print(reasoning, end="", flush=True)
        if chunk.content:
            print(chunk.content, end="", flush=True)
    print()


asyncio.run(main())

In a notebook with an active event loop, use await main() instead of asyncio.run(main()).

Tool calling and agents

Bind tools to a model that supports function calling:

from langchain_core.tools import tool
from langchain_qwq import ChatQwQ


@tool
def multiply(a: int, b: int) -> int:
    """Multiply two integers."""
    return a * b


model = ChatQwQ(
    model="qwen-plus-latest",
    extra_body={"enable_thinking": True},
)
response = model.bind_tools([multiply]).invoke("Use multiply to calculate 17 * 19.")
print(response.tool_calls)

bind_tools supplies tool definitions and returns requested tool calls; it does not execute those tools. An agent can handle the tool execution loop:

from langchain.agents import create_agent

agent = create_agent(model, tools=[multiply])
result = agent.invoke({"messages": [("user", "Use multiply to calculate 17 * 19.")]})
print(result["messages"][-1].content)

For ChatQwQ streaming, completed tool calls appear when the provider finishes the generation, or at a clean end of stream if it omits a finish marker. Do not expect executable argument fragments in earlier chunks. Provider errors and cancelled streams do not flush unfinished calls. This buffering applies to synchronous and asynchronous streams, including streaming callbacks.

Structured output

ChatQwQ uses function calling for structured output. Passing "json_mode" or "json_schema" to this wrapper also selects function calling; it does not enable native JSON mode.

from pydantic import BaseModel
from langchain_qwq import ChatQwQ


class Person(BaseModel):
    name: str
    age: int


model = ChatQwQ(
    model="qwen-plus-latest",
    extra_body={"enable_thinking": True},
)
structured = model.with_structured_output(Person, method="function_calling")
person = structured.invoke("Extract the person: Alice is 30 years old.")
print(person)

ChatQwen also supports method="json_mode" with a compatible model. Use a separate instance with thinking disabled for this example:

from langchain_qwq import ChatQwen

json_model = ChatQwen(model="qwen-plus-latest", enable_thinking=False)
structured = json_model.with_structured_output(Person, method="json_mode")
print(structured.invoke("Extract the person: Alice is 30 years old."))

For ChatQwen, structured-output setup can disable its enable_thinking flag for hybrid models. Models whose names contain thinking use function calling instead. "json_schema" is mapped to JSON mode by the base implementation; it is not a separate strict-schema API. A Pydantic schema validates the parsed result. Use include_raw=True to receive raw, parsed, and parsing_error fields when inspecting parsing failures.

ChatQwen thinking controls

Use controls supported by the selected model. On DashScope, for example:

from langchain_qwq import ChatQwen

model = ChatQwen(
    model="qwen-plus-latest",
    enable_thinking=True,
    thinking_budget=100,
)
print(model.invoke("What is 17 multiplied by 19?").content)

thinking_budget limits thinking tokens where the model supports it. It does not guarantee a particular answer length. See Alibaba's thinking-mode documentation for current model support and limits.

Some OpenAI-compatible servers expect thinking control inside chat_template_kwargs:

from langchain_qwq import ChatQwen

model = ChatQwen(
    model="Qwen/Qwen3.6-35B-A3B",
    base_url="http://localhost:8000/v1",
    api_key="test-key",  # Placeholder for a local server without authentication.
    extra_body={"chat_template_kwargs": {"enable_thinking": False}},
)

Omit the separate enable_thinking constructor argument in this form. The nested value takes precedence if both forms are present. For structured output, select a method supported by the server, such as method="json_mode" where available. This local example assumes you have already served the named model.

Vision inputs

Use ChatQwen with an image-capable model available at your endpoint. A typical message has this shape; replace image_url with an accessible image URL:

from langchain_core.messages import HumanMessage
from langchain_qwq import ChatQwen

vision_model = ChatQwen(model="qwen3-vl-plus")
message = HumanMessage(
    content_blocks=[
        {"type": "image", "url": image_url},
        {"type": "text", "text": "Describe this image."},
    ]
)
response = vision_model.invoke([message])

Text-only models cannot gain vision support from this message format. Confirm the model identifier and image support in your provider's current model catalog.

DashScope context-cache middleware

DashScopeContextCacheMiddleware adds an explicit cache marker to the latest message. Use it with a DashScope model that supports that cache format and with text content suitable for the middleware:

from langchain.agents import create_agent
from langchain_qwq import ChatQwen
from langchain_qwq.middleware import DashScopeContextCacheMiddleware

model = ChatQwen(model="qwen-plus-latest")
agent = create_agent(model, middleware=[DashScopeContextCacheMiddleware()])

Cache availability and billing depend on the selected model and endpoint; see DashScope context caching. The middleware does not provide a local response cache.

Development

From a clone of this repository, install the Poetry dependency groups:

poetry install --with test,lint,typing,codespell,dev
make format
make lint
make test
make spell_check
make check_imports
make integration_test

Unit tests disable network sockets. Integration tests use real provider APIs and require a valid DASHSCOPE_API_KEY; local test credentials can be placed in tests/.env. The suite tests ChatQwQ with qwen-plus-latest in thinking mode and ChatQwen with qwen-plus-latest. Model availability and API charges apply.

The notebooks in docs/ can be viewed on GitHub or in VS Code. Install Jupyter separately if you want to run them interactively. Older notebooks may use retired model identifiers; apply the migration above before running them.

Metadata

Release files for langchain-qwq 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for langchain-qwq 0.4.0
File Size Uploaded Provenance Actions
langchain_qwq-0.4.0.tar.gz 19.7 kB Without provenance Details for langchain_qwq-0.4.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for langchain-qwq 0.4.0
File Interpreter ABI Platform Actions
langchain_qwq-0.4.0-py3-none-any.whl Python 3 none any Details for langchain_qwq-0.4.0-py3-none-any.whl

Total release size: 38.2 kB

Release files / langchain_qwq-0.4.0.tar.gz

Download URL langchain_qwq-0.4.0.tar.gz
Size 19.7 kB
Tags Source
SHA-256 checksum
How to use checksums
ac0ec124327860ffcc766484aca0ffc16ce002725d73352d82bef09633c661ba
BLAKE2b-256 checksum
How to use checksums
04a4da529323899b91109da746777452e2e96b270d5f9d39de399c25c3c96111
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.0.1 CPython/3.13.0rc3 Darwin/25.5.0

Release files / langchain_qwq-0.4.0-py3-none-any.whl

Download URL langchain_qwq-0.4.0-py3-none-any.whl
Size 18.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8a9ba3c16f8f143628b033e99ea701d1b6dd695276f16ab9a85ded2694d0e8b1
BLAKE2b-256 checksum
How to use checksums
42586468da3f5eda0c1aa52b3f4eae96971835bd7016b30ebe5f39868108df29
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/2.0.1 CPython/3.13.0rc3 Darwin/25.5.0

Security for langchain-qwq 0.4.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page