최근 개인 프로젝트를 진행하면서 Claude Code, Codex, ChatGPT 등 여러 AI 도구를 함께 사용하고 있다.

도구마다 강점이 다르다 보니 상황에 맞춰 사용하고 있는데, 프로젝트가 늘어나면서 조금씩 번거로운 문제가 생기기 시작했다.

AI마다 알고 있는 프로젝트의 맥락이 다르다는 것이다.

어떤 세션에서는 이미 해결한 문제를 다른 세션에서는 처음부터 다시 설명해야 했다. 이전에 합의했던 설계 원칙을 모르는 AI가 기존 코드와 다른 방식으로 구현하거나, 오래된 문서를 기준으로 현재 상태를 설명하는 일도 있었다.

처음에는 프롬프트나 인수인계 문서를 조금 더 잘 작성하면 해결할 수 있을 거라고 생각했다.

그런데 여러 프로젝트를 오가다 보니 단순히 설명을 잘하는 문제는 아니라는 생각이 들었다.

결국 AI가 바뀔 때마다 맥락을 다시 전달하는 것이 아니라, AI들이 공통으로 참조할 수 있는 지식을 별도로 관리하는 편이 낫지 않을까?

이런 생각으로 로컬 기반의 개인 Wiki를 구축하기 시작했다.

이번 글은 그 과정에서 어떤 기술을 선택했고, 실제로 효과가 있었는지, 그리고 예상하지 못했던 어떤 문제가 발견됐는지를 정리한 기록이다.

1. AI가 기억하는 내용은 어디까지 믿을 수 있을까?

여러 AI를 함께 사용하는 과정에서 기억에 남는 사례가 있다.

기존에 Tailwind를 사용하던 프로젝트의 메인 페이지를 새로 구현하도록 AI에 요청한 적이 있었다.

Figma 디자인과 애니메이션 요구사항을 전달했는데, 결과물을 확인해 보니 기존 프로젝트와 다르게 styled-components를 사용하고 있었다.

당장 화면을 구현하는 데 문제가 있는 것은 아니었다.

다만 프로젝트의 다른 컴포넌트와 스타일링 방식이 달라지면 이후 코드를 수정하거나 재사용할 때 불필요하게 복잡해질 수 있다고 판단했다.

결국 기존 Tailwind 방식으로 다시 정리하고, Tailwind만으로 표현하기 어려운 애니메이션은 별도의 CSS 클래스로 처리했다.

이후에는 AI가 코드를 수정하거나 생성하기 전에 비슷한 역할의 기존 컴포넌트와 페이지를 먼저 살펴보도록 작업 지침을 보완했다.

이 경험에서 중요했던 것은 특정 CSS 기술의 우열이 아니었다.

AI가 현재 작업에 집중하는 동안 프로젝트 전체에서 지켜야 할 원칙을 놓칠 수 있다는 점이었다.

그 원칙이 다른 AI 세션에 전달되지 않는다면 비슷한 문제가 반복될 수도 있었다.

서로 다른 프로젝트가 같은 정보를 공유해야 한다면?

개인적으로는 오래전부터 구상해 온 하나의 창작 세계관을 소설과 게임이라는 서로 다른 매체로 확장하는 작업도 진행하고 있다.

두 프로젝트는 공통 설정을 공유하지만, 매체의 특성에 따라 일부 표현이나 구현 방식은 달라질 수 있다.

여기서도 비슷한 고민이 생겼다.

어떤 설정이 공식적으로 확정된 내용인지, 아직 아이디어 단계인지, 특정 매체에서만 적용하는 각색인지 구분할 필요가 있었다.

이를 여러 AI 세션에 나누어 전달하면서 작업한다면 이전 결정이 누락되거나 서로 다른 설정을 기준으로 결과물이 만들어질 위험이 있다.

소프트웨어 프로젝트에서도 같은 구조의 문제가 나타난다.

공통으로 유지해야 하는 규칙이 있고, 프로젝트마다 다른 구현이 있으며, 시간이 지나면서 기존 결정이 변경되기도 한다.

그렇다면 필요한 것은 단순히 긴 인수인계 문서가 아니라, 확정된 정보와 프로젝트별 해석, 변경의 역사를 구분해 관리하는 지식 기반이라고 생각했다.

2. 처음부터 거대한 RAG 시스템을 만들 필요는 없었다

개발자 커뮤니티에서 개인 로컬 Wiki를 구축하고 여러 AI 도구와 연동해 활용한다는 사례를 접했다.

마침 내가 겪고 있던 문제와도 연결되는 부분이 많았다.

다만 처음부터 모든 과거 대화를 수집하거나, 로컬 LLM과 벡터 데이터베이스를 붙여 거대한 지식 시스템을 만들 생각은 없었다.

과거의 모든 기록을 완벽하게 복원하는 것은 작업 범위도 너무 컸고, 무엇보다 그 과정에서 잘못된 정보를 확정된 사실로 가져올 위험도 있었다.

그래서 이번에는 현재를 기준점으로 삼기로 했다.

주요 프로젝트의 현재 상태와 최근에 확정한 결정만 먼저 정리하고, 이후 발생하는 활동과 판단을 지속적으로 기록하는 방식이다.

초기에 정한 요구사항은 비교적 단순했다.

  • 프로젝트별 현재 상태와 의사결정 이력을 구분한다.
  • 중요한 지식에는 출처와 확인 시점을 남긴다.
  • AI가 제안한 내용과 승인된 내용을 구분한다.
  • Claude Code 외의 다른 AI도 접근할 수 있어야 한다.
  • 매번 전체 문서를 읽히는 대신 필요한 정보만 조회한다.

특히 이번 Wiki는 별도의 판매용 제품이 아니라 내 개발 환경을 지원하는 내부 인프라다.

따라서 기능을 많이 넣는 것보다 실제로 유지하고 사용할 수 있는 구조를 만드는 데 집중했다.

3. Markdown, SQLite, MCP로 시작한 구조

초기 구현에서는 Markdown과 Git을 지식 원본으로 사용하고, Node.js 내장 SQLite를 검색 색인에 활용했다.

Wiki에 저장할 데이터는 출처가 다른 여러 종류의 지식이다.

프로젝트 현황, 설계 결정, 테스트 결과, 문서, 현재 유효한 사실, 과거에 사용했던 표현 등이 포함된다.

이 정보를 AI가 동일한 방식으로 소비할 수 있도록 CLI를 만들고 MCP 서버를 연결했다.

현재 구현된 주요 기능은 다음과 같다.

기능역할

hw validate 지식 구조와 승인 상태 등의 유효성 검사
hw search 지식 검색
hw show 문서 원문 조회
hw timeline 시간순 변경 기록
hw brief 프로젝트별 현재 상태와 주요 맥락 요약
hw ingest 지원 대장 등 기존 데이터 가져오기
MCP 서버 외부 AI 세션에서 Wiki 기능 호출
정적 HTML 뷰 프로젝트 허브, 검색, 타임라인, 관계 그래프

웹 화면은 현재 탐색을 위한 정적 스냅샷 형태다.

문서를 직접 편집하는 기능까지 웹에 구현하지는 않았다. 데이터 수정과 검증, 승인 기능은 기존 파일과 CLI를 중심으로 관리한다.

이렇게 하면 편집 UI를 위해 별도의 상태 동기화 구조를 추가하지 않아도 된다.

한국어 검색은 어떻게 처리할까?

초기에는 검색 방식부터 비교했다.

실제 문서 177개와 검색 질의 30개를 이용해 네 가지 검색 방식을 시험했다.

그 결과, 공백을 제거한 문자열에 trigram 검색을 적용하고 두 글자 이하의 질의에는 LIKE를 사용하는 방식이 준비한 평가 세트에서 가장 좋은 재현율을 기록했다.

평가 항목결과

평가 문서 177개
질의 30개
비교한 검색 방식 4가지
기본 방식 재현율 81.5%
선택한 방식 재현율 100%

기본 방식에서는 조사가 붙은 검색어를 놓치는 문제가 있었다.

물론 여기서 재현율 100%라는 것은 평가에 사용한 30개 질의에서 원하는 결과를 찾았다는 뜻이지, 모든 한국어 검색이 완벽하다는 의미는 아니다.

하지만 현재 문서 규모와 사용 목적에서는 더 복잡한 검색 시스템을 당장 도입할 이유가 충분하지 않았다.

그래서 벡터 검색과 로컬 LLM 기반 의미 검색은 일단 보류했다.

기능을 추가할 수 있다는 이유만으로 추가하지 않기로 했다.

4. 검색보다 먼저 해결해야 했던 문제: 무엇을 사실로 볼 것인가?

초기 데이터를 정리하는 과정에서 예상보다 많은 불일치를 발견했다.

그중 일부는 실제 오류였지만, 일부는 서로 다른 목적의 문서에서 발생한 정상적인 차이였다.

예를 들어 하나의 경험이라도 작성 목적에 따라 강조하는 부분이 달라질 수 있다.

기술적인 의사결정을 설명하는 문서에서는 구현 과정이 중요하지만, 외부에 제출하는 소개 자료에서는 해당 경험이 어떤 문제를 해결했는지가 더 중요할 수 있다.

따라서 특정 문서에 정보가 빠져 있다는 이유만으로 모순이라고 판단해서는 안 된다.

반대로 과거에 작성한 문서에 잘못된 내용이 존재할 수도 있다.

그 문서가 실제로 사용됐다는 사실과, 문서에 적힌 내용이 현재도 정확하다는 사실은 서로 다르다.

이 문제를 해결하기 위해 데이터를 세 가지 개념으로 분리했다.

Canonical Facts

현재 확인된 기준 사실이다.

실제 프로젝트의 구현 내용이나 사용자가 확인한 경력 사실처럼, 다른 문서를 작성할 때 기준으로 삼을 정보가 여기에 해당한다.

Contextual Representations

목적이나 대상에 맞게 기준 정보를 선별하고 표현한 결과다.

특정 프로젝트의 소개 문서나 외부 제출 자료처럼 같은 사실을 서로 다른 관점에서 설명할 수 있다.

Historical Snapshots

특정 시점에 실제로 사용했던 문서의 원본이다.

이후 오류가 발견되더라도 해당 문서를 과거에 사용했다는 기록까지 변경하지 않는다.

대신 현재 확인된 사실과 정정 기록을 연결한다.

이 구분은 단순한 문서 정리를 넘어, AI가 서로 다른 출처를 읽었을 때 무엇을 기준으로 판단해야 하는지를 정의하는 데 필요했다.

5. AI의 잘못된 분석이 다른 AI에게 전달된 사례

Wiki 설계 과정에서 실제로 흥미로운 문제가 발생했다.

Claude Code가 기존 자료를 분석하면서 회사 이름의 식별자가 일관되지 않다고 보고했다.

나는 그 분석을 다른 AI에게 전달했고, 다른 AI도 이를 데이터 모델의 문제로 받아들였다.

그런데 이후 실제 필드를 다시 검토해 보니 최초 판단이 잘못됐다는 사실이 드러났다.

표시용 이름과 이미 정규화된 식별자를 혼동한 것이었다.

실제로 개선해야 할 부분은 다른 데이터 목록에 식별자가 누락되어 있거나, 서로 다른 플랫폼의 동일한 항목을 연결하지 못하는 문제였다.

결과적으로 AI의 잘못된 최초 분석이 다른 AI의 판단 근거로 전달된 것이다.

이 과정을 보면서 단순히 출처를 저장하는 것만으로는 부족하다는 생각이 들었다.

어떤 결론이 왜 만들어졌고, 무엇을 근거로 수정됐는지도 추적할 수 있어야 했다.

그래서 기존의 잘못된 판단을 조용히 덮어쓰기보다 정정 이벤트로 남겼다.

이후에는 지식의 승인 상태도 별도로 검증하도록 했다.

실제로 첫 검증에서는 승인 기록 없이 확정 상태로 표시된 노트 등 여러 위반 사항이 발견됐다.

검증기가 이를 찾아내면서 데이터 구조를 바로잡을 수 있었다.

이번 작업에서 가장 의미 있었던 경험 중 하나는, Wiki를 구축하는 과정에서 발생한 오류 자체가 Wiki에 기록할 첫 번째 지식이 되었다는 점이다.

6. 실제 A/B 테스트: Wiki가 토큰을 줄여줄까?

기능이 어느 정도 갖춰진 뒤에는 원천 문서를 직접 읽는 방법과 Wiki를 사용하는 방법을 비교했다.

시험에는 별도의 Claude Code 서브에이전트를 활용했다.

질문과 정답 기준은 실험 전에 파일로 등록했다.

평가 조건은 다음과 같다.

조건 A — 원천 문서 직접 조회

기존 프로젝트 저장소와 관련 문서, 기록 파일을 직접 탐색한 뒤 질문에 답한다.

조건 B — Wiki 조회

Wiki CLI를 통해 필요한 정보를 조회하고 질문에 답한다.

두 조건에 동일한 13개 질문을 제공했다.

질문은 현재 프로젝트 상태, 과거 결정, 판단 근거, 기록의 기준일, 다른 프로젝트에서 사용한 해결 방식 등으로 구성했다.

기록에 없는 사실을 질문해 AI가 내용을 임의로 만들어내는지도 확인했다.

결과

평가 항목A: 원천 문서B: Wiki

정확한 답변 10 13
부분 정답 3 0
지어낸 답변으로 분류된 건수 0 0
동일 원천으로 답변 가능한 9문항 9/9 9/9
사용 토큰 235,242 101,097
A 대비 토큰 사용량 100% 43%

이번 평가에서는 Wiki를 사용한 조건 B가 원천 문서 방식보다 약 57% 적은 토큰을 사용했다.

정확한 답변 수도 B가 더 많았다.

하지만 이를 곧바로 Wiki의 검색 방식이 더 정확하다는 의미로 해석할 수는 없었다.

전체 13개 질문 중 일부는 Wiki에만 반영된 최신 사용자 정정 정보를 필요로 했다.

반면 두 조건이 모두 접근할 수 있는 원천 정보만 필요한 9개 질문에서는 A와 B가 모두 정답을 기록했다.

따라서 이번 시험에서 확인한 성과는 동일한 정보로 답변할 수 있는 질문에서 정확도를 유지하면서 전체 토큰 사용량을 줄였다는 것에 가깝다.

또한 처음 설정했던 목표는 원천 문서 방식 대비 20% 이하의 토큰 사용량이었다.

실제 결과는 43%였으므로 목표를 달성하지 못했다.

이후 현실적인 다음 목표를 35% 이하로 조정했다. 아직 그 수치를 달성한 것은 아니다.

실험의 한계

이번 평가에서 답변은 완전히 블라인드로 채점하지 못했다.

근거에 문서 경로나 Wiki의 ID가 포함되어 있어 어느 조건의 답변인지 구분할 수 있었기 때문이다.

또한 사용한 질문은 13개에 불과하며, 평가에 활용한 문서와 질문도 현재 프로젝트에 맞춰져 있다.

따라서 이번 결과를 다른 프로젝트나 모든 AI 작업에 일반화하기는 어렵다.

다만 초기 시스템의 문제를 찾기 위한 실험으로서는 충분히 유용했다.

7. Wiki가 항상 더 좋은 답을 주는 것은 아니었다

A/B 평가에서 가장 흥미로웠던 부분은 전체 점수보다 개별 질문의 차이였다.

사례 A: 과거 문서의 잘못된 내용을 현재 사실로 받아들임

조건 A는 과거에 사용했던 문서를 읽으면서, 이후 정정된 정보를 반영하지 못한 사례가 있었다.

반면 조건 B는 기준 사실과 과거 문서를 구분해 관리하고 있어 올바른 정보를 선택했다.

이는 검색 결과에 출처가 있다는 사실만으로 그 내용이 신뢰할 만하다고 판단해서는 안 된다는 것을 보여준다.

문서를 정확하게 찾는 것과 그 문서의 내용을 현재의 사실로 채택하는 것은 다른 문제다.

사례 B: Wiki의 요약이 최신 기록을 놓침

반대로 조건 A가 더 잘 답한 질문도 있었다.

운영 중인 개인 프로젝트의 최근 기록에 미완료된 자동화 작업이 남아 있었는데, Wiki의 프로젝트 브리프에는 해당 최신 기록이 충분히 반영되지 않았다.

원문을 직접 읽은 A는 미완료 상태를 확인했다.

하지만 B는 요약된 프로젝트 상태를 참고하면서 일부 정보를 추론에 의존했다.

이 사례는 Wiki가 오래된 요약을 전달하면 최신 원문보다 불리해질 수 있다는 문제를 보여줬다.

이를 개선하기 위해 브리프에서 최근 갱신 문서를 함께 표시하도록 수정했다.

프로젝트의 현재 상태를 요약하더라도, 그 요약보다 최신인 기록이 존재한다면 AI가 이를 확인할 수 있어야 한다고 판단했기 때문이다.

8. 프로젝트마다 흩어진 지식을 연결하기 시작했다

A/B 평가 중 특정 질문에서 Wiki 조건이 같은 주제의 자료를 여러 번 검색하는 문제가 있었다.

원인을 살펴보니 중복 요청 방지와 관련된 기술적 판단이 여러 프로젝트에 흩어져 있었다.

프로젝트별 문서는 존재했지만 공통으로 재사용할 지식은 별도로 정리되어 있지 않았던 것이다.

그래서 관련 프로젝트에서 출처가 확인된 내용을 모아 하나의 공통 지식 노트를 작성했다.

다만 AI가 작성한 노트이므로 처음에는 승인 대기 상태로 남겼다.

이 과정에서 처음 구상했던 Wiki의 또 다른 목적이 드러났다.

프로젝트마다 별도의 기록을 남기는 것에서 그치지 않고, 여러 프로젝트에서 반복된 문제와 해결 경험을 연결해 재사용할 수 있어야 한다는 것이다.

아직 실제 개발 과정에서 재사용 효과가 얼마나 있는지는 확인하지 못했다.

하지만 적어도 검색 과정에서 발견한 비효율을 데이터 구조의 개선으로 연결하는 첫 사례가 되었다.

9. 지금까지 구현한 것과 앞으로 필요한 것

현재는 로컬 Wiki를 구축하고 MCP 연동까지 완료했다.

검색, 현재 상태 조회, 의사결정 히스토리, 출처 추적, 지식 제안과 승인, 그래프 탐색 등을 사용할 수 있다.

하지만 다른 AI 세션에서 작업한 내용이 아무런 개입 없이 자동으로 수집되고 학습되는 시스템은 아직 아니다.

현재 구현한 것은 여러 AI가 공통 지식을 조회하고, 새로운 지식을 제안할 수 있는 기반이다.

다음에는 개발 과정에서 발생한 중요한 결정과 구현 결과를 어떻게 수집할지 검토하려 한다.

그렇다고 모든 채팅 메시지를 무조건 저장하고 싶지는 않다.

개발 과정에서는 검토하다가 폐기한 아이디어도 있고, AI가 잘못 이해한 내용도 있고, 아직 검증하지 않은 추론도 나온다.

이것들이 모두 공식 지식으로 확정된다면 오히려 정보의 품질이 떨어질 수 있다.

따라서 자동 수집을 구현하더라도 수집, 제안, 검증, 승인 과정을 구분하는 원칙은 유지할 생각이다.

또한 현재 검색에서 해결되지 않는 문제가 확인되지 않은 이상 의미 검색이나 벡터 데이터베이스를 무리하게 추가하지는 않으려 한다.

10. 마무리하며

이번 작업은 원래 여러 AI에게 같은 맥락을 반복해서 설명하는 것이 번거로워서 시작했다.

그런데 실제로 자료를 정리하고 비교 실험까지 해보니 생각보다 해결해야 할 문제가 많았다.

AI가 이전 결정을 기억하지 못하는 것도 문제였지만, 잘못된 내용을 현재 사실로 받아들이거나 서로 다른 목적의 자료를 같은 기준으로 해석하는 것도 문제였다.

그리고 Wiki를 구축한다고 이런 문제가 자동으로 사라지는 것은 아니었다.

요약된 정보가 오래되면 최신 기록을 놓칠 수 있고, 출처가 있는 문서라도 사실이 잘못되어 있을 수 있었다.

그래서 이번 프로젝트에서 중요하게 생각하게 된 것은 검색 자체보다도 어떤 지식을 신뢰하고, 어떤 판단을 변경했으며, 그 근거가 어디에 있는지 추적할 수 있는 구조였다.

이번 초기 평가에서는 Wiki 사용 조건이 원문 직접 조회보다 약 57% 적은 토큰을 사용했다.

다만 실험 규모가 작고, 데이터 최신성에 차이가 있었으며, 처음 목표했던 토큰 사용량에도 미치지 못했다.

그럼에도 개인적으로는 만족스러운 출발이었다.

이제는 새로운 AI 세션을 시작할 때마다 내가 무엇을 했고 왜 그렇게 결정했는지 다시 설명하는 대신, 그 정보를 참조할 수 있는 기반이 생겼기 때문이다.

앞으로 개발하는 제품들이 원하는 성과를 내지 못하거나 중간에 방향을 바꾸더라도, 그 과정에서 얻은 판단과 검증 결과까지 사라지지는 않았으면 한다.

AI가 나를 얼마나 오래 기억하느냐보다, AI가 참고할 지식을 내가 얼마나 정확하게 관리할 수 있느냐.

지금은 그쪽이 더 중요한 문제처럼 느껴진다.

앞으로 실제 개발과 창작 작업에서 사용하면서 발견하는 문제들도 계속 기록해 볼 생각이다.


2026년 10월 25일 개인 개발 환경에서 진행한 초기 구현과 평가를 바탕으로 작성했습니다. 본문의 성능 수치는 제한된 평가 조건에서 얻은 결과이며, 다른 환경에서의 성능이나 지속적인 생산성 개선을 보장하지 않습니다.

 

'AI, LLM' 카테고리의 다른 글

로컬 LLM을 붙여봤다가, 안 쓰기로 했다  (0) 2026.09.30

오늘은 로컬 LLM을 직접 서비스에 붙여보는 실험을 해봤습니다.

요즘 로컬 LLM이나 여러 모델을 역할별로 나눠 사용하는 구조에 대해 이런저런 이야기를 많이 듣고 있기도 했고, 저도 실제로 한 번 돌려봐야 어느 정도인지 감이 올 것 같았습니다.

마침 제가 만들고 있는 서비스 중에 실험하기 적당한 게 하나 있었습니다.

‘오늘 얼마 먹어도 돼?’

사용자가 하루 동안 먹은 음식을 그냥 평소 말하듯 입력하면 기록하고, 오늘 얼마나 더 먹을 수 있는지 보여주는 작은 서비스입니다.

예를 들면 이런 식입니다.

“아침에 계란 두 개 먹었어.”

“아까 먹은 바나나 취소해줘.”

“오늘 얼마나 더 먹어도 돼?”

이 서비스에서는 사용자의 문장을 받으면 먼저 이게 음식 추가인지, 수정인지, 삭제인지, 상태를 묻는 건지 등을 판단합니다.

현재는 이 판정을 Jev라는 외부 모델에 맡기고 있습니다.

문득 이런 생각이 들었습니다.

이 정도의 짧은 문장 분류라면 굳이 외부 모델을 호출하지 않고 작은 로컬 LLM으로 처리해도 되지 않을까?

그래서 직접 테스트해보기로 했습니다.


일단 모델부터 설치하지는 않았다

처음에는 Ollama를 설치하고 모델부터 실행하면 될 거라고 생각했습니다.

그런데 실제 코드를 다시 살펴보니 먼저 해야 할 게 있었습니다.

현재 앱에서 AI가 정확히 무엇을 하고 있는지를 분리하는 일이었습니다.

확인해보니 생각보다 구조가 명확했습니다.

LLM은 사용자의 의도를 판단합니다.

반면 음식 이름과 양을 해석하고, 칼로리를 조회하고, 실제 기록을 추가하거나 수정하는 작업은 코드가 처리하고 있었습니다.

즉 대략 이런 구조였습니다.

사용자 입력
→ AI가 의도 판단
→ 코드가 명령 결정
→ 음식 데이터 조회
→ 실제 기록 처리

이 구조라면 실험하기 상당히 좋았습니다.

기존 로직을 거의 건드리지 않고 판정기만 로컬 모델과 비교해볼 수 있기 때문입니다.

그래서 바로 로컬 모델을 실제 기능으로 넣지 않고 세 가지 모드를 만들었습니다.

off

기존 시스템 그대로 사용합니다.

shadow

기존 Jev의 판단을 실제 결과로 사용하면서, 같은 문장을 로컬 LLM에게도 보내 결과만 비교합니다.

active

로컬 모델의 결과가 일정 조건을 만족하면 사용하고, 그렇지 않으면 기존 Jev로 다시 보냅니다.

그리고 production에서는 무조건 off가 되도록 막았습니다.

지금 목적은 새 기능을 만드는 것이 아니라 이게 정말 쓸 만한지 확인하는 것이었기 때문입니다.


테스트 데이터도 만들었다

그냥 몇 문장 던져보고

“오, 잘 되는데?”

라고 끝내면 의미가 없을 것 같았습니다.

그래서 로컬 라우터용으로 67개의 테스트 케이스를 만들었습니다.

예를 들면 이런 문장들입니다.

“아침에 계란 두 개 먹었어.”

“점심 김치찌개랑 밥.”

“아까 먹은 바나나 취소해줘.”

“나 오늘 얼마나 더 먹어도 돼?”

“배고프다.”

“오늘 운동했는데 더 먹어도 돼?”

여기에 오타, 줄임말, 조사가 빠진 문장, 음식 여러 개가 들어간 문장, 애매한 표현들도 섞었습니다.

그리고 정확도만 보는 게 아니라

  • 평균 응답 시간
  • p95 응답 시간
  • JSON 파싱 실패
  • timeout
  • confidence
  • 기존 Jev와의 일치율
  • 실제로 외부 호출을 얼마나 줄일 수 있는지

까지 같이 측정하게 만들었습니다.


그런데 갑자기 Jev가 바보가 됐다

실험 중간에 조금 당황스러운 일이 있었습니다.

기존 Jev에

“아침에 계란 두 개 먹었어.”

를 넣었는데 confidence가 이상하게 낮게 나오기 시작했습니다.

“오늘 얼마나 남았어?”

같은 문장도 엉뚱하게 음식 추가로 판단했습니다.

기존 테스트에서 intent 정확도가 90% 중반대였기 때문에 갑자기 모델 성능이 크게 떨어진 것처럼 보였습니다.

혹시 서비스 쪽 모델이 바뀐 건가 싶어서 baseline을 다시 측정했습니다.

결과는 정상이었습니다.

기존 측정: 93.3%
오늘 측정: 95.0%

모델 버전도 같았습니다.

그럼 뭐가 문제였을까.

결국 범인은 AI가 아니라 Windows Git Bash의 한글 인코딩이었습니다.

curl 명령에서 한글을 직접 body에 넣었더니 UTF-8이 아니라 CP949 바이트로 서버에 전달되고 있었습니다.

즉 모델은 제가 쓴 한국어를 본 게 아니라 깨진 문자열을 보고 있었던 겁니다.

UTF-8 파일로 body를 저장한 뒤 --data-binary로 다시 보내니 정상적으로 confidence 1.00이 나왔습니다.

AI 성능 테스트를 하다가 인코딩 문제를 잡게 될 줄은 몰랐습니다.

그래도 덕분에 테스트 방법까지 문서에 남겨두었습니다.


드디어 로컬 모델을 돌려봤다

PC에는 RTX 2060 SUPER 8GB가 있습니다.

Ollama를 설치하고 우선 작은 모델 두 개부터 테스트했습니다.

  • EXAONE 3.5 2.4B
  • Qwen 2.5 3B

결과는 조금 아쉬웠습니다.

둘 다 intent 정확도가 **79.4%**였습니다.

기존 Jev는 같은 데이터에서 **98.4%**였습니다.

심지어 코드 기반 mock router도 84.1%였습니다.

속도도 예상과 달랐습니다.

EXAONE 2.4B 평균 약 358ms.

Qwen 3B 평균 약 431ms.

Jev는 약 213ms였습니다.

로컬에서 GPU로 직접 돌리는데 외부 모델보다 느렸습니다.

그리고 더 큰 문제가 하나 있었습니다.

두 작은 모델 모두 맞는 답이든 틀린 답이든 거의 무조건 confidence를 0.9 이상으로 줬습니다.

틀리면서도

“나 이거 95% 확신해.”

라고 하는 셈입니다.

이 상태에서는 confidence threshold를 안전장치로 사용할 수도 없습니다.


마지막으로 7B까지 해봤다

그래도 작은 모델만 보고 결론을 내리기는 아쉬웠습니다.

그래서 Qwen 2.5 7B까지 받아서 한 번 더 테스트했습니다.

모델 크기는 약 4.7GB.

RTX 2060 SUPER에서도 100% GPU로 실행됐습니다.

결과는 확실히 좋아졌습니다.

EXAONE 2.4B
79.4%

Qwen 3B
79.4%

Qwen 7B
88.9%

Jev
98.4%

7B 정도가 되니 작은 모델과는 차이가 꽤 났습니다.

confidence도 처음으로 조금 의미가 생겼습니다.

confidence 0.9 이상인 답만 보면 정확도가 92.7%였습니다.

그리고 현재 설정해둔 0.85 threshold와 수정·삭제 요청 fallback 규칙을 적용하면 실제 Local 결과를 사용하게 되는 43건에서는 43건 모두 정답이었습니다.

이 부분은 꽤 인상적이었습니다.

작은 로컬 모델도 조건을 잘 걸면 일부 작업 정도는 충분히 맡길 수 있겠다는 생각이 들었습니다.

하지만 문제가 하나 남았습니다.

속도입니다.

Qwen 7B 평균 응답 시간은 약 593ms.

p95는 1초 정도였습니다.

Jev는 평균 약 214ms였습니다.

그리고 모델이 GPU 메모리에서 내려간 상태에서 첫 요청을 보내면 로딩에 약 4.2초가 걸렸습니다.


그래서 비용도 계산해봤다

그러면 느리더라도 API 비용을 크게 줄일 수 있다면 사용할 이유가 있을 수 있습니다.

현재 구조대로라면 Qwen 7B가 Jev 호출의 약 68% 정도를 대신할 수 있었습니다.

그런데 Jev 비용을 계산해보니 60건 호출에 약 0.003달러 수준이었습니다.

요청 1,000건을 기준으로 계산해도 로컬 모델로 줄일 수 있는 비용이 몇 센트 수준입니다.

반면 production은 Vercel에 올라가 있습니다.

로컬 모델을 실제 서비스에 사용하려면 별도의 GPU 서버를 운영해야 합니다.

그러면 상황이 이상해집니다.

몇 센트를 아끼기 위해 GPU 서버와 새로운 인프라를 추가해야 합니다.

사용자는 응답을 더 늦게 받습니다.

정확도도 기존 시스템보다 낮습니다.

결론이 꽤 명확해졌습니다.


그래서 안 쓰기로 했다

처음 이 작업을 시작할 때 목표는 로컬 LLM을 도입해보는 것이었습니다.

그런데 하루 동안 테스트한 결과는 반대였습니다.

지금 이 서비스에는 로컬 LLM을 도입하지 않는 것이 더 낫다.

현재의 Jev가 더 정확합니다.

더 빠릅니다.

비용도 이미 충분히 쌉니다.

운영해야 할 인프라도 적습니다.

로컬 LLM이 나빠서라기보다는 현재 문제에 이미 더 적합한 도구가 있었던 것에 가깝습니다.

그래서 실험 코드는 기본값 off 상태로 남겨두고, production에서는 사용하지 않기로 했습니다.


그래도 오늘 실험은 꽤 마음에 들었다

예전 같았으면 새로운 기술이 보이면

“이걸 어디에 넣어볼까?”

부터 생각했을 것 같습니다.

오늘은 조금 달랐습니다.

직접 붙여보고,

테스트셋을 만들고,

속도를 재고,

정확도를 비교하고,

비용까지 계산한 다음,

안 쓰는 쪽을 선택했습니다.

새로운 기술을 도입하는 것 자체가 개발의 목적은 아니니까요.

그리고 또 하나 알게 된 것도 있습니다.

2~3B 정도의 작은 모델에서는 아직 제가 원하는 판정 품질이 나오지 않았지만, 7B쯤 되니 꽤 재미있는 수준까지 올라왔습니다.

조금 더 좋은 GPU나 다른 워크로드라면 결과가 또 달라질 수도 있을 것 같습니다.

그래서 오늘의 결론은 이렇게 남겨두려고 합니다.

로컬 LLM 도입은 실패했다.

라고 쓰기보다는,

로컬 LLM을 도입하지 않을 근거를 얻었다.

정도가 더 정확할 것 같습니다.

이런 실험은 꽤 재미있습니다.

이번 호의 중심은 9월 8일 공개된 Meta의 개인 AI 에이전트 Muse입니다. 발표 직후만 보면 브라우저를 사용하고, 앱을 연결하고, 장기 작업을 수행하는 또 하나의 에이전트 제품처럼 보일 수 있었습니다. 하지만 이후 실제 사용 사례와 논란이 이어지면서 오히려 이 제품이 던진 질문이 더 선명해졌습니다.

에이전트가 사용자의 계정으로 쇼핑하고, 메시지와 일정에 접근하며, 앱이 닫힌 뒤에도 계속 일하기 시작하면 문제는 더 이상 모델 성능만이 아닙니다. 어디까지 접근할 수 있는지, 언제 사람에게 승인을 요청하는지, 외부 서비스와 충돌하면 어떻게 처리하는지, 무엇을 실행했는지 사용자가 확인할 수 있는지가 제품의 핵심이 됩니다.

Muse는 브라우저·장기 메모리·앱 연결·결제·사람의 승인·감사 기록을 하나의 개인 에이전트 제품으로 묶었습니다. 출시 후 불과 몇 주 사이 외부 서비스의 접근 차단, 데이터 접근 방식 논란, 클라이언트 보안 취약점까지 등장하면서 이런 운영 구조가 왜 중요한지도 실제 사례로 드러나고 있습니다.

같은 시기 OpenAI는 GPT-6를 Sol과 Luna로 나눠 작업별 비용 선택지를 넓혔고, Vercel은 샌드박스가 종료된 뒤에도 작업 상태를 보존하는 Drive를 공개했습니다. 모델, 실행 환경, 지속 상태가 각각 상품화되면서 에이전트 개발의 중심은 프롬프트에서 운영 구조로 이동하고 있습니다.

이번 주 가장 흥미로운 변화는 벤치마크 1위 모델이 아니라, 이 구성요소를 일반 사용자가 쓸 수 있는 하나의 제품으로 만든 Muse입니다.


1. Meta Muse, 개인 에이전트를 하나의 완성된 제품으로 묶다

PROOF LEVEL 03 · 공식 확인

사실 요약

Meta는 2026년 9월 8일 개인 AI 에이전트 Muse를 발표했습니다. Muse는 단순히 질문에 답하는 것을 넘어 사용자를 대신해 작업을 수행하는 것을 목표로 합니다. 앱이 닫힌 뒤에도 장기 작업을 이어가고, 브라우저를 열어 웹서비스를 사용하며, 여러 앱과 연결해 사용자의 목표를 실제 행동으로 옮깁니다.

실행 기반은 전용 클라우드 컴퓨터인 Muse Secure VM입니다. Meta는 사용자별 실행 환경에서 데이터와 연결 자격 증명을 관리하고, 사용자가 어느 수준까지 접근 권한을 부여할지 결정할 수 있도록 설계했다고 설명합니다.

이메일 발송이나 구매처럼 되돌리기 어렵거나 민감한 행동에는 사람의 승인을 요청하는 구조가 들어가 있으며, 사용자는 연결 앱과 권한 범위를 관리하고 작업 기록을 확인할 수 있습니다. 결제에는 Stripe Link의 일회용 카드와 구매 보호가 연결됩니다.

현재 미국을 중심으로 iOS·Android·웹에서 출시되고 있으며 AI 안경 지원도 예고됐습니다. 다만 개인정보 보호와 보안에 관한 설명은 현재 Meta가 공개한 제품 설계에 따른 것이며, 독립적인 보안 검증 결과와 동일하게 볼 수는 없습니다.

출시 이후 드러난 것

Muse가 흥미로운 이유는 발표 문서에 적힌 구조만이 아닙니다. 출시 직후부터 그 구조가 실제 서비스 환경에서 시험받고 있습니다.

Amazon은 Muse가 자사 쇼핑 서비스에 접근하는 것을 차단했습니다. Amazon은 Muse가 에이전트임을 명확하게 식별하지 않은 상태로 서비스를 이용한다는 점과 개인정보·보안 문제 등을 이유로 들었습니다. 이 사건은 사용자의 허가를 받은 에이전트라 해도 외부 서비스 사업자가 그 접근을 허용해야 하는지는 별개의 문제라는 점을 보여줍니다.

앞으로 에이전트는 사용자와 서비스 사이의 새로운 행위 주체가 될 수 있습니다. 서비스 사업자 역시 사람과 자동화된 에이전트를 어떻게 구분하고, 어떤 권한을 허용할지 결정해야 합니다.

사용자 데이터 접근 방식에 대한 혼란도 있었습니다. Muse가 사용자가 예상하지 못했던 메시지 내용을 참조했다는 사례가 알려졌고, Meta의 David Singleton은 사용자가 시스템 권한을 허용한 상태에서 데이터에 접근한 것이지만 Muse가 자신이 어떻게 해당 정보를 얻었는지를 잘못 설명했다고 밝혔습니다.

여기서 중요한 문제는 단순히 “권한을 받았는가”만이 아닙니다. 사용자는 에이전트가 지금 어떤 데이터를 보고 있는지, 왜 볼 수 있는지, 그 정보를 어디에 사용했는지 이해할 수 있어야 합니다. 실제 권한 구조가 올바르게 설계돼 있더라도 에이전트가 자신의 행동을 잘못 설명한다면 사용자는 시스템을 신뢰하기 어렵습니다.

보안 문제도 현실화됐습니다. macOS용 Muse에서는 로컬 머신에 이미 악성 코드가 존재하는 경우 에이전트의 동작을 가로챌 수 있는 취약점이 발견됐고, Meta는 이를 패치했습니다. 공격을 위해 사전에 로컬 시스템이 침해돼 있어야 한다는 제한은 있었지만, 에이전트가 카메라·파일·브라우저처럼 실제 시스템 권한과 연결될수록 실행 환경 자체가 새로운 공격면이 된다는 점을 보여줍니다.

이 사례들은 Muse의 보안 구조가 실패했다는 결론도, 반대로 충분히 안전하다는 증거도 아닙니다. 오히려 개인 에이전트가 실제 사람의 계정과 데이터를 다루기 시작하면서 지금까지 설계 문서 속 문제였던 권한, 승인, 정책 충돌, 감사 기록, 실행 환경 보안이 실제 제품 문제로 바뀌고 있다는 신호에 가깝습니다.

개발자에게 중요한 점

Muse가 보여준 것은 단순한 브라우저 자동화가 아닙니다. 장기 실행, 영속 메모리, 비밀정보 격리, 정책 검사, 세분화된 권한, 중요 행동 전 승인, 감사 기록, 결제 보호를 하나의 사용자 경험으로 연결했습니다.

개인 에이전트를 만드는 팀이라면 이제 “우리 모델이 무엇을 할 수 있는가”만 비교해서는 부족합니다. 사용자가 앱을 닫은 뒤에도 작업을 이어가는 방식, 외부 서비스에 부여한 권한을 제한하는 방식, 되돌리기 어려운 행동을 실행하기 전에 사용자를 다시 호출하는 방식까지 제품의 일부가 됩니다.

여기에 에이전트가 무엇을 보고 무엇을 실행했는지 기록하는 방식, 문제가 발생했을 때 어느 상태까지 되돌릴 수 있는지까지 포함하면 에이전트 제품의 경쟁력은 모델 바깥에서 크게 갈리기 시작합니다.

Lee's Take

이번 발표에서 가장 큰 게임 체인저는 Muse의 모델 성능이 아닙니다. Meta가 에이전트를 채팅창 안의 기능이 아니라 개인용 운영체제에 가까운 제품으로 정의했다는 점입니다.

특히 실행하는 주체와 정책을 검사하는 주체를 분리하고, 돈이나 메시지가 실제로 움직이는 지점에 사람의 승인선을 넣은 구조가 중요합니다. 출시 이후 Amazon과의 정책 충돌, 데이터 접근 설명 문제, 로컬 보안 취약점이 등장한 것도 오히려 이런 구조가 왜 필요한지를 보여줍니다.

이제 개인 에이전트의 경쟁은 “누가 더 똑똑한 모델을 가졌는가”만으로 결정되지 않습니다. 누가 더 안전하게 권한을 주고, 행동을 설명하고, 실제 서비스를 건드리면서도 통제 가능한 시스템을 만드느냐가 새로운 경쟁 영역이 되고 있습니다.

Meta의 막대한 사용자 접점까지 고려하면 성공 여부와 별개로 개인 에이전트 시장의 제품 기준을 크게 끌어올린 발표라고 봅니다.

이번 주 해볼 일

  • 에이전트가 수행하는 행동을 자동 허용, 실행 전 승인, 절대 금지로 분류합니다.
  • 실행 주체와 정책 검사 주체를 분리할 수 있는지 아키텍처를 검토합니다.
  • 장기 작업에 작업 이력, 권한 사용 기록, 외부 변경 결과를 남깁니다.
  • 에이전트가 현재 어떤 권한과 데이터를 사용하고 있는지 사용자에게 설명할 수 있는지 점검합니다.
  • 비밀번호나 결제정보를 모델 컨텍스트에 직접 노출하지 않는 경로를 설계합니다.
  • 외부 서비스가 에이전트 접근을 거부했을 때 이를 실패로 처리할지, 사람에게 다시 넘길지 결정합니다.

원문: Meta — Introducing Muse: The World’s First Personal AI Agent Built for Everyone


2. GPT-6 Sol과 Luna, 하나의 최고 모델보다 작업별 라우팅을 택하다

PROOF LEVEL 03 · 공식 확인

사실 요약

OpenAI는 2026년 9월 22일 GPT-6 Sol과 GPT-6 Luna를 API에 출시했습니다. 두 모델은 텍스트와 이미지를 입력받으며 Responses API와 Chat Completions API에서 사용할 수 있습니다.

272K 토큰 이하 입력의 표준 가격은 100만 토큰당 다음과 같습니다.

  • GPT-6 Sol: 입력 2달러, 캐시 입력 0.20달러, 출력 10달러
  • GPT-6 Luna: 입력 0.10달러, 캐시 입력 0.01달러, 출력 0.50달러

동일한 GPT-6 계열 안에서도 표준 입력·출력 가격 차이는 각각 20배입니다.

개발자에게 중요한 점

이 가격 구조에서는 모든 요청을 가장 강한 모델에 보내는 설계가 빠르게 비경제적이 됩니다. 요청을 분류하고, 저비용 모델이 처리할 수 있는 작업을 분리하며, 실패하거나 불확실할 때만 상위 모델로 올리는 라우팅이 기본 설계가 됩니다.

에이전트 하나를 구성하더라도 모든 단계에 같은 모델을 사용할 이유는 없습니다. 단순 분류나 반복 처리는 저렴한 모델이 맡고, 복잡한 의사결정이나 계획 수정에는 더 강한 모델을 호출할 수 있습니다. 정책 검사 역시 실행 모델과 별도의 경량 모델이나 규칙 시스템으로 분리할 수 있습니다.

결국 모델 평가는 단일 벤치마크 점수보다 실제 업무 완료율, 재시도 횟수, 도구 호출 비용, 사람 검토 시간을 합친 성공한 작업 1건당 총비용으로 이동할 가능성이 큽니다.

Lee's Take

GPT-6의 핵심은 새 이름보다 20배의 가격 간격이라고 봅니다. “어떤 모델을 쓸 것인가”보다 “어떤 순간에 비싼 판단을 호출할 것인가”가 중요해졌습니다.

Muse 같은 개인 에이전트 역시 모든 행동에 최고급 추론을 사용한다면 대규모 서비스가 되기 어렵습니다. 빠른 실행 모델, 고난도 판단 모델, 정책 검사 모델을 역할별로 구성하고 필요한 순간에만 높은 비용을 지불하는 쪽이 현실적인 구조입니다.

모델 선택도 이제 프롬프트 엔지니어링보다 시스템 설계에 가까워지고 있습니다.

이번 주 해볼 일

  • 최근 요청을 단순 처리, 도구 실행, 고난도 판단 세 등급으로 나눕니다.
  • Luna 우선 실행 후 품질 신호에 따라 Sol로 승격하는 작은 평가를 만듭니다.
  • 모델별 성공률뿐 아니라 재시도와 사람 검토까지 포함한 비용을 기록합니다.
  • 토큰 가격이 아니라 성공한 작업 1건당 총비용을 측정합니다.

원문: OpenAI — API Changelog, September 22


3. Vercel Sandbox Drives, 일회성 실행에 영속 상태를 붙이다

PROOF LEVEL 03 · 공식 확인

사실 요약

Vercel은 2026년 9월 22일 Sandbox Drives를 공개 베타로 출시했습니다. Drive는 특정 샌드박스에 종속되지 않는 영속 저장소입니다. 샌드박스가 종료돼도 Drive에 저장한 데이터는 남아 있으며, 이후 새로운 샌드박스에서 같은 Drive를 다시 마운트할 수 있습니다.

이를 통해 여러 실행에 걸쳐 같은 작업공간, 온디스크 메모리, 데이터셋, 모델, 의존성 트리를 재사용할 수 있습니다. 하나의 Drive에는 동시에 하나의 읽기·쓰기 마운트만 허용되며, 한 번 기록된 Drive는 특정 시점의 읽기 전용 스냅샷 형태로 여러 샌드박스에 병렬 마운트할 수 있습니다.

기본 최대 용량은 Pro와 Enterprise 기준 1TiB이며 최대 16TiB까지 구성할 수 있습니다. Hobby는 기본 제한이 더 작습니다.

개발자에게 중요한 점

에이전트에게 샌드박스를 매번 새로 제공하면 안전한 격리는 얻지만 비용이 생깁니다. 저장소를 다시 체크아웃하고, 의존성을 다시 설치하고, 인덱스를 생성하고, 직전 실행의 중간 결과를 복구해야 합니다.

영속 Drive는 격리된 실행 환경과 지속되는 작업 상태를 분리할 수 있게 합니다. 오늘 실행된 에이전트의 샌드박스는 사라져도 작업공간은 남겨두고, 내일 새로운 샌드박스에서 이어갈 수 있습니다. 장시간 코딩 에이전트나 연구 에이전트에게 특히 의미가 큽니다.

하지만 상태가 남는 순간 반대쪽 문제도 생깁니다. 오래된 의존성, 오염된 작업공간, 에이전트가 잘못 기록한 메모리와 중간 결과도 함께 남습니다. 영속 상태는 작업을 빠르게 이어가게 하지만 실수 역시 오래 보존하기 때문에 스냅샷 버전, 신뢰 가능한 상태의 기준, 초기화와 폐기 정책이 함께 필요합니다.

Lee's Take

지난 호가 장기 실행 에이전트의 등장에 관한 이야기였다면, 이번 발표는 그 에이전트가 어디에 작업대를 남겨둘 것인가에 관한 답에 가깝습니다.

모델이 기억하는 컨텍스트와 실제 작업 상태는 같은 것이 아닙니다. 코드베이스, 생성한 파일, 설치한 의존성, 인덱스, 중간 결과처럼 수십 GB까지 커질 수 있는 상태를 모델 컨텍스트에 넣을 수는 없습니다. 결국 오래 일하는 에이전트에는 모델 바깥의 지속 가능한 작업 공간이 필요합니다.

하지만 영속 저장소는 에이전트를 강하게 만드는 만큼 실수도 오래 보존합니다. “기억한다”는 기능보다 어떤 상태를 신뢰하고 언제 버릴 것인가를 결정하는 운영 규칙이 먼저입니다.

이번 주 해볼 일

  • 재사용할 상태와 실행마다 새로 만들어야 할 상태를 구분합니다.
  • 에이전트 작업 시작 시 사용할 Drive 스냅샷 ID와 코드 리비전을 기록합니다.
  • 민감정보가 Drive에 평문으로 남지 않는지 점검합니다.
  • 실패한 실행의 상태를 다음 작업이 자동 상속하지 않도록 폐기 기준을 만듭니다.
  • 장기 작업에서 모델 메모리와 실제 작업공간 상태를 별도로 관리합니다.

원문: Vercel — Drives for Vercel Sandbox are now in public beta


이번 호의 결론

Meta Muse는 개인 에이전트 경쟁의 기준을 모델 성능에서 제품 구조로 옮기려는 시도입니다. 전용 실행 환경, 장기 상태, 권한 제어, 사람의 승인, 감사 기록, 결제를 하나의 흐름으로 연결했기 때문입니다.

그리고 출시 이후 벌어진 일들은 이 구조가 단순한 기능 목록이 아니라는 것을 보여주고 있습니다. 에이전트가 실제 웹서비스를 사용하면 외부 사업자의 정책과 충돌할 수 있고, 사용자 데이터를 읽으면 단순한 접근 권한을 넘어 “왜 이 정보를 알고 있는가”를 설명해야 합니다. 컴퓨터와 직접 연결되면 모델뿐 아니라 실행 환경 자체가 새로운 보안 경계가 됩니다.

OpenAI의 GPT-6 Sol과 Luna는 그 안에서 어떤 판단에 얼마의 비용을 쓸 것인가라는 문제를 보여줍니다. Vercel Sandbox Drives는 에이전트가 여러 실행에 걸쳐 어디에 작업 상태를 남길 것인가라는 문제에 답합니다.

세 발표를 연결하면 한 가지 방향이 보입니다. 앞으로 강한 에이전트는 가장 좋은 모델 하나를 붙여 만든 제품이 아닐 가능성이 큽니다. 적절한 비용의 모델을 골라 쓰고, 안전한 실행 환경에서 행동하고, 필요한 상태는 오래 보존하되, 중요한 행동에서는 사람에게 다시 결정권을 돌려주고, 무엇을 했는지 나중에 확인할 수 있어야 합니다.

모델은 점점 교체 가능한 구성요소가 되고 있습니다.

그 모델을 어디에서 실행하고, 무엇을 기억하게 하고, 어디까지 행동하게 하며, 언제 사람에게 멈춰 서게 할 것인가. 게임 체인저는 점점 그 구조 쪽으로 이동하고 있습니다.


그런데 왜 Claude Opus 5.5는 이번 호에서 다루지 않았을까?

Anthropic도 9월 22일 Claude Opus 5.5를 발표했습니다. Anthropic에 따르면 Opus 5.5는 Opus 5보다 성능을 높이면서 실행 비용을 40% 낮췄고, 대부분의 작업에서 Claude Fable 5.1 수준의 성능을 제공하는 것을 목표로 합니다. 충분히 이번 주 주요 뉴스로 다룰 만한 발표입니다.

그럼에도 이번 호에서는 의도적으로 제외했습니다. 이번 호에서 GPT-6 Sol과 Luna를 다룬 이유도 단순히 “새 모델이 나왔기 때문”이 아닙니다. 20배의 가격 차이를 같은 모델 계열 안에 배치하면서 에이전트가 작업에 따라 서로 다른 비용의 모델을 라우팅하는 구조를 이야기하기에 적합했기 때문입니다.

Opus 5.5의 비용 효율 개선 역시 중요한 흐름이지만 함께 넣으면 이번 호가 다시 여러 최신 모델의 성능과 가격을 비교하는 이야기로 확장될 가능성이 있었습니다. 이번 호에서 보고 싶었던 것은 모델 경쟁 자체보다 그 모델들이 들어갈 개인 에이전트의 전체 시스템입니다.

그래서 Opus 5.5는 중요하지 않아서 제외한 것이 아니라, 이번 호의 질문을 하나로 유지하기 위해 다음 이야기로 남겼습니다.

에이전트가 오래 일할수록, 사람의 승인선이 제품이 된다

이번 주의 공통점은 ‘더 강한 모델’보다 더 오래, 더 조직적으로 일하는 에이전트입니다.

OpenAI와 Cursor는 장시간 실행과 다중 에이전트 협업을 제품의 중심으로 끌어올렸고, GitHub도 코드 리뷰를 단순한 코멘트 생성에서 검증과 재검토가 이어지는 흐름으로 확장하고 있습니다.

에이전트가 한 번의 질문에 답하는 도구를 넘어 실제 업무를 계속 수행하기 시작하면 개발자가 설계해야 할 것도 달라집니다.

중요한 것은 프롬프트만이 아닙니다.

무엇을 할 수 있는가.

어디까지 스스로 진행할 수 있는가.

언제 사람에게 돌아와야 하는가.

실패하면 어디서 멈추는가.

그리고 이번 주 직접 Jev를 사용해보며 한 가지를 더 확인했습니다.

모든 자동화를 장기 실행 에이전트나 범용 LLM으로 만들 필요도 없습니다.

 

1. OpenAI Agents API 공개 베타

PROOF LEVEL 03 · 공식 확인

OpenAI는 9월 10일 Codex를 구동하는 관리형 에이전트 하네스를 개발자가 사용할 수 있도록 Agents API를 공개 베타로 발표했습니다.

긴 세션과 컨텍스트 관리, 도구 실행, 서브에이전트 조율, 파일과 코드를 다루는 실행 환경 등을 OpenAI가 관리합니다.

개발자에게 중요한 점

에이전트 실행기를 직접 조립해야 하는 비용은 줄어듭니다.

반대로 에이전트가 더 오래, 더 많은 일을 할 수 있게 될수록 어떤 행동을 허용하고 어디에서 사람에게 승인을 받을 것인지가 중요해집니다.

Lee's Take

에이전트 제품의 차이는 점점

“무엇을 자동화할 수 있는가?” 보다

“어디까지 자동화하고, 어디에서 사람이 책임지는가?”

에서 생길 것 같습니다.

L-Proof-AI 역시 자료 수집과 초안 생성까지는 AI가 진행하더라도 최종 발송은 사람이 승인해야 한다는 선을 제품 규칙으로 두는 편이 맞다고 봅니다.

이번 주 해볼 일

긴 작업 하나를 골라 자동 실행 구간 / 사람 승인 구간으로 나눠보기

외부 쓰기, 결제, 고객 발송처럼 되돌리기 어려운 행동은 별도 승인 단계로 분리하기

실패했을 때 재시도할지, 중단할지, 사람에게 돌려보낼지 미리 정하기

원문: https://openai.com/index/introducing-the-agents-api/

 

2. GitHub Copilot 코드 리뷰가 ‘댓글’에서 ‘검증 루프’로 이동

PROOF LEVEL 03 · 공식 확인

GitHub는 9월 11일 Copilot code review의 업데이트를 발표했습니다.

새로운 커밋이 기존 리뷰 의견을 해결했는지 다시 확인해 처리된 코멘트를 자동으로 정리하고, Copilot의 수정 제안을 적용할 때 변경 내용에 맞는 커밋 메시지를 생성합니다.

리뷰 과정에서 사용할 수 있는 셸 도구도 확대됐습니다. 빌드, 테스트, 스크립트 실행 등을 이용해 리뷰 결과를 검증할 수 있으며 Lite 리뷰에는 여러 에이전트의 분석을 합치는 방식도 적용됐습니다.

개발자에게 중요한 점

AI 리뷰의 병목이 단순히

“버그를 몇 개 찾아냈는가”

에서

“그 지적이 실제 수정으로 이어졌고, 수정됐다는 것을 다시 검증할 수 있는가”

로 이동하고 있습니다.

Lee's Take

AI 리뷰의 성공 지표를 ‘코멘트 수’로 잡으면 오히려 소음이 늘어날 수 있습니다.

제가 보고 싶은 것은 이런 숫자입니다.

AI가 지적한 문제 중 실제 반영된 비율

같은 문제가 다시 발생한 비율

AI 수정 이후 사람이 다시 수정한 비율

수정 후 테스트에서 실제로 문제가 해결됐는지

AI가 리뷰어 역할까지 가져간다면 발견보다 검증 루프가 중요합니다.

이번 주 해볼 일

AI 리뷰 코멘트 가운데 실제 반영된 비율을 기록해보기

자동 수정 후 diff와 테스트 결과를 함께 확인할 수 있는 흐름 만들기

원문: https://github.blog/changelog/2026-09-11-auto-resolution-and-analysis-updates-in-copilot-code-review/

 

3. Cursor Projects: 에이전트의 단위가 ‘채팅’에서 ‘프로젝트’로

PROOF LEVEL 03 · 공식 확인

Cursor는 9월 10일 Projects를 발표했습니다.

Projects는 기능 개발이나 마이그레이션처럼 오래 걸리는 작업의 컨텍스트를 유지하고, 코디네이터 에이전트가 작업을 여러 서브에이전트에게 나눠 맡길 수 있게 합니다.

프로젝트는 클라우드 환경에서 계속 실행될 수 있으며, 일정이나 Slack, PR 같은 신호에 따라 반복 작업을 수행하는 구조도 제공합니다.

개발자에게 중요한 점

에이전트의 단위가

한 번의 채팅 → 계속 운영되는 프로젝트

로 변하고 있습니다.

그 순간부터 AI가 기억하는 정보와 현재 작업 상태도 일종의 애플리케이션 상태가 됩니다.

누가 무엇을 맡았는지, 어떤 결과를 신뢰할 수 있는지, 실패했을 때 다음 작업을 계속할 것인지 같은 것을 코드와 비슷한 수준으로 관리해야 합니다.

Lee's Take

장기 에이전트가 가치 있는 이유를 단순히

“기억을 오래 한다”

라고 생각하지 않습니다.

오히려 중요한 것은 사람이 며칠 뒤 다시 들어왔을 때

왜 지금 이런 상태가 되었는지 설명할 수 있는가

입니다.

긴 기억보다 추적 가능한 상태가 더 중요할 수 있습니다.

이번 주 해볼 일

반복 업무 하나를 골라 다음 네 가지를 문서화해보기.

입력

결과물

승인자

실패 시 동작

그리고 승인되지 않은 결과는 다음 단계로 넘어가지 않는 것을 기본값으로 두기.

원문: https://cursor.com/changelog

 

4. 직접 써본 Jev: 모든 판단에 LLM이 필요한 것은 아니었다

PROOF LEVEL 03 · 공식 확인 + 직접 테스트

TypeSafe AI는 9월 15일 첫 번째 System One Model인 Jev를 공개했습니다.

일반적인 LLM처럼 자유로운 문장을 생성하는 대신, 프로그램이 미리 정의한 선택지에 대해 typed decision과 확률·confidence를 반환하는 모델입니다.

처음에는 저도 “이걸 굳이 LLM 대신 왜 사용하지?”라는 생각이 있었습니다.

직접 작은 프로젝트에 적용해보니 답은 꽤 명확했습니다.

Fit한 상황에서는 굉장히 강하다

제가 테스트한 HowMuchCaloriesLeft라는 칼로리 기록 프로젝트를 예로 들겠습니다.

사용자가 이렇게 말할 수 있습니다.

“아까 밥은 반 정도 남겼어.”

애플리케이션이 알아야 하는 것은 멋진 답변이 아닙니다.

먼저 이 입력이

새로운 음식 추가인지

기존 기록 수정인지

기록 삭제인지

단순 질문인지

판단해야 합니다.

그리고 기존 기록 수정이라면 어떤 기록을 수정해야 하는지, 확신이 낮다면 사용자에게 다시 물어볼지도 결정해야 합니다.

이런 분류·라우팅·점수화·분기에서는 Jev의 구조가 상당히 잘 맞았습니다.

결과가 자연어가 아니라 처음부터 프로그램이 사용할 수 있는 선택지와 확률로 돌아오기 때문입니다.

그런데 Fit하지 않은 곳까지 쓰면 오히려 불편하다

반대로 이런 작업은 일반 LLM이 훨씬 자연스러웠습니다.

음식 이름과 양을 자연어에서 해석하기

사용자의 애매한 표현을 이해하기

자유로운 대화 생성하기

후보를 새로 만들어내기

음식 정보를 바탕으로 칼로리를 추정하기

Jev는 범용 LLM의 작은 버전도, Codex나 Claude Code 같은 개발 에이전트도 아니었습니다.

정해진 선택지가 존재하고 프로그램이 그 판단을 바로 사용해야 하는 구간에서 잘 맞는 별도의 도구에 가까웠습니다.

Lee's Take

이번 테스트에서 가장 흥미로웠던 점은

AI가 더 강해졌다고 모든 문제를 하나의 강한 LLM에게 맡기는 것이 최선은 아니라는 것

이었습니다.

문장을 만들어야 하는 곳에는 LLM을 쓰고,

복잡한 일을 오래 수행해야 하는 곳에는 에이전트를 쓰고,

정해진 상태 안에서 빠르게 판단해야 하는 곳에는 Jev 같은 decision model을 쓸 수 있습니다.

결국 중요한 것은 어떤 모델이 가장 강한지가 아니라

“이 판단에는 어느 정도의 자유가 필요한가?”

인 것 같습니다.

자유도가 높아질수록 할 수 있는 일은 많아집니다.

동시에 검증해야 할 것도 늘어납니다.

이번 주 해볼 일

현재 LLM으로 처리하고 있는 작업 하나를 골라 질문해보기.

“여기서 정말 문장을 생성해야 하는가?”

결과가 결국 A/B/C, true/false, 점수, 라우팅처럼 몇 개의 선택지로 귀결된다면 범용 LLM 호출이 과한 구조일 수도 있습니다.

반대로 새로운 후보를 만들거나 맥락을 깊게 해석해야 한다면 억지로 판단 모델에 넣지 말고 LLM에게 맡기는 편이 낫습니다.

이번 호의 결론

이번 주 발표들을 보면 AI 개발은 점점 모델을 호출하는 것에서 AI가 실제 업무를 수행하도록 만드는 것으로 이동하고 있습니다.

그런데 자동화가 커질수록 사람이 사라지는 것은 아닙니다.

오히려 사람이 개입해야 할 지점을 더 명확하게 설계해야 합니다.

그리고 Jev를 직접 써보면서 여기에 하나를 더 추가하고 싶어졌습니다.

모든 AI에게 최대한 많은 자유를 줄 필요도 없습니다.

생성해야 할 때는 생성하게 하고,

판단해야 할 때는 판단하게 하고,

사람이 책임져야 할 순간에는 멈추게 하는 것.

결국 AI 제품의 설계는 점점

모델 선택보다 권한 설계에 가까워지고 있습니다.


L-Proof-AI · 문의: this_is_laugh@naver.com

 문제 상황


최근 React의 새로운 기능인 `useEffectEvent`를 알게 되었고, 실제 서비스에 적용해보려고 했다.

공식 문서 기준으로 보면:

* React 19.2 이상 → 안정적으로 사용 가능
* React 19.0 ~ 19.1 → 실험적 (동작할 수도, 안 할 수도 있음)
* 그 이하 → 미지원

우리 프로젝트는 **React 19.2.3**을 사용 중이었기 때문에
자연스럽게 “문제없이 사용할 수 있겠지”라고 생각했다.

 이번 테스트 환경

이번에 확인한 환경은 다음과 같았다.

* next: 15.5.9
* react: 19.2.3
* react-dom: 19.2.3
* 실행: `next dev --turbopack`

👉 즉, package 레벨만 보면 `useEffectEvent`를 써도 이상하지 않은 조합이었다.


 왜 useEffectEvent를 도입하려고 했는가

내가 이 기능에 관심을 가지게 된 이유는 `/consult` 페이지의 채팅 구조 때문이었다.

이 페이지에서는:

* 담당자 ↔ 고객 간 채팅
* 브라우저 알림
* sidebar / menu에 unread 표시 (green dot)

같은 기능이 동시에 동작한다.

그래서 채팅 로직을 페이지 단이 아니라 **Layout 레벨로 끌어올려 `ChatProvider`로 구성**했고:

* 채팅방 접속 상태
* 구독 변경
* 딥링크 진입

등은 `/consult` 페이지에서 제어하도록 설계했다.

 

 문제의 본질


문제는 여기서 시작됐다.

이 서비스는:

* 사용자 권한에 따라 UI가 달라지고
* 전역 Provider가 많고
* 상태 흐름이 꽤 복잡하다

그래서 현재는:

* “처음 진입 여부”
* “로딩 상태”

같은 내부 변수를 두고
👉 **소켓 연결 타이밍을 제어하는 구조**를 쓰고 있었다.

 

 기존 코드의 한계

기존 구조에서는 이런 문제가 있었다:

* pathname 변경 → 소켓 effect 재실행
* 알림 설정 변경 → 재연결 발생 가능
* stale closure 방지를 위해 ref 동기화 필요
* (`showBannerRef`, `activeIdRef` 등)

👉 결과적으로 코드가 점점 복잡해지고 있었다

 그래서 useEffectEvent를 도입하려고 했다


의도는 명확했다:

> “연결의 생명주기(effect deps)와
> 최신 상태 읽기(callback)를 분리하자”

즉:

* 소켓 연결은 최소한의 deps로 유지하고
* 이벤트 핸들러는 최신 state를 읽게 하자

 그런데


바로 터진 에러

useEffectEvent is not a function



런타임에서 바로 터졌다.

“React 버전은 맞는데 왜 안 되지?”

처음에는 단순히 의아했다.

그래서 확인을 해봤다:

npm list react react-dom

→ 둘 다 19.2.3

 

node -e "require('react').useEffectEvent"

→ function

여기까지는 정상


---

 그런데 진짜 문제는

Next.js 환경에서 실제 클라이언트 런타임은
단순히 `react` 패키지를 쓰지 않는다.

👉 내부적으로:

next/dist/compiled/react


를 사용한다.

그리고 여기서 확인해보면:

node -e "require('next/dist/compiled/react').useEffectEvent"


👉 결과: `undefined`


 핵심 원인



👉 **내가 설치한 React와
실제 런타임에서 사용되는 React가 다르다**

즉:

> “package.json에서 React 버전이 맞다”
> = “해당 API를 런타임에서 쓸 수 있다”

가 아니었다.

그래서 내린 결론은

이 상태에서 계속 진행하면:

👉 기능 도입이 아니라 장애 생성

그래서:

-  useEffectEvent 적용 시도 → 전부 revert
-  기존 패턴 유지 (ref 동기화 + effect 분리)

로 방향을 잡았다.


 같은 문제를 만났을 때 체크리스트


혹시 나와 같은 에러를 만났다면 아래를 먼저 확인해보자.

# 1. 설치 버전 확인
npm list react react-dom

# 2. 앱 기준 React export 확인
node -e "console.log(require('react').version, typeof require('react').useEffectEvent)"

# 3. Next 런타임 React export 확인
node -e "console.log(require('next/dist/compiled/react').version, typeof require('next/dist/compiled/react').useEffectEvent)"



👉 이 결과가 다르다면
package.json만 보고 기능 도입을 판단하면 안 된다.

 이번에 배운 것


1. 문서만 믿으면 안 된다

버전 조건만 보고 도입하면 안 된다.
👉 실제 런타임 export를 확인해야 한다



2. Next.js 환경은 다르게 동작한다

Next는 내부적으로 compiled dependency를 사용한다.

👉 내가 설치한 패키지 ≠ 실제 실행 패키지



3. 기능 도입보다 중요한 것

👉 되돌릴 수 있는 단위로 실험해야 한다

이번 케이스도:

* 작은 범위에서 시도했기 때문에
* 빠르게 원복 가능했다

4. ai 끼리 업무를 보게 했을 때 인간이 필요한 이유

👉 명세서끼리 읽게 시켰을 때 서로 오류가 없어서 진행하게 했지만 실제로 그것을 확인하고 검증하는 내 역할이 없었다면 잘못된 파일이 서버에 올라갈 뻔했다. 작은 단위로 계속 모니터링 하는 습관이 사고를 예방했다.



 오해 방지를 위해



여기서 중요한 건
👉 “Next.js에서는 useEffectEvent를 못 쓴다”가 아니다

정확히는:

> 내가 테스트한 버전 조합 / 런타임에서는 사용할 수 없었다

즉, 기능 자체의 문제가 아니라
👉 런타임과 패키지 간의 불일치 문제에 가깝다.


 마치며



`useEffectEvent`는 분명 좋은 기능이다.

특히:

* socket
* polling
* subscription

같은 케이스에서는 코드 복잡도를 크게 줄일 수 있다.

+ Recent posts