Nodaro 문서
문서노드 레퍼런스모델템플릿AI 에이전트(MCP)개발자셀프 호스팅리서치비교
TypeScript SDK

LLM과 Reduce

client.llm으로 언어 모델에서 검증된 JSON을 받고, client.reduce로 여러 결과 중 가장 좋은 것을 고르거나, 투표하거나, 이어 붙이거나, 병합합니다.

client.llm은 언어 모델에 구조화된 출력을 요청합니다. 시스템 프롬프트, 입력, JSON Schema를 보내면 스키마에 맞는 객체를 돌려받습니다. client.reduce는 Reduce 팬인 단계를 단독으로 실행합니다. 여러 결과 중 가장 좋은 것을 고르고, 개수를 세고, 투표하고, 텍스트를 이어 붙이거나 JSON을 병합합니다. 워크플로에서 최적 선택 노드가 하는 일입니다. 둘 다 모델 등급에 따라 크레딧이 듭니다.

메서드

메서드기능
llm.structured(input)요청 한 번으로 언어 모델에서 검증된 객체 받기
llm.structuredJob(input)같은 호출을 폴링하는 작업으로 실행
reduce.run(input)여러 입력을 고르기, 세기, 투표, 이어 붙이기, 병합으로 하나로 줄이기

client.llm

구조화된 출력입니다. 내 시스템 프롬프트와 JSON Schema를 넣으면 검증된 객체가 나옵니다. 플랫폼이 모델 경로를 고르고, JSON 출력을 강제하고, 내 스키마로 검증하며, 포기하기 전에 유효하지 않은 답을 모델에 다시 보냅니다. 모델 등급에 따라 llm-structured로 청구됩니다.

llm.structured(input)

모델에 요청하고 답을 기다립니다(POST /v1/llm/structured). 호출 한 번에 몇 분이 걸릴 수 있으며, 이는 클라이언트의 기본 타임아웃 60초보다 깁니다. 이 호출에는 더 큰 timeoutMs로 클라이언트를 만들거나 structuredJob()을 사용하세요.

structured<T>(input: LlmStructuredInput): Promise<{
  jobId: string
  output: T
  usage: { inputTokens: number; outputTokens: number }
}>

속성

타입

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 }>

속성

타입

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)

여러 입력을 하나로 줄입니다. MCP reduce 도구와 최적 선택 노드와 같은 방식으로 동작합니다.

run(input: ReduceInput): Promise<ReduceResult>

속성

타입

전략strategyConfig반환값
pick-best-llm{ criteria, inputKind?, llmModel? }. inputKind는 "text" 또는 "image-url"입니다. llmModel은 판단할 모델을 고르며, 그 모델의 크레딧 등급이 적용됩니다.언어 모델이 가장 좋다고 판단한 입력과 그 인덱스, 판단 이유
concat{ separator? }, 기본값은 빈 줄모든 입력을 이어 붙인 텍스트 하나
first-non-empty없음비어 있지 않은 첫 입력
count없음입력의 개수
vote{ caseSensitive? }, 기본값은 false가장 많이 나온 입력. 동률이면 먼저 나온 입력입니다.
merge-json{ strategy? }: "deep"(기본값) 또는 "shallow"JSON 입력을 병합한 객체 하나
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가 발생합니다.

자주 묻는 질문

언어 모델에서 내 스키마에 맞는 JSON을 받으려면 어떻게 하나요?

시스템 프롬프트, 입력, JSON Schema 객체를 넣어 client.llm.structured를 호출하세요. 플랫폼이 모델이 그 형태로 답하도록 강제하고, 답을 검증하고, 유효하지 않은 답은 다시 시도한 다음, 파싱된 객체를 반환합니다.

structured 대신 structuredJob은 언제 사용하나요?

오래 걸리는 호출에는 structuredJob을 사용하세요. structured는 요청 한 번으로 답을 기다리며, 이는 기본 타임아웃 60초보다 긴 몇 분이 걸릴 수 있습니다. structuredJob은 jobId를 바로 반환합니다.

생성한 이미지 여러 장 중 가장 좋은 것을 고르려면 어떻게 하나요?

strategyId를 pick-best-llm으로, 내 기준을 criteria로, inputKind를 image-url로 지정해 client.reduce.run을 호출하고, 이미지 URL을 inputs로 전달하세요. 결과에 선택된 URL, 그 인덱스, 모델의 판단 이유가 담깁니다.

언어 모델이 필요 없는 Reduce 전략은 무엇인가요?

concat, first-non-empty, count, vote, merge-json은 모델 없이 실행됩니다. 언어 모델에 판단을 맡기는 전략은 pick-best-llm뿐입니다.

최종 업데이트

목차