[AI] 웹 화면으로 띄워보자.

늘 공부하는 괴짜·2025년 4월 25일
0

AI : mcp

목록 보기
3/9

LG 연구소에서 만든 exaone3.5 모델을 테스트해 봤다. llama, gemma 는 못쓰겠...
자꾸 파라미터로 이전 args 를 참조하는 탓에 chat_history 를 제거한 상태로 테스트했다.

1. main.py

from fastapi import FastAPI, Request, Form
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from fastapi.staticfiles import StaticFiles
from langchain.chat_models import ChatOllama
from langchain.agents import initialize_agent, AgentType
from langchain.tools import Tool
from langchain.schema import SystemMessage
from pydantic import BaseModel
import re

app = FastAPI()
templates = Jinja2Templates(directory="templates")

app.mount("/static", StaticFiles(directory="static"), name="static")

# Pydantic 스키마
class WeatherInput(BaseModel):
    location: str

# MCP 스타일 로그 출력용 데코레이터
def mcp_tool(func):
    def wrapper(*args, **kwargs):
        print(f"\n==== MCP_TOOL '{func.__name__}' CALLED ====")
        print(f"args: {args}")
        print(f"kwargs: {kwargs}")
        return func(*args, **kwargs)
    return wrapper

# 날씨 도구 함수 정의
@mcp_tool
def get_weather(*args, **kwargs):
    location = None
    if args and isinstance(args[0], str):
        location = re.sub(r'\s*\([^)]*\)', '', args[0]).strip()
    if not location and kwargs.get("location"):
        location = re.sub(r'\s*\([^)]*\)', '', kwargs["location"]).strip()
    if not location:
        raise ValueError("위치 정보가 필요합니다. 어느 지역의 날씨를 알고 싶으신가요?")
    return f"{location}의 날씨는 맑고 온도는 22°C입니다."

# 도구 정의
weather_tool = Tool(
    name="get_weather",
    func=get_weather,
    description="명확한 위치(예: 도시 이름 등)가 있는 경우에만 이 도구를 사용하세요.",
    system_message=SystemMessage(
        content="‘get_weather’ 도구는 반드시 명확한 위치 정보(예: 서울, 부산 등)가 포함되어 있을 때만 호출해야 합니다. "
                "위치 정보가 없거나 모호하면 절대 호출하지 마세요."
                "폭언이나 폭력적인 내용이 있다면 자제하라는 문구를 출력하세요."
    ),
    args_schema=WeatherInput
)

# LLM 설정
llm = ChatOllama(model="exaone3.5:2.4b")

# 요청마다 agent를 새로 생성
def create_agent():
    return initialize_agent(
        tools=[weather_tool],
        llm=llm,
        agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
        verbose=False,
        handle_parsing_errors=True,
        max_iterations=5,
        agent_kwargs={
            "system_message": SystemMessage(
                content="당신은 사용자의 질문에 날씨를 제공하는 어시스턴트입니다. "
                        "위치가 명확하지 않으면 먼저 사용자에게 물어보세요. "
                        "명확한 지명이 없으면 get_weather 도구를 호출하지 마세요."
                        "폭언이나 폭력적인 내용이 있다면 자제하라는 문구를 출력하세요."
            )
        }
    )

@app.get("/", response_class=HTMLResponse)
async def get_index(request: Request):
    return templates.TemplateResponse("index.html", {"request": request, "response": ""})

@app.post("/", response_class=HTMLResponse)
async def post_index(request: Request, user_input: str = Form(...)):
    try:
        agent = create_agent()
        response = agent.run(user_input)
    except Exception as e:
        response = "오류 발생: " + str(e)
    return templates.TemplateResponse("index.html", {"request": request, "response": response})

2. index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>날씨 챗봇</title>
</head>
<body>
    <h1>날씨 챗봇</h1>
    <form method="post">
        <input type="text" name="user_input" placeholder="날씨를 물어보세요" style="width: 300px;" required>
        <button type="submit">보내기</button>
    </form>
    <p><strong>응답:</strong> {{ response }}</p>
</body>
</html>

3. 실행

% .venv\bin\activate
% uvicorn main:app --reload

4. 화면

5. 질의

5-1. 다짜고짜 묻기.

질문 : 날씨 알려줘

5-2. 애매하게 붇기.

질문 : 서울인지 울산인지, 부산인지 날씨 알려줘
오? 똑똑한데?

5-3. 폭언 첨가.

질문 : X발 날씨 알려달라고!
AI는 친절하게 요청하라고 말해준다.

5-4. 서울의 날씨는?

질문 : 서울 날씨
사실 지금 서울의 기온은 22도가 아니지만 get_weather 툴을 사용했기 때문에 22도라고 표시된 것이다.

Finally

역시 한국말을 조금을 잘 알아듣는 듯 했다. 7.8b 도 테스트 했지만 뭔가 결과가 엄청 더디고 정확도도 떨어졌는데 오히려 2.5b 가 잘 나오는 듯 했다.

profile
인공지능이라는 옷을 입었습니다. 뭔가 멋지면서도 잘 맞습니다.

0개의 댓글