
회사에서 자동화 관련 업무들을 진행하며, 반복 작업을 자동화하여 업무 생산성을 향상시킬 수 있는 일에 대한 관심이 많아졌습니다. AI 공부도 할 겸, AI 활용 능력도 향상시킬 겸 사이드 프로젝트를 하나 진행하게 되었고, 해당 프로젝트에 대해 간단하게 기술하고자 합니다.
이 프로젝트는 AI Agent 기반의 환경에서 실행 가능한 Flutter 앱 테스트 자동화 워크플로우를 만드는 것이 목적입니다. 일반 유닛 또는 위젯 테스트가 아닌, Maestro를 사용해서 가상 디바이스에서 특정 시나리오가 예상대로 실행되는지 테스트합니다.
Maestro
모바일 UI 및 E2E(End-to-End) 테스트 자동화 프레임워크입니다. YAML로 간단하게 테스트 파일을 작성할 수 있으며, 하나의 테스트 파일로 iOS와 Android 모두 테스트 할 수 있습니다.
사실 Maestro 기반 테스트 플로우를 작성하는 것은 그렇게 어렵지 않습니다. 개발자가 아닌 기획자나 QA도 쉽게 작성할 수 있습니다. 요즘은 LLM을 사용해서 테스트 코드를 더 쉽게 작성할 수 있죠. 그래서 이 프로젝트가 의미가 있을까 하는 고민이 있었습니다.
하지만 LLM를 사용해서 빠르게 코드를 작성할 수 있다해도, 파일을 생성하고, 코드를 수정하고, 테스트를 실행하기 위한 명령어를 입력하는 것은 개발자의 몫입니다. 이 과정을 명령어 하나로 자동화 할 수 있다면 꽤 유용한 프로젝트가 될 것 같다는 생각이 들었습니다.
제일 먼저 실행 프로세스에 대해 정의했습니다.
프로세스를 정의한 후, 어떤 도구들을 사용할지 정의했습니다. LLM은 open ai gpt-4 모델을, AI 에이전트로는 요즘 핫한 Codex CLI를 사용하기로 했습니다. 요즘 클로드코드와 비교되며 핫한 것도 있지만, 반복 작업 자동화에는 코덱스가 더 적합하다는 여러 의견들에 기반하여 결정한것도 있습니다.
대략적인 프로세스를 설계한 뒤, AI의 도움을 받으며 작업을 시작했습니다. 이 과정에서 AI Orchestration, Deterministic Flow, Sandbox 등 다양한 AI관련 지식들을 알게 되었는데요, 이 내용들은 프로젝트 구조 단계에서 후술하겠습니다.
아래 이미지는 전반적인 워크플로우를 도식화한 이미지입니다. 제미나이에서 이미지 생성을 담당하는 모델인 Nano Banana 2로 만든 이미지인데요, 결과물이 생각보다 괜찮아서 놀랐습니다. 대화 세션이 길어질수록 성능이 저하되는 것 같기는 한데 그래도 이정도면 사용하기에 충분한 것 같습니다.

1. 에이전트 구성 및 동작 흐름
이 프로젝트는 Deterministic flows 기반 AI 오케스트레이션 구조입니다. 하나의 역할을 담당하는 세 개의 독립적인 에이전트들을 만들고, 특정 단계의 에이전트의 결과값이 다음 단계를 담당하는 에이전트의 입력값이 되어 작업이 실행되도록 구현했습니다.
Deterministic flows
AI 에이전트 설계 방식 중 하나로, 하나의 큰 과제를 작고 명확한 단계로 쪼갠 뒤, 여러 에이전트가 앞 단계의 결과물을 이어받아 순차적으로 처리합니다.
Determisitic flows에 대한 설명과 예제 코드는 Open AI - Common agentic patterns에서 확인 가능합니다. 해당 링크에서는 Deterministic flows 외 다양한 에이전트 설계 패턴들을 알아볼 수 있습니다.
저의 경우 사용자의 입력값을 LLM 서버로 전달하는 Planner Agent, Planner Agent의 결과값인 JSON 데이터를 입력값으로 받고, 파싱 후 테스트 파일을 생성해주는 Generator Agent, 테스트 파일을 실행하고 결과를 도출하는 Runner Agent를 정의했습니다.
1-1. Planner Agent
python3 cli.py \
--intent "Start dashboard page test. Search text "Search fruits..." and enter Durian. click search
button, and check Durian text is visible in the list only." \
--app-id "com.example.maestroTest" \
--deep-link "myapp://dashboard" \
--test-name "dashboard_test"
{
"appId": "com.example.maestroTest",
"route": "myapp://dashboard",
"steps": [
{ "action": "open" },
{ "action": "deeplink" },
{ "action": "assert_visible", "target": "Durian" }
]
}
기존에는 LLM 서버로 프롬프트를 전달하는 작업까지 Planner Agent가 담당했었는데요, 이렇게 구현을 하고 코덱스 cli에서 동작시키니 샌드박스 관련 문제로 워크플로우가 실행되지 않는 문제가 있었습니다.
The command got past credentials and reached the OpenAI API call, but failed because the sandbox cannot resolve/connect to the network:
Codex는 기본적으로 샌드박스 모드입니다. 즉 로컬 개발환경 또는 클라우드 환경에서 네트워크 통신을 할 때, 악성 코드가 외부로 데이터를 유출하는 것을 방지하기 위해서 기본적으로 네트워크 접근 권한을 끄고 실행합니다. 따라서 이 문제를 해결하기 위해, FastAPI 기반의 별도 LLM 서버를 만들고, Planner Agent는 이 로컬 서버를 통해 LLM 응답을 수신하는 방식으로 우회해서 구현했습니다. localhost를 통한 자기 자신과의 통신(Loopback)은 외부 네트워크 요청이 필요하지 않기 때문입니다.
샌드박스 모드는 변경 가능합니다. 하지만 full access 모드로 설정할 경우, 외부 네트워크 통신 시 악성 코드가 유입될 가능성이 있기 때문에 권장되지 않습니다. 관련 글은 Open AI Developers - Sandbox에서 확인 가능합니다.
Codex Sandbox
- Sandbox는 코덱스가 컴퓨터 내에서 어느정도까지 자율적으로 작업을 실행할 수 있는지에 대한 범위입니다. 기본적으로는 현재 프로젝트 폴더 내의 파일 작성/수정만 허용되며, 인터넷 또는 워크스페이스 외부 접근 시 실행 여부에 대해 사용자에게 물어봅니다.
1-2. Generator Agent
# login_test.yaml
- tapOn: "Login"
- inputText: "user1234"
- assertVisible: "Dashboard"
Plan 단계와 Generation 단계에는 각 에이전트가 생성한 결과물이 유효한지(JSON이 필수 필드를 포함하고 있는지, 특정 필드가 empty string은 아닌지)를 검증하는 Validator를 추가해서, 코드 수준의 단순한 가드레일을 구현했습니다.
AI Guardrails
- LLM이 유해하거나 잘못된 정보를 생성하지 않도록 통제하는 기술입니다. LLM의 성능은 뛰어나지만, 환각(학습 데이터에 없는 정보를 통계적 패턴에 기반해 그럴듯하게 생성해 잘못된 정보를 사실처럼 제공), 편향(학습 데이터에 내재한 사회, 문화적 편향이 모델에 반영돼 차별적이거나 반사회적인 응답 생성) 등의 약점을 가지고 있기 때문에, 이를 예방할 수 있는 가드레일 방식이 필요합니다.
1-3. Runner Agent

이번 프로젝트를 통해 Codex CLI도 사용해보고, AI 관련 새로운 것들도 배우게 되어서 유의미한 시간을 보냈던 것 같습니다. 평소에 자동화되었으면 좋겠다고 생각했던 업무들에 적용하기 위해, 앞으로 비슷한 프로젝트를 많이 진행해보면 좋을 것 같다는 생각이 들었습니다.
Open AI - Common agentic patterns
Open AI Developers - Sandbox
InfoGrab - DevOps를 위한 AI 가드레일 플레이북