Convert LLM generate_summary() methods to the more generic run_inference()
This commit is contained in:
@@ -50,19 +50,24 @@ class LLMSwitcher(ParallelPipeline, Generic[StrategyType]):
|
|||||||
self.llms = llms
|
self.llms = llms
|
||||||
self.strategy = strategy
|
self.strategy = strategy
|
||||||
|
|
||||||
async def generate_summary(self, summary_prompt: str, context: LLMContext) -> Optional[str]:
|
async def run_inference(
|
||||||
"""Generate a conversation summary from the given LLM context, using the currently active LLM.
|
self, context: LLMContext, system_instruction: Optional[str] = None
|
||||||
|
) -> Optional[str]:
|
||||||
|
"""Run a one-shot, out-of-band (i.e. out-of-pipeline) inference with the given LLM context, using the currently active LLM.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
summary_prompt: The prompt to use to guide generating the summary.
|
|
||||||
context: The LLM context containing conversation history.
|
context: The LLM context containing conversation history.
|
||||||
|
system_instruction: Optional system instruction to guide the LLM's
|
||||||
|
behavior. You could also (again, optionally) provide a system
|
||||||
|
instruction directly in the context. If both are provided, the
|
||||||
|
one in the context takes precedence.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The generated summary, or None if generation failed.
|
The LLM's response as a string, or None if no response is generated.
|
||||||
"""
|
"""
|
||||||
if self.strategy.active_llm:
|
if self.strategy.active_llm:
|
||||||
return await self.strategy.active_llm.generate_summary(
|
return await self.strategy.active_llm.run_inference(
|
||||||
summary_prompt=summary_prompt, context=context
|
context=context, system_instruction=system_instruction
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@@ -199,55 +199,45 @@ class AnthropicLLMService(LLMService):
|
|||||||
response = await api_call(**params)
|
response = await api_call(**params)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
async def generate_summary(
|
async def run_inference(
|
||||||
self, summary_prompt: str, context: LLMContext | OpenAILLMContext
|
self, context: LLMContext | OpenAILLMContext, system_instruction: Optional[str] = None
|
||||||
) -> Optional[str]:
|
) -> Optional[str]:
|
||||||
"""Generate a conversation summary from the given LLM context.
|
"""Run a one-shot, out-of-band (i.e. out-of-pipeline) inference with the given LLM context.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
summary_prompt: The prompt to use to guide generating the summary.
|
|
||||||
context: The LLM context containing conversation history.
|
context: The LLM context containing conversation history.
|
||||||
|
system_instruction: Optional system instruction to guide the LLM's
|
||||||
|
behavior. You could also (again, optionally) provide a system
|
||||||
|
instruction directly in the context. If both are provided, the
|
||||||
|
one in the context takes precedence.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The generated summary, or None if generation failed.
|
The LLM's response as a string, or None if no response is generated.
|
||||||
"""
|
"""
|
||||||
try:
|
messages = []
|
||||||
if isinstance(context, LLMContext):
|
system = []
|
||||||
# Not sure if it's strictly necessary to adapt messages here
|
if isinstance(context, LLMContext):
|
||||||
# since they'll just be a string in the prompt, but erring on
|
# Future code will be something like this:
|
||||||
# the side of putting them in the format the LLM would expect
|
# adapter = self.get_llm_adapter()
|
||||||
# if consuming them directly (i.e. assuming greater LLM
|
# params: AnthropicLLMInvocationParams = adapter.get_llm_invocation_params(context)
|
||||||
# familiarity with its own format).
|
# messages = params["messages"]
|
||||||
# adapter = self.get_llm_adapter()
|
# system = params["system_instruction"]
|
||||||
# params: AnthropicLLMInvocationParams = adapter.get_llm_invocation_params(context)
|
raise NotImplementedError("Universal LLMContext is not yet supported for Anthropic.")
|
||||||
# messages = params["messages"]
|
else:
|
||||||
raise NotImplementedError(
|
context = AnthropicLLMContext.upgrade_to_anthropic(context)
|
||||||
"Universal LLMContext is not yet supported for Anthropic."
|
messages = context.messages
|
||||||
)
|
system = getattr(context, "system", None) or system_instruction
|
||||||
else:
|
|
||||||
messages = context.messages
|
|
||||||
|
|
||||||
prompt_messages = [
|
# LLM completion
|
||||||
{
|
response = await self._client.messages.create(
|
||||||
"role": "user",
|
model=self.model_name,
|
||||||
"content": f"Conversation history: {messages}",
|
messages=messages,
|
||||||
},
|
system=system,
|
||||||
]
|
max_tokens=8192,
|
||||||
|
stream=False,
|
||||||
|
)
|
||||||
|
|
||||||
# LLM completion
|
return response.content[0].text
|
||||||
response = await self._client.messages.create(
|
|
||||||
model=self.model_name,
|
|
||||||
messages=prompt_messages,
|
|
||||||
system=summary_prompt,
|
|
||||||
max_tokens=8192,
|
|
||||||
stream=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
return response.content[0].text
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Anthropic summary generation failed: {e}", exc_info=True)
|
|
||||||
return None
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def enable_prompt_caching_beta(self) -> bool:
|
def enable_prompt_caching_beta(self) -> bool:
|
||||||
|
|||||||
@@ -791,33 +791,37 @@ class AWSBedrockLLMService(LLMService):
|
|||||||
"""
|
"""
|
||||||
return True
|
return True
|
||||||
|
|
||||||
async def generate_summary(
|
async def run_inference(
|
||||||
self, summary_prompt: str, context: LLMContext | OpenAILLMContext
|
self, context: LLMContext | OpenAILLMContext, system_instruction: Optional[str] = None
|
||||||
) -> Optional[str]:
|
) -> Optional[str]:
|
||||||
"""Generate a conversation summary from the given LLM context.
|
"""Run a one-shot, out-of-band (i.e. out-of-pipeline) inference with the given LLM context.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
summary_prompt: The prompt to use to guide generating the summary.
|
|
||||||
context: The LLM context containing conversation history.
|
context: The LLM context containing conversation history.
|
||||||
|
system_instruction: Optional system instruction to guide the LLM's
|
||||||
|
behavior. You could also (again, optionally) provide a system
|
||||||
|
instruction directly in the context. If both are provided, the
|
||||||
|
one in the context takes precedence.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The generated summary, or None if generation failed.
|
The LLM's response as a string, or None if no response is generated.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
messages = []
|
||||||
|
system = []
|
||||||
if isinstance(context, LLMContext):
|
if isinstance(context, LLMContext):
|
||||||
# Not sure if it's strictly necessary to adapt messages here
|
# Future code will be something like this:
|
||||||
# since they'll just be a string in the prompt, but erring on
|
|
||||||
# the side of putting them in the format the LLM would expect
|
|
||||||
# if consuming them directly (i.e. assuming greater LLM
|
|
||||||
# familiarity with its own format).
|
|
||||||
# adapter = self.get_llm_adapter()
|
# adapter = self.get_llm_adapter()
|
||||||
# params: AWSBedrockLLMInvocationParams = adapter.get_llm_invocation_params(context)
|
# params: AWSBedrockLLMInvocationParams = adapter.get_llm_invocation_params(context)
|
||||||
# messages = params["messages"]
|
# messages = params["messages"]
|
||||||
|
# system = params["system_instruction"]
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
"Universal LLMContext is not yet supported for AWS Bedrock."
|
"Universal LLMContext is not yet supported for AWS Bedrock."
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
context = AWSBedrockLLMContext.upgrade_to_bedrock(context)
|
||||||
messages = context.messages
|
messages = context.messages
|
||||||
|
system = getattr(context, "system", None) or system_instruction
|
||||||
|
|
||||||
# Determine if we're using Claude or Nova based on model ID
|
# Determine if we're using Claude or Nova based on model ID
|
||||||
model_id = self.model_name
|
model_id = self.model_name
|
||||||
@@ -825,12 +829,7 @@ class AWSBedrockLLMService(LLMService):
|
|||||||
# Prepare request parameters
|
# Prepare request parameters
|
||||||
request_params = {
|
request_params = {
|
||||||
"modelId": model_id,
|
"modelId": model_id,
|
||||||
"messages": [
|
"messages": messages,
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": [{"text": f"Conversation history: {messages}"}],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"inferenceConfig": {
|
"inferenceConfig": {
|
||||||
"maxTokens": 8192,
|
"maxTokens": 8192,
|
||||||
"temperature": 0.7,
|
"temperature": 0.7,
|
||||||
@@ -838,7 +837,8 @@ class AWSBedrockLLMService(LLMService):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
request_params["system"] = [{"text": summary_prompt}]
|
if system:
|
||||||
|
request_params["system"] = [{"text": system}]
|
||||||
|
|
||||||
async with self._aws_session.client(
|
async with self._aws_session.client(
|
||||||
service_name="bedrock-runtime", **self._aws_params
|
service_name="bedrock-runtime", **self._aws_params
|
||||||
|
|||||||
@@ -733,57 +733,49 @@ class GoogleLLMService(LLMService):
|
|||||||
def _create_client(self, api_key: str, http_options: Optional[HttpOptions] = None):
|
def _create_client(self, api_key: str, http_options: Optional[HttpOptions] = None):
|
||||||
self._client = genai.Client(api_key=api_key, http_options=http_options)
|
self._client = genai.Client(api_key=api_key, http_options=http_options)
|
||||||
|
|
||||||
async def generate_summary(
|
async def run_inference(
|
||||||
self, summary_prompt: str, context: LLMContext | OpenAILLMContext
|
self, context: LLMContext | OpenAILLMContext, system_instruction: Optional[str] = None
|
||||||
) -> Optional[str]:
|
) -> Optional[str]:
|
||||||
"""Generate a conversation summary from the given LLM context.
|
"""Run a one-shot, out-of-band (i.e. out-of-pipeline) inference with the given LLM context.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
summary_prompt: The prompt to use to guide generating the summary.
|
|
||||||
context: The LLM context containing conversation history.
|
context: The LLM context containing conversation history.
|
||||||
|
system_instruction: Optional system instruction to guide the LLM's
|
||||||
|
behavior. You could also (again, optionally) provide a system
|
||||||
|
instruction directly in the context. If both are provided, the
|
||||||
|
one in the context takes precedence.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The generated summary, or None if generation failed.
|
The LLM's response as a string, or None if no response is generated.
|
||||||
"""
|
"""
|
||||||
try:
|
messages = []
|
||||||
if isinstance(context, LLMContext):
|
system = []
|
||||||
# Not sure if it's strictly necessary to adapt messages here
|
if isinstance(context, LLMContext):
|
||||||
# since they'll just be a string in the prompt, but erring on
|
adapter = self.get_llm_adapter()
|
||||||
# the side of putting them in the format the LLM would expect
|
params: GeminiLLMInvocationParams = adapter.get_llm_invocation_params(context)
|
||||||
# if consuming them directly (i.e. assuming greater LLM
|
messages = params["messages"]
|
||||||
# familiarity with its own format).
|
system = params["system_instruction"]
|
||||||
adapter = self.get_llm_adapter()
|
else:
|
||||||
params: GeminiLLMInvocationParams = adapter.get_llm_invocation_params(context)
|
context = GoogleLLMContext.upgrade_to_google(context)
|
||||||
messages = params["messages"]
|
messages = context.messages
|
||||||
else:
|
system = getattr(context, "system_message", None) or system_instruction
|
||||||
messages = context.messages
|
|
||||||
|
|
||||||
# Format conversation history as user message
|
generation_config = GenerateContentConfig(system_instruction=system)
|
||||||
contents = [
|
|
||||||
Content(role="user", parts=[Part(text=f"Conversation history: {messages}")])
|
|
||||||
]
|
|
||||||
|
|
||||||
# Use summary_prompt as system instruction
|
# Use the new google-genai client's async method
|
||||||
generation_config = GenerateContentConfig(system_instruction=summary_prompt)
|
response = await self._client.aio.models.generate_content(
|
||||||
|
model=self._model_name,
|
||||||
|
contents=messages,
|
||||||
|
config=generation_config,
|
||||||
|
)
|
||||||
|
|
||||||
# Use the new google-genai client's async method
|
# Extract text from response
|
||||||
response = await self._client.aio.models.generate_content(
|
if response.candidates and response.candidates[0].content:
|
||||||
model=self._model_name,
|
for part in response.candidates[0].content.parts:
|
||||||
contents=contents,
|
if part.text:
|
||||||
config=generation_config,
|
return part.text
|
||||||
)
|
|
||||||
|
|
||||||
# Extract text from response
|
return None
|
||||||
if response.candidates and response.candidates[0].content:
|
|
||||||
for part in response.candidates[0].content.parts:
|
|
||||||
if part.text:
|
|
||||||
return part.text
|
|
||||||
|
|
||||||
return None
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Google summary generation failed: {e}", exc_info=True)
|
|
||||||
return None
|
|
||||||
|
|
||||||
def needs_mcp_alternate_schema(self) -> bool:
|
def needs_mcp_alternate_schema(self) -> bool:
|
||||||
"""Check if this LLM service requires alternate MCP schema.
|
"""Check if this LLM service requires alternate MCP schema.
|
||||||
|
|||||||
@@ -191,19 +191,23 @@ class LLMService(AIService):
|
|||||||
"""
|
"""
|
||||||
return self._adapter
|
return self._adapter
|
||||||
|
|
||||||
async def generate_summary(
|
async def run_inference(
|
||||||
self, summary_prompt: str, context: LLMContext | OpenAILLMContext
|
self, context: LLMContext | OpenAILLMContext, system_instruction: Optional[str] = None
|
||||||
) -> Optional[str]:
|
) -> Optional[str]:
|
||||||
"""Generate a conversation summary from the given LLM context.
|
"""Run a one-shot, out-of-band (i.e. out-of-pipeline) inference with the given LLM context.
|
||||||
|
|
||||||
|
Must be implemented by subclasses.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
summary_prompt: The prompt to use to guide generating the summary.
|
|
||||||
context: The LLM context containing conversation history.
|
context: The LLM context containing conversation history.
|
||||||
|
system_instruction: Optional system instruction to guide the LLM's
|
||||||
|
behavior. You could also (again, optionally) provide a system
|
||||||
|
instruction directly in the context.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The generated summary, or None if generation failed.
|
The LLM's response as a string, or None if no response is generated.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(f"generate_summary() not supported by {self.__class__.__name__}")
|
raise NotImplementedError(f"run_inference() not supported by {self.__class__.__name__}")
|
||||||
|
|
||||||
def create_context_aggregator(
|
def create_context_aggregator(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -245,53 +245,35 @@ class BaseOpenAILLMService(LLMService):
|
|||||||
params.update(self._settings["extra"])
|
params.update(self._settings["extra"])
|
||||||
return params
|
return params
|
||||||
|
|
||||||
async def generate_summary(
|
async def run_inference(
|
||||||
self, summary_prompt: str, context: LLMContext | OpenAILLMContext
|
self, context: LLMContext | OpenAILLMContext, system_instruction: Optional[str] = None
|
||||||
) -> Optional[str]:
|
) -> Optional[str]:
|
||||||
"""Generate a conversation summary from the given LLM context.
|
"""Run a one-shot, out-of-band (i.e. out-of-pipeline) inference with the given LLM context.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
summary_prompt: The prompt to use to guide generating the summary.
|
|
||||||
context: The LLM context containing conversation history.
|
context: The LLM context containing conversation history.
|
||||||
|
system_instruction: Optional system instruction to guide the LLM's
|
||||||
|
behavior. You could also (again, optionally) provide a system
|
||||||
|
instruction directly in the context.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
The generated summary, or None if generation failed.
|
The LLM's response as a string, or None if no response is generated.
|
||||||
"""
|
"""
|
||||||
try:
|
if isinstance(context, LLMContext):
|
||||||
if isinstance(context, LLMContext):
|
adapter = self.get_llm_adapter()
|
||||||
# Not sure if it's strictly necessary to adapt messages here
|
params: OpenAILLMInvocationParams = adapter.get_llm_invocation_params(context)
|
||||||
# since they'll just be a string in the prompt, but erring on
|
messages = params["messages"]
|
||||||
# the side of putting them in the format the LLM would expect
|
else:
|
||||||
# if consuming them directly (i.e. assuming greater LLM
|
messages = context.messages
|
||||||
# familiarity with its own format).
|
|
||||||
adapter = self.get_llm_adapter()
|
|
||||||
params: OpenAILLMInvocationParams = adapter.get_llm_invocation_params(context)
|
|
||||||
messages = params["messages"]
|
|
||||||
else:
|
|
||||||
messages = context.messages
|
|
||||||
prompt_messages = [
|
|
||||||
{
|
|
||||||
"role": "system",
|
|
||||||
"content": summary_prompt,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"role": "user",
|
|
||||||
"content": f"Conversation history: {messages}",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
# LLM completion
|
# LLM completion
|
||||||
response = await self._client.chat.completions.create(
|
response = await self._client.chat.completions.create(
|
||||||
model=self.model_name,
|
model=self.model_name,
|
||||||
messages=prompt_messages,
|
messages=messages,
|
||||||
stream=False,
|
stream=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
return response.choices[0].message.content
|
return response.choices[0].message.content
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"OpenAI summary generation failed: {e}", exc_info=True)
|
|
||||||
return None
|
|
||||||
|
|
||||||
async def _stream_chat_completions_specific_context(
|
async def _stream_chat_completions_specific_context(
|
||||||
self, context: OpenAILLMContext
|
self, context: OpenAILLMContext
|
||||||
|
|||||||
Reference in New Issue
Block a user