LLM
wippy/llm モジュールは、複数のプロバイダー(OpenAI、Anthropic、Google、ローカルモデル)の大規模言語モデルを操作するための統一インターフェースを提供します。テキスト生成、ツール呼び出し、構造化出力、エンベディング、ストリーミングに対応しています。
セットアップ
Section titled “セットアップ”プロジェクトにモジュールを追加します:
wippy add wippy/llmwippy install_index.yaml で依存関係を宣言します。LLM モジュールには環境ストレージ(APIキー用)とプロセスホストが必要です:
version: "1.0"namespace: app
entries: - name: os_env kind: env.storage.os
- name: processes kind: process.host lifecycle: auto_start: true
- name: dep.llm kind: ns.dependency component: wippy/llm version: "*" parameters: - name: env_storage value: app:os_env - name: process_host value: app:processesenv.storage.os エントリは、OS 環境変数を LLM プロバイダーに公開します。APIキーを環境変数として設定してください(例: OPENAI_API_KEY、ANTHROPIC_API_KEY)。
テキスト生成
Section titled “テキスト生成”エントリに llm ライブラリをインポートし、generate() を呼び出します:
entries: - name: ask kind: function.lua source: file://ask.lua method: handler imports: llm: wippy.llm:llmlocal llm = require("llm")
local function handler() local response, err = llm.generate("What are the three laws of robotics?", { model = "gpt-4o" })
if err then return nil, err end
return response.resultend
return { handler = handler }generate() の第1引数には、文字列プロンプト、プロンプトビルダー、またはメッセージのテーブルを指定できます。第2引数はオプションテーブルです。
生成オプション
Section titled “生成オプション”| オプション | 型 | 説明 |
|---|---|---|
model | string | モデル名またはクラス(必須) |
temperature | number | ランダム性の制御、0-1 |
max_tokens | number | 生成する最大トークン数 |
top_p | number | Nucleus サンプリングパラメータ |
top_k | number | Top-k フィルタリング |
thinking_effort | number | 思考の深さ 0-100(思考機能を持つモデル) |
tools | table | ツール定義の配列 |
tool_choice | string | "auto"、"none"、"any"、またはツール名 |
stream | table | ストリーミング設定: { reply_to, topic, buffer_size } |
timeout | number | リクエストタイムアウト(秒単位、デフォルト 600) |
レスポンス構造
Section titled “レスポンス構造”| フィールド | 型 | 説明 |
|---|---|---|
result | string | 生成されたテキストコンテンツ |
tokens | table | トークン使用量: prompt_tokens、completion_tokens、thinking_tokens、total_tokens |
finish_reason | string | 生成が停止した理由: "stop"、"length"、"tool_call"、"filtered"、"error" |
tool_calls | table? | ツール呼び出しの配列(モデルがツールを呼び出した場合) |
metadata | table | プロバイダー固有のメタデータ |
usage_record | table? | 使用量追跡レコード |
プロンプトビルダー
Section titled “プロンプトビルダー”マルチターン会話や複雑なプロンプトには、プロンプトビルダーを使用します:
imports: llm: wippy.llm:llm prompt: wippy.llm:promptlocal llm = require("llm")local prompt = require("prompt")
local conversation = prompt.new()conversation:add_system("You are a helpful assistant.")conversation:add_user("What is the capital of France?")
local response, err = llm.generate(conversation, { model = "gpt-4o", temperature = 0.7, max_tokens = 500})ビルダーメソッド
Section titled “ビルダーメソッド”| メソッド | 説明 |
|---|---|
prompt.new() | 空のビルダーを作成 |
prompt.with_system(content) | システムメッセージ付きでビルダーを作成 |
:add_system(content, meta?) | システムメッセージを追加 |
:add_user(content, meta?) | ユーザーメッセージを追加 |
:add_assistant(content, meta?) | アシスタントメッセージを追加 |
:add_developer(content, meta?) | 開発者メッセージを追加 |
:add_message(role, content_parts, name?, meta?) | ロールとコンテンツパーツを指定してメッセージを追加 |
:add_function_call(name, args, id?) | アシスタントからのツール呼び出しを追加 |
:add_function_result(name, result, id?) | ツール実行結果を追加 |
:add_cache_marker(id?) | キャッシュ境界をマーク(Claude モデル) |
:get_messages() | メッセージ配列を取得 |
:build() | llm.generate() 用の { messages = ... } テーブルを取得 |
:clone() | ビルダーのディープコピーを作成 |
:clear() | すべてのメッセージを削除 |
すべての add_* メソッドはチェーン呼び出しのためにビルダーを返します。
マルチターン会話
Section titled “マルチターン会話”メッセージを追加してターン間のコンテキストを構築します:
local conversation = prompt.new()conversation:add_system("You are a helpful assistant.")
-- first turnconversation:add_user("What is Lua?")local r1 = llm.generate(conversation, { model = "gpt-4o" })conversation:add_assistant(r1.result)
-- second turn with full contextconversation:add_user("What makes it different from Python?")local r2 = llm.generate(conversation, { model = "gpt-4o" })マルチモーダルコンテンツ
Section titled “マルチモーダルコンテンツ”テキストと画像を1つのメッセージに組み合わせます:
local conversation = prompt.new()conversation:add_message(prompt.ROLE.USER, { prompt.text("What's in this image?"), prompt.image("https://example.com/photo.jpg")})| 関数 | 説明 |
|---|---|
prompt.text(content) | テキストコンテンツパーツ |
prompt.image(url, mime_type?) | URL からの画像 |
prompt.image_base64(mime_type, data) | Base64 エンコードされた画像 |
| 定数 | 値 |
|---|---|
prompt.ROLE.SYSTEM | "system" |
prompt.ROLE.USER | "user" |
prompt.ROLE.ASSISTANT | "assistant" |
prompt.ROLE.DEVELOPER | "developer" |
prompt.ROLE.FUNCTION_CALL | "function_call" |
prompt.ROLE.FUNCTION_RESULT | "function_result" |
prompt.ROLE.CACHE_MARKER | "cache_marker" |
オリジナルを変更せずにバリエーションを作成するには、ビルダーをクローンします:
local base = prompt.new()base:add_system("You are a helpful assistant.")
local conv1 = base:clone()conv1:add_user("What is AI?")
local conv2 = base:clone()conv2:add_user("What is ML?")ストリーミング
Section titled “ストリーミング”プロセス通信を使用してリアルタイムでレスポンスをストリーミングします。これには process.lua エントリが必要です:
local llm = require("llm")
local TOPIC = "llm_stream"
local function main() local stream_ch = process.listen(TOPIC)
local response = llm.generate("Write a short story", { model = "gpt-4o", stream = { reply_to = process.pid(), topic = TOPIC, }, })
while true do local chunk, ok = stream_ch:receive() if not ok then break end
if chunk.type == "chunk" then io.write(chunk.content) elseif chunk.type == "thinking" then io.write(chunk.content) elseif chunk.type == "error" then io.print("Error: " .. chunk.error.message) break elseif chunk.type == "done" then break end end
process.unlisten(stream_ch)endチャンクタイプ
Section titled “チャンクタイプ”| タイプ | フィールド | 説明 |
|---|---|---|
"chunk" | content | テキストコンテンツの断片 |
"thinking" | content | モデルの思考プロセス |
"tool_call" | name, arguments, id | ツール呼び出し |
"error" | error.message, error.type | ストリームエラー |
"done" | meta | ストリーム完了 |
process.lua エントリが必要です。Wippy のプロセス通信システム(process.pid()、process.listen())を使用するためです。
ツール呼び出し
Section titled “ツール呼び出し”インラインスキーマとしてツールを定義し、generate() に渡します:
local llm = require("llm")local prompt = require("prompt")local json = require("json")
local tools = { { name = "get_weather", description = "Get current weather for a location", schema = { type = "object", properties = { location = { type = "string", description = "City name" }, }, required = { "location" }, }, },}
local conversation = prompt.new()conversation:add_user("What's the weather in Tokyo?")
local response = llm.generate(conversation, { model = "gpt-4o", tools = tools, tool_choice = "auto",})
if response.tool_calls and #response.tool_calls > 0 then for _, tc in ipairs(response.tool_calls) do -- execute the tool and get a result local result = { temperature = 22, condition = "sunny" }
-- add the exchange to the conversation conversation:add_function_call(tc.name, tc.arguments, tc.id) conversation:add_function_result(tc.name, json.encode(result), tc.id) end
-- continue generation with tool results local final = llm.generate(conversation, { model = "gpt-4o" }) print(final.result)endツール呼び出しフィールド
Section titled “ツール呼び出しフィールド”| フィールド | 型 | 説明 |
|---|---|---|
id | string | 一意の呼び出し識別子 |
name | string | ツール名 |
arguments | table | スキーマに一致するパース済み引数 |
| 値 | 動作 |
|---|---|
"auto" | モデルがツールを使用するかどうかを決定(デフォルト) |
"none" | ツールを使用しない |
"any" | 少なくとも1つのツールを使用する必要がある |
"tool_name" | 指定されたツールを使用する必要がある |
スキーマに一致する検証済み JSON を生成します:
local llm = require("llm")
local schema = { type = "object", properties = { name = { type = "string" }, age = { type = "number" }, hobbies = { type = "array", items = { type = "string" }, }, }, required = { "name", "age", "hobbies" }, additionalProperties = false,}
local response, err = llm.structured_output(schema, "Describe a fictional character", { model = "gpt-4o",})
if not err then print(response.result.name) print(response.result.age)endrequired 配列に含める必要があります。オプションフィールドにはユニオン型を使用してください: type = {"string", "null"}。additionalProperties = false を設定してください。
モデルは meta.type: llm.model を持つレジストリエントリとして定義されます:
entries: - name: gpt-4o kind: registry.entry meta: name: gpt-4o type: llm.model title: GPT-4o comment: OpenAI's flagship model capabilities: - generate - tool_use - structured_output - vision class: - balanced priority: 100 max_tokens: 128000 output_tokens: 16384 pricing: input: 2.5 output: 10 providers: - id: wippy.llm.openai:provider provider_model: gpt-4oモデルエントリフィールド
Section titled “モデルエントリフィールド”| フィールド | 説明 |
|---|---|
meta.name | API 呼び出しで使用されるモデル識別子 |
meta.type | llm.model である必要があります |
meta.capabilities | 機能リスト: generate、tool_use、structured_output、embed、thinking、vision、caching |
meta.class | クラスメンバーシップ: fast、balanced、reasoning など |
meta.priority | クラスベース解決の数値優先度(高い方が優先) |
max_tokens | 最大コンテキストウィンドウ |
output_tokens | 最大出力トークン数 |
pricing | 100万トークンあたりのコスト: input、output |
providers | id(プロバイダーエントリ)と provider_model(プロバイダー固有のモデル名)を含む配列 |
ローカルモデル
Section titled “ローカルモデル”ローカルでホストされたモデル(LM Studio、Ollama)の場合、カスタム base_url を持つ別のプロバイダーエントリを定義します:
- name: local_provider kind: registry.entry meta: name: ollama type: llm.provider title: Ollama Local driver: id: wippy.llm.openai:driver options: api_key_env: none base_url: http://127.0.0.1:11434/v1
- name: local-llama kind: registry.entry meta: name: local-llama type: llm.model title: Local Llama capabilities: - generate max_tokens: 4096 output_tokens: 4096 pricing: input: 0 output: 0 providers: - id: app:local_provider provider_model: llama-3.2モデルは正確な名前、クラス、または明示的なクラスプレフィックスで参照できます:
-- exact model namellm.generate("Hello", { model = "gpt-4o" })
-- model class (picks highest priority in that class)llm.generate("Hello", { model = "fast" })
-- explicit class syntaxllm.generate("Hello", { model = "class:reasoning" })解決順序:
- 正確な
meta.nameで一致 - クラス名で一致(
meta.priorityが最も高いものが優先) class:プレフィックス付きの場合、そのクラス内のみを検索
モデルディスカバリー
Section titled “モデルディスカバリー”実行時に利用可能なモデルとその機能を照会します:
local llm = require("llm")
-- all modelslocal models = llm.available_models()
-- filter by capabilitylocal tool_models = llm.available_models("tool_use")local embed_models = llm.available_models("embed")
-- list model classeslocal classes = llm.get_classes()for _, c in ipairs(classes) do print(c.name .. ": " .. c.title)endエンベディング
Section titled “エンベディング”セマンティック検索用のベクトルエンベディングを生成します:
local llm = require("llm")
-- single textlocal response = llm.embed("The quick brown fox", { model = "text-embedding-3-small", dimensions = 512,})-- response.result is a float array
-- multiple textslocal response = llm.embed({ "First document", "Second document",}, { model = "text-embedding-3-small" })-- response.result is an array of float arraysプロバイダーステータス
Section titled “プロバイダーステータス”作業を送信する前にプロバイダーを確認します。準備状態の確認や軽量なヘルスモニタリングに有用です:
local status, err = llm.status({ model = "gpt-4o",})| オプション | 説明 |
|---|---|
model | 必須。確認するモデル。 |
provider_id | 任意。モデル解決をスキップし、特定のプロバイダーを対象にします。 |
プロバイダーの StatusResponse を返します(内容はプロバイダーによって異なります)。
エラーハンドリング
Section titled “エラーハンドリング”エラーは第2戻り値として返されます。エラー時、第1戻り値は nil です:
local response, err = llm.generate("Hello", { model = "gpt-4o" })
if err then io.print("Error: " .. tostring(err)) returnend
io.print(response.result)エラータイプ
Section titled “エラータイプ”| 定数 | 説明 |
|---|---|
llm.ERROR_TYPE.INVALID_REQUEST | 不正なリクエスト |
llm.ERROR_TYPE.AUTHENTICATION | 無効な API キー |
llm.ERROR_TYPE.RATE_LIMIT | プロバイダーのレート制限超過 |
llm.ERROR_TYPE.SERVER_ERROR | プロバイダーのサーバーエラー |
llm.ERROR_TYPE.CONTEXT_LENGTH | 入力がコンテキストウィンドウを超過 |
llm.ERROR_TYPE.CONTENT_FILTER | 安全システムによるコンテンツフィルタリング |
llm.ERROR_TYPE.TIMEOUT | リクエストタイムアウト |
llm.ERROR_TYPE.MODEL_ERROR | 無効または利用不可のモデル |
| 定数 | 説明 |
|---|---|
llm.FINISH_REASON.STOP | 正常完了 |
llm.FINISH_REASON.LENGTH | 最大トークン数に到達 |
llm.FINISH_REASON.CONTENT_FILTER | コンテンツがフィルタリングされた |
llm.FINISH_REASON.TOOL_CALL | モデルがツール呼び出しを行った |
llm.FINISH_REASON.ERROR | 生成中にエラーが発生 |
ケイパビリティ
Section titled “ケイパビリティ”| 定数 | 説明 |
|---|---|
llm.CAPABILITY.GENERATE | テキスト生成 |
llm.CAPABILITY.TOOL_USE | ツール/関数呼び出し |
llm.CAPABILITY.STRUCTURED_OUTPUT | JSON 構造化出力 |
llm.CAPABILITY.EMBED | ベクトルエンベディング |
llm.CAPABILITY.THINKING | 拡張思考 |
llm.CAPABILITY.VISION | 画像理解 |
llm.CAPABILITY.CACHING | プロンプトキャッシュ |
- エージェント - ツール、デリゲート、メモリを備えたエージェントフレームワーク
- LLM エージェントの構築 - ステップバイステップのチュートリアル
- フレームワーク概要 - フレームワークモジュールの使用方法