davidmigloz / langchain_dart

Build LLM-powered Dart/Flutter applications.
https://langchaindart.dev
MIT License
387 stars 67 forks source link

Make LanguageModelOptions (like ChatOpenAIOptions) more bind-friendly #481

Closed tolo closed 1 month ago

tolo commented 1 month ago

Feature request

LanguageModelOptions (like ChatOpenAIOptions, ChatMistralAIOptions etc) should not set a default model, as this will reset the model to the default one every time you use the bind operator (for instance). Example:

final llm = ChatOpenAI(
  defaultOptions: const ChatOpenAIOptions(model: 'gpt-4o', temperature: 0.1),
);
final modifiedLlm = llm.bind(const ChatOpenAIOptions(temperature: 1.0));
// Below invocation will use the default gpt-3.5-turbo model, instead of 
// the expected gpt-4o model
final res = await modifiedLlm.invoke(PromptValue.string('Hello'));

Motivation

Removing the default value (and moving it into the Chat/LLM API implementations) will improve the developer experience and reduce the likelihood of errors (using the incorrect model). It would also be more in line with the Python implementation.

Your contribution

Could possibly create a PR/PRs (spans multiple packages) if need be.

davidmigloz commented 1 month ago

Hey @tolo ,

Thanks for the suggestion. It was something I had in mind as I already got a couple of reports of people getting confused about why the wrong model was used (e.g. when binding tools).

I would still like to keep model as part of the options, as that allows the use of the same wrapper (and underlying HTTP client) for calling different models.

So maybe we can have something like:

const defaultModel = 'gpt-3.5-turbo';

//...

class ChatOpenAI extends BaseChatModel<ChatOpenAIOptions> {

  ChatOpenAI({
    //...
    super.defaultOptions = const ChatOpenAIOptions(
      model: defaultModel,
    ),
  });

  //...

  CreateChatCompletionRequest _createChatCompletionRequest(
    final List<ChatMessage> messages, {
    final ChatOpenAIOptions? options,
    final bool stream = false,
  }) {
    return CreateChatCompletionRequest(
      model: ChatCompletionModel.modelId(
        options?.model ?? defaultOptions.model ?? defaultModel,
      ),
      //...
    );
  )

And remove the default value from the ChatOpenAIOptions constructor.

What do you think?

tolo commented 1 month ago

Yes, the model property should definitely remain in the options classes, it's just the default value in the constructor that should be removed. So above (falling back on default model instead of throwing error I guess?) looks good provided that is done. 👍

davidmigloz commented 1 month ago

This should further improve the binding experience: https://github.com/davidmigloz/langchain_dart/pull/500