반응형
앞선 글에서 로컬 LLM을 이용하여 에이전틱 프로그래밍 데모 해보기 를 진행해보았다.
하지만 문제가 있었는데, 테스트로 xeyes 를 만들어보라고 했을 때, llama3.1:8b 모델은 경량이라 그런지 하는 시늉만 하는 느낌이었다.
그래서 Google Gemini 를 연동하여 해보고자 한다.
문제점 발견 : llama 모델의 한계
llama 모델이 시늉만 한다는 내역을 아래와 같이 확인할 수 있다.
아래의 코드로 에이전트를 통해서 xeyes 프로그램을 생성하도록 실행시켜보았다.
더보기
import os
from crewai import Agent, Task, Crew, LLM
# 1. 로컬 Ollama 환경 설정
# Ollama는 기본적으로 11434 포트에서 OpenAI와 호환되는 로컬 API 서버를 제공합니다.
os.environ["OPENAI_API_KEY"] = "ollama" # 로컬 환경이므로 임의의 문자열을 넣으면 됩니다.
# 가지고 계신 8B 모델의 정확한 이름으로 변경하세요 (예: 'llama3', 'gemma:7b', 'phi3' 등)
target_model = "llama3.1:8b"
llm = LLM(
model=target_model,
base_url="http://localhost:11434",
temperature=0.1
)
# 2. 에이전트 정의
developer = Agent(
role='GUI 프로그래밍 전문가',
goal='요구사항을 완벽히 준수하는 파이썬 코드를 작성합니다.',
backstory='당신은 특히 tkinter의 Canvas 위젯 작업 시 "이전 프레임 삭제(delete)"와 "정확한 좌표 계산"을 가장 중요하게 생각합니다.',
llm=llm
)
reviewer = Agent(
role='코드 품질 및 로직 검수관',
goal='작성된 코드에서 불필요한 기능(코 등)이 포함되었는지, 화면 초기화 로직이 있는지 검사합니다.',
backstory='당신은 사용자의 요구사항에 없는 기능이 추가되는 것을 극도로 싫어하며, 리소스 낭비(초기화 누락)를 찾아내는 전문가입니다.',
llm=llm
)
# 3. 작업 정의 (문제를 명시적으로 해결하도록 지시)
coding_task = Task(
description='''
파이썬 tkinter를 이용해 xeyes를 만드세요.
[필수 해결 과제]
1. 화면 갱신 시 반드시 canvas.delete("all")을 호출하여 잔상이 남지 않게 하세요.
2. '두 눈(흰자)'과 '두 눈동자(검은색)'만 그리세요. 코(Nose)나 입 등 다른 얼굴 부위는 절대로 그리지 마세요.
3. 눈동자는 반드시 눈(흰자)의 영역 안에서만 움직여야 합니다. (삼각함수 사용)
''',
expected_output='버그가 수정된 파이썬 소스 코드',
agent=developer
)
review_task = Task(
description='''
전달받은 코드를 검토하세요.
- canvas.delete("all") 혹은 유사한 초기화 코드가 없다면 다시 작성하도록 지시하세요.
- 코(Nose)를 그리는 코드가 포함되어 있다면 즉시 삭제하세요.
- 모든 검토가 끝나면 최종 코드를 'fixed_xeyes.py'로 저장하세요.
''',
expected_output='최종 검수 완료된 파이썬 코드',
output_file='fixed_xeyes.py',
agent=reviewer,
context=[coding_task]
)
# 4. 실행
crew = Crew(
agents=[developer, reviewer],
tasks=[coding_task, review_task],
verbose=True
)
crew.kickoff()
llama3.1:8b의 결과물
마우스 움직임에 눈이 따라다니지 않는다..
심지어 생성 결과에 따라서는 실행 조차 되지 않는 경우가 있었다.

생성된 코드는 아래 접은 글을 펼쳐서 확인 할 수 있다.
더보기
# ```python
import tkinter as tk
import math
class Xeyes:
def __init__(self):
self.root = tk.Tk()
self.canvas = tk.Canvas(self.root, width=400, height=400)
self.canvas.pack()
self.eye_radius = 50
self.pupil_radius = 10
self.eye_x = 200
self.eye_y = 150
def update(self):
self.canvas.delete("all") # 초기화 코드 추가
self.canvas.create_oval(self.eye_x - self.eye_radius, self.eye_y - self.eye_radius,
self.eye_x + self.eye_radius, self.eye_y + self.eye_radius)
self.canvas.create_oval(self.eye_x - self.pupil_radius, self.eye_y - self.pupil_radius,
self.eye_x + self.pupil_radius, self.eye_y + self.pupil_radius)
def move_pupil(self):
angle = 0
x = self.eye_x + (self.eye_radius - self.pupil_radius) * math.cos(angle)
y = self.eye_y + (self.eye_radius - self.pupil_radius) * math.sin(angle)
self.canvas.create_oval(x - self.pupil_radius, y - self.pupil_radius,
x + self.pupil_radius, y + self.pupil_radius)
def run(self):
self.root.after(1000 // 60, self.update)
self.move_pupil()
self.root.mainloop()
xeyes = Xeyes()
xeyes.run()
# ```
Gemini 연동하기
Gemini 연동에 필요한 구글 SDK 패키지를 추가로 설치해야한다.
아래의 명령어로 설치하도록 하자.
pip install langchain-google-genai
Gemini API Key 획득하기
- Google AI Studio 접속: Google AI Studio (aistudio.google.com)에 Google 계정으로 로그인합니다.
- API 키 생성: 좌측 메뉴에서 **'Get API key'**를 클릭한 후, 'Create API key' 버튼을 누릅니다.
- 프로젝트 선택: 새로운 Google Cloud 프로젝트를 생성하거나 기존 프로젝트를 선택하여 키를 발급받습니다.
- 키 복사: 생성된 AIzaSy... 로 시작하는 문자열을 복사해 둡니다. 이 키는 절대 외부에 노출되지 않도록 주의해야 합니다.
Gemini 를 연동하기 위한 코드 수정하기
앞선 코드의 상단을 아래와 같이 바꾼다.
# 1. Google Gemini 환경 설정
# 발급받은 구글 API 키를 환경 변수에 등록합니다.
os.environ["GEMINI_API_KEY"] = "AIza*****"
# CrewAI 내부의 LiteLLM 라우터를 통해 Gemini를 호출합니다.
# 모델 이름 앞에 'gemini/'를 붙여주는 것이 핵심입니다.
llm = LLM(
# model="gemini/gemini-2.5-pro", # 가장 똑똑하고 추론 능력이 뛰어난 Pro 모델 (복잡한 코딩, 아키텍처 설계용)
model="gemini/gemini-2.5-flash", # 빠르고 가성비가 좋은 Flash 모델 (가벼운 스크립트, 데모 테스트용)
temperature=0.1
)
전체 코드는 아래의 접은 글을 펼쳐서 확인할 수 있다.
더보기
import os
from crewai import Agent, Task, Crew, LLM
# 1. Google Gemini 환경 설정
# 발급받은 구글 API 키를 환경 변수에 등록합니다.
os.environ["GEMINI_API_KEY"] = "AIza****"
# CrewAI 내부의 LiteLLM 라우터를 통해 Gemini를 호출합니다.
# 모델 이름 앞에 'gemini/'를 붙여주는 것이 핵심입니다.
llm = LLM(
# model="gemini/gemini-2.5-pro", # 가장 똑똑하고 추론 능력이 뛰어난 Pro 모델 (복잡한 코딩, 아키텍처 설계용)
model="gemini/gemini-2.5-flash", # 빠르고 가성비가 좋은 Flash 모델 (가벼운 스크립트, 데모 테스트용)
temperature=0.1
)
# 2. 에이전트 정의
developer = Agent(
role='GUI 프로그래밍 전문가',
goal='요구사항을 완벽히 준수하는 파이썬 코드를 작성합니다.',
backstory='당신은 특히 tkinter의 Canvas 위젯 작업 시 "이전 프레임 삭제(delete)"와 "정확한 좌표 계산"을 가장 중요하게 생각합니다.',
llm=llm
)
reviewer = Agent(
role='코드 품질 및 로직 검수관',
goal='작성된 코드에서 불필요한 기능(코 등)이 포함되었는지, 화면 초기화 로직이 있는지 검사합니다.',
backstory='당신은 사용자의 요구사항에 없는 기능이 추가되는 것을 극도로 싫어하며, 리소스 낭비(초기화 누락)를 찾아내는 전문가입니다.',
llm=llm
)
# 3. 작업 정의 (문제를 명시적으로 해결하도록 지시)
coding_task = Task(
description='''
파이썬 tkinter를 이용해 xeyes를 만드세요.
[필수 해결 과제]
1. 화면 갱신 시 반드시 canvas.delete("all")을 호출하여 잔상이 남지 않게 하세요.
2. '두 눈(흰자)'과 '두 눈동자(검은색)'만 그리세요. 코(Nose)나 입 등 다른 얼굴 부위는 절대로 그리지 마세요.
3. 눈동자는 반드시 눈(흰자)의 영역 안에서만 움직여야 합니다. (삼각함수 사용)
''',
expected_output='버그가 수정된 파이썬 소스 코드',
agent=developer
)
review_task = Task(
description='''
전달받은 코드를 검토하세요.
- canvas.delete("all") 혹은 유사한 초기화 코드가 없다면 다시 작성하도록 지시하세요.
- 코(Nose)를 그리는 코드가 포함되어 있다면 즉시 삭제하세요.
- 모든 검토가 끝나면 최종 코드를 'fixed_xeyes.py'로 저장하세요.
''',
expected_output='최종 검수 완료된 파이썬 코드',
output_file='fixed_xeyes.py',
agent=reviewer,
context=[coding_task]
)
# 4. 실행
crew = Crew(
agents=[developer, reviewer],
tasks=[coding_task, review_task],
verbose=True
)
crew.kickoff()
위의 코드를 실행하면 아래의 결과를 얻을 수 있다.
마우스가 위치한 곳으로 눈동자가 움직이는 것을 확인 할 수 있다.

Gemini가 생성하는 코드가 확실히 더 괜찮은 품질의 코드를 생성하는 것을 확인했다.
Gemini가 생성한 코드는 아래 접은 글을 펼치면 나온다.
더보기
# 제시된 코드를 검토한 결과, 다음 사항을 확인했습니다.
# 1. **`canvas.delete("all")` 호출**: `draw_eyes` 함수 내에서 `self.canvas.delete("all")`이 명확하게 호출되어 이전 프레임을 지우고 잔상이 남지 않도록 합니다. 초기화 로직이 올바르게 구현되어 있습니다.
# 2. **코(Nose) 그리는 코드 포함 여부**: 코드를 면밀히 검토한 결과, 눈(흰자위)과 눈동자(검은색)를 그리는 코드 외에 코를 포함한 다른 얼굴 부위를 그리는 코드는 일절 포함되어 있지 않습니다. 불필요한 기능이 추가되지 않았습니다.
# 제시된 코드는 모든 검토 기준을 완벽하게 충족합니다. 따라서 수정할 부분이 없습니다.
# ```python
import tkinter as tk
import math
class XEyesApp:
def __init__(self, master):
self.master = master
master.title("xeyes")
master.resizable(False, False) # 창 크기 조절 방지
# 캔버스 설정
self.canvas_width = 400
self.canvas_height = 250
self.canvas = tk.Canvas(master, width=self.canvas_width, height=self.canvas_height, bg="lightgray")
self.canvas.pack()
# 눈(흰자) 및 눈동자(검은색) 파라미터 설정
self.eye_radius = 60 # 흰자위의 반지름
self.pupil_radius = 25 # 눈동자의 반지름
self.eye_offset_x = 80 # 캔버스 중앙에서 각 눈의 중심까지의 수평 거리
self.eye_offset_y = 0 # 캔버스 중앙에서 각 눈의 중심까지의 수직 거리 (현재는 중앙)
# 캔버스 중앙 좌표 계산
self.center_x = self.canvas_width / 2
self.center_y = self.canvas_height / 2
# 각 눈의 중심 좌표 계산
self.left_eye_center = (self.center_x - self.eye_offset_x, self.center_y - self.eye_offset_y)
self.right_eye_center = (self.center_x + self.eye_offset_x, self.center_y - self.eye_offset_y)
# 눈동자가 눈(흰자) 영역을 벗어나지 않도록 하는 최대 이동 거리 계산
# 눈동자 중심이 눈의 중심으로부터 이 거리 이상 떨어질 수 없습니다.
self.max_pupil_dist = self.eye_radius - self.pupil_radius
# 초기 마우스 위치 (캔버스 중앙으로 설정)
self.mouse_x = self.center_x
self.mouse_y = self.center_y
# 마우스 움직임 이벤트 바인딩
self.canvas.bind("<Motion>", self.on_mouse_move)
# 초기 화면 그리기
self.draw_eyes()
def on_mouse_move(self, event):
"""마우스 움직임 이벤트 핸들러"""
self.mouse_x = event.x
self.mouse_y = event.y
self.draw_eyes() # 마우스가 움직일 때마다 눈을 다시 그립니다.
def draw_eyes(self):
"""눈과 눈동자를 그리는 함수"""
# 1. 화면 갱신 시 반드시 canvas.delete("all")을 호출하여 잔상이 남지 않게 하세요.
self.canvas.delete("all")
# 왼쪽 눈 그리기
self._draw_single_eye(self.left_eye_center[0], self.left_eye_center[1])
# 오른쪽 눈 그리기
self._draw_single_eye(self.right_eye_center[0], self.right_eye_center[1])
def _draw_single_eye(self, eye_cx, eye_cy):
"""단일 눈(흰자)과 눈동자를 그리는 헬퍼 함수"""
# 2. '두 눈(흰자)'만 그립니다.
# 흰자위 그리기 (흰색 타원)
self.canvas.create_oval(
eye_cx - self.eye_radius, eye_cy - self.eye_radius,
eye_cx + self.eye_radius, eye_cy + self.eye_radius,
fill="white", outline="black", width=2
)
# 3. 눈동자는 반드시 눈(흰자)의 영역 안에서만 움직여야 합니다. (삼각함수 사용)
# 눈의 중심에서 마우스 위치까지의 벡터 계산
dx = self.mouse_x - eye_cx
dy = self.mouse_y - eye_cy
# 눈의 중심에서 마우스까지의 거리 계산
dist_to_mouse = math.sqrt(dx**2 + dy**2)
# 눈동자가 눈(흰자) 영역을 벗어나지 않도록 실제 이동 거리 제한
# 마우스가 멀리 있어도 눈동자는 max_pupil_dist 이상 움직이지 않습니다.
actual_pupil_dist = min(dist_to_mouse, self.max_pupil_dist)
# 눈의 중심에서 마우스까지의 각도 계산 (삼각함수 사용)
# math.atan2(y, x)는 x축 양의 방향과 점 (x, y) 사이의 각도를 라디안으로 반환합니다.
angle = math.atan2(dy, dx)
# 삼각함수를 사용하여 눈동자의 중심 좌표 계산
pupil_cx = eye_cx + actual_pupil_dist * math.cos(angle)
pupil_cy = eye_cy + actual_pupil_dist * math.sin(angle)
# 2. '두 눈동자(검은색)'만 그립니다.
# 눈동자 그리기 (검은색 타원)
self.canvas.create_oval(
pupil_cx - self.pupil_radius, pupil_cy - self.pupil_radius,
pupil_cx + self.pupil_radius, pupil_cy + self.pupil_radius,
fill="black", outline="black"
)
# 메인 실행 블록
if __name__ == "__main__":
root = tk.Tk()
app = XEyesApp(root)
root.mainloop()
# ```
*** EOF ***
728x90
'SW' 카테고리의 다른 글
| 에이전틱 프로그래밍 데모 해보기 (1/2, local LLM - Ollama) (0) | 2026.04.12 |
|---|---|
| Docker Image/Container 확인/실행/삭제 방법 (0) | 2026.04.12 |
| Ubuntu 에서 windows 의 4분할 화면 쓰는 방법 (0) | 2026.04.12 |
| WARNING: Unable to detect NVIDIA/AMD GPU on Docker (0) | 2026.03.25 |
| 설치한 Nvidia드라이버, Docker 에서 그냥 쓰기 : NVIDIA Container Toolkit (0) | 2026.03.25 |
