うごく生ゴミプログラマの備忘録

うごく生ゴミ 〜再臨〜

VS Code + GitHub Copilotに追加プラグイン無しでAmazon Bedrockのモデルを設定する

VS Code, GitHub Copilotに追加プラグイン無しでAmazon Bedrockのモデルを設定する方法がわかったので、備忘録かいておくます。

ただ、今のところAmazon Bedrock上のAnthropic製のモデルを動かすということができなかった。

AWS側の設定

AWSのマネジメントコンソールから、IAM → IAM users → Security credentialsタブ に移動し、Amazon Bedrock用APIキーを作成する。

AWSスクリーンショット

VS Code側の設定

VS Codeを起動し、GitHub Copilotのモデル管理画面に遷移する。

VS Codeスクリーンショット2
GitHub Copiotの

モデルを追加... をクリックする。

Custom Entpoint をクリックする。

Amazon Bedrockなど、分かりやすい名前を入力する。

VS Codeスクリーンショット4

AWS側でAPIキーを入力する。

以下のような画面がでるので、使いたいモデルの設定をする。

VS Codeスクリーンショット5

今回は、DeepSeekとgpt-oss-20bとgpt-oss-120bの3つを使いたかったので、以下のような設定値にしてみました。リージョンは us-west-2 オレゴンを使っているので "url": "https://bedrock-mantle.us-west-2.api.aws/v1" としています。

   {
        "name": "Amazon Bedrock",
        "vendor": "customendpoint",
        "apiKey": "${input:chat.lm.secret.xxxxxxxxxxxxxx}",
        "apiType": "chat-completions",
        "models": [
            {
                "id": "openai.gpt-oss-20b",
                "name": "gpt-oss-20B",
                "url": "https://bedrock-mantle.us-west-2.api.aws/v1",
                "toolCalling": true,
                "vision": true,
                "maxInputTokens": 128000,
                "maxOutputTokens": 16000
            },
            {
                "id": "openai.gpt-oss-120b",
                "name": "gpt-oss-120B",
                "url": "https://bedrock-mantle.us-west-2.api.aws/v1",
                "toolCalling": true,
                "vision": true,
                "maxInputTokens": 128000,
                "maxOutputTokens": 16000
            },
            {
                "id": "deepseek.v3.2",
                "name": "DeepSeek V3.2",
                "url": "https://bedrock-mantle.us-west-2.api.aws/v1",
                "toolCalling": true,
                "vision": true,
                "maxInputTokens": 164000,
                "maxOutputTokens": 16000
            }
        ]
    }

ポイントは、bedrock-runtime のURLではなく、bedrock-mantleのAPIエンドポイント(https://bedrock-mantle.us-west-2.api.aws/v1)を利用する点。

bedrock-mantleについては以下の記事が詳しかったです。今回のケースで、bedrock-mantleのエンドポイントの何がうれしいかというと、Amazon Bedrockネイティブの形式ではなく、OpenAI互換の形式で呼び出せる点。(Anthropic形式にも対応しているらしいが、私の環境ではまだ動作確認できていない。)

zenn.dev

bedrock-mantleのエンドポイントに対応しているかは、AWSのドキュメントで確認できる。 docs.aws.amazon.com

また、gpt-oss 20bの場合、サポートしているAPIとしてCHAT COMPLETIONSに対応しているので、前述のVS Codeの設定は以下ように設定しています。

"apiType": "chat-completions",

補足

Anthropicのモデルについて、以下のURLをみると Claude 4.5 Haiku は bedrock-mantleをサポートしているとあり、"apiType": "messages", エンドポイントに "https://bedrock-mantle.{region}.api.aws/anthropic/v1/messages" を指定すれば動作するように見えるが、私の環境では現状動作が確認できていないです。(なにか間違っているのか、AWS側でbedrock-mantle経由でアクセスできるアカウントに制限をかけているのか、ちょっとよくわからないです。)

docs.aws.amazon.com

動作させたスクリーンショット

↓設定したAmazon Bedrock側のモデルを実際に動かした結果。(Amazon Bedrock側のgpt-oss-20bを動かしています。)

VS Codeスクリーンショット5

ひとまずAmazon BedrockのモデルをGitHub Copilotとして動かすことができました。

マビノギに楽天モバイルのテザリングで接続時にエラー(エラーコード20014)の対応

マビノギ楽天モバイルテザリングで接続時にエラー(エラーコード20014)が発生した。(マビノギ自体は起動するが、マビノギのID選択ダイアログが表示されず、エラーダイアログが表示される現象)

いろいろ調べたところ、とりあえず自分の環境では以下の手順で解決したので、同様の現象で困っている人&自分の備忘録のためにメモしときます。

コントールパネル ↓ ネットワークと共有設定 ↓ テザリングしているネットワークのプロパティから「インターネットプロトコル バージョン6(TCP/IPv6)」のチェックを外す ↓ OKボタンをクリック

で解決した。

↓はスクショ コントロールパネル

Docker Desktop(Mac版)がマルウェア扱いされた。アンインストールからHomebrew経由でインストールしたら解決した

なんか私物のPC(M1 Mac)のDocker Desktopがマルウェア扱いされる現象が現れて、 アンインストール ↓ 公式のインストーラーから再インストール ↓ 公式で公開されてるコマンドの実行

でも解決しなかったんだが、

アンインストール ↓ Homebrew経由でインストール

したら解決した。

コマンドは↓を実行した。

$ brew install --cask docker

外部ライブラリ使っているAWS Lambda関数(Python)のzipファイル作成シェルスクリプト(Poetry管理プロジェクト)

Poetryで管理しているPythonで書いたAWS Lambdaの関数(外部ライブラリも使っている)を、zipにまとめるスクリプトを書いたので備忘録として残しておく。

フォルダ構成

アプローチ

Poetryで管理している場合、 .venv/lib/python*/site-packages/ に poetry add したライブラリがインストールされるので、site-pckages 下のファイルと、自分で書いたソースコードをガッチャンコしたフォルダを作って、それをzipコマンドでzipにまとめるというやり方をした。

ただし .venv フォルダをプロジェクトディレクトリ内に作成するには、

poetry config virtualenvs.in-project true

で、Poetryの仮想環境をプロジェクトディレクトリ内に作成するよう設定が必要なので注意。

ワイはDockerfileに

RUN poetry config virtualenvs.in-project true

って書いてる。

スクリプト

build.sh の全文

#!/bin/sh

cd `dirname $0`
cd ../

rm -rf ./dist/
mkdir -p ./dist/package/

cp --recursive ./.venv/lib/python*/site-packages/. ./dist/package/
cp --recursive ./src/. ./dist/package/

cd ./dist/package/
zip -r ../package ./

cd ../
rm -rf ./package/

ポイント

srcディレクトリと.venv/lib/python*/site-packages/ を dist/package/ ディレクトリにコピーしている。

cp --recursive ./.venv/lib/python*/site-packages/. ./dist/package/
cp --recursive ./src/. ./dist/package/

zipを作成した後

zipを作成した後は、マネジメントコンソールからアップロードするなり、aws cli からアップロードするなり好きにしましょうという感じ。

ワイは以下のようなシェルスクリプト(deploy.shに該当)を書いて、S3にアップロードしてからLambda関数を更新するようにしてみた。

#!/bin/sh

cd `dirname $0`
cd ../

aws s3 cp ./dist/package.zip s3://<Amazon S3バケット名>/<S3キー>

aws lambda update-function-code \
    --function-name <AWS Lambda関数名> \
    --s3-bucket <バケット名> \
    --s3-key <S3キー>

LangChain(TypeScript)のRetrievalQAChainとOpenAI APIで、自前のドキュメントに関する質問に答えてくれるプログラムを作ってみた。

概要

OpenAIのChatGPTさん、めっちゃ頭良いけど、自分しか持って無くてインターネットに公開していない情報については回答してくれないので、自分しか持ってないドキュメントの内容に関する質問に回答してくれるプログラムを作ってみたので、その備忘録。

GitHubリポジトリ

こちらのリポジトリソースコードはアップロードしています。

github.com

使う技術

  • Node.js(バージョン18.14.2)

  • TypeScript

  • LangChain(TypeScript/JavaScript 版)

  • OpenAI APIAPIキーを発行します)

ダミーファイルを作成

そんなすぐに、良い感じのドキュメントを用意できないので、BingのAIさんに、いくつか社内用語を出力してもらって、それをテキストファイルとして保存しました。

テキストファイルはすべて documentsディレクトリに保存しています。

ディレクトリ構成

こんな感じ

create-vector フォルダ

documentsフォルダ内のテキストをvectorストアに保存するプログラム

call-query フォルダ

保存済のvectorストアを読み込み、質問の回答を得るプログラム

documents フォルダ

テキストファイルを保存しておくフォルダ(ここでは架空の企業の社内用語と説明のテキストファイル)

database フォルダ

ベクターストアの内容を保存しておくフォルダ

今回はベクターストアとして、ローカルに保存できるHNSWLibを利用します。

実行の流れ

ドキュメントの内容をベクターストアに保存するプログラムを実行する ↓ 保存済のvectorストアを読み込み、質問の回答を得るプログラムを実行する

プログラムのコード

create-vector-store/index.ts

documentsフォルダ内のドキュメントの内容をベクターストアに保存するプログラム

RecursiveCharacterTextSplitterで、ドキュメントの内容を100token以下になるまで分割しVectorStoreに保存しています。

import path from 'path';
import dotenv from 'dotenv';
import { OpenAIEmbeddings } from 'langchain/embeddings/openai';
import { DirectoryLoader } from 'langchain/document_loaders/fs/directory';
import { TextLoader } from "langchain/document_loaders/fs/text";
import { RecursiveCharacterTextSplitter } from "langchain/text_splitter";
import { HNSWLib } from "langchain/vectorstores/hnswlib";


// .envファイルから環境変数を読み込み
dotenv.config();


const main = async function () {
  console.log("start");

  // 自前で準備したドキュメントを保存しているディレクトリの絶対パス
  const documentPath = path.join(__dirname, '../documents/');

  const directoryLoader = new DirectoryLoader(documentPath, {
    '.txt': (path) => {
      return new TextLoader(path)
    }
  });
  const documents = await directoryLoader.load();

  const splitter = new RecursiveCharacterTextSplitter({
    chunkSize: 100,
    chunkOverlap: 10,
  });

  const texts = await splitter.splitDocuments(documents);
  const embeddings = new OpenAIEmbeddings({
    openAIApiKey: process.env.OPENAI_API_KEY
  });
  const vectorStore = await HNSWLib.fromDocuments(texts, embeddings);

  const databasePath = path.join(__dirname, '../database/');
  await vectorStore.save(databasePath);

  console.log("end");
};

main();

call-query/index.ts

保存済のvectorストアを読み込み、質問の回答を得るプログラム

ここで、保存済のベクターストアから読み取り、RetrievalQAChainを使って自前のドキュメントの内容に対する質問に関する質問の回答を得ます。

import path from 'path';
import dotenv from 'dotenv';
import { OpenAIEmbeddings } from 'langchain/embeddings/openai';
import { OpenAI } from "langchain/llms/openai";
import { HNSWLib } from "langchain/vectorstores/hnswlib";
import { RetrievalQAChain } from "langchain/chains";


// .envファイルから環境変数を読み込み
dotenv.config();


const main = async function () {
  // 実行時引数が指定されているか確認
  if (process.argv.length < 3) {
    return;
  }

  const databasePath = path.join(__dirname, '../database/');
  const embeddings = new OpenAIEmbeddings();

  // 保存済のベクターストアから読み込み
  const vectorStore = await HNSWLib.load(databasePath, embeddings);

  const model = new OpenAI({
    openAIApiKey: process.env.OPENAI_API_KEY
  });
  const chain = RetrievalQAChain.fromLLM(model, vectorStore.asRetriever());

  // 実行時引数から質問内容を取得
  const query = process.argv[2];

  const { text } = await chain.call({ 
    query
  });

  // 質問内容と回答内容をコンソールに表示
  console.log(`Q: ${ query }\nA: ${ text }`);

};

main();

実行手順

ベクターストアの作成

$ cd <プロジェクトディレクトリ>/create-vector-store/
$ npm run start

質問をする

$ cd <プロジェクトディレクトリ>/create-vector-store/
$ npm run start --query=<質問>

実行結果例

ちゃんとdocumentsフォルダに保存しているドキュメントの内容に沿った回答をもらえました。

また、試しにdocumentsフォルダ内のドキュメントには記載の無い質問をすると、ちゃんと "分からない" 旨の回答がかえってきました。素直だな。

まとめ

とりあえず、自前で準備したドキュメントに関する回答を得ることができた。

今回はDirectoryLoaderの中で、テキストファイルに対してのみ読み取りを行っているが、これをPDFやWord、PowerPointに対応させれば、より汎用的に使えるようになるかもしれないなと思いました。

Dockerfileで、PATH通らなかった

最初こう書いてたんだけど、Node.jsのPATHが上手く通ってなくって、

ENV PATH $HOME/.nodebrew/current/bin:$PATH

↓のように書き直したら通りました。

ENV PATH /root/.nodebrew/current/bin:$PATH

github.com

以上でした。おやすみなさい。