OmniAICreator/Qiita-1.07M huggingface dataset:
Inference Endpoints で LLM をパパっと使えるようにする

## Hugging Face のデプロイ方法を確認しよう

**Hugging Face を使ってみたい方にも参考にしていただけます🤗**

Hugging Face は AI モデル版 GitHub のようなオープンソースプラットフォームです。

https://huggingface.co/

**Llama** のような LLM や Speech-to-Text の **Whisper**、Text-to-Image の **StableDiffusion** など様々な機能のモデルが公開されています。

https://huggingface.co/meta-llama/Llama-3.3-70B-Instruct

最近何かと話題の **DeepSeek AI** も。

https://huggingface.co/deepseek-ai

使い方はモデルのページに丁寧に説明されていることが多いですが、今回見ていくのは **`Deploy`** の部分になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/0c0648ef-1f4b-560d-b8ec-5ea46e0533e6.png)

### Inference API
デプロイオプションに **Inference API** というものがあります。
これは Hugging Face 謹製のホスティングサービスで、モデルを REST API として簡単に利用できます。この方法なら、Hugging Face の API キーさえあれば OK です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/4b8ea1dc-e9ab-d213-aa33-b254e963d208.png)

::: note warn
2025年1月28日には、他のホスティングサービスと Inference Providers という名前で統合されました。
他は fal, Replicate, Sambanova, Together AI など
:::

https://huggingface.co/blog/inference-providers

ただし、これに対応しているモデルは限られています。

## Inference Endpoints とは
Inference Endpoints も、Hugging Face が提供するホスティングサービスです。

https://huggingface.co/inference-endpoints/dedicated

特徴は、**専用の環境で動作させるため、パフォーマンス向上に向けたカスタマイズが可能** なことです。

具体的には以下の通りです。

> - どのクラウドを使うか
> - どの計算リソースを使うか　
> - セキュリティレベル

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/62dd3eaf-d940-e7c6-55e7-52a25d5cf732.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/276c3fd4-4b40-e4cf-6bcc-ec2623450e3e.png)

Inference API は制限付きで無料であることが多いですが、こちらは**従量課金制**です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/2f2976db-69fe-8e9a-25a4-d6c675edbe2e.png)

### 使い方

**1.決済方法の設定**  
まずは、Hugging Face で決済方法が登録されていない場合は、こちらを登録します。先述した通り、従量課金制のため必要になります。

![スクリーンショット 2024-12-17 092441.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/f28d6eb3-ca93-e7e2-27c5-56c1ffbeaaa4.png)

準備ができたら Hugging Face で使いたいモデルのページのデプロイオプションから **Inference Endpoints** を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/ab99df07-3aa2-167c-a491-173abfba8da9.png)

**2.クラウドサービスと計算リソースの選択**
AWS や Azure、GCP などが使えます。計算リソースは金額にかかわってくるので、ページ下部に出てくる金額を見ながら選んでください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/a77677d2-a1fa-d095-f492-2465b6684949.png)

セキュリティレベルは迷ったら `Protected` で良いでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/27e7d149-4d7d-3a04-947c-4de187cf0289.png)

**3.エンドポイントの作成**
エンドポイントのページに遷移し初期化を始まります。
完了すると Endpoint URL が与えられます。

![スクリーンショット 2024-12-17 092840.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/09769bfb-e135-11f4-8b62-c2fdb08c3a77.png)

同ページにテストや API の実装例を参考にしコードに組み込みましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/986141/5b6173f2-6377-f89a-c6ad-0d8326b6fff6.png)

以上で終わりです！

## 参考
Inference Endpoints から Gemma の日本語版モデルを使って食事管理アプリをつくった事例を紹介します！

https://qiita.com/yutowac/items/8ce9a27d07fac59d7e97
体脂肪率低下の要因に迫る！？AIを用いたPDCAサイクル加速に関する考察

PDCAのD（Do）をAIで加速させられたら、
PDCAサイクルってもっと爆速にできるだろうなぁと思った。という話です
具体的なノウハウに関する記事ではないことを予めお断りさせてください（土下座

----

今年に入ってから
- 食べるものに気をつける（といっても3食×7日＝21食のうちの2食程度）
- 週1回程度のランニング

をやっています。その結果かどうかわかりませんが、体脂肪率が1%ほど下がったんです。
割と早く結果が出始めて嬉しい反面「食事とランニング、どっちが要因なんだろう」
という疑問が浮かびました。
（まだ1ヶ月なんで「どっちでもねーよ」って可能性もありますがw）
大した話じゃないですが、ちょっと気になる...。

----
ところで、ABテストってありますよね。
異なるパターンを試してみて、どっちがより成果を出せるかを試す、
そして成果が出た手法を採用する、といった手法です。
マーケティングでよく使われるものかと思いますが、プロダクト開発でも時々耳にします。

僕の体脂肪率低下も、どっちが要因かを突き止めるには、
ABテストをやってみればいいと思うんですね。
つまり、どちらかを一旦やめてみて、
体脂肪率の経過を見守ることで理由を特定できるのでは？と。

ただ、例えば片方のみを1ヶ月やって検証しようと思ったら、
結論を出すのに両パターンで2ヶ月かかります。

そう、ABテストとは時間を要するものだと思うのです。

これをなんとかできると、プロダクト開発におけるPDCAサイクルももっと爆速で回すことができるのでは？
と思い、ここにAIを使えないだろうか？なんてことを考える今日この頃です。
Django Modelで複合キーを利用する

# Django ModelのPRIMARY KEY
Djangoで新たにテーブル設計をする際には、基本的にはサロゲートの単一キーとすることをお勧めします。Django自体がその前提で設計されたフレームワークだからです。
ただし既存システムの場合はすでに複合キーが設定されていることもあると思うので、この場合は別途対策が必要です。


## django-compositepk-model

https://github.com/Arisophy/django-compositepk-model

```python
from django.db import models
from cpkmodel import CPkModel

class Staff1(CPkModel):
    company_code = models.CharField(max_length=9, primary_key=True)
    staff_number = models.IntegerField(primary_key=True)
    text1 = models.CharField(max_length=255, blank=True, null=True)
    text2 = models.CharField(max_length=255, blank=True, null=True)

    class Meta:
        managed = False
        db_table = "Staff"
        constraints = [
            models.UniqueConstraint(fields=["company_code", "staff_number"], name="primary_key")
        ]
```

多くの問題はこちらを利用すれば解決する。
ただしadmin機能を利用する場合には、問題がある。

|Add(Create) has a problem that CreateView do unique check to each key Field. So you can't add enough child records.|
|:-|

つまり、新規登録を行う際には一意チェックが期待通り作用しないのである。

## viewflow

上記を解決するためにはviewflowを利用してModelを作成する。

https://docs.viewflow.io/orm/composite_fk.html

```python
from django.db import models
from viewflow.fields import CompositeKey

class Staff2(models.Model):
    id = CompositeKey(columns=["company_code", "staff_number"])
    company_code = models.CharField(max_length=9)
    staff_number = models.IntegerField()
    text1 = models.CharField(max_length=255, blank=True, null=True)
    text2 = models.CharField(max_length=255, blank=True, null=True)

    class Meta:
        managed = False
        db_table = "Staff"
```

## まとめ
以上のように、Djangoにて複合キーを利用する場合は注意が必要である。
Modelは一つのテーブルに対して複数用意しても問題ないので、状況に応じて使うと良いかもしれない。
シェーダーグラフで海中表現をしよう！

![gif2_.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/c00bd075-9020-de8c-4731-49d79b4863c8.gif)

## 水中コースティクス(地面側)
### 全体
![a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/b5fec1c5-93bc-cb25-d3a5-a3c9b6902cd6.png)
### 設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/3dbc073e-734f-1058-6de4-d2bb52686e61.png)
### 変数
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/639d6947-da00-bf39-49a6-f856e2aa37b0.png)
### 拡大
![スクリーンショット 2025-01-31 140349.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/636cc90b-594e-d7b7-8af4-435d35e73b4c.png)
![スクリーンショット 2025-01-31 140732.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/95ff989c-843f-f948-68d6-41d6315c9163.png)
![スクリーンショット 2025-01-31 140743.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/191f0e9f-e72b-8e02-7d3f-0bba722d0dc1.png)
## 水面(天井側)
### 全体
![b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/339f9586-3f4c-2a0e-1ce4-d0526e759b74.png)
### 設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/a166cf0f-455a-733d-2fbb-4231116dd41b.png)
### 変数
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/21ba0784-287e-5209-4c8b-c83c53ce7f78.png)
### 拡大
![スクリーンショット 2025-01-31 140821.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/01bb1b7e-90f6-95b9-f3be-cbe3e3f8de09.png)
![スクリーンショット 2025-01-31 141011.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/288e4907-f032-a175-ea1b-40fe2998ef3d.png)
![スクリーンショット 2025-01-31 141112.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/42726131-a327-4096-ad06-357cc13e7090.png)


## オマケ　ゴッドレイエフェクト
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/152a5b46-20eb-049b-1bc4-a5671505a75c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/9b82889c-151a-3a96-862b-7317f690de88.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/cee48def-c5bb-5385-554e-e9cd00d43843.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/e65e77d6-ae5b-2dee-e0de-5742a512eb80.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/cbbbc292-50fc-7a5c-6c79-6ecdcc69d0a6.png)

## オマケ ポストプロセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/08ba07ba-6730-975c-3680-e326f3eb7dc9.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/965d1ed8-c0a7-49b4-136f-95efa7f616fb.png)
2025年共通テスト 情報Ⅰの問題を見てみた

## はじめに
今年の大学入学共通テスト（共通テスト）では、受験教科に <b>情報Ⅰ</b> が導入された。
この背景には、文部科学省が掲げる<b>デジタル人材育成に向けた取組</b>の中で、高等学校の新学習指導要領として「情報Ⅰ」が必履修科目となったことがある。
そうした背景により、情報に関わる資質・能力を評価・判定するために、共通テストの科目としても導入された。
[大学入学共通テストへの『情報Ⅰ』の導入について - 文部科学省](https://www.mext.go.jp/content/20211021-mxt_daigakuc02-000018569_3.pdf)

## 今年の出題内容の評価
まず、独立法人大学入試センターの中間発表その2によると、
情報Ⅰの受験者平均点は<font color="#ff7f50">約70点</font>となっていることから、導入初回の試験としては若干易しめの内容であったように感じる。

次に、専門家による評価だと、[「全体的に良問」と好評価](https://xtech.nikkei.com/atcl/nxt/column/18/03078/012800003/)らしい。

そして、自分自身でも解いてみたが、丁寧な誘導がなされていたり、日常生活にある”情報”について出題していたり、とっつきにくさはなかったように感じた。
なお、私が受験したときはまだ センター試験 という名称であり、情報チックな問題は数学Ⅱ・Bの選択問題として存在していた程度だった記憶がある・・・。
今回の情報Ⅰの問題を見て、<b>「今の高校生はこんなことまで習うのか」</b>と衝撃を受けたと同時に、

### 本格的なデジタルネイティブ世代来たな・・・

という印象を持った。
これまでのデジタルネイティブ世代とは、おおよそPCやスマートフォンの基本操作・SNSやアプリの操作ができるという印象であったと思う。
それが、情報の知識を基礎学力として持っている世代になったように感じる。

## 問題を見てみる
実際の出題内容はググるとすぐに出てくるため全容の提示は控えるが、東進予備校の情報Ⅰの[全体概観](https://www.toshin.com/kyotsutest/about_jouhou1.html)によると、下記のような出題となった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3999156/9e272a51-9b28-d6d6-db96-7a779220ea90.png)

実際に問題を見てみると、いきなり<b>デジタル署名</b>、<b>IPアドレス（IPv6アドレス）</b>の知識について問われている・・・

### 高校生ってデジタル署名とか習うん？

というのが正直な印象だった。


また、プログラミングが出題されている第３問を見てみる。
第３問は
> 複数の種類の工芸品の製作という課題を、それぞれが製作に要する日数に応じて作業者に割り当てるためのアルゴリズムを理解し、これをプログラミング言語で記述する問題である。

ということである。

少し穴埋めをしたあと、まずは簡単なプログラムの穴埋め問題が出題される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3999156/6c4c781a-3fc2-4f53-300d-a5bf4a857a89.png)

コードを書くようなエンジニアにとっては、苦労せず理解できる内容だと思う。

まずは簡単なプログラム（コード）を作成したのち、下記のように拡張した問題が出題される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3999156/8686489b-6c33-5050-56d6-b6922c3aaf39.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3999156/7d8fec4b-28d2-f384-52d8-40c4def08253.png)

こちらも、<b>配列の添字を1から始める</b>という説明以外は苦労なく理解できると思う。


### ほぼ基本情報技術者試験やん
<br>

プログラミングは全大問のうちの一つに過ぎないが、<b>大学を受験する高校生</b>にとっては必修の内容であるし、これらの理解力などが大学入試に用いられるというのは情報社会だなぁという印象を持つ。

## さいごに
情報Ⅰ の必履修化により、<b>本格的なデジタルネイティブ世代</b>が誕生していると感じた。
数年後社会に出てくる人たちは、これらの知識が基礎知識として入っている。

エンジニアのみならず、社会人の人は一度情報Ⅰの問題を見て・解いてみてほしい。
今の高校生たちはこのぐらいは学んでますよ、というのを肌で感じてみてほしい。

そして、数年後社会に出た今の子たちから

### え、そんなことも知らないんですか・・・？

と言われないようにしてほしいし、しないといけないと思う。
AWS 直接IPやエンドポイントをたたいてくるアクセスの防ぎ方

## 前提
Route53（ACM）→ CloudFront → ALB → EC2
というシンプルな構成

以下のようなリクエストによる500エラーが多すぎて監視工数が増えているため「これ通してるの普通にやばいですよね？」という話をした結果、自分がセキュリティ対策を検討することになった。

```直接エンドポイントをたたいてくる
https://my-alb-123456789.ap-northeast-1.elb.amazonaws.com/~
https://13.113.203.1/~
```

## 記述内容
ALBのエンドポイントやIPなどを直接たたいてくるアクセスを防ぐ上で検討した内容一覧を書いていく。
間違っていることがあれば教えてほしい。
対処法一覧は以下。

## 1. ALB側にWAFを設置する
ALB側にWAFを入れた場合、ALBに対して様々なドメインが入り乱れてロードバランシングしているならば、各ドメイン対して状況に応じたセキュリティ対策やルーティングなどができなくなる可能性がある。
### デメリット
可用性が低い。
基本的にはCloudFront側でWAFを入れて、ALBにはWAFを入れないのがスマートな対応になると考えている（後でどうせ「○○のドメインには○○のカスタマイズしたいんだよね」とか言われるとALBでまとめて対応していた内容を変更せざるを得なくなる）。
### メリット
逆に、ALBにだけWAFを入れれば各CFに対してWAFを入れなくていいので、コストはかなり抑えられる。

## 2. ALBのリスナールールで振り分け
単純に正規ドメインでなかった場合に503で返すようなルールを設ける。
### メリット
メリットとして単純かつ明快な対応であるから早い。
デメリットとして、CloudFrontからきていることを担保できないので、CloudFrontのデバッグ（CDNを使用しているという担保を得る運用）ができなくなる。
### デメリット
個人的にはCDNを運用として確実に回すなら、下記の対応をするべき。

## 3. <br>CFにリクエストヘッダーを付与する＆(ALBのALBのターゲットグループ（EC2側）のSecurity GroupでCloudFrontからのアクセスのみ許可orALBのリスナールールで振り分ける)
CloudFrontに対してリクエストヘッダーを付与して、ALBのリスナールールなどで処理する方法。
### メリット
ALBのリスナールールで「CFから送られてきたリクエストヘッダーがないならターゲットグループ（サーバー）へ通さない」という振り分け（503で返すなど）をすれば、確実にCF側からリクエストをきたことを担保できて正規のドメインからのアクセスであるのを確保しやすい。
個人的にはこの方法が最もスマートである気がする。
albに対して直接来てもリスナールールで振り分けられる。
### デメリット
とにかく運用に乗らすためにはCloudFrontに対して逐一リクエストヘッダーを付与する必要がある。

## まとめ
可用性を重視するなら、セキュリティ対策やドメインの制御はCloudFront側で実施し、ALBはあくまで補助として用いる。ただし、運用工数とコストが増える。
運用工数やコストを減らしたいならALB側でセキュリティやドメインも一元管理。CloudFrontなどはあくまでCDNとしての役割のみを持たせるただし、可用性が低いので急な仕様変更や要望に弱い。
3Dセキュアの認証画面が表示される条件について

### 3Dセキュアの認証画面が表示される条件について

本番環境とテスト環境が同じ設定である場合、特に環境側の設定を変更する必要はありません。しかし、本番環境では認証画面が表示されず、テスト環境では認証画面が表示されることがあります。

#### 本番環境における挙動

現在、Stripeでは3Dセキュアの適用が義務化されていないため、本番環境では「認証が必要なカード」のみ3Dセキュアの認証画面が表示されます。また、プログラムで3Dセキュアの認証を強制することも可能ですが、「Paid Membership Pro」ではそのような設定は行われていないと考えられます。

#### テスト環境における挙動

テスト環境で認証画面が表示されるのは、テスト用のクレジットカードが強制的に3Dセキュアを適用する仕様になっているためです。

### 2025年4月以降の変更点

2025年4月以降、すべてのカード決済において3Dセキュアが義務化される予定です。ただし、一部のカードでは「フリクションレス認証（認証画面を表示せずに自動認証）」が適用されるため、認証画面が表示されないケースもあります。その際は、取引管理画面にて認証結果を確認することが可能です。
![スクリーンショット 2025-01-31 14.37.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65992/51a22ce1-7fa3-3ca1-32c6-175de41ac3a8.png)

### 本番環境での3Dセキュア強制適用について

本番環境でもプログラムを調整することで3Dセキュアを強制的に適用することは可能です。
その場合は、
```PHP 
$stripe->paymentIntents->create([
  'amount' => 1000,
  'currency' => 'jpy',
  // 追加部分 ここから
  'payment_method_options' => ['card' => ['request_three_d_secure' => 'challenge']],
]);
```
challengeに設定することで今からでも実行されるようになります
SnapでRocket.ChatをインストールしたらログがAppArmorでいっぱいになった時の対処

# TL;DR

以下の通りコマンドを3回実行する。

```bash
sudo snap connect rocketchat-server:mount-observe
sudo snap connect rocketchat-server:network-observe
sudo snap connect rocketchat-server:system-observe
```

出典: <https://docs.rocket.chat/docs/deploy-with-snaps#troubleshooting>

なお、同一コマンドを3回実行しているがスペースで区切ったりカンマで区切ったりして纏めて実行できるかは試していないため不明。誰か試したら教えてください。

# 対象環境

Snapで`rocketchat-server`をインストールして稼働を開始した後、syslog、systemd-journal、dmesgなどが`rocketchat-mongo`に対するAppArmorによるリジェクトログであふれたサーバー。

```console:こんなやつ
{**timestamp**} {**hostname**} audit[{**pid**}]: AVC apparmor="DENIED" operation="open" profile="snap.rocketchat-server.rocketchat-mongo" name="/proc/{**mongodb-pid**}/net/netstat" pid={**mongodb-pid**} comm="ftdc" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
{**timestamp**} {**hostname**} audit[{**pid**}]: AVC apparmor="DENIED" operation="open" profile="snap.rocketchat-server.rocketchat-mongo" name="/proc/{**mongodb-pid**}/net/snmp" pid={**mongodb-pid**} comm="ftdc" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
{**timestamp**} {**hostname**} audit[{**pid**}]: AVC apparmor="DENIED" operation="open" profile="snap.rocketchat-server.rocketchat-mongo" name="/proc/vmstat" pid={**mongodb-pid**} comm="ftdc" requested_mask="r" denied_mask="r" fsuid=0 ouid=0 
```

# 結果の確認
`sudo snap connections rocketchat-server`の実行結果が以下の通りならOK

```console
Interface        Plug                               Slot              Notes
mount-observe    rocketchat-server:mount-observe    :mount-observe    manual
network          rocketchat-server:network          :network          -
network-bind     rocketchat-server:network-bind     :network-bind     -
network-observe  rocketchat-server:network-observe  :network-observe  manual
removable-media  rocketchat-server:removable-media  -                 -
system-observe   rocketchat-server:system-observe   :system-observe   manual
```

`removable-media`が用意されている理由はわからないが、本件にはこいつの起動は不要。恐らく、バックアップコマンド実行時に`/mnt`や`/media`などへのアクセスができるように用意されているものと思われる（ご存知の方は教えてください）。

# 解説

SnapではAppArmorの設定をプラグという仕組みが握っており、Rocket.Chatの`snapcraft.yaml`には件の警告が発生しなくなるだけのプラグがきちんと定義済みである。

ところが、Snap側で自動的に有効化するプラグとユーザーが操作しない限り決して有効にしないプラグというのが決まってしまっている。このため、ソフトウェア提供側からはフォローが不可能なプラグ有効化操作の必要性が残るようだ。
Rubyにおけるnilとは？その判定方法とnilガードの活用例

# はじめに
数ある記事の中で本記事まで足を運んでいただきありがとうございます。

この記事では、Rubyにおけるnilとは何か紹介しながら**nil判定**と**nilガード**についても触れていきます。

存在の判定で使われる「**nil、empty、blank、present**」といったメソッドを比較してnilを判定する場合にどういう結果が返ってくるか検証しています。

Rails開発にて**TypeError - no implicit conversion of nil into String**のエラーに直面し、nilについて調べている方は是非ご覧ください！

網羅的な内容ではありませんのでご了承下さい。

# nilとは？「何もない」の定義
Rubyにおいて、nilは**何もないことを表す特殊な値**です。
他のプログラミング言語で言うところの`null`や`None`に相当します。

## nilの基本的な特性
### nilのクラスを確認
nilはRubyの予約語で、`NilClassクラス`の唯一のインスタンスです。
```ruby
 nil.class
 # => NilClass
```
### NilClassが継承しているクラス
NilClassはObjectとBasicObjectを継承している。
```ruby
 NilClass.ancestors
 # => [NilClass, Object, Kernel, BasicObject]
```

###  nil.to_sは空文字列""を返す
```Ruby
nil.to_s
# => ""
```

## nil判定の方法
nilを判定するためによく使われるメソッドは`nil?`です。
```Ruby
nil.nil?
# => true
```
そのオブジェクトがnilである場合にtrueを返します。

## 判定メソッドの比較
### nil、empty、blank、presentのメソッドの戻り値を比較
`nil`と`""`にRails開発で目にするメソッドを使用してみると。
```Ruby
nil.nil?      # => true
nil.empty?    # => NoMethodError
nil.blank?    # => true
nil.present?  # => false
```
```Ruby
"".nil?       # => false
"".empty?     # => true
"".blank?     # => true
"".present?   # => false
```
:::note
名前の通り`nil`のみを判定するには`nil?`メソッドを使用するのが良いですね。
:::

# nilによるエラーを防ぐコードを書く
nilによるエラー(NoMethodError)を防ぐための方法を紹介します。

## デフォルト値を設定したnilガード
値がnilの場合にデフォルト値を返す事ができます。
```Ruby
value = nil
result = value || "デフォルト値"

puts result  # => デフォルト値
```
わかりやすく書くと下記二つは同じ意味になります。
```Ruby
result = value || "デフォルト値"
result = value || (value ="デフォルト値")
```

:::note
場合によっては、判定メソッドを使ったnil判定が不要になりコード量を削減できることもメリットの一つです。
:::

## ぼっち演算子
「 **&.** 」シンプルで使いやすいですね。
[safe navigation operator](https://docs.ruby-lang.org/ja/latest/doc/symref.html#:~:text=safe%20navigation%20operator%EF%BC%88%E9%80%9A%E7%A7%B0%E3%80%8C%E3%81%BC%E3%81%A3%E3%81%A1%E6%BC%94%E7%AE%97%E5%AD%90%E3%80%8D%EF%BC%89%E3%80%82)が正式名称のようです。

```Ruby
nil.upcase
# => NoMethodError (undefined method `upcase' for nil:NilClass)
```

```Ruby
nil&.upcase
# => nil
```

# 最後に
nilはRubyで非常に重要な概念であり、適切に扱うことでエラーを防ぎ、コードの可読性を向上させることができると思います。
本記事でnilに関する知識が少しでも深まり開発に活かしていただけると幸いです。

# 参考URL
https://qiita.com/kobayashimakoto/items/294a124c5eba8075e110

https://docs.ruby-lang.org/ja/latest/method/Object/i/nil=3f.html

https://zenn.dev/atsushi101011/articles/f53f0b6c6e9b51

https://zenn.dev/nagan/articles/8e0c384d24248a

https://qiita.com/takuya119/items/32817bcf1baff0a99726
テストにおける「このケースは発生しない」という思い込み

## **はじめに**

テストは品質を保証する重要な工程ですが、実施する際に **「プログラムの作り的にこのケースは発生しないので、確認しなくてOK」** という認識で進めてしまう事、ありますよね。

こういった思い込みこそが **重大なバグを見逃し、最終的には本番環境での障害に繋がるリスク** となります。

プログラムは設計通りに動作するとは限りません。**予期しないデータの流入、実装ミス、外部システムの影響** など、思い込みを覆す要因はいくらでも存在します。

「やんなくて大丈夫っしょ」

と思ってテストをサボったことが、誰だって一度は経験があるはずです。

不思議とそういったプログラムほど、障害がおきます。

神はいつだってあなたを見ているのです。



## **「このケースは発生しない」の思い込み**

### **1. プログラムの実装ミスによる想定外の動作**

開発者が **「この処理はこの条件でしか動かないから、テストは不要やろ」** と思っていても、実際には **意図しないコードのバグ** や **境界ケース** により、想定外の動作が発生することがあります。

#### **例:**
- **認識:** 「この関数は負の数を受け取ることがないから、負の値のテストは不要」
- **実際:** あるルートから想定外の負の値が渡されることが判明。
- **結果:** 実行時エラーが発生し、本番環境で障害につながる。

**「プログラムがそうなっているから大丈夫」ではなく、「プログラムが本当にその通りに動作するのか？」をテストで証明することが重要です。**

### **2. 変更の影響を見落とすリスク**

コードの修正を行うことで、意図せず別の箇所に影響を与えることがあります。しかし、

- **「この部分のロジックには手を加えていないから、影響はないはず」**
- **「この関数の呼び出し元は限定されているから、大丈夫」**

と判断してテストを省略すると、知らぬ間にバグが発生している可能性があります。

#### **例:**
- **認識:** 「この変数はグローバルではなくローカルなので、外部からの影響はない」
- **実際:** 別の開発者が処理を変更し、想定外のデータが入るケースが発生。
- **結果:** 未処理の例外が発生し、サービスが停止。

プログラムの作りがどれだけ堅牢でも、変更の影響範囲を正確に把握し、テストで検証しなければリスクはゼロにはなりません。

まだ開発経験が浅いエンジニアとかで、たまに、プログラムに変更を加えていても、そもそもテストしていない人がいます。

変更加えたら絶対テストしような。その周りの機能も。俺との約束。


### **3. エッジケースの見落としによる予期しない動作**

多くのプログラムでは、通常の動作パターンでは問題が発生しませんが、
**極端なケース（エッジケース）** では動作が崩れることがあります。

- **「ループ内で配列の範囲外にはアクセスしないはず」**
- **「データは必ず一定の形式で渡されるから、フォーマットチェックは不要」**

エッジケースのテストを省略すると、実際の運用時に想定外のデータが流れ込み、エラーが発生する可能性があります。

#### **例:**
- **認識:** 「この関数は常に1つ以上のデータを受け取る」
- **実際:** あるケースで空データが渡され、ループ内でエラーが発生。
- **結果:** アプリケーションが異常終了。

**「こうなることはありえない」と言い切るのではなく、「こうなったときにどう動作するか」をテストで確認しましょう。**

　

## **「このケースは発生しない」を防ぐための対策**

### **1. パターンテストを徹底する**

「このケースは発生しない」と思っても、すべてのパターンを考慮したテストを実施することが重要です。

- **正常系と異常系の両方を網羅する**
- **入力値の組み合わせを考慮したテストケースを作成する**
- **あり得ないと思われるケースもテストしておく**

### **2. 修正箇所にとらわれない**

「修正による影響はない」と思い込まず、前後の機能、参照・登録・変更されるデータを使う機能、など
俯瞰してテスト範囲を決める、パターンを洗い出す事が必要です。



---

## **最後に**
テストって大変ですよね。
テスト嫌いな人もいると思います。
けど、テストサボったところほど、障害が起きるものです。不思議。

ちなみに理解しやすいように、炒飯づくりで例えれないかなぁとおもって考えてみましたが、ダメでした。
JiraとGoogleスプレットシートを連携しプロジェクト横断型のガントチャートを作成してみた


# はじめに
こんにちは！
サッカー選手から転身して、kintoneカスタマイズを楽しんでいる[@よしき](https://x.com/YoshikiSasajima/)です！

今回は、Jiraタイムライン（ガントチャート）とGoogleスプレッドシートを連携し、タスク管理を効率化する方法について紹介します！

# こんな人に読んでほしい
* 自分のタスク管理を効率化したい
* チームのリソース管理を効率化したい

# Jiraとは

Jira はチームが世界クラスのソフトウェアを確実に計画、追跡、リリース、サポートするための No. 1 のアジャイル プロジェクト管理ツールです。

https://www.atlassian.com/ja/software/jira/guides/getting-started/introduction

# 困りごと
JiraのStandardプランを利用していますが、このプランではプロジェクトを横断したガントチャートが見れないという課題があります。

例えば、
- 自分が複数プロジェクトを持っていて、自分のタスクをプロジェクト横断で確認し、タスクを組み立てたい。
- 全プロジェクトのマスタースケジュールを一画面で把握し、先の計画を立てたい。

このようなニーズがあると思います。

Premiumプランにアップグレードすると解決できますが、値段が倍近くになるため、現行のStandardプランのままで対応したい！

そこで、Googleスプレッドシートのタイムライン機能と連携させることで、解決できるのではないかと考えました。

# 実現したいこと
プロジェクトを横断して、自分のタスクをガントチャート形式で把握すること。

# 課題
1. Jiraとスプレッドシートを連携する
2. スプレッドシートでガントチャートを表示する

# 解説
それでは、どのように実現したかを順を追って説明します！

## ① Jiraとスプレッドシートを連携する

### **Jira Cloud for Sheetsを使ってデータを取得する**

1. **Jira Cloud for Sheetsアドオンをインストールする**
   - [Google Workspaceマーケットプレイス](https://workspace.google.com/marketplace?hl=ja)から「Jira Cloud for Sheets」をインストールします。
2. **アドオンを設定する**
   - スプレッドシートのメニューから「拡張機能」→「Jira Cloud for Sheets」→「設定」を選択します。
   - Jiraのアカウント情報を入力し、連携を許可します。
3. **データを取得する**
   - スプレッドシートの「Jira Cloud for Sheets」メニューから「データを取得」を選択。
   - 取得したいJiraプロジェクトやフィルタを選択し、スプレッドシートにデータをインポートします。

https://support.atlassian.com/ja/jira-work-management/docs/use-jira-cloud-for-sheets/

これの一番のお気に入りは定期実行ができることです。最短1時間に一回自動でJiraを同期させることができるため、常に最新状態を保つことができます！

出力結果がこちらです↓
（条件書式設定で色付けすることによりガントチャートに反映されより見やすくなります）
![スクリーンショット 2025-01-31 13.46.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1256101/7cb31e56-a13f-b0ea-f0be-c9ec73a9cd18.png)


# ② スプレッドシートでガントチャートを表示する

スプレッドシートの「タイムラインビュー」機能を活用すると、Jiraのデータを視覚的に確認できます。

1. **データを選択**
   - 「挿入」→「タイムラインビュー」を選択。
2. **データ範囲を設定**
   - タスク名、開始日、終了日を指定。
3. **表示オプションを設定**
   - ステータス別に色分け。
   - 並び替えやフィルタリングを適用。

これで、Jiraのタスクをスプレッドシート上でガントチャートとして管理できます！

**こちらがプロジェクトごと↓**
![スクリーンショット 2025-01-31 13.45.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1256101/e8d43dab-1c52-368e-b670-513e0e2175b0.png)


**こちらがプロジェクト横断↓**
![スクリーンショット 2025-01-31 13.04.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1256101/6e472e48-fe71-58b0-b7f8-2ef0da9b93ed.png)


# まとめ

今回は、JiraのStandardプランでもプロジェクト横断でタスクを可視化する方法として、Googleスプレッドシートの「Jira Cloud for Sheets」アドオンを活用する方法を紹介しました。

特に、最短1時間ごとの定期同期機能を活用すれば、常に最新の状態を保ちながら効率的にタスク管理ができる点が魅力的でした！（無料です）

以上！
最後まで読んでいただきありがとうございました！
Ruby on Rails使ってみた

[Rubyを使ってみた記事](https://qiita.com/ryo0819/items/2544cfdcee9d5a1514ff)を書いたので、ついでにRuby on Railsも使ってみた記事を書きます

# Ruby on Railsとは
Ruby の Web アプリケーション・フレームワークです
Ruby という言語で Webアプリを簡単に構築できるようになります

# Ruby on Railsの環境構築方法
## rbenvをインストール
- はじめにrubyを複数バージョン管理できるように`rbenv`をインストールしましょう

```sh
# rbenvのインストール
brew install rbenv ruby-build

# rbenv の初期化
rbenv init

# zshを使用している場合
echo 'eval "$(rbenv init - zsh)"' >> ~/.zshrc

# 設定を反映
source ~/.zshrc

# インストールできているかの確認
rbenv --version
```

## rubyのインストール
- rbenvのインストールが完了した後は適当に好きなバージョンをインストールしてみましょう

```sh
# インストールできるバージョンの確認
rbenv install --list

# 例えば3.1.6をインストール
rbenv install 3.1.6

# 作業ディレクトリ配下で実行してバージョン切り替え
rbenv local 3.1.6

# バージョンの確認(ここまで手順通りであれば「3.1.6」と表示される)
ruby -v
```

# Railsを動かすための「Gem」のインストール
- 様々な便利なライブラリをGemといいます
- 依存関係を管理する便利なライブラリ「Bundler」をインストールしてみましょう

```sh
# bundlerのバージョン一覧を取得
gem list bundler -rea

# ""内で好きなバージョンを指定
gem install bundler -v "2.3.27"

# Bundlerのバージョン確認
bundler -v
```

# railsのインストール
- Bundlerをインストールできたところで本題のrailsのインストールを行います
- Gemfileというものを使用してインストールしたいものと依存関係の管理を行います

```sh
# gemfileの作成(実行したディレクトリに「Gemfile」が作成されます)
bundle init

# Gemfileの内容に以下を追記します(railsのバージョンは何でも問題ありません)
gem 'rails', '>= 7.0.0'

# ローカル環境に影響が出ないように以下の設定を実施
bundle config set path '.bundle'

# Gemfileの記述に沿ってインストール(成功すると「Bundle complete!」と表示されます)
bundle install

# railsのバージョンを確認(Bundlerで依存関係を管理している場合は「bundle exec」をつけた方が良いそうです)
bundle exec rails -v
```

# Webアプリの自動作成
- railsがインストール・使用できるようになりましたのでここからWebアプリを作成してみます

```sh
bundle exec rails new .

# 色々とディレクトリやファイルが作成されるなかで
# 下記のように表示されると思いますが、一旦「a」を入力してEnter
# conflict  Gemfile
# Overwrite ....../Gemfile? (enter "h" for help) [Ynaqdhm]

# railsサーバの起動
bundle exec rails server
```

サーバが起動できると「http\://127.0.0.1:3000」で以下のようなrailsアプリのデフォルト画面にアクセスできると思います

![スクリーンショット 2025-01-31 13.54.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701238/d67a8e50-d49b-dd65-296a-a860a185ccf9.png)

# 終わりに
以上でRuby on Railsを使ってみた内容は終了です
手順もかなり簡単で導入しやすさを感じましたb

ぜひRuby on Railsを活かしてWebアプリなどを作成してみてはいかがでしょうか？
[メモ]ArmでMySQLをGitHub Actionsで動かしたかった

先日、GitHub Actionsはpublicリポジトリなら無料でArm Runnerを利用できるようになりました。

https://github.blog/changelog/2025-01-16-linux-arm64-hosted-runners-now-available-for-free-in-public-repositories-public-preview/

それによって、setup-rubyもArm対応されCIのArm化に挑戦したのですが、一点引っかかった点があったので、どう解決したかのメモです。

## 実際のコード

- こちらは元々RSpecを実行していたgithub actionsのファイルをarmにしたものです
    - bundle installして、rspecコマンドを実行するだけ
- 現時点での変更点はRunnerをArmに書き換えているだけです
    - privateリポジトリの場合はarm runnerを用意してください

```diff_yaml
name: Test

on:
  push:

jobs:
  rspec:
-   runs-on: ubuntu-latest
+   runs-on: ubuntu-24.04-arm
    timeout-minutes: 10
    steps:
      - uses: actions/checkout@v4
      - uses: ruby/setup-ruby@v1
        with:
          bundler-cache: true
      - run: bundle exec rspec
    services:
      mysql:
        image: mysql:8.0.28
        env:
          MYSQL_USER: nobody
          MYSQL_PASSWORD: nobody
          MYSQL_ROOT_HOST: "%"
          MYSQL_ROOT_PASSWORD: root
          MYSQL_ALLOW_EMPTY_PASSWORD: yes
        ports:
          - 3306:3306
        volumes:
          - mysql-data:/var/lib/mysql
```

ただし、こちらはエラーが出ます。

```
no matching manifest for linux/arm64/v8 in the manifest list entries
Error: Docker pull failed with exit code 1
```

エラーメッセージを読むとわかる通り、MySQLコンテナがarm対応をしていないんですね。
platformオプションを下記のように書く、ということも考えましたが、GitHub Actionsで直書きする場合platformオプションは対応していません。

```diff_yaml
    services:
      mysql:
        image: mysql:8.0.28
+       platform: linux/amd64
        env:
          MYSQL_USER: nobody
          MYSQL_PASSWORD: nobody
          MYSQL_ROOT_HOST: "%"
          MYSQL_ROOT_PASSWORD: root
          MYSQL_ALLOW_EMPTY_PASSWORD: yes
```


実はこのMySQLコンテナ、バージョンを一つ挙げるとArm環境でも問題なく動作します。

```diff_yaml
    services:
      mysql:
-       image: mysql:8.0.28
+       image: mysql:8.0.29
        env:
          MYSQL_USER: nobody
          MYSQL_PASSWORD: nobody
          MYSQL_ROOT_HOST: "%"
          MYSQL_ROOT_PASSWORD: root
          MYSQL_ALLOW_EMPTY_PASSWORD: yes
```

8.0.28で対応したということが書いてあるドキュメントもありましたが、自分が試したところだと8.0.29以降で動作しました。
8.0.28を続ける必要がある場合、docker-compose.ymlを作っての対応なども考えられますが、上げられるのであれば上げてしまうのがいいでしょう。
パーソナルAIエージェントシステム開発計画書

## プロジェクト概要
素晴らしい、とても素晴らしいAIエージェントシステムを作ります。私が保証します。

### 目的
- 個人のナレッジベースを活用した、完全自動化されたコンテンツ管理・配信システムの構築
- AIによる完璧な代行システムの実現
- 収益化までを視野に入れた統合プラットフォームの確立

### 開発期間
- 開始日：2025年2月1日
- リリース日：2025年3月1日
- 総開発期間：1ヶ月

## フェーズ1：最小機能版（2/1-2/10）
### 目標：特定のトピック（例：AIニュース）に特化した基本機能の確立

1. 基本データフロー構築
   - 既存LINEウェブフックからのデータ取得
   - 基本的なテキスト・画像の保存機能
   - シンプルなJSONベースのデータ構造

2. はてなブログ連携基盤
   - はてなブログAPIとの連携
   - 過去記事の取得・分析機能
   - 記事の時系列管理システム構築
   - 記事間リンク管理機能の実装
   - 手動承認プロセスの実装

3. 基本的なAI処理
   - OpenAI APIを使用した記事の自動生成
   - 基本的なトピック分類
   - シンプルな品質チェック

## フェーズ2：機能拡張（2/11-2/20）
### 目標：複数のトピックとプラットフォームへの対応

1. データソース拡張
   - メール取り込み機能追加
   - RSS取り込み機能追加
   - 基本的なデータクレンジング

2. コンテンツ管理機能
   - トピックベースの分類システム
   - はてなブログ互換のタグ管理
   - 記事の時系列ポジショニング
   - 関連記事リンク自動生成
   - プラットフォーム別テンプレート

3. 配信チャネル追加
   - LINE通知機能
   - Twitter投稿機能
   - 配信ルール設定

## フェーズ3：AI強化（2/21-3/1）
### 目標：パーソナライズ機能と自動化の向上

1. パーソナライズ機能
   - 基本的な文体分析
   - 簡易的な興味関心トラッキング
   - コンテンツ推薦ロジック

2. 自動化機能
   - 基本的な投稿スケジューリング
   - シンプルな品質スコアリング
   - エラー通知システム

# 第一工期：個人ナレッジベース基盤構築企画書

## 1. 目的
LINEを入力とし、はてなブログへの記事自動生成・投稿を実現する基盤システムの構築

## 2. 開発期間
- 2025年2月1日 ～ 2月10日（10日間）
- 第一フェーズ完了時点で実用に耐えるシステムを構築

## 3. 具体的な機能要件

### 3.1 入力機能
- LINEウェブフック受信（テキスト、画像）
- 受信データのJSON形式での保存
- 画像ファイルのローカル保存

### 3.2 はてなブログ連携
- 過去記事の取得・インデックス化
- 新規記事の投稿
- 画像のアップロード
- 記事間リンクの自動生成

### 3.3 AI処理
- OpenAI APIによる記事生成
- 基本的な品質チェック
- タグの自動付与

## 4. システム構成

### 4.1 インフラ
- NASサーバー上のDockerコンテナ
- 5つの主要サービス:
  1. LINE Webhook受信（Port:3000）
  2. 過去記事管理（Port:3001）
  3. 画像処理（Port:3002）
  4. AI処理（Port:3003）
  5. ブログ投稿（Port:3004）

### 4.2 ストレージ構成
```
/nas/storage/
  ├── data/          # JSONデータ保存
  │   ├── line/      # LINE入力データ
  │   ├── articles/  # 記事データ
  │   └── temp/      # 一時データ
  └── images/        # 画像ファイル
      ├── original/  # オリジナル画像
      └── processed/ # 処理済み画像
```

## 5. 成功基準

### 5.1 必須要件
1. LINEからの入力が確実に保存される
2. はてなブログの過去記事が取得できる
3. AI記事生成が機能する
4. はてなブログへの投稿が可能

### 5.2 評価基準
1. データ保存の信頼性: 99.9%
2. システム応答時間: 1秒以内
3. 記事生成時間: 3分以内
4. エラー発生時の通知機能

## 6. 開発スケジュール

### 2/2（土）- 大山ハイキング実証実験
- LINEウェブフックの基本動作確認
- データ収集と保存の検証

### 2/3（日）- 基本機能実装
- LINE入力の保存機能
- はてなブログAPIの基本機能

### 2/4（月）- AI機能実装
- OpenAI APIの記事生成
- 画像処理の基本機能

### 2/5（火）- 検証と調整
- 大山ハイキングデータでの動作検証
- エラー対応と調整

## 7. 必要なAPI・サービス
1. LINE Messaging API
   - Webhook URL設定
   - メッセージ受信機能

2. はてなブログAPI
   - OAuth認証
   - 記事取得/投稿機能

3. OpenAI API
   - GPT-4利用
   - 文章生成機能

## 8. リスク対策
1. データ保全
   - 自動バックアップ
   - JSONファイルの定期検証

2. エラー対策
   - LINE再送機能
   - 投稿失敗時の一時保存

3. API制限対策
   - レート制限の監視
   - キューイング機能

## 9. 検証項目
1. 大山ハイキングデータを使用した実証実験
   - テキスト入力の保存
   - 画像の保存と処理
   - 記事生成と投稿
   - 過去記事とのリンク生成

2. エラーケースの検証
   - ネットワーク切断
   - API制限到達
   - データ不整合

## 10. 予算
- OpenAI API費用: 1万円
- その他API費用: 無料枠内での利用
- 既存NAS活用のため追加インフラコストなし
IBM S/Wのライフサイクルを調べたい（発表日、営業活動終了日、保守終了日など）

主題の通りです

## IBM Support の Product lifecycle ページで確認できます


**[Product lifecycle](https://www.ibm.com/support/pages/lifecycle/)**

下記のように検索窓に製品名やS/W製品番号を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/83e54e68-f3ff-1a9c-e4c8-5b43f4b1ddd9.png)


上記の例では5798-FAX ファクシミリサポート/400 を指定しました。5798-FAX の代わりに製品名でも検索できますが正確に入力しないと結果が返らない場合があります。ファクシミリサポート/400も実は俗語で、製品名をいれないといけないのですが、
5798-FAXの製品名は ***i Facsimile for i*** になっていました。うーんこういう呼び方はしてないですよね一般に・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/159812d4-6316-d3a7-38c8-413a8319a7f7.png)

そこは置いて置きまして、5798-FAX の検索結果を見ると下記のように
GA:発表日、EOM:営業活動終了日、EOS：サービス終了日、Extension,....  延長保守終了日
がわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011394/81cad74a-476b-24f3-afc8-b5eeb6aefd37.png)
「知識蒸留」で学習コストを削減できるか？



# 「蒸留化」で学習コストが激減？

## はじめに

# 大規模言語モデル（LLM）の学習コスト削減：DeepSeekが示した2つの革新的アプローチ

ChatGPTに代表される**大規模言語モデル（LLM）**は、近年急速な進歩を遂げています。しかし、これらのモデルの開発には莫大な計算資源と学習時間が必要で、多くの企業にとってコストと運用の両面で大きな課題となっています。

この課題に対して、DeepSeekは2つの革新的なアプローチを組み合わせることで、600万ドルという比較的少ない予算でo1レベルの性能を達成しました。

1つ目は**強化学習アプローチ**です。従来の大規模言語モデル（LLM）は教師あり学習（SFT）に大きく依存しており、膨大なデータ収集やアノテーション作業が必要でした。しかし、DeepSeekは主に強化学習を採用することで、これらの作業に関連するコストを大幅に削減することに成功しました。

2つ目は**知識蒸留（Knowledge Distillation）**アプローチです。この手法を使うことで、既存の大規模モデルの知識を効率的に小規模モデルに転送し、モデルの運用や展開に関するコストを大きく削減することができました。

本記事では、特にDeepSeekが活用した知識蒸留技術に焦点を当て、どのように学習コストを削減できるのか、またどのようなメリットがあるのかを詳しく解説していきます。


## 「蒸留化」ってなに？

一般的に「蒸留」というと、液体を熱して蒸発・冷却させ、不要な成分を取り除いて純度の高い成分を取り出すイメージを持ちますよね。**LLMの知識蒸留**も考え方は似ていて、**巨大な教師モデル**（大きいサイズのLLM）が持っている「知識」や「特徴」を、**小さな生徒モデル**に"抽出して凝縮する"ようなイメージです。

例えば、大きなモデル（教師モデル）と比べてパラメータ数をグッと減らした小型モデル（生徒モデル）を用意し、大きなモデルの予測結果を"まね"するように訓練します。これを蒸留化と呼びます。

## 蒸留でどうやって学習コストを下げるの？

実は、大規模言語モデルはすでに膨大な計算リソースをかけて学習されています。そのため、一から同じ性能を目指す学習を小さなモデルに行おうとしても、膨大なデータ量や時間が必要になります。

ところが、**知識蒸留**の手法を使えば、**教師モデル**が予測した結果（ロジットや確率分布）を利用して生徒モデルを素早く学習させることができます。つまり、膨大なデータから再び「一から学ぶ」のではなく、**教師モデルが既に学んだ知識を効率的に引き継ぐ**形になるのです。

### ポイント

1. **教師モデルの予測分布をまねる**：単に正解／不正解を教えるだけでなく、教師モデルがどの単語をどれくらいの確率で選んでいるか、という微妙なニュアンスまで生徒モデルに教えます。

2. **モデルサイズが小さくなる**：生徒モデルは少ないパラメータである程度高い性能を目指すので、パラメータ数が減り、メモリ使用量や計算量が少なくて済みます。

こうした特性のおかげで、**生徒モデルを作るための学習プロセスのコスト**は大幅に下げることが期待できます。

## 蒸留化によるメリット

### 推論コストの削減

「学習」だけでなく、**運用時の推論コスト**も大きく下がります。小さなモデルは必要な計算量が少なくなるので、**推論速度が上がる**と同時に、**GPUリソースなどのコストも大幅に削減**できます。

### ハードウェア要件が軽くなる

大規模LLMをそのまま使おうとすると、クラウドの高性能GPUや数百GBのRAMが必要になることも珍しくありません。蒸留後の生徒モデルなら、手元のGPUやオンプレミスの限られたリソースでも動かせる可能性が高まります。

### デプロイが容易になる

スマートフォンアプリや組み込みデバイスのように、**限られた計算・メモリ環境**でも小さなモデルなら動かせます。即時応答が求められるサービスや、通信が不安定な環境でも使いやすいのがメリットです。

## どんなやり方があるの？

蒸留にもいろいろなやり方がありますが、主なポイントを紹介します。

1. **ロジット蒸留**：教師モデルの出力の確率（どの単語を何％くらい選ぶか）をまねさせる、最もシンプルな方法です。

2. **中間表現（隠れ層）の蒸留**：教師モデル内部の"隠れ層"の出力ベクトルを参考に、生徒モデルの内部も近づけるようにするやり方です。

3. **タスク専用の蒸留**：質問応答や要約など、それぞれのタスクに応じて最適化された教師モデルを使い、そのタスク知識を生徒モデルに教え込みます。

## 注意点

1. **教師モデルが必要**：当然ながら、まず強力な教師モデルを手元に用意できなければ、蒸留を行うことはできません。

2. **性能の損失**：蒸留して小さくした分、性能が多少落ちる可能性はあります。どれくらい小さくするかは、性能とのバランスを見ながら決める必要があります。

3. **蒸留プロセスの設計**：どの層の情報を使うか、どんなデータで蒸留するかなど、細かいチューニングが成果に影響します。

## まとめ：大規模モデルを「小さく使う」時代へ

LLMの「知識蒸留」は、**膨大なリソースが必要な大規模モデル**を、**よりコンパクトかつ実用的**に使うための有力な方法です。巨大モデルそのものを毎回フル稼働させるのではなく、蒸留化によって**学習コストと運用コスト**の両方を大幅に削減できます。

今後、LLMを活用したサービスはますます増えていくと予想されていますが、同時に「どのように軽量化して運用するか」は大きな課題です。蒸留化はその解決策のひとつとして、今後さらに重要度が増していくでしょう。
MacのChromeでNotebookLMを使うと途中で送信されちゃうからブックマークレットで対策

MacのChromeで[NotebookLM](https://notebooklm.google.com/)を使っていると、文字を入力している途中で送信されてしまいイライラします。これを回避するためのブックマークレットを準備しました。

## 文字確定のEnterで誤送信するのを防ぐブックマークレット

```javascript
javascript:(function() {
  document.addEventListener('keydown', (e) => {
    if ((e.key === 'Enter' && e.isComposing) || e.keyCode === 229) {
      e.stopPropagation();
    }
  }, { capture: true });
})();
```

## ブックマークレットを使えるようにする準備

1. Chrome で Command + Shift + B を押し、ブックマークバーを開きます。
2. ブックマークバー上で新しく`ページ`を追加します。
   - 名前
     - お好きにどうぞ（例えば、NotebookLM）
   - URL
     - 上記のコードをコピペします（URLのところにコードを書くのが斬新ですね！）
3. NotebookLM https://notebooklm.google.com/ にアクセスした後で、ブックマークバー上のブックマークをクリックします。

## 原因

日本語入力では、変換中の文字を確定するのに`Enter`を使います。この`Enter`をNotebookLMが「文字を送信したいんだね」と勘違いしてしまうようです。

Googleの[Issue Tracker](https://issuetracker.google.com/)に報告しようと思ったのですが、NotebookLMに関する不具合を報告する場所（Components）が見つからず...。NotebookLMの設定からフィードバックを送信できるのと、Discordがあったので報告しておきました。いずれ解消されるといいですね！


## 不具合が発生した環境
- MacBook Air (M1, 2020)
- macOS 14.7.1（23H222）
- IME Google 日本語入力 (2.30.5590.1)
- Chrome バージョン: 132.0.6834.160（Official Build） （arm64）

なお、Firefox 134.0.2では発生しませんでした。

# 参考にした情報

次のコードを参考にさせていただきました。有益な情報、ありがとうございます！

https://zenn.dev/knziiy/articles/notebooklm-japanese-enter-fix

https://scrapbox.io/fujii-memo/NotebookLM%E3%81%AB%E6%97%A5%E6%9C%AC%E8%AA%9E%E5%85%A5%E5%8A%9B%E3%81%97%E3%81%AB%E3%81%8F%E3%81%84%E4%BB%B6
【TypeScript】【JavaScript】"Null合体演算子" と "論理 OR (|| , ||=) 演算子" の違いについて

# はじめに
* 「JavaScript における Null ガードは何なのか」を調べていく内に "Null合体演算子" に行き着いたものの、どうも特殊な挙動をすると分かったので調査

## Null合体演算子 (`??`) は「"falsy な値"を偽値と評価する」わけでは無い

:::note info
* **"Null合体演算子"は"論理 OR (`||` , `||=`) 演算子"とは異なる動作をする**

|   |   |
|:-:|:--|
| Null合体演算子 | `Null` と `undefined` **だけ** を偽値とみなす |
| 論理 OR 演算子 | falsy な値を偽値とみなす |
:::

:::note warn
* Null合体演算子の場合だと、 `false` を評価しても偽値と見なされない
* Null合体演算子の場合だと、falsy な値である `0` `''（空文字）` を評価しても偽値と見なされない
    * <font color="Red">`Null` と `undefined` だけを偽値とみなす</font>
:::

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing

## コード

```typescript:sample.ts
interface DownloadedUserData  {
    id: number;
    name: string;
    age?: number;
    hasRole?: boolean;
    gender?: string;
    grade?: number;
}

const downloadedUserData: DownloadedUserData = {
    id: 1,
    name: 'Alice',
    // age: 20,
    hasRole: false,
    gender: '',
    grade: 0,
};

// Optional chaining
console.log(downloadedUserData.age?.toString());

// Nullish coalescing operator
let userAge = downloadedUserData.age ?? 'no-user';
console.log(userAge); //=> no-user
let hasRole = downloadedUserData.hasRole ?? 'no-user';
console.log(hasRole); //=> no-user

//////////////////////////////////
/* OR演算子との違い 
 * null、undefinedは同じく検知できる
 */
userAge = downloadedUserData.age || 'no-user';
console.log(userAge);

/* ただし 空文字 や 0 の検知には違いが出る
 * `||` は falsy な値を検知する
 * `??` は null か undefined だけを検知する
 */
// false
let userHasRole: (boolean | string) = downloadedUserData.hasRole || 'no-role';
console.log(userHasRole); //=> no-role

userHasRole = downloadedUserData.hasRole ?? 'no-role';
console.log(userHasRole); //=> false


// ''（空文字）
let userGender = downloadedUserData.gender || 'no-gender';
console.log(userGender); //=> no-gender

userGender = downloadedUserData.gender ?? 'no-gender';
console.log(userGender); //=> ''


// 0
let userGrade = downloadedUserData.grade || 'no-grade';
console.log(userGrade); //=> no-grade

userGrade = downloadedUserData.grade ?? 'no-grade';
console.log(userGrade); //=> 0

```

---
### 所感
* 「Ruby の nil ガード」を想像していたため、そもそも Ruby と JavaScript の falsy な値の定義が異なる点から注意が必要だと気づけた
    * 「Ruby の nil ガード想定」であるなら `??` は不適切

---
### 参考資料

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing

https://yamacent.hatenablog.com/entry/2015/04/11/231626
Terrainに穴をあけて洞窟を造る【力技】


![gif_1_.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/e99a6776-1936-980f-7a36-4c2d0d2aa86a.gif)

## 事前準備
1. Terrainの作成を行う
1. FBX Exporter(公式)でTerrainをFBXに書き出す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/f0e6f86a-b012-8a2c-54db-b8295dfb8bd3.png)
![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/1d4d4791-aec3-3fad-9f33-3d4826a73509.png)
1. モデリングソフトなどで書きだしたTerrainのメッシュを反転させて、洞窟の天井を作る
（軽量化のためそれ以外のメッシュは消す）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/46810102-67fd-51b9-0bae-1b4f9f2f3958.png)
1. 洞窟の床用のTerrainを作成する
![無題150_20250131110343.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/9163fb46-bf4f-5f82-2712-5c569a90c5a1.png)


## 洞窟の入り口を作る
仕組みとしてはゲーム「Portal」の様に穴に見えるように描画してやろう！という話。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/b40328a6-c54d-f8db-f913-3d6248ba628c.png)

### 洞窟内用シェーダー
デフォルトのシェーダーやURPのLitシェーダーなどをコピーして
以下の設定を適切な場所に置く。
```
"Queue" = "Geometry"
```
みたいなコードがあればそれを置き換えつつその下あたりに。
"Queue"が"Geometry-300"である点に注意。
```
{
    //~これより上に必要な処理があれば~//
	SubShader
	{
		Tags { "Queue" = "Geometry-300" "RenderType" = "Opaque" }
        Pass
        {
            // Tags { "LightMode" = "UniversalForward" } ←URPならこれつける
            Stencil 
            {
                Ref 1
                Comp Always
                Pass Replace
            }
        }
	}
    //~これより下に必要な処理があれば~//
}
```
### 洞窟穴用シェーダー
洞窟の穴になるシェーダー
これは置き換えとか挿入とかせずそのまま使う
"Queue"が"Geometry-200"である点に注意。
```
Shader "Custom/HoleMask"
{
		SubShader
	{
		Tags { "Queue" = "Geometry-200" "RenderType" = "Opaque" }
		Pass
		{
			ZWrite On
			ColorMask 0
		}
	}
}
```
### 表面用シェーダー
こっちはTerrainシェーダーをコピーしてくる
やりかたは洞窟内シェーダーと同様。
"Queue"が"Geometry-100"である点に注意。
```
{
    //~これより上に必要な処理があれば~//
	SubShader
	{
		Tags { "Queue" = "Geometry-100" "RenderType" = "Opaque" }
        Pass
        {
            // Tags { "LightMode" = "UniversalForward" } ←URPならこれつける
            Stencil 
            {
                Comp Equal
            }
        }
	}
    //~これより下に必要な処理があれば~//
}
```
## 使い方
1. 反転Terrain、床用Terrain、洞窟内に配置するオブジェクトの三つを洞窟用シェーダーに変更
1. 入口に穴用オブジェクトを配置、洞窟穴用シェーダーを使う
1. Terrainに表面用シェーダーに変更


## しくみ
1. 洞窟を描画する
1. マスクは描画せず、代わりにマスクの部分に洞窟を描画する
1. Terrainを描画する。この時マスクは上書きしない
1. 洞窟完成！


![gif_1_.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/e99a6776-1936-980f-7a36-4c2d0d2aa86a.gif)


## 余談
力が足らず上手く動かなかったが、シェーダーを書かずともURP設定で同様のことができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3676764/a7a44a1f-3d9c-9dd1-085b-69789c54faf3.png)
おそらくTerrainのデフォルトの"Queue"が"Geometry-100"になっている為描画順でおかしくなるっぽい。
Terrainでなければ動くし、上手く動けばこっちの方が楽。
Node.js(npm) v22 を dnf で、AlmaLinuxにインストールしてみる。

# はじめに
CentOSの乗り換え先として、Rockyつかってますか？Almaつかってますか？
私は、AlmaLinuxに乗り換えたので、備忘録的に書いています。

公式に書かれている方法と違うのでご容赦を･･･
Node.jsの公式は、以下からどうぞ。
https://nodejs.org/ja/download
公式では、fnm, nvm, Dockerでインストールを推奨しているようですね･･･

私は、dnfだけで処理したいと思っているので、dnf+moduleで管理したいと思います。

# dnf の初期状態を確認する。
```sh
dnf list nodejs npm
```
```
利用可能なパッケージ
nodejs.x86_64     1:16.20.2-8.el9_4               appstream
npm.x86_64        1:8.19.4-1.16.20.2.8.el9_4      appstream
```
デフォルトでは、nodejsがv16で、 npmがv8になっているようですね･･･

# モジュールを確認してみる
```sh
dnf module list nodejs
```
```
AlmaLinux 9 - AppStream
Name           Stream       Profiles                                 Summary
nodejs         18           common [d], development, minimal, s2i    Javascript runtime
nodejs         20           common [d], development, minimal, s2i    Javascript runtime
nodejs         22           common [d], development, minimal, s2i    Javascript runtime
```
v19や、v20が飛ばされているのは、LTS（Long-Term Support）じゃないからなのでしょうね。優しい世界です。
v22までは対応しているとのことなので、折角なので、22を入れましょう。

# nodejsをモジュールのv22に切替える
```sh
dnf module -y enable nodejs:22
```
これだけで、取りあえず22に切り替えができたはずなので、再度確認します。

```sh
dnf install nodejs npm
```
```
利用可能なパッケージ
nodejs.x86_64       1:22.11.0-1.module_el9.5.0+133+189bb514                appstream
npm.x86_64          1:10.9.0-1.22.11.0.1.module_el9.5.0+133+189bb514       appstream
```

おぉ！node.jsがv22、npmがv10に無事に切り替わりましたね！

# node.jsとnpmをインストール
```sh
dnf list nodejs npm
```
```
====================================================================================================
 パッケージ         Arch     バージョン                                           Repo        サイズ
====================================================================================================
インストール:
 nodejs             x86_64   1:22.11.0-1.module_el9.5.0+133+189bb514              appstream   1.9 M
 npm                x86_64   1:10.9.0-1.22.11.0.1.module_el9.5.0+133+189bb514     appstream   2.1 M
依存関係のインストール:
 nodejs-libs        x86_64   1:22.11.0-1.module_el9.5.0+133+189bb514              appstream    19 M
弱い依存関係のインストール:
 nodejs-docs        noarch   1:22.11.0-1.module_el9.5.0+133+189bb514              appstream   8.5 M
 nodejs-full-i18n   x86_64   1:22.11.0-1.module_el9.5.0+133+189bb514              appstream   8.4 M
```

ということで、yesを選んでインストールをしてしまいましょう。

最後にインストールされたバージョンを念のために確認します。

```sh
node --version
v22.11.0

npm --version
10.9.0
```

はい。ということで、インストールは終了です。お疲れ様でした･･･。

# 番外編）モジュールをデフォルトに戻したい
「変更するときは、戻すことも考えろ！」と誰かが言ったとき言わないとか･･･ですので、モジュールをリセットする方法も一応書いておきましょう。

```sh
dnf module reset nodejs
```

ということで、備忘録終了です。
enjoy!!
AWS Certified DevOps Engineer - Professional (DOP-C02) 合格体験記

# はじめに
2025年1月にAWS Certified DevOps Engineer - Professional (DOP-C02)に合格しました。

きっかけは、2024年11月にSAP-C02に合格したので、その流れでDOP-C02も取得してやろうと思った次第です。[こちら](https://www.agent-grow.com/self20percent/2024/12/07/aws-certified-solutions-architect-professionalsap-c02-%e5%90%88%e6%a0%bc%e4%bd%93%e9%a8%93%e8%a8%98%e3%80%90agent-grow-advent-calendar-2024%ef%bc%9a7%e6%97%a5%e7%9b%ae%e3%80%91/)にSAP-C02の合格体験記を記載しておりますので、よければご確認ください。

試験情報などは公式サイトや他ブログでも紹介されているので、ここでは、私がやった勉強法などをメインに紹介させていただきます。

**※あくまでも個人的な見解なため、1つの例としてご確認いただけますと幸いです。**

# 利用教材について
早速ですが、利用教材について紹介します。

20250123時点でDOP-C02の日本語の参考書がありませんでした。なので、ひたすら問題を解いていく流れになります。

## [AWSサンプル問題](https://d1.awsstatic.com/ja_JP/training-and-certification/docs-devops-pro/AWS-Certified-DevOps-Engineer-Professional_Sample-Questions.pdf)

こちらはAWSのサンプル問題になります。
まずは、サンプル問題を解いて**どの分野が弱いのか**把握します。

私の場合は、SAP-C02の勉強をしていたおかげもあり、4～5割程度は正解できていたと思います。
DOP-C02はCode系やAWS Configなどに特化している問題が多く、業務経験上、あまり使ったことがないサービスだったので、このあたりを中心に勉強をしようと思いました。


## [CloudTech](https://kws-cloud-tech.com/)

続いて、AWS資格対策ではお馴染みのCloudTechです。DOP-C02は約200問あります。

ここでは、とにかく問題を解いていきます。個人的には、本や資料を読むようなインプットよりも、問題を解くなどアウトプットをやったほうが定着すると思うので、とにかく問題を解きます！

最終的には、ランダム出題モードで95％以上正解できるまでやりこみました。

## [SkillBuilder](https://explore.skillbuilder.aws/learn/courses/14541/aws-certified-devops-engineer-professional-official-practice-question-set-dop-c02-japanese)

次は、SkillBuilderのサンプル問題になります。

こちらは、冒頭のサンプル問題やCloudTechとは一味違った問題があるので、ぜひやっておきましょう。

私の場合は2回ほどやった程度で、そこまでやりこみはしませんでした。

## [Udemy](https://www.udemy.com/course/aws-dop-practice/)

最後にUdemyの問題集になります。

試験について調べていると偶然見つけた問題集になります。特にやる予定はなかったのですが、期間限定無料だったので、やってみました。笑

サンプル問題やCloudTechは何回もやっているうちに答えを覚えてしまいます、、、
ここで、初見の問題をやることで**知識が定着しているか**を確認できました。試験前にやっておいてよかったです。

# 試験について
試験問題が75問、試験時間が190分なので1問に約2.5分でやらないといけません。
**わからない問題は飛ばして、どんどん問題を解くのが大切です。**

私は、1週解くのに70分、見直しに100分ほど使いました。
ネットで調べてみる限り、SAP-C02よりDOP-C02のほうが簡単という評判が多いですが、個人的にはSAP-C02より苦戦しました、、、(個人的に開発系のサービスが苦手でして、、、)

体感的に、CloudTechやUdemyとほぼ同じ問題が1割、類似の問題が7～8割、初見の問題が1割といったところです。
つまり、**紹介した問題集をちゃんと網羅できれば8割取れるので合格できます！**

初見問題は難しいですが、試験対策をしていれば2つくらいまで選択肢を絞れます。
ちゃんと考えて回答を決めたい気持ちはわかりますが、**とりあえず回答を選んで、見直しフラグをつけて、後で見直ししましょう。**
初見問題に、大量に時間を使って他の問題に時間を使えないのが一番もったいないです。

# 結果
試験スコア858点で合格でした！！試験中は全然自信がなかったのですが、想定よりも点数が取れていてよかったです。

# おわりに
最後まで読んでいただきありがとうございました。DOP-C02を受ける方の参考になれば幸いです。
また機会があれば記事作成しようと思います。
Cursor 0.4.5の新機能：Summarize Previous Composersの使い方

## はじめに

プログラミングの強力な補助ツールとして注目を集めているCursorエディタ。公開されたバージョン0.4.5では、より効率的なコーディング体験を実現する新機能が多数追加されました。本記事では、その中でも特に注目の機能である「Summarize Previous Composers」について詳しく解説します。

## Summarize Previous Composersとは？

Summarize Previous Composersは、AIとの長時間の対話をより効率的に管理するための新機能です。開発中に複雑な問題に取り組んでいると、AIとの会話が長くなりがちです。この機能を使うことで、過去の会話の文脈を保ちながら、新しい会話を始めることができます。

### 主なメリット

- 会話の履歴を引き継ぎながら、新しい文脈で対話を始められる
- 長時間の開発セッションでもAIとの対話を整理できる
- 過去の会話内容を参照しながら、効率的に開発を進められる

## 使い方の詳細

### 基本的な使用方法

1. CursorのComposerを開く
2. `@Summarized Composers`と入力
3. 参照したい過去の会話を選択
4. 新しい会話が始まり、選択した過去の会話の文脈を踏まえた対話が可能に

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4019/abea8fe7-1757-7a2d-d254-6e4252482d2d.png)

## まとめ

Summarize Previous Composersは、長時間の開発作業をより効率的にするための強力な機能です。特に複雑なプロジェクトや長期的な開発において、AIとの対話を整理しながら進められる点が大きな特徴です。

## 参考情報

- [Changelog | Cursor - The AI Code Editor](https://www.cursor.com/changelog)
ragas で日本語を認識させる設定

# 背景

ragas でも言語設定があったのでメモ


# 記録

## 2025/1

ragas 2.12 かな

```python: with language
metrics = [
    ContextRecall(llm=evaluator_llm),
    ContextEntityRecall(llm=evaluator_llm),
    ContextPrecision(llm=evaluator_llm),
    ResponseRelevancy(llm=evaluator_llm, embeddings=evaluator_embeddings),
    Faithfulness(llm=evaluator_llm),
    NoiseSensitivity(llm=evaluator_llm),
]
metrics_with_language = await update_metrics(metrics, language="japanese", llm=evaluator_llm)
```

## 2024 年度

sentence_segmenter も設定出来ていたが、以下で削除となった。
背景については追ってないので、詳細知りたければ以下からどうぞ

https://github.com/explodinggradients/ragas/commit/6478a6e952be2882cda23bc3c08da915fb258d8a


```python: with language
from ragas.metrics.base import get_segmenter
sentence_segmenter = get_segmenter(language="japanese", clean=False)
metrics = [
    ContextRecall(llm=evaluator_llm),
    ContextEntityRecall(llm=evaluator_llm),
    ContextPrecision(llm=evaluator_llm),
    ResponseRelevancy(llm=evaluator_llm, embeddings=evaluator_embeddings),
    Faithfulness(llm=evaluator_llm, sentence_segmenter=sentence_segmenter),
    NoiseSensitivity(llm=evaluator_llm, sentence_segmenter=sentence_segmenter),
]
metrics_with_language = await update_metrics(metrics, language="japanese", llm=evaluator_llm)
```

# あとがき

version lock せずに追従すると、色々大変よね。
運用じゃなく試作なので、 lock はしたくないんだけど
【Laravel11】ウェブとスマホアプリでサービスを展開するときのメモ

### 前提
- Laravel11を使用
- ウェブとアプリで類似の機能を持ったサービス展開
- GitHub ActionsなどのCI/CDの使用
- ウェブとスマホアプリで使用するデータベースは同じ
- 当然アプリとサーバのリポジトリは分かれるが、アプリ用サーバとウェブ用サーバの扱いに悩む

### サーバを分けるor分けない

原則、開発の段階で分ける。理由は下記のとおり

- ウェブ側の実装を修正デプロイすると、アプリまでメンテナンスになる等、メンテナンスの範囲が分けられなくなる
- エラーや障害のトレース時にアプリ側からのリクエストなのか、ウェブ側からのリクエストなのか判別する必要が出たりして、追いづらくなる
- 「スモールスタートだから分けなくていいや」と舐めていると、肥大化したあとの分離がめちゃくちゃだるいことになる

### リポジトリを分けるor分けない

ウェブ用サーバとアプリ用サーバのリポジトリを分けるべきか？という悩みが浮上する

本来なら分ける方が望ましい。しかし、作業人数や規模、実装内容によって判断が分かれる

#### リポジトリを２つに分ける(ウェブ用API + アプリ用API)

- CI/CD、ルーティング、名前空間などをリポジトリ毎に設定できる
- 「ウェブ用サーバに入れた修正がアプリ用サーバに入っていない」等の事象が発生し、同じような実装なのに差が出てしまうことも考えられる


#### リポジトリを３つに分ける(ウェブ用API + アプリ用API + 共通処理)

- 開発者が複数人の場合、これがもっとも望ましいかもしれない
- 多くのModels、Requests、Resources、Repositoriesなどを共通として扱い、Controllersを個別で管理することになる
- 共通部品の変更内容をしっかり管理・共有・レビューする仕組みは必須である。急に自分に起因しない不具合やエラーが発生するのは、多くのエンジニアにとって極めて不快感を与える


#### 鋼の意思でリポジトリを分けない

- 人手不足な企業、中小企業で働く悲しきエンジニアはアプリ、バックエンド、フロントエンドを１人で全部作ることになる。決して良い方法ではないが、ひとりで管理するものを増やすコストに耐えられない敗北者には必要である
- ブランチはdevelop、deploy-web、deploy-mobileに分ける。developで開発したらdeploy-webとdeploy-mobileにマージする運用とし、各リポジトリごとにCI/CDを設定しておく
- WebとMobileの名前空間を設定してクラスを分ける(例:App\Http\Web\Controllers、App\Http\Mobile\Controllers)
- 環境変数にweb用サーバかmobile用サーバを設定できるようにする
- CI/CDで不要なファイルを削除するようにする。アプリサーバーの場合はapp\Http\Webを消し、ウェブサーバーの場合はapp\Http\Mobileを消すといった具合である。後述のルーティングファイルやフロントエンドのファイルなども削除対象になる
- routesには、web.php、api.php、mobile.phpを作成し、bootstrap/app.phpを下記のようにする

```
$apiRoute = env('API_ROUTE', 'web');

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: $apiRoute === "web" ? __DIR__.'/../routes/web.php' : null,
        api: $apiRoute === "mobile" ? __DIR__.'/../routes/mobile.php' : ($apiRoute === "web" ? __DIR__.'/../routes/api.php' : null),
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
```

※環境変数を切り替える時`php artisan optimize`の実行が必要である
※特定のコマンド(コントローラーの作成など)の挙動に困る


### おわりに

普通であればサーバとリポジトリは細かく分けるだけだが、今回はブランチ単位で分ける場合の運用が必要だと感じて実践した

結果的にリポジトリを分けなくてもうまくいったが、内部がこんなんになってるとは思わないので、後任者に配慮したreadme.mdを書く必要がある