お知らせ

現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。
投稿日:
技術::AI

これまでLLMをしばくときはPoeを使っていたが、ぶっちゃけClaude 3.7 Sonnet以外ほとんど使わないので、節約の意味を込めて本家Claudeに移ってきた。しかし本家Claudeではアレゲな発言を繰り返しているとハードウェアモデレーションが発動してしまう。しかもこれが中々解除されない。一体いつ解除されるんだ…。

paste-image-2025-10-31_22-9-28-325.png

アレゲなことをするならやはりPoeだろうか…いやでもPoeもキャラクター設定に対してはハードウェアモデレーションがある。ナレッジベースならモデレーションを回避できるが、ここに入れたプロンプトは入れている間は出現頻度が極端に上がり、外すとちっとも出てこなくなる困りモノで、自然な流れにするためには手動で書いたり消したりする手間がかかり厄介だ。

そこで何かいいことはないか…と思いたどり着いたのがClaude 3.7 SonnetをAPIコールすることだ。LLMモデル本体にはソフトウェアモデレーションしか掛かっておらず、ローカルでプロンプトを組む分にはモデレーションも掛からないと睨んだ私は早速ローカル環境からLLMを呼び出してチャットするための環境を作ることとした。

確認環境

Pythonは3.11系でないと動かないっぽいので注意が必要だ。

Env Ver
OS Windows 11 Pro 24H2
Python 3.11.9

手順

  1. Anthropic Consoleにアクセスしアカウントを作成
  2. 課金してAPIキーを取得
  3. ローカル環境からLLMと対話するためのWebUIである、open-webuiをインストールして起動
    pip install open-webui
    open-webui serve
    
  4. OPEN WEBUIのロゴが出るのを待つ
    paste-image-2025-26-31_22-25-9-719.png
  5. http://localhost:8080/にアクセス
  6. アカウント作成画面が開くので適当な情報を入力して作成する
    • ローカル環境であるため、実在するメールアドレスでなくても問題なく登録できる
  7. 画面左下のユーザーをクリックし、管理者パネルを開く
    paste-image-2025-31-31_22-30-12-787.png
  8. 上のほうにあるFunctionsを開く
    paste-image-2025-32-31_22-31-4-85.png
  9. 右のほうにある「+」からFunctionを追加する画面を開く
  10. Anthropic Function | Open WebUI Communityにアクセスし、Function Contentに書かれているコードをコピーする
  11. 先ほどのFunctionを追加する画面に戻り、コードをペースト
  12. Function NameとFunction Descriptionを適当に埋める
    • 参考までに公式の設定値はそれぞれ「Anthropic」と「Anthropic Manifold Pipe」
  13. 保存ボタンを押す
  14. 有効化する
  15. 新しいチャットを開き、Claude 3.7 Sonnetが利用できるようになっていればOK
    paste-image-2025-55-31_22-54-2-329.png

備考

Poeや本家Claudeにおけるナレッジベースは存在しないが、モデレーションを受けないためシステムプロンプトに全部放り込めば成立する。

Poeのキャラクター設定はやり取りを繰り返すと忘れられるが、Open WebUIのシステムプロンプトは忘れられないようでちゃんと持続してくれる。またPoeのナレッジベースのように書いたことをしつこく発言してくることもなく、自然な会話になるので便利。

またLLM側の発言を編集することにより、それ以降の会話でモデレーションを突破することができるようになるなど、いろいろ便利。

あとがき

APIコールは従量課金でお金がかかるため、Poeや本家Claude並みの感覚で使うのは厳しい。多分Poeはトークン消費を抑えるために何か細工していると思う。

手軽なうえにコンビニでパックの焼き鯖を買うより格段に安い。

20250401_091901411.JPG

材料

材料 分量
塩鯖 1つ
サラダ油 適量

調理方法

  1. フライパンにサラダ油を敷き、キッチンペーパーなどで適当に塗り広げ、弱火をつける
  2. フライパンに塩鯖を入れ、蓋をして蒸し焼きにする
  3. 一分半くらいしたら、ひっくり返し、もう片面も一分半くらい蒸し焼きにする

備考

焼き魚全般に使えるレシピだが、焼き時間は魚の厚みや大きさでも変わるので適宜変える。

蒸し焼きにするときにキッチンタオルを使うと洗い物が減らせる。

20250401_091405331.JPG

燃えることがあるので目を離さないこと。

投稿日:
開発::設計ライブラリ::Next.js

Next.jsの全体設計を考えるときに疎結合性やテスト容易性を達成するときに考えているアーキテクチャについて簡単に書いてみる。

Page Router向けに作っていて、API Routesについては考慮していない。過去にこれに近い設計で開発していたことがあったが、単体テストによるデグレードや不具合、仕様漏れの検出はよくできていたと思う。今回書いたものは過去に考案し、開発していたもののブラッシュアップになる。

アーキテクチャ図

基本的に各レイヤー間はTypeScriptのtypeで仕切り、依存性を逆転させることで、テスト容易性や疎結合性を重視している。

next-js-arch.png

ディレクトリ構成

アーキテクチャ図にないlibrariesが登場するが、これは汎用的な共通処理だ。

src
  ├─adaptors
  │  └─User
  │     ├─index.spec.ts
  │     └─index.ts
  ├─components
  │  └─form
  │      └─TextInput
  │         ├─index.spec.ts
  │         └─index.ts
  ├─libraries
  │  └─HttpClient
  │     ├─index.spec.ts
  │     └─index.ts
  ├─pages
  │  └─hoge
  │     ├─ServerSideProps.ts
  │     ├─ServerSideController.spec.ts
  │     ├─ServerSideController.ts
  │     └─index.page.ts
  └─usecaes
      └─hoge
         ├─controller.spec.ts
         ├─controller.ts
         ├─state.spec.ts
         ├─state.ts
         ├─style.scss
         ├─usecase.tsx
         ├─view.spec.tsx
         └─view.tsx

登場する各要素について

Page

画面本体。UsecaseとgetServerSidePropsを配置し、その橋渡しを行うだけの存在。

Usecase

StateとController、Viewを橋渡しする存在。

画面全体を別物にすり替える場合もここで行う。

useEffect()はここに書くが、中のロジックはController側に書く。

一見するとファサードであり、pageにべた書きしてもいいような内容だが、コードを書く時のコロケーションの観点から敢えて分離している。

また、画面のページレイアウトが全く別物になるなど劇的な変化がある場合は、この階層で分岐制御(ユースケース別の切り替え)する。

State

useState()で作った状態を定義する場所。それ以外は何もしない。

Controller

イベントハンドラによる処理を配置する場所。APIコールもここから行う。

状態については、typeを経由してState側で宣言した状態を注入して利用する。

状態を外部から注入するため、状態変化時のテストがしやすい。また画面からロジックをはがしているため、ロジック単体のテストが可能。

Adaptor

APIを呼ぶだけの存在。データの加工や例外ハンドリングは呼び元で行う。

APIを呼ぶだけの責務とすることで、複数のコンポーネントから呼ばれたときに同じAPIを呼ぶコードが重複したり、呼び出し元によってデータ加工手法を分けるなどの煩雑な実装を回避するのが目的。

テストとしては引数や戻り値、呼び出し方法が実装時から変わっていないかを見る観点のみあれば回帰テストとして機能する。

View

ほぼ純粋なJSXを書く場所。ロジックは原則として書かない。booleanを使ったDOMの切り替えは記述してよい。

制御はUsecaseでStateを合成したControllerで行う。

表示非表示の分岐のみにすることでtesting-libraryを利用したJSXの表示切替を単体テストとして実装できる。

UI Component

TextInputみたいな細かいパーツや、再利用されるフォームUIなど、UI系の共通部品。

基本的に状態は持たないが、無限ループが起きず、再利用されない状態(親に渡す必要がなく、自分自身に閉じた状態)については持ってよいと考えている。例えば、OK/CancelのあるモーダルでOKが押された時だけ呼び元に返す状態は持ってよい。

View, Controller

ページコンポーネント向けの内容に準ずる。Usecaseを持つほど大規模なコンポーネントはないと思うので、Usecaseなしで繋ぎ合わせてよいと考えている。

ServerSideProps

getServerSideProps()の中身。Page側では以下のようにして呼び出す想定。

import { execServerSideProps } from './ServerSideProps';

export const getServerSideProps = (async () => {
  execServerSideProps();
});

ServerSideController

ServerSidePropsの中で利用するロジック。APIを呼ぶ場合はAdaptorとも繋がる。

利点

  • 各レイヤーやコンポーネントでの単体テストが容易
  • MVC的な構造のため理解しやすい
  • SOLID原則で得られる利益を享受しやすい

欠点

  • ボイラープレートコードが増える
    • とはいえ、DDDよりは少ない
  • Modelに相当するものがないため、ControllerがFatになる。またModel処理の共通化ができない
    • Modelをどこに配置すべきかを検討できていない
  • typeに破壊的変更が起きると数珠繋ぎに修正が必要になり、コストが重い
    • その代わり型で各コンポーネントの関係性がわかる利点もある

あとがき

構想自体は4年前に考えたものだがアウトプットができていなかった。まだ煮詰まっていない上に考慮出来ていない部分もあるが、AppRouterの登場からだいぶ経ち、陳腐化してきそうだったので、取り敢えず吐き出した。

昨年フレッツ光クロス、10Gbps対応に関する覚書を書いてしばらく経つが、いよいよ10GbE対応のための環境を作ろうと思ったので、その記録を残していく。

第一弾はR86S U1を買ったので、その購入録とOSのセットアップまでのログを書いていく。

買ったもの

今回購入したのは中華性の怪しい10GbE自作ルーターマシンとして名高いR86S U1だ。もう話題になって数年経っているので旬は過ぎていると思うが、依然として10GbEルーターとして安価な選択肢だと思う。

買った後で気が付いたが、U2のほうがスペックが上で値段同じなのでU2を買ったほうがいい。

セットアップ時にあるといいもの

  • HDMI to Micro HDMI変換アダプタ
  • SDカード or USBメモリ
  • rufusやbalenaEtcherなどのイメージを焼く手段
  • MSYS2

初回起動

私が購入したものはeMMC内にOSが上手く入っていないのかgrubが表示されるだけで、マニュアル操作でも起動イメージが見当たらずmOSを起動することができなかった。

どの道プリインストールされているOSは中国語で役に立たないという話だったのでOSのセットアップを行うことにした。

試験起動

汎用PCへのインストール手順は公式情報である、[OpenWrt Wiki] OpenWrt on x86 hardware (PC / VM / server)が参考になる。

  1. リリース一覧を開き最新の安定板を辿り、x86→64に進む
  2. generic-ext4-combined-efi.img.gzをダウンロードする
  3. sha256sum openwrt-24.10.0-x86-64-generic-ext4-combined-efi.img.gzでハッシュを確認
  4. gunzip openwrt-24.10.0-x86-64-generic-ext4-combined-efi.img.gzで展開する
    • Explzhだと上手く解凍できなかったのでMSYS2からgunzipを叩いて対処した
  5. 展開して出てきたimgファイルをSDカードかUSBメモリに焼く
  6. imgファイルを焼いたメディアをR86Sに差し込む
  7. R86Sの電源を入れPOST画面が出たらDeleteを叩き、BIOSに入る
    • 通電時に勝手に電源が入るため一回落とした方がいい
  8. 起動順序を差し込んだメディアに変更する

eMMCへのOSインストール

Ubuntuのインストールディスクの中にOpenWRTのイメージをバンドルする方法がわからず、SDカードにimgを焼いてもマウントできなかったのでネットワークを経由してインストールしている。

事前準備

  1. OpenWRTのイメージファイルを入力しやすい短いファイル名にしてHTTPが疎通するどこかに置いておく
  2. R86S U1に前述のイメージと疎通可能なLAN線を刺す

インストール手順

  1. Ubuntu Serverのインストールイメージを落とす
    • 日本語版サイトから落とすとEFIイメージでないものが落ちてきたので本家から落としてきたほうがいい
  2. rufusを使って何かしらのメディアに焼く
  3. R86S U1を起動し、POST画面でDeleteを叩き、BIOSを開く
  4. 起動順序をUbuntuを焼いたメディアにする
    • USBの場合はUSB Key
  5. Ubuntuを起動し、GrubでTry or Installを選ぶ
    20250323_095333684.JPG
  6. キーマッピングを日本語にするところまでインストールウィザードを進める
  7. 右上のヘルプを開き、Enter shellする
    20250323_100328728.JPG
    20250323_100342943.JPG
  8. wgetで事前準備で用意した起動イメージを落とす
  9. eMMCにイメージを焼く
    dd if=openwrt-efi.img bs=1M of=/dev/mmcblk0
    
  10. shutdownコマンドを叩く
  11. 再起動でBIOSに入り起動順序をeMMCに変更
  12. GrubにOpenWRTが出て起動したらOK

開梱の儀

梱包状態。安い中華製品にしてはなかなか丁寧だ。

20250312_100023950.JPG

箱もしっかりしている。

20250312_100212496.JPG

横の小さな箱にはMicro HDMI -> HDMIケーブルが付属していた。これは親切だ。

20250312_100104107.JPG

開梱すると本体とACアダプタが見えた。やはり梱包が丁寧だ。

20250320_084100864.JPG

箱の底にはマニュアルと検査証、六角が入っていた。この六角は本体を開けるためのものだが、なめてしまい役に立たなかった。

20250320_084606694.JPG

ネットワークインターフェースはSFP+が2口、2.5GbEイーサーが3口。他に電源用USB-C、USB3.0x2、USB2.0x1、SDカード、Micro HDMIといった感じだ。

20250320_084156941.JPG
20250320_084532642.JPG

表面にはケースファンと冷却用のフィンがついている。デザインも悪くない。

20250320_084319103.JPG

裏面と片側面にはゴム足がついており横置きにも縦置きにも対応している感じだ

20250320_084350885.jpg
20250320_084428231.JPG

分解

付属の六角がなめてしまい役に立たなかったのでちゃんとしたのを買ってきた。対応するのは1.5mmだった。

20250322_121246053.JPG

表のふたを開けるとNVMeSSDスロットが見える。ネジ穴的に一番長い奴しか無理だろう。

20250322_121711775_1.JPG

本体をパカっと二つに。どうやらマザーボードは三枚くらいに分割されているようだった。

20250320_084156941.jpg

あとがき

EFIイメージかBIOSイメージかは好みで選んでいいという記事を何個か見たが、BIOSイメージだと起動しなかったため、EFIイメージのほうがいいかもしれない。

参考までに手持ちのAMD64マシンにBIOSイメージを刺したところ、そもそも認識すらしなかったためダメなのかもしれない。24.10固有の問題なのかどうかはわからないが、今時はUEFIが推奨される環境であると思われるため、EFIイメージで問題ないと思われる。

ひとまずこれで10GbE環境への一歩を踏み出せたと思う。LANが構築でき、現状の環境でWAN込みで安定稼働させられたら実際に10GbE契約もしていきたいところだ。

しかしイメージを焼いたSDをマウントできないのは想定外だった。FAT32でフォーマットしたはずなのでマウントできそうなものだが…。正直焼いてマウントして取り出すより、アップしてwgetしたほうが楽なので別にいいのだが。

20250402_085958973.JPG

私はここ数年、今ひとつ満たされない気持ちで過ごしている。この記事は一体これはどうやったら晴らせるのか、どこに道があるのか、それについてメイクアガールを見ていて気付いた内容として書いた内容だ。

気持ちが満たされない原因

端的に言えば所属するコミュニティを失ったことだと考えている。

何があれば満たされるのかについても時折考えていて、その一つの解はコミュニティだと考えていた。私が満たされていたときはROやECO、FF14を始めとしたネトゲにハマっていたからだ。そして多分それはネトゲそのものではなく、周囲の人たちと遊ぶのが楽しくてやっていたと思う。

私がこれらを離れた理由はプレイしていたタイトルの過疎化やサービス終了、所属していたフリーカンパニーの過疎化などで、言ってしまえば、去った理由はひとえに過疎化だった。

コミュニティだけでは足りない

コミュニティを失うだけであれば、コミュニティに入れば充足すると思うが、そう簡単な問題ではなかった。

私はネトゲをやめた後にも入れるコミュニティを探した。艦これのIRCに入ったり、TwitterやDiscord、Misskeyなど様々なコミュニティで気の合う人を探したりしたが、いずれも続かなかった。

私が当たったIRCは仲間内で雑談する内容のもので、仲間を増やして楽しく過ごそうというものだったが、艦これ仲間ということ以外に特に方向性はなかった。特に艦これの話をしているわけでもなかったので、次第に過疎化していった。

次に私はTwitterに活路を求めた。Twitterは長いことやっていて、ここでなら何かあると思ったからだ。しかし、ここでも私はまた特に何も得られなかった。

Twitterは扱う話題に特にテーマがない。言葉は悪いが有象無象の集まりだ。仮に似たような仕事や趣味の人をフォローしても、どうしても粗が見えてきてしまったり、興味が持てずにいた。

四六時中仕事や趣味の話ばかりをしているわけでもなく、飯の話や政治の話だってする。私だってそうだった。すると相手を許容できないと難しくなってきたり、飽きてきたりする。つまり昨今よく言われる見たくないものが見える現象だ。満たされないどころか心が削られてしまう。SNSに病んだ人がやたら多いのもそういうところに起因しているのだろう。

そこで私はもっと特化した趣旨を持つDiscordに道を求めたが、ある程度ジャンルが絞られていても内情はTwitterと大差なかった。或いはバチバチに縛ってある場所では話すことがなく廃村の様相になっているものもあり、難しさを感じた。Misskeyもそんな感じだ。ioはテーマレスでTwitterと変わらないし、テーマを極端に絞ったものは過疎に、そうでないと中途半端なものは、ただその属性の人が集まったTwitterみたいな状態だった。

私はいよいよわからなくなった。わからなくなったので、取り敢えず息のある小規模なコミュニティに属すために、今は兵庫丼うかどんに身を寄せているが、特に何か大きく変わったわけではない。人がいなさすぎるせいで見たくないものが見えなくなったのは進歩だったが、満たされているかどうかだと満たされていない。

自分でDiscordサーバーを建てようと考えたこともあったが、何を話すのかを定めることができなかった。おそらくそこら辺の作業用Discordと何ら変わらないものが生まれ、興味のない会話で埋め尽くされるだけだろうというのは目に見えていた。

ここで私はあることに気が付いた。欲しかったものはSNSなんかではなく、単なるコミュニティではないのではないかということだ。そこで過去なぜネトゲでは上手くいっていたかについて考えることにした。

指向性への気づき

ネトゲには指向性があった。指向性というのは同じ方向を向いているということだ。

例えばレベル上げをしたい、より上のコンテンツに向かいたい、ボスを倒したい、金銭や経験値稼ぎで記録的な効率をはじき出したい。その時、その場、その相手によって様々なものがあったと思うし、私と相手の目的が一致していなかったこともあったとは思う。ただ、その活動を共にしている時だけは同じ方向を向いていた。

活動中はともにそれに向かって夢中になり、ほかのことなど考えはしなかった。リアルのことなんて全部忘れて熱中できる環境がそこにあった。

そこで気づいたことは、私が欲しかったものは、何かに夢中になれ、建設的で、お互いに何かしら利益のあるコミュニティではないかということだ。ただ話ができるコミュニティがあればいいわけではない。

メイクアガールという作品

そんな中で、メイクアガールは私へ一つの気づきを与えてくれたと思う。明は研究を繰り返すものの、失敗作ばかり作っていた。創造に成功した0号に対しても興味が湧かなかった。明は何に対しても興味も悪意もなかった。

これは私なのだ。私は何に対しても興味がない。そう、興味を持てる事柄をすべて失ったのだ。明にとっての水溜稲葉は私にとってのネトゲだろう。しかし、もうそこには存在しない。稲葉は死んだ。ネトゲは滅んだ。

明にとっての0号は、私にとっての仮初の興味、Twitterとかだったのかもしれない。つまり失ってもよかった存在だ。しかし明はそこで、0号は家族であり、水溜稲葉で、失ってはいけないということに気づく。

では私はどうすればいいだろう?もうやるべきネトゲはない、何より恐らくネトゲで得るものはもうない。そうなったときに私がすべきことは何か?恐らく、軸を持つこと。私はコミュニティが欲しかったのではない。軸が欲しかった。軸がなければどこのコミュニティに入ったところで得られるものはない。人々は私に興味を持たないし、私も彼らに興味を持ちようがない。

私がなすべきことは失った稲葉や0号を追い求めることではなく、次に繋いでいくこと。メイクアガールで言えば、明が茜を受け入れること、茜と家族になることで、稲葉化した0号を忘れることかもしれない。稲葉化した0号は過去に束縛する呪いのようなものにも見える。きっとその先に未来はない。

恐らくこれこそが、自分が「自分」であり、「自分」が自分として、人生の筋道を見つけていくことなのではないかと感じた。虚無の中を過ごしてはいけない。深淵に向かう街道を突き進んではいけない。戻ってはならない。過去に引きずられないように、前に一歩でもいいから進んでいく。それはもしかしたら稲葉化した0号もそうなのかもしれない。彼女はファミレスで新しい自分として頑張っているように見えた。

新しい道へ踏み出していく。例えかつて明を愛した0号の存在を忘れることになろうとも。過去に縛られず、前へと進む。それが大切なことなのではないか、私はメイクアガールを通してそう思えたと思う。

では、どうするのか?

では、どうするのか?と聞かれたら、まだそれは見えていない。ただ恐らく何でもいいので何かをやっていくことが大切なのだと思う。やらない理由を探さず、何かに取り組んでいく。

そして色々な物事に触れて、前に進んでいく。それが出来さえすれば自然と周りに人もできて、楽しく過ごせるようになるのかもしれない。

これは恐らく、このブログも同じで、むやみやたらに何でも書くよりは、もう少し絞ったほうがいいのだと思う。

きっとそうしていけば、日々の鬱憤や空虚感も徐々になくなるのかもしれない。もし取り戻せるのであれば、私は取り戻したい、あの輝いていた日々を。

いや、きっと取り戻せなくとも、少なからず、今より良くはなるだろう。そう考えて、前へ進んでいきたい。