local-agent: Ollama 기반 로컬 에이전트 초기 버전 구현
이번 커밋은 Ollama를 백엔드로 사용하여 개인 에이전트 루프를 구축하는 초기 버전을 구현했습니다. `qwen2:7b` 모델을 활용하며, 쉘, HTTP, 데이터베이스 도구를 사용할 수 있습니다. 특히 위험한 작업(쉘 실행, DB 쓰기, GET이 아닌 HTTP 호출)에 대해서는 사용자 확인 단계를 추가하여 안전성을 높였습니다.
요약
이 커밋은 Ollama를 통해 로컬에서 실행되는 AI 에이전트의 첫 번째 버전을 선보입니다. qwen2:7b 모델을 사용하며, 쉘, HTTP, 데이터베이스 접근 기능을 제공합니다. 중요한 변경사항은 local_agent/agent.py 파일에 새로운 에이전트 로직이 추가되었고, README.md에 프로젝트 설명과 사용법이 상세히 기재되었다는 점입니다. 총 572라인의 코드가 추가되었습니다.
배경 및 목적
개인적인 프로젝트나 업무 자동화를 위해 로컬 환경에서 강력한 AI 에이전트를 구축하고자 했습니다. 외부 API에 의존하지 않고, 사용자의 컴퓨터에서 직접 작동하며, 다양한 작업을 수행할 수 있는 에이전트가 필요했습니다. 특히 AI가 임의의 코드를 실행하거나 중요한 데이터를 변경할 수 있는 가능성을 고려하여, 안전 장치를 마련하는 것이 중요한 목적이었습니다.
구현 내용
이번 작업에서는 주로 local_agent 디렉토리 내 여러 파일들을 수정하고 새로운 기능을 추가했습니다.
주요 변경사항
- 에이전트 핵심 로직 구현 (
local_agent/agent.py):- Ollama 클라이언트와 연동하여 사용자 프롬프트에 대한 응답을 생성하고, 필요한 경우 도구를 호출하는 로직을 구현했습니다.
run_agent_turn함수는 사용자 턴을 처리하며, 최대 도구 호출 횟수를 제한하고, JSON 파싱 오류를 여러 번 연속으로 발생할 경우 대처하는 로직을 포함합니다.confirm함수를 사용하여 쉘 실행, DB 쓰기, GET 외 HTTP 호출과 같은 위험한 작업에 대한 사용자 확인 절차를 추가했습니다.
- README 문서 작성 (
README.md):- 프로젝트의 목표, 설정 방법, 실행 방법, 안전 모델(Confirmation model), 제공되는 도구 목록, 알려진 한계점, 확장 방법에 대한 상세한 설명을 추가했습니다.
- CLI 인터페이스 구현 (
local_agent/cli.py):argparse를 사용하여--yes(auto-approve),--model,--host,--max-hops등의 커맨드 라인 인자를 지원하도록 구현했습니다.- Windows 환경에서 한글 깨짐을 방지하기 위해 표준 입출력 스트림의 인코딩을 UTF-8로 설정하는 로직을 추가했습니다.
- 설정 로딩 및 관리 (
local_agent/config.py):- 기본 설정값, YAML 설정 파일, 환경 변수, CLI 인자를 순서대로 적용하여 최종 설정을 로드하는 로직을 구현했습니다.
- 도구 등록 및 관리 (
local_agent/tools/__init__.py):ToolSpec데이터 클래스와tool데코레이터를 정의하여 새로운 도구를 쉽게 등록하고 관리할 수 있도록 했습니다.- Ollama API에서 요구하는 형식으로 도구 정의를 반환하는
ollama_tool_defs함수를 추가했습니다. shell,http,database모듈을 임포트하여 해당 도구들이 자동으로 등록되도록 했습니다.
변경된 파일 목록
.gitignoreREADME.mdconfig.example.yamllocal_agent/__init__.pylocal_agent/__main__.pylocal_agent/agent.pylocal_agent/cli.pylocal_agent/config.pylocal_agent/confirmation.pylocal_agent/history.pylocal_agent/ollama_client.pylocal_agent/tools/__init__.pylocal_agent/tools/database.pylocal_agent/tools/http.pylocal_agent/tools/shell.pyrequirements.txttests/__init__.pytests/test_confirmation.pytests/test_registry.py
코드 라인 수
- 총 추가 라인: 572
- 총 삭제 라인: 0
핵심 코드 설명
local_agent/agent.py 파일의 run_agent_turn 함수는 이 커밋의 핵심 로직을 담고 있습니다.
def run_agent_turn(history: History, client: OllamaClient, auto_approve: bool, max_tool_hops: int = 8) -> bool:
# ... (이전 부분 생략) ...
for _hop in range(max_tool_hops):
response = client.chat(messages=history.as_list(), tools=ollama_tool_defs())
message = _get(response, "message")
tool_calls = _get(message, "tool_calls")
content = _get(message, "content") or ""
if content:
print(content)
if not tool_calls:
history.append({"role": "assistant", "content": content})
return auto_approve
history.append({"role": "assistant", "content": content, "tool_calls": tool_calls})
# ... (도구 실행 및 결과 처리 로직) ...
decision = confirm(name, args, auto_approve) # 사용자 확인
if decision == "always":
auto_approve = True
decision = True
if not decision:
result = {"error": "user declined to execute this tool call"}
else:
try:
result = spec.fn(**args) # 실제 도구 함수 실행
except TypeError as e:
result = {"error": f"invalid arguments for {name}: {e}"}
except Exception as e:
result = {"error": f"tool execution failed: {e}"}
history.append_tool_result(name, result)
# ... (이후 부분 생략) ...
이 코드는 Ollama 모델로부터 응답을 받고, tool_calls이 존재하면 각 도구 호출에 대해 confirm 함수를 통해 사용자 승인을 받습니다. 승인된 도구는 spec.fn(**args)를 통해 실행되며, 결과는 다시 history에 기록됩니다.
기술적 의사결정
이 단계에서는 특별히 복잡한 기술적 의사결정은 없었지만, 몇 가지 고려사항이 있었습니다.
- LLM 백엔드 선택: Ollama를 선택한 이유는 로컬 환경에서 다양한 모델을 쉽게 실행하고 관리할 수 있다는 점 때문입니다. 외부 API 의존성을 줄이고 싶었고, Ollama는 이를 충족하는 좋은 솔루션이었습니다.
- 도구 호출 방식: Ollama의 네이티브
tool_callingAPI를 활용하기로 결정했습니다. 이는 모델이 자체적으로 도구 사용을 판단하고 인자를 생성하도록 유도하는 효과적인 방법입니다. - 안전 기능 구현: 쉘 실행, DB 쓰기 등은 잠재적으로 위험할 수 있으므로,
confirm함수를 통해 명시적인 사용자 확인을 거치도록 구현했습니다.auto_approve옵션을 통해 반복적인 확인을 건너뛸 수 있도록 하여 편의성도 고려했습니다.
배운 점 및 개선점
- 배운 점:
- LLM에게 도구 사용 능력을 부여하는 것은 매우 강력한 기능이며, 이를 통해 복잡한 작업을 자동화할 수 있다는 것을 배웠습니다.
- 로컬 에이전트의 안전성을 확보하기 위해 사용자 확인 절차를 추가하는 것이 필수적임을 깨달았습니다.
- Ollama와 같은 로컬 LLM 실행 환경의 편리함과 가능성을 경험했습니다.
- 개선점:
- 현재
query_database의 쓰기/읽기 구분은 정규식 기반으로 이루어져 있어, 복잡한 SQL 문법을 완벽하게 처리하지 못하는 한계가 있습니다. SQL 파서를 도입하여 더 정확하게 구분할 필요가 있습니다. - 쉘 명령 실행 시 샌드박싱이 되어있지 않아 보안에 취약할 수 있습니다. 추후 샌드박싱 기술 도입을 고려해볼 수 있습니다.
qwen2:7b모델은 때때로 잘못된 도구 호출 JSON을 생성할 수 있습니다. 모델의 성능 향상이나 오류 처리 로직의 정교화가 필요할 수 있습니다.
- 현재
- 다음 단계 계획:
local_agent/tools디렉토리에 더 많은 유용한 도구들을 추가할 예정입니다. (예: 파일 시스템 접근, 외부 API 호출 등)- 사용자 경험 개선을 위해 대화 기록 관리 기능을 더욱 강화할 것입니다.
- 테스트 커버리지를 높여 안정성을 확보할 계획입니다.
참고 자료
- Ollama 공식 웹사이트
- Ollama Python 라이브러리 문서 (예상, 실제 코드에 명시되지는 않음)
- LLM Tool Calling 관련 일반적인 패턴 및 구현 방식