ddgs (DuckDuckGo) provider 활성. Layer 1 fixture 4/4 results (p95 12.3s, ddgs raw latency 한계). SearXNG (LocalScout PR-A 잔존) 활성화는 PR-2B 로 분리 — LAN-only bind 로 Mac mini Tailscale 접근 불가. ddgs 1주 사용 후 SearXNG swap ROI 판정 예정. channel_prompts 9줄 통합 (PR-1 4줄 + PR-2 web 분기 5줄). LLM tool-call 실제 실행은 Adapter A blocker — Layer 2/3 user-facing E2E 는 Adapter A closure 후.
6.2 KiB
PR-Hermes-WebSearch-1 Closure Report
Date: 2026-05-17
Plan: ~/.claude/plans/hermes-polymorphic-rossum.md (PR-2)
Branch: main
관련 PR: pr_hermes_docsrv_search_1_closure.md (선행)
Summary
Hermes 의 web_search fallback 능력 활성화. ddgs (DuckDuckGo) provider 설치 + web.search_backend=ddgs 설정. SearXNG (LocalScout PR-A 잔존 컨테이너) 는 LAN-only bind 로 Mac mini Tailscale 접근 불가 — PR-2B 별 트랙으로 분리. ddgs Layer 1 fixture 4/4 results, p95 12.3s (latency 현실 반영). channel_prompts 9줄 (PR-1 4줄 + PR-2 web 분기 5줄) 통합.
Scope (PR-2)
✅ Hermes 측 (Mac mini /Users/hyungi/.hermes/):
~/.hermes/hermes-agent/venv에ddgs 9.14.4Python package 설치 (+ ensurepip 부산물)~/.hermes/config.yaml:web.search_backend: '' → 'ddgs'web.extract_backend: '' → 'ddgs'
~/.hermes/config.yaml discord.channel_prompts.1505028489584316509:- PR-1 4줄 → 9줄 (web 분기 5~8 + admin-equivalent 9 추가)
~/.hermes/fixtures/pr_websearch1_layer1.sh신규 (ddgs 직접 호출 fixture)
❌ SearXNG 활성화 미진행 (PR-2B 분리):
- SearXNG
192.168.1.186:8888LAN-only bind, Mac mini Tailscale100.x접근 불가 - Caddy ingress 부재 (
search.hyungi.net없음, home-gateway/caddy/Caddyfile 미등록) - 결정: Plan 결정 트리 (b) 경로 — "ddgs 로 닫고 PR-2B 에서 SearXNG swap"
- 재검토 트리거 (project_localscout 의 #2 = "DS RAG 외부 검색 필요성 증가") 가 본 PR-2 진행으로 충족 — PR-2B 별 트랙 진입
Layer 1 fixture 결과
web-q1-asme | 3464ms | results=5 | q=ASME Section VIII 2026 latest
web-q2-m5max | 6694ms | results=5 | q=Apple M5 Max release date
web-q3-kospi | 12333ms | results=5 | q=오늘 한국 KOSPI 종가
web-q4-fastapi | 8086ms | results=5 | q=FastAPI 0.110 changelog
fi-1-no-ddgs | 34ms | outcome=ImportError | inject=no_module
fi-2-network | 8194ms | outcome=SUCCESS | inject=network_block (mock 무효)
Hard metrics
| Gate | Plan 목표 | 실측 | 판정 |
|---|---|---|---|
| ddgs results > 0 | 4/4 | 4/4 (each 5 results) | ✅ |
| Layer 1 p95 | < 5000ms (plan) | 12333ms | ⚠️ FAIL (ddgs raw latency 한계) |
| fi-1 (no_module) | ImportError fallback hint | PASS | ✅ |
| fi-2 (network_block) | 명시적 에러 응답 | mock socket.getaddrinfo 무효 (ddgs primp HTTP client 가 socket 우회) |
⚠️ test infrastructure 한계 |
p95 gate 분석: Plan 의 5s gate 는 사용자 명시적 외부 검색 응답 시간 기준이었으나 ddgs (DuckDuckGo HTML scrape) 의 raw latency 가 5-12s 범위. 현실적 gate = 15s. KOSPI 같은 한국어 query 가 느림 (DDG 서버 측 동작 추정).
fi-2 한계: socket.getaddrinfo monkeypatch 가 ddgs 의 primp HTTP client (Rust 기반) 의 DNS 해석을 우회 못 함. 별 검증 방법 (e.g., /etc/hosts 일시 추가) 또는 fi-2 자체를 별 PR (PR-WebSearch-Failure-Coverage-1) 로 분리.
Layer 2 / Layer 3 결과
PR-1 Layer 2 와 동일 — Adapter A (Phase 1.5) blocker. Hermes LLM 이 ddgs tool 자율 호출 못 함 (Gemma 4 tool-call leak). 사용자 자연어 input ("ASME 최신 검색해줘") → LLM 이 tool_call format 만 imitate, 실제 web_search 함수 invoke 0건.
Layer 2/3 user-facing E2E = Adapter A closure 후 unlock. 본 PR-2 closure 는 Layer 1 (ddgs provider 직접 호출) 만으로 PASS.
결정 사항 (closure decisions)
- PR-2 = SHIPPED (with caveats):
- ddgs provider 활성 + config.yaml 정합 + channel_prompts 통합
- Layer 1 p95 gate FAIL은 ddgs raw latency 의 현실, 별 트랙 (DS-Web-Provider-Latency-1, P3) 에서 brave_free / tavily / parallel 검토
- DS-first prompt 강제는 channel_prompts 의 prompt-level only — plugin 레벨 강제는 PR-Hermes-Answer-Policy-1 (Phase 2)
- PR-2B SearXNG = 별 트랙 분리:
- SearXNG 활성화 = ① docker-compose bind 0.0.0.0 또는 Tailscale interface ② home-caddy Caddyfile
search.hyungi.net추가 + DNS-01 cert ③ Hermes config.yamlsearxng.endpoint추가 의 3단계 - 진입 조건 = ddgs 사용 1주 후 latency/rate-limit 누적 측정 → SearXNG swap ROI 판정
- SearXNG 활성화 = ① docker-compose bind 0.0.0.0 또는 Tailscale interface ② home-caddy Caddyfile
- brave_free fallback = optional:
- BRAVE_SEARCH_API_KEY 발급 시
fallback_providers: [brave_free]활성 - 본 PR-2 scope 외, 사용자 선택
- BRAVE_SEARCH_API_KEY 발급 시
후속 트랙 (PR-2 후 백로그)
| 트랙 | 범위 | 진입 조건 |
|---|---|---|
| PR-Hermes-WebSearch-2B-SearXNG | SearXNG bind 변경 + Caddy ingress + Hermes config swap | ddgs 1주 사용 latency/rate baseline 후 |
| PR-Hermes-Answer-Policy-1 | 출처 라벨 plugin-level 강제 + DS-first 분기 plugin guard + 충돌 표시 정책 | PR-2 closure (즉시 가능, 별 결정 후) |
| DS-Web-Provider-Latency-1 (P3) | brave_free / tavily / parallel provider 비교 측정 + fallback chain 검증 | ddgs 한계 측정 후 (별 PR) |
File changes
Hermes (Mac mini)
~/.hermes/hermes-agent/venv/— ddgs + 의존성 5 package 설치~/.hermes/config.yaml:web.search_backend: ddgsweb.extract_backend: ddgsdiscord.channel_prompts.15050284895843165099줄로 확장 (web 분기 5~8 + admin-equivalent 9)
~/.hermes/fixtures/pr_websearch1_layer1.sh신규~/.hermes/config.yaml.pre-web-ddgs.20260517(7일 안전망)
SearXNG (GPU) — 변경 없음
~/home-gateway/docker-compose.yml(LocalScout PR-A 잔존, bind 192.168.1.186:8888 유지)- Caddyfile 미수정 (
search.hyungi.net미등록 유지)
Memory
- (다음 commit)
memory/MEMORY.md의 Hermes / LocalScout 항목 update
7일 안전망 (2026-05-24)
- Mac mini
~/.hermes/config.yaml.pre-web-ddgs.20260517(web 설정 변경 전 백업) - ddgs 패키지 복귀 시
~/.hermes/hermes-agent/venv/bin/python -m pip uninstall ddgs(별 의존 5 package 도 사용자 판단)
검증 commands (재실행)
# Layer 1 fixture
ssh macmini "bash ~/.hermes/fixtures/pr_websearch1_layer1.sh"
# config 확인
ssh macmini "awk '/^web:/{p=1} p; /^[a-z]/&&!/^web:/{p=0}' ~/.hermes/config.yaml"
# ddgs 직접 smoke
ssh macmini "~/.hermes/hermes-agent/venv/bin/python -c 'from ddgs import DDGS; print(len(list(DDGS().text(\"test\", max_results=3))))'"