From 6413fc1e97bfce8ca7402e61d39d58e7adb80838 Mon Sep 17 00:00:00 2001 From: Sebastian Husch Lee Date: Mon, 20 Jul 2026 09:39:13 +0200 Subject: [PATCH 1/5] add tutorial --- index.toml | 14 +- ...ing_Pre_Built_Agents_from_Agent_Pack.ipynb | 480 ++++++++++++++++++ 2 files changed, 493 insertions(+), 1 deletion(-) create mode 100644 tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb diff --git a/index.toml b/index.toml index 4a2160c5..6e524467 100644 --- a/index.toml +++ b/index.toml @@ -260,4 +260,16 @@ completion_time = "20 min" created_at = 2026-03-30 dependencies = ["haystack-ai", "turboquant-vllm", "transformers-haystack"] featured = false -python_version = "3.12" \ No newline at end of file +python_version = "3.12" + +[[tutorial]] +title = "Using Pre-Built Agents from Agent Pack" +description = "Run and customize the ready-made Advanced RAG and Deep Research agents from the experimental Agent Pack" +level = "advanced" +weight = 13 +notebook = "50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb" +aliases = [] +completion_time = "25 min" +created_at = 2026-07-20 +dependencies = ["agent-pack-haystack", "arrow", "tavily-haystack", "trafilatura", "pypdf"] +featured = false \ No newline at end of file diff --git a/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb b/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb new file mode 100644 index 00000000..446f22c0 --- /dev/null +++ b/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb @@ -0,0 +1,480 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "10827537", + "metadata": {}, + "source": [ + "# Tutorial: Using Pre-Built Agents from Agent Pack\n", + "\n", + "- **Level**: Advanced\n", + "- **Time to complete**: 25 minutes\n", + "- **Components/Packages Used**: [`agent-pack-haystack`](https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/agent_pack) ([`create_advanced_rag_agent`](https://docs.haystack.deepset.ai/docs/advanced-rag-agent), [`create_deep_research_agent`](https://docs.haystack.deepset.ai/docs/deep-research-agent)), [`Agent`](https://docs.haystack.deepset.ai/docs/agent), [`InMemoryDocumentStore`](https://docs.haystack.deepset.ai/docs/inmemorydocumentstore)\n", + "- **Prerequisites**: An [OpenAI API key](https://platform.openai.com/api-keys) and a [Tavily API key](https://app.tavily.com) (free tier available)\n", + "- **Goal**: After completing this tutorial, you'll understand what Agent Pack is and why it exists, and you'll have run and customized two ready-made agents: the **Advanced RAG Agent** and the **Deep Research Agent**." + ] + }, + { + "cell_type": "markdown", + "id": "98dd9cf3", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "A language model and a set of tools are the core building blocks of an agent. But a *robust* agent usually needs more than that: an architecture that splits work across sub-agents, techniques for keeping the context window small but focused, and hooks to shape the agent loop before and after it runs. Assembling those pieces correctly is where most of the effort goes.\n", + "\n", + "[**Agent Pack**](https://docs.haystack.deepset.ai/docs/agent-pack) is a collection of complex, pre-configured Haystack agents that package these techniques into working agents. Each one is a complete architecture built from Haystack primitives ([`Agent`](https://docs.haystack.deepset.ai/docs/agent), [Tools](https://docs.haystack.deepset.ai/docs/tool), [hooks](https://docs.haystack.deepset.ai/docs/hooks), [`State`](https://docs.haystack.deepset.ai/docs/state), and Pipelines), exposed behind a single `create_*` entry point.\n", + "\n", + "There are three ways to use an agent from the pack:\n", + "\n", + "- **Run it as is.** Call the `create_*` function, pass a question, and get an answer. The defaults are chosen to work out of the box.\n", + "- **Customize it.** Each entry point exposes keyword arguments for swapping models, adding tools, and tuning behavior.\n", + "- **Copy it.** Read the implementation and adapt it as a blueprint for your own architecture.\n", + "\n", + "### Why these two agents?\n", + "\n", + "The pack ships agents that solve genuinely hard, recurring problems, so you don't have to rebuild the architecture each time:\n", + "\n", + "- The **Advanced RAG Agent** tackles a common RAG failure mode: an agent that *guesses* which metadata fields and values exist and builds broken filters. Instead, this agent inspects the document store (fields, values, ranges) and constructs valid Haystack filters to narrow retrieval. Reach for it when your corpus has rich metadata (categories, dates, ratings, languages...) and answering questions well depends on filtering by it.\n", + "- The **Deep Research Agent** is a canonical multi-agent pattern: it researches a question on the web with an orchestrator that delegates focused sub-questions to isolated sub-researchers, then writes a cited Markdown report. Its key idea is **context management** through isolation and compression. Reach for it when a question needs broad, multi-source web research rather than a single lookup.\n", + "\n", + "In this tutorial you'll run both agents, look at what they return, and customize them." + ] + }, + { + "cell_type": "markdown", + "id": "a1114b46", + "metadata": {}, + "source": [ + ":::warning\n", + "**Agent Pack is experimental.** Its APIs and agent architectures can change in any release, without following the usual Haystack deprecation policy. It is distributed separately from `haystack-ai` (in [`haystack-core-integrations`](https://github.com/deepset-ai/haystack-core-integrations)) precisely so these patterns can evolve quickly. Expect things to change and occasionally break, and pin a version if you depend on it in production.\n", + ":::" + ] + }, + { + "cell_type": "markdown", + "id": "0549fb8d", + "metadata": {}, + "source": [ + "## Preparing the Environment\n", + "\n", + "First, install `agent-pack-haystack` along with the optional runtime dependencies the two agents need:\n", + "\n", + "- `arrow` renders today's date into the Advanced RAG Agent's system prompt, so it can build filters for relative dates like \"the last 5 years\".\n", + "- `tavily-haystack`, `trafilatura`, and `pypdf` power the Deep Research Agent's web search and its HTML/PDF page reading." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92f47f96", + "metadata": {}, + "outputs": [], + "source": [ + "%%bash\n", + "\n", + "pip install -q agent-pack-haystack arrow tavily-haystack trafilatura pypdf" + ] + }, + { + "cell_type": "markdown", + "id": "26c24d26", + "metadata": {}, + "source": [ + "### Enter API Keys\n", + "\n", + "Both agents use OpenAI models by default. The Deep Research Agent additionally uses [Tavily](https://tavily.com) for web search. Enter the keys below:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "87b8157b", + "metadata": {}, + "outputs": [], + "source": [ + "from getpass import getpass\n", + "import os\n", + "\n", + "if not os.environ.get(\"OPENAI_API_KEY\"):\n", + " os.environ[\"OPENAI_API_KEY\"] = getpass(\"Enter your OpenAI API key:\")\n", + "if not os.environ.get(\"TAVILY_API_KEY\"):\n", + " os.environ[\"TAVILY_API_KEY\"] = getpass(\"Enter your Tavily API key:\")" + ] + }, + { + "cell_type": "markdown", + "id": "767401d6", + "metadata": {}, + "source": [ + "## Part 1: The Advanced RAG Agent\n", + "\n", + "The Advanced RAG Agent answers questions from documents it retrieves out of a document store. What makes it *advanced* is that it doesn't guess your metadata: it can inspect the store, discover which fields and values exist, and build a [metadata filter](https://docs.haystack.deepset.ai/docs/metadata-filtering) to narrow retrieval when that helps. Plain, unfiltered retrieval stays available when it doesn't.\n", + "\n", + "### Indexing a corpus with metadata\n", + "\n", + "Let's index a small set of documents with varied metadata (`category`, `year`, `rating`), then ask a question that can only be answered well by filtering on that metadata." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4bda1e15", + "metadata": {}, + "outputs": [], + "source": [ + "from haystack import Document\n", + "from haystack.document_stores.in_memory import InMemoryDocumentStore\n", + "\n", + "document_store = InMemoryDocumentStore()\n", + "document_store.write_documents(\n", + " [\n", + " Document(\n", + " content=\"CRISPR gene editing corrected a hereditary blindness mutation in a clinical trial.\",\n", + " meta={\"category\": \"science\", \"year\": 2021, \"rating\": 4.6},\n", + " ),\n", + " Document(\n", + " content=\"A quantum computer demonstrated error-corrected logical qubits.\",\n", + " meta={\"category\": \"science\", \"year\": 2023, \"rating\": 4.8},\n", + " ),\n", + " Document(\n", + " content=\"Dolly the sheep became the first mammal cloned from an adult somatic cell.\",\n", + " meta={\"category\": \"science\", \"year\": 1996, \"rating\": 4.2},\n", + " ),\n", + " Document(\n", + " content=\"The Berlin Wall fell, a decisive moment in the end of the Cold War.\",\n", + " meta={\"category\": \"history\", \"year\": 1989, \"rating\": 4.7},\n", + " ),\n", + " Document(\n", + " content=\"Argentina won the FIFA World Cup final against France on penalties.\",\n", + " meta={\"category\": \"sports\", \"year\": 2022, \"rating\": 4.9},\n", + " ),\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d4fa6802", + "metadata": {}, + "source": [ + "### Creating the agent\n", + "\n", + "`create_advanced_rag_agent` needs two things: the `document_store` (which feeds the metadata-inspection tools and a direct fetch-by-filter tool) and a `retriever` (which becomes the agent's relevance-scoring `search_documents` tool). Here we use a keyword [`InMemoryBM25Retriever`](https://docs.haystack.deepset.ai/docs/inmemorybm25retriever), but it can also be an embedding retriever or a full retrieval `Pipeline`.\n", + "\n", + "The retriever you pass should be **relevance-scoring** (BM25, embedding, or hybrid). Direct, unscored fetching by metadata is already handled by the agent's built-in `fetch_documents_by_filter` tool." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "919aa4e3", + "metadata": {}, + "outputs": [], + "source": [ + "from haystack.components.retrievers.in_memory import InMemoryBM25Retriever\n", + "from haystack_integrations.agent_pack import create_advanced_rag_agent\n", + "\n", + "rag_agent = create_advanced_rag_agent(\n", + " document_store=document_store, retriever=InMemoryBM25Retriever(document_store=document_store, top_k=5)\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "3b5c2c9a", + "metadata": {}, + "source": [ + "### Running the agent\n", + "\n", + "Call the agent with your question as a user message. We pass [`print_streaming_chunk`](https://docs.haystack.deepset.ai/docs/agent#streaming) as the `streaming_callback` so you can watch the agent work: it first lists the metadata fields, checks the `category` values and the `year` range, then retrieves with a filter it builds itself." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9a5b1e8", + "metadata": {}, + "outputs": [], + "source": [ + "from haystack.dataclasses import ChatMessage\n", + "from haystack.components.generators.utils import print_streaming_chunk\n", + "\n", + "result = rag_agent.run(\n", + " messages=[ChatMessage.from_user(\"What science advances happened after 2015?\")],\n", + " streaming_callback=print_streaming_chunk,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "68cada14", + "metadata": {}, + "source": [ + "The agent's answer is in `last_message`, and every document it retrieved during the run is accumulated (deduplicated by id) under `documents`. The answer cites documents by the first 8 characters of their id, for example `[doc a1b2c3d4]`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d7c51b5", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"ANSWER:\\n\", result[\"last_message\"].text)\n", + "\n", + "print(\"\\nRETRIEVED DOCUMENTS:\")\n", + "for doc in result[\"documents\"]:\n", + " print(f\"[doc {doc.id[:8]}] {doc.meta} :: {doc.content[:60]}\")" + ] + }, + { + "cell_type": "markdown", + "id": "f48421c0", + "metadata": {}, + "source": [ + "Under the hood, the agent worked through three logical stages using five tools: it **inspected** the metadata (`list_metadata_fields`, `get_metadata_field_values`, `get_metadata_field_range`), **retrieved** documents (`search_documents`, optionally narrowed by a filter, or `fetch_documents_by_filter` for direct lookups), and **answered** using only what it retrieved. To keep filters valid, the Haystack filter grammar is embedded directly in the retrieval tools' parameter descriptions, so the model learns it at the point of use.\n", + "\n", + "> 💡 The metadata tools rely on document store methods (`get_metadata_fields_info`, `get_metadata_field_unique_values`, `get_metadata_field_min_max`) that aren't part of the base `DocumentStore` protocol. `InMemoryDocumentStore` and most integrations implement them (OpenSearch, Elasticsearch, Weaviate, Chroma, pgvector, Qdrant, Pinecone, and more)." + ] + }, + { + "cell_type": "markdown", + "id": "dcd8b9e2", + "metadata": {}, + "source": [ + "### Customizing the agent\n", + "\n", + "Everything is configured through keyword arguments. Only `document_store` and `retriever` are required. A few useful ones:\n", + "\n", + "- `llm`: the chat generator that drives the agent loop. Defaults to `OpenAIResponsesChatGenerator(\"gpt-5.4\")` with low reasoning effort. Swap in any tool-calling generator, from OpenAI or another provider.\n", + "- `max_agent_steps`: caps the loop (default `20`). If the loop is cut off before an answer is written, a built-in `BackupAnswerHook` makes one extra call to produce a best-effort answer, so `last_message` always carries text.\n", + "- `max_fetched_docs`: how many documents `fetch_documents_by_filter` shows per call (default `10`).\n", + "- `extra_tools`, `state_schema`, `hooks`: extend the agent with your own tools, state, and hooks.\n", + "\n", + "Here we swap the LLM for a smaller, widely available model and tighten the step budget:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "edee54d4", + "metadata": {}, + "outputs": [], + "source": [ + "from haystack.components.generators.chat import OpenAIChatGenerator\n", + "\n", + "custom_rag_agent = create_advanced_rag_agent(\n", + " document_store=document_store,\n", + " retriever=InMemoryBM25Retriever(document_store=document_store, top_k=5),\n", + " llm=OpenAIChatGenerator(model=\"gpt-4o-mini\"),\n", + " max_agent_steps=10,\n", + ")\n", + "\n", + "result = custom_rag_agent.run(messages=[ChatMessage.from_user(\"Which documents describe events before 1990?\")])\n", + "print(result[\"last_message\"].text)" + ] + }, + { + "cell_type": "markdown", + "id": "41b3360b", + "metadata": {}, + "source": [ + "**Using a retrieval pipeline.** To use a multi-component retrieval flow (for example hybrid retrieval), pass a `Pipeline` as `retriever` and supply `retrieval_pipeline_input_mapping` (mapping the tool's `query` and `filters` to your pipeline's input sockets) and, optionally, `retrieval_pipeline_output_mapping`. See the [Advanced RAG Agent docs](https://docs.haystack.deepset.ai/docs/advanced-rag-agent) for a full hybrid-retrieval example.\n", + "\n", + "**Using the tools on their own.** The four document-store-backed tools are exported individually and bundled as `DocumentStoreToolset`, so you can drop them into your own `Agent` with your own prompt, treating the pack as a toolbox rather than a finished agent:\n", + "\n", + "```python\n", + "from haystack.components.agents import Agent\n", + "from haystack_integrations.agent_pack.advanced_rag import DocumentStoreToolset\n", + "\n", + "agent = Agent(\n", + " chat_generator=...,\n", + " tools=[DocumentStoreToolset(document_store), my_retrieval_tool],\n", + ")\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "8efe9b0b", + "metadata": {}, + "source": [ + "## Part 2: The Deep Research Agent\n", + "\n", + "The Deep Research Agent takes a question, researches it on the web, and produces a structured, cited Markdown report. It's a small multi-agent system organized into three phases: **Scope**, **Research**, and **Write**.\n", + "\n", + "- **Scope** (a `before_run` hook): rewrites your question into a focused research brief.\n", + "- **Research**: an **orchestrator** agent splits the brief into a few non-overlapping sub-questions and delegates each to an isolated **sub-researcher** agent. Each sub-researcher searches the web, optionally reads promising pages, reflects, and returns a *compressed, cited summary*.\n", + "- **Write** (an `after_run` hook): turns the brief plus the collected summaries into the final report.\n", + "\n", + "The key idea is **context management**. Raw web content (search results, full pages, PDFs) is large and noisy; if it all piled into one context window, output quality would degrade. So each sub-researcher runs in its own private context, and only its short summary leaves it, both to the orchestrator (to decide whether to dig deeper) and into a shared `notes` list (which the writer turns into the report). The bulky raw research never propagates." + ] + }, + { + "cell_type": "markdown", + "id": "1f20f77e", + "metadata": {}, + "source": [ + "### Running the agent\n", + "\n", + "`create_deep_research_agent()` works with zero arguments. But the defaults research broadly (up to 5 sub-questions, 5 concurrent sub-researchers, 20 steps each), which can take several minutes and cost real tokens. For this tutorial we'll deliberately scope it down, which also previews the customization knobs. Even so, expect this cell to take a couple of minutes." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d55db360", + "metadata": {}, + "outputs": [], + "source": [ + "from haystack_integrations.agent_pack import create_deep_research_agent\n", + "\n", + "research_agent = create_deep_research_agent(\n", + " max_subtopics=2, # delegate at most 2 sub-questions (breadth)\n", + " max_concurrent_researchers=2, # run at most 2 sub-researchers at once\n", + " max_researcher_steps=6, # cap each sub-researcher's search/read/think loop\n", + " max_search_results=5, # results per web_search call\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8dc042f6", + "metadata": {}, + "outputs": [], + "source": [ + "from haystack.dataclasses import ChatMessage\n", + "\n", + "result = research_agent.run(\n", + " messages=[ChatMessage.from_user(\"What are the main techniques for managing the context window in LLM agents?\")]\n", + ")\n", + "\n", + "print(result[\"report\"])" + ] + }, + { + "cell_type": "markdown", + "id": "586d0d9e", + "metadata": {}, + "source": [ + "The main output is `report`: the final Markdown report with inline `[text](url)` citations. The run also returns the intermediate `brief` and `notes`, plus the standard `Agent` outputs (`messages`, `last_message`, `step_count`, `token_usage`, `tool_call_counts`). Let's look at the brief the Scope phase produced and how many research notes were collected:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5e88ffe8", + "metadata": {}, + "outputs": [], + "source": [ + "print(\"RESEARCH BRIEF:\\n\", result[\"brief\"])\n", + "print(f\"\\nCollected {len(result['notes'])} research note(s).\")\n", + "print(\"\\nFIRST NOTE (a sub-researcher summary):\\n\", result[\"notes\"][0][:800])" + ] + }, + { + "cell_type": "markdown", + "id": "8d3eb1d3", + "metadata": {}, + "source": [ + "### Customizing the agent\n", + "\n", + "Each phase takes its own `ChatGenerator`, so you can mix models by cost and capability, or swap in a different provider entirely:\n", + "\n", + "- `scope_llm`, `orchestrator_llm`, `writer_llm`: default to `OpenAIResponsesChatGenerator(\"gpt-5.4\")` (the heavier reasoning steps).\n", + "- `researcher_llm`, `summarizer_llm`: default to `OpenAIResponsesChatGenerator(\"gpt-5.4-mini\")` (run many times, so a cheaper model keeps cost down).\n", + "\n", + "And the breadth/depth of the investigation is fully tunable: `max_subtopics`, `max_concurrent_researchers`, `max_orchestrator_steps`, `max_researcher_steps`, `max_search_results`, and `max_content_length`.\n", + "\n", + "For example, to make the whole run cheaper you might point every phase at a smaller model:\n", + "\n", + "```python\n", + "from haystack.components.generators.chat import OpenAIChatGenerator\n", + "from haystack_integrations.agent_pack import create_deep_research_agent\n", + "\n", + "cheap_agent = create_deep_research_agent(\n", + " scope_llm=OpenAIChatGenerator(model=\"gpt-4o-mini\"),\n", + " orchestrator_llm=OpenAIChatGenerator(model=\"gpt-4o-mini\"),\n", + " researcher_llm=OpenAIChatGenerator(model=\"gpt-4o-mini\"),\n", + " summarizer_llm=OpenAIChatGenerator(model=\"gpt-4o-mini\"),\n", + " writer_llm=OpenAIChatGenerator(model=\"gpt-4o-mini\"),\n", + " max_subtopics=3,\n", + ")\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "aa45f1d4", + "metadata": {}, + "source": [ + "## Agent Pack as a blueprint\n", + "\n", + "Beyond running and customizing, the third way to use the pack is to **copy it**. Both agents are built entirely from public Haystack primitives, so their source doubles as a reference architecture:\n", + "\n", + "- The Deep Research Agent shows how to nest agents (a sub-agent exposed to the orchestrator as a `ComponentTool`) and how `outputs_to_string` and `outputs_to_state` control what a sub-agent returns to the caller versus what it saves for later, the core of its context isolation.\n", + "- The Advanced RAG Agent shows how to build tools over a document store, embed a grammar in a tool's parameter description, accumulate results in `State`, and use an `after_run` hook as a safety net.\n", + "\n", + "Browse the source in [`haystack-core-integrations/integrations/agent_pack`](https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/agent_pack) and adapt whichever parts fit your use case." + ] + }, + { + "cell_type": "markdown", + "id": "94f5479d", + "metadata": {}, + "source": [ + "## What's next\n", + "\n", + "🎉 Congratulations! You've run and customized two ready-made agents from Agent Pack, and seen how they can also serve as blueprints for your own architectures.\n", + "\n", + "Because Agent Pack is experimental, keep an eye on its [documentation](https://docs.haystack.deepset.ai/docs/agent-pack) and [repository](https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/agent_pack) for changes, and [open an issue](https://github.com/deepset-ai/haystack-core-integrations/issues) if you find a bug or have an idea for an agent that could belong in the pack.\n", + "\n", + "To learn more about building agents from scratch, check out these tutorials:\n", + "\n", + "- [Build a Tool-Calling Agent](https://haystack.deepset.ai/tutorials/43_building_a_tool_calling_agent)\n", + "- [Creating a Multi-Agent System with Haystack](https://haystack.deepset.ai/tutorials/45_creating_a_multi_agent_system)\n", + "- [Human-in-the-Loop with Haystack Agents](https://haystack.deepset.ai/tutorials/47_human_in_the_loop_agent)\n", + "\n", + "To stay up to date on the latest Haystack developments, you can [sign up for our newsletter](https://landing.deepset.ai/haystack-community-updates) or [join Haystack discord community](https://discord.gg/Dr63fr9NDS)." + ] + }, + { + "cell_type": "markdown", + "id": "c87c7c14", + "metadata": {}, + "source": [ + "## About us\n", + "\n", + "This [Haystack](https://haystack.deepset.ai/) notebook was made with love by [deepset](https://deepset.ai) in Berlin, Germany\n", + "\n", + "We bring NLP to the industry via open source! \n", + "Our focus: Industry specific language models & large scale QA systems. \n", + " \n", + "Some of our other work: \n", + "- [Distilled roberta-base-squad2 (aka \"tinyroberta\")](https://huggingface.co/deepset/tinyroberta-squad2)\n", + "- [German BERT (aka \"bert-base-german-cased\")](https://deepset.ai/german-bert)\n", + "- [GermanQuAD and GermanDPR datasets and models (aka \"gelectra-base-germanquad\", \"gbert-base-germandpr\")](https://deepset.ai/germanquad)\n", + "\n", + "Get in touch and join the Haystack community\n", + "\n", + "

For more info on Haystack, visit our GitHub repo and Documentation. \n", + "\n", + "We also have a Discord community where you can chat with us and other community members!

" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 77aa3bcdd185c25aefcf775b5b8391d74101ce66 Mon Sep 17 00:00:00 2001 From: Sebastian Husch Lee Date: Mon, 20 Jul 2026 09:49:00 +0200 Subject: [PATCH 2/5] improve end section --- ...ing_Pre_Built_Agents_from_Agent_Pack.ipynb | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb b/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb index 446f22c0..1dc07414 100644 --- a/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb +++ b/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb @@ -439,30 +439,6 @@ "\n", "To stay up to date on the latest Haystack developments, you can [sign up for our newsletter](https://landing.deepset.ai/haystack-community-updates) or [join Haystack discord community](https://discord.gg/Dr63fr9NDS)." ] - }, - { - "cell_type": "markdown", - "id": "c87c7c14", - "metadata": {}, - "source": [ - "## About us\n", - "\n", - "This [Haystack](https://haystack.deepset.ai/) notebook was made with love by [deepset](https://deepset.ai) in Berlin, Germany\n", - "\n", - "We bring NLP to the industry via open source! \n", - "Our focus: Industry specific language models & large scale QA systems. \n", - " \n", - "Some of our other work: \n", - "- [Distilled roberta-base-squad2 (aka \"tinyroberta\")](https://huggingface.co/deepset/tinyroberta-squad2)\n", - "- [German BERT (aka \"bert-base-german-cased\")](https://deepset.ai/german-bert)\n", - "- [GermanQuAD and GermanDPR datasets and models (aka \"gelectra-base-germanquad\", \"gbert-base-germandpr\")](https://deepset.ai/germanquad)\n", - "\n", - "Get in touch and join the Haystack community\n", - "\n", - "

For more info on Haystack, visit our GitHub repo and Documentation. \n", - "\n", - "We also have a Discord community where you can chat with us and other community members!

" - ] } ], "metadata": { From f2dda96abd43d945a1822b3bff49192d53017cb9 Mon Sep 17 00:00:00 2001 From: Sebastian Husch Lee Date: Mon, 20 Jul 2026 10:15:23 +0200 Subject: [PATCH 3/5] improvements --- index.toml | 2 +- ...ing_Pre_Built_Agents_from_Agent_Pack.ipynb | 46 ++++++++++++++----- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/index.toml b/index.toml index 6e524467..b6c4bcfe 100644 --- a/index.toml +++ b/index.toml @@ -271,5 +271,5 @@ notebook = "50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb" aliases = [] completion_time = "25 min" created_at = 2026-07-20 -dependencies = ["agent-pack-haystack", "arrow", "tavily-haystack", "trafilatura", "pypdf"] +dependencies = ["haystack-ai>=3.0", "agent-pack-haystack", "arrow", "tavily-haystack", "trafilatura", "pypdf"] featured = false \ No newline at end of file diff --git a/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb b/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb index 1dc07414..4010f9e7 100644 --- a/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb +++ b/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb @@ -10,7 +10,7 @@ "- **Level**: Advanced\n", "- **Time to complete**: 25 minutes\n", "- **Components/Packages Used**: [`agent-pack-haystack`](https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/agent_pack) ([`create_advanced_rag_agent`](https://docs.haystack.deepset.ai/docs/advanced-rag-agent), [`create_deep_research_agent`](https://docs.haystack.deepset.ai/docs/deep-research-agent)), [`Agent`](https://docs.haystack.deepset.ai/docs/agent), [`InMemoryDocumentStore`](https://docs.haystack.deepset.ai/docs/inmemorydocumentstore)\n", - "- **Prerequisites**: An [OpenAI API key](https://platform.openai.com/api-keys) and a [Tavily API key](https://app.tavily.com) (free tier available)\n", + "- **Prerequisites**: Haystack 3.0 or later, an [OpenAI API key](https://platform.openai.com/api-keys), and a [Tavily API key](https://app.tavily.com) (free tier available)\n", "- **Goal**: After completing this tutorial, you'll understand what Agent Pack is and why it exists, and you'll have run and customized two ready-made agents: the **Advanced RAG Agent** and the **Deep Research Agent**." ] }, @@ -233,7 +233,15 @@ "id": "f48421c0", "metadata": {}, "source": [ - "Under the hood, the agent worked through three logical stages using five tools: it **inspected** the metadata (`list_metadata_fields`, `get_metadata_field_values`, `get_metadata_field_range`), **retrieved** documents (`search_documents`, optionally narrowed by a filter, or `fetch_documents_by_filter` for direct lookups), and **answered** using only what it retrieved. To keep filters valid, the Haystack filter grammar is embedded directly in the retrieval tools' parameter descriptions, so the model learns it at the point of use.\n", + "### How it works under the hood\n", + "\n", + "The agent is a single Haystack [`Agent`](https://docs.haystack.deepset.ai/docs/agent) that works through three logical stages using five tools:\n", + "\n", + "- **Inspect metadata** with `list_metadata_fields`, `get_metadata_field_values`, and `get_metadata_field_range` (the system prompt tells it to list the fields first).\n", + "- **Retrieve documents** with `search_documents` (your relevance-scoring retriever, optionally narrowed by a filter) or `fetch_documents_by_filter` (a direct metadata lookup when scoring isn't needed).\n", + "- **Answer** using only the retrieved documents, citing each as `[doc ]`.\n", + "\n", + "To keep filters valid, the Haystack filter grammar is embedded directly in the retrieval tools' parameter descriptions, so the model learns it at the point of use rather than from a long system prompt. Every retrieved document is accumulated in the agent's [`State`](https://docs.haystack.deepset.ai/docs/state) under `documents` (deduplicated by id), which is why the run returns them alongside the answer. And if the loop is cut off by `max_agent_steps` before an answer is written, a built-in `BackupAnswerHook` (an `after_run` hook) makes one extra call to produce a best-effort answer, so `last_message` always carries text.\n", "\n", "> 💡 The metadata tools rely on document store methods (`get_metadata_fields_info`, `get_metadata_field_unique_values`, `get_metadata_field_min_max`) that aren't part of the base `DocumentStore` protocol. `InMemoryDocumentStore` and most integrations implement them (OpenSearch, Elasticsearch, Weaviate, Chroma, pgvector, Qdrant, Pinecone, and more)." ] @@ -302,13 +310,7 @@ "source": [ "## Part 2: The Deep Research Agent\n", "\n", - "The Deep Research Agent takes a question, researches it on the web, and produces a structured, cited Markdown report. It's a small multi-agent system organized into three phases: **Scope**, **Research**, and **Write**.\n", - "\n", - "- **Scope** (a `before_run` hook): rewrites your question into a focused research brief.\n", - "- **Research**: an **orchestrator** agent splits the brief into a few non-overlapping sub-questions and delegates each to an isolated **sub-researcher** agent. Each sub-researcher searches the web, optionally reads promising pages, reflects, and returns a *compressed, cited summary*.\n", - "- **Write** (an `after_run` hook): turns the brief plus the collected summaries into the final report.\n", - "\n", - "The key idea is **context management**. Raw web content (search results, full pages, PDFs) is large and noisy; if it all piled into one context window, output quality would degrade. So each sub-researcher runs in its own private context, and only its short summary leaves it, both to the orchestrator (to decide whether to dig deeper) and into a shared `notes` list (which the writer turns into the report). The bulky raw research never propagates." + "The Deep Research Agent takes a question, researches it on the web, and produces a structured, cited Markdown report. Under the hood it's a small multi-agent system (we'll look at how it works right after running it), but the entry point is a single call." ] }, { @@ -374,6 +376,24 @@ "print(\"\\nFIRST NOTE (a sub-researcher summary):\\n\", result[\"notes\"][0][:800])" ] }, + { + "cell_type": "markdown", + "id": "39aabb3e", + "metadata": {}, + "source": [ + "### How it works under the hood\n", + "\n", + "The agent is built around a single top-level [`Agent`](https://docs.haystack.deepset.ai/docs/agent) acting as the **orchestrator**, with two [hooks](https://docs.haystack.deepset.ai/docs/hooks) that wrap its loop to create three phases:\n", + "\n", + "- **Scope** (a `before_run` hook): a plain LLM call rewrites your question into a focused research `brief`, stored on the agent's [`State`](https://docs.haystack.deepset.ai/docs/state).\n", + "- **Research** (the orchestrator loop): the orchestrator splits the brief into a few non-overlapping sub-questions and delegates each to an isolated **sub-researcher** agent, exposed to it as a tool. It can fire several off at once (bounded by `max_concurrent_researchers`) and collects their summaries into a shared `notes` list.\n", + "- **Write** (an `after_run` hook): a final LLM call turns the brief plus `notes` into the `report`.\n", + "\n", + "Each **sub-researcher** is its own `Agent` that searches the web (`web_search`), optionally reads promising pages (`read_url`, which fetches and summarizes a page or PDF toward the question), reflects (`think_tool`), and finishes by writing one short, cited summary.\n", + "\n", + "The key idea is **context management**. Raw web content (search results, full pages, PDFs) is large and noisy; if it all piled into one context window, output quality would degrade. So each sub-researcher runs in its own private context, and only its short summary leaves it, controlled by two settings on the delegation tool: `outputs_to_string` (what the orchestrator sees) and `outputs_to_state` (what's appended to `notes` for the writer). The bulky raw research never propagates to the orchestrator or the writer." + ] + }, { "cell_type": "markdown", "id": "8d3eb1d3", @@ -427,11 +447,13 @@ "source": [ "## What's next\n", "\n", - "🎉 Congratulations! You've run and customized two ready-made agents from Agent Pack, and seen how they can also serve as blueprints for your own architectures.\n", + "🎉 Congratulations! You've run and customized both agents in Agent Pack, seen how they work under the hood, and how they can serve as blueprints for your own architectures.\n", + "\n", + "**Realistically, what to expect from Agent Pack going forward:** it's an early, experimental project, so treat these agents as a fast-moving starting point rather than a stable API. Expect the `create_*` signatures and internals to change as the patterns settle (the customization interface in particular is still being refined), so pin a version if you build on it. The pack lives outside `haystack-ai` on purpose so it can move quickly, and it doubles as a place to prototype capabilities that may later graduate into Haystack itself. More agents are likely to land here over time.\n", "\n", - "Because Agent Pack is experimental, keep an eye on its [documentation](https://docs.haystack.deepset.ai/docs/agent-pack) and [repository](https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/agent_pack) for changes, and [open an issue](https://github.com/deepset-ai/haystack-core-integrations/issues) if you find a bug or have an idea for an agent that could belong in the pack.\n", + "The most useful thing you can do is give feedback: if you hit a bug, or have an idea for a complex agent that belongs in the pack, [open an issue](https://github.com/deepset-ai/haystack-core-integrations/issues). Keep an eye on the [documentation](https://docs.haystack.deepset.ai/docs/agent-pack) and the [repository](https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/agent_pack) for updates.\n", "\n", - "To learn more about building agents from scratch, check out these tutorials:\n", + "To go deeper on building agents from scratch, check out these tutorials:\n", "\n", "- [Build a Tool-Calling Agent](https://haystack.deepset.ai/tutorials/43_building_a_tool_calling_agent)\n", "- [Creating a Multi-Agent System with Haystack](https://haystack.deepset.ai/tutorials/45_creating_a_multi_agent_system)\n", From e230a074adc3aa4e00f73c7dccb38b207c0fefce Mon Sep 17 00:00:00 2001 From: Sebastian Husch Lee Date: Mon, 20 Jul 2026 12:28:34 +0200 Subject: [PATCH 4/5] PR comment --- .../50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb b/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb index 4010f9e7..12cad2eb 100644 --- a/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb +++ b/tutorials/50_Using_Pre_Built_Agents_from_Agent_Pack.ipynb @@ -55,14 +55,7 @@ "cell_type": "markdown", "id": "0549fb8d", "metadata": {}, - "source": [ - "## Preparing the Environment\n", - "\n", - "First, install `agent-pack-haystack` along with the optional runtime dependencies the two agents need:\n", - "\n", - "- `arrow` renders today's date into the Advanced RAG Agent's system prompt, so it can build filters for relative dates like \"the last 5 years\".\n", - "- `tavily-haystack`, `trafilatura`, and `pypdf` power the Deep Research Agent's web search and its HTML/PDF page reading." - ] + "source": "## Preparing the Environment\n\nFirst, install `agent-pack-haystack` along with the optional runtime dependencies the two agents need:\n\n- `arrow` renders today's date into the agents' system prompts (both the Advanced RAG and Deep Research agents use it), so they can reason about relative dates like \"the last 5 years\".\n- `tavily-haystack`, `trafilatura`, and `pypdf` power the Deep Research Agent's web search and its HTML/PDF page reading." }, { "cell_type": "code", @@ -475,4 +468,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file From bc37580c74a71ad7a30826beb0b31d8eb8968293 Mon Sep 17 00:00:00 2001 From: Sebastian Husch Lee Date: Mon, 20 Jul 2026 14:58:15 +0200 Subject: [PATCH 5/5] add missing api key to workflow --- .github/workflows/run_tutorials.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/run_tutorials.yml b/.github/workflows/run_tutorials.yml index e7c66624..81f6ff16 100644 --- a/.github/workflows/run_tutorials.yml +++ b/.github/workflows/run_tutorials.yml @@ -78,6 +78,7 @@ jobs: SERPERDEV_API_KEY: ${{ secrets.SERPERDEV_API_KEY }} NOTION_API_KEY: ${{ secrets.NOTION_API_KEY }} MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }} + TAVILY_API_KEY: ${{ secrets.TAVILY_API_KEY }} steps: - name: Checkout