LocalLens
ウォークスルー

0. プロジェクトのセットアップ

Bun + TypeScript のプロジェクトを初期化し、QVAC をインストールし、以降のウォークスルーで使う開発ツールを固定する。

ソースファイルを書く前に、動作する Bun + TypeScript のプロジェクトが 必要です。このステップは 1 分ほどで終わり、後の src/cli.tssrc/server.ts が走る土台ができます。

前提条件

  • Bun >=1.3.0(インストール)
  • Node >=22.17.0(TypeScript と一部の node: モジュールが使用)

OpenAI のキーも、Pinecone のアカウントも、GPU も不要です。すべてが QVAC を 通してローカルで動きます。

1. プロジェクトを作る

mkdir locallens
cd locallens
bun init -y

bun init -y は最小限の package.jsontsconfig.json.gitignore、 そしてプレースホルダの index.ts を書き出します。index.ts は削除して ください。本物のエントリポイント(src/cli.tssrc/server.ts)は後で 作ります。

2. 依存をインストールする

bun add @qvac/sdk
bun add -d typescript @types/bun @biomejs/biome

それぞれの用途は次のとおりです。

パッケージ用途
@qvac/sdkローカル AI ループ: モデル読み込み、RAG、テキスト生成。LocalLens 唯一のランタイム依存。
typescriptこれから書く 8 ファイルに対する strict 型チェック。
@types/bunBun.argvBun.serveBun.fileimport.meta.dir の型定義。
@biomejs/biomelint とフォーマットの一体型ツール。ESLint + Prettier の代わり。

依存の全体はこれだけです。ベクトルデータベースも、埋め込みライブラリも、 チャンク分割器もありません。

3. ランタイムバージョンを固定する

作られたばかりの package.json を開き、type: "module"engines フィールドを設定します。これでリポジトリをクローンする誰もが同じ ランタイムで動かせます。

package.json
{
  "name": "locallens",
  "version": "0.1.0",
  "type": "module",
  "private": true,
  "license": "MIT",
  "engines": {
    "bun": ">=1.3.0",
    "node": ">=22.17.0"
  }
}

4. 使うスクリプトを追加する

これらを package.json に追加します。それぞれ後のステップで配線され ますが、今は存在するだけで十分です。

package.json
{
  "scripts": {
    "cli": "bun run src/cli.ts",
    "dev": "bun run src/server.ts",
    "start": "bun run src/server.ts",
    "build": "bun build src/server.ts --target=bun --outdir=dist",
    "test": "bun test",
    "typecheck": "tsc --noEmit",
    "lint": "biome check .",
    "format": "biome format --write .",
    "check": "bun run lint && bun run typecheck && bun run test && bun run build"
  }
}

bun run check は CI が使う複合コマンドです。lint → 型 → テスト → ビルドの順に走り、どこかで失敗すれば非ゼロで終了します。

5. tsconfig.json を引き締める

bun init は妥当なデフォルトを出力しますが、このウォークスルーでは 追加で 2 つほど必要なものがあります。strict mode、Bun の型、そして .ts 拡張子を明示的に import できる設定です。生成されたファイルを 次の内容で置き換えてください。

tsconfig.json
{
  "compilerOptions": {
    "target": "ES2023",
    "module": "ESNext",
    "moduleResolution": "Bundler",
    "types": ["bun"],
    "allowImportingTsExtensions": true,
    "noEmit": true,
    "strict": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "verbatimModuleSyntax": true
  },
  "include": ["src/**/*.ts", "tests/**/*.ts"]
}

特筆しておきたいフラグが 2 つあります。

  • allowImportingTsExtensions: true を有効にすると、ソースに import "./domain.ts" と書けます。Bun はそのまま実行できますし、 明示的な拡張子は tsc を満足させます。
  • verbatimModuleSyntax: true は、型だけの import に import type を 要求します。このウォークスルーのコードはその書き方になっており、 このフラグでそれを強制します。

6. Biome を設定する

Biome が lint とフォーマットの両方を担当します。設定ファイルは 1 つ だけです。

biome.json
{
  "$schema": "https://biomejs.dev/schemas/2.4.15/schema.json",
  "files": {
    "includes": ["**", "!dist", "!node_modules", "!.locallens"]
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "linter": {
    "enabled": true,
    "rules": { "recommended": true }
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "double",
      "semicolons": "always",
      "trailingCommas": "all"
    }
  }
}

!.locallens の除外は、アプリが動き出すと効いてきます。このフォルダは JSON ストアと brain データが置かれる場所で、Biome がフォーマットしようと してはいけません。

7. QVAC を設定する

QVAC はランタイム設定をリポジトリルートの qvac.config.json から 読み込みます。ゲートウェイがロードできるよう、今ここで作っておきます。

qvac.config.json
{
  "loggerLevel": "info",
  "loggerConsoleOutput": true,
  "httpDownloadConcurrency": 3,
  "serve": {
    "models": {
      "locallens-chat": {
        "model": "QWEN3_1_7B_INST_Q4",
        "default": true,
        "preload": false,
        "config": {
          "ctx_size": 4096,
          "temp": 0.2,
          "top_p": 0.9
        }
      },
      "locallens-embed": {
        "model": "GTE_LARGE_FP16",
        "default": true,
        "preload": false
      }
    }
  }
}

知っておきたい選択がいくつかあります。

  • preload: false — モデルは起動時ではなく、初回利用時に読み込まれます。 bun run dev の起動を速く保ちます。
  • ctx_size: 4096 — チャットモデルのコンテキストウィンドウ。あとで 検索の top-K を上げる場合、この数字を意識してください。
  • temp: 0.2 — 引用根拠付きの回答に向けた低温度設定。モデルにはソースを 言い換えてほしいので、創作させない方向です。

8. ソース用の場所を作る

mkdir src tests examples

これ以降の各ウォークスルーステップは src/ 配下にファイルを書き込みます。 tests/ には rag.tsfiles.ts 用に追加する Bun テスト 2 本が入ります。 examples/sample-brain/ は CLI が向けるデモフォルダです。

現時点の状態

プロジェクトの骨組みはこれで揃いました。package.jsontsconfig.jsonbiome.jsonqvac.config.json、そして 3 つの空の ディレクトリ (src/tests/examples/) です。bun run typecheck はまだ実行しないでください。include: ["src/**/*.ts", "tests/**/*.ts"] の設定で両ディレクトリが空の状態だと、TypeScript は次のエラーで 終了します。

error TS18003: No inputs were found in config file 'tsconfig.json'.

これは現時点では想定どおりです。最初のソースファイルは次のステップ で登場します。src/domain.ts が出来た瞬間に bun run typecheck は 通るようになり、ウォークスルーの残りの間はずっとパスし続けます。

`bun init` が用意しないもの

bun init -y は意図的に最小限です。Biome、QVAC、strict TypeScript の フラグ、上記のスクリプトセットは入りません。本ページは bun init の 上に乗せる「こだわり層」と捉えてください。これ以降はすべて、この 8 ステップの結果のような状態のプロジェクトを前提にしています。

次はドメイン型と AppError、最初の 本物のソースファイルです。

On this page