LLM と Reduce
client.llm で言語モデルから検証済みの JSON を取得し、client.reduce で複数の結果からベストを選んだり、多数決を取ったり、結合や統合をしたりします。
client.llm は、言語モデルに構造化出力を依頼します。システムプロンプトと入力、JSON Schema を送ると、そのスキーマに一致するオブジェクトが返ります。client.reduce は、Reduce のファンインの処理を単体で実行します。複数の結果からベストを選ぶ、件数を数える、多数決を取る、テキストを結合する、JSON をマージするといった、ワークフロー内のベストを選択(Choose Best)ノードが行う処理です。どちらも、モデルのティアに応じてクレジットがかかります。
メソッド
| メソッド | 内容 |
|---|---|
llm.structured(input) | 言語モデルから、検証済みのオブジェクトを 1 回のリクエストで取得します |
llm.structuredJob(input) | 同じ呼び出しを、ポーリングするジョブとして実行します |
reduce.run(input) | 多数の入力を、選択、カウント、多数決、結合、マージのいずれかで 1 つにまとめます |
client.llm
構造化出力:システムプロンプトと JSON Schema を渡すと、検証済みのオブジェクトが返ります。プラットフォームがモデルのレーンを選び、JSON 出力を強制し、指定したスキーマに沿って検証し、無効な答えは、あきらめる前にモデルへ差し戻します。課金は llm-structured として、モデルのティアごとに行われます。
llm.structured(input)
モデルに問い合わせ、答えを待ちます(POST /v1/llm/structured)。1 回の呼び出しに数分かかることがあり、クライアントのデフォルトの 60 秒のタイムアウトより長くなる場合があります。大きめの timeoutMs を指定してクライアントを作成するか、structuredJob() を使ってください。
structured<T>(input: LlmStructuredInput): Promise<{
jobId: string
output: T
usage: { inputTokens: number; outputTokens: number }
}>Prop
Type
type Plan = { title: string; scenes: string[] }
const { output } = await client.llm.structured<Plan>({
system: "You write production plans for short films.",
input: "A rainy chase through Rome, 60 seconds.",
jsonSchema: {
type: "object",
properties: {
title: { type: "string" },
scenes: { type: "array", items: { type: "string" } },
},
required: ["title", "scenes"],
},
schemaName: "production_plan",
})
console.log(output.title, output.scenes.length)llm.structuredJob(input)
同じ呼び出しを、ジョブとして実行します(POST /v1/llm/structured/jobs)。jobId がすぐに返るので、client.jobs.getStatus() でポーリングします。ジョブは、動画から下書きを作ることもできます。その場合、プラットフォームはまず動画を分析し、その分析結果を入力に加えます。
structuredJob(input: LlmStructuredJobInput): Promise<{ jobId: string }>Prop
Type
const { jobId } = await client.llm.structuredJob({
system: "You write production plans.",
input: "A rainy chase through Rome.",
jsonSchema: { type: "object", properties: { title: { type: "string" } }, required: ["title"] },
origin: "my-app",
label: "Rome chase",
})
// later, even from another session
const { data } = await client.jobs.getStatus(jobId)
if (data.status === "completed") {
console.log((data.output_data as { output: { title: string } }).output.title)
}
const { data: runs } = await client.jobs.list({ type: "llm-structured", origin: "my-app" })ジョブの実行中、output_data には stage が入り、値は analyzing(動画からの下書きの場合)または drafting です。完了すると、output_data には output、inputTokens、outputTokens が入り、動画からの下書きの場合はさらに analysisJobId と analysisCredits も入ります。
analysisJobIdが指すジョブが自分のものではない、存在しない、または完了した動画分析ではない場合、422 で失敗します。コードはanalysis_not_found、not_analysis、analysis_failed、analysis_not_ready、invalid_analysisのいずれかです。- このルートがないプラットフォームでは、
NotFoundErrorがスローされます。 - 言語モデルの呼び出しを Nodaro Cloud に送るセルフホスティング環境では、
503 provider_unavailableが返ります。これは一時的なエラーではなく、そのインスタンスでは利用できないものとして扱ってください。
client.reduce
reduce.run(input)
多数の入力を 1 つに集約します。MCP の reduce ツールや、ベストを選択ノードと同じ処理です。
run(input: ReduceInput): Promise<ReduceResult>Prop
Type
| 戦略 | strategyConfig | 返す内容 |
|---|---|---|
pick-best-llm | { criteria, inputKind?, llmModel? }。inputKind は "text" または "image-url" です。llmModel は判定に使うモデルを選び、そのモデルのクレジットのティアが適用されます。 | 言語モデルが最も優れていると判断した入力で、そのインデックスと判断理由を含みます |
concat | { separator? }。デフォルトは空行です。 | すべての入力を 1 つのテキストに結合したもの |
first-non-empty | なし | 空でない最初の入力 |
count | なし | 入力の件数 |
vote | { caseSensitive? }。デフォルトは false です。 | 最も頻度の高い入力です。同数の場合は最初のものが選ばれます。 |
merge-json | { strategy? }:"deep"(デフォルト)または "shallow" | JSON の入力を 1 つのオブジェクトにマージしたもの |
const result = await client.reduce.run({
strategyId: "pick-best-llm",
strategyConfig: { criteria: "The sharpest image with no artifacts", inputKind: "image-url" },
inputs: [url1, url2, url3, url4, url5],
})
console.log(result.output) // the chosen URL
console.log(result.meta.selectedIndex) // 0 to 4
console.log(result.meta.reasoning) // why the model chose it結果は { jobId, output, meta } です。output は、選ばれた値または結合された値で、文字列です。meta.summary は常に設定されます。pick-best-llm と vote は meta.selectedIndex を設定し、pick-best-llm はさらに meta.reasoning も設定します。
// Majority vote
const winner = await client.reduce.run({ strategyId: "vote", inputs: ["red", "blue", "red"] })
// Deep-merge JSON fragments
const merged = await client.reduce.run({
strategyId: "merge-json",
inputs: [JSON.stringify({ a: 1, nested: { x: 1 } }), JSON.stringify({ b: 2, nested: { y: 2 } })],
})
JSON.parse(merged.output) // { a: 1, b: 2, nested: { x: 1, y: 2 } }すべての入力が空か空白だけの場合、呼び出しは失敗し、ステータスが 400 で code が no_valid_inputs の NodaroError になります。クレジットは、ほかの生成と同じように確保されるため、残高が足りない場合は InsufficientCreditsError がスローされます。
よくある質問
関連ページ
ベストを選択
ノードの実行
ジョブと実行
ピッカー、プリセット、プロンプト
最終更新