LLM Client Integration for LangChain with Chain-of-Thought Support
This package provides a seamless integration between custom LLM clients (e.g., DeepSeek, GLM, Qwen) and LangChain’s BaseChatModel, with built-in support for chain-of-thought (CoT) reasoning, structured output parsing, and both synchronous/asynchronous streaming.
Designed for developers who want fine-grained control over LLM interactions while leveraging LangChain’s ecosystem (e.g., callbacks, astream_events, tools, agents), this implementation wraps any OpenAI-compatible API into a fully compliant LangChain chat model.
📦 Features
- ✅ LangChain-Compatible Chat Model: Implements
BaseChatModelwith full support for sync/async, streaming/non-streaming. - 🔗 Chain-of-Thought (Thinking) Mode: Enable or disable CoT reasoning per model (GLM, Qwen, DeepSeek).
- 🧠 Custom Message Types:
ChatMessageandChatMessageChunkpreserve raw LLM responses (ChatCompletion/ChatCompletionChunk). - 📐 Structured Output Parsing:
SchemaParsergenerates schema-aware prompts and robustly parses LLM responses into Pydantic models. - ⚙️ Flexible LLM Client: Configurable base URL, API key fallbacks, and dynamic reconfiguration.
- 🌐 Streaming Support: Full compatibility with LangChain’s event streaming (
astream_events, callbacks).
🗂️ Project Structure
lingua-agent/
├── pyproject.toml # ← MUST contain project metadata & deps
├── README.md
├── LICENSE
└── src/
└── lingua_agent/ # ← top-level package name
├── __init__.py
├── llm_api/ # ← core LLM integration
│ ├── __init__.py
│ ├── llm_client.py
│ ├── llm_client_chat_model.py
│ ├── message_chunk.py
│ └── thinking_config.py
└── utils/ # ← helpers
├── __init__.py
└── schema_parse.py
🚀 Quick Start
1. Install Dependencies
pip install langchain-core openai pydantic
2. Initialize the LLM Client
from llm_client import LLMClient
llm_client = LLMClient(
model="deepseek-chat",
api_key="your-api-key",
enable_thinking=True # Enable chain-of-thought if supported
)
3. Wrap as LangChain Chat Model
from llm_client_chat_model import LLMClientChatModel
chat_model = LLMClientChatModel(llm_client=llm_client)
4. Use with LangChain
from langchain_core.messages import HumanMessage
# Non-streaming
response = chat_model.invoke([HumanMessage(content="Explain quantum computing.")])
print(response.content)
# Streaming
for chunk in chat_model.stream([HumanMessage(content="Write a haiku.")]):
print(chunk.content, end="", flush=True)
5. Parse Structured Output
from pydantic import BaseModel
from schema_parser import SchemaParser
class Answer(BaseModel):
summary: str
keywords: list[str]
parser = SchemaParser(Answer)
prompt = parser.schema_generation_prompt + "\n\nUser: Summarize climate change."
response = chat_model.invoke([HumanMessage(content=prompt)])
answer: Answer = parser.parse_response_to_base_model(response.content)
🔧 Configuration
Supported Models & CoT Parameters
| Model Prefix | Enable Thinking | Disable Thinking |
|---|---|---|
glm |
{"thinking": {"type": "enabled"}} |
{"thinking": {"type": "disabled"}} |
qwen |
{"enable_thinking": True} |
{"enable_thinking": False} |
deepseek |
{} (no extra params) |
{} |
The
LLMClientauto-detects model type and injects parameters viaextra_body.
API Key Resolution
The client checks environment variables in order:
DEEPSEEK_API_KEYOPENAI_API_KEYZHIPU_API_KEYAPI_KEY
📝 Notes
- Streaming Merge:
merge_chunks_to_completion()reconstructs fullChatCompletionfrom chunks, including usage stats and custom fields likereasoning_content. - Error Resilience:
SchemaParseruses fallback strategies to extract JSON from LLM responses (code blocks, raw JSON). - Callbacks: Fully supports LangChain’s callback system (
on_llm_new_token,astream_events, etc.).
📜 License
MIT License — feel free to use, modify, and distribute.
Built for researchers and developers who need reliable, structured, and introspectable LLM interactions within the LangChain framework.
Release files for LangLLM 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| langllm-0.1.0.tar.gz | 10.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| langllm-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 23.6 kB
Release files / langllm-0.1.0.tar.gz
| Download URL | langllm-0.1.0.tar.gz |
|---|---|
| Size | 10.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9222dc3a548f0c0f98503d55da7864038f58ed1222cf11290daacc6ef5f412fb
|
|
BLAKE2b-256 checksum How to use checksums |
84632f96a53b282316323a506171b999f25ac49a2a0fcee21e121313c1ac9220
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|
Release files / langllm-0.1.0-py3-none-any.whl
| Download URL | langllm-0.1.0-py3-none-any.whl |
|---|---|
| Size | 13.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c1ca91a8d296dca67aebfcc1bfb3460a665e6c772f3633ac65120d59756a5d78
|
|
BLAKE2b-256 checksum How to use checksums |
d1e36e6819c6b057f5c2b7af6bca9635f3de794444a3dca8e96eb47b4d0fd4b3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.3
|