完全にプライバシー保護されたAIカウンセラーとしてEmacsのdoctorを進化させる
しむどん
:
2025-08-29
- Emacsのセラピー機能「doctor」のバックエンドをローカルLLMに置き換えた。
- 情報を外部サーバに送信しないため、完全にプライバシー保護された会話が可能になった。
-
システムの構成要素として、以下を使用した。
- オープンソースの軽量モデルJan-v1-4B-GGUF
- LMStudioを使ってローカルAPIサーバを構築
- ローカルAPIサーバを自作のEmacs Lisp、
doctor-quackから直接接続 doctor-quackでは、curlを使ってAPIに接続。
- より安全にAIカウンセリングやサポートを気軽に利用できるようになった。
LMStudioを設定しAPIサーバを起動する
LMStudioにモデルをダウンロードする。モデルはJan-v1-4B-GGUFを使用する。
ダウンロードしたモデルを使ってAPIサーバーを起動する。
ここで提供されるWeb APIのリクエストとレスポンスの形式は、OpenAI APIと、とてもよく似ているため、OpenAI APIに書いたコードがそのまま使える事も多い。
Emacs Lispを修正する
以前作成したdoctor-quack.elの doctor-quack-send-curl-request を少しだけ(というかAPIのオリジンだけ)書き換えて呼び出せるようにした。APIは /v1/chat/completions を使用する。
(defun doctor-quack-send-curl-request ()
(interactive)
(message "ペイロード用ファイルを作成")
(let ((payload
(with-current-buffer (get-buffer-create "*LLM: context*")
(goto-char (point-min))
(let ((contexts (json-read-array)))
(let ((body (json-read-from-string doctor-quack-request-body-template)))
(setcdr (assoc 'messages body) contexts)
body)))))
(make-directory "~/.cache/openai" t)
(setq doctor-quack-openai-api-request-body-file
(make-temp-file (expand-file-name "~/.cache/openai/chat-completions-") nil ".json"
(json-encode payload))))
(message "Succeed to create body file: %s" doctor-quack-openai-api-request-body-file)
(message "出力バッファを初期化する")
(with-current-buffer (get-buffer-create doctor-quack-openai-api-request-stdout-buffer-name)
(erase-buffer)
(doctor-quack-update-curl-stdout-end-position))
(message "curlプロセスを起動する")
(setq doctor-quack-openai-api-curl-process
(make-process :name "*doctor: curl: OpenAI*"
:buffer doctor-quack-openai-api-request-stdout-buffer-name
:stderr "*doctor: curl: OpenAI: stderr*"
:command `(,doctor-quack-curl-executable
"--data" ,(format "@%s" doctor-quack-openai-api-request-body-file)
"-K-")
:filter (lambda (process output)
(with-current-buffer (process-buffer process)
(goto-char (point-max))
(insert output)
(doctor-quack-register-process-output)
))
:sentinel (lambda (process event)
(doctor-quack-register-process-output))))
(message "リクエストを送信する")
(with-current-buffer (get-buffer-create doctor-quack-openai-api-request-temp-buffer-name)
(erase-buffer)
(insert (format "
url \"%s/v1/chat/completions\"
request \"POST\"
header \"Content-Type: application/json\"
header \"Authorization: Bearer %s\"
" "http://127.0.0.1:1234" "DUMMY"))
(process-send-region doctor-quack-openai-api-curl-process (point-min) (point-max))
(process-send-eof doctor-quack-openai-api-curl-process))
(message "doctor: send request"))これによって、バックエンドにローカルLLMを使用するdoctorを使えるようになった。