Add comprehensive documentation and templates for LangChain skill development
- Introduced a new reference document for streaming output issues, detailing the differences between streaming APIs and providing solutions for common problems. - Created a structured output issues reference, outlining the use of `with_structured_output`, `response_format`, and schema enforcement strategies. - Added a user query convention guide to standardize structured questions for skill authors, including block types for queries and data gathering. - Implemented a template for a chat model, encapsulating API key management, request payload construction, and response handling. - Established a symlink for the LangChain dev guide in the Claude skills directory for easier access. - Initialized a skills lock file to manage dependencies and versions for the LangChain dev guide.
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
# CN Model Integration Guide
|
||||
|
||||
Help developers write LangChain integration classes for a specified Chinese model (e.g., Qwen, GLM, DeepSeek, Moonshot) using the OpenAI-compatible interface.
|
||||
|
||||
> [!CAUTION]
|
||||
> **Never read, write, or access user configuration files such as `.env`, `.env.local`, `credentials.json`, or any other files that may contain secrets or sensitive information.** API Keys and other credentials must always be filled in by the user themselves — do not peek into or modify these files under any circumstances.
|
||||
|
||||
## Step 1: Gather Information
|
||||
|
||||
Confirm the following details with the user. If the user does not explicitly provide any of these, use reasonable defaults from the provider's documentation.
|
||||
|
||||
<!-- gather
|
||||
prompt: "Confirm the following details for the model integration:"
|
||||
fields:
|
||||
- name: model_name
|
||||
question: "Model name (lowercase, used for directory and class names)"
|
||||
example: "qwen"
|
||||
required: true
|
||||
- name: api_base
|
||||
question: "API base URL (OpenAI-compatible endpoint)"
|
||||
example: "https://dashscope.aliyuncs.com/compatible-mode/v1"
|
||||
required: true
|
||||
- name: api_key_env
|
||||
question: "API key environment variable name"
|
||||
example: "QWEN_API_KEY"
|
||||
required: true
|
||||
fallback: "Use reasonable defaults from the provider's documentation."
|
||||
-->
|
||||
|
||||
1. **Model Name** — lowercase, e.g., `qwen`, `glm`, `deepseek`. Used for directory names, class names, and `_llm_type`.
|
||||
2. **API Base URL** — the model's OpenAI-compatible endpoint URL.
|
||||
3. **API Key Environment Variable Name** — e.g., `QWEN_API_KEY`.
|
||||
|
||||
Additionally, inspect the project directory structure to determine the Python package manager (`uv.lock` → uv, `poetry.lock` → poetry, `requirements.txt` → pip, etc.).
|
||||
|
||||
## Step 2: Create Directory and Files
|
||||
|
||||
1. Create a top-level directory `<models_dir>/`.
|
||||
2. Create a model subdirectory `<models_dir>/<model_name>/` with `model_name` in lowercase.
|
||||
3. Keep the top-level `<models_dir>/__init__.py` empty.
|
||||
|
||||
```
|
||||
<models_dir>/
|
||||
├── __init__.py # empty
|
||||
├── <model_name>/
|
||||
│ ├── __init__.py
|
||||
│ └── chat_model.py
|
||||
└── ...
|
||||
```
|
||||
|
||||
## Step 3: Check if DeepSeek
|
||||
|
||||
**If the model is DeepSeek**, install `langchain-deepseek` and use `ChatDeepSeek` directly. Skip all subsequent steps.
|
||||
|
||||
**If the model is another provider**, continue with the steps below.
|
||||
|
||||
## Step 4: Copy the Template
|
||||
|
||||
1. Check whether `langchain-openai` is installed; install it if not.
|
||||
2. Copy the template from [../../template/chat_model.py](../../template/chat_model.py) into the target subdirectory.
|
||||
3. Create `__init__.py`: `from .chat_model import <CHAT_CLASS_NAME>`
|
||||
|
||||
## Step 5: Replace Placeholders
|
||||
|
||||
Use grep to list all placeholders, then replace each one with the actual value:
|
||||
|
||||
| Placeholder | Description | Example (Qwen) |
|
||||
|-------------|-------------|----------------|
|
||||
| `ChatModel` | Class name | `ChatQwen` |
|
||||
| `PROVIDER_API_KEY` | API Key env var name | `QWEN_API_KEY` |
|
||||
| `PROVIDER_API_BASE` | API Base env var name | `QWEN_API_BASE` |
|
||||
| `PROVIDER_API_BASE_URL` | Default API URL | `https://dashscope.aliyuncs.com/compatible-mode/v1` |
|
||||
| `chat-provider` | Model identifier for `_llm_type` | `chat-qwen` |
|
||||
| `provider-name` | Value for `response_metadata["model_provider"]` | `dashscope` |
|
||||
| `Provider` | Provider display name for error messages | `Qwen` |
|
||||
|
||||
Each placeholder is a standalone, complete token — simply do a global find-and-replace. Apply replacements in both `chat_model.py` and `__init__.py`.
|
||||
|
||||
## Step 6: Configure Model Profile (Optional)
|
||||
|
||||
Use `langchain-model-profiles` to download profile information for the model provider. `<provider_name>` is the provider name; try a few likely candidates.
|
||||
|
||||
1. Check whether `langchain-model-profiles` is installed; install it if not.
|
||||
2. Run the download command:
|
||||
|
||||
```bash
|
||||
langchain-profiles refresh --provider <provider_name> --data-dir ./<models_dir>/<model_name>/data
|
||||
```
|
||||
|
||||
On success, a `data/_profiles.py` file is generated under the model directory, which is used by `_get_default_model_profile` in the template. If you cannot find the corresponding provider after several attempts, skip this step.
|
||||
|
||||
## Step 7: Write Integration Tests
|
||||
|
||||
After the model class is complete, you must write integration tests. See the detailed guide at [integration-tests.md](integration-tests.md).
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **Before running integration tests, you must remind the user to edit the `.env` file themselves and fill in the required API Key and other environment variables.**
|
||||
>
|
||||
> When running tests, you will likely encounter common setup issues (package not importable, async test mode, etc.). Refer to the "Common Issues" section at the end of [integration-tests.md](integration-tests.md) for fixes.
|
||||
@@ -0,0 +1,117 @@
|
||||
# Chat Model Integration Tests
|
||||
|
||||
After writing `chat_model.py`, you must write integration tests to verify the model class works correctly.
|
||||
|
||||
## Test Framework
|
||||
|
||||
Use `ChatModelIntegrationTests` from `langchain_tests` as the base class, and run tests with pytest.
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```bash
|
||||
pip install langchain-tests pytest python-dotenv
|
||||
```
|
||||
|
||||
## Test File Structure
|
||||
|
||||
Place test files following standard unit test directory conventions:
|
||||
|
||||
```
|
||||
src/<models_dir>/<model_name>/
|
||||
├── __init__.py
|
||||
├── chat_model.py
|
||||
└── ...
|
||||
|
||||
tests/
|
||||
└── test_chat_<model_name>.py
|
||||
```
|
||||
|
||||
## Standard Test Class
|
||||
|
||||
For a new provider (e.g., Qwen, GLM), create a test class that inherits from `ChatModelIntegrationTests` and provides the following properties:
|
||||
|
||||
```python
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
from dotenv import load_dotenv
|
||||
from langchain_core.language_models import BaseChatModel
|
||||
from langchain_tests.integration_tests import ChatModelIntegrationTests
|
||||
|
||||
from models.qwen.chat_model import ChatQwen # replace with the actual import path
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
class TestChatQwen(ChatModelIntegrationTests):
|
||||
@property
|
||||
def chat_model_class(self) -> type[BaseChatModel]:
|
||||
return ChatQwen
|
||||
|
||||
@property
|
||||
def chat_model_params(self) -> dict:
|
||||
return {
|
||||
"model": "qwen-plus",
|
||||
"temperature": 0,
|
||||
}
|
||||
```
|
||||
|
||||
### Required Properties
|
||||
|
||||
| Property | Description |
|
||||
|----------|-------------|
|
||||
| `chat_model_class` | Returns the chat model class under test. |
|
||||
| `chat_model_params` | Parameters for creating an instance. Must include `model`; `temperature: 0` is recommended for deterministic results. |
|
||||
|
||||
## Running Tests
|
||||
|
||||
```bash
|
||||
# Run tests for a single model
|
||||
pytest tests/test_chat_<model_name>.py -v
|
||||
|
||||
# Skip tests marked as xfail (run only expected passes)
|
||||
pytest tests/test_chat_<model_name>.py -v -m "not xfail"
|
||||
|
||||
# Run all model tests
|
||||
pytest tests/ -v
|
||||
```
|
||||
|
||||
## Common Issues
|
||||
|
||||
After setting up the test, you will likely encounter the following issues. Address them before concluding tests pass.
|
||||
|
||||
### Model package not importable
|
||||
|
||||
By default, the `<models_dir>/` directory is not installed as a Python package, so `from <models_dir>.xxx import ...` in tests will fail. Two changes are needed in `pyproject.toml`:
|
||||
|
||||
**1) Add build-system config:**
|
||||
|
||||
```toml
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["<models_dir>"]
|
||||
```
|
||||
|
||||
**2) Install in editable mode:**
|
||||
|
||||
```bash
|
||||
uv pip install -e .
|
||||
```
|
||||
|
||||
Without this, pytest fails with `ModuleNotFoundError: No module named '<models_dir>'`.
|
||||
|
||||
### Async tests not running (pytest-asyncio strict mode)
|
||||
|
||||
pytest-asyncio defaults to `Mode.STRICT`, which requires every async test to have an `@pytest.mark.asyncio` decorator. `langchain_tests` async methods lack this decorator.
|
||||
|
||||
Add to `pyproject.toml`:
|
||||
|
||||
```toml
|
||||
[tool.pytest.ini_options]
|
||||
asyncio_mode = "auto"
|
||||
```
|
||||
|
||||
Without this, all async tests (`test_ainvoke`, `test_astream`, `test_abatch`, etc.) fail with "async def functions are not natively supported."
|
||||
Reference in New Issue
Block a user