메인 콘텐츠로 건너뛰기
리서치 에이전트는 단순한 검색 결과 하나나 빠른 모델 답변 이상을 원할 때 유용합니다. 좋은 리서치 에이전트는 광범위한 주제를 검색 쿼리로 바꾸고, 소스를 수집하고, 중요한 증거를 추출하고, 빈 곳을 추가 조사하고, 나중에 검토할 수 있는 인용된 브리핑을 작성할 수 있습니다. 이 튜토리얼에서는 Python과 Venice API로 프라이빗 리서치 에이전트를 만듭니다. 마지막에는 주제를 조사하고, 공개 페이지를 Markdown으로 스크래핑하고, 소스 청크를 요약하고, 갭 인식 후속 리서치 패스를 실행하고, 선택적 로컬 JSONL 아티팩트와 함께 인용된 보고서를 생성하는 CLI가 갖춰집니다. 전체 코드 구현이 궁금하다면 GitHub 레포를 확인하세요. 계속하기 전에 Venice API 키가 필요합니다:

무엇을 만드나요

레퍼런스 구현은 몇 가지 명확한 부분으로 구성된 작은 Python 프로젝트입니다: 흐름은 다음과 같습니다: 프라이빗 리서치 에이전트 파이프라인
  1. 주제에 대해 다양한 검색 쿼리를 생성하도록 Venice에 요청.
  2. 하나 이상의 공급자로 웹 검색.
  3. 읽기 전에 URL 중복 제거.
  4. Venice의 scrape endpoint로 각 공개 소스 페이지를 Markdown으로 변환.
  5. 긴 페이지를 청크로 분할.
  6. 각 청크에서 증거를 추출하도록 Venice에 요청.
  7. 청크 증거를 소스 노트로 변환하도록 Venice에 요청.
  8. 후속 쿼리를 생성하기 전에 리서치 갭과 소스 균형 문제 식별.
  9. 각주 스타일 인용이 포함된 최종 보고서를 합성하도록 Venice에 요청.
이는 에이전트가 오케스트레이션, 소스 노트, 아티팩트, 최종 보고서를 사용자의 머신에 유지한다는 실질적 의미에서 “프라이빗”합니다. Venice는 API를 통해 모델 호출과 스크래핑을 처리합니다. 기본 레퍼런스 구현은 여전히 DuckDuckGo나 arXiv로 검색 쿼리를 보내므로, 공급자 선택을 프라이버시 설계의 일부로 다루세요.

프로젝트 설정

레퍼런스 프로젝트는 Python 3.13과 uv를 사용하지만, 일반 가상 환경에서도 같은 코드가 동작합니다. 새 프로젝트 생성:
의존성 설치:
pip를 선호한다면 가상 환경을 만들고 같은 패키지를 설치하세요:
로컬 개발용 .env 파일 생성:
코드 수정 없이 모델을 변경할 수 있도록 VENICE_MODEL을 사용합니다. 레퍼런스 구현은 현재 기본값으로 openai-gpt-55를 사용하지만, Venice 계정에서 사용 가능한 다른 chat 모델로 교체할 수 있습니다.

데이터 모델 만들기

에이전트 로직을 작성하기 전에 파이프라인을 흐르는 객체를 정의합니다. 이 모델은 모든 소스가 출처(어디서 왔는지, 어떤 쿼리가 찾았는지, 언제 수집되었는지, 어떻게 청킹되었는지)를 가지므로 나머지 코드를 더 이해하기 쉽게 만듭니다. research_agent/models.py 생성:
여기서 중요한 필드는 canonical_url, content_hash, chunks입니다. canonical_url은 검색 결과가 추적 파라미터나 fragment에서만 다를 때 에이전트가 같은 소스를 반복해서 읽지 않도록 합니다. content_hash는 다른 URL에 있더라도 중복 페이지를 잡는 데 도움이 됩니다. chunks는 context 한도로 인해 유용한 증거를 잃는 대신 긴 페이지를 더 작은 조각으로 요약할 수 있게 합니다. dataclass 아래에 헬퍼 함수를 추가하세요:
여기서 청킹은 의도적으로 단순합니다: 오버랩이 있는 고정 크기 문자 청크. Venice의 scrape endpoint가 보통 raw HTML보다 훨씬 깨끗한 Markdown을 반환하기 때문에 데모 리서치 에이전트에는 이 정도면 충분합니다. 긴 기술 문서에 대한 프로덕션 리서치라면 헤딩, 문단, 또는 토큰 수로 분할해 개선할 수 있습니다.

Venice 클라이언트 빌드

다음으로 작은 Venice 클라이언트를 만듭니다. Venice가 OpenAI 호환이므로 chat completion에 OpenAI Python SDK를 쓸 수도 있지만, 레퍼런스 구현은 같은 클라이언트가 Venice의 POST /augment/scrape endpoint를 호출할 수 있도록 httpx를 직접 사용합니다. research_agent/venice.py 생성:
from_env() 헬퍼는 시크릿을 소스 코드 밖에 둡니다. python-dotenv.env에서 VENICE_API_KEYVENICE_MODEL을 로드할 수 있기 때문에 로컬 개발이 편리합니다. 이제 chat completion을 추가하세요:
최종 보고서에는 스트리밍을 사용하고 싶습니다. 심층 보고서는 (훨씬 많은 텍스트를 생성하기 때문에) 상당히 더 오래 걸릴 수 있습니다. 이는 최종 출력을 생성하는 데 극도로 오랜 시간이 걸리는 요청에서 타임아웃 문제를 일으킬 수 있습니다. 스트리밍을 사용하면 이 문제를 제거하고 요청을 타임아웃 실패에 더 강하게 만들 수 있습니다:
그런 다음 스크래핑을 추가하세요:
Venice의 scrape endpoint는 공개 접근 가능한 URL을 받아 페이지를 Markdown으로 반환합니다. 즉, 모델이 raw HTML을 파싱할 필요가 없고, 소스 추출 prompt가 더 깨끗한 텍스트로 동작할 수 있습니다. 나머지 헬퍼는 재시도와 응답 파싱을 처리합니다:
전체 레포에는 스트리밍 chat completion에서 server-sent event를 읽는 견고한 _post_chat_stream() 헬퍼도 포함되어 있습니다. 스트리밍 없이 시작한 다음 나머지 리서치 흐름이 동작하면 추가할 수 있습니다.

검색 공급자 추가

검색 레이어는 두 가지 일을 합니다: 소스 URL을 찾고, Venice 스크래퍼를 통해 그 URL들을 가져옵니다. 레퍼런스 구현은 일반 웹 검색에 DuckDuckGo의 HTML endpoint를, 논문에 arXiv의 Atom API를 사용합니다. research_agent/web.py 생성:
이제 DuckDuckGo를 추가하세요:
그리고 arXiv:
WebSearch 클래스가 공급자를 조율하고 페이지를 가져옵니다:
전체 레퍼런스 구현은 재시도, 호스트 수준 요청 지연, 더 친절한 에러를 추가합니다. 리서치 에이전트는 자동화를 차단하거나, 예기치 않게 리다이렉트하거나, 일시적 에러를 반환하는 페이지를 다루는 데 많은 시간을 보내므로 그런 기능들은 유지할 가치가 있습니다. 하단에 작은 공급자 헬퍼를 추가하세요:

로컬 아티팩트 작성

리서치 워크플로의 경우 감사 가능성이 중요합니다. 최종 보고서가 놀라운 내용을 말한다면, 어떤 소스가 그것을 이끌었는지 검토할 수 있어야 합니다. research_agent/artifacts.py 생성:
이는 줄당 하나의 JSON 객체를 작성해 아티팩트를 추가하고, 검토하고, 나중에 명령줄 도구로 처리하기 쉽게 만듭니다.

리서치 에이전트 빌드

이제 Venice, 검색, 모델, 아티팩트가 있으니 실제 에이전트를 만들 수 있습니다. research_agent/agent.py 생성:
system prompt는 핵심 행동 가드레일입니다. 모델이 기억에서 인상적으로 들리는 보고서를 만들기를 원하지 않습니다. 소스 자료를 사용하고 증거가 빈약할 때 불확실성을 알리기를 원합니다. 아직 추가하지 않았다면 models.py에 두 개의 최종 dataclass도 필요합니다:
다음으로 ResearchAgent를 정의하세요:
run() 메서드가 리서치 패스를 조율합니다:
두 개의 seen_* 집합이 에이전트가 중복 소스에 시간을 낭비하지 않도록 막습니다. URL 중복 제거는 반복된 링크를 잡습니다. 콘텐츠 해시 중복 제거는 미러, 신디케이트된 게시물, 같은 최종 콘텐츠로 리다이렉트되는 페이지를 잡습니다.

초기 및 후속 검색 계획

첫 번째 모델 호출은 주제를 검색 쿼리로 바꿉니다:
각 리서치 패스 후 업데이트된 에이전트는 더 의도적인 갭 분석 단계를 수행합니다. 현재 노트를 살펴보고, 도메인별로 소스 클러스터를 세고, Venice에 어떤 커버리지가 누락되어 있는지 묻고, 그 갭을 아티팩트에 기록한 다음, 결과 쿼리를 다음 패스에 사용합니다. 갭 분석 루프 먼저 소스 균형을 추적하세요:
이는 에이전트가 소스 클러스터 캡처를 알아차릴 수 있는 단순한 방법을 제공합니다. 모든 소스가 한 회사, 한 프레임워크, 또는 한 도메인에서 온다면, 후속 쿼리는 같은 것을 더 모으는 대신 의도적으로 소스 집합을 넓혀야 합니다. 이제 후속 검색을 만들 때 그 균형 정보를 사용하세요:
새로운 레퍼런스 구현은 이것을 _gap_follow_up_queries()로 감싸고, Venice에 갭 레코드와 쿼리를 모두 반환하도록 요청합니다:
--artifacts가 활성화되면 이 레코드는 research_gaps.jsonl에 작성됩니다. 그러면 에이전트가 특정 2차 패스 쿼리를 검색한 이유에 대한 유용한 감사 추적을 얻습니다. 파서는 관대해야 합니다. 모델이 잘못된 JSON을 반환하면 에이전트는 원래 주제로 폴백합니다:
이 패턴은 에이전트 코드 전반에 걸쳐 사용할 가치가 있습니다: 구조화된 출력을 요청하고, 파싱하고, 출력이 사용 불가능할 때 단순한 폴백을 제공하세요.

소스 읽기 및 요약

이제 소스 노트를 수집합니다. 에이전트는 각 쿼리를 검색하고, Venice scrape를 통해 각 결과를 가져오고, Markdown을 청킹하고, 유용한 증거를 요약합니다.
개별 검색과 가져오기 실패가 전체 실행을 중단해서는 안 됩니다. 공개 웹은 지저분합니다. 어떤 페이지는 스크래핑을 차단하고, 어떤 페이지는 PDF를 반환하고, 어떤 페이지는 다운되어 있으며, 어떤 페이지는 예기치 않은 곳으로 리다이렉트합니다. 리서치 에이전트는 계속 움직이며 무엇이 실패했는지 기록해야 합니다. 소스 읽기 메서드는 다음과 같습니다:
각 소스 청크에 대해 Venice에 짧은 증거 요약과 정확한 인용을 요청하세요:
그런 다음 청크 요약을 소스 노트로 축소하세요:
이 2단계 요약이 에이전트가 기본 “이 URL들을 요약하세요” 스크립트보다 더 신뢰성 있게 느껴지게 만드는 부분입니다. 모델은 먼저 소스 청크를 읽고, 그 추출된 증거 조각들로부터 소스 수준 노트를 작성합니다.

최종 보고서 작성

에이전트가 소스 노트를 갖게 되면 보고서를 작성할 수 있습니다. 단일 패스 보고서 작성기로 시작하세요:
레퍼런스 구현은 심층 보고서를 위해 더 나아갑니다: Venice에 개요를 요청하고, 각 보고서 섹션을 별도로 초안하고, 마지막 편집자 패스에 완성된 보고서를 조립하고 내부 소스 ID를 각주 스타일 인용으로 변환하도록 요청합니다. 그 단계적 접근은 장문 리서치 출력이 필요할 때 유용한데, 하나의 거대한 prompt는 종종 너무 많이 압축하기 때문입니다. 업데이트된 prompt는 또한 보고서를 빈약한 의사결정 가이드 대신 광범위한 소스 기반 조사로 밀어붙입니다. 소스 베이스가 한 클러스터에 편향되어 있다면, 편집자 prompt는 Venice에 그 편향을 인정하고 이를 분야 전체의 대표로 제시하지 말라고 지시합니다. 다이제스트 헬퍼를 추가하세요:
마지막으로 에러 기록을 추가하세요:
이 시점에서 핵심 리서치 루프가 자리 잡혔습니다.

CLI 추가

이제 명령줄 진입점이 필요합니다. main.py 생성:
CLI는 리서치 중에 실제로 튜닝할 손잡이를 노출합니다: 이제 모든 것을 연결하세요:
이로써 동작하는 로컬 리서치 CLI가 생깁니다.

에이전트 실행

빠른 리서치 패스 실행:
보고서를 Markdown 파일에 작성:
더 많은 소스와 여러 공급자 사용:
최종 보고서 스타일 선택:
간결한 소스 기반 브리핑에는 brief, 더 풍부한 조사에는 standard, 단계적 개요/섹션/편집자 워크플로에는 deep을 사용하세요. 감사 가능한 아티팩트 저장:
아티팩트가 활성화되면 다음과 같은 파일이 보입니다:
이 파일들은 에이전트가 결론에 도달한 방식을 이해하고 싶을 때 유용합니다. 예를 들어 source_notes.jsonl은 요약된 소스 증거를, research_gaps.jsonl은 후속 검색이 생성된 이유를, errors.jsonl은 검색, 스크래핑, 요약 중 실패한 페이지를 보여줍니다.

프라이버시 및 신뢰성 노트

리서치 에이전트는 여러 시스템에 접근하므로 무엇이 어디로 가는지 정확하게 하는 것이 도움이 됩니다: 프라이빗 리서치 에이전트 데이터 경계 검색 경로의 더 많은 부분을 Venice 안에 두고 싶다면, 공급자 레이어를 DuckDuckGo를 직접 쿼리하는 대신 Venice의 POST /augment/search endpoint를 호출하도록 조정할 수 있습니다. 레퍼런스 구현은 데모가 실행하고 이해하기 쉽도록 경량 공개 공급자를 사용합니다. 신뢰성을 위해 이 기본값들을 보수적으로 유지하세요:
  • Venice 호출과 웹 요청에 재시도 사용.
  • 같은 호스트에서 많은 페이지를 읽고 있다면 작은 --request-delay 추가.
  • 광범위한 주제가 무기한 실행되지 않도록 --max-sources 상한.
  • 최종 출력을 감사할 수 있도록 중요한 보고서에는 --artifacts 저장.
  • 보고서를 ground truth가 아닌 브리핑으로 취급. 정확성이 중요할 때 인용을 원본 소스로 추적하세요.

부품 테스트

시스템의 대부분을 테스트하는 데 라이브 웹 요청이나 Venice 호출이 필요 없습니다. 레퍼런스 레포는 가짜 Venice와 가짜 웹 클래스로 리서치 루프, 중복 제거 동작, 아티팩트, 보고서 prompt를 테스트합니다. 유용한 첫 번째 테스트는 URL 정규화입니다:
그런 다음 중복 콘텐츠가 건너뛰어지는지 테스트:
가짜(Fake)는 에이전트 테스트를 훨씬 빠르고 덜 깨지게 만듭니다. 라이브 검색 결과, 네트워크 상태, 모델 출력에 의존하지 않고 오케스트레이션 로직을 검증할 수 있습니다.

벤치마킹

많은 AI 공급자가 이제 자체 심층 리서치 워크플로를 갖고 있으므로 레퍼런스 레포에는 Perplexity의 Deep Research 도구에 대한 간단한 벤치마크가 포함되어 있습니다. 두 에이전트에게 AI 에이전트 프레임워크 아키텍처에 대한 보고서 작성을 요청했고, 생성된 보고서는 GitHub 레포에 체크인되었습니다. 이는 공식 벤치마크가 아닙니다. 보고서 구조, 소스 커버리지, 인용 품질, 에이전트가 한 소스 클러스터에 과도하게 집중하는지를 검토하는 실용적 방법입니다. 그것이 또한 업데이트된 구현이 후속 검색 전에 research_gaps.jsonl과 소스 균형을 추적하는 이유입니다.

이 예제 확장

베이스라인 에이전트가 동작하면, 개선할 실용적 방법은 다음과 같습니다:
  • POST /augment/search를 사용해 Venice 검색 공급자 추가.
  • JSONL 파일 대신 작은 SQLite 데이터베이스에 보고서와 아티팩트 저장.
  • 신뢰할 수 있는 리서치 도메인에 대한 소스 allowlist 또는 blocklist 추가.
  • 깨끗한 HTML을 노출하지 않는 소스에 대해 Venice scrape와 문서 파싱을 결합해 PDF 지원 추가.
  • prompt 변경 후 리서치 품질을 비교할 수 있도록 주제와 예상 소스 유형의 평가 세트 추가.
  • 최종 보고서를 저장하기 전에 Venice에 뒷받침되지 않는 주장을 찾도록 요청하는 검토 단계 추가.
가장 큰 업그레이드는 보통 더 나은 소스 선택입니다. 쿼리 생성이 도움이 되지만, 저신호 요약보다 1차 소스, 표준 문서, 공식 docs, 논문, 변경 로그, 데이터셋 페이지를 선호함으로써 품질을 개선할 수도 있습니다.

마무리

읽어 주셔서 감사합니다! 이것이 Python과 Venice API로 실용적인 프라이빗 리서치 에이전트를 만드는 데 도움이 되었기를 바랍니다. 여기서 유용한 패턴은 단순히 “모델에게 무언가를 조사하라고 요청하는” 것이 아닙니다. 리서치를 감사 가능한 단계로 나누는 것입니다: 검색 계획, 소스 수집, 증거 추출, 소스 노트 작성, 갭에 대한 후속 작업, 인용과 함께 합성. 그 단계들을 명시적으로 유지함으로써 시간이 지남에 따라 검사하고, 테스트하고, 개선하기 더 쉬운 리서치 워크플로를 얻습니다.