MirageShellTool
MirageShellTool
Mirage 통합 가상 파일시스템 위에서 Agent에게 bash 셸을 제공하는 Tool이에요. S3, Google Drive, Postgres 같은 백엔드를 하나의 파일 트리로 마운트해요.
출처: MirageShellTool
본문
개요
MirageShellTool은 Agent에게 Mirage 통합 가상 파일시스템 위의 단일 셸을 쥐어줘요. 이질적인 백엔드들(객체 저장소, 데이터베이스, SaaS 앱, 로컬 디스크)을 나란히 마운트하는 하나의 디렉토리 트리예요. 파일 내용을 미리 프롬프트에 넣는 대신, Agent가 일반 bash 명령(ls, cat, grep, wc, …)을 실행하면서 마운트된 데이터를 스스로 탐색해요. 명령 출력은 모델에 도달하기 전에 텍스트로 정규화되고 잘려요.
이 도구는 워크스페이스를 구성하는 두 개의 직렬화 가능한 헬퍼로 뒷받침돼요.
MirageWorkspace: 라이브 Mirage 워크스페이스를 지연(lazily) 생성하는 마운트 트리 설명이에요. 도구 뒤의 공유 백엔드이며, Agent 없이도run()/run_async()메서드로 직접 쓸 수 있어요.MirageMount: 단일 백엔드의 선언적 설명이에요. 어디에 마운트되는지(path), 어떤 백엔드인지(resource,"s3","gdrive","postgres","disk","ram"같은 Mirage 레지스트리 이름), 어떻게 구성되는지(config)를 담아요. 자격 증명은 HaystackSecret으로 전달할 수 있으며, 라이브 워크스페이스가 만들어질 때만 해석돼요.
모든 백엔드가 같은 방식으로 마운트되므로, 하나의 도구로 Agent에게 S3, Google Drive, Slack, Gmail, Redis, Postgres, 로컬 디스크 등에 대한 균일한 접근을 제공해요 — MirageMount만 바꾸면 Agent 명령은 그대로 유지돼요. Mirage는 호스트로 셸을 띄우지 않으므로, Agent의 폭발 반경(blast radius)은 붙인 마운트로 제한돼요(보안 모델 참고).
파라미터
workspace는 필수이며, Agent가 접근할 마운트를 설명하는MirageWorkspace여야 해요.name은 선택이고 기본값은"mirage_shell"이에요. LLM에 노출되는 도구 이름을 설정해요.description은 선택이에요. 커스텀 도구 설명이에요. 설정하지 않으면 마운트 트리에서 자동 생성돼요.invocation_timeout은 선택이고 기본값은60.0이에요. 명령 완료를 기다리는 최대 초 수예요.max_output_chars는 선택이고 기본값은20000이에요. 명령 출력은 모델에 반환되기 전에 이 문자 수로 잘려요.allowed_commands는 선택이에요. 설정하면 이 명령 이름들만 실행할 수 있어요(예:["ls", "cat", "grep"]). 보안 모델 참고.denied_paths는 선택이에요. 설정하면 이 경로 부분 문자열 중 하나를 참조하는 명령은 거부돼요.
사용법
MirageShellTool을 쓰려면 Mirage 통합을 설치해요.
pip install mirage-haystack
Agent와 함께
MirageShellTool을 Agent 컴포넌트와 함께 쓸 수 있어요. Agent는 warm_up()에서 워크스페이스를 시작하고, bash로 도구를 구동하며 마운트된 파일들을 스스로 탐색해 질문에 답해요.
아래 예시는 작은 "로그 트리아지(log triage)" Agent를 만들어요. 로그 파일 디렉토리가 읽기 전용으로 마운트되고, Agent가 bash로 그 내용을 조사해 질문에 답해요. 로컬 disk 마운트를 사용해서 완전히 자립적이에요. MirageMount를 s3, gdrive, postgres, …로 바꾸면 같은 Agent를 다른 백엔드에 연결할 수 있어요.
import os
import tempfile
from haystack.components.agents import Agent
from haystack.components.generators.chat import OpenAIChatGenerator
from haystack.dataclasses import ChatMessage
from haystack_integrations.tools.mirage import (
MirageMount,
MirageShellTool,
MirageWorkspace,
)
# Create some sample data on disk (in a real setup this already exists).
data_dir = tempfile.mkdtemp(prefix="mirage-logs-")
with open(os.path.join(data_dir, "api.log"), "w") as fh:
fh.write(
"INFO request /health 200\nERROR db connection timeout\nERROR db connection timeout\n",
)
with open(os.path.join(data_dir, "worker.log"), "w") as fh:
fh.write("INFO job 41 done\nERROR job 42 failed: OutOfMemory\n")
# Describe the workspace. The read-only mount is the authoritative write boundary:
# Mirage refuses any write to it regardless of the command the model chooses.
workspace = MirageWorkspace(
mounts=[
MirageMount(
path="/logs",
resource="disk",
config={"root": data_dir},
read_only=True,
),
],
)
tool = MirageShellTool(workspace, allowed_commands=["ls", "cat", "grep", "head", "wc"])
agent = Agent(
chat_generator=OpenAIChatGenerator(model="gpt-4o-mini"),
tools=[tool],
system_prompt=(
"You are a log-triage assistant. A virtual filesystem is available through the `mirage_shell` "
"tool. Use bash commands (ls, cat, grep, wc, ...) to inspect the mounted files under /logs before "
"answering. Base your answer only on what the files actually show."
),
)
response = agent.run(
messages=[
ChatMessage.from_user(
"Across all files in /logs, what is the single most common ERROR message, "
"and how many times does it occur?",
),
],
)
print(response["last_message"].text)
tool.close()
Agent 없이 명령 실행
MirageWorkspace는 단독으로 쓸 수 있어요. 마운트 트리를 테스트하거나 비-에이전틱 파이프라인을 만들 때 편리해요. 단독으로 쓸 때는 첫 호출 전에 warm_up()을 호출하고(또는 첫 번째 run()이 지연 생성), 끝나면 close()로 리소스를 해제해요.
from haystack_integrations.tools.mirage import MirageMount, MirageWorkspace
workspace = MirageWorkspace(
mounts=[
MirageMount(path="/data", resource="ram"), # in-memory scratch space
MirageMount(
path="/s3",
resource="s3",
config={"bucket": "my-bucket"},
read_only=True,
),
],
)
print(workspace.run("ls /s3"))
print(workspace.run("grep -r alert /s3/logs | wc -l"))
workspace.close()
자격 증명이 있는 백엔드 마운트
자격 증명이 필요한 백엔드는 config로 받아요. 비밀을 Haystack Secret으로 전달하면 라이브 워크스페이스가 만들어질 때만 해석되고, 평문으로 직렬화되지 않아요.
from haystack.utils import Secret
from haystack_integrations.tools.mirage import MirageMount
MirageMount(path="/data", resource="ram") # in-memory scratch
MirageMount(path="/local", resource="disk", config={"root": "/srv/data"}) # local disk
MirageMount(path="/s3", resource="s3", config={"bucket": "my-bucket"}, read_only=True)
MirageMount(
path="/drive",
resource="gdrive",
config={
"client_id": "...",
"refresh_token": Secret.from_env_var("GDRIVE_REFRESH_TOKEN"),
},
read_only=True,
)
Mirage 설치에서 사용 가능한 백엔드 이름은 MirageMount.available_resources()로 확인할 수 있고, 각 백엔드가 기대하는 config 키는 해당 백엔드의 Mirage config 클래스에서 나와요.
보안 모델
Mirage는 호스트로 셸을 띄우지 않아요. 모든 명령은 Mirage 자체의 가상 파일시스템 인터프리터 안에서 실행되므로, Agent의 폭발 반경은 붙인 마운트로 제한돼요. Agent가 할 수 있는 일을 정하는 두 가지 컨트롤이 있어요.
- 마운트별 읽기 전용 모드(
MirageMount(..., read_only=True))가 권위 있는 쓰기 경계예요. 사용된 명령과 무관하게 Mirage가 읽기 전용 마운트에 대한 어떤 쓰기도 거부해요. 이 방식으로 수정·삭제를 막아요. Agent가 바꾸면 안 되는 것은 모두 읽기 전용으로 마운트하세요. - 명령 허용 목록(
allowed_commands)은 어떤 명령이 실행될 수 있는지 제한해요. Mirage가 실행할 모든 명령에 강제되며,$(...), 백틱,<(...), 서브셸 안에 중첩된 명령도 포함돼요. 그래서rm도 허용되지 않으면ls "$(rm x)"는 거부돼요. 이것은 샌드박스가 아니라 Agent를 유도하는 최선 노력 필터로 취급하세요.eval,bash,sh,source,xargs,timeout처럼 그 자신이 다른 명령을 실행하는 명령을 허용하면 사실상 무엇이든 허용하는 셈이니, 신뢰할 수 없거나 호스팅된 용도로는 그런 것들을 목록에 넣지 마세요. - **
denied_paths**는 해당 경로 부분 문자열 중 하나를 참조하는 명령을 거부해요.