Agentic 워크플로우
Agentic workflow에서도 실행 범위는 애플리케이션이 정합니다. controller는 orchestrator.toml에 허용된 도구와 호출 상한 안에서만 다음 행동을 고릅니다. 새 프로젝트는 구조로 확정되는 경로를 OKF 규칙에 두고 남은 판단만 controller에 맡기는 rules-first로 시작하세요.
| 범위 | 먼저 실행되는 것 | 맞는 상황 |
|---|---|---|
rules-first | OKF routing rule, 필요할 때 controller | 업무 규칙이 있거나 점차 늘어날 서비스 |
full | controller | 모든 요청에 의미 기반 도구 선택이 필요한 범용 assistant |
# Wizard에서 Agentic rules-first를 선택합니다.uv run llamon orch support-desk
# CI에서는 선택값을 명시해 같은 프로젝트를 반복 생성합니다.uv run llamon orch support-desk \ --workflow agentic --scope rules-first \ --agent search=registry:support-search \ --agentic-model 59 --agentic-prompt support-supervisor \ --yes기존 --recipe hybrid는 agentic + rules-first, --recipe agentic은 agentic + full에 대응하는 호환 설정입니다. 새 프로젝트에는 --workflow를 사용하세요.
고정 route와 controller
섹션 제목: “고정 route와 controller”요청 facts만 보고 자식이 확정되면 OKF rule의 then.call에 둡니다. 표현의 뜻을 해석하거나 여러 후보 가운데 골라야 할 때만 controller 도구로 노출합니다.
| 요구 | 둘 자리 |
|---|---|
| 특정 schema면 OCR 호출 | OKF 고정 route |
| “이전 결과”가 가리키는 업무 판정 | controller |
| 모든 요청의 감사 로그 | workflow 경계 또는 앱 코드 |
| 결제·삭제 | side_effecting 도구와 사용자 승인 |
조건 없이 항상 부를 자식을 controller 도구로 노출하면 모델 판단과 호출 예산만 늘어납니다.
---type: routing_ruletitle: document-searchpriority: 20when: schema: support.document-query.v1then: agentic: support # schema가 맞으면 controller를 거치지 않고 고정 첫 도구를 호출합니다. call: search response_data_schema: support.search.result.v1 text: "$user.text"generated: by: process:project-routing-author at: 2026-07-16T00:00:00+09:00---라우팅 rule과 해당 facts contract는 okf/에 둡니다. data-summary나 prompt transform의 독립 response contract는 okf-contracts/가 기본 위치입니다. 조건과 선택자 문법은 OKF 라우팅 rule, projection DSL은 응답 계약을 참고하세요.
서로 의존하는 고정 child가 2~4개면 같은 rule의 then.sequence로 선언합니다. 각 단계는 정식 routing child로 실행되며 다음 단계는 기존 read-only selector인 $prev.text·$prev.data_parts·$prev.files로 직전 결과를 받습니다.
---type: routing_ruletitle: document-intakepriority: 100when: facts: - path: request.hasNewAttachments op: eq value: truethen: sequence: - id: review call: document_review text: "$user.text" data: "$context.data" files: "$context.files" response_data_schema: document-review.result.v1 - id: apply call: benefit text: "$prev.text" data: "$prev.data_parts" files: "$prev.files" output: apply---단계별 when이나 loop는 지원하지 않습니다. sequence는 root의 call·agentic·compose·result_gate·입력 selector와 함께 쓸 수 없고, output을 생략하면 마지막 단계가 primary입니다. 각 call alias는 부팅 시 모두 검증합니다. child가 input_required이면 완료한 앞 단계는 다시 호출하지 않고 기다리던 단계의 exact 입력과 target snapshot으로 재개합니다. 현재 v1은 RuleSource.request() 기반 rule에만 적용합니다.
controller와 도구
섹션 제목: “controller와 도구”[agents]는 alias와 target의 연결표이고, [agentic.support.tools]는 controller allowlist입니다. 자식을 연결했다고 자동으로 도구가 되지는 않습니다.
[agents]search = "registry:support-search"ticket = "registry:ticket-service"
[agentic.support]model = "59"prompt = "support-supervisor"max_controller_steps = 4max_tool_calls = 3context_turns = 10context_roles = ["user", "assistant"]work_memory_context = "relevant"
[agentic.support.tools.search]# 조회 전용 도구는 제한된 대화와 기억 문맥을 받을 수 있습니다.safety = "read_only"input = "conversation"response_data_schema = "support.search.result.v1"
[agentic.support.tools.ticket]# 외부 상태를 바꾸므로 저장된 입력에 대한 사용자 승인이 필요합니다.safety = "side_effecting"input = "request"request_data_schema = "support.ticket.request.v1"controller가 고르는 행동은 네 가지입니다.
| 행동 | 결과 |
|---|---|
call_tool | allowlist의 남은 도구 하나 호출 |
final | 사용자에게 보낼 답변 초안 확정 |
request_input | 보완 질문과 checkpoint 저장 |
request_review | 인증된 담당자 검수에 초안을 등록하고 대기 |
완료한 도구는 같은 입력 구간의 available_tools에서 빠집니다. request_input으로 새 업무 입력을 받아도 execution 전체의 controller 단계 수와 도구 호출 수는 초기화되지 않습니다.
input = "conversation"은 검색·조회·상담 같은 read-only 도구가 “해당 문서의 조사 방법은?” 같은 후속 질문을 독립 child text로 받게 하는 opt-in입니다. 기본 context는 현재 요청 text를 그대로 사용하므로 기존 도구 동작은 바뀌지 않습니다. 직전 assistant 답변을 참조해야 하면 context_roles = ["user", "assistant"]를 함께 사용하세요. conversation은 context의 attachment·WorkMemory 범위를 유지하며, controller는 TextPart만 제안하고 data·files·target은 바꿀 수 없습니다.
read-only 결과를 바로 완료할지는 completion·completion_when·result_transitions으로 제한합니다. 고정 첫 호출에는 result_gate를 사용합니다. 조건, retry와 resume policy digest는 결과 정책이 기준입니다.
문맥과 사람의 개입
섹션 제목: “문맥과 사람의 개입”AgenticProgram은 설정한 최근 대화와 WorkMemory를 controller 관측에 제한된 크기로 투영합니다. 기본 context_roles = ["user"]에는 이전 assistant 답변이 들어가지 않습니다. 원본 파일, OCR 전문, 가공 전 payload, credential과 URL도 자동 투영하지 않습니다. 저장과 회수 범위는 상태·기억·재개에서 정합니다.
side_effecting 도구 승인은 요청한 사용자가 저장된 호출 spec과 입력을 실행하도록 허가하는 경계입니다. HumanReviewPort는 별도의 인증된 담당자가 최종 답변을 승인하거나 수정하는 경계입니다. 둘은 서로 대체하지 않습니다. 자세한 차이는 최종 응답과 안전 경계를 보세요.
보조 판단과 병렬 통합
섹션 제목: “보조 판단과 병렬 통합”규칙과 controller 사이에 작은 판단 하나가 필요하거나, 같은 질문의 독립 답변을 합쳐야 할 때만 아래 유틸을 사용합니다.
| 문제 | 선택 |
|---|---|
| 구조화 값으로 분기 | OKF rule |
| 독립 계약·이력·가드레일이 필요한 분류 | 작은 A2A Agent |
| 한 지점의 제한된 의미 판정 | decider |
| 서로 다른 작업을 병렬 실행 | ctx.gather() |
| 같은 입력의 독립 답변을 judge가 통합 | fuse_panel() |
decider
섹션 제목: “decider”decider는 A2A 자식이 아니라 프로세스 안에서 한 번 실행하는 상태 없는 구조화 판단 LLM입니다. 답변 작성, 도구 반복, memory나 MCP가 필요하다면 작은 Agent로 분리하세요.
from llamon_agent import DeciderSpec, LLMConfig, classify_into_labels
def build_deciders() -> dict[str, DeciderSpec]: return { "ticket_scope": DeciderSpec( llm=LLMConfig(id="59", temperature=0.0), template=classify_into_labels, defaults={ "definitions": { "followup": "앞선 티켓의 결과나 사유를 묻는 경우", "new_request": "새 작업을 요청하는 경우", "unclear": "판단 근거가 부족한 경우", } }, ) }template과 prompt 가운데 하나만 사용합니다. 호출값은 같은 이름의 defaults보다 우선합니다. 결과는 허용 라벨과 confidence를 확인한 뒤 분기하세요.
from llamon_agent import validated_decider_label
raw = await deciders["ticket_scope"].decide(ctx.user_text, labels=LABELS)label = validated_decider_label(raw, LABELS, min_confidence=0.7) or "unclear"구조화 출력이 실패하면 일반 JSON 파싱을 한 번 더 시도해 모델 호출이 최대 두 번 일어날 수 있습니다. 마지막 파싱 실패는 빈 dict지만 전송·인증 예외까지 숨기지는 않습니다.
fuse_panel
섹션 제목: “fuse_panel”fuse_panel()은 같은 입력을 여러 자식에게 병렬로 보내고 응답한 후보만 judge에게 전달합니다. 자식별 입력이 다르면 ctx.gather()를 쓰세요.
from llamon_agent.orchestrator import fuse_panel
fused = await fuse_panel( ctx, panel=("reviewer_a", "reviewer_b"), judge="judge",)if fused.verdict is None: # 유효 후보가 하나도 없으면 judge를 호출하지 않습니다. return ctx.emit(await ctx.call("fallback", text=ctx.user_text))return ctx.emit(fused.verdict)answered·absent·candidates는 출처를 보존하지만 최종 응답에 자동으로 실리지 않습니다. 호출 예외와 is_error·is_unavailable 후보는 absent로 빠집니다. judge의 오류나 input_required는 성공으로 바꾸지 않으므로 호출부가 verdict 상태를 처리합니다.
병렬 호출만으로 답의 다양성이 생기지는 않습니다. 모델, 데이터 접근과 검증 방법이 실제로 독립적인지 확인하고 비용은 패널 전체와 judge 호출을 합산하세요.
다음 문서
섹션 제목: “다음 문서”- 최종 문장, 가드레일과 담당자 검수: 최종 응답과 안전 경계
- 대화, WorkMemory와 checkpoint: 상태·기억·재개
- 예외와 재시도: 운영과 실패 복구