8000 Support multiple providers in ekg-llm, call ekg-embedding-connect by ahyatt · Pull Request #198 · ahyatt/ekg · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Support multiple providers in ekg-llm, call ekg-embedding-connect #198

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

8000
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions doc/ekg.org
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ triples library is already installed.
** Version 0.7.0
- Added =ekg-show-notes-for-query= using =triples-fts=.
- Speed up for LLM calls with notes as context
- Support multiple values in =ekg-llm-providers= so that they can be chosen from.
- Ensure SQL connection and schema for embedding calls.
** Version 0.6.4
- Fix display of extended structured data in notes.
- Add contrib directory and =ekg-email= as a contribution to import emails to notes in a structured way.
Expand Down Expand Up @@ -834,14 +836,15 @@ embedding.

The embedding interfaces with your preferred LLM provider via the =llm= package.
This package allows the user to define their preferred llm backends, which will
be stored in ~ekg-llm-provider~. Please see the [[https://github.com/ahyatt/llm][LLM module project page]] for a
complete description on how to do this, but an example would be the following:
be stored in ~ekg-embedding-provider~. Please see the [[https://github.com/ahyatt/llm][LLM module project page]] for
a complete description on how to do this, but an example would be the following:

#+begin_src emacs-lisp
(use-package ekg
:init
(require 'llm-openai) ;; the specific LLM provider must be required
(require 'ekg-embedding)
(require 'ekg-llm)
(ekg-embedding-generate-on-save)
(let ((my-provider (make-llm-openai :key "my-openai-api-key")))
(setq ekg-llm-provider my-provider
Expand Down Expand Up @@ -1021,6 +1024,8 @@ description of how to do this, but an example would be the following:
(use-package ekg
:init
(require 'llm-openai) ;; the specific LLM provider must be required
(require 'ekg-llm)
(require 'ekg-embedding)
(let ((my-provider (make-llm-openai :key "my-openai-api-key")))
(setq ekg-llm-provider my-provider
ekg-embedding-provider my-provider)))
Expand All @@ -1030,12 +1035,19 @@ The embedding and LLM providers can be different. The LLM provider can change
at will, while the embedding provider must be the same for all embeddings in the
database. It is necessary to create both of these providers, because some LLM
functionality depends on having embeddings.

The variable ~ekg-llm-provider~, can be a single provider, similar to
~ekg-embedding-provider~, or a list. If it is a list, the first element will be
used by default. However, when the user invokes =ekg-llm-send-and-append-note= or
=ekg-llm-send-and-replace-note= with a prefix argument (normally via =C-u M-x=), the
user can select among the different providers.

*** Augmenting notes with LLM output
To send a note to an LLM and capture its response, call
=ekg-llm-send-and-append-note=, which is by default bound to =[C-c .]=. A
prefix argument (=[C-u C-c .]=) will let you edit the prompt before it is sent.
The output from the LLM is appended at the end of the note, in a special
section.
=ekg-llm-send-and-append-note=, which is by default bound to =[C-c .]=. A prefix
argument (=[C-u C-c .]=) will let you edit the prompt, temperature, and possibly
the provider used before it is sent. The output from the LLM is appended at the
end of the note, in a special section.

In addition to the contents of the note, ekg will construct a larger prompt for
the LLM. The prompt consists of context about previous notes that contain the
Expand Down
25 changes: 19 additions & 6 deletions doc/ekg.texi
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@ triples library is already installed.
Added @samp{ekg-show-notes-for-query} using @samp{triples-fts}.
@item
Speed up for LLM calls with notes as context
@item
Support multiple values in @samp{ekg-llm-providers} so that they can be chosen from.
@item
Ensure SQL connection and schema for embedding calls.
@end itemize

@node Version 064
Expand Down Expand Up @@ -1276,14 +1280,15 @@ embedding.

The embedding interfaces with your preferred LLM provider via the @samp{llm} package.
This package allows the user to define their preferred llm backends, which will
be stored in @code{ekg-llm-provider}. Please see the @uref{https://github.com/ahyatt/llm, LLM module project page} for a
complete description on how to do this, but an example would be the following:
be stored in @code{ekg-embedding-provider}. Please see the @uref{https://github.com/ahyatt/llm, LLM module project page} for
a complete description on how to do this, but an example would be the following:

@lisp
(use-package ekg
:init
(require 'llm-openai) ;; the specific LLM provider must be required
(require 'ekg-embedding)
(require 'ekg-llm)
(ekg-embedding-generate-on-save)
(let ((my-provider (make-llm-openai :key "my-openai-api-key")))
(setq ekg-llm-provider my-provider
Expand Down Expand Up @@ -1473,6 +1478,8 @@ description of how to do this, but an example would be the following:
(use-package ekg
:init
(require 'llm-openai) ;; the specific LLM provider must be required
(require 'ekg-llm)
(require 'ekg-embedding)
(let ((my-provider (make-llm-openai :key "my-openai-api-key")))
(setq ekg-llm-provider my-provider
ekg-embedding-provider my-provider)))
Expand All @@ -1483,6 +1490,12 @@ at will, while the embedding provider must be the same for all embeddings in the
database. It is necessary to create both of these providers, because some LLM
functionality depends on having embeddings.

The variable @code{ekg-llm-provider}, can be a single provider, similar to
@code{ekg-embedding-provider}, or a list. If it is a list, the first element will be
used by default. However, when the user invokes @samp{ekg-llm-send-and-append-note} or
@samp{ekg-llm-send-and-replace-note} with a prefix argument (normally via @samp{C-u M-x}), the
user can select among the different providers.

@menu
* Augmenting notes with LLM output::
* Using ekg notes as prompts::
Expand All @@ -1493,10 +1506,10 @@ functionality depends on having embeddings.
@subsection Augmenting notes with LLM output

To send a note to an LLM and capture its response, call
@samp{ekg-llm-send-and-append-note}, which is by default bound to @samp{[C-c .]}. A
prefix argument (@samp{[C-u C-c .]}) will let you edit the prompt before it is sent.
The output from the LLM is appended at the end of the note, in a special
section.
@samp{ekg-llm-send-and-append-note}, which is by default bound to @samp{[C-c .]}. A prefix
argument (@samp{[C-u C-c .]}) will let you edit the prompt, temperature, and possibly
the provider used before it is sent. The output from the LLM is appended at the
end of the note, in a special section.

In addition to the contents of the note, ekg will construct a larger prompt for
the LLM@. The prompt consists of context about previous notes that contain the
Expand Down
2 changes: 2 additions & 0 deletions ekg-embedding.el
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ If SUCCESS-CALLBACK is non-nil, call it after setting the value,
with NOTE as the argument.

If ERROR-CALLBACK is non-nil use it on error, otherwise log a message."
(ekg-embedding-connect)
(llm-embedding-async
ekg-embedding-provider
(funcall ekg-embedding-text-selector
Expand Down Expand Up @@ -156,6 +157,7 @@ NOTE is the note to create an embedding for."

(defun ekg-embedding-generate-for-note-tags (note)
"Calculate and set the embedding for all the tags of NOTE."
(ekg-embedding-connect)
(cl-loop for tag in (ekg-note-tags note) do
(ekg-embedding-refresh-tag-embedding tag)))

Expand Down
59 changes: 40 additions & 19 deletions ekg-llm.el
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ those other tags."
(defconst ekg-llm-provider nil
"The provider of the embedding.
This is a struct representing a provider in the `llm' package.
The type and contents of the struct vary by provider.")
The type and contents of the struct vary by provider.

It can also be a list of providers, in which case the first one is the
default.")

(defconst ekg-llm-trace-buffer "*ekg llm trace*"
"Buffer to use for tracing the LLM interactions.")
Expand Down Expand Up @@ -160,7 +163,18 @@ ARG comes from the calling function's prefix arg."
;; instructions this way.
(read-string "Prompt: " instructions-initial 'ekg-llm-prompt-history instructions-initial t)
instructions-initial)))
(ekg-llm-send-and-use (ekg-llm-interaction-func interaction-type) instructions-for-use)))
(ekg-llm-send-and-use (ekg-llm-interaction-func interaction-type) instructions-for-use
(if arg
(read-number "Temperature: " 0.5)
0.5)
(when (and arg (listp ekg-llm-provider))
(let ((provider-alist (mapcar (lambda (provider)
(cons (llm-name provider)
provider))
ekg-llm-provider)))
(assoc-default (completing-read "Provider: "
provider-alist
nil t) provider-alist))))))

(defun ekg-llm-send-and-append-note (&optional arg)
"Send the note text to the LLM, appending the result.
Expand Down Expand Up @@ -261,28 +275,29 @@ structs."
(dolist (note (ekg-get-notes-with-any-tags tags))
(iter-yield (ekg-llm-note-to-text note)))))

(defun ekg-llm-send-and-use (marker-func instructions &optional temperature)
(defun ekg-llm-send-and-use (marker-func instructions &optional temperature provider)
"Run the LLM and replace markers supplied by MARKER-FUNC.
If PROMPT is nil, use `ekg-llm-default-prompt'. TEMPERATURE is a
float between 0 and 1, controlling the randomness and creativity
of the response. INSTRUCTIONS gives instructions for the
LLM on what to generate, and will be used in the prompt."
(let ((prompt (make-llm-chat-prompt
:temperature temperature
:context (concat (ekg-llm-prompt-prelude) "\n"
(llm-prompt-fill
'ekg-llm-fill-prompt
ekg-llm-provider
:instructions instructions
:tags (mapconcat 'identity (ekg-note-tags ekg-note) ", ")
:tag-notes (ekg-llm-make-any-tag-generator (ekg-note-tags ekg-note))
:similar-notes (ekg-llm-make-similar-note-generator ekg-note)))
:interactions (ekg-llm-note-interactions)))
(markers (funcall marker-func)))
(let* ((provider (or provider (ekg-llm--provider)))
(prompt (make-llm-chat-prompt
:temperature temperature
:context (concat (ekg-llm-prompt-prelude) "\n"
(llm-prompt-fill
'ekg-llm-fill-prompt
provider
:instructions instructions
:tags (mapconcat 'identity (ekg-note-tags ekg-note) ", ")
:tag-notes (ekg-llm-make-any-tag-generator (ekg-note-tags ekg-note))
:similar-notes (ekg-llm-make-similar-note-generator ekg-note)))
:interactions (ekg-llm-note-interactions)))
(markers (funcall marker-func)))
(delete-region (car markers) (cdr markers))
(condition-case nil
(llm-chat-streaming-to-point
ekg-llm-provider
provider
prompt
(marker-buffer (car markers))
(marker-position (car markers))
Expand Down Expand Up @@ -331,6 +346,12 @@ newline."
(if modified (format "Modified: %s" (format-time-string "%Y-%m-%d" modified)) "")))
", "))))

(defun ekg-llm--provider ()
"Return the provider for the LLM."
(if (listp ekg-llm-provider)
(car ekg-llm-provider)
ekg-llm-provider))

(defun ekg-llm-query-with-notes (query)
"Query the LLM with QUERY, including relevant notes in the prompt.
The answer will appear in a new buffer"
Expand All @@ -343,10 +364,10 @@ The answer will appear in a new buffer"
query
:context
(llm-prompt-fill 'ekg-llm-note-query-prompt
ekg-llm-provider
(ekg-llm--provider)
:notes (ekg-llm-make-similar-text-generator query)))))
(condition-case nil
(llm-chat-streaming ekg-llm-provider
(llm-chat-streaming (ekg-llm--provider)
prompt
(lambda (text)
(with-current-buffer buf
Expand All @@ -358,7 +379,7 @@ The answer will appear in a new buffer"
(insert text)))
(lambda (_ msg)
(error "Could not call LLM: %s" msg)))
(not-implemented (llm-chat ekg-llm-provider prompt)))))
(not-implemented (llm-chat (ekg-llm--provider) prompt)))))
(pop-to-buffer buf)))

(provide 'ekg-llm)
Expand Down
0