mirror of
https://github.com/hoshikawa2/compass_backoffice.git
synced 2026-07-09 13:54:20 +00:00
113 lines
4.0 KiB
Python
113 lines
4.0 KiB
Python
"""
|
|
Local Langfuse client wrapper with enriched error handling.
|
|
|
|
The get_prompt_from_langfuse() method from agent_framework.prompts silently
|
|
captures all exceptions without indicating the root cause of the failure.
|
|
This module replaces that function with a wrapper that:
|
|
- Distinguishes between authentication errors, prompt not found, and network errors.
|
|
- Logs the root cause in a structured way.
|
|
- Supports retrieval by label (e.g. "production") instead of version "latest".
|
|
"""
|
|
|
|
import langfuse
|
|
from typing import Optional, Tuple
|
|
from src.core.logging import get_logger
|
|
from src.core.config import settings
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
def _build_httpx_client():
|
|
"""Mirror setup_observer's behavior: honor settings.OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE."""
|
|
cert_path = settings.OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE
|
|
if not cert_path:
|
|
return None
|
|
try:
|
|
import httpx
|
|
return httpx.Client(verify=cert_path)
|
|
except Exception as exc:
|
|
logger.warning("Failed to build httpx client for Langfuse provider: %s", exc)
|
|
return None
|
|
|
|
|
|
def get_prompt_with_config_from_langfuse(
|
|
prompt_name: str,
|
|
label: str = "production",
|
|
) -> Tuple[Optional[str], dict]:
|
|
"""
|
|
Fetches a text prompt + its `config` dict from Langfuse.
|
|
|
|
Langfuse permite anexar um objeto JSON `config` ao lado do corpo do
|
|
prompt (editável pela mesma UI). Usamos isso para guardar tuning
|
|
parameters que o squad de prompt-engineering pode ajustar sem deploy
|
|
(ex.: tamanho de janelas de histórico, thresholds, flags).
|
|
|
|
Args:
|
|
prompt_name: Nome do prompt registrado no Langfuse.
|
|
label: Label a recuperar (default: "production").
|
|
|
|
Returns:
|
|
Tupla `(content, config)`. `content=None` quando o prompt não foi
|
|
encontrado ou houve erro de rede/auth — nesses casos o caller deve
|
|
cair em fallback local. `config` é `{}` quando o prompt não tem
|
|
config setado.
|
|
"""
|
|
|
|
try:
|
|
client_kwargs = {
|
|
"public_key": settings.LANGFUSE_PUBLIC_KEY,
|
|
"secret_key": settings.LANGFUSE_SECRET_KEY,
|
|
"host": settings.LANGFUSE_BASE_URL,
|
|
}
|
|
httpx_client = _build_httpx_client()
|
|
if httpx_client is not None:
|
|
client_kwargs["httpx_client"] = httpx_client
|
|
client = langfuse.Langfuse(**client_kwargs)
|
|
except Exception as e:
|
|
logger.error(
|
|
"Failed to initialize the Langfuse client. Check LANGFUSE_PUBLIC_KEY, LANGFUSE_SECRET_KEY and LANGFUSE_BASE_URL. "
|
|
f"Error: {e}"
|
|
)
|
|
return None, {}
|
|
|
|
try:
|
|
prompt_obj = client.get_prompt(name=prompt_name, label=label)
|
|
except Exception as e:
|
|
logger.error(
|
|
f"Unexpected error while fetching prompt '{prompt_name}' from Langfuse: "
|
|
f"{type(e).__name__}: {e}"
|
|
)
|
|
return None, {}
|
|
|
|
# The Langfuse v3 SDK returns different types depending on the prompt type.
|
|
# For text prompts (type="text"), the content is in the .prompt attribute.
|
|
if prompt_obj is None:
|
|
logger.warning(f"Langfuse returned None for prompt '{prompt_name}'.")
|
|
return None, {}
|
|
|
|
# Try both known SDK attributes to ensure version compatibility.
|
|
content = getattr(prompt_obj, "prompt", None) or getattr(prompt_obj, "content", None)
|
|
|
|
if not content:
|
|
logger.warning(
|
|
f"Prompt '{prompt_name}' found but has no content. "
|
|
f"Available attributes: {[a for a in dir(prompt_obj) if not a.startswith('_')]}"
|
|
)
|
|
return None, {}
|
|
|
|
# `config` é opcional no Langfuse. Normalizamos para dict para que o
|
|
# caller possa sempre fazer `config.get(...)` sem checar tipo.
|
|
raw_config = getattr(prompt_obj, "config", None)
|
|
config = raw_config if isinstance(raw_config, dict) else {}
|
|
|
|
return content, config
|
|
|
|
|
|
def get_prompt_from_langfuse(
|
|
prompt_name: str,
|
|
label: str = "production",
|
|
) -> Optional[str]:
|
|
"""Backwards-compatible wrapper que ignora o `config` do prompt."""
|
|
content, _config = get_prompt_with_config_from_langfuse(prompt_name, label)
|
|
return content
|