07. 웹 검색 + 로컬 지식베이스 (RAG)
학습 목표
이 튜토리얼을 마치면 다음을 할 수 있습니다:
web.search도구가 HITL 승인 게이트를 통과하는 과정을 이해한다euleragent rag init/add/status/query로 로컬 지식베이스를 구축한다- 글로브 패턴으로 특정 파일 형식만 인제스트한다
- 웹 검색 보안 설정(도메인 화이트리스트)을 적용한다
- 웹 검색과 로컬 KB를 같은 실행에서 함께 사용한다
- 실전 시나리오: 기술 블로그 작성에 내부 문서 + 웹 정보를 결합한다
- MCP 검색 프로바이더를 설정하고
euleragent mcp sync/show로 관리한다 - SearchRouter의 자동 라우팅 개념과
search_routing.jsonl아티팩트를 이해한다 - MCP 카탈로그 스냅샷으로 검색 소스 구성의 재현성을 보장한다
--source-set옵션으로 실행별 검색 소스 집합을 지정한다
사전 준비
- 워크스페이스 초기화 완료 (
euleragent init) - 에이전트 생성:
euleragent new blog-writer --template marketing-expert
- Ollama 실행 (또는
default_llm_profile: fake):
ollama serve
ollama pull nomic-embed-text # RAG 임베딩 모델
RAG(Retrieval-Augmented Generation)란?
RAG는 LLM이 응답을 생성하기 전에 관련 문서를 검색하여 컨텍스트로 주입하는 기술입니다. euleragent에서는 두 가지 검색 소스를 지원합니다:
| 소스 | 명령어 | 특징 |
|---|---|---|
| 로컬 지식베이스 | rag init/add/query |
내부 문서, 오프라인, 빠름 |
| 웹 검색 | web.search (HITL 게이트) |
최신 정보, 승인 필요 |
web.search의 HITL 보안 게이트
web.search는 외부 네트워크에 데이터를 전송하므로 항상 사람의 승인이 필요합니다. 이 과정을 먼저 이해합니다.
web.search가 위험한 이유
- 데이터 유출 위험: 쿼리에 포함된 내부 정보가 검색 엔진으로 전송됩니다
- 비용: 검색 API는 사용량에 따라 비용이 발생합니다
- 예상치 못한 결과: 검색 결과가 에이전트의 출력에 영향을 미칩니다
승인 없이 실행이 불가능한 이유
tools.yaml의 require_approval 목록에 web.search가 포함되어 있습니다:
# .euleragent/agents/blog-writer/tools.yaml
require_approval:
- web.search
- web.fetch
- file.write
- shell.exec
이 설정으로 인해 에이전트가 web.search를 제안해도 사람의 수락 없이는 실행되지 않습니다.
MCP 기반 웹 검색 설정 (권장)
중요:
rag.web_search설정은 deprecated입니다. 새로운 프로젝트에서는 MCP 서버 방식을 사용하세요.
euleragent는 MCP(Model Context Protocol) 기반 검색 프로바이더를 권장합니다. MCP 서버가 설정되어 있으면 MCP 우선 라우팅이 적용되며, MCP 미설정 시에만 legacy rag.web_search로 fallback합니다 (1회 DeprecationWarning 발생).
빠른 시작: 데모 MCP Web Search 서버
euleragent 저장소에 포함된 데모 서버로 즉시 시작할 수 있습니다:
# 1. 데모 MCP web search 서버 실행 (별도 터미널)
python examples/mcp/web_search_server.py
# MCP web search demo server listening on 0.0.0.0:9021
# Provider: fake
# Endpoint: POST http://0.0.0.0:9021/mcp
# 2. workspace.yaml에서 MCP 서버 주석 해제
# .euleragent/config/workspace.yaml 편집:
# mcp:
# enabled: true
# servers:
# - id: local_web_search
# url: http://localhost:9021/mcp
# allow_tools: [web.search, web.fetch]
# ...
# 3. 카탈로그 동기화
euleragent mcp sync
euleragent mcp show
workspace.yaml MCP 설정 예시
# .euleragent/config/workspace.yaml
mcp:
enabled: true
servers:
- id: local_web_search
url: http://localhost:9021/mcp
allow_tools: [web.search, web.fetch]
cost_tier: free
risk_default: high
require_approval_enable: true
timeout_seconds: 30
config:
provider: fake # fake | brave | tavily | duckduckgo
api_key: "" # set for brave/tavily
max_results: 10
MCP 우선 라우팅: MCP 서버에
web.search가allow_tools에 포함되어 있으면, 기존rag.web_search설정보다 우선 적용됩니다.
Legacy 설정 (deprecated)
아래 설정은 하위호환성을 위해 유지되며, MCP 미설정 시 자동으로 fallback합니다:
# .euleragent/config/workspace.yaml
mcp:
enabled: true
catalog_path: .euleragent/state/mcp_catalog.json
sources:
- name: tavily
type: web_search
provider: tavily
api_key: tvly-YOUR_API_KEY
priority: 1
- name: brave
type: web_search
provider: brave
api_key: BSA-YOUR_API_KEY
priority: 2
- name: local_kb
type: rag
project: my-project
priority: 0 # 가장 높은 우선순위 (로컬 우선)
source_sets:
default: [local_kb, tavily]
academic: [local_kb, tavily]
news: [brave, tavily]
offline: [local_kb]
MCP 카탈로그 동기화 및 확인
설정 후 카탈로그를 동기화하고 상태를 확인합니다:
# 카탈로그 동기화 — 각 소스의 연결 상태를 확인하고 스냅샷 생성
euleragent mcp sync
예상 출력:
MCP catalog sync completed.
Sources: 3
[OK] local_kb (rag, 7 chunks)
[OK] tavily (web_search, connected)
[OK] brave (web_search, connected)
Source sets: 4 (default, academic, news, offline)
Snapshot: .euleragent/state/mcp_catalog_snapshot.json
# 현재 카탈로그 상태 확인
euleragent mcp show
예상 출력:
MCP Catalog
Sources:
NAME TYPE PROVIDER STATUS PRIORITY
local_kb rag — active 0
tavily web_search tavily active 1
brave web_search brave active 2
Source Sets:
default: local_kb, tavily
academic: local_kb, tavily
news: brave, tavily
offline: local_kb
단계별 실습
Step 1: RAG 지식베이스 초기화
프로젝트별 지식베이스를 초기화합니다:
euleragent rag init --project my-project
예상 출력:
RAG knowledge base initialized.
Project: my-project
DB: .euleragent/projects/my-project/rag.db
Chunks: 0
Docs: 0
프로젝트가 없으면 자동으로 생성됩니다. 지식베이스는 프로젝트 디렉토리 안에 SQLite DB로 저장됩니다.
Step 2: 문서 인제스트 — 디렉토리 전체
로컬 문서를 지식베이스에 추가합니다. 마크다운, 텍스트, PDF 등 다양한 형식을 지원합니다:
# 예시 문서 디렉토리 생성
mkdir -p ./docs/product
cat > ./docs/product/overview.md << 'EOF'
# FastBridge 제품 개요
FastBridge는 FastAPI 기반 고성능 API 게이트웨이입니다.
## 핵심 기능
- 요청 라우팅 및 로드 밸런싱
- JWT 기반 인증/인가
- 레이트 리미팅
- 실시간 모니터링 대시보드
EOF
cat > ./docs/product/tech_stack.md << 'EOF'
# FastBridge 기술 스택
## 백엔드
- Python 3.11
- FastAPI 0.110
- SQLAlchemy 2.0
- Redis (캐싱)
## 인프라
- Docker + Kubernetes
- GitHub Actions (CI/CD)
EOF
문서 인제스트:
euleragent rag add --project my-project --path ./docs/
예상 출력:
Ingesting documents from ./docs/ ...
[OK] ./docs/product/overview.md → 4 chunks
[OK] ./docs/product/tech_stack.md → 3 chunks
Ingested 2 documents, 7 chunks total.
Project: my-project
Total chunks in KB: 7
Step 3: 특정 형식만 인제스트 — 글로브 패턴
--glob 옵션으로 특정 파일 형식만 선택적으로 인제스트합니다:
# 마크다운 파일만
euleragent rag add \
--project my-project \
--path ./docs/ \
--glob "*.md"
# 텍스트 파일만
euleragent rag add \
--project my-project \
--path ./docs/ \
--glob "*.txt"
# 특정 하위 디렉토리만
euleragent rag add \
--project my-project \
--path ./docs/ \
--glob "product/*.md"
예상 출력:
Ingesting documents matching "*.md" from ./docs/ ...
[OK] overview.md → 4 chunks
[OK] tech_stack.md → 3 chunks
[skip] data.csv ← glob 패턴 불일치
Ingested 2 documents, 7 chunks total.
Step 4: 지식베이스 상태 확인
euleragent rag status --project my-project
예상 출력:
RAG Knowledge Base Status
Project: my-project
DB: .euleragent/projects/my-project/rag.db
Documents: 2
Chunks: 7
Embedding: ollama/nomic-embed-text
Last added: 2026-02-23 10:30:00
Document list:
[1] docs/product/overview.md 4 chunks 2026-02-23 10:30:00
[2] docs/product/tech_stack.md 3 chunks 2026-02-23 10:30:00
Step 5: 지식베이스 직접 쿼리
에이전트를 통하지 않고 직접 RAG 검색을 테스트합니다:
euleragent rag query \
--project my-project \
--q "FastBridge의 인증 방식은?" \
--top-k 3
예상 출력:
Query: "FastBridge의 인증 방식은?"
Top-3 results:
[1] score=0.8923
Source: docs/product/overview.md
Chunk: "JWT 기반 인증/인가"
[2] score=0.7234
Source: docs/product/overview.md
Chunk: "FastBridge는 FastAPI 기반 고성능 API 게이트웨이입니다. 핵심 기능: 요청 라우팅..."
[3] score=0.6891
Source: docs/product/tech_stack.md
Chunk: "Python 3.11, FastAPI 0.110..."
다른 쿼리 시도:
euleragent rag query \
--project my-project \
--q "Python version" \
--top-k 2
Step 6: 웹 검색 보안 설정 — 도메인 화이트리스트
workspace.yaml에서 허용 도메인을 제한할 수 있습니다:
cat .euleragent/config/workspace.yaml
tools_policy:
network:
default: deny # 기본 외부 통신 차단
require_approval: true # 모든 외부 통신 승인 필요
allow_domains: # 허용 도메인 화이트리스트
- arxiv.org
- github.com
- docs.python.org
- fastapi.tiangolo.com
rag:
web_search:
provider: fake # 테스트용 (실제: tavily | brave | duckduckgo)
require_approval: true
api_key: "" # 실제 프로바이더 사용 시 API 키
도메인 화이트리스트의 작동 방식:
현재 allow_domains는 메타데이터로 기록되어 사람이 승인 시 참고합니다. 승인 시 쿼리나 URL이 화이트리스트 도메인에 속하는지 직접 확인 후 수락/거부합니다.
MCP 검색 프로바이더의 승인 흐름:
MCP를 사용하는 경우, SearchRouter가 외부 소스로 라우팅한 검색만 승인 대상이 됩니다. 승인 정보에 라우팅 대상 소스가 함께 표시됩니다:
euleragent approve show apv_xxx
{
"tool_name": "web.search",
"params": {"query": "API gateway comparison 2025"},
"side_effects": ["external_network"],
"mcp_source": "tavily",
"source_set": "default",
"allowed_domains": ["fastapi.tiangolo.com", "docs.python.org"]
}
로컬 KB로 라우팅된 검색은 외부 네트워크를 사용하지 않으므로 승인 큐에 나타나지 않습니다.
# 승인 시 도메인 확인
euleragent approve show apv_xxx
{
"tool_name": "web.search",
"params": {"query": "FastAPI authentication JWT 2025"},
"side_effects": ["external_network"],
"allowed_domains": ["fastapi.tiangolo.com", "docs.python.org"]
}
실제 API 키 기반 웹 검색 설정:
# workspace.yaml — 실제 Tavily 웹 검색 사용 시
rag:
web_search:
provider: tavily
api_key: tvly-YOUR_TAVILY_API_KEY
require_approval: true
max_results: 5
Step 7: 로컬 KB만 사용하는 에이전트 실행
먼저 로컬 KB만으로 블로그 글을 작성합니다:
euleragent run blog-writer \
--task "FastBridge API 게이트웨이 소개 블로그 글을 작성해줘. 기술 스택과 핵심 기능을 포함해야 해. result.md에 저장해줘." \
--project my-project \
--mode plan
예상 출력:
Run b2c3d4e5f6a1 started
Project: my-project
RAG: my-project KB active (7 chunks)
[loop 1/5] Retrieving from local KB...
RAG hit: "FastBridge는 FastAPI 기반..." (score: 0.89)
RAG hit: "JWT 기반 인증/인가..." (score: 0.83)
RAG hit: "Python 3.11, FastAPI 0.110..." (score: 0.78)
[loop 2/5] Generating blog post...
→ Proposed: file.write (path: result.md)
Run b2c3d4e5f6a1 completed (state: PENDING_APPROVAL)
1 approval(s) pending.
승인 후 실행:
euleragent approve accept-all --run-id b2c3d4e5f6a1 --actor "user:you" --execute
cat result.md
Step 8: 웹 검색 + 로컬 KB 결합
가장 강력한 패턴입니다. 내부 문서와 최신 웹 정보를 함께 사용합니다:
euleragent run blog-writer \
--task "FastBridge API 게이트웨이 vs 최신 오픈소스 API 게이트웨이 비교 블로그를 작성해줘. FastBridge 내부 문서를 기반으로 하고, 경쟁사 정보는 웹에서 검색해서 포함해줘. result.md에 저장해줘." \
--project my-project \
--mode plan \
--max-loops 4
예상 출력:
Run c3d4e5f6a1b2 started
Project: my-project
RAG: my-project KB active (7 chunks)
[loop 1/4] Retrieving from local KB...
RAG hits: 3 chunks retrieved from my-project KB
[loop 2/4] Planning web searches for competitor info...
→ Proposed: web.search (query: "open source API gateway comparison 2025")
→ Proposed: web.search (query: "Kong APISIX Traefik features comparison")
[loop 3/4] Planning output...
→ Proposed: file.write (path: result.md)
Run c3d4e5f6a1b2 completed (state: PENDING_APPROVAL)
3 approval(s) pending.
[2x] web.search
[1x] file.write
웹 검색 먼저 승인하고 실행:
euleragent approve accept-all \
--run-id c3d4e5f6a1b2 \
--tool web.search \
--actor "user:you" \
--execute
예상 출력:
Accepted and executed 2 web.search approval(s).
[OK] "open source API gateway comparison 2025" → 5 results
[OK] "Kong APISIX Traefik features comparison" → 4 results
파일 쓰기 승인:
euleragent approve accept-all \
--run-id c3d4e5f6a1b2 \
--tool file.write \
--actor "user:you" \
--execute
결과 확인:
cat result.md
# FastBridge vs 오픈소스 API 게이트웨이 비교
# (내부 문서 + 웹 검색 결과 결합)
Step 9: 인용(citations) 확인
RAG가 활성화된 실행에서는 citations.json이 생성됩니다:
cat .euleragent/runs/c3d4e5f6a1b2/artifacts/citations.json
예상 출력:
[
{
"citation_id": "cit_001",
"doc_id": "doc_overview",
"chunk_id": "chunk_003",
"content": "JWT 기반 인증/인가",
"source": "docs/product/overview.md",
"score": 0.8923
},
{
"citation_id": "cit_002",
"doc_id": "doc_tech",
"chunk_id": "chunk_001",
"content": "Python 3.11, FastAPI 0.110",
"source": "docs/product/tech_stack.md",
"score": 0.7891
}
]
RAG 컨텍스트 전체 확인:
cat .euleragent/runs/c3d4e5f6a1b2/artifacts/rag_context.json
외부 전송 감사 로그:
cat .euleragent/runs/c3d4e5f6a1b2/external_transmission.jsonl
{"tool": "web.search", "query": "open source API gateway comparison 2025", "timestamp": "2026-02-23T10:30:15Z", "approval_id": "apv_w1"}
{"tool": "web.search", "query": "Kong APISIX Traefik features comparison", "timestamp": "2026-02-23T10:30:17Z", "approval_id": "apv_w2"}
Step 10: 검색 라우팅 이해
MCP 검색 프로바이더를 구성하면 SearchRouter가 에이전트의 검색 요청을 자동으로 적절한 소스로 라우팅합니다. 에이전트는 단일 web.search 도구만 호출하지만, 내부적으로 SearchRouter가 쿼리 특성에 따라 로컬 KB, Tavily, Brave 등 최적의 소스를 선택합니다.
SearchRouter 작동 방식:
에이전트 → web.search("FastBridge 인증 방식")
│
▼
SearchRouter
├─ 쿼리 분석: 내부 제품명 포함 → 로컬 KB 우선
├─ source_set: default → [local_kb, tavily]
└─ 라우팅 결정: local_kb (priority 0)
│
▼
로컬 KB에서 검색 → 결과 반환
에이전트 → web.search("API gateway market trends 2025")
│
▼
SearchRouter
├─ 쿼리 분석: 외부 시장 정보 → 웹 검색 필요
├─ source_set: default → [local_kb, tavily]
└─ 라우팅 결정: tavily (로컬 KB 매치 없음)
│
▼
Tavily 웹 검색 → 결과 반환 (승인 필요)
각 실행에서 라우팅 결정은 search_routing.jsonl에 기록됩니다:
cat .euleragent/runs/c3d4e5f6a1b2/search_routing.jsonl
{"query": "FastBridge 인증 방식", "routed_to": "local_kb", "source_set": "default", "reason": "internal_doc_match", "approval_required": false, "timestamp": "2026-02-23T10:30:10Z"}
{"query": "open source API gateway comparison 2025", "routed_to": "tavily", "source_set": "default", "reason": "external_info_needed", "approval_required": true, "timestamp": "2026-02-23T10:30:15Z"}
{"query": "Kong APISIX Traefik features comparison", "routed_to": "brave", "source_set": "default", "reason": "tavily_fallback", "approval_required": true, "timestamp": "2026-02-23T10:30:17Z"}
로컬 KB 라우팅은 승인 불필요: SearchRouter가 로컬 KB로 라우팅한 검색은 외부 네트워크를 사용하지 않으므로 HITL 승인이 필요하지 않습니다. 외부 검색 소스로 라우팅된 경우에만 승인 게이트가 활성화됩니다.
Step 11: --source-set으로 검색 소스 지정
실행 시 --source-set 옵션으로 사용할 검색 소스 집합을 명시적으로 지정할 수 있습니다:
# 기본 소스 셋 사용 (local_kb + tavily)
euleragent run blog-writer \
--task "FastBridge 소개 블로그 작성" \
--project my-project \
--mode plan
# 오프라인 모드: 로컬 KB만 사용
euleragent run blog-writer \
--task "FastBridge 내부 기술 문서 정리" \
--project my-project \
--source-set offline \
--mode plan
# 뉴스 소스 사용: 최신 시장 동향 조사
euleragent run blog-writer \
--task "API 게이트웨이 시장 최신 동향 조사" \
--project my-project \
--source-set news \
--mode plan
--source-set을 지정하지 않으면 workspace.yaml의 mcp.source_sets.default가 사용됩니다.
Step 12: MCP 카탈로그 스냅샷
MCP 카탈로그 스냅샷은 실행 시점의 검색 소스 구성을 기록하여 재현성을 보장합니다. 각 실행의 아티팩트에 스냅샷이 자동으로 포함됩니다.
cat .euleragent/runs/c3d4e5f6a1b2/artifacts/mcp_catalog_snapshot.json
{
"snapshot_hash": "sha256:a3f8e2d1c4b5...",
"created_at": "2026-02-23T10:30:00Z",
"sources": [
{
"name": "local_kb",
"type": "rag",
"status": "active",
"chunks": 7,
"content_hash": "sha256:b7c9d1e2f3..."
},
{
"name": "tavily",
"type": "web_search",
"provider": "tavily",
"status": "active"
},
{
"name": "brave",
"type": "web_search",
"provider": "brave",
"status": "active"
}
],
"source_set_used": "default",
"resolved_sources": ["local_kb", "tavily"]
}
스냅샷 해시의 역할:
- snapshot_hash는 카탈로그 구성 전체의 해시값입니다
- 동일한 해시 = 동일한 검색 소스 구성으로 실행됨을 보장합니다
- 감사(audit) 시 실행 당시 어떤 소스가 활성 상태였는지 정확히 추적할 수 있습니다
- 로컬 KB의 content_hash는 지식베이스 내용 변경도 추적합니다
# 두 실행의 카탈로그 스냅샷 비교
diff <(jq '.snapshot_hash' .euleragent/runs/RUN1/artifacts/mcp_catalog_snapshot.json) \
<(jq '.snapshot_hash' .euleragent/runs/RUN2/artifacts/mcp_catalog_snapshot.json)
Step 13: 전체 흐름 다이어그램
euleragent run blog-writer --project my-project --source-set default --mode plan
│
▼
[컨텍스트 구성]
system prompt + memory snapshot + MCP 카탈로그 스냅샷
│
▼
[로컬 KB RAG 검색]
euleragent rag query --project my-project
→ 관련 내부 문서 청크 추출
│
▼
[LLM 루프]
├─ 로컬 KB 결과를 컨텍스트에 주입
├─ web.search 제안 (외부 정보 필요 시)
└─ file.write 제안 (최종 결과물)
│
▼
[SearchRouter — MCP 라우팅]
├─ 쿼리 분석 → 소스 선택 (source_set 기준)
├─ 로컬 KB 매치 → 즉시 반환 (승인 불필요)
└─ 외부 소스 → 승인 큐로 전달
│
▼
[승인 큐]
web.search (medium) → 사람이 쿼리 + MCP 소스 검토
file.write (medium) → 사람이 내용 검토
│
▼
[수락 후 실행]
→ 웹 검색 결과 컨텍스트 추가
→ 최종 블로그 포스트 생성
│
▼
artifacts/
├── result.md ← 최종 블로그 글
├── citations.json ← 로컬 KB 인용
├── rag_context.json ← RAG 컨텍스트 전체
├── search_routing.jsonl ← 검색 라우팅 결정 기록
├── mcp_catalog_snapshot.json ← MCP 카탈로그 스냅샷
└── external_transmission.jsonl ← 외부 전송 감사 로그
workspace.yaml RAG 및 MCP 설정 전체 참조
# .euleragent/config/workspace.yaml
# LLM 프로바이더
llm_profiles:
local:
provider: ollama
base_url: http://localhost:11434
model: qwen3:32b
timeout_seconds: 120
keep_alive: 5m
is_external: false
openai:
provider: openai
api_key: ''
model: gpt-4o-mini
base_url: https://api.openai.com/v1
is_external: true
default_llm_profile: local
# 메모리 (장기기억)
memory:
enabled: true
store: sqlite
sqlite_path: .euleragent/state/memory.db
embedding:
provider: ollama # RAG 임베딩용
model: nomic-embed-text
retrieval:
top_k: 8
min_score: 0.2
# 도구 보안 정책
tools_policy:
network:
default: deny
require_approval: true
allow_domains:
- arxiv.org
- github.com
- docs.python.org
- huggingface.co
# RAG 설정
rag:
enabled: true
chunk_size: 512 # 청크 크기 (토큰)
chunk_overlap: 64 # 청크 간 겹침
embedding:
provider: ollama
model: nomic-embed-text
web_search:
provider: fake # fake | tavily | brave | duckduckgo
api_key: "" # 실제 프로바이더 API 키
require_approval: true # 항상 true 권장
max_results: 5
# MCP 검색 프로바이더 설정 (선택 사항)
mcp:
enabled: true
catalog_path: .euleragent/state/mcp_catalog.json
sources:
- name: local_kb
type: rag
project: my-project
priority: 0
- name: tavily
type: web_search
provider: tavily
api_key: tvly-YOUR_API_KEY
priority: 1
- name: brave
type: web_search
provider: brave
api_key: BSA-YOUR_API_KEY
priority: 2
source_sets:
default: [local_kb, tavily]
academic: [local_kb, tavily]
news: [brave, tavily]
offline: [local_kb]
예상 출력 요약
# RAG 초기화
$ euleragent rag init --project my-project
RAG knowledge base initialized. Chunks: 0, Docs: 0
# 문서 추가
$ euleragent rag add --project my-project --path ./docs/
Ingested 2 documents, 7 chunks total.
# 상태 확인
$ euleragent rag status --project my-project
Documents: 2, Chunks: 7
# 직접 쿼리
$ euleragent rag query --project my-project --q "인증 방식"
[1] score=0.8923 Source: overview.md "JWT 기반 인증/인가"
# 에이전트 실행 (로컬 KB + 웹 검색)
Run c3d4e5f6... started
RAG hits: 3 chunks from my-project KB
Proposed: web.search × 2, file.write × 1
3 approval(s) pending.
자주 묻는 질문 / 흔한 오류
Q: rag add 후 rag query에서 결과가 나오지 않습니다.
임베딩 모델이 실행 중인지 확인하세요. provider: ollama로 설정된 경우 nomic-embed-text 모델이 필요합니다:
ollama pull nomic-embed-text
ollama list # 모델 목록 확인
provider: fake로 설정하면 오프라인에서도 동작하지만 의미 기반 검색이 제한됩니다.
Q: 이미 추가한 문서를 다시 추가하면 중복이 발생하나요?
동일한 파일 경로와 콘텐츠가 이미 존재하면 자동으로 스킵됩니다. 파일이 수정된 경우에는 기존 청크를 삭제하고 새로 인제스트합니다:
# 수정된 파일 재인제스트
euleragent rag add --project my-project --path ./docs/product/overview.md
# [update] overview.md → 4 chunks (replaced existing)
Q: allow_domains 설정이 실제로 웹 요청을 차단하나요?
현재 버전에서 allow_domains는 메타데이터로 기록되며, 실제 도메인 필터링은 승인 단계에서 사람이 직접 확인합니다. 프로그램적으로 차단하는 기능은 향후 버전에서 추가될 예정입니다. 지금은 승인 시 URL/쿼리를 직접 검토하여 화이트리스트 준수 여부를 확인하세요.
Q: 로컬 PDF 파일도 인제스트할 수 있나요?
현재 지원하는 형식은 마크다운(.md), 텍스트(.txt), 일반 텍스트입니다. PDF는 먼저 텍스트로 변환한 후 인제스트하세요:
# pdftotext 사용 (poppler-utils 설치 필요)
pdftotext document.pdf document.txt
euleragent rag add --project my-project --path ./document.txt
Q: 여러 프로젝트의 RAG를 공유하려면 어떻게 하나요?
현재 RAG는 프로젝트별로 독립적입니다. 공통 문서를 여러 프로젝트에 추가하려면 각 프로젝트에 개별적으로 인제스트해야 합니다:
euleragent rag add --project project-a --path ./shared-docs/
euleragent rag add --project project-b --path ./shared-docs/
Q: web.search를 승인 없이 자동 실행하고 싶습니다.
보안상 권장하지 않습니다. 하지만 신뢰할 수 있는 환경에서 자동화가 필요하다면 tools.yaml의 require_approval에서 web.search를 제거하세요:
# tools.yaml (보안 위험 — 신중하게 사용)
require_approval:
- file.write
- file.delete
- shell.exec
# web.search 제거 → 자동 실행
이 경우 모든 외부 전송이 자동으로 이루어지므로 allow_domains와 external_transmission.jsonl 감사 로그를 철저히 관리하세요.
자주 하는 실수 (순서 어긋남)
| 증상 | 원인 | 복구 |
|---|---|---|
Error: No knowledge base found for project 'X'. |
rag init 미실행 |
euleragent rag init --project X |
No results found. |
KB에 문서 미추가 | euleragent rag add --project X --path docs/ |
다음 단계: 08_mcp_provider_and_tools.md — MCP 프로바이더를 설정하여 다양한 외부 검색 소스를 통합 관리하는 방법을 심층 학습합니다.