<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Project on Chanyeol Dev</title>
    <link>https://chanyeols.com/categories/project/</link>
    <description>Recent content in Project on Chanyeol Dev</description>
    <generator>Hugo</generator>
    <language>ko-kr</language>
    <lastBuildDate>Mon, 23 Mar 2026 14:30:00 +0900</lastBuildDate>
    <atom:link href="https://chanyeols.com/categories/project/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Spring AI 프로젝트 마무리: 로컬 LLM 챗봇의 한계와 향후 발전 로드맵 (7편)</title>
      <link>https://chanyeols.com/posts/spring-ai-chatbot-retrospective-roadmap/</link>
      <pubDate>Mon, 23 Mar 2026 14:30:00 +0900</pubDate>
      <guid>https://chanyeols.com/posts/spring-ai-chatbot-retrospective-roadmap/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;[Dev-Fortune] 시리즈 다시보기&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/spring-ai-ollama-chatbot-planning/&#34;&gt;1편: 기획부터 스택 선정까지&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/ollama-spring-boot-local-llm-setup/&#34;&gt;2편: 로컬 LLM Ollama 연동&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/spring-ai-rag-simplevectorstore-ingestion/&#34;&gt;3편: RAG와 Vector Store 구축&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/prompt-engineering-ai-persona-tuning/&#34;&gt;4편: 프롬프트 엔지니어링 실전&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/spring-webflux-sse-ai-streaming-api/&#34;&gt;5편: 스트리밍 API 구현&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/spring-ai-rag-workflow-analysis/&#34;&gt;6편: 전체 워크플로우 분석&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;1-서론-프로젝트를-마무리하며&#34;&gt;1. 서론: 프로젝트를 마무리하며&lt;/h2&gt;
&lt;p&gt;시니컬한 개발자 챗봇 &amp;lsquo;Dev-Fortune&amp;rsquo;을 통해 Spring AI와 RAG의 가능성을 엿보았습니다. 마지막으로 이 프로젝트의 한계를 짚어보고 고도화 로드맵을 그려봅니다.&lt;/p&gt;
&lt;h2 id=&#34;2-미래-고도화-로드맵-as-is-vs-to-be&#34;&gt;2. 미래 고도화 로드맵 (AS-IS vs TO-BE)&lt;/h2&gt;
&lt;p&gt;현재의 메모리 기반 구조에서 영구 저장소와 맥락 인지 능력을 갖춘 시스템으로의 진화 방향입니다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>[Dev-Fortune] 시리즈 다시보기</strong></p>
</blockquote>
<ul>
<li><a href="/posts/spring-ai-ollama-chatbot-planning/">1편: 기획부터 스택 선정까지</a></li>
<li><a href="/posts/ollama-spring-boot-local-llm-setup/">2편: 로컬 LLM Ollama 연동</a></li>
<li><a href="/posts/spring-ai-rag-simplevectorstore-ingestion/">3편: RAG와 Vector Store 구축</a></li>
<li><a href="/posts/prompt-engineering-ai-persona-tuning/">4편: 프롬프트 엔지니어링 실전</a></li>
<li><a href="/posts/spring-webflux-sse-ai-streaming-api/">5편: 스트리밍 API 구현</a></li>
<li><a href="/posts/spring-ai-rag-workflow-analysis/">6편: 전체 워크플로우 분석</a></li>
</ul>
<h2 id="1-서론-프로젝트를-마무리하며">1. 서론: 프로젝트를 마무리하며</h2>
<p>시니컬한 개발자 챗봇 &lsquo;Dev-Fortune&rsquo;을 통해 Spring AI와 RAG의 가능성을 엿보았습니다. 마지막으로 이 프로젝트의 한계를 짚어보고 고도화 로드맵을 그려봅니다.</p>
<h2 id="2-미래-고도화-로드맵-as-is-vs-to-be">2. 미래 고도화 로드맵 (AS-IS vs TO-BE)</h2>
<p>현재의 메모리 기반 구조에서 영구 저장소와 맥락 인지 능력을 갖춘 시스템으로의 진화 방향입니다.</p>
<div class="mermaid">
graph LR
    subgraph "AS-IS (Current)"
        A[SimpleVectorStore] --- B[In-Memory]
        C[Stateless] --- D[No History]
    end
<pre><code>subgraph &quot;TO-BE (Future)&quot;
    E[PostgreSQL + pgvector] --- F[Persistent Storage]
    G[ChatMemory / Redis] --- H[Context Awareness]
    I[Multi-Persona] --- J[Style Selection]
end

A -.-&gt; E
C -.-&gt; G
</code></pre>
</div>
<h2 id="3-핵심-고도화-포인트">3. 핵심 고도화 포인트</h2>
<ul>
<li><strong>PostgreSQL + pgvector</strong>: 수만 건의 데이터를 영구 저장하고 고속 검색.</li>
<li><strong>Chat Memory</strong>: 이전 대화 맥락을 기억하는 지능형 대화.</li>
<li><strong>멀티 페르소나</strong>: 에인절 시니어, 까칠한 CTO 등 페르소나 확장.</li>
</ul>
<h2 id="4-결론">4. 결론</h2>
<p>Java 진영에서도 AI 개발이 너무나 쉽고 우아해졌습니다. 여러분의 앞날에 컴파일 에러 없는 평안만 가득하시길 바라며 시리즈를 마칩니다.</p>
<p><strong>당신의 인생을 계속 디버깅하세요!</strong></p>
]]></content:encoded>
    </item>
    <item>
      <title>Spring AI RAG 워크플로우 분석: 사용자 질문부터 AI 답변까지의 여정 (6편)</title>
      <link>https://chanyeols.com/posts/spring-ai-rag-workflow-analysis/</link>
      <pubDate>Sun, 22 Mar 2026 14:30:00 +0900</pubDate>
      <guid>https://chanyeols.com/posts/spring-ai-rag-workflow-analysis/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;[Dev-Fortune] 시리즈 다시보기&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/spring-ai-ollama-chatbot-planning/&#34;&gt;1편: 기획부터 스택 선정까지&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/ollama-spring-boot-local-llm-setup/&#34;&gt;2편: 로컬 LLM Ollama 연동&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/spring-ai-rag-simplevectorstore-ingestion/&#34;&gt;3편: RAG와 Vector Store 구축&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/prompt-engineering-ai-persona-tuning/&#34;&gt;4편: 프롬프트 엔지니어링 실전&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/spring-webflux-sse-ai-streaming-api/&#34;&gt;5편: 스트리밍 API 구현&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;1-서론-조각난-퍼즐을-하나로-합치기&#34;&gt;1. 서론: 조각난 퍼즐을 하나로 합치기&lt;/h2&gt;
&lt;p&gt;데이터의 이동이 일어나는 찰나의 순간, 서버 내부에서 일어나는 유기적인 상호작용을 파헤쳐 보겠습니다.&lt;/p&gt;
&lt;h2 id=&#34;2-전체-워크플로우-시퀀스-deep-dive&#34;&gt;2. 전체 워크플로우 시퀀스 (Deep-Dive)&lt;/h2&gt;
&lt;p&gt;사용자의 엔터 키 한 번이 답변으로 돌아오기까지의 7단계 여정입니다.&lt;/p&gt;
&lt;div class=&#34;mermaid&#34;&gt;
sequenceDiagram
    autonumber
    User-&gt;&gt;Controller: 고민 입력 (JSON)
    Controller-&gt;&gt;Service: 사주 분석 요청
    Service-&gt;&gt;VectorStore: 고민 기반 유사도 검색
    VectorStore--&gt;&gt;Service: 관련 사주 데이터 반환
    Service-&gt;&gt;AI: 프롬프트 조합 후 전달 (System+User)
    AI--&gt;&gt;Controller: 스트리밍 답변 생성 (Flux)
    Controller--&gt;&gt;User: SSE 응답 (실시간 텍스트)
&lt;/div&gt;
&lt;h2 id=&#34;3-데이터-흐름의-5단계&#34;&gt;3. 데이터 흐름의 5단계&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;요청 수신&lt;/strong&gt;: JSON 고민 데이터 접수.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;의미 검색&lt;/strong&gt;: 사주 데이터 조각 탐색.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;프롬프트 조합&lt;/strong&gt;: 페르소나 + 지식 + 질문 결합.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;추론 및 생성&lt;/strong&gt;: AI의 인격이 투영된 답변 생성.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;스트리밍 응답&lt;/strong&gt;: 차가운 조언의 실시간 전달.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;결국 &lt;strong&gt;데이터가 지능을 만들고, 프롬프트가 성격을 만듭니다.&lt;/strong&gt;&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>[Dev-Fortune] 시리즈 다시보기</strong></p>
</blockquote>
<ul>
<li><a href="/posts/spring-ai-ollama-chatbot-planning/">1편: 기획부터 스택 선정까지</a></li>
<li><a href="/posts/ollama-spring-boot-local-llm-setup/">2편: 로컬 LLM Ollama 연동</a></li>
<li><a href="/posts/spring-ai-rag-simplevectorstore-ingestion/">3편: RAG와 Vector Store 구축</a></li>
<li><a href="/posts/prompt-engineering-ai-persona-tuning/">4편: 프롬프트 엔지니어링 실전</a></li>
<li><a href="/posts/spring-webflux-sse-ai-streaming-api/">5편: 스트리밍 API 구현</a></li>
</ul>
<h2 id="1-서론-조각난-퍼즐을-하나로-합치기">1. 서론: 조각난 퍼즐을 하나로 합치기</h2>
<p>데이터의 이동이 일어나는 찰나의 순간, 서버 내부에서 일어나는 유기적인 상호작용을 파헤쳐 보겠습니다.</p>
<h2 id="2-전체-워크플로우-시퀀스-deep-dive">2. 전체 워크플로우 시퀀스 (Deep-Dive)</h2>
<p>사용자의 엔터 키 한 번이 답변으로 돌아오기까지의 7단계 여정입니다.</p>
<div class="mermaid">
sequenceDiagram
    autonumber
    User->>Controller: 고민 입력 (JSON)
    Controller->>Service: 사주 분석 요청
    Service->>VectorStore: 고민 기반 유사도 검색
    VectorStore-->>Service: 관련 사주 데이터 반환
    Service->>AI: 프롬프트 조합 후 전달 (System+User)
    AI-->>Controller: 스트리밍 답변 생성 (Flux)
    Controller-->>User: SSE 응답 (실시간 텍스트)
</div>
<h2 id="3-데이터-흐름의-5단계">3. 데이터 흐름의 5단계</h2>
<ol>
<li><strong>요청 수신</strong>: JSON 고민 데이터 접수.</li>
<li><strong>의미 검색</strong>: 사주 데이터 조각 탐색.</li>
<li><strong>프롬프트 조합</strong>: 페르소나 + 지식 + 질문 결합.</li>
<li><strong>추론 및 생성</strong>: AI의 인격이 투영된 답변 생성.</li>
<li><strong>스트리밍 응답</strong>: 차가운 조언의 실시간 전달.</li>
</ol>
<p>결국 <strong>데이터가 지능을 만들고, 프롬프트가 성격을 만듭니다.</strong></p>
<p><strong>마지막 7편에서는 프로젝트를 마무리하며 미래 고도화 로드맵을 그려보겠습니다.</strong></p>
]]></content:encoded>
    </item>
    <item>
      <title>Spring WebFlux와 SSE로 구현하는 AI 스트리밍 API: 실시간 대화 경험 (5편)</title>
      <link>https://chanyeols.com/posts/spring-webflux-sse-ai-streaming-api/</link>
      <pubDate>Sat, 21 Mar 2026 14:30:00 +0900</pubDate>
      <guid>https://chanyeols.com/posts/spring-webflux-sse-ai-streaming-api/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;[Dev-Fortune] 시리즈 다시보기&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/spring-ai-ollama-chatbot-planning/&#34;&gt;1편: 기획부터 스택 선정까지&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/ollama-spring-boot-local-llm-setup/&#34;&gt;2편: 로컬 LLM Ollama 연동&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/spring-ai-rag-simplevectorstore-ingestion/&#34;&gt;3편: RAG와 Vector Store 구축&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/prompt-engineering-ai-persona-tuning/&#34;&gt;4편: 프롬프트 엔지니어링 실전&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;1-서론-ai-답변-왜-기다리게-하나요&#34;&gt;1. 서론: AI 답변, 왜 기다리게 하나요?&lt;/h2&gt;
&lt;p&gt;사용자 경험(UX)을 위해 한 글자씩 타이핑하듯 보여주는 스트리밍 방식은 필수적입니다. 우리 프로젝트는 &lt;strong&gt;WebFlux&lt;/strong&gt;와 **SSE(Server-Sent Events)**를 활용했습니다.&lt;/p&gt;
&lt;h2 id=&#34;2-스트리밍-시퀀스-다이어그램&#34;&gt;2. 스트리밍 시퀀스 다이어그램&lt;/h2&gt;
&lt;p&gt;서버와 클라이언트 간의 끊임없는 데이터 흐름을 살펴보세요.&lt;/p&gt;
&lt;div class=&#34;mermaid&#34;&gt;
sequenceDiagram
    participant U as User
    participant S as Spring Server (Flux)
    participant A as AI Model (Ollama)
&lt;pre&gt;&lt;code&gt;U-&amp;gt;&amp;gt;S: POST /chat (Request)
Note over S,A: Connection Stay Open
A--&amp;gt;&amp;gt;S: &amp;quot;오늘의&amp;quot; (Token 1)
S--&amp;gt;&amp;gt;U: data: &amp;quot;오늘의&amp;quot;
A--&amp;gt;&amp;gt;S: &amp;quot; 사주는&amp;quot; (Token 2)
S--&amp;gt;&amp;gt;U: data: &amp;quot; 사주는&amp;quot;
Note right of U: 사용자는 실시간으로 글자가 보임
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id=&#34;3-flux와-sse&#34;&gt;3. Flux와 SSE&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;MediaType.TEXT_EVENT_STREAM_VALUE&lt;/code&gt;를 사용하여 AI가 단어(Token)를 생성할 때마다 즉시 클라이언트로 전송합니다. 비차단(Non-blocking) 방식인 WebFlux는 답변을 기다리는 동안 쓰레드를 점유하지 않아 성능적으로도 우수합니다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>[Dev-Fortune] 시리즈 다시보기</strong></p>
</blockquote>
<ul>
<li><a href="/posts/spring-ai-ollama-chatbot-planning/">1편: 기획부터 스택 선정까지</a></li>
<li><a href="/posts/ollama-spring-boot-local-llm-setup/">2편: 로컬 LLM Ollama 연동</a></li>
<li><a href="/posts/spring-ai-rag-simplevectorstore-ingestion/">3편: RAG와 Vector Store 구축</a></li>
<li><a href="/posts/prompt-engineering-ai-persona-tuning/">4편: 프롬프트 엔지니어링 실전</a></li>
</ul>
<h2 id="1-서론-ai-답변-왜-기다리게-하나요">1. 서론: AI 답변, 왜 기다리게 하나요?</h2>
<p>사용자 경험(UX)을 위해 한 글자씩 타이핑하듯 보여주는 스트리밍 방식은 필수적입니다. 우리 프로젝트는 <strong>WebFlux</strong>와 **SSE(Server-Sent Events)**를 활용했습니다.</p>
<h2 id="2-스트리밍-시퀀스-다이어그램">2. 스트리밍 시퀀스 다이어그램</h2>
<p>서버와 클라이언트 간의 끊임없는 데이터 흐름을 살펴보세요.</p>
<div class="mermaid">
sequenceDiagram
    participant U as User
    participant S as Spring Server (Flux)
    participant A as AI Model (Ollama)
<pre><code>U-&gt;&gt;S: POST /chat (Request)
Note over S,A: Connection Stay Open
A--&gt;&gt;S: &quot;오늘의&quot; (Token 1)
S--&gt;&gt;U: data: &quot;오늘의&quot;
A--&gt;&gt;S: &quot; 사주는&quot; (Token 2)
S--&gt;&gt;U: data: &quot; 사주는&quot;
Note right of U: 사용자는 실시간으로 글자가 보임
</code></pre>
</div>
<h2 id="3-flux와-sse">3. Flux와 SSE</h2>
<p><code>MediaType.TEXT_EVENT_STREAM_VALUE</code>를 사용하여 AI가 단어(Token)를 생성할 때마다 즉시 클라이언트로 전송합니다. 비차단(Non-blocking) 방식인 WebFlux는 답변을 기다리는 동안 쓰레드를 점유하지 않아 성능적으로도 우수합니다.</p>
<h2 id="4-클라이언트에서의-처리">4. 클라이언트에서의 처리</h2>
<p>프론트엔드에서는 <code>fetch</code> API의 <code>getReader()</code>를 사용하여 한 글자씩 화면에 덧붙이는 작업을 수행합니다.</p>
<p><strong>다음 6편에서는 지금까지의 기술들을 하나로 묶어 전체 워크플로우를 심층 분석해 보겠습니다.</strong></p>
]]></content:encoded>
    </item>
    <item>
      <title>프롬프트 엔지니어링 실전: AI에게 시니컬한 개발자 페르소나 주입하기 (4편)</title>
      <link>https://chanyeols.com/posts/prompt-engineering-ai-persona-tuning/</link>
      <pubDate>Fri, 20 Mar 2026 14:30:00 +0900</pubDate>
      <guid>https://chanyeols.com/posts/prompt-engineering-ai-persona-tuning/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;[Dev-Fortune] 시리즈 다시보기&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/spring-ai-ollama-chatbot-planning/&#34;&gt;1편: 기획부터 스택 선정까지&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/ollama-spring-boot-local-llm-setup/&#34;&gt;2편: 로컬 LLM Ollama 연동&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/spring-ai-rag-simplevectorstore-ingestion/&#34;&gt;3편: RAG와 Vector Store 구축&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;1-서론-ai의-인격은-어디서-오는가&#34;&gt;1. 서론: AI의 &amp;lsquo;인격&amp;rsquo;은 어디서 오는가?&lt;/h2&gt;
&lt;p&gt;지식만 있는 AI는 백과사전일 뿐입니다. 우리가 원하는 &amp;ldquo;시니컬한 시니어 개발자&amp;rdquo; 인격을 형성하고 답변 형식을 강제하는 &lt;strong&gt;프롬프트 엔지니어링&lt;/strong&gt;을 살펴보겠습니다.&lt;/p&gt;
&lt;h2 id=&#34;2-프롬프트-조합-구조&#34;&gt;2. 프롬프트 조합 구조&lt;/h2&gt;
&lt;p&gt;시스템 지침(Persona)과 검색된 데이터, 사용자의 질문이 하나로 섞이는 과정입니다.&lt;/p&gt;
&lt;div class=&#34;mermaid&#34;&gt;
graph TD
    A[Persona: 실리콘밸리 개발자] + B[Rules: 반말/두문장] --&gt; E[System Message]
    C[Retrieved Saju Data] + D[User Message] --&gt; F[User Message with Context]
    E &amp; F --&gt; G((AI Model))
    G --&gt; H[Final Response]
&lt;/div&gt;
&lt;h2 id=&#34;3-시스템-프롬프트system-prompt-설계&#34;&gt;3. 시스템 프롬프트(System Prompt) 설계&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;apiContext&lt;/code&gt;를 통해 페르소나를 정의하고, 건조하고 시니컬한 반말 말투를 강제합니다. 특히 출력 형식을 엄격하게 통제하여 UI 일관성을 유지합니다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>[Dev-Fortune] 시리즈 다시보기</strong></p>
</blockquote>
<ul>
<li><a href="/posts/spring-ai-ollama-chatbot-planning/">1편: 기획부터 스택 선정까지</a></li>
<li><a href="/posts/ollama-spring-boot-local-llm-setup/">2편: 로컬 LLM Ollama 연동</a></li>
<li><a href="/posts/spring-ai-rag-simplevectorstore-ingestion/">3편: RAG와 Vector Store 구축</a></li>
</ul>
<h2 id="1-서론-ai의-인격은-어디서-오는가">1. 서론: AI의 &lsquo;인격&rsquo;은 어디서 오는가?</h2>
<p>지식만 있는 AI는 백과사전일 뿐입니다. 우리가 원하는 &ldquo;시니컬한 시니어 개발자&rdquo; 인격을 형성하고 답변 형식을 강제하는 <strong>프롬프트 엔지니어링</strong>을 살펴보겠습니다.</p>
<h2 id="2-프롬프트-조합-구조">2. 프롬프트 조합 구조</h2>
<p>시스템 지침(Persona)과 검색된 데이터, 사용자의 질문이 하나로 섞이는 과정입니다.</p>
<div class="mermaid">
graph TD
    A[Persona: 실리콘밸리 개발자] + B[Rules: 반말/두문장] --> E[System Message]
    C[Retrieved Saju Data] + D[User Message] --> F[User Message with Context]
    E & F --> G((AI Model))
    G --> H[Final Response]
</div>
<h2 id="3-시스템-프롬프트system-prompt-설계">3. 시스템 프롬프트(System Prompt) 설계</h2>
<p><code>apiContext</code>를 통해 페르소나를 정의하고, 건조하고 시니컬한 반말 말투를 강제합니다. 특히 출력 형식을 엄격하게 통제하여 UI 일관성을 유지합니다.</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#ff7b72">private</span><span style="color:#6e7681"> </span><span style="color:#ff7b72">final</span><span style="color:#6e7681"> </span>String<span style="color:#6e7681"> </span>apiContext<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#6e7681"> </span><span style="color:#a5d6ff">&#34;&#34;&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a5d6ff">    # 페르소나: 실리콘밸리 천재 개발자...
</span></span></span><span style="display:flex;"><span><span style="color:#a5d6ff">    # 답변 형식: 무조건 아래 두 문장 구조로만 답변해라.
</span></span></span><span style="display:flex;"><span><span style="color:#a5d6ff">    - &#34;오늘의 개발자 사주는 &#39;...&#39;다.&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a5d6ff">    - &#34;주의사항은 &#39;...&#39;이니 &#39;...&#39; 하지 않도록 조심해라.&#34;
</span></span></span><span style="display:flex;"><span><span style="color:#a5d6ff">&#34;&#34;&#34;</span>;<span style="color:#6e7681">
</span></span></span></code></pre></div><h2 id="4-few-shot-기법">4. Few-Shot 기법</h2>
<p>AI가 형식을 자꾸 어긴다면 예시를 몇 개 보여주는 Few-Shot 기법을 사용하여 일관성을 비약적으로 높일 수 있습니다.</p>
<p><strong>다음 5편에서는 답변을 실시간으로 전달하는 WebFlux 기반 스트리밍 API 구현을 알아보겠습니다.</strong></p>
]]></content:encoded>
    </item>
    <item>
      <title>Spring AI RAG 구현하기: SimpleVectorStore로 전문 지식 데이터 주입 (3편)</title>
      <link>https://chanyeols.com/posts/spring-ai-rag-simplevectorstore-ingestion/</link>
      <pubDate>Thu, 19 Mar 2026 14:30:00 +0900</pubDate>
      <guid>https://chanyeols.com/posts/spring-ai-rag-simplevectorstore-ingestion/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;[Dev-Fortune] 시리즈 다시보기&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/spring-ai-ollama-chatbot-planning/&#34;&gt;1편: 기획부터 스택 선정까지&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/ollama-spring-boot-local-llm-setup/&#34;&gt;2편: 로컬 LLM Ollama 연동&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;1-서론-ai는-어떻게-사주를-공부하는가&#34;&gt;1. 서론: AI는 어떻게 사주를 &amp;lsquo;공부&amp;rsquo;하는가?&lt;/h2&gt;
&lt;p&gt;AI에게 새로운 지식을 가르치는 방법 중 가장 경제적이고 정확한 &lt;strong&gt;RAG(Retrieval-Augmented Generation)&lt;/strong&gt; 방식을 살펴봅니다. 질문이 들어올 때마다 관련 내용을 찾아서 읽어주며 답변하게 하는 원리입니다.&lt;/p&gt;
&lt;h2 id=&#34;2-데이터-주입-프로세스-data-ingestion&#34;&gt;2. 데이터 주입 프로세스 (Data Ingestion)&lt;/h2&gt;
&lt;p&gt;JSON 파일이 어떻게 벡터화되어 메모리에 저장되는지 그 흐름을 도식화했습니다.&lt;/p&gt;
&lt;div class=&#34;mermaid&#34;&gt;
flowchart LR
    A[(sajuAPI.json)] --&gt; B[DataLoader]
    B --&gt; C[Text 정제: Key-Value형식]
    C --&gt; D[Embedding Model]
    D --&gt; E{SimpleVectorStore}
    E --&gt; F[RAM Memory]
&lt;pre&gt;&lt;code&gt;style F fill:#f96,stroke:#333,stroke-width:2px
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id=&#34;3-simplevectorstore와-dataloader&#34;&gt;3. SimpleVectorStore와 DataLoader&lt;/h2&gt;
&lt;p&gt;우리 프로젝트는 별도의 DB 없이 메모리 기반의 &lt;code&gt;SimpleVectorStore&lt;/code&gt;를 사용합니다. &lt;code&gt;UnidocuDataLoader&lt;/code&gt;는 서버 기동 시점에 JSON 데이터를 읽어 벡터로 변환하여 주입합니다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>[Dev-Fortune] 시리즈 다시보기</strong></p>
</blockquote>
<ul>
<li><a href="/posts/spring-ai-ollama-chatbot-planning/">1편: 기획부터 스택 선정까지</a></li>
<li><a href="/posts/ollama-spring-boot-local-llm-setup/">2편: 로컬 LLM Ollama 연동</a></li>
</ul>
<h2 id="1-서론-ai는-어떻게-사주를-공부하는가">1. 서론: AI는 어떻게 사주를 &lsquo;공부&rsquo;하는가?</h2>
<p>AI에게 새로운 지식을 가르치는 방법 중 가장 경제적이고 정확한 <strong>RAG(Retrieval-Augmented Generation)</strong> 방식을 살펴봅니다. 질문이 들어올 때마다 관련 내용을 찾아서 읽어주며 답변하게 하는 원리입니다.</p>
<h2 id="2-데이터-주입-프로세스-data-ingestion">2. 데이터 주입 프로세스 (Data Ingestion)</h2>
<p>JSON 파일이 어떻게 벡터화되어 메모리에 저장되는지 그 흐름을 도식화했습니다.</p>
<div class="mermaid">
flowchart LR
    A[(sajuAPI.json)] --> B[DataLoader]
    B --> C[Text 정제: Key-Value형식]
    C --> D[Embedding Model]
    D --> E{SimpleVectorStore}
    E --> F[RAM Memory]
<pre><code>style F fill:#f96,stroke:#333,stroke-width:2px
</code></pre>
</div>
<h2 id="3-simplevectorstore와-dataloader">3. SimpleVectorStore와 DataLoader</h2>
<p>우리 프로젝트는 별도의 DB 없이 메모리 기반의 <code>SimpleVectorStore</code>를 사용합니다. <code>UnidocuDataLoader</code>는 서버 기동 시점에 JSON 데이터를 읽어 벡터로 변환하여 주입합니다.</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-java" data-lang="java"><span style="display:flex;"><span><span style="color:#8b949e;font-style:italic">// 텍스트 정제 예시</span><span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span>String<span style="color:#6e7681"> </span>content<span style="color:#6e7681"> </span><span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#6e7681"> </span>String.format(<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">    </span><span style="color:#a5d6ff">&#34;it_interpretation: %s\nanti_pattern: %s\nbad_habit: %s&#34;</span>,<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span><span style="color:#6e7681">    </span>item.get(<span style="color:#a5d6ff">&#34;it_interpretation&#34;</span>),<span style="color:#6e7681"> </span>...<span style="color:#6e7681">
</span></span></span><span style="display:flex;"><span>);<span style="color:#6e7681">
</span></span></span></code></pre></div><h2 id="4-유사도-검색similarity-search">4. 유사도 검색(Similarity Search)</h2>
<p>사용자가 &ldquo;프로젝트 마감&quot;에 대해 물으면, 벡터 저장소는 의미적으로 유사한 사주 데이터 상위 3개를 찾아 AI에게 전달합니다.</p>
<p><strong>다음 4편에서는 이 데이터를 기반으로 시니컬한 말투를 생성하는 &lsquo;프롬프트 엔지니어링&rsquo;에 대해 다뤄보겠습니다.</strong></p>
]]></content:encoded>
    </item>
    <item>
      <title>로컬 LLM Ollama와 Spring Boot 연동하기: 서버 설정과 성능 최적화 (2편)</title>
      <link>https://chanyeols.com/posts/ollama-spring-boot-local-llm-setup/</link>
      <pubDate>Wed, 18 Mar 2026 14:30:00 +0900</pubDate>
      <guid>https://chanyeols.com/posts/ollama-spring-boot-local-llm-setup/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;[Dev-Fortune] 시리즈 다시보기&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://chanyeols.com/posts/spring-ai-ollama-chatbot-planning/&#34;&gt;1편: 기획부터 스택 선정까지&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;1-서론-왜-유료-api-대신-로컬-llm인가&#34;&gt;1. 서론: 왜 유료 API 대신 로컬 LLM인가?&lt;/h2&gt;
&lt;p&gt;이번 2편에서는 본격적인 구현의 첫 단추인 &lt;strong&gt;AI 모델 환경 구축&lt;/strong&gt;을 다룹니다. 우리는 비용 제로, 데이터 보안, 완전한 통제를 위해 &lt;strong&gt;Ollama&lt;/strong&gt;를 활용한 로컬 LLM 방식을 선택했습니다.&lt;/p&gt;
&lt;h2 id=&#34;2-로컬-ai-서버-연동-구조&#34;&gt;2. 로컬 AI 서버 연동 구조&lt;/h2&gt;
&lt;p&gt;Spring Boot가 로컬에서 실행 중인 Ollama와 통신하는 물리적 구조입니다.&lt;/p&gt;
&lt;div class=&#34;mermaid&#34;&gt;
graph LR
    subgraph &#34;Local PC&#34;
        A[Spring Boot App] -- &#34;HTTP Post (11434)&#34; --&gt; B[Ollama Server]
        B -- &#34;Model Load&#34; --&gt; C[qwen2.5:3b]
&lt;pre&gt;&lt;code&gt;    subgraph &amp;quot;Application.properties&amp;quot;
        D[Base-URL]
        E[Temperature: 0.4]
        F[Model Name]
    end
    D -.-&amp;gt; A
    E -.-&amp;gt; A
end
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id=&#34;3-spring-boot-프로젝트-설정-applicationproperties&#34;&gt;3. Spring Boot 프로젝트 설정: application.properties&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;application.properties&lt;/code&gt; 파일에 담긴 설정값들을 하나씩 뜯어보며 그 의미를 파헤쳐 보겠습니다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<blockquote>
<p><strong>[Dev-Fortune] 시리즈 다시보기</strong></p>
<ul>
<li><a href="/posts/spring-ai-ollama-chatbot-planning/">1편: 기획부터 스택 선정까지</a></li>
</ul>
</blockquote>
<h2 id="1-서론-왜-유료-api-대신-로컬-llm인가">1. 서론: 왜 유료 API 대신 로컬 LLM인가?</h2>
<p>이번 2편에서는 본격적인 구현의 첫 단추인 <strong>AI 모델 환경 구축</strong>을 다룹니다. 우리는 비용 제로, 데이터 보안, 완전한 통제를 위해 <strong>Ollama</strong>를 활용한 로컬 LLM 방식을 선택했습니다.</p>
<h2 id="2-로컬-ai-서버-연동-구조">2. 로컬 AI 서버 연동 구조</h2>
<p>Spring Boot가 로컬에서 실행 중인 Ollama와 통신하는 물리적 구조입니다.</p>
<div class="mermaid">
graph LR
    subgraph "Local PC"
        A[Spring Boot App] -- "HTTP Post (11434)" --> B[Ollama Server]
        B -- "Model Load" --> C[qwen2.5:3b]
<pre><code>    subgraph &quot;Application.properties&quot;
        D[Base-URL]
        E[Temperature: 0.4]
        F[Model Name]
    end
    D -.-&gt; A
    E -.-&gt; A
end
</code></pre>
</div>
<h2 id="3-spring-boot-프로젝트-설정-applicationproperties">3. Spring Boot 프로젝트 설정: application.properties</h2>
<p><code>application.properties</code> 파일에 담긴 설정값들을 하나씩 뜯어보며 그 의미를 파헤쳐 보겠습니다.</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-properties" data-lang="properties"><span style="display:flex;"><span>spring.ai.ollama.base-url<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">http://localhost:11434</span>
</span></span><span style="display:flex;"><span>spring.ai.ollama.chat.options.model<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">qwen2.5:3b</span>
</span></span><span style="display:flex;"><span>spring.ai.ollama.chat.options.num-ctx<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">4096</span>
</span></span><span style="display:flex;"><span>spring.ai.ollama.chat.options.temperature<span style="color:#ff7b72;font-weight:bold">=</span><span style="color:#a5d6ff">0.4</span>
</span></span></code></pre></div><h3 id="핵심-파라미터-분석">핵심 파라미터 분석</h3>
<ul>
<li><strong>temperature=0.4</strong>: 사주라는 데이터에 기반하되, 개발자 특유의 시니컬한 변주를 주기 위한 최적의 밸런스입니다.</li>
<li><strong>num-ctx=4096</strong>: AI가 한 번에 기억할 수 있는 대화의 맥락 크기입니다.</li>
</ul>
<h2 id="4-spring-ai의-chatclient">4. Spring AI의 ChatClient</h2>
<p>설정을 마쳤다면 코드에서는 <code>ChatClient</code>를 통해 아주 간편하게 AI와 대화할 수 있습니다.</p>
<p><strong>다음 3편에서는 메모리 기반 벡터 저장소(<code>SimpleVectorStore</code>)를 활용하여 사주 데이터를 AI에게 학습시키는 RAG 시스템 구축 과정을 다루겠습니다.</strong></p>
]]></content:encoded>
    </item>
    <item>
      <title>Spring AI와 Ollama로 만드는 AI 개발자 사주 챗봇: 기획부터 스택 선정까지 (1편)</title>
      <link>https://chanyeols.com/posts/spring-ai-ollama-chatbot-planning/</link>
      <pubDate>Tue, 17 Mar 2026 14:30:00 +0900</pubDate>
      <guid>https://chanyeols.com/posts/spring-ai-ollama-chatbot-planning/</guid>
      <description>&lt;h2 id=&#34;1-프롤로그-왜-ai-개발자-사주인가&#34;&gt;1. 프롤로그: 왜 &amp;lsquo;AI 개발자&amp;rsquo; 사주인가?&lt;/h2&gt;
&lt;p&gt;전통적인 사주 풀이는 어렵고 따분합니다. &amp;ldquo;올해는 물의 기운이 강하니&amp;hellip;&amp;rdquo; 같은 말은 현대의 개발자들에게는 다소 와닿지 않죠. 하지만 만약 **&amp;ldquo;실리콘밸리 출신의 천재 개발자&amp;rdquo;**가 당신의 인생을 코드로 보고 &amp;lsquo;디버깅&amp;rsquo;해준다면 어떨까요?&lt;/p&gt;
&lt;p&gt;이 프로젝트는 바로 그 엉뚱한 상상에서 시작되었습니다. 감정 섞인 위로 대신, 건조하고 시니컬한 말투로 당신의 사주를 &amp;ldquo;안티 패턴&amp;quot;과 &amp;ldquo;배드 해빗(Bad Habit)&amp;ldquo;으로 분석해 주는 챗봇, **&amp;lsquo;Dev-Fortune&amp;rsquo;**입니다.&lt;/p&gt;
&lt;h2 id=&#34;2-프로젝트-시스템-구조도&#34;&gt;2. 프로젝트 시스템 구조도&lt;/h2&gt;
&lt;p&gt;전체적인 데이터 흐름과 기술 스택을 한눈에 살펴보겠습니다.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="1-프롤로그-왜-ai-개발자-사주인가">1. 프롤로그: 왜 &lsquo;AI 개발자&rsquo; 사주인가?</h2>
<p>전통적인 사주 풀이는 어렵고 따분합니다. &ldquo;올해는 물의 기운이 강하니&hellip;&rdquo; 같은 말은 현대의 개발자들에게는 다소 와닿지 않죠. 하지만 만약 **&ldquo;실리콘밸리 출신의 천재 개발자&rdquo;**가 당신의 인생을 코드로 보고 &lsquo;디버깅&rsquo;해준다면 어떨까요?</p>
<p>이 프로젝트는 바로 그 엉뚱한 상상에서 시작되었습니다. 감정 섞인 위로 대신, 건조하고 시니컬한 말투로 당신의 사주를 &ldquo;안티 패턴&quot;과 &ldquo;배드 해빗(Bad Habit)&ldquo;으로 분석해 주는 챗봇, **&lsquo;Dev-Fortune&rsquo;**입니다.</p>
<h2 id="2-프로젝트-시스템-구조도">2. 프로젝트 시스템 구조도</h2>
<p>전체적인 데이터 흐름과 기술 스택을 한눈에 살펴보겠습니다.</p>
<div class="mermaid">
graph TD
    A[사용자 고민 입력] --> B[Spring Boot Application]
    subgraph "Backend Stack"
        B --> C{Spring AI}
        C --> D[WebFlux/Streaming]
        C --> E[SimpleVectorStore]
    end
    subgraph "AI Engine"
        C -- HTTP:11434 --- F[Ollama: qwen2.5]
    end
    subgraph "Data Source"
        G[(sajuAPI.json)] --> E
    end
    B --> H[시니컬한 개발자 사주 답변]
</div>
<h2 id="3-기술-스택-the-stack">3. 기술 스택 (The Stack)</h2>
<ul>
<li><strong>Framework</strong>: Spring Boot 3.x</li>
<li><strong>AI Library</strong>: <strong>Spring AI</strong></li>
<li><strong>LLM</strong>: <strong>Ollama</strong> (qwen2.5:3b)</li>
<li><strong>Vector DB</strong>: <code>SimpleVectorStore</code></li>
<li><strong>Data Source</strong>: JSON 기반의 사주 풀이 데이터</li>
</ul>
<h2 id="4-왜-spring-ai와-rag인가">4. 왜 Spring AI와 RAG인가?</h2>
<p>일반적인 모델은 사주에 대한 지식이 파편화되어 있거나, 우리가 원하는 특유의 &ldquo;개발자 스타일&quot;로 대답하도록 통제하기 어렵습니다. 이를 해결하기 위해 우리는 <strong>RAG(Retrieval-Augmented Generation)</strong> 기법을 사용하여 전문 사주 데이터를 미리 벡터화해서 저장해 둡니다.</p>
<p>다음 편에서는 <strong>Ollama를 이용해 내 컴퓨터에 로컬 AI 환경을 구축하고 Spring Boot와 연결하는 방법</strong>을 알아보겠습니다.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
