Skip to content

Commit 2b50b43

Browse files
Support passing prompt_label to langfuse (#11018)
* fix: add prompt label support to prompt management hook * feat: support 'prompt_label' parameter for langfuse prompt management Closes #9003 (reply in thread) * fix(litellm_logging.py): deep copy optional params to avoid mutation while logging * fix(log-consistent-optional-param-values-across-providers): ensures params can be used for finetuning from providers * fix: fix linting error * test: update test * test: update langfuse tests * fix(litellm_logging.py): avoid deepcopying optional params might contain thread object
1 parent cd496fe commit 2b50b43

31 files changed

+116
-87
lines changed

litellm/integrations/anthropic_cache_control_hook.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ def get_chat_completion_prompt(
2828
prompt_id: Optional[str],
2929
prompt_variables: Optional[dict],
3030
dynamic_callback_params: StandardCallbackDynamicParams,
31+
prompt_label: Optional[str] = None,
3132
) -> Tuple[str, List[AllMessageValues], dict]:
3233
"""
3334
Apply cache control directives based on specified injection points.
@@ -79,10 +80,10 @@ def _process_message_injection(
7980
# Case 1: Target by specific index
8081
if targetted_index is not None:
8182
if 0 <= targetted_index < len(messages):
82-
messages[targetted_index] = (
83-
AnthropicCacheControlHook._safe_insert_cache_control_in_message(
84-
messages[targetted_index], control
85-
)
83+
messages[
84+
targetted_index
85+
] = AnthropicCacheControlHook._safe_insert_cache_control_in_message(
86+
messages[targetted_index], control
8687
)
8788
# Case 2: Target by role
8889
elif targetted_role is not None:

litellm/integrations/custom_logger.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ async def async_get_chat_completion_prompt(
8787
dynamic_callback_params: StandardCallbackDynamicParams,
8888
litellm_logging_obj: LiteLLMLoggingObj,
8989
tools: Optional[List[Dict]] = None,
90+
prompt_label: Optional[str] = None,
9091
) -> Tuple[str, List[AllMessageValues], dict]:
9192
"""
9293
Returns:
@@ -104,6 +105,7 @@ def get_chat_completion_prompt(
104105
prompt_id: Optional[str],
105106
prompt_variables: Optional[dict],
106107
dynamic_callback_params: StandardCallbackDynamicParams,
108+
prompt_label: Optional[str] = None,
107109
) -> Tuple[str, List[AllMessageValues], dict]:
108110
"""
109111
Returns:

litellm/integrations/custom_prompt_management.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ def get_chat_completion_prompt(
1818
prompt_id: Optional[str],
1919
prompt_variables: Optional[dict],
2020
dynamic_callback_params: StandardCallbackDynamicParams,
21+
prompt_label: Optional[str] = None,
2122
) -> Tuple[str, List[AllMessageValues], dict]:
2223
"""
2324
Returns:
@@ -43,6 +44,7 @@ def _compile_prompt_helper(
4344
prompt_id: str,
4445
prompt_variables: Optional[dict],
4546
dynamic_callback_params: StandardCallbackDynamicParams,
47+
prompt_label: Optional[str] = None,
4648
) -> PromptManagementClient:
4749
raise NotImplementedError(
4850
"Custom prompt management does not support compile prompt helper"

litellm/integrations/humanloop.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,8 @@ def get_chat_completion_prompt(
155155
prompt_id: Optional[str],
156156
prompt_variables: Optional[dict],
157157
dynamic_callback_params: StandardCallbackDynamicParams,
158-
) -> Tuple[
159-
str,
160-
List[AllMessageValues],
161-
dict,
162-
]:
158+
prompt_label: Optional[str] = None,
159+
) -> Tuple[str, List[AllMessageValues], dict,]:
163160
humanloop_api_key = dynamic_callback_params.get(
164161
"humanloop_api_key"
165162
) or get_secret_str("HUMANLOOP_API_KEY")

litellm/integrations/langfuse/langfuse_prompt_management.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,12 @@ def integration_name(self):
130130
return "langfuse"
131131

132132
def _get_prompt_from_id(
133-
self, langfuse_prompt_id: str, langfuse_client: LangfuseClass
133+
self,
134+
langfuse_prompt_id: str,
135+
langfuse_client: LangfuseClass,
136+
prompt_label: Optional[str] = None,
134137
) -> PROMPT_CLIENT:
135-
return langfuse_client.get_prompt(langfuse_prompt_id)
138+
return langfuse_client.get_prompt(langfuse_prompt_id, label=prompt_label)
136139

137140
def _compile_prompt(
138141
self,
@@ -176,18 +179,16 @@ async def async_get_chat_completion_prompt(
176179
dynamic_callback_params: StandardCallbackDynamicParams,
177180
litellm_logging_obj: LiteLLMLoggingObj,
178181
tools: Optional[List[Dict]] = None,
179-
) -> Tuple[
180-
str,
181-
List[AllMessageValues],
182-
dict,
183-
]:
182+
prompt_label: Optional[str] = None,
183+
) -> Tuple[str, List[AllMessageValues], dict,]:
184184
return self.get_chat_completion_prompt(
185185
model,
186186
messages,
187187
non_default_params,
188188
prompt_id,
189189
prompt_variables,
190190
dynamic_callback_params,
191+
prompt_label=prompt_label,
191192
)
192193

193194
def should_run_prompt_management(
@@ -211,6 +212,7 @@ def _compile_prompt_helper(
211212
prompt_id: str,
212213
prompt_variables: Optional[dict],
213214
dynamic_callback_params: StandardCallbackDynamicParams,
215+
prompt_label: Optional[str] = None,
214216
) -> PromptManagementClient:
215217
langfuse_client = langfuse_client_init(
216218
langfuse_public_key=dynamic_callback_params.get("langfuse_public_key"),
@@ -219,7 +221,9 @@ def _compile_prompt_helper(
219221
langfuse_host=dynamic_callback_params.get("langfuse_host"),
220222
)
221223
langfuse_prompt_client = self._get_prompt_from_id(
222-
langfuse_prompt_id=prompt_id, langfuse_client=langfuse_client
224+
langfuse_prompt_id=prompt_id,
225+
langfuse_client=langfuse_client,
226+
prompt_label=prompt_label,
223227
)
224228

225229
## SET PROMPT

litellm/integrations/prompt_management_base.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ def _compile_prompt_helper(
3333
prompt_id: str,
3434
prompt_variables: Optional[dict],
3535
dynamic_callback_params: StandardCallbackDynamicParams,
36+
prompt_label: Optional[str] = None,
3637
) -> PromptManagementClient:
3738
pass
3839

@@ -49,11 +50,13 @@ def compile_prompt(
4950
prompt_variables: Optional[dict],
5051
client_messages: List[AllMessageValues],
5152
dynamic_callback_params: StandardCallbackDynamicParams,
53+
prompt_label: Optional[str] = None,
5254
) -> PromptManagementClient:
5355
compiled_prompt_client = self._compile_prompt_helper(
5456
prompt_id=prompt_id,
5557
prompt_variables=prompt_variables,
5658
dynamic_callback_params=dynamic_callback_params,
59+
prompt_label=prompt_label,
5760
)
5861

5962
try:
@@ -82,6 +85,7 @@ def get_chat_completion_prompt(
8285
prompt_id: Optional[str],
8386
prompt_variables: Optional[dict],
8487
dynamic_callback_params: StandardCallbackDynamicParams,
88+
prompt_label: Optional[str] = None,
8589
) -> Tuple[str, List[AllMessageValues], dict]:
8690
if prompt_id is None:
8791
raise ValueError("prompt_id is required for Prompt Management Base class")
@@ -95,6 +99,7 @@ def get_chat_completion_prompt(
9599
prompt_variables=prompt_variables,
96100
client_messages=messages,
97101
dynamic_callback_params=dynamic_callback_params,
102+
prompt_label=prompt_label,
98103
)
99104

100105
completed_messages = prompt_template["completed_messages"] or messages

litellm/integrations/vector_stores/bedrock_vector_store.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ async def async_get_chat_completion_prompt(
7575
dynamic_callback_params: StandardCallbackDynamicParams,
7676
litellm_logging_obj: LiteLLMLoggingObj,
7777
tools: Optional[List[Dict]] = None,
78+
prompt_label: Optional[str] = None,
7879
) -> Tuple[str, List[AllMessageValues], dict]:
7980
"""
8081
Retrieves the context from the Bedrock Knowledge Base and appends it to the messages.
@@ -99,10 +100,11 @@ async def async_get_chat_completion_prompt(
99100
f"Bedrock Knowledge Base Response: {bedrock_kb_response}"
100101
)
101102

102-
context_message, context_string = (
103-
self.get_chat_completion_message_from_bedrock_kb_response(
104-
bedrock_kb_response
105-
)
103+
(
104+
context_message,
105+
context_string,
106+
) = self.get_chat_completion_message_from_bedrock_kb_response(
107+
bedrock_kb_response
106108
)
107109
if context_message is not None:
108110
messages.append(context_message)
@@ -126,9 +128,9 @@ async def async_get_chat_completion_prompt(
126128
)
127129
)
128130

129-
litellm_logging_obj.model_call_details["vector_store_request_metadata"] = (
130-
vector_store_request_metadata
131-
)
131+
litellm_logging_obj.model_call_details[
132+
"vector_store_request_metadata"
133+
] = vector_store_request_metadata
132134

133135
return model, messages, non_default_params
134136

@@ -140,9 +142,9 @@ def transform_bedrock_kb_response_to_vector_store_search_response(
140142
"""
141143
Transform a BedrockKBResponse to a VectorStoreSearchResponse
142144
"""
143-
retrieval_results: Optional[List[BedrockKBRetrievalResult]] = (
144-
bedrock_kb_response.get("retrievalResults", None)
145-
)
145+
retrieval_results: Optional[
146+
List[BedrockKBRetrievalResult]
147+
] = bedrock_kb_response.get("retrievalResults", None)
146148
vector_store_search_response: VectorStoreSearchResponse = (
147149
VectorStoreSearchResponse(search_query=query, data=[])
148150
)

litellm/litellm_core_utils/litellm_logging.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ def get_chat_completion_prompt(
539539
prompt_id: Optional[str],
540540
prompt_variables: Optional[dict],
541541
prompt_management_logger: Optional[CustomLogger] = None,
542+
prompt_label: Optional[str] = None,
542543
) -> Tuple[str, List[AllMessageValues], dict]:
543544
custom_logger = (
544545
prompt_management_logger
@@ -559,6 +560,7 @@ def get_chat_completion_prompt(
559560
prompt_id=prompt_id,
560561
prompt_variables=prompt_variables,
561562
dynamic_callback_params=self.standard_callback_dynamic_params,
563+
prompt_label=prompt_label,
562564
)
563565
self.messages = messages
564566
return model, messages, non_default_params
@@ -572,6 +574,7 @@ async def async_get_chat_completion_prompt(
572574
prompt_variables: Optional[dict],
573575
prompt_management_logger: Optional[CustomLogger] = None,
574576
tools: Optional[List[Dict]] = None,
577+
prompt_label: Optional[str] = None,
575578
) -> Tuple[str, List[AllMessageValues], dict]:
576579
custom_logger = (
577580
prompt_management_logger
@@ -594,6 +597,7 @@ async def async_get_chat_completion_prompt(
594597
dynamic_callback_params=self.standard_callback_dynamic_params,
595598
litellm_logging_obj=self,
596599
tools=tools,
600+
prompt_label=prompt_label,
597601
)
598602
self.messages = messages
599603
return model, messages, non_default_params

litellm/main.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
get_optional_params_image_gen,
9898
get_optional_params_transcription,
9999
get_secret,
100+
get_standard_openai_params,
100101
mock_completion_streaming_obj,
101102
read_config_args,
102103
supports_httpx_timeout,
@@ -428,6 +429,7 @@ async def acompletion(
428429
prompt_id=kwargs.get("prompt_id", None),
429430
prompt_variables=kwargs.get("prompt_variables", None),
430431
tools=tools,
432+
prompt_label=kwargs.get("prompt_label", None),
431433
)
432434

433435
#########################################################
@@ -983,6 +985,7 @@ def completion( # type: ignore # noqa: PLR0915
983985
assistant_continue_message=assistant_continue_message,
984986
)
985987
######## end of unpacking kwargs ###########
988+
standard_openai_params = get_standard_openai_params(params=args)
986989
non_default_params = get_non_default_completion_params(kwargs=kwargs)
987990
litellm_params = {} # used to prevent unbound var errors
988991
## PROMPT MANAGEMENT HOOKS ##
@@ -1001,6 +1004,7 @@ def completion( # type: ignore # noqa: PLR0915
10011004
non_default_params=non_default_params,
10021005
prompt_id=prompt_id,
10031006
prompt_variables=prompt_variables,
1007+
prompt_label=kwargs.get("prompt_label", None),
10041008
)
10051009

10061010
try:
@@ -1234,10 +1238,13 @@ def completion( # type: ignore # noqa: PLR0915
12341238
max_retries=max_retries,
12351239
timeout=timeout,
12361240
)
1237-
logging.update_environment_variables(
1241+
cast(LiteLLMLoggingObj, logging).update_environment_variables(
12381242
model=model,
12391243
user=user,
1240-
optional_params=optional_params,
1244+
optional_params={
1245+
**standard_openai_params,
1246+
**non_default_params,
1247+
}, # [IMPORTANT] - using standard_openai_params ensures consistent params logged to langfuse for finetuning / eval datasets.
12411248
litellm_params=litellm_params,
12421249
custom_llm_provider=custom_llm_provider,
12431250
)

litellm/proxy/_new_secret_config.yaml

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
model_list:
2-
- model_name: "gemini-2.0-flash"
2+
- model_name: "gemini-2.0-flash-gemini"
33
litellm_params:
4-
model: gemini/gemini-2.0-flash-live-001
5-
- model_name: "gpt-4.1-openai"
4+
model: gemini/gemini-2.0-flash
5+
- model_name: "gpt-4o-mini-openai"
66
litellm_params:
77
model: gpt-4.1-mini-2025-04-14
88
api_key: os.environ/OPENAI_API_KEY
@@ -71,6 +71,16 @@ model_list:
7171
model: mistral/*
7272
api_key: os.environ/MISTRAL_API_KEY
7373
access_groups: ["beta-models"]
74+
- model_name: my-langfuse-model
75+
litellm_params:
76+
model: langfuse/gpt-3.5-turbo
77+
prompt_id: "jokes"
78+
prompt_label: "latest"
79+
api_key: os.environ/OPENAI_API_KEY
7480

7581
litellm_settings:
76-
cache: true
82+
callbacks: ["langfuse"]
83+
84+
general_settings:
85+
store_model_in_db: true
86+
store_prompts_in_spend_logs: true

0 commit comments

Comments
 (0)