karthink / gptel

A simple LLM client for Emacs
GNU General Public License v3.0
1.03k stars 111 forks source link

gptel does not support multiple sessions that each of it has a different llm model, right? #285

Closed zbelial closed 2 months ago

zbelial commented 2 months ago

I opened a session (refer it as S1 in the following description) with model A and kept it there, then tested C-u M-x gptel-send with model B, after finishing this query, the model in S1 was changed to B.

karthink commented 2 months ago

You can set different models, model parameters and system messages in each buffer. Use this switch in the menu to toggle between setting globally and buffer-locally:

screenshot_20240412T160630

zbelial commented 2 months ago

Thanks for your quick response. It seems there is another case where the second session will disturb the first one: I tried to open a session S1 with model A ( I mean by calling gptel), then open a second session S2 with model B, then in S1, the model in S1 would be changed to B. (I used gptel in this way because I wanted to choose a better answer from these two models) Is this the expected ATM? Thanks.

karthink commented 2 months ago

Thanks for your quick response. It seems there is another case where the second session will disturb the first one: I tried to open a session S1 with model A ( I mean by calling gptel), then open a second session S2 with model B, then in S1, the model in S1 would be changed to B. (I used gptel in this way because I wanted to choose a better answer from these two models) Is this the expected ATM? Thanks.

No, this is not the expected behavior if you set the model buffer-locally.

Can you give me the precise sequence of steps involved? Your description above is not clear.

zbelial commented 2 months ago

Sorry for not being clear.

I wrote a function like the following to choose a model every time I call it:

(defun my-gptel ()
  (interactive)
  (let ((name)
        (backend))
    (setq name (completing-read "Backend: " (mapcar #'car gptel--known-backends)))
    (when (and name
               (setq backend (alist-get name gptel--known-backends nil nil #'equal)))
      (setq gptel-backend backend
            gptel-model (nth 0 (gptel-backend-models backend)))
      (let ((locale-coding-system 'utf-8))
        (call-interactively #'gptel)))))

And I added two openai-compatible models(with name "ChatGLM" and "Moonshot").

The steps I use:

  1. call my-gptel and select "ChatGLM", I also ask a question "Who are you?" 图片

You can see that "ChatGLM" appears on the header line.

  1. Then I call my-gptel again and select "MoonShot". 图片

  2. switch back to "ChatGLM" buffer, you will find the header is changed, and it seems the model used in this buffer is changed too. 图片

So is gptel designed this way? What can I do to use it to achieve my goal (two models in two gptel buffers)? Thanks.

karthink commented 2 months ago

So is gptel designed this way?

It's not. Have you tried what I suggested in my message above?

What can I do to use it to achieve my goal (two models in two gptel buffers)? Thanks.

By "use it", do you mean using your "my-gptel" function?

zbelial commented 2 months ago

By "use it", do you mean using your "my-gptel" function? I meant using gptel. I wrote my-gptel to make it easier to select a model before actually invoking gptel.

It's not. Have you tried what I suggested in my message above?

Yes, I tried (gptel-menu, right? ). It's just that I have to set the model using gptel-menu in the first session after I start the second session with another different model.

Anyway, thanks for pointing out that I can use gptel-menu to change something local in buffer, I didn't know that.

karthink commented 2 months ago

Yes, I tried (gptel-menu, right? ). It's just that I have to set the model using gptel-menu in the first session after I start the second session with another different model.

You don't have to do that, there seems to be some misunderstanding here. In gptel-menu, did you flip the switch (press =) to set things buffer-locally?

zbelial commented 2 months ago

did you flip the switch (press =) to set things buffer-locally?

Yes. But I still used my-gptel in my last test. Shouldn't I use my-gptel?

And I tested again just now. Following are the steps:

  1. Call my-gptel, select "ChatGLM" -- session S1 图片

  2. Call gptel-menu and press = to switch to for this buffer (actually it's already for this buffer) 图片

  3. Call my-gptel, select "Moonshot" (I also call gptel-menu ) -- session S2 图片

  4. Switch to S1 and call gptel-menu there, you can find that model was changed to "Moonshot:moonshot-v1-8k", and header line was modified too. 图片

Following is my entire config:

(setq gptel-temperature 0.1)
(setq gptel-default-mode 'org-mode)
(setq gptel-use-curl nil)
(setq gptel--num-messages-to-send 1)

(setq gptel-display-buffer-action '(display-buffer-full-frame))
(add-hook 'gptel-post-response-functions 'gptel-end-of-response)

(setq gptel--backend-moonshot (gptel-make-openai "Moonshot"
                                :host "api.moonshot.cn"
                                :endpoint "/v1/chat/completions"
                                :key "keykeykey"
                                :models '("moonshot-v1-8k"
                                          "moonshot-v1-32k"
                                          "moonshot-v1-128k")))

(setq-default gptel-backend gptel--backend-moonshot
              gptel-model "moonshot-v1-8k")

(setq gptel--backend-chatglm-token "tokentokentoken")
(defun gptel--backend-chatglm-header ()
  (let ((token gptel--backend-chatglm-token))
    `(("Authorization" .  ,(concat "Bearer " token)))))
(setq gptel--backend-chatglm (gptel-make-openai "ChatGLM"
                               :host "open.bigmodel.cn"
                               :endpoint "/api/paas/v4/chat/completions"
                               :models '("glm-4")
                               :stream nil
                               :header #'gptel--backend-chatglm-header))
(setq-default gptel-backend gptel--backend-chatglm
              gptel-model "glm-4")

(defun my-gptel ()
  (interactive)
  (let ((name)
        (backend))
    (setq name (completing-read "Backend: " (mapcar #'car gptel--known-backends)))
    (when (and name
               (setq backend (alist-get name gptel--known-backends nil nil #'equal)))
      (setq gptel-backend backend
            gptel-model (nth 0 (gptel-backend-models backend)))
      (let ((locale-coding-system 'utf-8))
        (call-interactively #'gptel)))))

Was there anything I did wrong? Or something is wrong in my config? Thanks.

karthink commented 2 months ago

Thank you for the details, I can now address the confusion.

Setting the global/buffer-local switch in the transient menu makes setting the model from the transient menu global or buffer-local. So here are two ways to set different models for use in two buffers:

Method 1: Using gptel-menu

  1. Open two gptel buffers (or any Emacs buffers, they don't have to be "chat" buffers)
  2. In one of the buffers, bring up the menu.
  3. In the menu, ensure that the switch is set to "Set for buffer" and not "Globally".
  4. In the menu, choose your backend/model (with -m) and other parameters (including the system message).
  5. Quit the menu (with q or C-g).

Now your two buffers will be using different models.

Method 2: Using my-gptel

I don't understand why you're setting the model and then calling the menu in my-gptel, when you can set the model from the menu:

(defun my-gptel ()
  (interactive)
  (let ((name)
        (backend))
    ;;;; UNNECESSARY ;;;;;;;;;;;;;;;;;
    ;; (setq name (completing-read "Backend: " (mapcar #'car gptel--known-backends)))
    ;; (when (and name
    ;;            (setq backend (alist-get name gptel--known-backends nil nil #'equal)))
    ;;   (setq gptel-backend backend
    ;;         gptel-model (nth 0 (gptel-backend-models backend)))
    ;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
      (let ((locale-coding-system 'utf-8))
        (call-interactively #'gptel)))))

Nevertheless, if you need to do it this way for some reason, you can replace the setq above with setq-local, and the backend and model will be set buffer-locally.

zbelial commented 2 months ago

then calling the menu in my-gptel

In my previous comment, the reason why I called gptel-menu after calling my-gptel was I wanted to show you what the problem was.

The use case in my mind is just:

  1. call my-gptel, select a model A
  2. call my-gptel, select a model B
  3. then use A or B in their buffers

It's just that I didn't get what I wanted.

But anyway, I know how gptel works and how to get along with it. Thanks for explaining it to me and for developing this great package. I'll close this issue.