1. LLM 연결하기
진행하는 프로젝트에서는 AI Agent를 확장 가능한 구조로 만들고 싶었기에 Hexagonal Architecture를 기반으로 구현하려고 한다.
그런 관점에서 볼때 LLM은 외부 시스템에 해당하기 때문에 도메인 로직에서 직접 호출하지 않고 Port / Adapter 구조로 분리하여 구현되어야 한다.
이렇게 구조를 나누는 이유는
OpenLLM->ClosedLLM추가 및 변경 가능- 모델 추가 및 변경 가능
API방식 변경 가능- 테스트 가능
- 의존성 분리
즉,
1
Domain -> Port -> Adapter -> LLM
구조로 연결하도록 하기 위함이다.
이번 글에서는 그 첫번째로 Ollama를 통해서 Qwen2.5:7b 모델을 Adapter로 연결해 본다.
2. LLM Port 정의
LLM은 외부 시스템이므로 Port를 먼저 정의한다.
경로 domain/port/llm_port.py
1
2
3
4
5
6
7
8
9
from abc import ABC, abstractmethod
class LLMPort(ABC):
@abstractmethod
def generate(self, prompt: str) -> str:
pass
LLM을 사용하는 쪽에서는 이 인터페이스만 알고 있으면 된다. 이렇게 되면 Adapter를 변경해도 도메인 코드에 추가적은 추정은 필요 없어진다.
3. Ollama Adapter 구현
Adapter는 외부 시스템과 연결되는 구현체이므로 adapter레이어에 작성한다. 경로 adapter/llm/ollama_adapter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import requests
from domain.port.llm_port import LLMPort
class OllamaLLMAdapter(LLMPort):
def __init__(self, model: str):
self.model = model
self.url = "http://localhost:11434/api/generate"
def generate(self, prompt: str) -> str:
response = requests.post(
self.url,
json={
"model": self.model,
"prompt": prompt,
"stream": False
},
)
response.raise_for_status()
data = response.json()
return data["response"]
해당 Adapter는
Ollama API 호출- 모델 실행
- 결과반환
의 역할만 수행한다. 도메인 로직은 Ollama에 대해 알 필요가 없다.
4. Application Service에서 사용
Agent 실행 로직은 application 레ㅇ이어에 위치 시킨다. 경로 application/service/agent_service.py
1
2
3
4
5
6
7
8
9
10
from domain.port.llm_port import LLMPort
class AgentService:
def __init__(self, llm: LLMPort):
self.llm = llm
def ask(self, text: str) -> str:
return self.llm.generate(text)
Application은
Port만 의존Adapter모름
이게 Hexagonal Architecture의 핵심이다.
5. 실행 코드 작성
main에서 Adapter를 생성하고 Service에 주입한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from adapter.llm.ollama_adapter import OllamaLLMAdapter
from application.service.agent_service import AgentService
def main():
llm = OllamaLLMAdapter(
model="qwen2.5:7b"
)
service = AgentService(llm)
result = service.ask(
"DDD가 무엇인지 설명해줘"
)
print(result)
if __name__ == "__main__":
main()
위 코드를 실행하면 Ollama를 통해 qwen2.5:7b LLM 모델이 호출되어 응답을 받을 수 있게 된다.

6. 현재 구조
현재 구조와 의존성 방향으로 봤을떄 의도한대로 Domain은 외부 의존성을 아무것도 모르게 된다.
이런 구조를 유지하면서 기능을 계속 추가할 예정이다.
7. 다음 단계
지금은 LLM만 연결한 상태이기 때문에 Agent라고 하기에는 부족한점이 많다.
AI Agent가 되려면 외부 기능을 사용할 수 있어야 한다. 다음 글에서는 Tool에 대해 알아보고 추가하여 외부 기능을 호출할 수 있도록 기능을 확장해 본다.