@@ -62,36 +62,80 @@ dependencyManagement {
6262}
6363```
6464
65- ### 2. application.yml 설정
65+ ### 2. .env 파일 설정 (우리 프로젝트 방식)
66+
67+ 프로젝트 루트에 ` .env ` 파일 생성:
68+ ``` env
69+ GROQ_API_KEY=gsk_your_groq_api_key_here
70+ WEATHER_API_KEY=your_weather_api_key_here
71+ ```
72+
73+ ### 3. BackendApplication.kt - dotenv 로딩
74+
75+ ``` kotlin
76+ import io.github.cdimascio.dotenv.dotenv
77+ import org.springframework.boot.autoconfigure.SpringBootApplication
78+ import org.springframework.boot.runApplication
79+
80+ @SpringBootApplication
81+ class BackendApplication
82+
83+ fun main (args : Array <String >) {
84+ // .env 파일 로딩 (Spring보다 먼저 실행)
85+ val dotenv = dotenv {
86+ ignoreIfMissing = true
87+ ignoreIfMalformed = true
88+ }
89+ dotenv.entries().forEach { entry ->
90+ System .setProperty(entry.key, entry.value)
91+ }
92+
93+ runApplication<BackendApplication >(* args)
94+ }
95+ ```
96+
97+ ### 4. application.yml 설정
6698
6799``` yaml
68100spring :
69101 ai :
70102 openai :
71103 api-key : ${GROQ_API_KEY}
72- # Groq API 사용 (OpenAI 호환)
73- base-url : https://api.groq.com/openai
104+ base-url : https://api.groq.com/openai # /v1 자동 추가됨
74105 chat :
75106 options :
76- model : openai/gpt-oss-120b # Groq의 오픈소스 모델
107+ model : openai/gpt-oss-120b
77108 temperature : 0.7
78109 max-tokens : 4096
79110
80- # 또는 OpenAI 직접 사용시:
81- # spring:
82- # ai:
83- # openai:
84- # api-key: ${OPENAI_API_KEY}
85- # chat:
86- # options:
87- # model: gpt-4o
88- # temperature: 0.7
89-
111+ # 날씨 API 설정 (기상청)
112+ weather :
113+ api :
114+ key : ${WEATHER_API_KEY}
115+ base-url : http://apis.data.go.kr/1360000/MidFcstInfoService
116+
90117logging :
91118 level :
92119 org.springframework.ai : DEBUG
93120` ` `
94121
122+ ### 5. WebClientConfig.kt - HTTP 클라이언트 설정
123+
124+ ` ` ` kotlin
125+ import org.springframework.context.annotation.Bean
126+ import org.springframework.context.annotation.Configuration
127+ import org.springframework.web.reactive.function.client.WebClient
128+
129+ @Configuration
130+ class WebClientConfig {
131+ @Bean
132+ fun webClient() : WebClient {
133+ return WebClient.builder().build()
134+ }
135+ }
136+ ```
137+ ```
138+
95139---
96140
97141## Tool/Function Calling
@@ -134,7 +178,7 @@ class WeatherService {
134178}
135179```
136180
137- ### Tool 등록 및 사용
181+ ### 6. AiConfig.kt - ChatClient 설정 (우리 프로젝트)
138182
139183``` kotlin
140184import org.springframework.ai.chat.client.ChatClient
@@ -144,14 +188,12 @@ import org.springframework.context.annotation.Configuration
144188
145189@Configuration
146190class AiConfig {
147-
191+
148192 @Bean
149- fun chatClient (
150- chatModel : ChatModel ,
151- weatherService : WeatherService // @Tool이 있는 서비스 주입
152- ): ChatClient {
193+ fun chatClient (chatModel : ChatModel , weatherTool : WeatherTool ): ChatClient {
194+ println (" 📌 Registering WeatherTool with @Tool methods" )
153195 return ChatClient .builder(chatModel)
154- .defaultTools(weatherService ) // Tool 자동 감지 및 등록
196+ .defaultTools(weatherTool ) // @ Tool 어노테이션 자동 감지
155197 .build()
156198 }
157199}
@@ -161,18 +203,55 @@ class AiConfig {
161203
162204## ChatClient 사용법
163205
164- ### 기본 사용
206+ ### ChatController - 실제 엔드포인트 (우리 프로젝트)
165207
166208``` kotlin
209+ import org.springframework.ai.chat.client.ChatClient
210+ import org.springframework.web.bind.annotation.*
211+
167212@RestController
168- class ChatController (private val chatClient : ChatClient ) {
169-
213+ @CrossOrigin
214+ class ChatController (
215+ private val chatClient : ChatClient ,
216+ private val weatherTool : WeatherTool
217+ ) {
218+
170219 @GetMapping(" /chat" )
171220 fun chat (@RequestParam message : String ): String {
172- return chatClient.prompt()
173- .user(message)
174- .call()
175- .content() ? : " 응답 없음"
221+ println (" 🚀 사용자 메시지: $message " )
222+
223+ return try {
224+ val response = chatClient.prompt()
225+ .user(message)
226+ .call()
227+ .content()
228+
229+ println (" 🤖 AI 응답: $response " )
230+ response ? : " 응답을 받을 수 없습니다."
231+ } catch (e: Exception ) {
232+ println (" ❌ 오류 발생: ${e.message} " )
233+ " 오류가 발생했습니다: ${e.message} "
234+ }
235+ }
236+
237+ // 디버그용 날씨 API 직접 호출
238+ @GetMapping(" /weather/debug" )
239+ fun debugWeatherApi (
240+ @RequestParam(defaultValue = " 서울" ) location : String
241+ ): Map <String , Any ?> {
242+ return try {
243+ val response = weatherTool.getWeatherForecast(location, null , null )
244+ mapOf (
245+ " success" to true ,
246+ " location" to location,
247+ " response" to response
248+ )
249+ } catch (e: Exception ) {
250+ mapOf (
251+ " success" to false ,
252+ " error" to (e.message ? : " 알 수 없는 오류" )
253+ )
254+ }
176255 }
177256}
178257```
@@ -327,6 +406,52 @@ spring:
327406
328407---
329408
409+ ## 🚀 실행 및 테스트 방법
410+
411+ ### 1. API 키 발급
412+
413+ #### Groq API 키 발급
414+ 1 . [ Groq Console] ( https://console.groq.com/ ) 접속
415+ 2 . 계정 생성 후 로그인
416+ 3 . API Keys 메뉴에서 새 키 생성
417+ 4 . ` gsk_... ` 형태의 키 복사
418+
419+ #### 기상청 API 키 발급
420+ 1 . [ 기상청 Open API] ( https://www.data.go.kr/data/15084084/openapi.do ) 접속
421+ 2 . 중기예보조회서비스 신청
422+ 3 . 승인 후 서비스 키 발급 (1-2일 소요)
423+
424+ ### 2. 애플리케이션 실행
425+
426+ ``` bash
427+ # 1. 프로젝트 클론
428+ git clone https://github.com/Mrbaeksang/spring-ai-weather-tool.git
429+ cd spring-ai-weather-tool
430+
431+ # 2. .env 파일 생성
432+ echo " GROQ_API_KEY=your_groq_key_here" > .env
433+ echo " WEATHER_API_KEY=your_weather_key_here" >> .env
434+
435+ # 3. 빌드 및 실행
436+ ./gradlew bootRun
437+ ```
438+
439+ ### 3. 테스트
440+
441+ #### 브라우저 테스트
442+ ```
443+ http://localhost:8080/chat?message=서울 날씨 어때?
444+ http://localhost:8080/chat?message=부산 3일 후 날씨는?
445+ http://localhost:8080/weather/debug?location=제주
446+ ```
447+
448+ #### 예상 응답
449+ ```
450+ AI 응답: "서울 3일 후 날씨는 맑을 예정이고, 기온은 15-25도, 강수확률은 오전 20% 오후 30%입니다."
451+ ```
452+
453+ ---
454+
330455## 실전 예제
331456
332457### 실제 프로젝트 예제 (WeatherTool - 우리 프로젝트)
0 commit comments