MyStock - JSON Export 최적화

앞선 실험에서는 MyStock의 투자 데이터를 JSON으로 내보내 여러 LLM에 그대로 던져봤다. 계좌 상태와 손익, 보유 ETF의 가격과 거래량, 투자자 수급, ETF 구성종목과 최근 변화, 실제 기초자산 기준의 중복 노출, 거래내역, 그리고 시장지표의 과거 데이터까지 한 파일에 넣었다. 당시 Pretty JSON은 약 1.28MB까지 커졌는데, 내 계좌 하나를 분석하기 위한 파일이라는 점을 생각해도 1.3MB 정도는 별문제가 아니라고 생각했다.

 

데이터를 충분히 넣어두면 LLM이 그 안에서 필요한 정보를 알아서 찾아 관계를 연결할 것으로 기대했지만, 실제 결과는 달랐다. 눈에 잘 보이는 현재 수익률이나 보유 비중은 비교적 잘 사용하면서도, 일부러 넣어둔 과거 시장 흐름이나 ETF 구성 변화, 수급처럼 해석에 시간이 필요한 데이터는 아예 사용하지 않는 경우가 반복됐다.

 

첫 번째 실험에서 얻은 결론은 데이터가 부족하다는 것이 아니었다. JSON 안에 데이터가 존재하는 것과 LLM이 그 데이터를 실제 분석에 사용하는 것은 전혀 다른 문제였다. 그래서 당시에는 데이터를 더 추가하는 대신 어떤 정보를 어떤 순서로 확인할지 실행 프롬프트를 강화하는 방향으로 바꿨고, 그 결과 일부 영역의 활용률은 실제로 좋아졌다. 그 글의 마지막에는 다음 실험으로 “이 컨텍스트를 얼마나 줄여도 같은 판단 품질을 유지할 수 있을까?”라는 질문을 남겼다. 이번 v2 작업은 바로 그 질문에서 시작했다.

22KB의 지시문

Historical path를 안 보면 먼저 보라고 했고, 과거와 현재를 비교하라고 했으며, 비슷한 과거 구간을 찾았으면 이후 1주·4주·12주의 실제 경로를 확인하라고 했다. 과거 결과를 미래 예측처럼 쓰지 말 것, ETF 비중 변화를 운용사의 확신으로 단정하지 말 것, captured cash를 추가 매수 여력으로 해석하지 말 것 같은 경계도 붙였다.

 

내가 직관적으로 확인할 수 있게 시각화도 시켰으나, 내가 원하는 방향이 아니었으며 JSON의 analysis_request는 반복적인 수정 작업으로 약 22KB까지 커졌다. 요즘은 Context Engineering이니 Harness니 여러 이름으로 부르는 모양인데, 난 여전히 쌍팔년도 방식의 프롬프트 엔지니어링이라고 생각한다. AI가 말을 안 들으면 조건을 하나 더 쓰고, 또 안 들으면 한 줄 더 붙였다.

데이터가 많다고 다 읽는 것도 아니고, 지시가 많다고 다 따르는 것도 아니었다.

시각화 역시 지시를 강화한다고 안정적으로 해결되지는 않았다. 어떤 LLM은 과거 사례까지 분석하고도 차트를 생략했고, 차트를 만들더라도 내가 확인하려던 과거와 현재의 비교가 아니라 단순한 지수 흐름을 보여주기도 했다. 결국 시각화 문제까지 해결하려고 실행 프롬프트를 계속 늘리는 것이 맞는지 다시 생각하게 됐다.

다이어트의 착각

처음 질문은 “얼마나 줄일 수 있을까?”였지만, 여러 번 분석을 돌려본 뒤에는 질문 자체가 잘못됐다고 느꼈다. LLM Export의 목적은 가장 작은 JSON을 만드는 것이 아니라, LLM이 현재 시장과 내 포트폴리오를 판단할 때 필요한 정보가 눈에 들어오는 구조를 만드는 것이었다.

그래서 Canonical DB와 LLM Export의 역할을 분리했다. DB에는 앞으로 어떤 분석에 다시 필요할지 모르는 실제 데이터를 충분히 보존하고, LLM에게 전달하는 JSON에서는 같은 사실을 지나치게 높은 해상도로 반복하는 부분을 줄이기로 했다. 반대로 판단에 필요한 시간적 맥락이 부족한 영역은 데이터를 더 제공하기로 했다.

 

대표적인 것이 Active ETF의 구성종목 데이터였다. 기존에는 최근 30일 동안 수집한 constituent snapshot을 날짜별 trajectory로 전달해 Verified Active만 합쳐도 704행이었다. 처음에는 하루하루의 비중 변화를 모두 제공하면 LLM이 그 안에서 의미 있는 변화를 알아서 찾을 것으로 생각했지만, 실제 consumer test에서는 현재 구성종목만 확인하거나 30일 trajectory를 거의 사용하지 않는 경우가 있었다. 내가 실제로 궁금했던 것도 하루하루의 모든 비중 변화가 아니었다. 현재 어떤 종목을 들고 있는지, 1주 전과 30일 전에 비해 비중이 어떻게 달라졌는지, 어떤 종목이 새로 들어오고 빠졌는지가 더 중요했다. 그래서 Canonical DB의 snapshot은 그대로 유지하면서 LLM projection에서는 현재 구성종목과 1주·30일 비중 변화, 편입·편출과 필요한 membership event만 전달하도록 변경했다. 그 결과 Active raw trajectory는 704행에서 0행이 됐고 필요한 변화 정보는 412행의 compact fact로 정리했다.

 

반대로 보유종목의 가격과 거래량은 줄이지 않았다. 내가 거래량을 JSON에 넣은 이유는 단순히 오늘 몇 주가 거래됐는지 확인하려는 것이 아니라, 시장 흐름이 바뀔 때 평소와 다른 거래량 변화가 나타나는 종목을 LLM이 먼저 찾아주길 바랐기 때문이다. 예를 들어 KODEX 미국AI소프트웨어TOP10은 하락과 정체 구간을 지나 최근 가격이 다시 움직이면서 거래량에도 변화가 나타났다. 최근 30일 Daily만으로는 그 변화가 이전 흐름과 비교해 어떤 모습인지 판단하기 부족하다고 봤고, 이 영역에는 오히려 6개월 Weekly price-volume을 추가했다. 최근 5일과 이전 5일, 최근 20일과 이전 20일의 평균 거래량 변화도 deterministic fact로 계산하되, MyStock이 이를 “매수세 유입”이나 “상승 신호”처럼 해석하지는 않도록 했다.

 

그 결과 Securities 영역은 약 79KB에서 108KB로 오히려 커졌다. 이후 Claude의 blind test에서는 실제로 여러 보유종목의 거래량을 비교해 미국AI소프트웨어의 변화가 다른 종목과 다르다는 점을 자발적으로 찾아냈다. 반대로 Active ETF는 704행의 raw trajectory를 제거했는데도 일부 consumer가 compact change만으로 최근 구성 변화를 분석했다. 처음에는 JSON을 줄이는 작업이라고 생각했지만 결과는 달랐다. 어떤 데이터는 줄였고 어떤 데이터는 오히려 늘렸다.

 

줄여야 할 것은 데이터의 양이 아니라 판단에 기여하지 않는 해상도였다.

해상도의 선택

Investor Flow도 같은 기준으로 다시 정리했다. 최근 데이터를 길게 나열하는 대신 단기와 중기 수급 방향을 비교할 수 있는 정보는 남기고, 반복되는 raw data는 줄였다. 반면 Market의 과거 데이터는 유지했다. 금리, 유가, 환율, 변동성, Fear & Greed와 주가가 과거에 어떤 관계를 보였는지는 MyStock이 미리 결론을 만들어주는 것보다 LLM이 실제 흐름을 보고 현재 시장과 비교했으면 하는 영역이었기 때문이다.

 

실행 프롬프트도 같은 방향으로 정리했다. 모든 데이터를 빠짐없이 언급하도록 요구하거나 특정 결과를 찾도록 지시하는 대신, 분석의 큰 흐름과 잘못된 해석을 막기 위한 최소한의 경계만 남겼다. 결국 v2에서 한 일은 JSON을 무조건 줄이는 것이 아니었다.

 

불필요하게 반복되는 세부정보는 줄이고, LLM이 판단하는데 필요한 근거는 남기거나 보강했다.

다섯 개의 시선

JSON을 새 대화에 전달하고 별도의 추가 힌트를 주지 않는 방식으로 다시 확인했다. ChatGPT 개인 계정의 새 대화, ChatGPT 무료 환경, Claude, Grok, Gemini 결과를 비교했다. 계정과 사용량, 모델 실행 조건을 완전히 통제한 벤치마크는 아니기 때문에 모델의 우열을 가리는 점수표로 사용하지 않았다.

항목 ChatGPT Pro ChatGPT 무료 Claude Grok Gemini
Historical market 실제 활용 O O O O △
Exact historical D0 O △ △ △ X
이후 actual path 활용 O △ △ △ X
Price / Volume 활용 O O O △ X
0041D0 거래량 변화 자발적 발견 X X O X X
Investor Flow 활용 O O O △ X
Active compact 변화 활용 O △ O △ X
F&G 관계 / 괴리 활용 △ △ O △ X
Look-through 활용 O O O O △
Captured cash 의미 준수 O O O O O/△
첫 응답 explanatory 시각화 X X X X X

같은 JSON을 전달했지만 모델이 선택한 근거는 달랐다. ChatGPT Pro는 3년 historical data에서 현재 금리·유가와 비교할 과거 구간과 이후 실제 경로까지 적극적으로 사용했고, Claude는 보유종목의 거래량 변화와 Fear & Greed의 괴리, Active ETF 구성 변화를 상대적으로 잘 찾아냈다. 반면 같은 데이터가 있어도 일부 모델은 이를 거의 사용하지 않았다.

 

중요한 것은 모든 모델이 같은 분석을 내놓는가가 아니었다. 분석 경로가 달라도 AI·반도체·성장주 노출의 집중, ETF 개수와 실제 look-through concentration의 차이, 높은 금리와 유가의 부담처럼 포트폴리오를 판단하는 주요 근거는 여러 결과에서 반복해서 나타났다.

 

같은 답을 만드는 것보다, 서로 다른 LLM이 중요한 근거에서 수렴하는지가 더 중요했다.

최소 충분 조건

이번 실험에서 확인하고 싶었던 것은 JSON을 얼마나 작게 만들 수 있느냐가 아니었다. 불필요한 디테일은 줄이고 필요한 근거는 보강한 뒤, 서로 다른 LLM이 이를 실제 분석에 사용할 수 있는지를 확인하는 것이었다. 결과적으로 모든 LLM이 같은 데이터를 사용하거나 같은 분석을 내놓지는 않았다. 하지만 분석 방식이 달라도 AI·반도체 집중, look-through를 통한 실제 중복 노출, 금리·유가와 현재 시장의 관계처럼 중요한 판단 근거는 여러 결과에서 반복적으로 확인됐다. 반면 JSON에 이미 있는 데이터를 보지 않거나, 다시 계산해보자고 제안하는 경우도 있었다.

 

시각화 역시 프롬프트를 계속 강화한다고 안정적으로 해결되지는 않았다. 분석 자체와 분리하는 편이 낫다고 판단했고, 분석 결과를 기준으로 현재 대화방의 ChatGPT를 갈궈서 그리기로 했다.  처음에는 데이터를 많이 주면 알아서 분석할 것으로 생각했고, 이후에는 지시를 자세하게 적으면 해결될 것으로 생각했다. 실제로 여러 LLM을 반복해서 확인해보니 둘 다 아니었다. 중요한 것은 데이터의 양이나 프롬프트의 길이가 아니라, LLM이 판단할 수 있는 정보를 어떻게 제공하느냐였다.

 

AI와 일하는 게 결코 쉽지는 않다. 그래도 이 요구사항대로 내가 직접 코딩하지 않아도 된다는 건 여전히 좋다. 그리고 난 여전히 이걸 쌍팔년도 방식의 프롬프트 엔지니어링을 하고 있는 것 같다.