Skip to content

Conversation

@mahdibayouli
Copy link
Collaborator

✅ Enable Drop-in Local LLM (LM Studio) Support & Robust Test Isolation

✨ Summary

This PR adds first-class LM Studio support as a drop-in OpenAI replacement and overhauls the test suite for fully isolated, fast testing. All changes are backwards-compatible with OpenAI cloud.


🚀 Features

🔁 Drop-in LLM Support

  • Switch via .env:
    LLM_PROVIDER=lmstudio
    OPENAI_API_BASE=http://host.docker.internal:1234/v1
    OPENAI_API_KEY=local-key
    OPENAI_MODEL=qwen1.5-7b-chat
  • No new env vars needed
  • Works with OpenAI-compatible models (e.g. qwen1.5-7b-chat)

📦 Structured Output Fallback

  • OpenAI-style structured output fallback:
    • openai_parser → function_calling → strict_json_prompt

🧠 Local Embeddings

  • Uses langchain_huggingface + sentence_transformers
  • All dependencies included in Docker images

🧪 Test Suite Overhaul

  • Fully mocked external services (LLM, Weaviate, etc.)
  • In-process FastAPI tests (no network calls)
  • Centralized config via pytest.ini
  • Test strategy documented in tests/README.md

🛠️ Changed Files (Highlights)

File Description
llm_service.py Adds robust fallback for structured output
embedder_service.py Switches to local HuggingFace embeddings
requirements.txt, Dockerfile Ensures all deps for local LLM/embedding
tests/, pytest.ini New isolated test infra
.env.example, README.md Updated usage guides and configs

⚙️ Usage

🖥️ LM Studio (Local)

  1. Run LM Studio.
  2. Set .env as shown above.
  3. Rebuild & restart GenAI container.

☁️ OpenAI (Cloud)

Use regular OpenAI env settings.

🧪 Run Tests

pytest -q

📝 Notes

  • Switching embedding provider may require Weaviate schema reset.
  • Structured output with LM Studio may have some limitations (see README).

@mahdibayouli mahdibayouli self-assigned this Jul 20, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds drop-in local LLM support via LM Studio as an OpenAI-compatible alternative and implements comprehensive test isolation infrastructure. The changes maintain full backward compatibility with OpenAI cloud services while enabling local development workflows.

Key changes include:

  • LM Studio integration with robust structured output fallback mechanisms
  • Local HuggingFace embeddings as an alternative to OpenAI embeddings
  • Comprehensive test suite with mocked external dependencies for fast, isolated testing

Reviewed Changes

Copilot reviewed 13 out of 14 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
llm_service.py Adds LM Studio provider support and multi-tier structured output fallback
embedder_service.py Implements provider-aware embedding selection (OpenAI vs HuggingFace)
requirements.txt Adds langchain_huggingface dependency for local embeddings
Dockerfile Installs sentence_transformers and langchain-huggingface packages
pytest.ini Configures test discovery and exclusion patterns
genai/tests/* New isolated test suite with comprehensive mocking
.env.example Updates configuration examples for LM Studio setup
README.md Adds detailed LM Studio setup and usage documentation

openai_api_base=os.getenv("OPENAI_API_BASE", "http://127.0.0.1:1234/v1"),
)

if provider in ("openai", "llmstudio", "local"):
Copy link

Copilot AI Jul 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conditional check includes 'llmstudio' but this case is already handled by the previous condition on line 25. This creates unreachable code for the 'llmstudio' case in this block.

Suggested change
if provider in ("openai", "llmstudio", "local"):
if provider in ("openai", "local"):

Copilot uses AI. Check for mistakes.
assert client is not None
return object()

monkeypatch.setenv("LLM_PROVIDER", "local")
Copy link

Copilot AI Jul 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line duplicates the setenv call from line 7. The duplicate environment variable setting is unnecessary.

Suggested change
monkeypatch.setenv("LLM_PROVIDER", "local")

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,42 @@
# tests/conftest.py
Copy link

Copilot AI Jul 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file comment indicates this is 'tests/conftest.py' but the actual file is 'test_api.py'. This misleading comment should be corrected.

Suggested change
# tests/conftest.py
# genai/tests/test_api.py - Test cases and fixtures for API testing

Copilot uses AI. Check for mistakes.
# Install curl & the new embeddings lib
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl \
&& pip install --no-cache-dir sentence_transformers langchain-huggingface \
Copy link

Copilot AI Jul 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Installing packages directly in the runtime stage bypasses dependency management. Consider adding these to requirements.txt and installing via the existing pip install command for consistency.

Copilot uses AI. Check for mistakes.
}

resp = client.chat.completions.create(
model=os.getenv("OPENAI_MODEL"),
Copy link

Copilot AI Jul 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The model parameter could be None if OPENAI_MODEL environment variable is not set, which may cause the OpenAI client to fail. Consider providing a default value.

Suggested change
model=os.getenv("OPENAI_MODEL"),
model=os.getenv("OPENAI_MODEL", "gpt-4o-mini"),

Copilot uses AI. Check for mistakes.

if provider == "openai":
embeddings_model = OpenAIEmbeddings(model="text-embedding-3-small")
else: # lmstudio → local HF model
Copy link

Copilot AI Jul 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment suggests this path is only for 'lmstudio' but the condition catches any non-openai provider. Consider making the condition more explicit or updating the comment to reflect the broader scope.

Suggested change
else: # lmstudio → local HF model
else: # Handles all non-"openai" providers (e.g., lmstudio → local HF model)

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

@GravityDarkLab GravityDarkLab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests works - tested with act - can skip piplines as they taking long

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants