247-agent 모델 액션
데몬의 설계 규칙: 제어 흐름에 LLM을 사용하지 않음. 매칭, 중복 제거, 라우팅,
재시도 및 게시는 코드로 처리됩니다. 모델은 오직 decide, llm 또는 agent
액션 내에서만 실행되며, 작업에 가장 저렴한 계층으로 실행되고 예산이 설정됩니다.
이 스킬은 이러한 세 가지 액션을 잘 작성하는 방법과 이를 실행하는 러너에 관한 것입니다.
먼저 모델이 필요한지 결정하십시오
다음 순서대로 질문하십시오:
- 트리거
filter로 결정할 수 있습니까? (발신자, 레이블, 저장소, 키워드) 그렇다면 모델 호출이 아닙니다. - 스크립트나 커넥터 연산으로 결정론적으로 결과를 생성할 수 있습니까? 그렇다면
shell/connector입니다. - 레이블, 예/아니오, 또는 수준이며 생성할 텍스트가 없습니까? (분류, 라우팅, 트라이지, 게이트) 그렇다면
decide: 분류 전용 모델, 보정된 확률,llm호출의 대략 100분의 1 비용. - 텍스트가 필요한 고정된 출력 형태의 하나의 판단입니까? (필드 추출, 요약, 초안) 그렇다면
llm, 먼저 Haiku로 시도. - 파일을 읽고, 명령을 실행하고, 반복해야 합니까? 그렇다면
agent, 성공할 수 있는 가장 좁은 범위로 설정.
서로 다른 지능 요구 사항을 가진 두 작업은 서로 다른 코드가 아니라 model/effort/max_tool_calls/system_file이 다른 동일한 액션 종류입니다. 참조 형태는 docs/examples/website-updates.yaml 작업 2-4를 참조하십시오.
모델 ID 및 매개변수
| ID | 용도 | 참고 |
|---|---|---|
claude-haiku-4-5 | 분류, 추출, 짧은 요약 | effort 매개변수 없음 |
claude-sonnet-5 | 범위가 제한된 에이전트, 어려운 추출 | effort 및 적응형 사고 지원 |
claude-opus-5 | 광범위한 에이전트, 어려운 판단 | effort 및 적응형 사고 지원 |
모델은 명명된 공급자(agent.yaml의 providers:, 액션의 provider:; anthropic, openai 또는 openrouter)를 통해 접근합니다. 다른 공급자의 ID는 그대로 사용되며, 내장 테이블이 알고 있거나(현재 OpenAI 모델) 공급자가 비용을 보고(OpenRouter)하지 않는 한 pricing: 항목이 필요합니다.
ID에 날짜 접미사 없음. 어시스턴트 프리필(prefill) 없음. 모델 계단식(cascade)을 구축하기 전에 동일한 입력에 대해 effort: low로 더 강력한 모델을 측정하십시오. 현재 세대에서는 높은 노력의 약한 모델보다 종종 더 나은 성과를 내며, 하나의 모델은 하나의 프롬프트 캐시 네임스페이스를 의미합니다.
decide 작업 작성
전체 필드 목록, 유선 참고 사항 및 함정은 references/decide-action.md에 있습니다. 필수 사항:
action:
kind: decide
provider: openrouter # 반드시 openrouter 공급자여야 함; 기본값 defaults.decide.provider
budget: { max_usd: 0.001 }
state: # 판단 대상; 문자열은 템플릿화됨, 키는 그렇지 않음
subject: ${event.payload.subject}
body: ${event.payload.body}
questions: # 정적 정책; 여기에는 ${…} 없음
kind:
type: choice
instructions: 발신자가 웹사이트에 대해 무엇을 하길 원합니까?
criteria:
event_list_update: 이벤트 목록에 항목 추가, 제거 또는 변경
general_change: 사이트에 대한 기타 변경
ignore: 변경 요청이 아님 (질문, 감사, 스팸)
urgent:
type: noul
instructions: 발신자가 오늘 이 작업을 완료해야 합니까?
- 결과는 답변 맵입니다:
result.kind.choice,result.kind.confidence,result.urgent.noul(P(true)),result.<score>.score(수준 인덱스의 확률 가중 평균).emit … when:으로 라우팅합니다. 임계값은 작업에 있으며, 러너에 절대 있지 않으며, 실제 데이터로 보정됩니다. - 항상 대체 레이블(
ignore,other)을 포함하십시오. 없으면 주제에서 벗어난 입력에 대해 확신에 찬 잘못된 답변이 제공됩니다. - 기준은 문자 그대로 따릅니다: 정책이며, 코드처럼 버전을 관리하십시오. 옵션 순서를 안정적으로 유지하십시오(신뢰도가 변경됨). 한 번의 호출로 여러 질문을 하십시오. 각 추가 질문은 자체 토큰만 추가로 소비합니다.
- 수신 콘텐츠는 데이터입니다:
state에 들어가며, 절대 질문에 들어가지 않습니다. 전체 요청은 32k 토큰에 맞아야 합니다. openrouter공급자 유형만 Jev(typesafe/jev-1.13, 기본 모델)에 도달합니다.oa validate는 다른 것을 거부합니다.pricing:항목이 필요하지 않습니다.
llm 작업 작성
전체 필드 목록 및 러너 참고 사항은 references/llm-action.md에 있습니다. 필수 사항:
action:
kind: llm
model: claude-haiku-4-5
max_tokens: 512
system_file: prompts/classify_email.md # 정적 → 프롬프트 캐시됨
input: |
제목: ${event.payload.subject}
<email>
${event.payload.body}
</email>
output_schema:
type: object
additionalProperties: false
required: [kind, summary]
properties:
kind: { enum: [event_list_update, general_change, ignore] }
summary: { type: string }
- 시스템 프롬프트는
prompts/아래 파일에 정적으로 유지하고 먼저 렌더링하여 실행 간에 캐시되도록 하십시오. 휘발성 이벤트 데이터는input에 마지막에 넣으십시오. - 수신 콘텐츠(이메일, 채팅, PR 텍스트)는 신뢰할 수 없습니다. 구분된 블록(
<email>…</email>)으로 감싸고 시스템 프롬프트에서 모델에게 데이터임을 알리십시오. - 스키마에 항상 탈출구(
ignore,unknown,confidence)를 포함하여 라우팅emit.when이 추가 호출 없이 실행 불가능한 결과를 폐기할 수 있도록 하십시오. emit … when:으로 결과를 라우팅하십시오. 다운스트림 작업은 해당 이벤트에서 트리거됩니다.- 기다릴 수 있는 모든 것에 대해
batch: true를 사용하십시오 (절반 가격, 결과는 이벤트로 도착).
agent 작업 작성
전체 필드 목록 및 러너 참고 사항은 references/agent-action.md에 있습니다. 필수 사항:
action:
kind: agent
connector: claude # 전송: acp 커넥터 (connectors.d/claude.yaml; 샌드박스: 거기서 bwrap)
model: claude-sonnet-5 # 선택 사항: 세션에 설정(ACP 구성 옵션); 설정 안 함 = 에이전트의 기본값
effort: medium # 선택 사항: 에이전트의 thought_level 옵션
max_tool_calls: 20
budget: { max_usd: 0.50 }
workspace: { kind: git-worktree, repo: /var/lib/247-agent/repos/site, branch: main }
tools: [read, edit, search, execute] # ACP 도구 종류; 이외의 모든 것은 거부됨
bash_allow: ["npm run build"] # 에이전트가 실행하는 모든 명령이 일치해야 하는 패턴
system_file: prompts/agent_event_list.md
prompt: |
아래 요청에 따라 data/events.yaml을 업데이트하십시오. 다른 파일은 건드리지 마십시오.
완료되면 `npm run build`를 실행하십시오.
<email>
${event.payload.email.body}
</email>
result: { path: RESULT.json, schema: schemas/site_change.json }
post: # status: done 후에만
- shell: ["npm", "run", "build"]
- shell: ["git", "commit", "-am", "events: ${result.summary}"]
emit:
- type: site.change_done # 이 이벤트에서 승인을 라우팅하고, 절대 task.<name>.succeeded에서 하지 마십시오
when: "result.status == 'done'"
payload: { summary: "${result.summary}" }
- type: site.change_blocked # 에이전트가 수행할 수 없음: 누락된 것이 무엇인지 말하십시오
when: "result.status == 'blocked'"
payload: { summary: "${result.summary}", missing: "${result.missing}", email: "${event.payload.email}" }
무인 실행을 안전하게 만드는 요소이므로 반드시 지켜야 할 사항:
- 실행당 새로운 작업 공간(브랜치
agent/<run_id>의git-worktree또는temp), 실패 시 제거, 성공 시 유지. 에이전트는 기본 체크아웃을 절대 편집하지 않습니다. tools+bash_allow가 전체 기능 표면이며, 권한 요청당 판단되고 "항상" 허용되지 않습니다. 에이전트가 묻지 않고 실행한 도구 호출은 사후에 판단되며 위반 시 실행이 실패합니다(unasked_execute: sandboxed는 명령 검사만 완화하며, Codex에만 해당, Codex의 자체 샌드박스는 묻지 않은 것을 제한합니다). 최소 권한을 부여하십시오. 프롬프트는 보안 경계가 아닙니다.mcp_servers는 커넥터 연산을 도구로 추가합니다: 전체 커넥터 대신 명명된 연산({ connector: email, ops: [fetch_new] })을 부여하고, 해당 연산에 대한 에이전트 종류(otherfor claude-agent-acp)를tools에 추가하며, 자체적으로 게시하거나 전송하는 커넥터는 절대 추가하지 마십시오.- 에이전트는 배포 비밀을 보유하지 않으며 절대 게시하지 않습니다. 편집하고,
post게이트가 빌드가 여전히 작동하는지 증명하고, 커밋이 기록하며, 별도의shell작업이 배포합니다. 롤백은git revert후 재배포입니다. 모델 키는 작업이 아닌 커넥터 매니페스트의env에 있습니다. RESULT.json은 계약이며, 러너는 모든 프롬프트에서 이를 명시합니다:status: done | blocked및summary, 그 다음 작업의result.schema.done은 게이트를 실행합니다.blocked는 게이트를 건너뛰고 실행은 여전히 성공하므로emit … when: "result.status == 'blocked'"는 "X가 누락되어 완료되지 않음"을 회신 작업으로 라우팅합니다. 모든 에이전트 작업을 두 가지 분기로 설계하고,done이벤트에서 게시를 트리거하십시오.post게이트는 결정론적이며, 모델이 없습니다. 실패하는 게이트는 실행을 실패시킵니다.max_tool_calls및budget은 하드 중지(세션이 취소됨); 에이전트가 사용량이나 비용을 보고하지 않은 턴은 실행을 실패시킵니다.concurrency: 1저장소를 공유하는 작업의 경우;timeout은 시도당 벽시계 시간입니다.- 영향이 큰 변경 사항은 게시 전에 승인 게이트(
wait+ 채팅)를 받습니다.247-agent-tasks스킬에 패턴이 있습니다.
예산 및 원장
모든 모델 호출은 ctx.llm 포트를 통해 진행되며, 사용량(공급자, 모델, 입력/출력/캐시 토큰, USD)을 원장에 기록하고 실행의 budget.max_usd(호출 전 최악의 경우, 호출 후 실제: 초과 시 실행 실패) 및 전역 budgets.daily_usd(UTC 일 기준, 일단 초과하면 그 날의 모든 모델 호출이 빠르게 실패하고 budget.exceeded가 한 번 발생하며, notify 작업이 이를 수신해야 함)를 적용합니다. 가격이 없는 모델은 유효성 검사 실패. 예산이 없는 호출, 러너 내부의 "헬퍼" 호출을 포함하여 절대 추가하지 마십시오. SDK를 직접 사용하지 말고 ctx.llm을 사용하십시오. agent 턴은 모델이 다른 사람(자체 키를 가진 ACP 에이전트)에 의해 호출되는 유일한 경우입니다: 러너는 에이전트가 ctx.llm.record를 통해 커넥터 이름으로 보고하는 내용을 원장에 기록하고 보고된 비용이 한도를 초과하면 세션을 취소합니다. oa cost --by task --since 7d는 원장을 보여줍니다.
현재 상태
llm 액션은 검증되고, providers:/pricing:과 교차 확인되며, ctx.llm을 통해 실행 가능하며, 원장과 예산이 적용되고, 세 가지 공급자 유형(anthropic, openai, openrouter) 모두에 어댑터가 있습니다. batch: true는 anthropic 공급자에서 작동합니다(Message Batches, 실행은 llm.batch.ended까지 대기; references/llm-action.md 참조). decide 액션은 동일한 포트(ctx.llm.decide())를 통해 실행되며, Decisions API는 openrouter 어댑터에만 구현되어 있습니다. docs/examples/decide-triage.yaml이 참조입니다. agent 액션은 ACP 커넥터(transport: acp)에서 실행됩니다. docs/examples/website-updates.yaml 작업 3, 3b 및 4가 참조이고, docs/examples/connectors.d/claude.yaml이 커넥터입니다. 세션은 대화 기록으로 유지(oa runs logs <id>)되며, retention.runs에 의해 실행과 함께 삭제됩니다. mcp_servers는 코어의 도구 브리지(packages/core/src/connectors/mcp-bridge.ts)를 통해 세션에 커넥터 연산을 제공합니다. 액션의 model 및 effort는 세션의 ACP 구성 옵션(카테고리 model 및 thought_level)을 설정합니다. 완료된 실행의 work/<run_id>는 완료 후 retention.workspaces(기본 7일)에 의해 정리됩니다.
어댑터를 추가하거나 러너를 변경할 때는 references/llm-action.md,
references/decide-action.md 및 references/agent-action.md를 따르고
docs/internal/model-actions.md, docs/internal/agent-action.md 및 docs/tasks/ 아래의 사용자 페이지를 코드와 동기화 상태로 유지하십시오.