stash - langsmith use batching for logging

This commit is contained in:
Ishaan Jaff 2024-09-11 08:06:56 -07:00
parent ce5182710f
commit 2fa9709af0
2 changed files with 84 additions and 47 deletions

View file

@ -55,8 +55,7 @@ def is_serializable(value):
class LangsmithLogger(CustomLogger): class LangsmithLogger(CustomLogger):
# Class variables or attributes def __init__(self, batch_size=1):
def __init__(self):
self.langsmith_api_key = os.getenv("LANGSMITH_API_KEY") self.langsmith_api_key = os.getenv("LANGSMITH_API_KEY")
self.langsmith_project = os.getenv("LANGSMITH_PROJECT", "litellm-completion") self.langsmith_project = os.getenv("LANGSMITH_PROJECT", "litellm-completion")
self.langsmith_default_run_name = os.getenv( self.langsmith_default_run_name = os.getenv(
@ -68,6 +67,8 @@ class LangsmithLogger(CustomLogger):
self.async_httpx_client = get_async_httpx_client( self.async_httpx_client = get_async_httpx_client(
llm_provider=httpxSpecialProvider.LoggingCallback llm_provider=httpxSpecialProvider.LoggingCallback
) )
self.batch_size = batch_size
self.log_queue = []
def _prepare_log_data(self, kwargs, response_obj, start_time, end_time): def _prepare_log_data(self, kwargs, response_obj, start_time, end_time):
import datetime import datetime
@ -102,7 +103,7 @@ class LangsmithLogger(CustomLogger):
project_name = metadata.get("project_name", self.langsmith_project) project_name = metadata.get("project_name", self.langsmith_project)
run_name = metadata.get("run_name", self.langsmith_default_run_name) run_name = metadata.get("run_name", self.langsmith_default_run_name)
run_id = metadata.get("id", None) run_id = metadata.get("id", None) or str(random.randint(1000, 9999))
parent_run_id = metadata.get("parent_run_id", None) parent_run_id = metadata.get("parent_run_id", None)
trace_id = metadata.get("trace_id", None) trace_id = metadata.get("trace_id", None)
session_id = metadata.get("session_id", None) session_id = metadata.get("session_id", None)
@ -174,48 +175,31 @@ class LangsmithLogger(CustomLogger):
return data return data
async def async_log_success_event(self, kwargs, response_obj, start_time, end_time): def _send_batch(self):
try: if not self.log_queue:
sampling_rate = ( return
float(os.getenv("LANGSMITH_SAMPLING_RATE"))
if os.getenv("LANGSMITH_SAMPLING_RATE") is not None
and os.getenv("LANGSMITH_SAMPLING_RATE").strip().isdigit()
else 1.0
)
random_sample = random.random()
if random_sample > sampling_rate:
verbose_logger.info(
"Skipping Langsmith logging. Sampling rate={}, random_sample={}".format(
sampling_rate, random_sample
)
)
return # Skip logging
verbose_logger.debug(
"Langsmith Async Layer Logging - kwargs: %s, response_obj: %s",
kwargs,
response_obj,
)
data = self._prepare_log_data(kwargs, response_obj, start_time, end_time)
url = f"{self.langsmith_base_url}/runs"
verbose_logger.debug(f"Langsmith Logging - About to send data to {url} ...")
headers = {"x-api-key": self.langsmith_api_key} url = f"{self.langsmith_base_url}/runs/batch"
response = await self.async_httpx_client.post( headers = {"x-api-key": self.langsmith_api_key}
url=url, json=data, headers=headers
try:
response = requests.post(
url=url,
json=self.log_queue,
headers=headers,
) )
if response.status_code >= 300: if response.status_code >= 300:
verbose_logger.error( verbose_logger.error(
f"Langmsith Error: {response.status_code} - {response.text}" f"Langsmith Error: {response.status_code} - {response.text}"
) )
else: else:
verbose_logger.debug( verbose_logger.debug(
"Run successfully created, response=%s", response.text f"Batch of {len(self.log_queue)} runs successfully created"
) )
verbose_logger.debug(
f"Langsmith Layer Logging - final response object: {response_obj}. Response text from langsmith={response.text}" self.log_queue.clear()
) except Exception as e:
except:
verbose_logger.error(f"Langsmith Layer Error - {traceback.format_exc()}") verbose_logger.error(f"Langsmith Layer Error - {traceback.format_exc()}")
def log_success_event(self, kwargs, response_obj, start_time, end_time): def log_success_event(self, kwargs, response_obj, start_time, end_time):
@ -240,23 +224,73 @@ class LangsmithLogger(CustomLogger):
response_obj, response_obj,
) )
data = self._prepare_log_data(kwargs, response_obj, start_time, end_time) data = self._prepare_log_data(kwargs, response_obj, start_time, end_time)
url = f"{self.langsmith_base_url}/runs" self.log_queue.append(data)
verbose_logger.debug(f"Langsmith Logging - About to send data to {url} ...")
response = requests.post( if len(self.log_queue) >= self.batch_size:
self._send_batch()
except:
verbose_logger.error(f"Langsmith Layer Error - {traceback.format_exc()}")
async def async_log_success_event(self, kwargs, response_obj, start_time, end_time):
try:
sampling_rate = (
float(os.getenv("LANGSMITH_SAMPLING_RATE"))
if os.getenv("LANGSMITH_SAMPLING_RATE") is not None
and os.getenv("LANGSMITH_SAMPLING_RATE").strip().isdigit()
else 1.0
)
random_sample = random.random()
if random_sample > sampling_rate:
verbose_logger.info(
"Skipping Langsmith logging. Sampling rate={}, random_sample={}".format(
sampling_rate, random_sample
)
)
return # Skip logging
verbose_logger.debug(
"Langsmith Async Layer Logging - kwargs: %s, response_obj: %s",
kwargs,
response_obj,
)
data = self._prepare_log_data(kwargs, response_obj, start_time, end_time)
self.log_queue.append(data)
if len(self.log_queue) >= self.batch_size:
await self._async_send_batch()
except:
verbose_logger.error(f"Langsmith Layer Error - {traceback.format_exc()}")
async def _async_send_batch(self):
import json
if not self.log_queue:
return
url = f"{self.langsmith_base_url}/runs/batch"
headers = {"x-api-key": self.langsmith_api_key}
try:
response = await self.async_httpx_client.post(
url=url, url=url,
json=data, json={
headers={"x-api-key": self.langsmith_api_key}, "post": self.log_queue,
},
headers=headers,
) )
if response.status_code >= 300: if response.status_code >= 300:
verbose_logger.error(f"Error: {response.status_code} - {response.text}") verbose_logger.error(
f"Langsmith Error: {response.status_code} - {response.text}"
)
else: else:
verbose_logger.debug("Run successfully created") verbose_logger.debug(
verbose_logger.debug( f"Batch of {len(self.log_queue)} runs successfully created"
f"Langsmith Layer Logging - final response object: {response_obj}. Response text from langsmith={response.text}" )
)
except: self.log_queue.clear()
except Exception as e:
verbose_logger.error(f"Langsmith Layer Error - {traceback.format_exc()}") verbose_logger.error(f"Langsmith Layer Error - {traceback.format_exc()}")
def get_run_by_id(self, run_id): def get_run_by_id(self, run_id):

View file

@ -14,3 +14,6 @@ model_list:
general_settings: general_settings:
master_key: sk-1234 master_key: sk-1234
litellm_settings:
success_callback: ["langsmith"]