{"id":37077737,"url":"https://github.com/liux2/langchain-llm-config","last_synced_at":"2026-01-14T09:01:08.150Z","repository":{"id":302091011,"uuid":"1010880367","full_name":"liux2/Langchain-LLM-Config","owner":"liux2","description":"Langchain LLM config adapters","archived":false,"fork":false,"pushed_at":"2025-12-23T07:35:57.000Z","size":1314,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-12-23T13:57:23.201Z","etag":null,"topics":["chat","embeddings","gemini","infinity","langchain","llm","openai","vllm"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/liux2.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-30T01:22:58.000Z","updated_at":"2025-12-23T07:36:00.000Z","dependencies_parsed_at":"2025-08-08T14:15:52.951Z","dependency_job_id":"9116bde4-86b1-4ebd-8030-eca1dab6d6b8","html_url":"https://github.com/liux2/Langchain-LLM-Config","commit_stats":null,"previous_names":["liux2/langchain-llm-config"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/liux2/Langchain-LLM-Config","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liux2%2FLangchain-LLM-Config","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liux2%2FLangchain-LLM-Config/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liux2%2FLangchain-LLM-Config/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liux2%2FLangchain-LLM-Config/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/liux2","download_url":"https://codeload.github.com/liux2/Langchain-LLM-Config/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/liux2%2FLangchain-LLM-Config/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28414732,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-14T08:38:59.149Z","status":"ssl_error","status_checked_at":"2026-01-14T08:38:43.588Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chat","embeddings","gemini","infinity","langchain","llm","openai","vllm"],"created_at":"2026-01-14T09:01:07.354Z","updated_at":"2026-01-14T09:01:08.135Z","avatar_url":"https://github.com/liux2.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Langchain LLM Config\n\nYet another redundant Langchain abstraction: comprehensive Python package for managing and using multiple LLM providers (OpenAI, VLLM, Gemini, Infinity) with a unified interface for both chat assistants and embeddings.\n\n[![PyPI version](https://badge.fury.io/py/langchain-llm-config.svg)](https://badge.fury.io/py/langchain-llm-config) [![Python package](https://github.com/liux2/Langchain-LLM-Config/actions/workflows/python-package.yml/badge.svg?branch=main)](https://github.com/liux2/Langchain-LLM-Config/actions/workflows/python-package.yml)\n\n## Features\n\n- 🤖 **Multiple Chat Providers**: Support for OpenAI, VLLM, and Gemini\n- 🔗 **Multiple Embedding Providers**: Support for OpenAI, VLLM, and Infinity\n- ⚙️ **Unified Configuration**: Single YAML configuration file for all providers\n- 🚀 **Easy Setup**: CLI tool for quick configuration initialization\n- 🔄 **Easy Context Concatenation**: Simplified process for combining contexts into chat\n- 🔒 **Environment Variables**: Secure API key management\n- 📦 **Self-Contained**: No need to import specific paths\n- ⚡ **Async Support**: Full async/await support for all operations\n- 🌊 **Streaming Chat**: Real-time streaming responses for interactive experiences\n- 🛠️ **Enhanced CLI**: Environment setup and validation commands\n- 🪶 **Lightweight Core**: Minimal dependencies with optional provider-specific packages\n- 🎯 **Flexible Installation**: Install only the providers you need\n\n## What's New in V2 Configuration\n\nThe V2 configuration format introduces a **model-centric** approach that provides:\n\n### Key Benefits\n\n- ✅ **Simpler API**: Reference models by name instead of provider/type hierarchy\n- ✅ **More Flexible**: Define multiple models per provider with different configurations\n- ✅ **Better Defaults**: Set default models by name, not provider\n- ✅ **VLM Support**: Ready for vision-language models with dedicated `vlm` type\n- ✅ **Clearer Structure**: Each model is a first-class entity with its own config\n- ✅ **Easy Migration**: One command to migrate from V1 to V2\n\n### Quick Comparison\n\n**V1 (Old):**\n\n```python\n# Provider-centric: specify provider name\nassistant = create_assistant(provider=\"openai\", ...)\n```\n\n**V2 (New):**\n\n```python\n# Model-centric: specify model name\nassistant = create_assistant(model=\"gpt-4-turbo\", ...)\n```\n\nSee the [Configuration Reference](#configuration-reference) section for detailed examples.\n\n## Installation\n\n### Basic Installation\n\nThe package has a lightweight core with optional dependencies for specific providers.\n\n**Core installation (minimal dependencies):**\n\n```bash\n# Using uv (recommended)\nuv add langchain-llm-config\n\n# Using pip\npip install langchain-llm-config\n```\n\n### Provider-Specific Installation\n\n**With OpenAI support:**\n\n```bash\nuv add \"langchain-llm-config[openai]\"\npip install \"langchain-llm-config[openai]\"\n```\n\n**With VLLM support:**\n\n```bash\nuv add \"langchain-llm-config[vllm]\"\npip install \"langchain-llm-config[vllm]\"\n```\n\n**With Gemini support:**\n\n```bash\nuv add \"langchain-llm-config[gemini]\"\npip install \"langchain-llm-config[gemini]\"\n```\n\n**With Infinity embeddings support:**\n\n```bash\nuv add \"langchain-llm-config[infinity]\"\npip install \"langchain-llm-config[infinity]\"\n```\n\n**With local models support (sentence-transformers):**\n\n```bash\nuv add \"langchain-llm-config[local-models]\"\npip install \"langchain-llm-config[local-models]\"\n```\n\n### Convenience Groups\n\n**All assistant providers (OpenAI, VLLM, Gemini):**\n\n```bash\nuv add \"langchain-llm-config[assistants]\"\npip install \"langchain-llm-config[assistants]\"\n```\n\n**All embedding providers (Infinity, local models):**\n\n```bash\nuv add \"langchain-llm-config[embeddings]\"\npip install \"langchain-llm-config[embeddings]\"\n```\n\n**Everything (all providers and features):**\n\n```bash\nuv add \"langchain-llm-config[all]\"\npip install \"langchain-llm-config[all]\"\n```\n\n### Development Installation\n\n```bash\ngit clone https://github.com/liux2/Langchain-LLM-Config.git\ncd langchain-llm-config\nuv sync --dev\nuv run pip install -e .\n```\n\n## Dependency Optimization\n\nThis package is designed with a **lightweight core** approach:\n\n### Core Dependencies (Always Installed)\n\n- `langchain-core` - Core abstractions only (much lighter than full `langchain`)\n- `langchain-openai` - OpenAI and VLLM provider support\n- `pydantic` - Data validation and parsing\n- `pyyaml` - Configuration file parsing\n- `python-dotenv` - Environment variable management\n- `openai` - OpenAI client library\n\n### Optional Dependencies\n\n- **Gemini**: `langchain-google-genai` - Only installed with `[gemini]` extra\n- **Infinity**: `langchain-community` - Only installed with `[infinity]` extra\n- **Local Models**: `sentence-transformers` - Only installed with `[local-models]` extra\n\n### Benefits\n\n- ✅ **Smaller installation size** - No heavy ML dependencies unless needed\n- ✅ **Faster installation** - Skip unnecessary packages\n- ✅ **Cleaner environments** - Only install what you use\n- ✅ **Better compatibility** - Avoid conflicts from unused dependencies\n\n## Quick Start\n\n### 1. Initialize Configuration\n\n```bash\n# Initialize config in current directory (v2 format by default)\nllm-config init\n\n# Or specify a custom location\nllm-config init ~/.config/api.yaml\n\n# Use legacy v1 format (deprecated)\nllm-config init --format v1\n```\n\nThis creates an `api.yaml` file with all supported providers configured using the new **v2 model-centric format**.\n\n### 2. Set Up Environment Variables\n\n```bash\n# Set up environment variables and create .env file\nllm-config setup-env\n\n# Or with custom config path\nllm-config setup-env --config-path ~/.config/.env\n```\n\nThis creates a `.env` file with placeholders for your API keys.\n\n### 3. Configure Your Providers\n\nEdit the generated `api.yaml` file with your API keys and settings.\n\n#### V2 Configuration Format (Recommended)\n\nThe new **model-centric** configuration format allows you to define models independently:\n\n```yaml\n# Default models to use\ndefault:\n  chat_provider: gpt-3.5-turbo\n  embedding_provider: text-embedding-ada-002\n\n# Model definitions\nmodels:\n  gpt-3.5-turbo:\n    model_type: chat\n    provider_type: openai\n    model_config:\n      api_base: https://api.openai.com/v1\n      api_key: ${OPENAI_API_KEY}\n      model_name: gpt-3.5-turbo\n      temperature: 0.7\n      max_tokens: 8192\n\n  text-embedding-ada-002:\n    model_type: embedding\n    provider_type: openai\n    model_config:\n      api_base: https://api.openai.com/v1\n      api_key: ${OPENAI_API_KEY}\n      model_name: text-embedding-ada-002\n\n  llama-2-local:\n    model_type: chat\n    provider_type: vllm\n    model_config:\n      api_base: http://localhost:8000/v1\n      api_key: ${OPENAI_API_KEY}\n      model_name: meta-llama/Llama-2-7b-chat-hf\n      temperature: 0.6\n      extra_body:\n        return_reasoning: false  # Set to true for reasoning output\n```\n\n#### V1 Configuration Format (Legacy, Auto-Converted)\n\nThe old provider-centric format is still supported but deprecated:\n\n```yaml\nllm:\n  openai:\n    chat:\n      api_base: \"https://api.openai.com/v1\"\n      api_key: \"${OPENAI_API_KEY}\"\n      model_name: \"gpt-3.5-turbo\"\n  default:\n    chat_provider: \"openai\"\n```\n\n**Note:** V1 configs are automatically converted to V2 at runtime with a deprecation warning.\n\n### 4. Set Environment Variables\n\nEdit the `.env` file with your actual API keys:\n\n```bash\nOPENAI_API_KEY=your-openai-api-key\nGEMINI_API_KEY=your-gemini-api-key\n```\n\n### 5. Use in Your Code\n\n#### Basic Usage (Synchronous)\n\n```python\nfrom langchain_llm_config import create_assistant, create_embedding_provider\nfrom pydantic import BaseModel, Field\nfrom typing import List\n\n\n# Define your response model\nclass ArticleAnalysis(BaseModel):\n    summary: str = Field(..., description=\"Article summary\")\n    keywords: List[str] = Field(..., description=\"Key topics\")\n    sentiment: str = Field(..., description=\"Overall sentiment\")\n\n\n# V2 API: Use model names directly (recommended)\nassistant = create_assistant(\n    model=\"gpt-3.5-turbo\",  # Reference model by name from config\n    response_model=ArticleAnalysis,\n    system_prompt=\"You are a helpful article analyzer.\",\n)\n\n# Use the assistant - returns dict with parsed data\n# Note: Structured output returns a dict, not a Pydantic model instance\nresult = assistant.ask(\"Analyze this article: ...\")\nprint(result[\"summary\"])  # Access as dict\nprint(result[\"keywords\"])\nprint(result[\"sentiment\"])\n\n# Raw text mode (no structured output)\nassistant_raw = create_assistant(\n    model=\"gpt-3.5-turbo\",\n    auto_apply_parser=False,  # Disable parsing\n    system_prompt=\"You are a helpful assistant.\",\n)\nresult = assistant_raw.ask(\"Tell me a joke\")\nprint(result)  # Returns string\n\n# Create an embedding provider\nembedding_provider = create_embedding_provider(\n    model=\"text-embedding-ada-002\"  # Reference model by name\n)\n\n# Get embeddings (synchronous)\ntexts = [\"Hello world\", \"How are you?\"]\nembeddings = embedding_provider.embed_texts(texts)\n\n# V1 API: Still supported (deprecated)\nassistant_v1 = create_assistant(\n    provider=\"openai\",  # Old way - provider name\n    response_model=ArticleAnalysis,\n)\n```\n\n#### Advanced Usage (Asynchronous)\n\n```python\nimport asyncio\n\n# Use the assistant (asynchronous)\nresult = await assistant.ask_async(\"Analyze this article: ...\")\nprint(result[\"summary\"])\n\n# Get embeddings (asynchronous)\nembeddings = await embedding_provider.embed_texts_async(texts)\n```\n\n#### Streaming Chat\n\n```python\nimport asyncio\nfrom langchain_llm_config import create_assistant\n\n\nasync def main():\n    \"\"\"Main async function to run the streaming chat example\"\"\"\n    # Create assistant with auto_apply_parser=False for streaming\n    assistant = create_assistant(\n        provider=\"openai\",\n        system_prompt=\"You are a helpful assistant.\",\n        auto_apply_parser=False,  # Required for streaming\n    )\n\n    print(\"🤖 Starting streaming chat...\")\n    print(\"Response: \", end=\"\", flush=True)\n\n    try:\n        # Simple streaming - just get text chunks\n        async for chunk in assistant.chat_async(\"Tell me a story\"):\n            print(chunk, end=\"\", flush=True)\n\n        print(\"\\n\")\n\n        # Advanced streaming - get chunks with metadata\n        async for chunk in assistant.chat_stream(\"Explain quantum computing\"):\n            if chunk[\"type\"] == \"stream\":\n                print(chunk[\"content\"], end=\"\", flush=True)\n            elif chunk[\"type\"] == \"final\":\n                print(f\"\\n\\nProcessing time: {chunk['processing_time']:.2f}s\")\n                print(f\"Model used: {chunk['model_used']}\")\n    except Exception as e:\n        print(f\"\\n❌ Error occurred: {e}\")\n\n\nif __name__ == \"__main__\":\n    # Run the async function\n    asyncio.run(main())\n```\n\n#### Kunlun API (Bearer Token Authentication)\n\nKunlun APIs are OpenAI-compatible but use bearer token authentication instead of API keys.\n\n```python\nfrom langchain_llm_config import create_assistant, create_embedding_provider\nfrom pydantic import BaseModel, Field\n\n# Define your response model\nclass Analysis(BaseModel):\n    summary: str = Field(description=\"Brief summary\")\n    key_points: list[str] = Field(description=\"Key points\")\n\n# Create Kunlun assistant with thinking mode enabled\nassistant = create_assistant(\n    model=\"kunlun-qwen3-235b\",\n    response_model=Analysis,\n    system_prompt=\"You are a helpful AI assistant.\"\n)\n\n# Use the assistant\nresult = assistant.ask(\"Analyze the impact of AI on society\")\nprint(result[\"summary\"])\nprint(result[\"key_points\"])\n\n# Create Kunlun embedding provider\nembedding_provider = create_embedding_provider(model=\"kunlun-bge-m3\")\nembeddings = embedding_provider.embed_texts([\"Hello world\", \"AI is amazing\"])\n```\n\n**Configuration:**\n\n```yaml\nmodels:\n  kunlun-qwen3-235b:\n    model_type: chat\n    provider_type: kunlun\n    model_config:\n      api_base: ${KUNLUN_QWEN3_235B_API_BASE}  # Your Kunlun API endpoint\n      bearer_token: ${KUNLUN_BEARER_TOKEN}\n      model_name: Qwen3-235B-A22B\n      temperature: 0.7\n      max_tokens: 8000\n      extra_body:\n        chat_template_kwargs:\n          enable_thinking: true  # Enable reasoning mode\n\n  kunlun-bge-m3:\n    model_type: embedding\n    provider_type: kunlun\n    model_config:\n      api_base: ${KUNLUN_BGE_M3_API_BASE}  # Your Kunlun API endpoint\n      bearer_token: ${KUNLUN_BEARER_TOKEN}\n      model_name: embedding\n      dimensions: 1024\n```\n\n**Environment Variables:**\n\n```bash\nexport KUNLUN_BEARER_TOKEN=\"your_jwt_token_here\"\nexport KUNLUN_QWEN3_235B_API_BASE=\"https://your-kunlun-endpoint/v1\"\nexport KUNLUN_BGE_M3_API_BASE=\"https://your-kunlun-endpoint/v1\"\n```\n\n**Key Features:**\n\n- 🔐 **Bearer Token Authentication**: Uses JWT tokens instead of API keys\n- 🧠 **Thinking Mode**: Enable reasoning with `chat_template_kwargs.enable_thinking`\n- 🔌 **OpenAI-Compatible**: Works with standard OpenAI API format\n- 🚀 **Full Feature Support**: Streaming, structured output, embeddings\n\n## Supported Providers\n\n### Chat Providers\n\n| Provider | Models | Features | Installation |\n|----------|--------|----------|-------------|\n| **OpenAI** | GPT-3.5, GPT-4, etc. | Streaming, function calling, structured output | ✅ Core (always available) |\n| **VLLM** | Any HuggingFace model | Local deployment, high performance | ✅ Core (always available) |\n| **Gemini** | Gemini Pro, etc. | Google's latest models | 📦 `[gemini]` extra required |\n| **Kunlun** | Qwen3, etc. | Bearer token auth, thinking mode | ✅ Core (always available) |\n\n### Embedding Providers\n\n| Provider | Models | Features | Installation |\n|----------|--------|----------|-------------|\n| **OpenAI** | text-embedding-ada-002, etc. | High quality, reliable | ✅ Core (always available) |\n| **VLLM** | BGE, sentence-transformers | Local deployment | ✅ Core (always available) |\n| **Infinity** | Various embedding models | Fast inference | 📦 `[infinity]` extra required |\n| **Kunlun** | BGE, Qwen3-Embedding, etc. | Bearer token auth | ✅ Core (always available) |\n\n## CLI Commands\n\n```bash\n# Initialize a new configuration file (v2 format by default)\nllm-config init [path]\nllm-config init --format v2  # Explicit v2 format\nllm-config init --format v1  # Legacy v1 format\n\n# Migrate v1 config to v2 format\nllm-config migrate [--output path]\n\n# Set up environment variables and create .env file\nllm-config setup-env [path] [--force]\n\n# Validate existing configuration\nllm-config validate [path]\n\n# Show package information\nllm-config info\n```\n\n## Advanced Usage\n\n### Custom Configuration Path\n\n```python\nfrom langchain_llm_config import create_assistant\n\nassistant = create_assistant(\n    response_model=MyModel,\n    config_path=\"/path/to/custom/api.yaml\"\n)\n```\n\n### Context-Aware Conversations\n\n```python\n# Add context to your queries\nresult = await assistant.ask_async(\n    query=\"What are the main points?\",\n    context=\"This is a research paper about machine learning...\",\n    extra_system_prompt=\"Focus on technical details.\"\n)\n```\n\n### Direct Provider Usage\n\n```python\nfrom langchain_llm_config import VLLMAssistant, OpenAIEmbeddingProvider\n\n# Core providers (always available)\nvllm_assistant = VLLMAssistant(\n    config={\"api_base\": \"http://localhost:8000/v1\", \"model_name\": \"llama-2\"},\n    response_model=MyModel\n)\n\nopenai_embeddings = OpenAIEmbeddingProvider(\n    config={\"api_key\": \"your-key\", \"model_name\": \"text-embedding-ada-002\"}\n)\n\n# Optional providers (require extras)\n# from langchain_llm_config import GeminiAssistant  # requires [gemini]\n# from langchain_llm_config import InfinityEmbeddingProvider  # requires [infinity]\n```\n\n### Complete Example with Error Handling\n\n```python\nimport asyncio\nfrom langchain_llm_config import create_assistant, create_embedding_provider\nfrom pydantic import BaseModel, Field\nfrom typing import List\n\nclass ChatResponse(BaseModel):\n    message: str = Field(..., description=\"The assistant's response message\")\n    confidence: float = Field(..., description=\"Confidence score\", ge=0.0, le=1.0)\n    suggestions: List[str] = Field(default_factory=list, description=\"Follow-up questions\")\n\nasync def main():\n    try:\n        # Create assistant\n        assistant = create_assistant(\n            response_model=ChatResponse,\n            provider=\"openai\",\n            system_prompt=\"You are a helpful AI assistant.\"\n        )\n        \n        # Chat conversation\n        response = await assistant.ask_async(\"What is the capital of France?\")\n        print(f\"Assistant: {response['message']}\")\n        print(f\"Confidence: {response['confidence']:.2f}\")\n        \n        # Create embedding provider\n        embedding_provider = create_embedding_provider(provider=\"openai\")\n        \n        # Get embeddings\n        texts = [\"Hello world\", \"How are you?\"]\n        embeddings = await embedding_provider.embed_texts_async(texts)\n        print(f\"Generated {len(embeddings)} embeddings\")\n        \n    except Exception as e:\n        print(f\"Error: {e}\")\n\n# Run the example\nasyncio.run(main())\n```\n\n## Configuration Reference\n\n### Environment Variables\n\nThe package supports environment variable substitution in configuration:\n\n```yaml\napi_key: \"${OPENAI_API_KEY}\"  # Will be replaced with actual value\n```\n\n### V2 Configuration Structure (Recommended)\n\nModel-centric configuration where each model is defined independently:\n\n```yaml\n# Default models\ndefault:\n  chat_provider: model-name      # Model name for chat\n  embedding_provider: model-name # Model name for embeddings\n\n# Model definitions\nmodels:\n  model-name:\n    model_type: chat | embedding | vlm\n    provider_type: openai | vllm | gemini | infinity | reasoning\n    model_config:\n      api_base: \"https://api.example.com/v1\"\n      api_key: \"${API_KEY}\"\n      model_name: \"actual-model-name\"\n      temperature: 0.7\n      max_tokens: 8192\n      top_p: 1.0\n      connect_timeout: 60\n      read_timeout: 60\n      extra_body:\n        return_reasoning: false  # Enable reasoning output (vLLM)\n      # ... other provider-specific parameters\n```\n\n### V1 Configuration Structure (Legacy)\n\nProvider-centric configuration (automatically converted to v2 at runtime):\n\n```yaml\nllm:\n  provider_name:\n    chat:\n      api_base: \"https://api.example.com/v1\"\n      api_key: \"${API_KEY}\"\n      model_name: \"model-name\"\n      # ... parameters\n    embeddings:\n      api_base: \"https://api.example.com/v1\"\n      api_key: \"${API_KEY}\"\n      model_name: \"embedding-model\"\n  default:\n    chat_provider: \"provider_name\"\n    embedding_provider: \"provider_name\"\n```\n\n### Migration from V1 to V2\n\nUse the CLI migration tool:\n\n```bash\n# Migrate and create backup\nllm-config migrate\n\n# Specify output path\nllm-config migrate --output api_v2.yaml\n```\n\nOr manually update your config following the v2 structure above.\n\n## Development\n\n### Testing with Different Provider Combinations\n\n```bash\n# Test core functionality only\nuv sync --extra test\nuv run pytest\n\n# Test with all providers\nuv sync --extra test --extra all\nuv run pytest\n\n# Test specific provider combinations\nuv sync --extra test --extra gemini\nuv run pytest tests/test_providers.py -k gemini\n```\n\n### Running Tests\n\n```bash\nuv run pytest\n```\n\n### Code Formatting\n\n```bash\nuv run black .\nuv run isort .\n```\n\n### Type Checking\n\n```bash\nuv run mypy .\n```\n\n## Contributing\n\n1. Fork the repository\n2. Create a feature branch\n3. Make your changes\n4. Add tests\n5. Submit a pull request\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n## Support\n\n- 📖 [Documentation](https://github.com/liux2/Langchain-LLM-Config#readme)\n- 🐛 [Issue Tracker](https://github.com/liux2/Langchain-LLM-Config/issues)\n- 💬 [Discussions](https://github.com/liux2/Langchain-LLM-Config/discussions)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliux2%2Flangchain-llm-config","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fliux2%2Flangchain-llm-config","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fliux2%2Flangchain-llm-config/lists"}