<feed xmlns="http://www.w3.org/2005/Atom"> <id>https://keencho.github.io/</id><title>keencho's blog</title><subtitle>A minimal, responsive, and powerful Jekyll theme for presenting professional writing.</subtitle> <updated>2026-07-23T14:45:08+09:00</updated> <author> <name>keencho</name> <uri>https://keencho.github.io/</uri> </author><link rel="self" type="application/atom+xml" href="https://keencho.github.io/feed.xml"/><link rel="alternate" type="text/html" hreflang="ko-KS" href="https://keencho.github.io/"/> <generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator> <rights> © 2026 keencho </rights> <icon>/assets/img/favicons/favicon.ico</icon> <logo>/assets/img/favicons/favicon-96x96.png</logo> <entry><title>pgvector 벡터 검색이 HNSW 인덱스를 안 탈 때</title><link href="https://keencho.github.io/posts/pgvector-hnsw-index-not-used/" rel="alternate" type="text/html" title="pgvector 벡터 검색이 HNSW 인덱스를 안 탈 때" /><published>2026-07-20T15:10:00+09:00</published> <updated>2026-07-20T15:10:00+09:00</updated> <id>https://keencho.github.io/posts/pgvector-hnsw-index-not-used/</id> <content src="https://keencho.github.io/posts/pgvector-hnsw-index-not-used/" /> <author> <name>keencho</name> </author> <category term="Database" /> <summary> pgvector 벡터 검색이 HNSW 인덱스를 안 탈 때 예전에 pgvector로 RAG 챗봇의 벡터 검색을 만든 글을 썼었다. 그때는 HNSW 인덱스 걸고 잘 돌아갔는데, 데이터가 쌓이고 회사(테넌트)가 늘면서 어느 날부터 검색이 눈에 띄게 느려졌다. 원래 수십 밀리초면 끝나던 게 수 초씩 걸렸다. 원인을 찾는 데 시간이 좀 걸렸는데, 알고 보니 HNSW 인덱스를 아예 안 타고 있었다. 인덱스를 걸어뒀는데 안 쓰고 전수 스캔을 하고 있었던 거다. 이 글은 그걸 어떻게 진단하고 고쳤는지, 그리고 RDS라서 추가로 부딪힌 벽에 대한 기록이다. 일단 EXPLAIN 부터 “느리다” 는 감이고, 확인은 EXPLAIN 이다. 벡터 검색 쿼리에 EXPLAIN을 붙여보니 이렇게 나왔다. Limit -&amp;gt... </summary> </entry> <entry><title>CloudFront Function 으로 엣지에서 처리하기</title><link href="https://keencho.github.io/posts/cloudfront-functions-edge/" rel="alternate" type="text/html" title="CloudFront Function 으로 엣지에서 처리하기" /><published>2026-06-21T14:25:00+09:00</published> <updated>2026-06-21T14:25:00+09:00</updated> <id>https://keencho.github.io/posts/cloudfront-functions-edge/</id> <content src="https://keencho.github.io/posts/cloudfront-functions-edge/" /> <author> <name>keencho</name> </author> <category term="AWS" /> <summary> CloudFront Function 으로 엣지에서 처리하기 메일 시스템 글에서 CloudFront로 프론트(React SPA)를 S3에 서빙한다고 했다. 근데 SPA를 S3 + CloudFront로 올리면 흔히 밟는 함정이 하나 있다. 사용자가 /posts/abc 같은 경로에서 새로고침을 하면 404가 뜬다. 이유는 단순하다. SPA는 라우팅을 브라우저(자바스크립트)가 한다. 실제로 S3에 있는 파일은 index.html 하나뿐이고, /posts/abc 라는 파일은 없다. 처음 접속해서 JS가 로드된 뒤에는 클라이언트 라우터가 화면을 바꿔주지만, 그 경로에서 새로고침하면 브라우저가 S3한테 /posts/abc 파일을 직접 달라고 하고, S3엔 그게 없으니 404다. 이걸 푸는 방법이 두 가지다. 하... </summary> </entry> <entry><title>멀티에이전트 RAG 직접 만들기</title><link href="https://keencho.github.io/posts/multi-agent-rag-tool-calling/" rel="alternate" type="text/html" title="멀티에이전트 RAG 직접 만들기" /><published>2026-05-17T16:05:00+09:00</published> <updated>2026-05-17T16:05:00+09:00</updated> <id>https://keencho.github.io/posts/multi-agent-rag-tool-calling/</id> <content src="https://keencho.github.io/posts/multi-agent-rag-tool-calling/" /> <author> <name>keencho</name> </author> <category term="AI" /> <summary> 멀티에이전트 RAG 직접 만들기 지난 글에서 검색을 다듬고, 마지막에 LLM이 “이 자료로 답할 수 있나” 를 판단하게 했다. 사실 그 판단으로 재검색·되묻기·거절을 가르는 순간, 이미 단순 RAG를 넘어 에이전트의 영역에 발을 들인 거였다. 이번 글은 그걸 제대로 밀고 나간 이야기다. 역할을 나눈 여러 LLM이 협업하고, 자료로 안 되는 건 도구(tool calling)를 불러서 답하는 구조다. 흔히 이런 건 LangChain이나 LangGraph 같은 프레임워크로 짠다. 근데 우리는 안 썼다. 이유는 뒤에서 얘기하고, 일단 뭘 만들었는지부터 보자. 왜 한 모델한테 다 안 시키나 제일 단순하게 가면, 검색한 자료랑 질문을 LLM 하나한테 통째로 주고 “알아서 판단하고 답해” 라고 할 수 있다. 근... </summary> </entry> <entry><title>가상 스크롤 직접 구현하기</title><link href="https://keencho.github.io/posts/virtual-scroll-from-scratch/" rel="alternate" type="text/html" title="가상 스크롤 직접 구현하기" /><published>2026-04-12T15:30:00+09:00</published> <updated>2026-04-12T15:30:00+09:00</updated> <id>https://keencho.github.io/posts/virtual-scroll-from-scratch/</id> <content src="https://keencho.github.io/posts/virtual-scroll-from-scratch/" /> <author> <name>keencho</name> </author> <category term="React" /> <summary> 가상 스크롤 직접 구현하기 회사 관리자 화면에 목록 테이블이 하나 있었는데, 데이터가 쌓이면서 행이 수만 개가 됐다. 그랬더니 페이지가 열릴 때 몇 초씩 멈추고, 스크롤은 뚝뚝 끊겼다. 원인은 단순했다. 화면엔 기껏해야 20~30행이 보이는데, DOM에는 수만 개의 행이 전부 그려져 있었던 거다. 브라우저 입장에선 보이든 안 보이든 그 수만 개를 다 만들어서 메모리에 들고 있어야 하고, 레이아웃도 계산해야 한다. 안 보이는 9천 몇백 행까지 다 그리느라 죽어나는 거다. 이걸 푸는 방법이 가상 스크롤(virtual scroll), 다른 말로 windowing이다. 라이브러리를 쓰면 금방인데, 원리를 알고 싶어서 직접 만들어봤다. 생각보다 핵심은 단순하다. 핵심 아이디어 - 보이는 것만 그린다 가상 스... </summary> </entry> <entry><title>RAG 검색 품질 끌어올리기</title><link href="https://keencho.github.io/posts/rag-pipeline-rerank-judge/" rel="alternate" type="text/html" title="RAG 검색 품질 끌어올리기" /><published>2026-02-15T17:40:00+09:00</published> <updated>2026-02-15T17:40:00+09:00</updated> <id>https://keencho.github.io/posts/rag-pipeline-rerank-judge/</id> <content src="https://keencho.github.io/posts/rag-pipeline-rerank-judge/" /> <author> <name>keencho</name> </author> <category term="AI" /> <summary> RAG 검색 품질 끌어올리기 지난 글에서 pgvector로 벡터 검색을 붙이고, 거기에 키워드 검색까지 섞은 하이브리드를 만들었다. 의미로도 찾고 정확한 단어로도 찾으니 후보를 빠짐없이 긁어오게 됐다. 근데 운영해보니 “후보를 잘 긁어온다” 와 “좋은 답이 나온다” 는 생각보다 거리가 멀었다. 문제는 이거였다. 하이브리드 검색이 후보를 20개쯤 가져오는데, 그 20개의 순서가 엉망이었다. 진짜 정답인 문서가 12번째에 깔려있고, 어중간하게 비슷한 문서가 1번에 올라와 있는 식이다. RAG는 보통 상위 몇 개만 LLM에 넘기니까, 정답이 12번째면 아예 안 보여진다. 검색은 됐는데 답은 틀리는 것이다. 이 글은 그 다음 이야기다. 긁어온 후보를 어떻게 다듬어서 진짜 쓸만한 걸 골라내는지. 검색이 “찾... </summary> </entry> </feed>
