처음부터 데이터 분석 에이전트 만들기 (Build a Data Analysis Agent from Scratch)
처음부터 데이터 분석 에이전트 만들기 (Build a Data Analysis Agent from Scratch)
이 가이드는 create_agent와 Deep Agents 미들웨어를 사용해, 첫 원리부터 데이터 분석 에이전트를 만들어 봐요. create_agent와 create_deep_agent 둘 다 도구·메모리 등을 세밀하게 제어할 수 있는데, 둘의 차이는 Deep Agents 쪽에 계획, 파일시스템 도구, 서브에이전트 같은 자주 쓰이는 기능이 이미 기본으로 들어 있다는 점이에요.
Deep Agents의 기본 하네스가 우리 상황에 맞지 않는다면, create_agent로 시작해서 하네스를 한 조각씩 조립하는 방법을 이 가이드에서 보여줘요. 각 구성 요소가 정확히 무엇을 더하는지 볼 수 있고, 필요한 것만 골라 넣을 수 있죠.
이 가이드를 따라가면 다음을 하는 에이전트를 만들게 돼요.
- 분석할 CSV 파일을 받는다
- 격리된 샌드박스에서 Python 코드를 작성하고 실행한다
- 시각화 작업은 전용 서브에이전트에 위임한다
- 스킬 파일에서 데이터 분석 패턴을 불러온다
최종 구성은 create_deep_agent가 기본으로 조립하는 것과 동일해요.
배울 내용
각 단계는 같은 데이터 분석 에이전트에 능력 하나씩을 더해요.
| 단계 | 이게 없으면 생기는 문제 | 추가하는 것 |
|---|---|---|
| 최소 에이전트 | — | 기본 루프: 모델 + 도구, 하네스 없음 |
| 샌드박스 + 파일시스템 | 에이전트가 CSV를 읽거나 Python을 실행할 수 없음 | 격리된 backend + 파일·실행 도구 |
| 요약 | 긴 세션에서 컨텍스트 한도에 부딪힘 | 자동 히스토리 압축 |
| 스킬 | 도메인 규칙이 시스템 프롬프트를 부풀림 | 점진적 공개를 통한 주문형 전문성 |
| 서브에이전트 | 차트 반복 작업이 메인 스레드를 막음 | 격리된 워커 + 병렬 위임 |
설정
1. 패키지 설치
이 튜토리얼에 필요한 패키지를 설치해요.
pip install deepagents langsmith
2. LangSmith API 키 설정
이 튜토리얼은 LangSmithSandbox를 사용해요. 이 클래스는 SandboxClient를 통해 샌드박스를 프로비저닝하는데, 해당 클라이언트는 환경 변수의 LANGSMITH_API_KEY로 LangSmith를 인증해요. 그래서 튜토리얼을 실행하려면 API 키가 필요해요. LangSmith를 설정하면 에이전트가 실행될 때 어떤 일이 일어나는지 추적(trace)도 볼 수 있어요.
- 무료 계정에 가입. Google, GitHub, 이메일로 가입할 수 있어요.
- Settings → API Keys에서 API 키를 만든다.
- LangSmith API 키를 내보낸다:
export LANGSMITH_API_KEY=...
- 추적을 켜면 각 구성 요소를 더할 때마다 도구 호출, 미들웨어 단계, 서브에이전트 위임을 살펴볼 수 있어요.
export LANGSMITH_TRACING=true
3. 모델 제공자 API 키 추가
코드 샘플에서 사용하는 모델 제공자의 API 키를 내보내요.
에이전트 만들기
최소 에이전트 만들기
데이터 분석 에이전트는 채팅 루프 하나로는 부족하지만, 우선 기준선(baseline)부터 시작해요. 모델과 루프만 있는 상태죠. 사용할 모델을 지정해서 create_agent를 사용해요.
이건 실행은 되지만, 에이전트에 파일시스템도 코드 실행 수단도 없어요. CSV를 분석하라고 하면 프롬프트에서 추측할 수밖에 없죠. 다음 단계들에서 실제 파일 접근과 코드 실행을 더할 거예요.
샌드박스 백엔드 추가
데이터를 효율적으로 분석하려면 에이전트가 파일 위에서 코드를 실행할 수 있어야 해요. 그러려면 두 가지가 필요해요.
- 에이전트가 파일을 놓고 그 파일 위에서 코드를 실행할 수 있는 격리된 샌드박스. 이렇게 하면 에이전트가 우리 호스트 머신에 접근할 수 없어요.
- 샌드박스에서 쓸 파일시스템 도구(
read_file,write_file,edit_file,delete,glob,grep)를 제공하는 backend.FilesystemMiddleware가 이 역할을 해요.LangSmithSandboxbackend가 샌드박스 프로토콜을 구현하기 때문에,FilesystemMiddleware는 셸 명령을 실행하게 해 주는execute도구도 추가해요.
LangSmithSandbox는 파일이 살고 명령이 실행되는 곳이에요. FilesystemMiddleware는 그 환경을 모델에게 도구로 노출하는 역할이죠. 같은 미들웨어는 나중에 backend를 바꿔도 다른 backend와 함께 동작해요.
LangSmithSandbox는 에이전트에게 파일시스템과 셸 명령을 실행하는 execute 도구가 있는 격리된 환경을 줘요. 덕분에 에이전트는 패키지를 설치하고, 스크립트를 작성하고, 호스트를 건드리지 않고 실행할 수 있어요. 기본 런타임 대신 커스텀 이미지로 부팅하려면 create_sandbox()에 snapshot_name이나 snapshot_id를 넘기면 돼요. 자세한 내용은 Sandbox snapshots를 참고해요.
이전 단계의 에이전트를 FilesystemMiddleware를 포함한 것으로 교체해요.
from langchain.agents import create_agent
from deepagents.backends.langsmith import LangSmithSandbox
from deepagents.middleware import FilesystemMiddleware
from langsmith.sandbox import SandboxClient
client = SandboxClient()
sandbox = None
sandbox = client.create_sandbox(name="langchain-docs", snapshot_name="docs-test-ci")
backend = LangSmithSandbox(sandbox=sandbox)
agent = create_agent(
model="google_genai:gemini-3.6-flash",
tools=[],
middleware=[FilesystemMiddleware(backend=backend)],
)
샌드박스 파일시스템은 노트북과 분리되어 있어요. 에이전트를 호출하기 전에 필요한 파일을 올려야 해요.
import csv
import io
rows = [
["Date", "Product", "Units", "Revenue"],
["2025-08-01", "Widget A", 10, 250],
["2025-08-02", "Widget B", 5, 125],
["2025-08-03", "Widget A", 7, 175],
["2025-08-04", "Widget C", 3, 90],
]
buf = io.StringIO()
csv.writer(buf).writerows(rows)
backend.upload_files([("/sales.csv", buf.getvalue().encode())])
upload_stream = agent.stream_events(
{
"messages": [
{
"role": "user",
"content": (
"Read /sales.csv and summarize total revenue by product in one "
"sentence. Do not run shell commands."
),
}
]
},
version="v3",
config={"recursion_limit": 8},
)
for item in upload_stream.messages:
print(item.text)
upload_stream.output
LangSmithSandbox에서는 업로드 경로가 절대 POSIX 경로여야 해요(예: /sales.csv). sales.csv 같은 상대 경로는 invalid_path로 거부되고 파일은 샌드박스에 쓰이지 않아요.
이전 단계들의 코드를 한 스크립트로 합쳐서 실행해요.
python analyze_sales.py
첫 실행에서 LangSmith가 샌드박스를 프로비저닝하는데 몇 초 걸릴 수 있어요. 스크립트는 sales.csv를 업로드하고, 에이전트 실행을 스트리밍하며, 보조 메시지가 도착할 때마다 출력해요. 샘플 판매 데이터 분석 결과(제품별 매출, 어떤 위젯이 가장 많이 팔렸는지, 간단한 추세 메모)를 볼 수 있어야 해요. 정확한 표현은 모델 실행마다 달라져요. LangSmith에서 실행을 열고, 에이전트가 답변 전에 파일시스템 도구(read_file, 그리고 샌드박스에서 Python을 실행한다면 execute)를 사용하는 모습을 지켜봐요.
컨텍스트 관리 추가
2단계 이후에는 모든 도구 결과가 메시지 히스토리에 남아요. 실제 분석 세션(여러 플롯, 실패한 스크립트, 큰 read_file 출력)은 컨텍스트 창을 금방 채워요. SummarizationMiddleware는 히스토리가 너무 커지면 이전 턴들을 압축해서, 메시지를 직접 다듬지 않아도 에이전트가 계속 동작하게 해 줘요. 이건 첫 sales.csv 질문에서는 별 의미가 없지만, "이제 제품별로 세그먼트하고 월별 추세를 플롯해 줘" 같은 후속 질문에서 중요해져요.
2단계의 에이전트를 SummarizationMiddleware를 미들웨어 목록에 추가한 형태로 업데이트해요.
다중 턴 세션을 실행해서 요약 동작을 확인해 봐요. 초기 분석 후, 더 많은 파일 읽기나 스크립트 실행을 유발하는 후속 질문을 해보세요. LangSmith에서 이후 모델 호출 전에 요약 단계가 있는지 찾아보세요. 자세한 내용은 Context engineering을 참고해요.
스킬 추가
Skills는 점진적 공개(progressive disclosure)를 통해 필요할 때만 에이전트에게 도메인 지식을 주는 방법이에요. 스킬에는 다단계 워크플로, 규칙, 관례가 들어갈 수 있어요. 이 정보를 스킬에 담아 두면 기본적으로 시스템 프롬프트에 추가되지 않아서, 작업에 그 지식이 필요할 때만 토큰을 쓰도록 보장해 줘요. 에이전트가 시작할 때는 각 스킬에 대한 가벼운 메타데이터만 봐요. 작업이 스킬을 필요로 할 때만 전체 스킬 파일을 주문형으로 불러오죠.
스킬 디렉터리에 스킬 파일을 만들어요.
skills/
pandas-patterns/
SKILL.md
---
name: pandas-patterns
description: Common pandas and matplotlib patterns for data analysis and visualization
---
## Data loading
Use `pd.read_csv()` for CSV files. Always check `df.info()` and `df.describe()` first.
## Visualization
Use `matplotlib` for bar charts, `seaborn` for statistical plots.
Save figures with `plt.savefig("output.png", dpi=150, bbox_inches="tight")`.
## Reporting
Write a markdown summary to `report.md` alongside any generated charts.
이 스킬에는 시각화를 어떻게 해야 하는지에 대한 정보가 들어 있어요. LangSmithSandbox에서는 스킬 경로가 로컬 머신이 아니라 샌드박스 파일시스템에서 해석돼요. SkillsMiddleware를 구성하기 전에 로컬 skills/ 디렉터리를 업로드해요.
from pathlib import Path
skills_dir = (Path(__file__).resolve().parent / "skills").resolve()
skill_files: list[tuple[str, bytes]] = []
for path in sorted(skills_dir.rglob("*")):
if not path.is_file():
continue
rel = path.resolve().relative_to(skills_dir)
skill_files.append((f"/skills/{rel.as_posix()}", path.read_bytes()))
backend.upload_files(skill_files)
그런 다음 SkillsMiddleware를 추가해 스킬을 가진 에이전트를 만들어요.
"Analyze sales.csv using our pandas patterns" 같은 프롬프트를 시도해 볼 수 있어요. 에이전트는 플로팅이나 리포트 지침이 필요할 때 스킬을 불러올 거예요. 스킬이 필요 없는 다른 질문을 하면 스킬을 불러오지 않아요.
시각화 서브에이전트 추가
일부 작업은 중간 출력(스크립트 초안, 실패한 실행, 파일 읽기)이 커서, 한 스레드에 두면 메인 에이전트의 컨텍스트를 어지럽힐 수 있어요. 서브에이전트는 자기만의 컨텍스트 창에서 실행되기 때문에, 슈퍼바이저는 그 과정의 모든 도구 호출이 아니라 최종 결과만 보게 돼요. 덕분에 메인 분석에 집중할 수 있고 후속 질문을 할 여지도 남아요.
서브에이전트를 쓰기 좋은 예가 차트 생성이에요. 플로팅은 대개 Python 스크립트를 반복하고, 패키지를 설치하고, 에러 출력을 읽고 나서야 그림이 완성되죠. 아래 visualizer 서브에이전트는 메인 에이전트가 계획과 분석을 계속하는 동안 그 작업을 격리해서 처리할 수 있어요. TodoListMiddleware를 함께 쓰면 메인 에이전트는 각 플롯을 기다리며 블로킹하지 않고 차트 작업을 병렬로 위임할 수 있어요.
4단계의 에이전트를 TodoListMiddleware와 SubAgentMiddleware를 추가한 형태로 업데이트해요.
from deepagents import SubAgent
from deepagents.middleware import (
FilesystemMiddleware,
SkillsMiddleware,
SubAgentMiddleware,
SummarizationMiddleware,
)
from langchain.agents.middleware import TodoListMiddleware
model = "google_genai:gemini-3.6-flash"
visualizer: SubAgent = {
"name": "visualizer",
"description": "Generates charts and visualizations from data files in the sandbox.",
"system_prompt": "You are a data visualization specialist. Write Python scripts using matplotlib and seaborn. Save all figures as PNG files.",
"tools": [],
"model": model,
}
agent = create_agent(
model=model,
tools=[],
middleware=[
FilesystemMiddleware(backend=backend),
SummarizationMiddleware(model=model, backend=backend),
SkillsMiddleware(backend=backend, sources=["/skills/"]),
TodoListMiddleware(),
SubAgentMiddleware(backend=backend, subagents=[visualizer]),
],
)
"Analyze sales.csv, then create a bar chart of revenue by product." 같은 프롬프트를 시도해 봐요. 메인 에이전트는 분석과 계획을 처리하고 task 도구를 통해 visualizer 서브에이전트에 차트 생성을 위임해요. 설정에서 추적을 켰다면 LangSmith에서 실행을 열어 보세요. visualizer로 가는 task 호출, 자기만의 도구 루프를 가진 별도의 하위 실행, 그리고 슈퍼바이저에게 돌아오는 짧은 결과를 볼 수 있을 거예요.
완성된 것
다음 미들웨어로 커스텀 에이전트를 만들었어요.
| 미들웨어 | 추가하는 것 |
|---|---|
FilesystemMiddleware + LangSmithSandbox |
격리된 파일시스템 + execute 도구 |
SummarizationMiddleware |
자동 컨텍스트 압축 |
SkillsMiddleware |
필요할 때 불러오는 도메인 지식 |
TodoListMiddleware + SubAgentMiddleware |
병렬 시각화 서브에이전트 |
이건 create_deep_agent와 같은 기반이에요. 무엇을 포함할지 정확히 제어할 수 있도록 직접 조립한 거죠. 여기서 끝이 아니에요. 조합 가능한 능력 전체 목록은 Prebuilt middleware를, create_agent의 모든 구성 옵션은 create_agent 참조를 보세요. 미리 조립된 버전으로 작업하려면 Customize Deep Agents를, create_deep_agent를 쓰는 전체 데이터 분석 예시는 Data analysis를 참고해요.