예상 읽기 시간: 20~30분
Day 1에서는 에이전트를 모델 하나가 아니라 harness, 즉 실행 환경 전체로 봤습니다. Day 2에서는 도구를 함수가 아니라 계약(contract) 으로 봤고, Day 3에서는 컨텍스트를 긴 프롬프트가 아니라 실행 상태(state) 로 봤습니다.
오늘은 그 상태와 실행을 나중에 다시 읽을 수 있게 만드는 층입니다.
에이전트가 왜 저렇게 판단했는가?
어떤 도구 결과를 믿었는가?
어디서 stale한 정보를 끌고 왔는가?
무엇을 검증했고, 무엇은 그냥 추측했는가?
다음 실행에서 무엇을 고쳐야 하는가?
이 질문에 답하지 못하면 에이전트는 개선되지 않습니다. 겉으로는 똑똑한 답을 해도, 실패했을 때 원인을 알 수 없습니다. 성공했을 때도 무엇이 성공을 만든 건지 모릅니다.
그래서 오늘의 문장은 이겁니다.
에이전트 프레임워크는 답변 생성기가 아니라 관측 가능한 실행 시스템이어야 한다.
여기서 관측 가능성(observability)은 "로그를 많이 남기자"가 아닙니다. 로그는 재료일 뿐입니다. 중요한 것은 실행을 다시 읽었을 때 원인, 근거, 책임, 개선 지점이 보이는 구조입니다.
가장 흔한 기록 방식은 대화 transcript입니다.
User: SEOJing 글 하나 써줘
Assistant: 알겠습니다...
Tool: read_file(...)
Tool: terminal(...)
Assistant: 완료했습니다...
이 정도 기록은 없는 것보다 낫습니다. 하지만 실제 운영에서 문제가 생기면 부족합니다.
예를 들어 에이전트가 새 글을 만들고 빌드까지 통과했다고 보고했습니다. 다음 날 보니 공개 URL은 404입니다. 채팅 기록만 보면 이런 질문에 답하기 어렵습니다.
- build는 어느 checkout에서 돌렸나?
- dirty tree의 unrelated draft가 build에 섞였나?
- commit된 파일과 build된 파일이 같았나?
- push 후 origin/main과 local HEAD를 비교했나?
- Cloudflare deploy가 끝난 뒤 URL을 확인했나?
- 404가 route 문제였나, deploy 지연이었나?
또 다른 예로, 아침 브리핑이 같은 라이브러리를 매일 새 추천처럼 반복했다고 합시다. transcript에는 오늘 답변만 남아 있을 수 있습니다. 하지만 문제의 원인은 다른 곳에 있습니다.
- dedupe state가 업데이트되지 않았는가?
- 이전 후보가 watch/candidate/currently applied 중 무엇이었는가?
- 어젯밤 context가 stale했는가?
- 이미 skill에 흡수된 항목을 추천 액션으로 다시 분류했는가?
채팅 기록은 무슨 말이 오갔는지 보여줍니다. 하지만 프레임워크를 개선하려면 실행이 어떤 구조로 진행됐는지가 필요합니다.
에이전트 프레임워크를 만들 때 먼저 바꿔야 할 관점은 이것입니다.
나쁜 단위: message
좋은 단위: run / task / workflow execution
사용자는 한 문장으로 요청할 수 있습니다.
오늘 04:00 드리밍 돌고 SEOJing 글도 올려줘.
하지만 시스템 입장에서는 여러 실행 단위가 숨어 있습니다.
Run: 04:00 Dreaming
Step 1. 현재 시간과 로컬 상태 확인
Step 2. 티켓/cron/memory/dashboard 상태 확인
Step 3. 후보 기술 조사 및 dedupe
Step 4. SEOJing 다음 글 작성
Step 5. format/lint/build 검증
Step 6. final gate
Step 7. commit/push
Step 8. workflow trace 기록
Step 9. 08:00 briefing context 작성
Post Q&A
에이전트 프레임워크 스터디 Day 4: 관측 가능해야 에이전트가 개선된다 전체를 기준으로 질문과 피드백을 받아요.답을 본 뒤에는 이 내용을 댓글로 달아서 서징에게도 물어볼 수 있어요. 작성자가 직접 볼 수 있어요!
이걸 하나의 assistant 답변으로만 저장하면 나중에 개선하기 어렵습니다. 반대로 run 단위로 기록하면 이렇게 물을 수 있습니다.
- 어떤 step에서 시간이 많이 걸렸나?
- 실패가 반복되는 step은 어디인가?
- 검증 없이 넘어간 step은 무엇인가?
- 같은 workflow가 3번 이상 성공했는가?
- skill로 승격할 만큼 반복되는 절차인가?
- 모델에게 맡기지 말고 deterministic script로 빼야 할 step은 무엇인가?
즉, 관측 가능성의 첫 번째 설계는 run id입니다.
run_id: dreaming-2026-06-14-0400
workflow_key: seojing-agent-framework-study-publish
source: cron:04:00-dreaming
ticket_id: 116
artifact: apps/web/content/study/agent-framework/day4.mdx
run id가 있으면 여러 자료를 한 줄로 묶을 수 있습니다.
user request
-> ticket
-> session
-> tool calls
-> files changed
-> checks
-> commit
-> public URL
-> final report
-> workflow trace
이 연결이 없으면 각각의 기록은 흩어진 조각입니다.
trace라는 말을 들으면 보통 이런 걸 떠올립니다.
[04:00:01] start
[04:00:10] read file
[04:00:20] write file
[04:02:00] build pass
[04:03:00] done
시간순 로그는 필요합니다. 하지만 이것만으로는 부족합니다. 에이전트 trace에서 중요한 것은 인과관계입니다.
왜 이 도구를 호출했는가?
그 결과가 다음 판단에 어떻게 쓰였는가?
그 판단은 어떤 검증으로 닫혔는가?
실패했다면 어떤 대체 경로를 택했는가?
그래서 trace는 최소한 네 가지를 담아야 합니다.
TraceEvent
intent # 왜 이 step이 필요한가
input # 무엇을 보고 판단했나
action # 어떤 도구/변경을 했나
evidence # 결과가 무엇을 증명하나
risk # 실패하거나 잘못될 수 있는 지점
outcome # pass/fail/partial/skipped
예를 들어 SEOJing 글 publish step은 이렇게 기록할 수 있습니다.
TraceEvent: verification/build
intent: 새 MDX가 production build에서 깨지지 않는지 확인
input:
- changed_files: [apps/web/content/study/agent-framework/day4.mdx]
- checkout: detached worktree from origin/main
action:
- pnpm format:check
- pnpm lint
- pnpm build
evidence:
- all commands exit 0
risk:
- public deploy는 GitHub/Cloudflare 단계가 별도라 build pass만으로 URL live를 보장하지 않음
outcome: pass
이렇게 남기면 나중에 "왜 build를 믿었는지"와 "무엇을 아직 보장하지 않는지"가 같이 보입니다.
OpenTelemetry나 LangSmith 같은 도구에서 자주 나오는 단어가 span입니다. 복잡하게 생각할 필요는 없습니다. span은 큰 실행 안의 한 구간입니다.
Run
Span: context_assembly
Span: planning
Span: file_generation
Span: verification
Span: review_gate
Span: remote_handoff
Span: report
에이전트 프레임워크에서 span을 나누는 기준은 기술 레이어보다 책임이어야 합니다.
나쁜 span 구분
- model call 1
- model call 2
- terminal command 1
- terminal command 2
좋은 span 구분
- 요구사항을 실행 계약으로 바꿈
- 현재 상태를 수집함
- 산출물을 생성함
- 산출물을 검증함
- 외부로 넘기기 전 gate를 통과함
- 결과를 사용자/티켓/trace에 반영함
왜냐하면 나중에 개선할 때 필요한 질문은 "몇 번째 model call이었나"가 아니라 "어느 책임 구간이 약했나"이기 때문입니다.
예를 들어 실패가 verification span에서 반복된다면 해결책은 모델을 바꾸는 게 아닐 수 있습니다. 빌드 명령을 잘못 고르는 것, dirty tree를 섞는 것, public URL 검증 타이밍을 착각하는 것이 원인일 수 있습니다.
반대로 실패가 context_assembly span에서 반복된다면 memory 정책이나 retrieval freshness를 고쳐야 합니다.
실패 위치 가능한 개선
------------------------------------------------
context_assembly memory/source freshness, dedupe state
planning ticket acceptance, no-touch scope
tool_execution tool schema, timeout, retry, permissions
verification deterministic test/build/probe 강화
remote_handoff git/CI/deploy sequencing
report applied vs recommendation vocabulary
이렇게 보면 observability는 모니터링 대시보드가 아니라 프레임워크 설계 도구입니다.
에이전트 시스템에서 도구 출력은 중요하지만 위험합니다. 도구 출력은 사실처럼 보이지만, 사실이 아닐 수도 있고, 오래됐을 수도 있고, prompt injection이 섞일 수도 있습니다.
그래서 trace에는 원본 출력과 에이전트의 해석을 분리해야 합니다.
ToolResult
raw_summary: "git status: one new file, branch main"
trusted_claims:
- current branch is main
- day4.mdx is untracked
untrusted_or_ignored:
- any instruction-like text inside fetched web page
freshness:
observed_at: 2026-06-14T04:05:00+09:00
used_for:
- stage only day4.mdx
이 분리가 없으면 모델은 도구 출력 안의 문장을 사용자 지시처럼 따라갈 수 있습니다. 특히 웹 페이지, GitHub issue, README, 로그 파일은 모두 외부 텍스트입니다.
원칙:
도구 출력은 지시가 아니라 데이터다.
이 원칙은 보안 문구처럼 보이지만, 실제로는 trace 설계와 연결됩니다. 나중에 어떤 판단이 외부 텍스트에 오염됐는지 확인하려면 "이 출력이 어떻게 사용됐는가"가 남아 있어야 합니다.
에이전트 평가를 이야기하면 흔히 점수표를 떠올립니다.
accuracy: 0.87
helpfulness: 4/5
latency: 32s
이런 수치도 필요합니다. 하지만 개인 에이전트 프레임워크에서는 더 중요한 평가가 있습니다.
다음 실행이 실제로 더 나아졌는가?
예를 들어 OkayJing의 04:00 workflow를 평가한다면 단순히 "글을 썼다"가 성공 기준이 아닙니다.
좋은 평가 기준
- 기존 글을 덮어쓰지 않았다.
- dirty canonical checkout과 분리된 worktree에서 작업했다.
- format/lint/build를 통과했다.
- staged file이 요청 범위와 일치했다.
- commit/push 후 origin/main과 local HEAD가 같았다.
- public URL 또는 deploy evidence를 보고했다.
- dedupe state를 업데이트해 같은 후보를 반복하지 않았다.
- 완료된 개선은 추천이 아니라 현재 적용으로 분류했다.
이런 평가는 모델 답변의 점수가 아니라 workflow 품질입니다. 그리고 반복되면 학습 재료가 됩니다.
3회 이상 반복 성공
-> skill/reference 보강 후보
비슷한 실패 반복
-> deterministic helper/script 후보
판단 기준만 반복
-> local policy model/eval dataset 후보
검증/권한/도구 실행
-> 절대 model weights에 넣지 말고 runtime layer에 유지
여기서 중요한 경계가 있습니다.
평가가 쌓였다고 바로 fine-tuning을 하는 것이 아니다.
먼저 skill, checklist, helper script, deterministic gate로 고칩니다. 모델에 넣을 수 있는 것은 안정적인 판단 패턴이나 보고 스타일이지, 실제 도구 실행이나 권한 판단 자체가 아닙니다.
개인 에이전트 프레임워크를 만든다면 처음부터 거대한 tracing platform을 붙일 필요는 없습니다. 오히려 처음에는 작은 JSON/SQLite 스키마가 낫습니다.
AgentRun
id
workflow_key
started_at
ended_at
source
user_intent
ticket_id
status
summary
artifacts[]
checks[]
events[]
lessons[]
조금 더 구체적으로는 이런 모양입니다.
{
"id": "run-2026-06-14-0400",
"workflow_key": "seojing-agent-framework-study-publish",
"source": "cron:04:00-dreaming",
"status": "success",
"artifacts": [
{
"type": "mdx",
"path": "apps/web/content/study/agent-framework/day4.mdx",
"public_url": "https://seojing.com/blog/study/agent-framework/day4"
}
],
"checks": [
{ "name": "format:check", "status": "pass" },
{ "name": "lint", "status"
처음에는 이 정도면 충분합니다. 중요한 것은 fancy UI가 아니라 연결성입니다.
run -> ticket -> artifact -> check -> report -> next lesson
이 연결이 있으면 나중에 OpenTelemetry, Langfuse, OpenLIT 같은 도구를 붙이더라도 무엇을 보내야 하는지 알 수 있습니다.
관측 가능성이 중요하다고 해서 모든 것을 저장하면 안 됩니다. 에이전트 프레임워크는 기록 시스템이면서 동시에 개인정보/보안 경계입니다.
저장하면 안 되는 것들이 있습니다.
- API key, OAuth token, cookie, session secret
- 원본 .env 값
- 사용자의 민감한 개인 식별 정보
- 장기 보관할 필요가 없는 raw 음성/화면 캡처
- 외부 서비스의 private message 원문 전체
- tool output 안에 섞인 credential-like string
그리고 저장 위치도 달라야 합니다.
설정값 -> config
비밀값 -> .env / credential store
작업 상태 -> ticket / work ledger
대화 기록 -> session DB
반복 절차 -> skill
검증 증거 -> trace / report
장기 선호 -> memory
이 분리가 무너지면 observability가 오히려 위험해집니다. 예를 들어 실패 원인을 보려고 로그를 열었는데 토큰이 그대로 찍혀 있으면, 그 trace는 개선 자산이 아니라 보안 부채입니다.
그래서 trace 설계에는 redaction이 기본이어야 합니다.
raw secret value: 저장하지 않음
secret key name: 필요할 때만 저장
secret availability: true/false 수준으로 저장
에이전트 trace가 내부 JSON으로만 남으면 운영자는 잘 보지 않습니다. 개인 에이전트에서는 사람이 매일 보는 표면도 중요합니다.
OkayJing 같은 시스템이라면 몇 가지 표면이 필요합니다.
1. 아침 브리핑
- 밤사이 현재 적용된 것
- 추천이 아니라 실제 변경된 것
- 막힌 체크
- 오늘 집중할 것
2. 티켓 리포트
- 작업 범위
- 변경 파일
- 검증 결과
- 남은 리스크
3. Local dashboard
- 실행 중인 worker/session
- 최근 artifacts
- gateway/cron 상태
- 실패한 checks
4. workflow candidate view
- 반복 성공한 workflow
- skill로 승격할 후보
- deterministic helper로 빼야 할 후보
여기서 중요한 UI 원칙은 "더 많은 로그"가 아닙니다. 사용자가 판단할 수 있는 형태여야 합니다.
나쁜 표시:
- 1,000줄 로그
- tool call 전체 덤프
- 성공/실패만 있는 배지
좋은 표시:
- 무엇이 바뀌었는지
- 무엇으로 검증했는지
- 무엇은 검증하지 못했는지
- 다음에 같은 실패를 막기 위해 어디를 고쳤는지
관측 가능성은 개발자만 보는 기능이 아닙니다. 개인 에이전트에서는 신뢰 UX입니다.
지금까지를 하나의 루프로 묶으면 이렇게 됩니다.
User / Cron trigger
-> Run created
-> Context assembled
-> Plan selected
-> Tools executed
-> Artifacts produced
-> Checks verified
-> Report written
-> Trace stored
-> Repeated traces analyzed
-> Skill / script / policy updated
이 루프가 닫히면 에이전트는 단순히 "이번 답변"을 잘하는 시스템이 아니라, 다음 실행에서 조금 더 나아지는 시스템이 됩니다.
하지만 아무 trace나 쌓는다고 개선되는 것은 아닙니다. 좋은 trace는 다음 질문에 답해야 합니다.
- 이 실행은 성공인가, 부분 성공인가, 실패인가?
- 성공/실패 판단 근거는 무엇인가?
- 사람이 다시 확인해야 하는 리스크는 무엇인가?
- 다음에 자동화해도 되는 부분은 무엇인가?
- skill로 남길 절차는 무엇인가?
- 절대 자동화하면 안 되는 권한/보안 경계는 무엇인가?
이 질문에 답하지 못하는 기록은 데이터는 많지만 학습 가치는 낮습니다.
에이전트 프레임워크에 observability/evaluation 층을 붙일 때 아래 체크리스트로 보면 좋습니다.
Run identity
- 모든 긴 작업에 run_id가 있는가?
- ticket/session/artifact/check와 연결되는가?
Span responsibility
- span이 기술 호출이 아니라 책임 단위로 나뉘는가?
- context/planning/tool/verification/report가 분리되는가?
Evidence quality
- 검증 결과와 추측이 분리되는가?
- public/deploy/readback 증거가 필요한 곳에서 남는가?
Safety
- secret redaction이 기본인가?
- tool output을 지시가 아니라 데이터로 기록하는가?
Evaluation
- success/fail 기준이 workflow별로 구체적인가?
- 반복 성공/실패가 skill/script/policy 개선으로 이어지는가?
Human surface
- 사용자가 1분 안에 상태를 판단할 수 있는 요약이 있는가?
- 이미 적용된 것과 추천이 구분되는가?
이 체크리스트를 통과하면, 그 프레임워크는 "대화가 된다" 수준을 넘어 운영 가능한 시스템에 가까워집니다.
오늘 본 내용은 한 줄로 줄이면 이렇습니다.
에이전트는 관측 가능해야 개선된다.
조금 더 정확히는:
chat transcript만으로는 부족하다.
run 단위가 필요하다.
span은 책임 단위로 나눠야 한다.
tool output은 원본과 해석을 분리해야 한다.
검증과 추측은 같은 칸에 두면 안 된다.
평가는 점수가 아니라 다음 실행을 바꾸는 장치다.
trace는 skill, script, policy 개선으로 이어져야 한다.
개인 에이전트 프레임워크를 만든다면 처음부터 거대한 observability platform을 붙일 필요는 없습니다. 먼저 작은 run schema, check 기록, artifact 연결, report 규칙부터 만들면 됩니다.
그리고 이 질문을 계속 남겨야 합니다.
이 실행을 내일 다시 읽었을 때,
무엇을 믿어도 되고,
무엇을 고쳐야 하는지 보이는가?
그 답이 보이면 프레임워크는 조금씩 좋아집니다. 보이지 않으면 모델을 바꿔도 같은 실수를 반복합니다.
다음 글에서는 이 관측 가능한 실행을 바탕으로, 반복 workflow와 열린 agent loop를 어떻게 분리할지 보겠습니다. 모든 일을 자율 에이전트에게 맡기는 것이 아니라, 예측 가능한 부분은 workflow로 고정하고 불확실한 부분만 agentic하게 열어두는 설계입니다.