2025,江端さんの技術メモ

はい、Mouse without Borders はホストを含めて最大 4台のPC まで接続して動作します。
したがって、今お使いのホストPCに加えてあと2台、合計3台のマシンを同時に制御することが可能です。

  • ホストPC … 実際にマウス・キーボードが接続されているPC

  • クライアントPC … 追加で操作するPC(最大3台)

設定画面で各PCのセキュリティコードコンピュータ名を入力すれば、3台構成でも問題なく利用できます。

もし希望があれば、3台目を追加する際の具体的な接続手順も説明できます。

中央

右側

左側

現在3台のマシンがあります。

左側の設定画面です。
問題点は 
(1)中央のマシンのマウスは、中央と右側を動き
(2)右側のマシンのマウスも、中央と右側を動き
(3)左側のマシンのマウスは、左側と中央を動き

3台共通して動かないということです。対処方法を教えてください

画像3枚を確認しました。状況を見ると、Mouse without Borders の「接続」が中央と片側のPCだけで完結していて、3台を一つのマトリックスとして認識できていません。
これだと、中央マシン経由の2台運用はできても、左 ↔ 右 の直接移動ができない状態になります。


原因

  • 全てのマシンが同じ「Security Key」と同じネットワーク上にある必要がありますが、現在はそれぞれの接続が部分的にしかリンクしていません。

  • 3台を同一の「Computer Matrix」に登録する設定が完了していません。
    (現状は、中央–右、中央–左のペア接続になっている)


対処手順(全台で共通設定にする)

  1. Security Key を統一

    • 左・中央・右、すべてのマシンで「Shared encryption key」の値を同じにします。

    • 今回の画像を見ると左と中央は tS3_hJ5-jK7_fD9/、右は非表示ですが違っている可能性があるため、手入力で合わせます。

    • 入力後「Apply」を押す。

  2. 全マシンを互いに認識させる

    • 各マシンの設定画面で、右下の「Go through the setup experience」をクリック。

    • 表示された「This is the new computer」に、ホスト(マウス・キーボードを使う中心PC)のSecurity Keyとコンピュータ名を入力。

    • これを、全てのマシン間で行い、3台すべてのサムネイルが表示される状態にする。

  3. Computer Matrix の並びを調整

    • 設定画面で3台のサムネイルをドラッグして、物理的な配置(左・中央・右)と同じ並びにする。

    • 「Two Row」のチェックは不要なら外す。

    • 「Apply」を押して保存。

  4. テスト

    • いずれかのマシンからマウスを動かし、左右両方向に移動できることを確認。

    • 全台でキーボード入力も共有されるか確認。


💡 ポイント

  • Mouse without Borders は全員が同じ Security Key を共有し、全台が同じ「Computer Matrix」に表示されている状態でないと、完全な3台運用になりません。

  • 途中のマシン経由でしか動かせない場合は、片方のPCがもう一方を認識していない証拠です。

2025,江端さんの技術メモ

pybind11とは何ですか

pybind11 とは、C++で書かれたコードをPythonから簡単に呼び出せるようにするライブラリです。具体的には、C++関数・クラスをPythonにバインディング(橋渡し)するための軽量なヘッダオンリーライブラリです。


✅ 要点まとめ

項目 内容
名称 pybind11
用途 C++コードをPythonから使えるようにする(バインディング)
特徴 ヘッダオンリー、軽量、C++11以降対応
主な代替 Boost.Python、SWIG など
主な用途 Pythonから高速なC++シミュレータや計算ライブラリを使うときなど

🧠 なぜ使うのか?

Pythonは書きやすいが遅い、C++は速いけど扱いにくい。
そのため、重い処理はC++で書き、インターフェースだけPythonで操作したいことがよくあります。

text
たとえば:
Python部分 → 学習ロジック(強化学習など)
C++部分 → シミュレータの高速実行

この「橋渡し」に pybind11 が使われます。


🔧 使用イメージ

C++側(example.cpp)

#include <pybind11/pybind11.h>

int add(int i, int j) {
    return i + j;
}

PYBIND11_MODULE(example, m) {
    m.def("add", &add, "A function which adds two numbers");
}

Python側

import example
print(example.add(1, 2))  # → 3

このように、C++の関数をまるでPythonで書いた関数のように使えるようになります。



🔚 まとめ

観点 内容
概要 C++とPythonをつなぐためのヘッダオンリーライブラリ
主目的 C++で書いた高速なロジックをPythonから呼び出す
利点 軽量・高速・簡単・CMakeと相性良好
使用場面 シミュレーション、機械学習、画像処理、ゲームエンジン等のバックエンド連携

必要であれば、あなたの railway_simulator モジュールが pybind11 で作られているかどうかも確認する手順を案内できます。

使用イメージを実際に動かすにはどうすれば良いですか

以下に、pybind11 を使って C++ 関数を Python から呼び出せるようにする最小構成の実行手順をまとめます。
Linux / WSL / Mac / MSYS2 などの UNIX互換環境を前提にしています(Windows でも MSYS2 や WSL を使えば同じです)。


✅ ゴール

C++ の関数を Python から呼び出せるようにする:

cpp
int add(int a, int b) { return a + b; }

↓ Pythonから:

python
>>> import example
>>> example.add(1, 2)
3

🔧 準備

① Python と pybind11 のインストール

以下をターミナルで実行:

bash
pip install pybind11

(C++コンパイラが必要です:gcc, clang, cl など)


📁 ② ファイルを作成

example.cpp(C++側)

#include <pybind11/pybind11.h>
int add(int i, int j) {
    return i + j;
}
PYBIND11_MODULE(example, m) {
    m.def("add", &add, "A function which adds two numbers");
}

⚙️ ③ ビルド(共有ライブラリ作成)

以下のコマンドをそのままコピー&ペースト:

c++ -O3 -Wall -shared -std=c++11 -fPIC \
    `python3 -m pybind11 --includes` \
    example.cpp -o example`python3-config --extension-suffix`

このコマンドは:

  • pybind11 のヘッダを含めて

  • example.so(もしくは .pyd)というPython拡張モジュールを作成します


✅ ④ 実行(Pythonから呼び出し)

ターミナルで Python を起動し、次を試してください:

>>> import example
>>> example.add(10, 5)
15

成功すれば pybind11 のバインディング成功です!


📎 注意点

項目 内容
ビルドは1行で 改行してしまうと command not found になります。1行にしてください
Windows の場合 -fPIC は不要/MSYS2環境を推奨します
pybind11 の場所 python3 -m pybind11 --includes により自動取得できます
Python バージョン python3.11 など環境によって異なる場合があります。必要なら python3-config を変更してください

✅ もしうまくいかなかったら…

次の情報を貼ってもらえれば、個別にビルドコマンドを調整できます:

  • OS種別(Windows / Mac / Ubuntu / WSL など)

  • Pythonバージョン(python3 --version

  • コンパイラの種類(gcc --version など)


必要であれば、CMakeLists.txt を使った構成や、.pyx ファイルとの違い(Cython との比較)についてもご説明します。

c++ -O3 -Wall -shared -std=c++11 -fPIC \
    python3 -m pybind11 --includes \
    example.cpp -o examplepython3-config --extension-suffix
> > /home/ebata/.pyenv/versions/3.8.10/bin/python3: No module named pybind11
example.cpp:1:10: fatal error: pybind11/pybind11.h: No such file or directory
    1 | #include <pybind11/pybind11.h>
      |          ^~~~~~~~~~~~~~~~~~~~~
compilation terminated.

と言われました

ありがとうございます。エラーメッセージを解析すると、以下の2つの問題が発生しています:


❌ 問題1:pybind11 がインストールされていない

bash
/home/ebata/.pyenv/versions/3.8.10/bin/python3: No module named pybind11

これは pybind11Python環境に未インストールであることを示しています。


❌ 問題2:C++ヘッダファイル pybind11/pybind11.h が見つからない

bash
example.cpp:1:10: fatal error: pybind11/pybind11.h: No such file or directory

これは Python モジュールが見つからなかったため、--includes で得られるインクルードパスも空になり、結果として pybind11.h が見つからないという流れです。


✅ 解決手順

以下の手順に従って修正してください。


① pybind11 を正しい Python 環境にインストール

あなたは pyenv を使って Python 3.8.10 を使っているようなので、次のコマンドを使います:

bash
~/.pyenv/versions/3.8.10/bin/pip install pybind11

※または pyenv の環境をアクティベートしてから:

bash
pyenv activate 3.8.10
pip install pybind11

② 再度ビルドコマンドを実行

インストール後、以下の1行コマンドを再度実行してください:

c++ -O3 -Wall -shared -std=c++11 -fPIC \
    `python3 -m pybind11 --includes` \
    example.cpp -o example`python3-config --extension-suffix`

(必要なら python3~/.pyenv/versions/3.8.10/bin/python3 に書き換えてください)


✅ うまくいけば…

カレントディレクトリに example.cpython-38-x86_64-linux-gnu.so のようなファイルができます。

Pythonで次のように実行できれば成功です:

bash
python3
>>> import example
>>> example.add(2, 3)
5

📌 備考(トラブル防止)

内容 対処法
複数バージョンの Python がある 明示的に ~/.pyenv/versions/3.8.10/bin/python3 を使う
pip install したのに ModuleNotFoundError pippython が同じ環境を見ているか確認(例:which pip, which python3
pybind11 のヘッダが見つからない python3 -m pybind11 --includes の出力結果を確認して -I/path/to/pybind11/include を手動で追加

2025,江端さんの技術メモ

以下に、Go言語で実装するシンプルな mTLS(相互TLS認証)通信プログラムを示します。
これは、サーバがクライアント証明書の検証を行い、クライアントがサーバに接続してデータを送るという最小構成のデモです。


✅ ファイル構成

.
├── server.go ← mTLS対応サーバ
├── client.go ← mTLS対応クライアント
├── ca.crt ← ルートCA証明書
├── server.crt ← サーバ証明書(caで署名)
├── server.key ← サーバ秘密鍵
├── client.crt ← クライアント証明書(caで署名)
└── client.key ← クライアント秘密鍵

🖥️ サーバ側(server.go

package main

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
)

func main() {
	// クライアント証明書を検証するためのCA証明書読み込み
	caCert, err := os.ReadFile("ca.crt")
	if err != nil {
		log.Fatal(err)
	}
	caPool := x509.NewCertPool()
	caPool.AppendCertsFromPEM(caCert)

	// TLS構成
	tlsConfig := &tls.Config{
		ClientAuth: tls.RequireAndVerifyClientCert,
		ClientCAs:  caPool,
		MinVersion: tls.VersionTLS12,
	}

	server := &http.Server{
		Addr:      ":8443",
		TLSConfig: tlsConfig,
	}

	http.HandleFunc("/secure", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "mTLS通信成功!")
	})

	log.Println("mTLSサーバ起動中:https://localhost:8443/secure")
	err = server.ListenAndServeTLS("server.crt", "server.key")
	if err != nil {
		log.Fatal(err)
	}
}

💻 クライアント側(client.go

package main

import (
	"crypto/tls"
	"crypto/x509"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
)

func main() {
	// クライアント証明書と鍵の読み込み
	cert, err := tls.LoadX509KeyPair("client.crt", "client.key")
	if err != nil {
		log.Fatal(err)
	}

	// サーバ証明書を検証するためのCA証明書読み込み
	caCert, err := os.ReadFile("ca.crt")
	if err != nil {
		log.Fatal(err)
	}
	caPool := x509.NewCertPool()
	caPool.AppendCertsFromPEM(caCert)

	// TLS設定
	tlsConfig := &tls.Config{
		Certificates:       []tls.Certificate{cert},
		RootCAs:            caPool,
		InsecureSkipVerify: false,
	}

	client := &http.Client{
		Transport: &http.Transport{TLSClientConfig: tlsConfig},
	}

	// サーバにリクエスト
	resp, err := client.Get("https://localhost:8443/secure")
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Printf("サーバ応答: %s\n", string(body))
}

🔐 証明書の作成(OpenSSL例)

# CA作成
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -subj "/CN=TestCA" -days 3650 -out ca.crt

# サーバ証明書
openssl genrsa -out server.key 2048
openssl req -new -key server.key -subj "/CN=localhost" -out server.csr
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650

# クライアント証明書
openssl genrsa -out client.key 2048
openssl req -new -key client.key -subj "/CN=myclient" -out client.csr
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 3650

✅ 実行方法

  1. 上記のOpenSSLコマンドで証明書類を生成
  2. server.go を起動

  3. client.go を別ターミナルで起動

以下のエラーが発生

ebata@DESKTOP-1QS7OI7:~/test_tls$ go run client.go
2025/07/29 02:33:59 Get "https://localhost:8443/secure": tls: failed to verify certificate: x509: certificate relies on legacy Common Name field, use SANs instead

x509: certificate relies on legacy Common Name field, use SANs instead
→ Go の TLS ライブラリ(特に Go 1.15 以降)では、Common Name(CN)だけの証明書ではサーバ認証に失敗します。
現在は SAN(Subject Alternative Name) が必要です。


✅ 対応策:証明書を SAN を含めて再生成する

OpenSSL の設定を使って、SAN付き証明書を発行します。


🔧 手順(openssl

1. san.cnf という設定ファイルを作成:

# san.cnf
[req]
default_bits       = 2048
distinguished_name = req_distinguished_name
req_extensions     = req_ext
prompt             = no

[req_distinguished_name]
CN = localhost

[req_ext]
subjectAltName = @alt_names

[alt_names]
DNS.1 = localhost

2. サーバ証明書を SAN付きで再生成:

# サーバ鍵生成
openssl genrsa -out server.key 2048

# CSR作成
openssl req -new -key server.key -out server.csr -config san.cnf

# 証明書発行(CAで署名)
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out server.crt -days 3650 -extensions req_ext -extfile san.cnf

✅ 説明

項目 内容
CN Common Name。旧来のFQDN指定(非推奨)
SAN Subject Alternative Name。現在はこちらが必須
localhost クライアントから接続するホスト名と一致させる必要あり

GoはこのSANにlocalhostが含まれていないとTLS検証に失敗します。


✅ 再実行の流れ(修正後)

go run server.go
# → 起動確認「mTLSサーバ起動中:https://localhost:8443/secure」

go run client.go
# → サーバ応答: mTLS通信成功!

2025,江端さんの技術メモ

C:\の128GBが限界に達していて、このままではWindow updateもできないので、C:\128GのSSDを500GのSSDに交換することにしました。

で、業者に問い合わせしてみたら、SSD抜きの作業で1万4000円~という連絡がきまして、「ちょっと高いなぁ」と思い、自力での交換に挑戦してみました。

今回購入したのは、この2つ。

(クリックするとamazonに飛びます)

業者に頼むより1万円ほど安いですが、リストア失敗を考えると1万円なら業者に頼んでもよかったかもしれません。実際、PCの中を明けて、どこに部品があるのか探し回ることになりました。

そんでもって、それをリストアするのにもひと苦労しました。

今回は、業者に預けている時間(2~3日くらい)の方が問題でした。私は、明日も、このPCで作業したかったので。

------

最近は、マニュアル読まなくなりました。でも、こういう動画があれば、マニュアルより安心して作業できます。

一発目のシステムの再起動が上手くいかず、青冷めましたが、その後、安定して起動するようになり一安心です(このドキドキが嫌いです。1万円ならペイする不安感です)。

で、最後は、ChatGPTの登場です。

画像をアップロードしました

ディスク1のクローンを作成したのですが、C:\にはあいからわず108.91GBしかありません。346.52GBの未割り当て領域をC:\に加えて拡張したいです。手順を教えて下さい

「ディスクの管理」画面を見る限り、ディスク1上のCドライブ(108.91GB)に続けて未割り当て領域(346.52GB)が存在しているため、以下の手順で Cドライブを拡張 できます。


✅ 手順:Windows標準機能「ディスクの管理」でCドライブを拡張する方法

  1. 「ディスクの管理」を開いた状態のまま、Cドライブ(108.91 GB)を右クリック

  2. 「ボリュームの拡張(E)...」を選択

  3. 「ボリューム拡張ウィザード」が表示されるので、「次へ(N)」をクリック

  4. 「使用可能な最大サイズ」が既に入力されていることを確認して「次へ(N)」

  5. 「完了(F)」をクリック


⚠ 注意点

  • 上記は「Cドライブの直後に未割り当て領域がある場合」に限って有効です。

  • もし他のパーティションがC:と未割り当て領域の間にある場合は、この方法は使えません(サードパーティ製ソフトが必要になります)。


💡 補足

  • 操作後、Cドライブは 108.91 + 346.52 ≒ 455.43GB に拡張されます。

  • システムドライブの操作なので、念のため事前にバックアップを取っておくと安全です。

これで、明日は安心して開発環境のインストールができます。

-----

なんやかんやで、また1万円ほど使ってしまいましたが、こういう作業も含めて、『これが私の趣味みたいなものかなぁ』と、半ば諦めています。

あまり、共感得られにくい趣味です ーー 引きこもりなら「ゲーム」方がウケは言いだろうな、と思います。

学業や業務の為に「システムのリストア」をしている"引きこもり"は、理解を得られにくいように思います。

 

2025,江端さんの技術メモ

WSLでWebサーバ(テスト)を立ち上げる方法

前提: wslにはUbuntuが入っていて、emacsなどもすでに入っている

(1)スタートメニューで Ubuntu を検索 → 起動すれば、確実にUbuntuが立ち上がります。

(2)デフォルトディレクトリは、/home/ebata で、Windowsからこの場所を見るには、\\wsl$\Ubuntu\home\ebata にアクセス(エクスプローラー)

(3)make my_web_project して、cd my_web_projectして、emacsで、index.htmlを作る。
こんな感じindex.htmlを作っておく。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>WSL Webサーバ テストページ</title>
</head>
<body>
  <h1>ようこそ!</h1>
  <p>これは WSL 上で動作している Web サーバから配信されたページです。</p>
  <p>このページは <code>index.html</code> です。</p>
</body>
</html>

(4)ebata@DESKTOP-1QS7OI7:~/my_web_project$ python3 -m http.server 8888 でサーバを立ち上げる

(5)これで、ローカルから、http://localhost:8888/ でアクセスできる。

(6)ところが、リモートから、http://192.168.0.3:8888/ ではアクセスできない

(7)そこで、方法①(推奨)Windows側でポートフォワーディングを設定
Windows PowerShell を 管理者として実行して以下を実行:
netsh interface portproxy add v4tov4 listenport=8888 listenaddress=0.0.0.0 connectport=8888 connectaddress=127.0.0.1

さらに Windowsファイアウォールでポート 8888 を許可してください:
New-NetFirewallRule -DisplayName "AllowPort8888" -Direction Inbound -LocalPort 8888 -Protocol TCP -Action Allow

(8)これで、リモートから、http://192.168.0.3:8888/ ではアクセスできるようになる

2025,江端さんの技術メモ

取り敢えず、192.168.0.8  の c:\Users\tomoi\rag_projectの中身でやったこと一覧

Ollamaは、どうやって知識を蓄えることができますか?

Ollama自体(正確にはOllama上で動くLLM)は「知識を蓄える(=記憶を永続化する)」機能は原則持っていません。理由と補足は以下の通りです:


🔍 なぜOllama(+LLM)は知識を蓄えないのか?

  • Ollamaが実行するのは事前学習済みの言語モデル(例:LLaMA 3やMistral)であり、内部に知識を書き込む(=学習させ直す)機能はない

  • 一時的な文脈(会話履歴など)は保持できるが、Ollama再起動や会話のリセットで消える。


✅ 知識を“蓄える”ように使いたい場合の方法

方法1: ベクトルDB+RAGで「覚えさせる」

RAG (Retrieval-Augmented Generation) という手法を使うと、ローカルLLMでも“知識を覚えたように使う”ことができます。

構成例:

要素 内容
LLM Ollama + llama3/mistral
知識DB ベクトルDB(例えば Chroma, Weaviate, FAISS など)
統合フレームワーク LangChain, LlamaIndex など
処理内容 PDF, テキスト, Web等 → 分割 → ベクトル化 → 質問に応じて該当知識を検索 → LLMに渡す

📌 つまり、「知識」を蓄えるのはLLMではなく、外部のベクトルデータベースです。


方法2: チューニング(学習)で知識そのものを埋め込む

これは本当の意味での「知識の蓄積」になりますが、難易度が高くなります。

方法

方法名 内容 難易度
LoRA(Low-Rank Adaptation) 特定の知識をモデルに微調整として埋め込む 中〜上
Full fine-tuning モデル全体を再学習 非現実的(高コスト・GPU必須)

🧠「覚えているように見せる」簡易テク

  • LangChainやLlamaIndexで、テキストやPDFファイルを渡すだけで“知識として答える”ように見せられる。

  • これにより、対話履歴を記憶しているように錯覚させることも可能です。


現在、Ollamaが動いていますが、知識を“蓄える”ようにしたいですが、その前にRAGとチューニングの違いについて教えて下さい

はい、非常に重要な質問です。
以下に「RAG」と「チューニング(LoRAなど)」の違いと使い分けを、わかりやすく解説します。


🧠 RAG(Retrieval-Augmented Generation)とは?

▶ 特徴

  • LLMの外部に知識を持たせる。

  • 質問に応じて必要な情報を検索してLLMに与える。

  • モデル自体は一切変更しない。

▶ イメージ

LLMが「図書館で調べながら答えてくれる」ような使い方

▶ メリット

  • 高速かつ安全(モデル改変なし)

  • データの更新が簡単(PDF差し替えなど)

  • ローカルでも構築しやすい

▶ デメリット

  • 検索精度に依存する(ベクトル検索や分割方法が重要)

  • 外部検索結果に基づくため、「推論能力」に制限あり


🔧 チューニング(Fine-tuning / LoRA)とは?

▶ 特徴

  • LLMのパラメータ自体を再学習する。

  • モデル内部に知識を埋め込む。

  • LoRA(Low-Rank Adaptation)を使うと軽量に実現可能。

▶ イメージ

LLMが「訓練して記憶を更新した頭脳を持っている」ような使い方

▶ メリット

  • 対話スタイルやドメイン知識を完全に内面化できる

  • オフラインでも即答できる(検索なし)

▶ デメリット

  • 訓練が難しい(GPU・スクリプト・パラメータ設計)

  • データの入れ替えが容易でない(再チューニングが必要)

  • 学習エラーで性能が落ちることもある


🔄 RAG vs チューニング 比較表

比較項目 RAG チューニング(LoRA含む)
知識の格納先 外部DB(検索) LLM本体(学習)
導入の簡単さ ◎ 簡単 △ 難易度高
データ更新 ◎ 簡単(ファイル差替え) ✕ 毎回再学習が必要
実行速度 ◯(検索+推論) ◎(即応)
精度の安定性 ◯ 安定 △ 調整による
用途 FAQ・文書検索 特定業務への最適化

🎯 どちらを使うべきか?

目的 選択すべき手法
社内文書を検索しながら答えさせたい ✅ RAG
マニュアルからFAQを生成させたい ✅ RAG
専門用語に強いAI秘書を作りたい ✅ チューニング(LoRA)
自分の書き癖や口調を覚えさせたい ✅ チューニング(LoRA)

まずは、「Ollama + RAG(ローカルでの知識追加)」の構築方法を教えて下さい。なおOllamaはWindows11で動いています

Windows 11 上で動いている Ollama に ローカル知識を与える(RAG構成) ためには、以下のステップを踏むのが最も簡単かつ安定です。

✅ 目標

「PDFやテキストをローカルに保存 → 質問 → Ollamaがその内容に基づいて答える」構成を作る。


🛠 必要なツール構成

ツール 目的
Ollama LLM本体(例:llama3)
LangChain or LlamaIndex チャットの実行+外部知識連携
ベクトルDB 知識の保存・検索(Chromaを使用)
Python スクリプト処理

🪜 手順一覧

① Python + ライブラリをインストール

  1. Python 3.10以上をインストール(公式サイト

  2. 以下をインストール:

pip install langchain llama-index chromadb ollama

③ 知識を追加する方法

  • docs/example.txt に内容を書いて保存(例:社内マニュアル、FAQなど)

  • PDFなら PyMuPDF を使って読み込めます:

pip install pymupdf
python
from langchain.document_loaders import PyMuPDFLoader
loader = PyMuPDFLoader("docs/manual.pdf")

📁 まとめ:フォルダ構成例

rag_project/
├── docs/
│ └── example.txt ←知識ソース ├── rag_ollama.py ←実行スクリプト  

✅ 必要なインストール

以下をすべてインストール済みであることを確認してください:

bash
pip install -U langchain langchain-community langchain-ollama chromadb
ollama run nomic-embed-text # 埋め込み用モデル
ollama run llama3 # LLM本体

🆕 rag_ollama.py(最新版)

from langchain_community.vectorstores import Chroma
from langchain_community.document_loaders import TextLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.chains import RetrievalQA
from langchain_ollama import OllamaEmbeddings, OllamaLLM

# 1. 知識となるテキストを読み込み
loader = TextLoader("docs/example.txt", encoding="utf-8")
documents = loader.load()

# 2. テキストをチャンクに分割
text_splitter = CharacterTextSplitter(chunk_size=500, chunk_overlap=50)
texts = text_splitter.split_documents(documents)

# 3. Ollama埋め込みモデルでベクトル化
embedding = OllamaEmbeddings(model="nomic-embed-text")

# 4. ChromaでベクトルDBに保存(自動永続化)
db = Chroma.from_documents(texts, embedding, persist_directory="./chroma_db")

# 5. Ollama本体モデル(例:llama3)
llm = OllamaLLM(model="llama3")

# 6. RAG構成(Retriever + LLM)
qa = RetrievalQA.from_chain_type(llm=llm, retriever=db.as_retriever())

# 7. 対話ループ
print("終了したいときは 'exit' または 'quit' と入力してください。\n")
while True:
    query = input("質問 > ")
    if query.strip().lower() in ["exit", "quit"]:
        break
    result = qa.invoke({"query": query})
    print("答え:", result["result"])

📁 フォルダ構成例

rag_project/
                  ├── rag_ollama.py
                  ├── chroma_db/ ← 自動生成される(永続保存)
                  └── docs/
                                 └── example.txt ← 知識として使いたい文書

📌 注意点

  • .persist()不要(Chromaが自動保存)

  • import元はすべて langchain_community または langchain_ollama に変更済み

  • run() ではなく .invoke() を使用

いま実施して気が付いたのですが、RAGはText(Sample.txt)に記載されたこと以外のことはこたえられないのですか? 

ollama run llama3

ではこたえられることが、

python rag_ollama.py

ではこたえられません。

はい、その気づきはまさにRAGの本質を突いています。
ご理解のとおり:


✅ 【結論】

RAGでの回答は「与えられた知識(たとえば sample.txt)に基づくもの」に限定されます。


🔍 なぜか?

🔁 モードの違い

実行コマンド 動作内容 回答の知識源
ollama run llama3 LLMが直接回答 LLaMA3があらかじめ学習した膨大な知識(Wikipediaなど)
python rag_ollama.py RAG構成で回答 あらかじめ与えられたテキストファイルのみ

つまり、RAGは「知らないことは答えない」ように設計されています。

で、いま、このハイブリッド方法についてコーディングしているんですが、上手く動いていません。

2025,江端さんの忘備録

今、新幹線の新横浜駅にいます。
I'm at Shin-Yokohama Station waiting for the Shinkansen.

出発1時間半前です。
It's an hour and a half before departure.

正直、安堵で腑抜けているところです。
Honestly, I'm feeling utterly relieved and drained.

-----

私の勤務している会社では、会社が発行したクレジットカードを用いた新幹線チケットの購入が認められなくなりました。
At my company, we're no longer allowed to buy Shinkansen tickets using company-issued credit cards.

代わりに、「JR東海エクスプレス予約」というサービスを、会社のシステム経由で使わなければならなくなり、さらに『早割○○○』でのチケット購入が必須となりました。
Instead, we are required to use the JR Central Express Reservation system via our company system and purchase tickets under special advance-discount plans.

出張というのは、現場で何が起きるかわかないものです。
Business trips are unpredictable by nature.

人身事故がなくても、遅延や遅着は当たり前。
Delays and late arrivals are common even without personal injury accidents.

鉄道を止める規模の地震は、日本各地で週単位で発生しています。
Earthquakes large enough to halt train services occur somewhere in Japan almost every week.

加えて、豪雪・豪雨は、もはや日常レベルです。
Additionally, heavy snow and rain are frequent occurrences.

つまり、チケット予約は「怖い」のです。
In short, booking tickets is a nerve-wracking affair.

いや、チケット予約そのものはどうということはありません。
The act of booking itself isn’t the problem.

怖いのは、予測不能の事態が発生したとき、ネット経由のチケットキャンセルが、ほぼ100%の確率で失敗することを、私は経験として知っているからです。
What scares me is the near-certainty that online ticket cancellations will fail during unforeseen events—something I know from painful experience.

キャンセルができなかった場合の「損金処理」の始末が、地獄のように面倒くさい。
Handling the accounting for unused tickets when cancellation fails is a nightmare.

これだけで、2日分の通常業務を吹き飛ばすくらいの時間がかかります。
It can eat up the equivalent of two full days’ worth of regular work.

なぜ、このようなことになるのか。
Why does this happen?

―― システム(のUI:ユーザーインターフェース)が、絶望的にアホだからです。
Because the system UI—the user interface—is hopelessly stupid.

-----

ANAのチケット予約システムも含めて、大抵の予約システムのUIはアホで、
Including ANA's flight reservation system, most booking UIs are simply idiotic.

特にキャンセルや解約に関しては、
Especially when it comes to cancellations and contract terminations,

―― 意図的に手続を妨害しているとしか思えないUI設計
—The UI seems deliberately designed to obstruct the process.

になっています。
That's how it feels.

キャンセルや解約の手続きは、トップページの先頭に、ワンボタンで配置すべきです。
Cancellation and termination options should be a one-click button at the top of the homepage.

(実際、私は町内会のホームページをリメイクしたとき、トップページに脱会用PDFのリンクを貼るようにデザインしました)
(When I redesigned our neighborhood association website, I made sure to put a link to the withdrawal form PDF right on the homepage.)

-----

最近思うのですが、ホームページのデザインにも、製作者の名前(×法人名、○個人名)を表示するべきではないでしょうか。
Lately, I think that website designs should include the actual designer’s name, not the company, but the individual.

アホなUIを設計したWebデザイナーは、業界から嘲笑され、顧客から憎悪される
A web designer who builds a foolish UI should be ridiculed by the industry and hated by users—

――これくらいのフィードバックがない限り、我が国のUIデザインは、これからも"アホ"を続けることになります。
—Without that level of feedback, Japanese UI design will remain forever idiotic.

というか、新幹線の予約システムも、異なるシステムを5つくらい作ればいいんです(5つの会社に発注する)。
Honestly, they should build five separate Shinkansen reservation systems, each developed by a different company.

そうして、アホなUIのWebは競争的に淘汰されるようになればいい。
That way, the dumb ones would be weeded out through competition.

(……と書きながら、排他制御やセキュアなデータ管理を考えると、それが現実的に難しいことも理解してはいるのですが)
(Though I say that, I also understand the practical challenges like exclusive access controls and secure data management.)

-----

今、私が新横浜駅の新幹線ホームで安堵して腑抜けている理由は、
Now, the reason I'm standing limp with relief on the Shinkansen platform at Shin-Yokohama Station

―― JR東海エクスプレス予約と私のPASMOとの紐付けが成功していることを、改札で確認できたからです。
—I confirmed at the gate that my JR Express Reservation was successfully linked to my PASMO card.

この紐付け作業のために、私は弊社のシステム部門の方を1時間以上拘束し、マンツーマンのテレビ会議で説明を受けながら操作を行いました。
To complete this linking process, I spent over an hour with a system department colleague in a one-on-one video call, receiving instructions step-by-step.

ちなみに、私は現役のシステムエンジニアですよ?
Just so you know—I’m a current, active system engineer.

そんな私が、機密情報を扱うシステム部門の人とタッグを組まなければ「紐付け」が完了しないシステムって、一体何なの?
If I have to team up with someone who manages confidential data to complete this process, what kind of system would that be?

そして今日は、その「紐付け」後、最初の運用日です。
And today is the first day I’m using the system post-linkage.

―― この紐付け、絶対に失敗している。そして私は大声で叫びながら、窓口やコールセンターに助けを求めるが、誰一人としてロクな回答ができず、キャンセルもできないまま、新幹線の発車時刻が過ぎていく……
—I had foreseen the worst: the link fails, I scream at the counter and call centers, no one can help, I can't cancel, and the train departs without me.

そういう最悪の未来を予知したがゆえに、私は「1時間半前の新横浜駅到着」を選んだのです。
That foresight is precisely why I arrived at Shin-Yokohama Station 90 minutes early.

だから、自動改札機から座席案内のタグが無事に出てきたとき、私は泣きそうになるくらい嬉しかったのです。
So when the seat tag came out of the automatic gate, I was on the verge of tears with joy.

-----

システムエンジニアとして、いま私の社会システムへの信頼度は、最大値を振り切ってマイナスに突入しています。
As a system engineer, my trust in our societal systems is currently off the scale, in the negative direction.

現在の私の唯一の希望は、生成AIによる「窓口システム」です。
My only hope now lies in AI-generated front-desk systems.

電話のたらい回しが、生成AIによって完全にワンストップで処理されるなら、
If generative AI can eliminate phone-based runarounds and offer accurate one-stop service,

―― もう、人間なんぞ消えてなくなってもいい
—Then let humanity vanish already.

と、私は言い切ります。
I say that without hesitation.

2025,江端さんの技術メモ

word で、本来 "1. 序論 1.1 背景 現在、日本の多くの行政区において...... "と表示されるところが、"1."、"1.1 "が表示されなくなりました。 ナビゲーションだけでなく、本文にも表示されていません

見出し1, 見出し2、が全部表示されなくなったが、これで直った。

心臓に悪いから、こういうのは止めて欲しい。

2025,江端さんの技術メモ

以前、

クローンのSDカードが動かん (The replica SD card doesn't work.) → 動きました(It works) writable: UNEXPECTED INCONSISTENCY; RUN fsck MANUALLY,

に記載しましたが、SDカードのサイズがほんの少しだけ小さいだけ、という理由で、ラズパイのSDカードのクローンを作るのに失敗したお話をしました。

で、あの時は、SDカード→SDカードの場合に成功したのですが、今回は、ハードディスクに格納したimgファイル→SDカードのケースで対応できませんでした。

📝補足:なぜ少し足りないだけでもダメ?

.img ファイルは「SDカード全体の構造」を再現する形式なので、たとえ未使用部分があってもその全体サイズ分を丸ごと書き込む必要があります。そのため、数百MBでも足りないと完全に書き込めません

そこで、今回は、この対応を試みて、1日がかりで成功しました。128GBのimgファイルのコピーって、もの凄く時間がかかる(2時間以上)ので、そっちでも苦労しました。

が、この方法で、なんとか成功できたようなので、自分用にメモを残しておきます(抜粋のみ)。

 

🔧 対処法 2:img ファイルを縮小する(上級者向け)

方法:Linuxまたは仮想マシン上で pishrink.sh を使う

sudo ./pishrink.sh shajyou_6001_20250221.img shajyou_6001_20250221_shrink.img

これにより、未使用領域を削除して圧縮済み .img を作成できます。これで書き込み先のSDカードがそれよりわずかに小さい場合にも書き込めるようになります。

※ Windows単体では難しいですが、WSLやUbuntu仮想マシンがあるなら対応可能です。

私は、WindowsのHDDにimgファイルもってきて、WSLから実施しました。

ただ、pishrink.sh はダウンロードする必要があります。https://github.com/Drewsif/PiShrink/blob/master/pishrink.sh

また、その途中でparted  のインストールも必要になりました。

sudo apt update
sudo apt install parted

こうして、

sudo ./pishrink.sh shajyou_6001_20250221.img shajyou_6001_20250221_shrink.img

を実施しました

で、その結果以下のようなものが作成されました。

約1/3に圧縮されていますので、128GBのSDカードには軽く入る計算になります。

さて、次に、SDカードへの書き込み(クローンの作成)に入ります

✅ おすすめ:Raspberry Pi Imager(公式ツール)

【手順】

  1. Raspberry Pi Imager をダウンロード・インストール
     → 公式サイト: https://www.raspberrypi.com/software/

  2. SDカードをPCに挿入

  3. Raspberry Pi Imagerを起動し、以下を選択:

    • 「OSを選ぶ」→ 一番下の「カスタムイメージを使う」→ shajyou_6001_20250221_shrink.img を選択

    • 「ストレージを選ぶ」→ SDカードを選択

  4. 「書き込む」をクリック → 書き込み完了まで待つ

書き込み→検証で1時間くらいはかかるので、諦めて待ってください。

-----

最後に、このクローンのSDカードで、ラズパイが立ち上がるのかを確認するのですが、かなりドキドキします。

私の場合、初回のブート時に、

てな画面がでてきて、自動的に再起動がかかりましたが、2度目の起動でログイン画面になり、ホッとしました。

最初は、USB関連を抜いて追いた方が良いかもしれません(キーボードとマウスはしょうがないとしても)。

以上

P.S. さて、これからあちこち(PCやらNASやら)にコピーしたimgファイルの削除です。imgファイルだけで128GBの容量を取られるので、本当にシャレになりません。

2025,江端さんの技術メモ

GStreamerをC言語でフレームレートの設定ができなかったので、色々試していましたが、

caps = gst_caps_from_string("video/x-raw, width=640, height=360,framerate=5/1")は動きません(少なくとも私のコードでは駄目だった)。

これね、GStreamerのコマンドと同じ内容になるように並べなければあらないようです。

gst-launch-1.0 rtspsrc location=rtsp://cam:Cam12345@192.168.0.10/Src/MediaInput/stream_1 latency=0 ! rtph264depay ! avdec_h264 ! videoconvert ! videoscale ! video/x-raw,width=640,height=360 ! videorate ! video/x-raw,framerate=1/1 ! x264enc bitrate=1700 speed-preset=ultrafast tune=zerolatency key-int-max=1 ! mpegtsmux ! srtserversink uri = "srt://192.168.101.10:38091" latency=500

これを忠実にコーディングする必要があるようです。

で、今のコードに入っていなかったのが"video/x-raw,framerate=1/1" です。

なので、capsfilter2 やら caps2 のコードを追加する必要がありました。
という訳で、以下のような追加をすることで動くようになりました。

ーーーーー

GstElement *videoscale, *capsfilter, *videorate, *x264enc, *mpegtsmux, *srtserversink;
GstElement *capsfilter2;

GstCaps *caps;
GstCaps *caps2;

ーーーーー

capsfilter = gst_element_factory_make("capsfilter", "capsfilter");
videorate = gst_element_factory_make("videorate", "videorate");
capsfilter2 = gst_element_factory_make("capsfilter", "capsfilter2");

ーーーーー

if (!pipeline || !rtspsrc || !rtph264depay || !avdec_h264 || !videoconvert || !videoscale ||
!capsfilter || !videorate || !capsfilter2 || !x264enc || !mpegtsmux || !srtserversink) {
g_printerr("Not all elements could be created.\n");
abc_log_message("Not all elements could be created.");
return -1;
}

ーーーーー

caps = gst_caps_from_string("video/x-raw,width=640,height=360");
g_object_set(capsfilter, "caps", caps, NULL);
gst_caps_unref(caps);
caps2 = gst_caps_from_string("video/x-raw,framerate=10/1");
g_object_set(capsfilter2, "caps", caps2, NULL);
gst_caps_unref(caps2);

ーーーーー

gst_bin_add_many(GST_BIN(pipeline), rtspsrc, rtph264depay, avdec_h264, videoconvert, videoscale,
capsfilter, videorate, capsfilter2, x264enc, mpegtsmux, srtserversink, NULL);

if (!gst_element_link_many(rtph264depay, avdec_h264, videoconvert, videoscale, capsfilter, videorate,
capsfilter2, x264enc, mpegtsmux, srtserversink, NULL)) {
g_printerr("Elements could not be linked.\n");
abc_log_message("Elements could not be linked.");
gst_object_unref(pipeline);
return -1;
}

ーーーーー

もっと簡単にできると思ったんだけどなぁ・・・結構、手間かかったなぁ。