An integration package connecting Moonshot AI and LangChain
Project description
LangChain Moonshot
langchain-moonshot is a standalone LangChain integration package for Moonshot AI chat models.
Upgrade Notes
0.1.0 is a breaking rewrite of the package.
- If you are upgrading from
0.0.6or0.0.7, note that the old PyPI releases exposedOpenAI,ChatOpenAI, andOpenAIEmbeddings. - Starting with
0.1.0, this project is rebuilt aroundChatMoonshotas the primary public integration. - The project homepage/repository has moved from
https://github.com/RyanFeiluX/langchain_moonshottohttps://github.com/ArcadiaLin/langchain-moonshot.
It provides a ChatMoonshot implementation built on top of langchain-openai, with Moonshot-specific support for:
reasoning_contentin non-streaming and streaming responsesthinking,prompt_cache_key,safety_identifier, andmax_completion_tokens- Moonshot model capability profiles
- tool calling, structured output, and multimodal inputs supported by Moonshot models
Overview
Integration details
| Class | Package | Status | Notes |
|---|---|---|---|
ChatMoonshot |
langchain-moonshot |
alpha | Standalone provider package for Moonshot AI |
Model features
| Tool calling | Structured output | Image input | Video input | Token-level streaming | Native async | Token usage | Reasoning traces |
|---|---|---|---|---|---|---|---|
| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Installation
Install from PyPI:
pip install langchain-moonshot
For local development:
uv sync --group dev --group test_integration
Standard Tests
This repository keeps only LangChain standard chat-model tests under tests/:
tests/unit_tests/test_standard.pytests/integration_tests/test_standard.py
Run the full standard suite in the current uv project and write the output to
pytest_standard.txt:
RUN_MOONSHOT_INTEGRATION=1 uv run pytest tests/unit_tests/test_standard.py tests/integration_tests/test_standard.py -q > pytest_standard.txt 2>&1
Run only the unit standard tests:
uv run pytest tests/unit_tests/test_standard.py -q > pytest_standard.txt 2>&1
Run only the live integration standard tests:
RUN_MOONSHOT_INTEGRATION=1 uv run pytest tests/integration_tests/test_standard.py -q > pytest_standard.txt 2>&1
Live integration tests require RUN_MOONSHOT_INTEGRATION=1 and MOONSHOT_API_KEY.
Current standard-test coverage and behavior:
- Default live standard model:
kimi-k2.5withthinking=Falseandtemperature=0.6 - All standard tests in this repository are constrained to
kimi-k2.5; the suite does not switch to any other Moonshot model - Covered by standard tests: serialization, env-based init, tool calling, structured output,
json_mode, image inputs, streaming, async, and VCR-backedtest_stream_time - Standard tests intentionally keep these capabilities unsupported: forced
tool_choice, runtimemodeloverride, PDF inputs, audio inputs, image/PDF tool messages, and Anthropic-style inputs - Known expected limitation:
output_version="v1"streaming tool calls can emit a natural-language preamble before the tool chunk stream, so the standardtest_tool_callingpath for that variant is markedxfail - Practical boundary: for day-to-day use, prefer
invoke()or default streaming output for tool calling; do not rely onoutput_version="v1"streamedcontent_blocksas the sole source of tool-call arguments
Credentials
Create a Moonshot API key in the Moonshot console, then set MOONSHOT_API_KEY.
import getpass
import os
if not os.getenv("MOONSHOT_API_KEY"):
os.environ["MOONSHOT_API_KEY"] = getpass.getpass("Enter your Moonshot API key: ")
If you are using Moonshot's China endpoint explicitly, you can also set:
os.environ.setdefault("MOONSHOT_API_BASE", "https://api.moonshot.cn/v1")
To enable LangSmith tracing:
os.environ["LANGSMITH_TRACING"] = "true"
os.environ["LANGSMITH_API_KEY"] = getpass.getpass("Enter your LangSmith API key: ")
Instantiation
from langchain_moonshot import ChatMoonshot
llm = ChatMoonshot(
model="kimi-k2.5",
thinking=True,
temperature=1.0,
max_retries=2,
)
Invocation
messages = [
("system", "You are a concise bilingual assistant."),
("human", "Summarize why Moonshot reasoning models are useful in two bullet points."),
]
ai_msg = llm.invoke(messages)
print(ai_msg.text)
print(ai_msg.additional_kwargs.get("reasoning_content"))
print(ai_msg.usage_metadata)
Streaming
streaming_llm = ChatMoonshot(
model="kimi-k2.5",
thinking=True,
temperature=1.0,
stream_usage=True,
)
full = None
for chunk in streaming_llm.stream("Explain streaming output in two short bullet points."):
if full is None:
full = chunk
else:
full += chunk
if chunk.text:
print(chunk.text, end="")
reasoning = chunk.additional_kwargs.get("reasoning_content")
if reasoning:
print(f"\n[reasoning] {reasoning}", end="")
print()
print(full.usage_metadata if full is not None else None)
Tool Calling
from langchain_core.messages import ToolMessage
from langchain_core.tools import tool
@tool
def add(a: int, b: int) -> int:
"""Add two integers."""
return a + b
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two integers."""
return a * b
llm_with_tools = ChatMoonshot(
model="kimi-k2.5",
thinking=False,
temperature=0.6,
).bind_tools([add, multiply])
messages = [
("system", "Use the provided math tools before answering."),
("human", "Add 17 and 25, multiply 12 by 13, then summarize the results."),
]
response = llm_with_tools.invoke(messages)
print(response.tool_calls)
if response.tool_calls:
tool_results = []
for tool_call in response.tool_calls:
if tool_call["name"] == "add":
result = add.invoke(tool_call["args"])
else:
result = multiply.invoke(tool_call["args"])
tool_results.append(
ToolMessage(content=str(result), tool_call_id=tool_call["id"])
)
final_response = llm_with_tools.invoke([*messages, response, *tool_results])
print(final_response.text)
Structured Output
Moonshot does not expose a distinct json_schema steering path in this package. ChatMoonshot.with_structured_output(..., method="json_schema") is intentionally downgraded to function_calling.
from pydantic import BaseModel, Field
class WeatherAnswer(BaseModel):
city: str = Field(description="City name")
summary: str = Field(description="One-sentence weather summary")
structured_llm = ChatMoonshot(
model="kimi-k2.5",
thinking=False,
temperature=0.6,
).with_structured_output(WeatherAnswer)
result = structured_llm.invoke("Summarize today's weather in Shanghai.")
print(result)
Multimodal Input
Vision-capable Moonshot models accept OpenAI-style image_url content blocks.
from langchain_core.messages import HumanMessage
vision_llm = ChatMoonshot(
model="moonshot-v1-32k-vision-preview",
)
message = HumanMessage(
content=[
{"type": "text", "text": "Describe the image and mention one concrete detail."},
{
"type": "image_url",
"image_url": {"url": "data:image/png;base64,<your-base64-image>"},
},
]
)
response = vision_llm.invoke([message])
print(response.text)
LangGraph Compatibility
ChatMoonshot works as a normal LangChain chat model inside LangGraph agent loops.
from typing import Annotated, Sequence, TypedDict
from langchain_core.messages import BaseMessage
from langgraph.graph import END, START, StateGraph
from langgraph.graph.message import add_messages
from langgraph.prebuilt import ToolNode
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], add_messages]
tools = [add, multiply]
model = ChatMoonshot(
model="kimi-k2.5",
thinking=False,
temperature=0.6,
).bind_tools(tools)
def model_call(state: AgentState) -> AgentState:
response = model.invoke([("system", "Use tools when needed."), *state["messages"]])
return {"messages": [response]}
def should_continue(state: AgentState) -> str:
last = state["messages"][-1]
return "continue" if getattr(last, "tool_calls", None) else "end"
graph = StateGraph(AgentState)
graph.add_node("agent", model_call)
graph.add_node("tools", ToolNode(tools=tools))
graph.add_edge(START, "agent")
graph.add_conditional_edges("agent", should_continue, {"continue": "tools", "end": END})
graph.add_edge("tools", "agent")
result = graph.compile().invoke(
{"messages": [("user", "Add 3 and 4, multiply 12 by 13, then summarize.")]}
)
print(result["messages"][-1].content)
Moonshot-Specific Notes
kimi-k2.5is validated more strictly than generic OpenAI-compatible models.- When
thinking=True,kimi-k2.5expectstemperature=1.0. - When
thinking=False,kimi-k2.5expectstemperature=0.6. - For
kimi-k2.5,top_pmust remain0.95,nmust remain1, and both penalties must remain0.0. - The integration accepts standard
tool_choicevalues for API compatibility. - Moonshot does not reliably force tool calls in live tests, so forced
tool_choiceis treated as unsupported in standard tests. - For
kimi-k2.5withthinking=True, tool forcing still must remaintool_choice="auto"or"none". - Moonshot builtin
$web_searchis rejected whenthinking=True.
Local Verification
uv run ruff check .
uv run mypy langchain_moonshot tests
uv run pytest tests/unit_tests/test_standard.py
RUN_MOONSHOT_INTEGRATION=1 uv run pytest tests/integration_tests/test_standard.py
RUN_MOONSHOT_INTEGRATION=1 uv run pytest tests/unit_tests/test_standard.py tests/integration_tests/test_standard.py -q > pytest_standard.txt 2>&1
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file langchain_moonshot-0.1.0.tar.gz.
File metadata
- Download URL: langchain_moonshot-0.1.0.tar.gz
- Upload date:
- Size: 39.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0d98b5ca0f707b631a138008087815990b8fc7e2cbc369205724ed5d322d056a
|
|
| MD5 |
6fa667734cb4b6f1cf30b6c9e7a8a8ae
|
|
| BLAKE2b-256 |
7edc4fbcb89c06259a18eb04f9d9229e6fc938011c060b82791e6e45d85f60e1
|
File details
Details for the file langchain_moonshot-0.1.0-py3-none-any.whl.
File metadata
- Download URL: langchain_moonshot-0.1.0-py3-none-any.whl
- Upload date:
- Size: 11.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.1 {"installer":{"name":"uv","version":"0.11.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f62d84ae7b0dcdd544c643778149437a632acd034c7f0e9e148f55285bf5796
|
|
| MD5 |
d365451d2338848f8854174b3ae3347d
|
|
| BLAKE2b-256 |
f02fcfab3472126a3532ddd3f68bf37205971d3fce1a7ec5aec2194b19bf3a40
|