LG 연구소에서 만든 exaone3.5 모델을 테스트해 봤다. llama, gemma 는 못쓰겠...
자꾸 파라미터로 이전 args 를 참조하는 탓에 chat_history 를 제거한 상태로 테스트했다.
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})
<!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>
% .venv\bin\activate
% uvicorn main:app --reload
질문 : 날씨 알려줘
질문 : 서울인지 울산인지, 부산인지 날씨 알려줘
오? 똑똑한데?
질문 : X발 날씨 알려달라고!
AI는 친절하게 요청하라고 말해준다.
질문 : 서울 날씨
사실 지금 서울의 기온은 22도가 아니지만 get_weather 툴을 사용했기 때문에 22도라고 표시된 것이다.
역시 한국말을 조금을 잘 알아듣는 듯 했다. 7.8b 도 테스트 했지만 뭔가 결과가 엄청 더디고 정확도도 떨어졌는데 오히려 2.5b 가 잘 나오는 듯 했다.