Featured Post

LLM에 코드 통째로 던지기 전에, Serena로 토큰 아끼며 개발하는 방법

Serena - 시맨틱 코드검색 관련 이미지

요즘 퇴근하고 집에 와서 커피 한 잔 내려놓고 사이드 프로젝트를 만지다 보면요. 예전처럼 IDE만 붙잡고 있는 게 아니라, 어느 순간 브라우저를 열고 LLM한테 코드를 붙여넣고 있더라고요. 참 세상 많이 바뀌었죠. 특히 AI 바이브 코딩이라는 말이 여기저기서 들리기 시작하면서, 개발자라면 한 번쯤 이런 고민을 해봤을 거예요. “이 코드 전체를 그냥 LLM한테 던져도 되나?” 저도 똑같이 그랬습니다. 급할 땐 일단 붙여넣고 보거든요. 그런데 그렇게 하다 보니 금방 느껴지더라고요. 아, 이건 편하긴 한데 토큰이 너무 아깝다.

그러다 알게 된 게 Serena라는 시맨틱 코드 검색 도구였어요. 처음엔 반신반의했습니다. 코드 검색이야 IDE에도 있고, grep도 있고, ripgrep도 있는데 뭐가 그렇게 다를까 싶었거든요. 그런데 막상 써보니까 느낌이 조금 달랐어요. 단순히 문자열을 찾는 게 아니라, “내가 지금 찾고 싶은 코드의 의미”에 가까운 것들을 골라주는 쪽에 가깝더라고요. 덕분에 LLM에게 넘기는 코드 양이 확 줄었고, 쓸데없는 맥락이 끼어드는 일도 줄었습니다. 오늘은 제가 직접 부딪히면서 정리한 토큰 절약 방법, Serena 설정 노하우, 그리고 AI 바이브 코딩을 조금 더 실용적으로 하는 방법을 편하게 풀어보려고 합니다.

Serena를 쓰기 전, 저는 코드를 너무 많이 던지고 있었습니다

솔직히 고백하자면, 처음 LLM으로 개발할 때는 좀 무식하게 썼습니다. 에러가 나면 관련 있을 것 같은 파일을 통째로 복사해서 붙여넣고, 그래도 답이 애매하면 주변 파일까지 추가로 넣었어요. 그러다 보면 어느 순간 프롬프트가 거의 작은 소설책처럼 길어집니다. LLM은 친절하게 답을 해주긴 하는데, 정작 핵심을 놓치거나 엉뚱한 파일을 보고 조언하는 경우도 많았고요.

한 번은 인증 로직에서 문제가 생겨서 auth, user, middleware 관련 파일을 거의 다 넣은 적이 있어요. 그때 LLM이 꽤 그럴듯한 답을 주긴 했는데, 알고 보니 제가 쓰지도 않는 예전 레거시 함수 기준으로 설명을 하고 있더라고요. 순간 좀 허탈했습니다. 내가 열심히 토큰을 써가며 넣은 코드가 오히려 답변 품질을 망치고 있었던 거죠.

그때부터 생각을 바꿨습니다. LLM에게 많이 주는 게 좋은 게 아니라, 필요한 코드만 정확하게 주는 게 훨씬 중요하다는 쪽으로요. 이게 말은 쉬운데, 실제 프로젝트에서는 쉽지 않습니다. 파일도 많고, 함수 이름도 비슷비슷하고, 예전 코드와 새 코드가 섞여 있거든요. Serena가 제 역할을 해준 지점이 바로 여기였습니다.

저장소 전체를 인덱싱하면 편할 줄 알았는데, 오히려 시끄러웠습니다

Serena를 처음 설치하고 나서 제일 먼저 한 일은 저장소 전체를 인덱싱하는 거였어요. 왠지 그래야 제대로 쓸 수 있을 것 같잖아요. 프로젝트 전체를 다 알고 있어야 똑똑하게 대답해줄 것 같고요. 그런데 하루 정도 써보고 바로 생각이 바뀌었습니다. 검색 결과에 예전 코드가 너무 많이 섞였어요.

특히 오래된 프로젝트일수록 이런 문제가 심합니다. 지금은 안 쓰는 유틸 함수, 예전에 만들었다가 버린 서비스 클래스, 마이그레이션하다 남은 중간 코드들이 검색 결과에 슬금슬금 끼어듭니다. 사람도 헷갈리는데 LLM이라고 안 헷갈릴 리가 없죠. 그래서 저는 인덱싱 전략을 바꿨습니다. 저장소 전체가 아니라 지금 작업 중인 브랜치와 필요한 파일만 대상으로 삼는 방식으로요.

예를 들어 main 브랜치 전체를 인덱싱하는 대신, 제가 작업 중인 feature/ai-chat 브랜치만 보게 했습니다. 거기에 확장자 필터까지 걸었어요. 지금 JavaScript 작업 중이면 .js, .ts 중심으로 보고, 설정 파일이나 빌드 산출물은 과감히 제외했습니다. 이렇게 하니까 검색 결과가 훨씬 조용해졌습니다. 뭐랄까, 시끄러운 회의실에서 나와 조용한 카페 구석자리에 앉은 느낌이랄까요.

제가 써본 방식 하루 평균 토큰 사용량 체감 검색 품질 느낀 점
저장소 전체 인덱싱 약 8,000 토큰 낮은 편 레거시 코드가 자꾸 끼어들어서 답변이 흐려졌습니다
현재 브랜치 중심 인덱싱 약 1,200 토큰 꽤 높음 지금 작업하는 코드 위주로 잡혀서 훨씬 편했습니다
확장자 필터까지 적용 약 900 토큰 가장 만족 설정 파일, 빌드 파일 노이즈가 줄어서 답이 선명해졌습니다

숫자만 보면 “오, 토큰이 줄었네” 정도로 보일 수 있는데요. 실제로는 그 이상입니다. 토큰을 아낀다는 건 단순히 비용을 줄인다는 뜻만은 아니더라고요. LLM이 엉뚱한 맥락을 참고할 가능성을 줄인다는 뜻이기도 합니다. 이게 은근히 큽니다. 개발하다 보면 틀린 답보다 더 무서운 게 그럴듯한데 틀린 답이잖아요.

프롬프트를 길게 쓰기보다, 검색 범위를 작게 만드는 게 낫더라고요

예전에는 프롬프트에 온갖 설명을 다 넣었습니다. “이 프로젝트는 이런 구조고, 이 함수는 이런 역할이고, 여기서 이런 문제가 나는데…” 하면서요. 물론 필요한 설명도 있지만, 매번 그렇게 쓰면 피곤합니다. 저도 퇴근 후에 개발하는 입장이라, 프롬프트 쓰다가 기운 빠지는 날이 있거든요.

Serena를 쓰면서 바꾼 방식은 단순합니다. LLM에게 긴 사연을 들려주기 전에, Serena가 가져오는 코드의 범위를 먼저 줄이는 것입니다. 예를 들어 findUser 함수와 관련된 부분만 보고 싶다면 그냥 넓게 “사용자 조회 코드 찾아줘”라고 하지 않고, 이런 식으로 범위를 좁힙니다.

"findUser" type:function

이렇게 하면 변수명이나 주석, 관련 없어 보이는 테스트 더미까지 마구 끌고 오는 일이 줄어듭니다. 특히 함수 단위로 문제를 볼 때는 이 방식이 꽤 잘 맞았습니다. 클래스 구조를 보고 싶을 땐 type:class, 테스트만 보고 싶을 땐 type:test처럼요. 별거 아닌데, 이 습관 하나가 토큰을 꽤 많이 아껴줍니다.

제가 자주 쓰는 식은 이런 느낌입니다.

  • 함수만 볼 때: type:function으로 범위를 줄입니다
  • 클래스 구조를 볼 때: type:class로 관련 클래스만 가져옵니다
  • 테스트 실패를 볼 때: type:test로 테스트 코드부터 확인합니다
  • 토큰을 줄이고 싶을 때: maxTokens 값을 작게 잡고 필요한 경우에만 늘립니다

저는 보통 maxTokens를 처음부터 크게 잡지 않습니다. 대충 256 정도로 시작해요. 물론 복잡한 리팩토링이나 아키텍처 검토를 할 때는 더 크게 잡아야 할 때도 있습니다. 그런데 버그 하나 찾는 상황에서는 처음부터 2,000 토큰씩 가져올 필요가 없더라고요. 작게 보고, 부족하면 조금씩 넓히는 방식이 훨씬 안정적이었습니다.

시맨틱 유사도는 너무 낮게 잡으면 친절한 척하면서 방해합니다

Serena를 쓰면서 은근히 중요했던 설정이 시맨틱 유사도 임계값이었습니다. 처음에는 혹시 놓치는 코드가 생길까 봐 0.5 정도로 낮게 잡았어요. 그런데 결과가 너무 많이 나왔습니다. “어, 이것도 관련 있을 수 있지 않나?” 싶은 것들이 줄줄이 나오는데, 막상 LLM에게 넘기면 맥락이 흐려지는 거죠.

그래서 저는 0.7 이상으로 올려서 써봤습니다. 이때부터 결과가 확실히 단정해졌어요. 물론 단점도 있습니다. 너무 엄격하게 잡으면 원하는 코드가 안 잡힐 때도 있어요. 그럴 땐 검색어를 조금 더 구체적으로 바꾸면 됩니다. 예를 들어 단순히 findUser만 넣지 말고, findUser by email처럼 의도를 살짝 붙여주는 식입니다.

유사도 설정 검색 결과 느낌 제가 느낀 장단점
0.5 전후 넓게 많이 가져옵니다 놓치는 건 적지만, 쓸데없는 코드도 같이 따라옵니다
0.7 전후 관련도 높은 코드 중심으로 잡힙니다 실무에서 가장 무난했습니다
0.8 이상 아주 좁게 가져옵니다 정밀하지만, 검색어가 애매하면 결과가 비어버릴 수 있습니다

이건 약간 여행 가방 싸는 거랑 비슷합니다. 혹시 몰라서 다 챙기면 마음은 편한데, 막상 이동할 때 너무 힘들잖아요. 필요한 것만 잘 챙기면 몸도 가볍고 판단도 빨라집니다. LLM에게 넘기는 코드도 똑같았습니다. 다 넣는다고 더 똑똑해지는 게 아니라, 오히려 꼭 필요한 것만 넣을 때 답이 좋아지는 경우가 많았어요.

.serenarc에 자주 쓰는 설정을 넣어두면 마음이 편합니다

제가 Serena를 쓰면서 가장 만족했던 부분은 프로젝트마다 설정을 고정해둘 수 있다는 점이었습니다. 특히 .serenarc 설정 파일을 프로젝트 루트에 만들어두면, 매번 같은 설정을 반복해서 입력하지 않아도 됩니다. 이런 작은 자동화가 나중엔 꽤 큰 차이를 만들어요.

저는 보통 node_modules, .next, dist, build 같은 디렉토리는 무조건 제외합니다. 이런 폴더까지 인덱싱하면 검색 결과가 지저분해지고, 토큰도 아깝습니다. 특히 프론트엔드 프로젝트에서 .nextdist가 끼어들면 정말 피곤합니다. 사람이 봐도 보기 싫은데 LLM에게 굳이 먹일 이유가 없죠.

제가 자주 쓰는 설정은 대충 이런 모양입니다.

{
  "templates": {
    "review": "너는 코드 리뷰 전문가야. 검색된 코드에서 잠재적 버그나 보안 취약점이 있는지 분석해줘.",
    "refactor": "검색된 코드 조각을 더 간결하고 현대적인 문법으로 리팩토링해줘. 불필요한 부분은 생략해도 돼."
  },
  "indexing": {
    "exclude": ["node_modules", ".next", "dist", "build"],
    "branch": "currentOnly",
    "maxFileSize": "100KB"
  }
}

이렇게 해두면 Serena를 호출할 때 매번 길게 설명하지 않아도 됩니다. 예를 들어 $serena review "findUser"처럼 짧게 던져도, 미리 정해둔 리뷰 관점이 적용되는 식이죠. 이런 게 별거 아닌 것 같아도 반복 작업에서는 체감이 큽니다. 프롬프트를 매번 길게 쓰는 것도 노동이거든요. 나이가 들어서 그런가, 저는 이제 손가락 피로도도 생산성이라고 봅니다.

커스텀 프롬프트 템플릿은 생각보다 훨씬 쓸모가 많았습니다

LLM을 개발에 쓰다 보면 자주 하는 요청이 정해져 있습니다. 코드 리뷰, 리팩토링, 테스트 작성, 에러 원인 분석, 보안 취약점 점검 같은 것들이죠. 그런데 매번 “너는 숙련된 백엔드 개발자이고…”로 시작하는 프롬프트를 쓰는 건 좀 귀찮습니다. 처음 며칠은 열심히 쓰는데, 바쁜 날엔 대충 쓰게 됩니다. 그러면 답변 품질도 같이 흔들리고요.

그래서 저는 자주 쓰는 요청을 템플릿으로 빼둡니다. 제일 많이 쓰는 건 reviewrefactor입니다. 특히 코드 리뷰 템플릿에는 제가 보고 싶은 관점을 확실히 넣어둡니다. “잠재적 버그”, “예외 처리 누락”, “보안 취약점”, “불필요한 복잡도” 같은 표현을 미리 넣어두면 답변이 훨씬 안정적입니다.

템플릿 이름 주로 쓰는 상황 프롬프트에 꼭 넣는 관점
review PR 올리기 전 셀프 리뷰 버그 가능성, 예외 처리, 보안 이슈
refactor 함수가 길어졌거나 중복이 보일 때 가독성, 중복 제거, 현대적인 문법
test 테스트 케이스가 부족할 때 경계값, 실패 케이스, mocking 범위

이렇게 해두면 AI 바이브 코딩이 조금 덜 즉흥적이 됩니다. 바이브는 살리되, 반복되는 판단 기준은 고정해두는 거죠. 저는 이 균형이 중요하다고 봅니다. AI를 쓰는 개발이 너무 즉흥적으로만 흘러가면 나중에 코드가 산으로 가기 쉽고, 반대로 너무 빡빡하게 통제하면 AI를 쓰는 맛이 사라집니다. 적당히 풀어주되, 중요한 기준은 설정 파일에 박아두는 쪽이 제 취향에 맞았습니다.

캐시는 꼭 켜두는 게 좋습니다, 같은 질문을 은근히 자주 하거든요

Serena를 쓰면서 생각보다 많이 덕을 본 게 캐시 설정입니다. 개발하다 보면 같은 함수를 여러 번 확인하게 됩니다. 처음엔 버그 원인 보려고 찾고, 그다음엔 리팩토링하려고 보고, 나중엔 테스트 만들려고 또 봅니다. 이때 매번 새로 검색하고 매번 비슷한 컨텍스트를 LLM에게 넘기면 아깝습니다.

캐시를 켜두면 동일하거나 비슷한 시맨틱 검색 결과를 빠르게 다시 가져올 수 있어서 반복 작업이 편해집니다. 물론 코드가 바뀌었는데 오래된 캐시를 보면 곤란하니, 브랜치 변경이나 큰 수정 이후에는 캐시 갱신 기준을 신경 써야 합니다. 그래도 저는 켜두는 쪽이 훨씬 낫다고 봅니다. 특히 사이드 프로젝트처럼 하루에 조금씩 끊어서 작업하는 환경에서는 더 그렇습니다. 어제 보던 함수를 오늘 다시 보는 일이 많거든요.

  • 같은 함수나 클래스에 대해 반복 질문이 많다면 캐시를 켜두는 편이 좋습니다
  • 브랜치를 자주 바꾼다면 캐시 갱신 기준을 같이 확인하는 게 안전합니다
  • 리팩토링 직후에는 예전 검색 결과가 섞이지 않도록 한 번 정리하는 습관이 좋습니다

저는 이 설정들을 적용하고 나서 한 달 기준으로 토큰 사용량이 대략 30% 정도 줄었습니다. 엄청 정밀하게 회계 장부처럼 계산한 건 아니지만, API 사용량을 보면 확실히 내려갔습니다. 더 좋았던 건 비용보다도 작업 흐름이 덜 끊겼다는 점이에요. 토큰 제한을 신경 쓰면서 조마조마하게 개발하는 게 은근히 집중력을 갉아먹거든요.

AI 바이브 코딩을 오래 하려면, 대충 던지는 습관부터 줄여야 합니다

제가 20년 가까이 개발 일을 하면서 느낀 게 하나 있습니다. 도구가 좋아질수록 기본기가 더 중요해진다는 겁니다. 예전에는 컴파일러와 IDE가 좋아지면서 코드를 대충 짜도 되는 것처럼 느껴질 때가 있었고, 요즘은 LLM이 있으니까 맥락을 대충 던져도 알아서 해줄 것처럼 보입니다. 그런데 실무에서는 꼭 그렇지 않더라고요.

LLM은 정말 훌륭한 동료처럼 느껴질 때가 많습니다. 하지만 그 동료에게 회의 자료를 산더미처럼 던져놓고 “알아서 핵심 찾아봐”라고 하면, 아무리 똑똑해도 답이 흐려질 수밖에 없습니다. Serena 같은 시맨틱 코드 검색 도구는 그 회의 자료를 미리 정리해주는 역할에 가깝습니다. 필요한 부분만 추려서 넘겨주니까 LLM도 더 좋은 답을 할 가능성이 높아지는 거죠.

제가 지금 기준으로 가장 추천하는 조합은 이렇습니다.

  • 저장소 전체보다 현재 브랜치 중심으로 인덱싱하기
  • node_modules, dist, build, .next는 과감하게 제외하기
  • 검색할 때 type:function, type:class, type:test로 범위 줄이기
  • 시맨틱 유사도는 0.7 전후부터 시작해보기
  • 자주 쓰는 요청은 .serenarc 템플릿으로 고정해두기
  • 반복 검색이 많다면 캐시를 켜두기

이런 분들이라면 Serena를 한 번 써볼 만합니다

이 글을 여기까지 읽으셨다면 아마 AI 바이브 코딩을 이미 하고 있거나, 적어도 꽤 진지하게 고민하고 있는 분일 가능성이 높습니다. 특히 LLM API 요금이 슬슬 신경 쓰이기 시작한 분, 사이드 프로젝트에서 매번 코드 붙여넣는 게 귀찮아진 분, 팀 프로젝트에서 레거시 코드 때문에 LLM 답변이 자꾸 흔들리는 분이라면 Serena 같은 도구를 한 번 써볼 만합니다.

프리랜서 개발자에게도 괜찮고, 회사에서 큰 저장소를 다루는 백엔드나 프론트엔드 개발자에게도 꽤 도움이 됩니다. 개인적으로는 토큰 비용을 줄이고 싶은 사람보다 LLM 답변 품질을 안정적으로 만들고 싶은 사람에게 더 추천하고 싶어요. 비용 절감은 따라오는 효과에 가깝고, 진짜 장점은 필요한 맥락만 골라서 대화할 수 있다는 데 있었습니다.

뭐랄까, 예전엔 여행 갈 때도 혹시 몰라서 가방에 이것저것 다 넣었습니다. 충전기도 두 개, 옷도 여분으로 몇 벌, 안 읽을 책까지 챙기고요. 그런데 많이 다니다 보니 알게 되더라고요. 짐이 가벼워야 더 멀리 갑니다. LLM과 함께 개발하는 방식도 비슷했습니다. 코드를 많이 던지는 것보다, 꼭 필요한 코드만 잘 챙겨서 넘기는 쪽이 훨씬 오래가고 편합니다.

Serena가 모든 걸 해결해주는 만능 도구는 아닙니다. 그래도 시맨틱 코드 검색토큰 절약을 함께 고민하는 개발자라면 꽤 좋은 선택지가 될 수 있습니다. 저처럼 퇴근 후 조용히 사이드 프로젝트를 만지는 40대 개발자에게도, 매일 큰 코드베이스와 씨름하는 현업 개발자에게도요. 한 번쯤 설정을 만져보세요. 생각보다 작은 설정 하나가 하루 작업 리듬을 꽤 부드럽게 바꿔줍니다.

댓글