feat: Intelligence Pipeline v3 — full implementation
Multi-stage evidence-grounded inference architecture replacing the monolithic 9B model extraction pipeline. CPU-first specialist services handle routine extraction while the 9B vLLM model is preserved for semantic adjudication of ambiguous cases. Key components: - Capability-aware inference gateway (OpenAI-compatible + Ollama) - Endpoint registry with DB migrations and REST API - Sentence-aware document segmenter (property tests) - Deterministic financial parsing with offset integrity - Symbol resolution with ambiguity detection - Specialist service (GLiNER2, dynamic batching, K8s deployment) - Company-specific sentiment (FinBERT, calibration) - Retrieval-based novelty and duplicate detection - Confidence calibration pipeline - Deterministic routing engine (property tests) - 9B adjudication layer with VRAM gating - Stock-specific impact model (features, labels, baseline, trained) - Pipeline orchestrator (state machine, queues, leases, feature flags) - Bounded parallelism (async workers, semaphore, load shedding) - Observability (tracing, metrics, alerts) - Compatibility adapter (v3→v2 golden mapping tests) - Shadow/canary promotion framework - Active learning and fine-tuning pipeline Test results: 1,161 tests pass, ruff lint clean. All 282 spec tasks completed.
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
"""Inference client factory with protocol alias resolution.
|
||||
|
||||
Replaces the legacy VLLMClient/OllamaClient fallback pattern with a
|
||||
capability-aware routing layer. Unknown protocols ALWAYS fail closed —
|
||||
they never silently fall back to Ollama.
|
||||
|
||||
Requirements: 2.2, 2.6
|
||||
Design: Inference Gateway — profiles and capability probes
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import warnings
|
||||
|
||||
from services.shared.inference.clients.ollama_native import OllamaNativeClient
|
||||
from services.shared.inference.clients.openai_compatible import OpenAICompatibleClient
|
||||
from services.shared.inference.errors import InferenceError, InferenceErrorCategory
|
||||
from services.shared.inference.models import InferenceTarget
|
||||
|
||||
# Backward-compatible protocol aliases.
|
||||
# "vllm" is retained as a deprecated alias for "openai_chat".
|
||||
# "ollama" is retained as an alias for "ollama_native".
|
||||
PROTOCOL_ALIASES: dict[str, str] = {
|
||||
"vllm": "openai_chat",
|
||||
"ollama": "ollama_native",
|
||||
}
|
||||
|
||||
# Canonical protocol names that the factory can instantiate.
|
||||
KNOWN_PROTOCOLS: frozenset[str] = frozenset({
|
||||
"openai_chat",
|
||||
"ollama_native",
|
||||
"specialist_http",
|
||||
})
|
||||
|
||||
|
||||
def resolve_protocol(provider_name: str) -> str:
|
||||
"""Resolve a protocol name or alias to a canonical protocol.
|
||||
|
||||
Raises InferenceError(CAPABILITY_UNAVAILABLE) for unknown protocols.
|
||||
Emits a deprecation warning for the deprecated "vllm" alias.
|
||||
|
||||
Args:
|
||||
provider_name: Raw protocol/provider string (e.g. "vllm", "ollama_native").
|
||||
|
||||
Returns:
|
||||
Canonical protocol string.
|
||||
|
||||
Raises:
|
||||
InferenceError: If the protocol is unknown and cannot be resolved.
|
||||
"""
|
||||
normalized = provider_name.strip().lower()
|
||||
|
||||
# Check if it's already a known canonical protocol
|
||||
if normalized in KNOWN_PROTOCOLS:
|
||||
return normalized
|
||||
|
||||
# Check aliases
|
||||
if normalized in PROTOCOL_ALIASES:
|
||||
canonical = PROTOCOL_ALIASES[normalized]
|
||||
if normalized == "vllm":
|
||||
warnings.warn(
|
||||
"Provider 'vllm' is deprecated. Use protocol 'openai_chat' instead. "
|
||||
"The 'vllm' alias will be removed in a future version.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return canonical
|
||||
|
||||
# Unknown protocol — fail closed, NEVER fall back to Ollama
|
||||
raise InferenceError(
|
||||
InferenceErrorCategory.CAPABILITY_UNAVAILABLE,
|
||||
f"Unknown protocol: {normalized!r}. "
|
||||
f"Supported protocols: {sorted(KNOWN_PROTOCOLS)}. "
|
||||
f"Supported aliases: {sorted(PROTOCOL_ALIASES.keys())}.",
|
||||
)
|
||||
|
||||
|
||||
def create_client(
|
||||
target: InferenceTarget,
|
||||
) -> OpenAICompatibleClient | OllamaNativeClient:
|
||||
"""Create the appropriate inference client for the given target.
|
||||
|
||||
Routes based on the target's protocol field. If the protocol is an alias
|
||||
(e.g. "vllm"), it is resolved first. Unknown protocols raise a typed
|
||||
configuration error — they NEVER silently fall back to Ollama.
|
||||
|
||||
Args:
|
||||
target: Fully resolved inference target with protocol, URL, etc.
|
||||
|
||||
Returns:
|
||||
An OpenAICompatibleClient or OllamaNativeClient instance.
|
||||
|
||||
Raises:
|
||||
InferenceError: If the protocol is unknown or unsupported.
|
||||
"""
|
||||
protocol = resolve_protocol(target.protocol)
|
||||
|
||||
if protocol == "openai_chat":
|
||||
return OpenAICompatibleClient(target)
|
||||
|
||||
if protocol == "ollama_native":
|
||||
return OllamaNativeClient(target)
|
||||
|
||||
# specialist_http is a valid protocol but has no client implementation yet
|
||||
# (handled by a separate specialist service layer). Fail closed here.
|
||||
raise InferenceError(
|
||||
InferenceErrorCategory.CAPABILITY_UNAVAILABLE,
|
||||
f"Protocol {protocol!r} is recognized but has no client implementation in this factory. "
|
||||
f"Use the specialist HTTP service layer directly.",
|
||||
)
|
||||
Reference in New Issue
Block a user