Skip to content

Streaming LiteLLM model responses #932

Closed
Closed

Description

@frederikhendrix

I would like to see the possiblitliy of running a Ollama model ( or any other model wrapped in the LiteLLM(stream=True)) and that when calling:

async for event in runner.run_async(

we can get partial chunks from the model which it is currently streaming so agents instantiated with LiteLLM can also stream back to the webui.

Eventhough the lite_llm.py does contain:

async def generate_content_async(
      self, llm_request: LlmRequest, stream: bool = False
  ) -> AsyncGenerator[LlmResponse, None]:
    """Generates content asynchronously.

    Args:
      llm_request: LlmRequest, the request to send to the LiteLlm model.
      stream: bool = False, whether to do streaming call.

    Yields:
      LlmResponse: The model response.
    """

    self._maybe_append_user_content(llm_request)
    logger.debug(_build_request_log(llm_request))

    messages, tools = _get_completion_inputs(llm_request)

    completion_args = {
        "model": self.model,
        "messages": messages,
        "tools": tools,
    }
    completion_args.update(self._additional_args)

    if stream:
      text = ""
      function_name = ""
      function_args = ""
      function_id = None
      completion_args["stream"] = True
      aggregated_llm_response = None
      aggregated_llm_response_with_tool_call = None
      usage_metadata = None

      for part in self.llm_client.completion(**completion_args):
        for chunk, finish_reason in _model_response_to_chunk(part):
          if isinstance(chunk, FunctionChunk):
            if chunk.name:
              function_name += chunk.name
            if chunk.args:
              function_args += chunk.args
            function_id = chunk.id or function_id
          elif isinstance(chunk, TextChunk):
            text += chunk.text
            yield _message_to_generate_content_response(
                ChatCompletionAssistantMessage(
                    role="assistant",
                    content=chunk.text,
                ),
                is_partial=True,
            )
          elif isinstance(chunk, UsageMetadataChunk):
            usage_metadata = types.GenerateContentResponseUsageMetadata(
                prompt_token_count=chunk.prompt_tokens,
                candidates_token_count=chunk.completion_tokens,
                total_token_count=chunk.total_tokens,
            )

          if finish_reason == "tool_calls" and function_id:
            aggregated_llm_response_with_tool_call = (
                _message_to_generate_content_response(
                    ChatCompletionAssistantMessage(
                        role="assistant",
                        content="",
                        tool_calls=[
                            ChatCompletionMessageToolCall(
                                type="function",
                                id=function_id,
                                function=Function(
                                    name=function_name,
                                    arguments=function_args,
                                ),
                            )
                        ],
                    )
                )
            )
            function_name = ""
            function_args = ""
            function_id = None
          elif finish_reason == "stop" and text:
            aggregated_llm_response = _message_to_generate_content_response(
                ChatCompletionAssistantMessage(role="assistant", content=text)
            )
            text = ""

      # waiting until streaming ends to yield the llm_response as litellm tends
      # to send chunk that contains usage_metadata after the chunk with
      # finish_reason set to tool_calls or stop.
      if aggregated_llm_response:
        if usage_metadata:
          aggregated_llm_response.usage_metadata = usage_metadata
          usage_metadata = None
        yield aggregated_llm_response

      if aggregated_llm_response_with_tool_call:
        if usage_metadata:
          aggregated_llm_response_with_tool_call.usage_metadata = usage_metadata
        yield aggregated_llm_response_with_tool_call

    else:
      response = await self.llm_client.acompletion(**completion_args)
      yield _model_response_to_generate_content_response(response)

im not able to get the is partial as true.

Activity

  1. changed the title [-]Streaming LiteLLM model respones[/-] [+]Streaming LiteLLM model responses[/+] on May 25, 2025
  2. added
    models[Component] This issue is related to model support
    on May 26, 2025
  3. added theissue type on May 26, 2025
  4. surajksharma07 commented on Oct 7, 2025

    @surajksharma07
    Collaborator

    Hi @frederikhendrix and thanks to everyone who participated in this thread.

    We're currently doing some housekeeping on our issue tracker. Given the rapid pace of development and the number of updates since this was last active, there's a good chance this issue has been resolved in a newer version. To help us keep our backlog focused on current issues, we are closing this as stale.

    If you're still facing this problem, could you please update to the very latest version of the library and confirm the issue still exists? If it does, please comment here, and we will be happy to reopen this issue and investigate further.

    Thanks for your contribution and understanding!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

models[Component] This issue is related to model support

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions