← 메인 리포트로
Deep Dive · 2026.05.28

LLM Structured Output + SaaS 역기획 + 린다 통합 설계

Part A: LLM Structured Output 2026.05 베스트 프랙티스 (Gemini · OpenAI · Anthropic 비교 + Schema 7원칙 + 검증/retry). Part B: Smartlead · Reply.io · Saleshandy · Outreach · Salesloft · Instantly 6사 역기획 (워크플로 · UI · 데이터 모델 · AI · edge case). Part C: 린다 코드의 LLM 호출 지점 매트릭스 + 전환 우선순위 5건. Part D: C2 분기 + C4 학습 루프에 Structured Output 을 매핑한 통합 구현 설계.

조사 시점 2026-05-28 대상 6 SaaS deep dive + 3 LLM provider 출처 공식 API docs · changelog · 2025-2026 자료 ~100건

A13 Provider 현황 비교 (2026.05)

Gemini responseSchema · OpenAI response_format=json_schema strict · Anthropic tool use + output_format (GA 2026) 의 핵심 차이. 린다 default 는 Gemini 3 Flash Preview (CLAUDE.md).

항목 Gemini (2.5 / 3 / 3.1) OpenAI (GPT-5.x) Anthropic (Claude 4.5 / 4.6 / 4.7)
API responseSchema (OpenAPI subset) + responseJsonSchema (full JSON Schema) + responseMimeType response_format={"type":"json_schema","json_schema":{"strict":true,...}} output_format (GA 2026) + tool use 패턴 (tool_choice + strict:true)
강제 메커니즘 서버측 schema 강제, key order 보존 (2.5+) Context-Free Grammar → invalid token masking, 디코더가 물리적으로 위반 불가 Grammar-constrained decoding, 첫 호출 grammar 컴파일 latency, 24h 캐시
지원 키워드 enum, anyOf, $ref, nullable, description, propertyOrdering, optionalProperties enum, oneOf, anyOf, nested objects/arrays, description. pattern/format 제한, recursive $ref 제한 tool input_schema 는 JSON Schema 거의 풀 지원. strict 모드에서 일부 제약
Nullable "nullable": true 명시 필수 — 없으면 hallucination 위험 strict 모드는 모든 필드 required 가정 → ["string","null"] union 권장 optional 누락 가능. 명시적 null 시 ["type","null"]
Schema 토큰 OH +60-100 input tok +80-120 (strict grammar 컴파일은 서버측 캐시) +150-300 (tool 정의가 가장 verbose)
Refusal 별도 필드 없음. 빈 / 부분 JSON 가능 message.refusal 별도 필드, 파싱 전 체크 필수 stop_reason: "refusal" + refusal 필드 (2026 추가)
Streaming partial 지원하나 incomplete chunks unparseable → streaming JSON parser 필요 정식 지원. partial JSON valid prefix 보장 tool use 스트리밍 OK. native output_format 도 partial 지원
복잡 schema 깊은 중첩·긴 enum·optional 다수 → 400. flat 권장 깊이 5+, 100+ 프로퍼티 strict 거부 tool input_schema 가 가장 관대

요약

  • Gemini = 가장 싸고 빠르나 복잡 schema 약함. 린다 default 에 적합.
  • OpenAI strict = 가장 엄격한 보장. high-stakes batch 분석 (objection 패턴 등) 에 적합.
  • Anthropic = tool use 유연성 + schema 표현력 최고. 비용·latency 가장 높음. Fallback 으로.

A2Schema 설계 7원칙

1 Flat over nested

2단계 이상 nested 는 Gemini 에서 400 또는 정확도 하락. address.city 같은 dotted key 를 top-level 컬럼으로 풀어쓸 것.

2 Enum > free text

분류 작업은 항상 enum. intent: "interested" | "rejected" | "ooo" | .... enum 이 100+ 면 hierarchy 로 분리.

3 Description = mini-prompt

LLM 이 description 을 prompt 처럼 읽는다. "return_date: 휴가/OOO 메일에서 발신자가 돌아오는 날짜. ISO-8601 (YYYY-MM-DD). 명시 안 됐으면 null." — example 까지 description 안에 넣을 것.

4 Reasoning field BEFORE answer

GSM8k 에서 reasoning 필드 추가만으로 4.5% → 95%. 항상 reasoningresult/intent 앞에 배치. JSON object key order 는 LLM 생성 순서와 일치하므로 chain-of-thought 효과.

5 Field count ≤ 12

한 호출당 12 초과 시 정확도 급락 (Gemini Flash 특히). 넘으면 두 호출로 분할 (extract → classify).

6 Nullable 명시

모르면 hallucinate. nullable: true + description 에 "확신 없으면 null" 명시. Gemini 는 특히 명시 안 하면 임의로 채운다.

7 Confidence score 같이

confidence: number (0-1) 추가. threshold 미만 → 사람 큐 또는 더 큰 모델로 escalate.

A3검증 / Retry / Fallback

3-tier 방어선

① Provider strict mode

Gemini responseSchema · OpenAI strict · Anthropic output_format

Grammar 강제로 syntactic validity 보장. 가장 빠른 fail-fast.

② Zod / Pydantic semantic

date 범위 · enum 외 값 · 음수 · cross-field 일관성

schema 가 표현 못 하는 의미 검증. callAIObject 가 이미 Zod 통합.

③ Retry with feedback

Instructor 패턴 · validation error 를 prompt 에 inject

exponential backoff (1s→2s→4s, max 3). 동일 위반 반복 시 더 큰 모델로 fallback (Flash Lite → Flash → Pro).

Refusal / Timeout / max_tokens

A4Use Case 별 추천 패턴

분류 (Classification)

추천: Gemini 3 Flash Lite + responseSchema enum

enum 은 모든 provider 가 grammar-level 강제. 분류는 reasoning 짧아 token cost 미미. reasoning → intent → confidence 순서.

추출 (Extraction)

추천: Gemini 3 Flash (default) / 복잡 entity 는 GPT-5.4-mini

nullable handling 이 핵심. 각 entity 마다 value + evidence_quote (원문 인용) + confidence. evidence_quote 강제로 hallucination 방어.

생성 (Generation)

추천: schema 없이 plain text 또는 최소 메타

긴 자연어는 schema 가 톤·자연스러움 해친다. 구조 필요한 메타데이터 (subject, CTA, tone) 만 schema, 본문은 string.

다단계 reasoning

추천: Claude 4.7 thinking 또는 Gemini 3 Pro thinking_budget

{plan, steps:[{action, expected}], final_output}. plan/steps 가 final_output 앞에 와야 chain-of-thought 효과.

A5이메일 SaaS 적용 Schema 예시

① OOO 복귀일 파싱 (Gemini 3 Flash · responseSchema)

parseOOOReturnDate JSON Schema
{
  "type": "object",
  "properties": {
    "reasoning":    { "type": "string", "description": "어떤 문구에서 복귀일을 추론했는지." },
    "is_ooo":       { "type": "boolean", "description": "OOO/휴가/부재중 자동응답인지." },
    "return_date":  { "type": "string", "nullable": true,
                       "description": "발신자 복귀일 ISO-8601 (YYYY-MM-DD). '다음 주' 같은 상대표현은 메일 수신일 기준 계산. 명시 안 됐으면 null." },
    "evidence_quote": { "type": "string", "nullable": true,
                        "description": "복귀일을 추론한 원문 인용 (최대 100자)." },
    "alternate_contact_email": { "type": "string", "nullable": true },
    "confidence":   { "type": "number", "minimum": 0, "maximum": 1 }
  },
  "required": ["reasoning","is_ooo","return_date","evidence_quote","alternate_contact_email","confidence"],
  "propertyOrdering": ["reasoning","is_ooo","return_date","evidence_quote","alternate_contact_email","confidence"]
}

② 답장 Intent 분류 7-way (Gemini 3 Flash Lite)

classifyReplyIntent JSON Schema
{
  "type": "object",
  "properties": {
    "reasoning": { "type": "string" },
    "intent": { "type": "string", "enum": [
      "interested",        // 미팅/제품 관심 표명
      "request_more_info", // 질문/추가 자료 요청
      "not_now_followup",  // 지금은 아니지만 나중에
      "not_interested",    // 명시적 거절
      "wrong_person",      // 잘못된 수신자/리퍼럴
      "ooo_autoreply",     // OOO 자동응답
      "unsubscribe"        // 수신 거부 요청
    ] },
    "sentiment": { "type": "string", "enum": ["positive","neutral","negative"] },
    "urgency":   { "type": "string", "enum": ["high","normal","low"] },
    "suggested_followup_days": { "type": "integer", "nullable": true,
                                "description": "not_now_followup 일 때만 D+N 권장." },
    "confidence": { "type": "number", "minimum": 0, "maximum": 1 }
  },
  "required": ["reasoning","intent","sentiment","urgency","suggested_followup_days","confidence"]
}

③ 거절 패턴 Batch 라벨링 (GPT-5.4-mini strict)

classifyRejectionPattern JSON Schema strict
{
  "type": "object",
  "properties": {
    "reasoning": { "type": "string" },
    "rejection_category": { "type": "string", "enum": [
      "budget", "timing", "already_have_solution", "no_authority",
      "no_pain", "competitor_locked", "compliance", "unclear"
    ] },
    "objection_phrase": { "type": "string",
                          "description": "원문에서 핵심 거절 표현 인용." },
    "rebuttal_angle":   { "type": "string",
                          "description": "이 거절에 대응할 다음 메일 앵글 (한 문장)." },
    "is_recoverable":   { "type": "boolean" }
  },
  "required": ["reasoning","rejection_category","objection_phrase","rebuttal_angle","is_recoverable"]
}

④ Zod / TS 등가 (callAIObject 호출 형태)

elysia-server/src/llm/schemas/reply-intent.ts TypeScript
import { z } from 'zod';
import { callAIObject } from '@/lib/ai-gateway/call';

export const ReplyIntentSchema = z.object({
  reasoning: z.string(),
  intent: z.enum([
    'interested', 'request_more_info', 'not_now_followup',
    'not_interested', 'wrong_person', 'ooo_autoreply', 'unsubscribe',
  ]),
  sentiment: z.enum(['positive','neutral','negative']),
  urgency:   z.enum(['high','normal','low']),
  suggested_followup_days: z.number().int().min(1).max(90).nullable(),
  confidence: z.number().min(0).max(1),
});

export async function classifyReply(reply: { subject: string; body: string }) {
  const result = await callAIObject({
    model: 'gemini-3-flash-lite',
    category: 'general',
    schema: ReplyIntentSchema,
    system: 'You classify B2B sales email replies. Output strict JSON.',
    prompt: `SUBJECT: ${reply.subject}\nBODY:\n${reply.body}`,
    temperature: 0.1,
  });
  if (result.confidence < 0.7) {
    // fallback: 더 큰 모델로 재시도
    return callAIObject({ ...args, model: 'gemini-3-flash-preview' });
  }
  return result;
}

A6Cost / Latency (2026.05 기준)

모델Input ($/M tok)Output ($/M tok)TTFTThroughputStructured OH
Gemini 3.1 Flash Lite~$0.10~$0.40~0.9s~250 tok/s+60-100 in
Gemini 3 Flash Preview$0.50$3.00~1.3s~284 tok/s+60-100 in
Gemini 3 Pro~$2.50~$15~2.5s~120 tok/s+60-100 in
GPT-5.4-mini~$0.25~$1.20~1.5s~150 tok/s+80-120 (cached)
GPT-5.4~$2.50~$10~2.0s~110 tok/s+80-120
Claude Haiku 4.5~$0.80~$4~600ms~95 tok/s+150-300
Claude Opus 4.7~$15~$75~2.0s~50 tok/s+150-300

500K 호출/월 분류 작업 기준 추정: Gemini Flash Lite ~$30 < GPT-5.4-mini ~$85 < Claude Haiku ~$210 < Gemini 3 Pro ~$600 < Claude Opus ~$3,000. Structured output 은 schema 토큰을 input 에 더하지만 output 토큰을 줄여 총 cost 는 보통 free-form 대비 동등 또는 -10%.

A72026 새 트렌드 (7가지)

  1. Constrained decoding 표준화. JSON mode (syntax-only) 는 legacy. OpenAI strict / Anthropic GA / Gemini propertyOrdering 이 default.
  2. Schema-first development. Zod/Pydantic 먼저 → prompt 는 schema 둘러쌀 뿐. 코드·prompt 가 schema 에서 자동 생성.
  3. Evidence quoting / grounded extraction. 추출 결과마다 evidence_quote 강제 → hallucination 거의 0. 2026 cookbook 표준.
  4. Reasoning field 분리. thinking_budget (Gemini 3) / reasoning_effort (GPT-5) / thinking (Claude 4.7) — 모델 내부 vs schema reasoning 둘 다 활용.
  5. Hybrid routing. 간단 schema → Flash Lite, 복잡 → Pro/Opus 자동 라우팅 (cost 40-60% 절감).
  6. Self-consistency for high-stakes. 분류 3회 호출 → majority vote. confidence < 0.7 일 때만 발동.
  7. Streaming structured (OpenAI 위주). Gemini 는 partial JSON parseable 보장 아직 약함 → 보통 non-streaming.

B1Smartlead 역기획

Smartlead Parent + Subsequence · AI Category Routing

A. 워크플로 / state machine

핵심 단위는 campaign + subsequence. campaign 활성화 시 lead enrollment → step 발송 후 reply 도착 → AI categorizer 호출 → 카테고리에 매칭되는 subsequence 의 trigger 와 매치 시 lead 가 subsequence 로 이동, parent 의 남은 step 영구 skip. Lifecycle: active → paused (on reply) → categorized → branched → completed | bounced | unsubscribed | OOO_rescheduled.

[Campaign Active] │ ▼ [Step N send] ─reply?──▶ [AI Categorizer (BYOK GPT-4)] │ │ │ ┌─────────┼──────────┬──────────┐ │ ▼ ▼ ▼ ▼ │ Interested Not Int Follow-Up OOO │ │ │ │ │ │ ▼ ▼ ▼ ▼ │ [Match subseq trigger?] [Parse return_date] │ │ │ │ Yes ◀─────┘ ▼ │ │ [Pause until date+1] ▼ ▼ [Next step] [Enter subsequence] (parent skipped)

B. UI 흐름

Form-driven 빌더 (드래그앤드롭 아님). Subsequence 는 별도 탭: Campaign > Subsequence > Add > Choose Condition > Choose Lead Status > Set Delay > Write Copy. Trigger 4종: Lead Categories (AI 분류), Text Content (reply 본문 키워드), Re-Engagement, Bounced Leads. delay 는 카테고리 부여 후 N일/시간. multichannel 없음 — email-only.

C. 데이터 모델 추정

campaign(id, name, status, schedule, settings_jsonb)
campaign_step(id, campaign_id, order, delay_minutes, subject, body, variants_jsonb)
subsequence(id, parent_campaign_id, name, condition_events jsonb, delay_minutes)
subsequence_step(...)
lead_category(id, campaign_id, name, prompt_text)   // 사용자 정의 카테고리 + AI prompt
campaign_lead(
  id, campaign_id, lead_id, status,
  current_step_id, current_subsequence_id, category_id, ooo_return_date,
  next_send_at)
reply_event(id, campaign_lead_id, received_at, body, ai_category_id, ai_confidence)
send_event(id, campaign_lead_id, step_id, sent_at, opened_at, clicked_at, bounced_at)

condition_events jsonb 예: [{type:"category",category_id:42}, {type:"text",keyword:"pricing"}, {type:"bounce"}, {type:"reengage"}]. API: POST /api/v1/campaigns/create-subsequence.

D. AI / LLM 사용 방식

  • 모델: BYOK ChatGPT-4 (Custom plan). Pro plan 은 default ML 5 카테고리, Custom plan 은 GPT-4 키 연결 시 10 카테고리. Base plan 은 AI 비활성.
  • 용도: ① Reply intent 분류 매 reply 호출, ② OOO 복귀일 파싱 + reschedule, ③ OOO 후속 reply recategorization, ④ Interested lead 응답 초안 생성 (AI Agent).
  • Prompt 패턴 추정: 사용자가 자연어 system prompt 직접 작성 ("If a reply contains scheduling intent, mark as Interested"). structured output 으로 {category, confidence, ooo_return_date?} 강제 추정.

E. 분기 평가 메커니즘

이벤트 기반 + 즉시 평가. step 발송 후 IMAP/Microsoft Graph webhook 으로 reply 도착 → AI categorizer 동기 호출 → 카테고리 부여 즉시 모든 active subsequence 의 condition_events 순회 평가 → 첫 매칭 wins. "5일 안 열면 분기" 같은 시간 조건은 1st-class 가 아니라 delay 필드로 — subsequence trigger 매칭 후 N일 wait 한 뒤 첫 step 발송.

F. Edge case

  • 답장 중복 도착: reply 단위 직렬 처리, 마지막 reply 의 카테고리 wins (advisory lock 추정).
  • OOO 우선: OOO 카테고리 부여 시 모든 step 일시정지 + return_date 까지 reschedule, 다른 trigger 보다 우선.
  • 같은 prospect 2 캠페인 enroll: campaign 단위 독립, 양쪽 다 발송 가능 (사용자 dedup 책임).
  • 여러 trigger 동시 매칭: condition_events 배열 순서대로 첫 매칭 wins.

G. 가격 / 제한 / 차별점

플랜가격분기/AI
Base$39/mosubsequence O, AI 분류 X
Pro$94/mo+ default AI 5 카테고리, API/webhook
Unlimited Smart$174/mo+ 무제한
Unlimited Prime$379/mo+ 12M leads, dedicated IP

차별점: 분기 trigger 의 1st-class 요소가 "AI 가 분류한 reply 의미" 라는 점 — open/click 이 아니라 reply intent 가 라우팅 키.

H. 출처

  • helpcenter.smartlead.ai/en/articles/215 (subsequence 가이드)
  • helpcenter.smartlead.ai/en/articles/209, 208, 95 (OOO)
  • api.smartlead.ai/api-reference/campaigns/create-subsequence
  • smartlead.ai/blog/ai-email-response-generator

B2Reply.io 역기획

Reply.io DAG of 8 step types · Condition node · Jason AI multi-backend

A. 워크플로

모델은 sequence (multichannel) + step (8 type) 의 그래프. type: email | linkedIn | call | sms | whatsApp | zapier | task | condition. condition step 이 분기 노드 — 이전 결과(open/reply/click/connect) 를 condition.property + rules 로 평가, Yes branch / No branch 두 자식 step 으로 갈라짐 (parentId + ifConditionPositive).

condition step 은 별도 waitInMinutes 로 "최대 N 분 기다린 뒤 평가" 가능 — 시간 만료시 No 분기로.

[Step1 email] │ ▼ [Step2 condition: replied?] ─ 10min poll, max waitInMinutes │ \ Yes(replied) No(no reply in window) │ \ [remove from seq] [Step3 linkedIn connect] │ ▼ [Step4 condition: connected?] │ \ Yes No │ \ [Step5 linkedIn msg] [Step6 call task]

B. UI 흐름

드래그앤드롭 시퀀스 캔버스. 좌측 sidebar 에서 step type drag → drop. condition step 떨어뜨리면 Yes/No 두 slot 자동 생성. condition 모달: "If the contact has..." dropdown (Opened email/Clicked link/Replied/Connected/Accepted invitation/Has phone/Email valid 등) → operator (is/isNot/contains/isSet/isNotSet) → value. wait timeout 별도 필드. multichannel 분기 예시: Email → if not opened 3d → LinkedIn connect → if accepted → LinkedIn msg → if no reply → Call task. step variant (A/B) 도 지원.

C. 데이터 모델 추정 (API 명세 기반 — 가장 명확)

sequence_step(
  id, sequence_id, parent_id,                // DAG 자기참조
  if_condition_positive bool,                // 부모가 condition 일 때 Yes/No
  type enum('email','linkedIn','call','sms','whatsApp','zapier','task','condition'),
  action_type,                                      // linkedIn: message|connect|inMail|...
  delay_minutes int,
  wait_minutes int,                          // condition only
  execution_mode enum('automatic','manual'),
  payload_jsonb                              // variants / message / conditions[]
)
contact_event(id, contact_id, sequence_id, step_id, type, occurred_at)
  // type: email_opened, email_clicked, email_replied,
  //        linkedin_accepted, linkedin_replied, call_completed, ...

condition payload_jsonb: {conditions:[{property:"emailOpened",rules:[{operator:"isSet"}]}]}. property 는 GET /v3/sequences/steps/contact-filter-properties 로 동적 조회.

D. AI / LLM 사용 방식

  • Jason AI 백엔드 사용자 선택: Claude, Gemini, Mistral, OpenAI GPT 중 toggle. 일반 builder 는 AI assist (copy) 만, autonomous reply 는 Jason AI plan ($500/mo+).
  • 용도: ① Reply intent 5-way 분류, ② 답장 자동 응답 생성, ③ Meeting booking (scheduling intent 감지 시 calendar slot), ④ 시퀀스 카피 생성, ⑤ ICP scoring (hiring·tech stack·growth signal 결합).
  • Prompt 패턴: system = ICP + 제품 + 톤 + 이전 thread (cache prefix) + reply 본문. structured output 으로 {intent_category, confidence, suggested_reply, scheduling_intent, recommended_action} 강제. Anthropic-style tool use 로 book_meeting / move_to_sequence / mark_unsubscribe 함수 호출 추정.

E. 분기 평가 — 10분 주기 polling

condition step 에 도달한 prospect 는 next_check_at = now + 10 min 으로 큐에 들어가고 워커가 그때마다 contact_event 조회. 조건 만족 → Yes 분기, wait_minutes 만료 → No 분기. atomic claim 은 sequence_contact.next_action_at < now FOR UPDATE SKIP LOCKED 패턴 추정. DAG 분기 깊이 사실상 무제한 (condition step 이 자식 condition 가능).

F. Edge case

  • 답장 평가 중 도착: replied 이벤트 contact_event 적재 → 다음 polling 사이클 반영. global "stop on reply" 켜면 polling 없이 즉시 종료.
  • OOO: Jason AI 가 OOO 분류 시 sequence pause + 복귀일 reschedule. 일반 builder 만 쓰면 OOO 도 "replied" 로 잡혀 잘못 stop. Jason AI 필수.
  • 2 시퀀스 동시 enroll: global "duplicate prevention" 옵션 있음.
  • OR 조합: rules 배열 + operator combination 으로 표현.
  • Timezone: prospect timezone 필드로 sending window 보정. condition polling 은 UTC.

G. 가격 / 차별점

플랜가격분기/AI
Email Volume$49-159/mo이메일 전용, 분기 O
Multichannel$89-99/user/mo+ LinkedIn/Call/SMS/WhatsApp 분기 (LinkedIn $69, Call $29 부가)
Jason AI Starter$500/mo1,000 active contacts, AI autonomous
Jason AI Growth$1,500/mo확장

차별점: 8 종 step type 의 진짜 multichannel (email + LinkedIn + call + SMS + WhatsApp) 을 DAG 분기로 묶을 수 있는 유일한 sequence builder + LLM 백엔드 사용자 선택권.

H. 출처

  • docs.reply.io/api-reference/sequence-steps/create-a-sequence-step.md
  • reply.io/blog/multichannel-conditional-sequences/
  • reply.io/jason-ai/

B3Saleshandy 역기획

Saleshandy Parent + Subsequence · AND condition matrix · Rule-based (No AI)

A. 워크플로

sequence + subsequence 모델. parent 는 선형 step. subsequence 진입 시 parent 의 남은 step 영구 skip. 특이점: 각 subsequence step 마다 condition 재평가 — 더이상 매칭 안 되면 status=Finished. lifecycle: Active → InSubsequence (immediate) → Completed | Finished | Replied | Bounced | Unsubscribed.

[Parent Step1] → [Parent Step2] → [Parent Step3] │ ▼ (open >=3 AND tag=ICP) ┌────────────────────┐ │ Subsequence A │ │ Step1 (re-check) │ ◀── 매 step 마다 condition 재평가 │ Step2 (re-check) │ │ Step3 (re-check) │ └────────────────────┘ │ ▼ [Finished/Completed] │ ▼ (다른 subseq 조건 매칭?) chain 가능 (prev Finished 후만)

B. UI 흐름

선형 form 빌더. parent step 추가 → Subsequence 버튼 활성화 → trigger 조건 모달 → AND 로 묶인 condition 빌더 (한 줄당 name dropdown + operation dropdown + value input, + 버튼으로 multi-row). condition name: Replied / Open Counts / Clicked URL / Specific Outcome / Steps Completed / Prospect Tag / Reply Keywords.

C. 데이터 모델 (API docs 기반 — 가장 명확)

subsequence(
  id, parent_sequence_id, title,
  schedule_id, first_step_relative_days,
  status enum('draft','active','paused')
)
subsequence_condition(
  id, subsequence_id,
  name enum('Replied','Email Open Count','Link Click',
              'Outcome','Tag','Step Completed','Reply Keyword'),
  operation enum('is','is not','is any','greater than',...),
  value text|int|bool,
  condition_id text                    // API 의 conditionId, 클라이언트 식별자
)

API: POST /v1/sequences/{sequenceId}/subsequence body = {title, scheduleId, firstStepRelativeDays, conditions:[{name,operation,value,conditionId}]}. 모든 condition 이 AND. value 타입은 server-side validation.

D. AI / LLM 사용 방식 — 거의 없음

3 사 중 AI 비중 가장 약함. "Reply Keywords" condition 도 단순 substring/regex. Outcome 은 사용자가 master inbox 에서 수동 태깅. OOO 자동 파싱·복귀일 reschedule 같은 기능 미지원. → 린다가 Saleshandy 보다 더 잘할 수 있는 가장 큰 영역.

E. 분기 평가 — 즉시 + 매 step 재평가

공식: "Prospects move into a subsequence immediately after the conditions are met; there is no delay." 이벤트 발생 시점에 AND-매트릭스 평가, 매칭 시 즉시 이동. 핵심 특이점: step 진입 직전에 conditions 를 다시 체크해 더이상 매칭 안 되면 Finished (implicit dynamic guard).

F. Edge case

  • OOO 미지원: 그냥 "replied" 로 잡혀 sequence stop. 사용자가 수동 outcome=OOO 태깅 + 별도 subsequence 만들어야 함 (큰 약점).
  • 여러 trigger 동시 매칭: 정의 순서대로 첫 매칭 wins. 한 prospect 동시에 두 subseq 진입 불가.
  • 분기 깊이: chain 가능하나 prev subsequence 가 Finished/Completed 필요 — 사실상 순차 진행만 (parallel branch X).

G. 가격 / 차별점

Outreach Starter ~$36 (분기 X) · Pro $69-74 (분기 O) · Scale $149+. AI 호출 없으므로 BYOK 없음.

차별점: AND-only 명시적·예측가능한 condition matrix + 매 step condition 재평가 (rule-based guard) — AI 의존 없이 결정론적 분기.

H. 출처

  • docs.saleshandy.com/en/articles/11154627 (가이드)
  • developer.saleshandy.com/api-reference/subsequences (API)
  • saleshandy.com/blog/introducing-subsequence-in-saleshandy/

B4Outreach 역기획

Outreach Linear Sequence + External Trigger (30 branch) + Ruleset + AI Agents

A. 워크플로 — 4-layer 아키텍처

핵심 통찰: Outreach 는 "branch 가 sequence 안에 있지 않다". Sequence 자체는 linear. 분기는 외부 Trigger 가 이벤트 받아 "현재 시퀀스를 finish 시키고 새 시퀀스로 옮긴다" 는 sequence swap 방식. 이게 mid-flight rewrite 의 토대.

┌─ Trigger evaluator (event-driven async) ─┐ │ │ [Prospect] ──enroll──▶ [Sequence] ─┤── Step N (email/call/task/LinkedIn) │ │ │ │ │ │ │ │ │ └─ event (opened/clicked/replied/ │ │ │ │ meeting/bounce) ───────────┤ │ │ │ ▼ │ │ │ ┌── Rule eval ─┐ │ │ │ │ main cond. │ │ │ │ │ branch[0..29]│ │ │ │ └──┬───────────┘ │ ┌──Ruleset (per-sequence)──┐ ▼ │ │ Safety / Opt-out / │ [Action: addToSeq, │ │ Prospect Stage / OOO / │ finishSeq, addTag, │ │ Call Task / External act. │ createTask, assign] │ └──────────────────────────┘ │ └─ AI Agent layer (Research/Personalization/Deal/Revenue) ─ populate custom fields ─ feed back to trigger conditions

B. UI — Trigger Builder 4-step wizard

  1. Event 선택: Prospect/Account created/updated, Mailing (열림·클릭·답장·바운스), Call, Meeting, Opportunity, 3rd-party (Drift, Intercom, Seismic, ...). Time-based 도 별도 (최소 20분 offset).
  2. Main condition: 모든 표준+커스텀 필드. 연산자: equals/contains/starts with/in/is set/changed from X/changed to Y. AND/OR 결합.
  3. Branching logic: 최대 30 branch. 각 branch 독립 condition + action set. main true 후 모든 branch condition 평가, action 일괄 실행 (sequential 보장 안 함 — 한 branch action 결과를 다음 branch 입력으로 못 씀 핵심 제약).
  4. Action: Add to Sequence / Finish Sequence / Create Task / Assign to Team (round-robin) / Add/Remove Tag / Update Field. Template/snippet/AI personalization block 으로 메시지 pre-fill.

C. 데이터 모델 추정

trigger(id, name, event_type, event_state, enabled, owner_id)
trigger_condition(id, trigger_id, branch_index NULL=main, expr_tree_jsonb)
trigger_action(id, trigger_id, branch_index, action_type, params_jsonb, order)

event_log(id, prospect_id, event_type, payload_jsonb, occurred_at)
  // append-only 스트림 — trigger evaluator 의 입력

agent_run(id, agent_type, target_id, source_type=internal|web,
          input_filter_jsonb, status, started_at, finished_at)
agent_output(id, agent_run_id, field_name, value_text, citations_jsonb)

핵심: trigger_condition.expr_tree_jsonb 가 AST 로 저장 ({op:"AND",children:[{field:"title",op:"contains",value:"VP"},...]}). 30 branch × 평균 5 조건 = 150 row/trigger.

D. AI / LLM 사용 방식

  • Kaia (conversation intelligence): 회의 1분 전 자동 join, 실시간 transcript (90%+ 정확도), action item 자동 추출, 키 모먼트 북마크, Content Card push. Sentiment 모델은 buyer-vs-seller speech 분리 후 별도 점수화 (Q4 2025: Smart Account Assist 가 dual-track ASR + per-speaker classifier).
  • Research Agent: source=internal(Kaia 80 calls + 500 emails) 또는 external(Gemini grounded). Output 은 structured custom field 에 채워짐. function calling / JSON schema 추정. 모든 output 에 citation array 동봉.
  • Personalization Agent: snippet 단위로 sequence step 안에 inline. Voicemail script 생성도 (Q4 2025 신규).
  • Deal Agent: multi-source LLM summarization → holistic update 1개. 1-click 으로 champion/economic buyer 필드 slot filling.
  • Revenue Agent: prospect sourcing + add-to-sequence outcome metric.
핵심 분리 패턴

Sequence rewrite ≠ in-place edit, but Sequence Swap

Outreach 에는 공식 "sequence rewrite agent" 가 없다. 대신 패턴은 — Research Agent 가 custom field 업데이트 → Trigger 가 field changed event 받음 → Finish Sequence + Add to Sequence (new) action → de-facto rewrite. 즉 LLM 이 sequence 의 step 을 바꾸는 게 아니라 시퀀스를 교체한다.

E. 분기 평가 / Atomic 처리

Trigger evaluator: 이벤트 기반 async. 모든 mutation 이 event_log append → consumer 가 enabled trigger fan-out 평가. Per-trigger 평가는 single-thread (race 방지). Branch 30개는 한 transaction 안에서 평가 후 action 일괄 enqueue.

Mid-flight rewrite atomic: sequence swap 은 state.status=finished(trigger_swap) + INSERT new sequence_state(step=0) 두 step. 같은 transaction. 진행 중 step 이 send 큐에 이미 enqueue 됐다면 send-time 에 state.status==active 재확인 (claim 패턴) 으로 fire-after-finish 방지. 이게 "in-flight enrollment 안전 swap" 의 mechanism.

F. Edge case

  • AI 오판 override: Research Agent output 은 custom field 이므로 user 가 직접 수정 가능. Citation 같이 저장돼서 "왜 이 값" 추적 가능 (explainability).
  • Audit: agent_run + event_log + trigger.fired_history 세 셋이 trail.
  • OOO 충돌: Ruleset OOO section 이 검출 시 pause until return_date. 그 사이 trigger fire 해도 paused 상태에선 step send 안 됨.
  • 승인 게이트: trigger enable/disable 이 핵심 — agent 자체엔 HITL 없음.

G. 가격 / 차별점

Standard ~$100/seat/mo · Professional $120-170 · Enterprise $160+. 최소 10-15 seat, annual contract, $5K-25K implementation fee. AI agents 는 Enterprise 또는 별도 SKU.

차별점: "Sequence 안에 분기 두지 말고, 외부 Trigger 가 sequence 전체를 swap 하는 event-driven 아키텍처 — 30-branch trigger × per-sequence Ruleset × AI custom-field-writer" 의 조합.

H. 출처

  • support.outreach.io/hc/en-us/articles/22968327588123 (Branching Conditions)
  • support.outreach.io/hc/en-us/articles/4882031368347 (Triggers Overview)
  • support.outreach.io/hc/en-us/articles/39482266094875 (Research Agent)
  • outreach.ai/resources/blog/outreach-q4-2025-product-release

B5Salesloft 역기획

Salesloft Cadence + Conductor AI (BPM) + Rhythm Focus Zone + Plays

A. 워크플로 — AI ranker 가 cadence orchestrator 대체

핵심: Conductor AI (Buyer Priority Model) 가 매 signal 마다 실시간 task ranking 재계산. patent-pending 자체 엔진. Cadence 안에 분기 거의 없음 — 모든 분기 로직은 Plays 와 Conductor ranking 으로 대체.

[Buyer Signal Bus] ──────────────────────────────────┐ ▲ G2/Seismic/Vidyard/Highspot/Drift/LeanData/CRM │ │ Email open/click/reply + call disposition │ │ Meeting outcome + website visit + content view │ │ ▼ ┌─Conductor AI─┐ │ Buyer Priority│ │ Model (BPM) │ │ — P(open opp │ │ or meeting │ │ in 7d) │ └──┬────────────┘ │ re-rank in real time ▼ [Cadence] ──steps──▶ task ┌──────────────────┬──────────────────┐ ▼ ▼ ▼ Cadence Focus Zone Rhythm Focus Zone Close Focus Zone step-driven signal-driven deal-stage ▲ │ [Plays] event-triggered

B. UI — 3개 Focus Zone

  • Cadence Focus Zone: cadence step task (이메일/콜/social touch). 전통적 step-driven.
  • Rhythm Focus Zone: Conductor AI 가 ranking 한 next-best-action. 각 task 옆에 "왜 이게 중요한가" 설명 (signal source + 영향 추정) 노출. explainability 의 UI 표현.
  • Close Focus Zone: pipeline 마감용. 분기말 close 가까운 deal.
  • Filter: action type / account tier / custom score / time zone / priority. user 는 ranking 위에 manual filter override 만, ranking 알고리즘 자체는 unblockable.

C. 데이터 모델 추정

signal(id, person_id|account_id, type, source, strength, payload_jsonb, occurred_at)
  // partition by occurred_at, retention 30-90d

bpm_score(id, person_id, score float, top_signals jsonb, rationale text,
          computed_at, valid_until)
  // recomputed on signal change (incremental)

rhythm_action(id, person_id, action_type, priority_score, reason_text,
              ranking_signal_id, expires_at, assigned_user_id, completed_at)
  // ephemeral task queue per user

play(id, name, event_type, conditions_jsonb, action_jsonb)
  // conditions can reference BPM score / signal types

핵심: bpm_score.rationale 가 자연어로 저장돼 UI "왜" 설명에 그대로 사용. signal 테이블 partition + 짧은 retention — Conductor 가 실시간 re-rank 위해 hot 데이터만 필요.

D. AI 사용 방식

  • Conductor AI = Buyer Priority Model (BPM): 7일 이내 (open opportunity OR booked meeting) 확률 추정 — binary classification with calibrated probability. LLM 이 아닌 자체 ML (patent-pending 명시) — 이유는 매 signal 마다 incremental 재계산 필요, LLM 호출 비용·latency 부적합.
  • Rhythm explanation: 자연어 reason 동봉. BPM 자체는 LLM 아니어도 rationale generation 은 LLM (template + signal slot filling) 가능성.
  • AI Email Assistant (Premier add-on): 답장 draft + cadence step email rewrite. 별도 LLM (OpenAI 추정).
  • Conversations (Kaia 대응): call 녹음 transcript + sentiment + coaching. Premier add-on.

E. 실행 / Race

Conductor 실행 주기: real-time, event-driven. Signal stream (Kafka-like) → BPM scorer → affected user 의 Rhythm queue 업데이트. UI 는 폴링/SSE 로 reload. Race: Rhythm action 은 ephemeral, expires_at 으로 stale 자동 drop. 동시 enqueue dedup: (person_id + action_type + signal_id) UNIQUE.

승인 vs 자동: Conductor 는 ranking 만, action 실행은 항상 user click. Plays 의 일부 action 만 auto-execute (canned email, log activity). AI 는 추천기, 사용자가 executor — Outreach 보다 보수적.

F. Edge case

  • AI 오판 override: Rhythm action dismiss 가능. Dismiss 가 feedback signal 로 모델에 들어가는 게 핵심 (active learning).
  • Audit: bpm_score.top_signals + rationale 가 UI 노출. Dismiss/완료 모두 로그.
  • 답장 도중 도착: signal stream 에 reply event 가 들어가면 BPM 자동 재계산 (오히려 더 정확).
  • OOO 충돌: cadence ruleset 격이 별도. OOO 검출 → cadence pause → Rhythm queue auto-demote.

G. 가격 / 차별점

Essentials / Advanced / Premier. Median $125-165/seat/mo. Dialer add-on $200-480/yr/user. Conversations·Rhythm·Deals 모두 별도 SKU. Conductor AI 는 Rhythm SKU 포함.

차별점: "Cadence 안에 분기 두지 않고, 7일 prediction BPM 이 매 signal 마다 실시간 task ranking 재계산 — AI ranker 가 cadence orchestrator 를 대체하는 구조."

H. 출처

  • salesloft.com/platform/rhythm
  • salesloft.com/company/newsroom/salesloft-announces-rhythm-powered-by-conductor-ai
  • help.salesloft.com/s/article/Salesloft-Conductor-AI

B6Instantly 역기획

Instantly Email-only · Label-driven Subsequence · GPT-4 Unibox V2 · Reply Agent (HITL/Autopilot)

A. 워크플로

cold email outbound 전문. Campaign (main sequence) + Subsequence (label/keyword-triggered branch) + Unibox V2 (AI-labeled inbox) + AI Reply Agent (HITL/Autopilot).

[Lead pool] ──CSV/API──▶ [Campaign] ──steps (email only)──┐ │ │ │ ▼ │ [Email sent] │ │ │ ┌──reply detected──┐ │ │ │ │ ▼ ▼ │ [Unibox V2] ◀── webhook/IMAP │ │ │ ┌──Unibox NLP──┐ │ │ GPT-4 based │ │ │ sentiment + │ │ │ 50+ language │ │ │ → label │ │ │ (default 8 +│ │ │ custom) │ │ └──────┬───────┘ │ ▼ │ [Lead status update] │ │ │ ┌──Subsequence trigger──┐ │ │ on status/keyword/ │ │ │ activity match │ │ └──────┬────────────────┘ │ ▼ │ [Subsequence step 1] ──▶ step 2 ──▶ ... │ └── complete or pause on reply

B. UI

Campaign builder: 단순 step list (email only). Day delay + variant. 다중채널 분기 없음.

Subsequence wizard 4-step: ① main 활성화 (선행 조건) → ② Trigger 선택 (3 타입): Status (8 default + custom) / Activity (link click, completed without reply, opened) / Keyword/phrase (세미콜론 구분, 정확 매칭 권장) → ③ Step 작성 + delay → ④ Daily limit + schedule.

Unibox V2: GPT-4 기반 sentiment + auto label. Default 8개 + 무제한 custom. Custom label = 라벨명 + AI description 텍스트 (pencil icon). Misclassification feedback (robot icon).

AI Reply Agent: HITL (draft → 사람 승인 → send) 또는 Autopilot (auto-send, 모호하면 pause). 5-step setup, step 5 (agent training) 가 가장 중요 — tone, product, goal context. "Optimize" 버튼이 AI 가 guidance 자체를 개선 제안.

C. 데이터 모델 추정

label(id, workspace_id, name, is_default, ai_description, created_by)
  // ai_description: GPT-4 prompt 의 한 줄 — few-shot 이 아닌 description-based zero-shot

reply_event(id, lead_id, raw_body, parsed_body,
            detected_language, sentiment_score,
            assigned_label_id, ai_confidence, received_at)

subsequence(id, parent_campaign_id, status, trigger_type, trigger_config_jsonb)
  // trigger_config: {label_id} | {keywords:[]} | {activity:"link_click"}

agent_config(id, workspace_id, mode=HITL|autopilot, training_context_text,
              optimize_iterations, label_filters_jsonb)
agent_draft(id, reply_event_id, draft_body, status=pending|approved|sent,
            credits_used, created_at)

D. AI 사용 방식 (핵심)

  • Unibox NLP: GPT-4 (공식 명시). Input = 답장 본문 + 원래 이메일 컨텍스트 + workspace label 정의 (name + ai_description). Output = label_id + sentiment + confidence. Structured output / function calling 매우 가능성 높음. 50+ language 는 별도 모델 아님 — GPT-4 의 native multilingual + zero-shot classification 한 prompt 안에서 처리.
  • 비용 모델: Unibox NLP 무료 (extra charge 없음). AI Reply Agent 만 5 credit/reply 과금. 이유: classification 은 input/output 토큰 작고 cache hit 높음. Generation 은 길고 unique.
  • Reply Agent: 모델 비공개. HITL/Autopilot. <5분 latency. OOO 자동 처리: NLP 가 OOO 라벨 + return_date 파싱 → campaign pause → return_date+1 day 에 follow-up scheduled. Training: agent_config.training_context_text 가 system prompt 의 일부로 injection. "Optimize" 는 meta-LLM 호출 — 기존 training text + 최근 misclassification 을 보고 새 text 제안.
  • 5 credit/reply 의 의미: pricing 환산하면 reply 1건 약 $0.005-0.02 — GPT-4o-mini / 4-turbo 1k 토큰 수준.

E. 실행 / Atomic

Reply pipeline: IMAP/webhook → reply_event 생성 → NLP 큐 (async <5분) → GPT-4 호출 → label 저장 → lead.current_label 업데이트 → subsequence trigger evaluator. 중요: 기존 매칭 lead 자동 진입 안 함 — 새로 라벨 받은 lead 만 (forward-only, race 회피).

Atomic claim: subsequence_state UNIQUE(lead_id, subsequence_id). HITL vs Autopilot: agent_config.mode + per-label override. Autopilot 이어도 confidence < threshold 면 HITL 폴백.

F. Edge case

  • Override: Unibox 의 robot 아이콘으로 라벨 수정 feedback. 라벨 수정 시 subsequence 자동 진입 트리거되지 않음 (manual move 만, 공식 명시).
  • Audit: reply_event 에 ai_confidence + assigned_label_id 저장. 모든 draft 는 agent_draft 보존.
  • OOO vs AI 충돌: OOO 라벨 우선 — 사용자 수동 변경 없으면 return_date 까지 pause. 수동 변경 시 OOO scheduled_send cancel.

G. 가격 / 차별점

Growth $37 / Hypergrowth $77.60 (annual) / Light Speed $286.30 / Enterprise quote. Seat 기반 X — send volume + feature tier 기반. AI Reply Agent 5 credit/reply, $9/150~$197/10K. AI Custom Label 은 Hyper Growth / Light Speed 한정. Unibox NLP 기본 라벨링은 모든 plan 무료.

차별점: cold-email-only narrow scope + GPT-4 기반 50+ language 라벨링 + label/keyword/activity trigger subsequence 가 default — branch UI 가 곧 'label-driven subsequence'인 가장 단순한 아키텍처.

H. 출처

  • help.instantly.ai/en/articles/8797578-unibox-v2
  • help.instantly.ai/en/articles/9712488-ai-custom-reply-labels
  • help.instantly.ai/en/articles/11774076-ai-reply-agent
  • developer.instantly.ai/api/v2/campaignsubsequence

B7종합 비교 + 5가지 핵심 인사이트

6사 핵심 비교

영역SmartleadReply.ioSaleshandyOutreachSalesloftInstantly
분기 모델 Parent + Subseq DAG of typed steps Parent + Subseq (매 step 재평가) Linear + External Trigger 없음 (AI ranking 대체) Parent + Subseq
Sequence 안 분기 없음 condition step (Yes/No) 없음 없음 (linear) 없음 (linear) 없음 (linear)
분기 발화 위치 Subseq trigger 평가 Condition step 10분 polling 이벤트 즉시 + step 재평가 Trigger evaluator (외부) Plays + BPM ranking Subsequence trigger
LLM 모델 BYOK GPT-4 Claude/Gemini/Mistral/GPT 선택 없음 (rule-based) 자체 + Gemini (grounding) 자체 BPM + LLM (assistant) GPT-4 (Unibox)
OOO 자동 처리 AI 복귀일 파싱 + reschedule Jason AI 필요 미지원 (수동) Ruleset OOO section cadence pause + demote NLP 가 라벨 + scheduled_send
다채널 Email only 8 step type Email + LinkedIn task Email/Call/LinkedIn/SMS/Task Email/Call/LinkedIn/SMS Email only
가격 (entry) $39/mo $49-99/user/mo $69-74/mo (Pro) $100-175/seat/mo $125-165/seat/mo $37-286/mo (volume)
차별점 AI reply intent 가 라우팅 1st-class 진짜 multichannel DAG + LLM 선택권 결정론적 rule + 매 step 재평가 Sequence swap (event-driven) AI ranker 가 orchestrator 대체 50+ language 무료 라벨링

5가지 핵심 인사이트 (린다 이식 관점)

Insight 1

Mid-flight rewrite 는 "step 을 바꾸는" 게 아니라 "sequence 전체를 swap" 으로 설계

Outreach 의 검증된 패턴. 필요한 것: (a) event_log append-only 스트림, (b) trigger evaluator (event_type 인덱스), (c) AST 형태의 trigger_condition.expr_tree_jsonb, (d) 30 branch 제약은 LLM 비용 한계가 아니라 evaluator latency 한계 — 린다도 비슷한 상한 필요. AI 가 sequence 직접 재작성하지 않고, AI 가 custom_field 채우고 trigger 가 그 변화 보고 시퀀스 swap 이 핵심 분리.

Insight 2

Priority re-ranking 은 LLM 이 아니라 calibrated classifier + LLM rationale 분리 설계

Salesloft Conductor 가 LLM 이 아닌 자체 ML 인 이유: ranking 은 매 signal arrival 마다 incremental 재계산 필요. LLM 비용·latency 부적합. 린다 도입 시: (a) signal table partitioned + 30-90d retention, (b) 가벼운 gradient boosting / logistic 모델 (린다 데이터 적으면 rule-based + learn-to-rank 부트스트랩), (c) rationale 생성만 LLM 으로 — score 의 top-k feature 를 자연어로 풀어주는 별도 step. UI 는 score+rationale 같이 노출 (explainability 가 채택률 핵심).

Insight 3

50+ language sentiment 는 별도 모델이 아니라 GPT-4o(-mini) / Gemini Flash 1회 호출로 충분

Instantly 가 무료 제공하는 게 GPT-4 native multilingual + zero-shot classification 덕분. 린다: (a) label.ai_description 텍스트만 user 작성, (b) 모든 라벨 정의를 system prompt 에 inject, (c) reply body + label list → structured JSON (label_id, confidence, sentiment, language, return_date). 비용은 input 토큰 dominant — 라벨 정의는 prompt cache 로 절감. Misclassification feedback 은 별도 label_feedback 테이블 저장 → 라벨 description 자동 개선 ("Optimize" 패턴).

Insight 4

HITL/Autopilot 은 binary 가 아니라 spectrum — confidence threshold 로 자동 폴백

Instantly Reply Agent 가 Autopilot 이어도 uncertain 이면 pause. 린다: agent_config.mode + per_label_threshold + global_confidence_floor 3-layer. Audit 은 agent_draft 보존 + credits_used + status. 5 credit/reply 의 pricing 신호 — Instantly 는 LLM cost 를 user 에게 직접 transfer. 린다도 LLM 호출량은 워크스페이스 단위 metering 필요.

Insight 5

분기 evaluator 의 atomic claim 이 가장 자주 깨지는 부분

Outreach 가 "30 branch action 결과를 다음 branch 입력으로 못 씀" 으로 제약 명시한 이유: branch 평가가 동시·일괄이 아니면 일관성 깨짐. 린다: (a) event_log consumer 가 per-trigger single-threaded 처리 (Redis stream consumer group), (b) action enqueue 시 (person_id, sequence_id, version) dedup, (c) sequence step send 직전에 state.status==active && version 일치 재확인 (claim 패턴). 답장 도착 같은 strong signal 은 synchronous fast path 로 별도 처리해 race 회피.

C1린다 AI Gateway 구조

LLM 호출은 이미 callAI / callAIObject / callAIWithRetry 통합 진입점으로 정리되어 있다. Gemini 카테고리 분리 (5개 키), 자동 토큰 추적 (ai_token_usage_logs), Zod 통합까지.

통합 진입점

elysia-server/src/lib/ai-gateway/call.ts

  • callAI() — 텍스트 (Google/OpenAI/Anthropic/Perplexity)
  • callAIObject() — 구조화 (Zod schema, Gemini structuredOutputs, OpenAI/Anthropic response_format 자동 처리)
  • callAIWithRetry() — fallback chain 지원
  • 모든 호출 자동 토큰 추적 via trackTokenUsage()ai_token_usage_logs

Gemini 카테고리 분리

elysia-server/src/lib/gemini.ts

  • 5개 API 키 분리: buyer-search-v1/v2, personalized-email, trend-signals, general
  • getGeminiClient(category) — 토큰 추적 Proxy 자동 적용
  • JSON 헬퍼: parseJsonArray<T>(), safeJsonParse<T>()

Claude 직호출

elysia-server/src/lib/claude.ts (Blog CMS 전용)

  • callClaude(systemPrompt, userPrompt, maxTokens)
  • 모델: claude-opus-4-6
  • Retry: 3회 (exponential backoff 2s × 2^n)

C2Use Case 별 LLM 호출 지점 (현황)

Classification (분류) — 6곳

파일함수모델현재 파싱Schema 후보
services/ai-classification.service.ts:49-55 classifyReply() gemini-3.1-flash-lite 수동 JSON.parse intent/sentiment/confidence enum
workers/bullmq/reply-tags-auto-classify.worker.ts:54-70 defaultGemini() gemini-3-flash responseMimeType + responseSchema ✓ matched_tag_names (이미 enum)
workers/bullmq/crm-stage-classify.worker.tsservices/crm/stage-classifier.service.ts:163+ classifyThread() claude-sonnet-4-6 callAIObject + Zod ✓ deal stage enum (이미 정의)

Extraction (추출)

파일함수모델현재 파싱
services/crm/stage-classifier.service.ts:97-114 llmOutputSchema (Zod) claude-sonnet-4-6 callAIObject + Zod ✓ (assigned_stage, confidence, signals, extraction_json)
skills/email-hunt/lib/company-emails.ts generateObject() - PrioritizedUrlsSchema

Generation (생성)

파일함수모델현재 파싱
services/sequence-proposal/generate-batch-emails.service.ts:1-80 generateBatchEmails() gemini-3-flash-lite callAIObject + Zod ✓ ({subject, bodyText}[])
lib/claude.ts:26-78 callClaude() claude-opus-4-6 text content parsing (Blog CMS)

Scoring / Evaluation

파일함수모델현재 파싱
services/hot-lead-evaluation/triage.service.ts:54-83 triageBatch() gemini-3-flash-preview callAIObject + Zod ✓ (batch 20명/콜)
services/lead-scoring.service.ts:60-68 LeadScoreSchema gpt-5-mini Zod 정의됐으나 callAI 텍스트 사용
services/scoring-preset-gemini.ts:56-115 callGeminiForPreset() gemini-3.1-flash-lite 수동 fetch + JSON.parse

이미 Structured Output 사용 중

Validation / Retry 패턴

전략예시코드 경로
Zod 스키마 검증stage-classifier, triage, lead-scoringcallAIObject 자동 파싱 + Zod validate
수동 JSON 파싱 + 폴백ai-classification, scoring-presettry-catch + safeJsonParse() → fallback
후보 set 필터링 (hallucination 방어)reply-tags-auto-classifyLLM matched_tags ∩ active_tags
CRM stage 신호 floor 강제stage-classifierLLM assignedStage ≥ signal-engine floor
Retry with fallback chaincallAIWithRetry()primary → fallback → error

C3전환 우선순위 5건 (ROI 높은 순)

#1 reply-tags-auto-classify → callAIObject 통일

현재 50% 완성 · 즉시 적용 가능

현재 Gemini responseMimeType + responseSchema (Google Type enum) 사용 중. callAIObject() 로 마이그레이션 → Zod schema 통일 + ai-sdk 자동 처리. 코드 간결화, 향후 모델 전환 유연성.

code cleanup

#2 generate-batch-emails 에 streamObject 추가

현재 callAIObject 사용 · UX 개선

streamObject() 로 TTFB 3.7× 향상 (bench-stream-vs-generate.ts 실측). 사용자 체감 속도 +300%, 동일 비용.

UX +300%

#3 hot-lead-evaluation/triage 유지 + 향후 임베딩 재순위화

현재 완성 · 후속 Phase 검토

callAIObject 사용, 배치 20명/콜, 비용 추적 완벽. Stage 2 로 임베딩 재순위화 추가 고려.

완성

#4 stage-classifier — spec-locked 유지

변경 금지 (§4.2 Step 3)

callAIObject + Zod + Claude Sonnet 4.6 안정. 향후 confidence threshold 통합만 (currently logged but not gated).

spec-locked

#5 lead-scoring.service → callAIObject + LeadScoreSchema

Schema 이미 정의됨 · 파싱 버그 제거 기대

현재 callAI 텍스트 → 수동 JSON.parse. 파싱 버그 제거, 타입 안전성 +100%, 캐시 hit rate 개선.

type-safe

D1C2 분기 + Structured Output 매핑

C2 행동 분기 구현 시 LLM 호출이 필요한 4 지점 + 각 지점의 Schema·모델·검증 매핑.

LLM 사용 지점모델Schema 핵심 필드Provider린다 파일
① 답장 intent 분류 (분기 라우팅의 키) Gemini 3 Flash Lite reasoning, intent (7 enum), sentiment, urgency, suggested_followup_days, confidence responseSchema services/ai-classification.service.ts 확장
② OOO 복귀일 추출 Gemini 3 Flash reasoning, is_ooo, return_date (nullable ISO), evidence_quote, alternate_contact_email, confidence responseSchema utils/auto-reply-detection.ts 신규 함수
③ 시퀀스 카피 자동 생성 (분기 step 추가 시) Gemini 3 Flash 본문 = plain text + 메타 (subject, primary_cta, tone) callAIObject (메타만) sequence-ai-gen.service.ts 확장
④ Subsequence 라우팅 추천 (AI fallback) Gemini 3 Flash recommended_subsequence_id, reasoning, alternatives[], confidence callAIObject services/sequence-branching.service.ts 신규

분기 평가 워크플로 (린다 적용안)

[Email sent] ──reply 도착──▶ [webhook.service: processInboundEmail] │ ▼ ┌── ai-classification.service ──┐ │ Gemini 3 Flash Lite │ │ responseSchema + Zod │ │ → intent + confidence │ └────────────┬──────────────────┘ │ ┌───────────────────┼──────────────────┐ ▼ ▼ ▼ intent=ooo_autoreply intent=interested intent=not_interested │ │ │ ▼ ▼ ▼ ┌── parseOOOReturnDate ─┐ stop seq enrollment.status │ Gemini 3 Flash │ route to AI = stopped (replyAutomationConfig) │ responseSchema │ draft worker │ → return_date │ └──────────┬────────────┘ ▼ enrollment.status = paused email_replies.resume_at = return_date │ ▼ enrollment-auto-resume.worker (1hr cron) │ ▼ status = active + next step reschedule

D2C4 학습 루프 + Structured Output 매핑

LLM 사용 지점모델Schema 핵심 필드Provider린다 파일
① 거절 패턴 batch 추출 (주 1회) GPT-5.4-mini strict reasoning, rejection_category (8 enum), objection_phrase, rebuttal_angle, is_recoverable response_format strict objection-pattern-extractor.worker 신규
② 거절 패턴 자연어 요약 Gemini 3 Flash pattern_summary, frequency, top_phrases[], avoidance_suggestion responseSchema 같은 워커 내부 후속 호출
③ 회신율 TOP 다이제스트 인사이트 생성 Gemini 3 Flash Lite weekly_summary, insights[], action_items[] responseSchema weekly-digest-data.service.ts 확장
④ Sentiment → Lead Score rationale Gemini 3 Flash Lite (선택) score_delta, reasoning (UI 노출용) responseSchema sentiment-score-sync.worker 신규
⑤ Mid-flight rewrite (Phase 4) Gemini 3 Pro thinking + Claude 4.7 thinking plan (sequence swap), rewrite_subject, rewrite_body, justification, citations[] responseSchema + tool use 신규 sequence-rewrite.service.ts

거절 패턴 학습 루프 (Outreach 패턴 + Insight 1 적용)

[Replies (30d)] ──batch──▶ [objection-pattern-extractor.worker (weekly)] │ ▼ ┌── ① GPT-5.4-mini strict ──┐ │ rejection_category + │ │ objection_phrase │ └────────────┬───────────────┘ │ ▼ ┌── ② Gemini 3 Flash ──┐ │ 자연어 요약 │ │ + top_phrases │ └────────────┬─────────┘ │ ▼ [objection_patterns 테이블] pattern · frequency example_replies[] avoidance_suggestion │ ▼ ┌────────────────────────────┴────────────────────────┐ ▼ ▼ [admin Insights 페이지] [sequence-ai-gen.service.ts] 매니저 동의/거부 (HITL) 새 시퀀스 생성 시 trigger 활성화 "avoid these phrasings" 컨텍스트 주입 │ ▼ enable=true [trigger: field_changed=avoid_phrase] │ ▼ [sequence-rewrite.service.ts (Phase 4)] Outreach 패턴 적용: AI 가 sequence 직접 수정 X → custom_field 채우고 trigger 가 sequence swap

D3권장 아키텍처 — 린다 통합 다이어그램

┌─────────────────────────────────────────────────────────────────────────┐ │ LINDA 통합 분기 + 학습 루프 아키텍처 (2026) │ └─────────────────────────────────────────────────────────────────────────┘ [Email/Reply Event Stream] ──append──▶ [event_log (append-only)] │ ┌───────────────────────────┼────────────────────────────┐ ▼ ▼ ▼ [synchronous fast path] [trigger evaluator] [analytics OLAP] - reply auto-stop - per-trigger single-thread - analyticsDb - bounce → status - branch[0..N] eval - weekly aggregate - OOO 즉시 라벨 - action enqueue │ │ ▼ ▼ ┌──── AI Gateway (callAIObject) ─────────────────────────┐ │ ① classifyReplyIntent (Gemini 3 Flash Lite + Zod) │ │ ② parseOOOReturnDate (Gemini 3 Flash + Zod) │ │ ③ classifyRejection (GPT-5.4-mini strict + Zod) │ │ ④ rewriteSequence (Phase 4: Gemini 3 Pro / Claude)│ │ all: confidence < 0.7 → fallback to bigger model │ │ all: rationale field BEFORE answer │ │ all: prompt cache for stable system prompts │ └─────────────────────────────────────────────────────────┘ │ ▼ [enrollment state machine] - active / paused / branched - stopped / completed - version 필드로 atomic claim │ ▼ [sequence-email-loader.worker] - pending step 로드 (조건 통과만) - branch_eligible=true 필터 │ ▼ [sequence-email.worker] - SES 발송 22 rps - send 직전 status 재확인 (claim) │ ▼ ┌───────────────────────────┴───────────────────────────┐ ▼ ▼ [weekly-digest.worker] [objection-pattern-extractor.worker] - 회신율 TOP 10 - 30d batch / 주 1회 - 거절 TOP 5 - GPT-5.4-mini strict - intent 분포 - objection_patterns 테이블 - LLM rationale 생성 (Gemini Flash Lite) - admin Insights UI - sequence-ai-gen 컨텍스트 주입

설계 결정 요약

결정참조 SaaS이유
분기 모델 = parent + subsequence (DAG X) Smartlead · Saleshandy UI 복잡도 ↓, 실무 운영 5단계 이상 가독성 무너짐. DAG 는 Phase 4 검토.
분기 평가 = 이벤트 즉시 + 시간조건은 delayed job Saleshandy 즉시 + Reply.io polling 절충 이벤트 즉시가 race 가장 적음. 시간조건만 BullMQ delayed.
OOO = LLM 복귀일 파싱 + 자동 재개 Smartlead · Saleshandy · Hunter 시장 표준. 린다 baseline parity.
Reply intent 분류 = Gemini 3 Flash Lite + Zod (린다 default) Instantly Unibox V2 저가 + 50+ language native. responseSchema 통일.
거절 패턴 학습 = batch 워커 + AI 추천, HITL approve Outreach Research Agent + Salesloft active learning 완전 자동 rewrite 는 위험. 사람 승인 게이트가 ROI 핵심.
Mid-flight rewrite = sequence swap (in-place edit X) Outreach 검증 패턴 Atomic 안전. AI 가 custom_field 채우고 trigger 가 swap.
HITL/Autopilot = confidence threshold spectrum Instantly Reply Agent binary 가 아니라 per-label threshold + global floor.
Explainability = LLM rationale 필드 + UI 노출 Salesloft Rhythm bpm_score.rationale 채택률 핵심. dismiss feedback 도 학습 시그널로.

D4권장 스택 + 단계별 작업 단위

LLM 권장 스택 (린다 한정)

작업모델호출 형태검증
답장 intent 분류 (7 cat) Gemini 3 Flash Lite responseSchema enum + reasoning + confidence Zod, confidence<0.7 → Flash 로 retry
OOO 복귀일 파싱 Gemini 3 Flash Preview responseSchema + nullable + evidence_quote Zod date parse, 미래 6개월 내 sanity check
거절 사유 batch 라벨링 (오프라인) GPT-5.4-mini strict json_schema strict Zod / Pydantic
시퀀스 카피 rewrite Gemini 3 Flash Preview plain text + 메타 호출 (subject, cta) 분리 tone classifier 후처리
고난도 reasoning (전략 분석) Gemini 3 Pro + thinking_budget responseSchema + plan field 사람 검수 큐
Fallback (Gemini 장애) Claude Haiku 4.5 tool use strict tool_choice forced 동일 Zod

공통 규칙

단계별 작업 단위 (노드 manifest)

노드크기작업새 파일 / 수정 파일
N1.1 [S] S llm/schemas SSOT 디렉토리 생성 + reply-intent, ooo-return-date, rejection-pattern, lead-score Zod 정의 신규 elysia-server/src/llm/schemas/*.ts 5 파일
N1.2 [M] M ai-classification.service.ts → callAIObject 전환 + ReplyIntentSchema 사용 services/ai-classification.service.ts
N1.3 [M] M parseOOOReturnDate 신규 함수 + Zod schema + Gemini 3 Flash 호출 utils/auto-reply-detection.ts 함수 추가
N1.4 [S] S email_replies.resume_at 컬럼 추가 migration drizzle migration + db/schema/emails.ts
N1.5 [M] M enrollment-auto-resume.worker 신규 (1hr cron) 신규 워커
N1.6 [L] L sequence-branching.service 신규 + branch-eval.worker + sequenceSteps 컬럼 추가 신규 service + worker + migration
N1.7 [M] M weekly-digest 확장 — 회신율 TOP / 거절 TOP / intent 분포 + LLM rationale weekly-digest-data.service.ts 확장
N1.8 [L] L objection-pattern-extractor.worker + objection_patterns 테이블 + admin Insights UI 신규 워커 + migration + admin page
N1.9 [M] M sentiment-score-sync.worker — Sentiment → leadScore 피드백 신규 워커
N1.10 [L] L Phase 4: sequence-rewrite.service (Outreach 패턴) + trigger field_changed evaluator 신규 service + trigger 엔진

최종 권고

  • Quick win (1-2주): N1.7 (회신율 TOP 다이제스트) — 데이터 이미 있음, weekly-digest 확장만으로 시장 큰 공백 메움.
  • Baseline parity (1-2주): N1.3 + N1.4 + N1.5 (OOO LLM 파싱 + 자동 재개) — Smartlead/Saleshandy 수준.
  • UI 자산 살리기 (4-6주): N1.6 (행동 분기 엔진) — StepConditionType 이 admin enum/UI 로 이미 있으나 DB/워커 미구현.
  • Frontier 진입 (2-4주): N1.8 ("관심 없음" 패턴 학습 → 다음 캠페인 회피) — Outreach 외 거의 없는 시장 frontier.
  • 아키텍처 핵심: AI 가 sequence 직접 재작성하지 않고, AI 가 custom_field 채우고 trigger 가 swap (Outreach 검증 패턴).
  • Schema SSOT: elysia-server/src/llm/schemas/ 디렉토리 신설, FE 도 re-export 로 SSOT 통일.