Behaviours in Elixir (at least) are about contracts. In this case, about making an _explicit_contract for others to implement. This idea (of contracts) is transversal to any programing paradigm you may use, be it OO, FP LP or something even crazier.
The idea here is that the rules of a good Architecture, which are based on defining boundaries and contracts are paradigm independent. Thus, it follows that Elixir/Erlang would need some way to define contracts - which came in the form of behaviours.
Behaviours probably resulted out of the way genservers are implemented. It’s a process, which does handle a lot of otp behaviour for you, but to be useful it needs to also do some user defined stuff. To be able to do that you give the genserver a module at startup, which the genserver calls, when userland code is required. Now when implementing said module you need to know which functions will be called by the genserver code and that’s what a behaviour defines.
Anyway Behaviours are similar to Interfaces in OOP language. You don’t need interfaces, many OOP languages don’t have interfaces. To be hones I never wrote any by myself. But if you are using interface, then you know that this given class (or module in Elixir) is interchangeable with every other class that uses this interface as long as you use a function that this interface guarantees. And it is very nice guarantee to have. Then you can safely change one class/module for other. For example, if you have few HTTP clients, and all of them use same interface/behaviour you can safely change between them without rewriting large portions of code.
From the OO perspective behaviours need to be understood in terms of the intent of the Template Method pattern:
Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure. (GoF)
Define the skeleton of a process, deferring some functionality to the callback module.
In Template Method the AbstractClass does expose an interface (implying a contract) that will be common to the ConcreteClasses but AbstractClass also contributes the common behaviour (which an interface cannot). In some ways the Template Method pattern is a compile time version of the Strategy pattern:
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it. (GoF)
Define a family of processes (workers) which can be uniformly supervised and managed. Callback modules lets the process computation vary independently from how it is supervised and managed.
Similarly a behaviour module is in charge of most of the standardized (common) aspects of the process lifecycle while the callback module primarily deals with the specific computation (work) that the process is responsible for.
Behaviours are module based and are sometimes used at compile time to vary production and testing module implementations but that is a degenerate use case.
During runtime (process instantiation) a process composes the behaviour and callback module - i.e. it’s only through processes that a behaviour module can spawn “multiple instances” of the behaviour, each process manifesting a specific binding between a behaviour and a callback module with its own state.
Designing for Scalability with Erlang/OTP p.10:
OTP generic behaviors can be seen as formalizations of concurrent design patterns.
So from the OTP perspective behaviours are about processes, not FP.
Actually behaviours predate Elixir by about 15 years. Elixir has inherited them from Erlang/OTP and uses some the standard OTP behaviours, like gen_servers, supervisors and applications, and extended them by adding some new behaviours, agent and task. Doing this is nothing strange as the behaviour concept is easily extensible both by design and implementation.