Skip to content

Commit 6c73dd2

Browse files
Merge branch 'main' into fix/remove-deprecated-components
# Conflicts: # tutorials/43_Building_a_Tool_Calling_Agent.ipynb
2 parents 37eb1f0 + c98721c commit 6c73dd2

9 files changed

Lines changed: 101 additions & 189 deletions

.github/workflows/dc_sync.yml

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,17 @@ jobs:
4646
- name: Checkout
4747
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
4848

49-
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
49+
- name: Setup Python and uv
50+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
5051
with:
5152
python-version: "3.11"
5253

5354
- name: Install requirements
55+
env:
56+
UV_EXCLUDE_NEWER: P3D # reject packages uploaded within the last 3 days (supply chain protection)
5457
run: |
55-
pip install --upgrade pip
56-
pip install -r requirements.txt
58+
uv venv
59+
uv pip install -r requirements.txt
5760
5861
- name: Generate file to upload
5962
id: file-generator
@@ -62,6 +65,7 @@ jobs:
6265
METADATA_FILE="$(basename ${{ matrix.file }} .ipynb).yml"
6366
echo "file=text/$FILE" >> "$GITHUB_OUTPUT"
6467
echo "metadata_file=text/$METADATA_FILE" >> "$GITHUB_OUTPUT"
68+
. .venv/bin/activate
6569
python scripts/generate_txt.py --metadata --notebooks ${{ matrix.file }}
6670
6771
- name: Upload tutorial to deepset Cloud

.github/workflows/full_dc_sync.yml

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,27 @@ jobs:
1010
- name: Checkout
1111
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
1212

13-
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
13+
- name: Setup Python and uv
14+
uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7.6.0
1415
with:
1516
python-version: "3.11"
1617

1718
- name: Install requirements
19+
env:
20+
UV_EXCLUDE_NEWER: P3D # reject packages uploaded within the last 3 days (supply chain protection)
1821
run: |
19-
pip install --upgrade pip
20-
pip install -r requirements.txt
22+
uv venv
23+
uv pip install -r requirements.txt
2124
2225
- name: Generate all tutorials and their metadata
23-
run: python scripts/generate_txt.py --notebooks all --metadata
26+
run: |
27+
. .venv/bin/activate
28+
python scripts/generate_txt.py --notebooks all --metadata
2429
2530
- name: Full sync
2631
env:
2732
DEEPSET_CLOUD_WORKSPACE: ${{ secrets.DEEPSET_CLOUD_WORKSPACE }}
2833
DEEPSET_CLOUD_API_KEY: ${{ secrets.DEEPSET_CLOUD_API_KEY }}
29-
run: python scripts/full_dc_sync.py
34+
run: |
35+
. .venv/bin/activate
36+
python scripts/full_dc_sync.py

.github/workflows/run_tutorials.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,12 @@ jobs:
9797
VERSION="${{ matrix.haystack_version }}"
9898
uv pip install "haystack-ai==${VERSION#v}"
9999
fi
100-
uv pip install nbconvert ipython
100+
uv pip install --exclude-newer P3D nbconvert ipython # P3D = 3-day cutoff; haystack-ai above is exempt
101101
102102
- name: Install tutorial dependencies
103103
if: toJSON(matrix.dependencies) != '[]'
104+
env:
105+
UV_EXCLUDE_NEWER: P3D # reject packages uploaded within the last 3 days (supply chain protection)
104106
run: |
105107
uv pip install "${{ join(matrix.dependencies, '" "')}}"
106108
@@ -124,6 +126,6 @@ jobs:
124126
125127
- name: Notify Slack on nightly failure
126128
if: failure() && github.event_name != 'pull_request'
127-
uses: deepset-ai/notify-slack-action@3cda73b77a148f16f703274198e7771340cf862b # v1
129+
uses: deepset-ai/notify-slack-action@a65def0c8bf91d6520286ab34280151c76a5a008 # v1.1.0
128130
with:
129131
slack-webhook-url: ${{ secrets.SLACK_WEBHOOK_URL_NOTIFICATIONS }}

.github/workflows/verify_generation.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ jobs:
1919
python-version: "3.11"
2020

2121
- name: Install dependencies
22+
env:
23+
UV_EXCLUDE_NEWER: P3D # reject packages uploaded within the last 3 days (supply chain protection)
2224
run: |
2325
uv venv
2426
uv pip install -r requirements.txt

tutorials/39_Embedding_Metadata_for_Improved_Retrieval.ipynb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@
132132
},
133133
{
134134
"cell_type": "code",
135-
"execution_count": 17,
135+
"execution_count": null,
136136
"metadata": {},
137137
"outputs": [
138138
{
@@ -170,6 +170,8 @@
170170
"from haystack import Document\n",
171171
"from haystack.document_stores.in_memory import InMemoryDocumentStore\n",
172172
"\n",
173+
"wikipedia.set_user_agent(\"haystack-tutorials\")\n",
174+
"\n",
173175
"some_bands = \"\"\"The Beatles,The Cure\"\"\".split(\",\")\n",
174176
"\n",
175177
"raw_docs = []\n",

tutorials/43_Building_a_Tool_Calling_Agent.ipynb

Lines changed: 22 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,7 @@
55
"metadata": {
66
"id": "2OvkPji9O-qX"
77
},
8-
"source": [
9-
"# Tutorial: Building a Tool-Calling Agent\n",
10-
"\n",
11-
"- **Level**: Beginner\n",
12-
"- **Time to complete**: 15 minutes\n",
13-
"- **Components Used**: [`Agent`](https://docs.haystack.deepset.ai/docs/agent), [`OpenAIChatGenerator`](https://docs.haystack.deepset.ai/docs/openaichatgenerator), [`SerperDevWebSearch`](https://docs.haystack.deepset.ai/docs/serperdevwebsearch), [`ComponentTool`](https://docs.haystack.deepset.ai/docs/componenttool), [`SuperComponent`](https://docs.haystack.deepset.ai/docs/supercomponents)\n",
14-
"- **Prerequisites**: You must have an [OpenAI API Key](https://platform.openai.com/api-keys) and a [SerperDev API Key](https://serper.dev/api-key)\n",
15-
"- **Goal**: After completing this tutorial, you'll have learned how to create an Agent that can use tools both components and pipelines to answer questions and perform tasks."
16-
]
8+
"source": "# Tutorial: Building a Tool-Calling Agent\n\n- **Level**: Beginner\n- **Time to complete**: 15 minutes\n- **Components Used**: [`Agent`](https://docs.haystack.deepset.ai/docs/agent), [`OpenAIChatGenerator`](https://docs.haystack.deepset.ai/docs/openaichatgenerator), [`SerperDevWebSearch`](https://docs.haystack.deepset.ai/docs/serperdevwebsearch), [`ComponentTool`](https://docs.haystack.deepset.ai/docs/componenttool), [`PipelineTool`](https://docs.haystack.deepset.ai/docs/pipelinetool)\n- **Prerequisites**: You must have an [OpenAI API Key](https://platform.openai.com/api-keys) and a [SerperDev API Key](https://serper.dev/api-key)\n- **Goal**: After completing this tutorial, you'll have learned how to create an Agent that can use both components and pipelines as tools to answer questions and perform tasks."
179
},
1810
{
1911
"cell_type": "markdown",
@@ -203,8 +195,8 @@
203195
},
204196
"outputs": [],
205197
"source": [
206-
"from haystack.components.builders.answer_builder import AnswerBuilder\n",
207198
"from haystack.components.converters.html import HTMLToDocument\n",
199+
"from haystack.components.converters.output_adapter import OutputAdapter\n",
208200
"from haystack.components.fetchers.link_content import LinkContentFetcher\n",
209201
"from haystack.components.websearch.serper_dev import SerperDevWebSearch\n",
210202
"from haystack.dataclasses import ChatMessage\n",
@@ -215,27 +207,33 @@
215207
"search_pipeline.add_component(\"search\", SerperDevWebSearch(top_k=10))\n",
216208
"search_pipeline.add_component(\"fetcher\", LinkContentFetcher(timeout=3, raise_on_failure=False, retry_attempts=2))\n",
217209
"search_pipeline.add_component(\"converter\", HTMLToDocument())\n",
210+
"search_pipeline.add_component(\n",
211+
" \"output_adapter\",\n",
212+
" OutputAdapter(\n",
213+
" template=\"\"\"\n",
214+
"{%- for doc in docs -%}\n",
215+
" {%- if doc.content -%}\n",
216+
" <search-result url=\\\"{{ doc.meta.url }}\\\">\n",
217+
" {{ doc.content|truncate(25000) }}\n",
218+
" </search-result>\n",
219+
" {%- endif -%}\n",
220+
"{%- endfor -%}\n",
221+
"\"\"\",\n",
222+
" output_type=str,\n",
223+
" ),\n",
224+
")\n",
218225
"\n",
219226
"search_pipeline.connect(\"search.links\", \"fetcher.urls\")\n",
220-
"search_pipeline.connect(\"fetcher.streams\", \"converter.sources\")"
227+
"search_pipeline.connect(\"fetcher.streams\", \"converter.sources\")\n",
228+
"search_pipeline.connect(\"converter.documents\", \"output_adapter.docs\")"
221229
]
222230
},
223231
{
224232
"cell_type": "markdown",
225233
"metadata": {
226234
"id": "wLIcnWl-66QA"
227235
},
228-
"source": [
229-
"### Creating a Tool from a Pipeline\n",
230-
"\n",
231-
"Next, wrap the `search_pipeline` inside a [`SuperComponent`](https://docs.haystack.deepset.ai/docs/supercomponents) and turn it into a tool using `ComponentTool`. The `ComponentTool` automatically creates LLM-compatible tool schemas based on the component’s input sockets. \n",
232-
"\n",
233-
"To control what data the `ComponentTool` should receive and returns, you can optionally define `input_mapping` and `output_mapping`. For example, this lets you ensure that only the `\"query\"` input of the `search_pipeline` is mentioned in LLM-compatible tool schema, and only `\"search_result\"` is returned from the `SuperComponent`.\n",
234-
"\n",
235-
"Finally, you can initialize the Agent with the resulting `search_tool`.\n",
236-
"\n",
237-
"> 💡 Learn alternative ways of creating tools in [`Tool`](https://docs.haystack.deepset.ai/docs/tool) and [`MCPTool`](https://docs.haystack.deepset.ai/docs/mcptool) documentation pages."
238-
]
236+
"source": "### Creating a Tool from a Pipeline\n\nNext, wrap the `search_pipeline` in a [`PipelineTool`](https://docs.haystack.deepset.ai/docs/pipelinetool). `PipelineTool` directly exposes a pipeline as an LLM-callable tool, replacing the older pattern of wrapping a pipeline in a `SuperComponent` and then passing it to `ComponentTool`.\n\nUse `input_mapping` and `output_mapping` to control which pipeline inputs and outputs are exposed. Here, `input_mapping` ensures only `\"query\"` is surfaced in the tool schema, and `output_mapping` extracts the formatted string produced by `output_adapter`.\n\nFinally, you can initialize the Agent with the resulting `search_tool`.\n\n> 💡 Learn alternative ways of creating tools in [`Tool`](https://docs.haystack.deepset.ai/docs/tool) and [`MCPTool`](https://docs.haystack.deepset.ai/docs/mcptool) documentation pages."
239237
},
240238
{
241239
"cell_type": "code",
@@ -244,43 +242,7 @@
244242
"id": "yxaN3KBo65pv"
245243
},
246244
"outputs": [],
247-
"source": [
248-
"from haystack.core.super_component import SuperComponent\n",
249-
"from haystack.tools import ComponentTool\n",
250-
"from haystack.components.agents import Agent\n",
251-
"from haystack.components.generators.chat import OpenAIChatGenerator\n",
252-
"\n",
253-
"search_component = SuperComponent(\n",
254-
" pipeline=search_pipeline,\n",
255-
" input_mapping={\"query\": [\"search.query\"]},\n",
256-
" output_mapping={\"converter.documents\": \"search_result\"},\n",
257-
")\n",
258-
"\n",
259-
"search_tool = ComponentTool(\n",
260-
" name=\"search\",\n",
261-
" description=\"Use this tool to search for information on the internet.\",\n",
262-
" component=search_component,\n",
263-
" outputs_to_string={\"source\": \"search_result\"},\n",
264-
")\n",
265-
"\n",
266-
"agent = Agent(\n",
267-
" chat_generator=OpenAIChatGenerator(model=\"gpt-4o-mini\"),\n",
268-
" tools=[search_tool],\n",
269-
" system_prompt=\"\"\"\n",
270-
" You are a deep research assistant.\n",
271-
" You create comprehensive research reports to answer the user's questions.\n",
272-
" You use the 'search'-tool to answer any questions.\n",
273-
" You perform multiple searches until you have the information you need to answer the question.\n",
274-
" Make sure you research different aspects of the question.\n",
275-
" Use markdown to format your response.\n",
276-
" When you use information from the websearch results, cite your sources using markdown links.\n",
277-
" It is important that you cite accurately.\n",
278-
" \"\"\",\n",
279-
" exit_conditions=[\"text\"],\n",
280-
" max_agent_steps=20,\n",
281-
")"
282-
]
283-
},
245+
"source": "from haystack.tools import PipelineTool\nfrom haystack.components.agents import Agent\nfrom haystack.components.generators.chat import OpenAIChatGenerator\n\nsearch_tool = PipelineTool(\n name=\"search\",\n description=\"Use this tool to search for information on the internet.\",\n pipeline=search_pipeline,\n input_mapping={\"query\": [\"search.query\"]},\n output_mapping={\"output_adapter.output\": \"search_result\"},\n outputs_to_string={\"source\": \"search_result\"},\n)\n\nagent = Agent(\n chat_generator=OpenAIChatGenerator(model=\"gpt-4o-mini\"),\n tools=[search_tool],\n system_prompt=\"\"\"\n You are a deep research assistant.\n You create comprehensive research reports to answer the user's questions.\n You use the 'search'-tool to answer any questions.\n You perform multiple searches until you have the information you need to answer the question.\n Make sure you research different aspects of the question.\n Use markdown to format your response.\n When you use information from the websearch results, cite your sources using markdown links.\n It is important that you cite accurately.\n \"\"\",\n exit_conditions=[\"text\"],\n max_agent_steps=20,\n)" },
284246
{
285247
"cell_type": "markdown",
286248
"metadata": {
@@ -303,7 +265,6 @@
303265
"query = \"What are the latest updates on the Artemis moon mission?\"\n",
304266
"messages = [ChatMessage.from_user(query)]\n",
305267
"\n",
306-
"agent.warm_up()\n",
307268
"agent_output = agent.run(messages=messages)\n",
308269
"\n",
309270
"print(agent_output[\"messages\"][-1].text)"
@@ -336,22 +297,7 @@
336297
"metadata": {
337298
"id": "czMjWwnxPA-3"
338299
},
339-
"source": [
340-
"Let's break down this last example in the tutorial.\n",
341-
"The **Agent** is the main component that orchestrates the interaction between the LLM and tools.\n",
342-
"We use **ComponentTool** as a wrapper that allows Haystack components to be used as tools by the agent.\n",
343-
"The **SuperComponent** wraps entire pipelines so that they can be used as components and thus also as tools.\n",
344-
"\n",
345-
"We created a sophisticated search pipeline that:\n",
346-
"1. Searches the web using SerperDevWebSearch\n",
347-
"2. Fetches content from the found links\n",
348-
"3. Converts HTML content to Documents\n",
349-
"4. Formats the results for the Agent\n",
350-
"\n",
351-
"The Agent then uses this pipeline as a tool to gather information and generate comprehensive answers.\n",
352-
"\n",
353-
"By the way, did you know that the Agent is a Haystack component itself? That means you can use and combine an Agent in your pipelines just like any other component!"
354-
]
300+
"source": "Let's break down this last example in the tutorial.\nThe **Agent** is the main component that orchestrates the interaction between the LLM and tools.\nWe use **ComponentTool** as a wrapper that allows individual Haystack components to be used as tools by the agent.\nThe **PipelineTool** wraps entire pipelines so that they can be used as tools directly, without needing an intermediate `SuperComponent`.\n\nWe created a sophisticated search pipeline that:\n1. Searches the web using SerperDevWebSearch\n2. Fetches content from the found links\n3. Converts HTML content to Documents\n4. Formats the results for the Agent\n\nThe Agent then uses this pipeline as a tool to gather information and generate comprehensive answers.\n\nBy the way, did you know that the Agent is a Haystack component itself? That means you can use and combine an Agent in your pipelines just like any other component!"
355301
},
356302
{
357303
"cell_type": "markdown",

0 commit comments

Comments
 (0)