From 660a268b9af2399c32a56380e34641ce3ad1cb4d Mon Sep 17 00:00:00 2001 From: zilto Date: Wed, 16 Oct 2024 15:37:39 -0400 Subject: [PATCH 1/8] added HaystackAction --- burr/integrations/haystack.py | 197 +++++ examples/haystack-integration/README.md | 5 + examples/haystack-integration/notebook.ipynb | 837 ++++++++++++++++++ .../haystack-integration/statemachine.png | Bin 0 -> 57178 bytes 4 files changed, 1039 insertions(+) create mode 100644 burr/integrations/haystack.py create mode 100644 examples/haystack-integration/README.md create mode 100644 examples/haystack-integration/notebook.ipynb create mode 100644 examples/haystack-integration/statemachine.png diff --git a/burr/integrations/haystack.py b/burr/integrations/haystack.py new file mode 100644 index 00000000..be212353 --- /dev/null +++ b/burr/integrations/haystack.py @@ -0,0 +1,197 @@ +from typing import Any, Optional, Union + +from haystack import Pipeline +from haystack.core.component import Component +from haystack.core.component.types import _empty as haystack_empty + +from burr.core.action import Action +from burr.core.graph import Graph, GraphBuilder +from burr.core.state import State + + +class HaystackAction(Action): + """Create a Burr `Action` from a Haystack `Component`.""" + + def __init__( + self, + component: Component, + reads: Union[list[str], dict[str, str]], + writes: Union[list[str], dict[str, str]], + name: Optional[str] = None, + bound_params: Optional[dict] = None, + ): + """ + Notes + - need to figure out how to use bind + - you can use `action.bind()` to set values of `Component.run()`. + """ + self._component = component + self._name = name + self._reads = list(reads.keys()) if isinstance(reads, dict) else reads + self._writes = list(writes.values()) if isinstance(writes, dict) else writes + self._bound_params = bound_params if bound_params is not None else {} + + self._socket_mapping = {} + if isinstance(reads, dict): + for state_field, socket_name in reads.items(): + self._socket_mapping[socket_name] = state_field + + if isinstance(writes, dict): + for socket_name, state_field in writes.items(): + self._socket_mapping[socket_name] = state_field + + @property + def reads(self) -> list[str]: + return self._reads + + @property + def writes(self) -> list[str]: + return self._writes + + @property + def inputs(self) -> tuple[dict[str, str], dict[str, str]]: + """Return dictionaries of required and optional inputs.""" + required_inputs, optional_inputs = {}, {} + for socket_name, input_socket in self._component.__haystack_input__._sockets_dict.items(): + state_field_name = self._socket_mapping.get(socket_name, socket_name) + + if state_field_name in self.reads: + continue + elif state_field_name in self._bound_params: + continue + + if input_socket.default_value == haystack_empty: + required_inputs[state_field_name] = input_socket.type + else: + optional_inputs[state_field_name] = input_socket.type + + return required_inputs, optional_inputs + + def run(self, state: State, **run_kwargs) -> dict[str, Any]: + """Call the Haystack `Component.run()` method. It returns a dictionary + of results with mapping {socket_name: value}. + + Values come from 3 sources: + - bound parameters (from HaystackAction instantiation, or by using `.bind()`) + - state (from previous actions) + - run_kwargs (inputs from `Application.run()`) + """ + values = {} + + # here, precedence matters. Alternatively, we could unpack all dictionaries at once + # which would throw an error for key collisions + for param, value in self._bound_params: + values[param] = value + + for param in self.reads: + values[param] = state[param] + + for param, value in run_kwargs.keys(): + values[param] = value + + return self._component.run(**values) + + def update(self, result: dict, state: State) -> State: + """Update the state using the results of `Component.run()`.""" + state_update = {} + for socket_name, value in result.items(): + state_field_name = self._socket_mapping.get(socket_name, socket_name) + if state_field_name in self.writes: + state_update[state_field_name] = value + + return state.update(**state_update) + + def bind(self, **kwargs): + """Bind a parameter for the `Component.run()` call.""" + self._bound_params.update(**kwargs) + return self + + +def _socket_name_mapping(pipeline) -> dict[str, str]: + """Map socket names to a single state field name. + + In Haystack, components communicate via sockets. A socket called + "embedding" in one component can be renamed to "query_embedding" when + passed to another component. + + In Burr, there is a single state object so we need a mapping to resolve + that `embedding` and `query_embedding` point to the same value. This function + creates a mapping {socket_name: state_field} to rename sockets when creating + the Burr `Graph`. + """ + sockets_connections = [ + (edge_data["from_socket"].name, edge_data["to_socket"].name) + for _, _, edge_data in pipeline.graph.edges.data() + ] + mapping = {} + + for from_, to in sockets_connections: + if from_ not in mapping: + mapping[from_] = {from_} + mapping[from_].add(to) + + if to not in mapping: + mapping[to] = {to} + mapping[to].add(from_) + + result = {} + for key, values in mapping.items(): + unique_name = min(values) + result[key] = unique_name + + return result + + +def _connected_inputs(pipeline) -> dict[str, list[str]]: + """Get all input sockets that are connected to other components.""" + return { + name: [ + socket.name + for socket in data.get("input_sockets", {}).values() + if socket.is_variadic or socket.senders + ] + for name, data in pipeline.graph.nodes(data=True) + } + + +def _connected_outputs(pipeline) -> dict[str, list[str]]: + """Get all output sockets that are connected to other components.""" + return { + name: [ + socket.name for socket in data.get("output_sockets", {}).values() if socket.receivers + ] + for name, data in pipeline.graph.nodes(data=True) + } + + +def haystack_pipeline_to_burr_graph(pipeline: Pipeline) -> Graph: + """Convert a Haystack `Pipeline` to a Burr `Graph`. + + From the Haystack `Pipeline`, we can easily retrieve transitions. + For actions, we need to create `HaystackAction` from components + and map their sockets to Burr state fields + """ + socket_mapping = _socket_name_mapping(pipeline) + connected_inputs = _connected_inputs(pipeline) + connected_outputs = _connected_outputs(pipeline) + + transitions = [(from_, to) for from_, to, _ in pipeline.graph.edges] + + actions = [] + for component_name, component in pipeline.walk(): + inputs_from_state = [ + socket_mapping[socket_name] for socket_name in connected_inputs[component_name] + ] + outputs_to_state = [ + socket_mapping[socket_name] for socket_name in connected_outputs[component_name] + ] + + haystack_action = HaystackAction( + name=component_name, + component=component, + reads=inputs_from_state, + writes=outputs_to_state, + ) + actions.append(haystack_action) + + return GraphBuilder().with_actions(*actions).with_transitions(*transitions).build() diff --git a/examples/haystack-integration/README.md b/examples/haystack-integration/README.md new file mode 100644 index 00000000..b99d7e17 --- /dev/null +++ b/examples/haystack-integration/README.md @@ -0,0 +1,5 @@ +# Haystack + Burr integration + +Haystack is a Python library to build AI pipelines. It assembles `Component` objects into a `Pipeline`, which is a graph of operations. One benefit of Haystack is that it provides many pre-built components to manage documents and interact with LLMs. + +This notebook shows how to convert a Haystack `Component` into a Burr `Action` and a `Pipeline` into a `Graph`. This allows you to integrate Haystack with Burr and leverage other Burr and Burr UI features! diff --git a/examples/haystack-integration/notebook.ipynb b/examples/haystack-integration/notebook.ipynb new file mode 100644 index 00000000..bcf711fe --- /dev/null +++ b/examples/haystack-integration/notebook.ipynb @@ -0,0 +1,837 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Haystack + Burr integration\n", + "\n", + "Haystack is a Python library to build AI pipelines. It assembles `Component` objects into a `Pipeline`, which is a graph of operations. One benefit of Haystack is that it provides many pre-built components to manage documents and interact with LLMs.\n", + "\n", + "This notebook shows how to convert a Haystack `Component` into a Burr `Action` and a `Pipeline` into a `Graph`. This allows you to integrate Haystack with Burr and leverage other Burr and Burr UI features!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Native Haystack\n", + "The next cells show how to build a simple RAG pipeline using Haystack. You create the components and add them to the pipeline using `.add_component()`. Then, you need to specify connections between components using `.connect()`." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/tjean/projects/dagworks/burr/.venv/lib/python3.11/site-packages/haystack/core/errors.py:34: DeprecationWarning: PipelineMaxLoops is deprecated and will be remove in version '2.7.0'; use PipelineMaxComponentRuns instead.\n", + " warnings.warn(\n", + "/home/tjean/projects/dagworks/burr/.venv/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import os\n", + "\n", + "from haystack.components.embedders import SentenceTransformersTextEmbedder\n", + "from haystack.components.builders import PromptBuilder\n", + "from haystack.components.generators import OpenAIGenerator\n", + "from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever\n", + "from haystack.document_stores.in_memory import InMemoryDocumentStore\n", + "from haystack import Pipeline\n", + "\n", + "# dummy OpenAI key to avoid raising an error\n", + "os.environ[\"OPENAI_API_KEY\"] = \"sk-...\"\n", + "\n", + "# 1. create components\n", + "document_store = InMemoryDocumentStore()\n", + "text_embedder = SentenceTransformersTextEmbedder(model=\"sentence-transformers/all-MiniLM-L6-v2\")\n", + "prompt_builder = PromptBuilder(template=\"Document: {{documents}} Question: {{question}}\")\n", + "retriever = InMemoryEmbeddingRetriever(document_store)\n", + "generator = OpenAIGenerator(model=\"gpt-4o-mini\")\n", + "\n", + "# 2. create pipeline\n", + "basic_rag_pipeline = Pipeline()\n", + "\n", + "# 3. add components to the pipeline\n", + "basic_rag_pipeline.add_component(\"text_embedder\", text_embedder)\n", + "basic_rag_pipeline.add_component(\"retriever\", retriever)\n", + "basic_rag_pipeline.add_component(\"prompt_builder\", prompt_builder)\n", + "basic_rag_pipeline.add_component(\"llm\", generator)\n", + "\n", + "# 4. connect components\n", + "basic_rag_pipeline.connect(\"text_embedder.embedding\", \"retriever.query_embedding\")\n", + "basic_rag_pipeline.connect(\"retriever\", \"prompt_builder.documents\")\n", + "basic_rag_pipeline.connect(\"prompt_builder\", \"llm\")\n", + "\n", + "basic_rag_pipeline.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Without using any integration, you could use Haystack within Burr's `actions`. The next is illustrative of how it can work." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "%3\n", + "\n", + "\n", + "\n", + "embed_text\n", + "\n", + "embed_text(): query_embedding\n", + "\n", + "\n", + "\n", + "retrieve_documents\n", + "\n", + "retrieve_documents(query_embedding): documents\n", + "\n", + "\n", + "\n", + "embed_text->retrieve_documents\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__user_question\n", + "\n", + "input: user_question\n", + "\n", + "\n", + "\n", + "input__user_question->embed_text\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "build_prompt\n", + "\n", + "build_prompt(documents): question_prompt\n", + "\n", + "\n", + "\n", + "input__user_question->build_prompt\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "retrieve_documents->build_prompt\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "generate_answer\n", + "\n", + "generate_answer(question_prompt): answer\n", + "\n", + "\n", + "\n", + "build_prompt->generate_answer\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from burr.core import action, State, ApplicationBuilder\n", + "\n", + "\n", + "@action(reads=[], writes=[\"query_embedding\"])\n", + "def embed_text(state: State, user_question: str) -> State:\n", + " text_embedder = SentenceTransformersTextEmbedder(model=\"sentence-transformers/all-MiniLM-L6-v2\")\n", + "\n", + " results = text_embedder.run(text=user_question)\n", + " return state.update(query_embedding=results[\"embedding\"])\n", + "\n", + "\n", + "@action(reads=[\"query_embedding\"], writes=[\"documents\"])\n", + "def retrieve_documents(state: State) -> State:\n", + " query_embedding = state[\"query_embedding\"]\n", + "\n", + " document_store = InMemoryDocumentStore()\n", + " retriever = InMemoryEmbeddingRetriever(document_store)\n", + "\n", + " results = retriever.run(query_embedding=query_embedding)\n", + " return state.update(documents=results[\"documents\"])\n", + "\n", + "\n", + "@action(reads=[\"documents\"], writes=[\"question_prompt\"])\n", + "def build_prompt(state: State, user_question: str) -> State:\n", + " documents = state[\"documents\"]\n", + "\n", + " prompt_builder = PromptBuilder(template=\"Document: {{documents}} Question: {{question}}\")\n", + "\n", + " results = prompt_builder.run(documents=documents, question=user_question) \n", + " return state.update(question_prompt=results[\"prompt\"])\n", + "\n", + "\n", + "@action(reads=[\"question_prompt\"], writes=[\"answer\"])\n", + "def generate_answer(state: State) -> State:\n", + " question_prompt = state[\"question_prompt\"]\n", + "\n", + " generator = OpenAIGenerator(model=\"gpt-4o-mini\")\n", + "\n", + " results = generator.run(prompt=question_prompt)\n", + " return state.update(answer=results[\"text\"])\n", + "\n", + "\n", + "app = (\n", + " ApplicationBuilder()\n", + " .with_actions(\n", + " embed_text,\n", + " retrieve_documents,\n", + " build_prompt,\n", + " generate_answer\n", + " )\n", + " .with_transitions(\n", + " (\"embed_text\", \"retrieve_documents\"),\n", + " (\"retrieve_documents\", \"build_prompt\"),\n", + " (\"build_prompt\", \"generate_answer\"))\n", + " .with_entrypoint(\"embed_text\")\n", + " .build()\n", + ")\n", + "app.visualize(include_state=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Notes:\n", + "- Instead of using `Component` objects, we wrap them into `@action` decorated functions.\n", + "- While Haystack pipelines allow components to communicate via sockets, Burr relies on a centralized state.\n", + "- Burr requires building the `Graph` \"all at once\" via the `ApplicationBuilder` or `GraphBuilder` while Haystack allows to incrementally add `.add_component()` and `.connect()` statements to the pipeline.\n", + "- Haystack allows the parameters of `Component.run()` to be provided by other components via sockets or from the user inputs. Burr separates the two via the `State` object or the function arguments given through `.run(inputs=...)`.\n", + "- Haystack `Component` are objects, meaning they need to be instantiated and are stateful. Burr `Action` are stateless, which allows to resume runs from any `State` and enable \"time-travel debugging\".\n", + "- Haystack uses a `Router` component to [expression conditional edges](https://docs.haystack.deepset.ai/reference/routers-api#conditionalrouter). Burr allows to add condition directly via the `.with_transitions()` method by specifying in the tuple `(from_action, to_action, condition)`." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "import burr.integrations.haystack\n", + "\n", + "%reload_ext autoreload\n", + "%autoreload 2\n", + "%aimport burr.integrations.haystack" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Burr's `HaystackAction`\n", + "\n", + "To avoid having to wrap each component into an `@action` function, the `HaystackAction` was added to Burr. It takes an instantiated `Component`, a `name`, and the `reads/writes` of the action.\n", + "\n", + "The next cell shows two identical actions, one without the integration (taken from the previous section) and one using `HaystackAction`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "from burr.integrations.haystack import HaystackAction\n", + "\n", + "@action(reads=[\"query_embedding\"], writes=[\"documents\"])\n", + "def retrieve_documents(state: State) -> State:\n", + " query_embedding = state[\"query_embedding\"]\n", + "\n", + " document_store = InMemoryDocumentStore()\n", + " retriever = InMemoryEmbeddingRetriever(document_store)\n", + " \n", + " results = retriever.run(query_embedding=query_embedding)\n", + " return state.update(documents=results[\"documents\"])\n", + "\n", + "\n", + "haystack_retrieve_documents = HaystackAction(\n", + " component=InMemoryEmbeddingRetriever(InMemoryDocumentStore()),\n", + " name=\"retrieve_documents\",\n", + " reads=[\"query_embedding\"],\n", + " writes=[\"documents\"],\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The next cell shows the entire application using the `HaystackAction` integration. The action `display_answer` defined using `@action` was added to show you can can combine both approaches.\n", + "\n", + "Note that some for some `HaystackAction`, `reads` and `writes` are dictionaries instead of the usual lists. This helps map the values from the Burr `State` to the Haystack `Component.run()` parameters and outputs. \n", + "\n", + "For example, in `generate_answer`:\n", + " - `reads={\"question_prompt\": \"prompt\"}` maps the state to the run method `Component.run(prompt=state[\"question_prompt\"])`\n", + " - `writes={\"text\": \"answer\"}` maps the results of `.run()` to the state update `state.update(answer=Component.run(...)[\"text\"])`" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "%3\n", + "\n", + "\n", + "\n", + "embed_text\n", + "\n", + "embed_text(): query_embedding\n", + "\n", + "\n", + "\n", + "retrieve_documents\n", + "\n", + "retrieve_documents(query_embedding): documents\n", + "\n", + "\n", + "\n", + "embed_text->retrieve_documents\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__text\n", + "\n", + "input: text\n", + "\n", + "\n", + "\n", + "input__text->embed_text\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "build_prompt\n", + "\n", + "build_prompt(documents): question_prompt\n", + "\n", + "\n", + "\n", + "retrieve_documents->build_prompt\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__top_k\n", + "\n", + "input: top_k\n", + "\n", + "\n", + "\n", + "input__top_k->retrieve_documents\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__scale_score\n", + "\n", + "input: scale_score\n", + "\n", + "\n", + "\n", + "input__scale_score->retrieve_documents\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__return_embedding\n", + "\n", + "input: return_embedding\n", + "\n", + "\n", + "\n", + "input__return_embedding->retrieve_documents\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__filters\n", + "\n", + "input: filters\n", + "\n", + "\n", + "\n", + "input__filters->retrieve_documents\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "generate_answer\n", + "\n", + "generate_answer(question_prompt): answer\n", + "\n", + "\n", + "\n", + "build_prompt->generate_answer\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__template\n", + "\n", + "input: template\n", + "\n", + "\n", + "\n", + "input__template->build_prompt\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__template_variables\n", + "\n", + "input: template_variables\n", + "\n", + "\n", + "\n", + "input__template_variables->build_prompt\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__question\n", + "\n", + "input: question\n", + "\n", + "\n", + "\n", + "input__question->build_prompt\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "display_answer\n", + "\n", + "display_answer(answer): \n", + "\n", + "\n", + "\n", + "generate_answer->display_answer\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__generation_kwargs\n", + "\n", + "input: generation_kwargs\n", + "\n", + "\n", + "\n", + "input__generation_kwargs->generate_answer\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__streaming_callback\n", + "\n", + "input: streaming_callback\n", + "\n", + "\n", + "\n", + "input__streaming_callback->generate_answer\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from burr.core import action, State, ApplicationBuilder\n", + "\n", + "embed_text = HaystackAction(\n", + " component=SentenceTransformersTextEmbedder(model=\"sentence-transformers/all-MiniLM-L6-v2\"),\n", + " name=\"embed_text\",\n", + " reads=[],\n", + " writes={\"embedding\": \"query_embedding\"},\n", + ")\n", + "\n", + "retrieve_documents = HaystackAction(\n", + " component=InMemoryEmbeddingRetriever(InMemoryDocumentStore()),\n", + " name=\"retrieve_documents\",\n", + " reads=[\"query_embedding\"],\n", + " writes=[\"documents\"],\n", + ")\n", + "\n", + "build_prompt = HaystackAction(\n", + " component=PromptBuilder(template=\"Document: {{documents}} Question: {{question}}\"),\n", + " name=\"build_prompt\",\n", + " reads=[\"documents\"],\n", + " writes={\"prompt\": \"question_prompt\"},\n", + ")\n", + "\n", + "generate_answer = HaystackAction(\n", + " component=OpenAIGenerator(model=\"gpt-4o-mini\"),\n", + " name=\"generate_answer\",\n", + " reads={\"question_prompt\": \"prompt\"},\n", + " writes={\"text\": \"answer\"}\n", + ")\n", + "\n", + "@action(reads=[\"answer\"], writes=[])\n", + "def display_answer(state: State) -> State:\n", + " print(state[\"answer\"])\n", + " return state\n", + "\n", + "\n", + "app = (\n", + " ApplicationBuilder()\n", + " .with_actions(\n", + " embed_text,\n", + " retrieve_documents,\n", + " build_prompt,\n", + " generate_answer,\n", + " display_answer,\n", + " )\n", + " .with_transitions(\n", + " (\"embed_text\", \"retrieve_documents\"),\n", + " (\"retrieve_documents\", \"build_prompt\"),\n", + " (\"build_prompt\", \"generate_answer\"),\n", + " (\"generate_answer\", \"display_answer\"),\n", + " )\n", + " .with_entrypoint(\"embed_text\")\n", + " .build()\n", + ")\n", + "app.visualize(include_state=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Converting a Haystack `Pipeline`\n", + "\n", + "If you have an existing Haystack `Pipeline`, you can convert it into a Burr `Graph` using in a single line of code using `haystack_pipeline_to_burr_graph()`.\n", + "\n", + "Next, we convert the `basic_rag_pipeline` defined at the beginning of the notebook. The resulting `Graph` can be passed to the `ApplicationBuilder.with_graph()` clause.\n", + "\n", + "The visualization should match the previous ones, but with different names (e.g., `generate_answer` is `llm`)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/svg+xml": [ + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "%3\n", + "\n", + "\n", + "\n", + "text_embedder\n", + "\n", + "text_embedder(): embedding\n", + "\n", + "\n", + "\n", + "retriever\n", + "\n", + "retriever(embedding): documents\n", + "\n", + "\n", + "\n", + "text_embedder->retriever\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__text\n", + "\n", + "input: text\n", + "\n", + "\n", + "\n", + "input__text->text_embedder\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "prompt_builder\n", + "\n", + "prompt_builder(documents): prompt\n", + "\n", + "\n", + "\n", + "retriever->prompt_builder\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__scale_score\n", + "\n", + "input: scale_score\n", + "\n", + "\n", + "\n", + "input__scale_score->retriever\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__filters\n", + "\n", + "input: filters\n", + "\n", + "\n", + "\n", + "input__filters->retriever\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__top_k\n", + "\n", + "input: top_k\n", + "\n", + "\n", + "\n", + "input__top_k->retriever\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__return_embedding\n", + "\n", + "input: return_embedding\n", + "\n", + "\n", + "\n", + "input__return_embedding->retriever\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__query_embedding\n", + "\n", + "input: query_embedding\n", + "\n", + "\n", + "\n", + "input__query_embedding->retriever\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "llm\n", + "\n", + "llm(prompt): \n", + "\n", + "\n", + "\n", + "prompt_builder->llm\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__template\n", + "\n", + "input: template\n", + "\n", + "\n", + "\n", + "input__template->prompt_builder\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__template_variables\n", + "\n", + "input: template_variables\n", + "\n", + "\n", + "\n", + "input__template_variables->prompt_builder\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__question\n", + "\n", + "input: question\n", + "\n", + "\n", + "\n", + "input__question->prompt_builder\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__generation_kwargs\n", + "\n", + "input: generation_kwargs\n", + "\n", + "\n", + "\n", + "input__generation_kwargs->llm\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__streaming_callback\n", + "\n", + "input: streaming_callback\n", + "\n", + "\n", + "\n", + "input__streaming_callback->llm\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from burr.integrations.haystack import haystack_pipeline_to_burr_graph\n", + "\n", + "haystack_graph = haystack_pipeline_to_burr_graph(basic_rag_pipeline)\n", + "app = (\n", + " ApplicationBuilder()\n", + " .with_graph(haystack_graph)\n", + " .with_entrypoint(\"prompt_builder\")\n", + " .build()\n", + ")\n", + "app.visualize(include_state=True)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/examples/haystack-integration/statemachine.png b/examples/haystack-integration/statemachine.png new file mode 100644 index 0000000000000000000000000000000000000000..907f4d28b4d1fc57a0d813ffc58ab5201bac6d1f GIT binary patch literal 57178 zcmd43bySq$);>HoiU=wpAfYHIsiZV0iZqhaN;eWimk1(KBGTQR(lDS>(j8KxAT^Y9 z!?y?Yyzjf#?_J;eeSdv(&N@e6=9&As?;Y2^_O%}$S!q$c3uG4%2n3$kQxQ1?;#?d8 zabgYUB>cwftP3gp-&t)5Q4z!;_CN8cv|t2+8X+bktY9BKKWg`!aA4=lvWny7%LSKD z5IwuBpwRo>14Uj*NPbPHm(c%4s=9R>OX^53IY&LA>G{Ds^cz z5N-baQlQv|Il}U_*UMkK4l7$_pAFg_3=C|?tDQFZSwqBc!wQaG@yZvIFa7(${Q^xT z-rpZO1$9eL{QdV%<5SGP_w*9a&dwGT6r_~$K6qg7=-92Pyl_VNL(AmG#)h828K$7o zv&V1!L*n)D*V2-fV`X5VjEKnT1!P~f-O`wze(kdx*cBiz{=KAehM(dmR%(nfd97m8wk-|2pE3!QS59*f_KI*$h8T#;Ly_qJAA8Po41yk?C3f?>dP6 zN4DgD{~Yi3-TdEM*YN)>9r3>`(r|KZwud#sba}j9?p)#~r}@at?CjnDxtzO%7rY+c zKoSnU4+sct(v5T7G4fw{o-?|$y9=8=!

({l5<4>5Hb1w>_vuL_`d0Bmyb<73dX< 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%0D9)w{Xz@$sz&a8l6xfoD-b=+LZvtr!Q* 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 Date: Wed, 16 Oct 2024 15:41:07 -0400 Subject: [PATCH 2/8] fixed dictionary iterator --- burr/integrations/haystack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/burr/integrations/haystack.py b/burr/integrations/haystack.py index be212353..aaa91345 100644 --- a/burr/integrations/haystack.py +++ b/burr/integrations/haystack.py @@ -80,7 +80,7 @@ def run(self, state: State, **run_kwargs) -> dict[str, Any]: # here, precedence matters. Alternatively, we could unpack all dictionaries at once # which would throw an error for key collisions - for param, value in self._bound_params: + for param, value in self._bound_params.items(): values[param] = value for param in self.reads: From 8f731b97e71db1a82a994be75b00cc7496b60b17 Mon Sep 17 00:00:00 2001 From: zilto Date: Wed, 16 Oct 2024 15:41:42 -0400 Subject: [PATCH 3/8] fixed kwargs iterator --- burr/integrations/haystack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/burr/integrations/haystack.py b/burr/integrations/haystack.py index aaa91345..88b5a84f 100644 --- a/burr/integrations/haystack.py +++ b/burr/integrations/haystack.py @@ -86,7 +86,7 @@ def run(self, state: State, **run_kwargs) -> dict[str, Any]: for param in self.reads: values[param] = state[param] - for param, value in run_kwargs.keys(): + for param, value in run_kwargs.items(): values[param] = value return self._component.run(**values) From 0b24192e90b257a900f7c9e992b75e88cdccc1e5 Mon Sep 17 00:00:00 2001 From: zilto Date: Wed, 16 Oct 2024 15:45:21 -0400 Subject: [PATCH 4/8] remove autoreload cell --- examples/haystack-integration/notebook.ipynb | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/examples/haystack-integration/notebook.ipynb b/examples/haystack-integration/notebook.ipynb index bcf711fe..4578d1ac 100644 --- a/examples/haystack-integration/notebook.ipynb +++ b/examples/haystack-integration/notebook.ipynb @@ -254,19 +254,6 @@ "- Haystack uses a `Router` component to [expression conditional edges](https://docs.haystack.deepset.ai/reference/routers-api#conditionalrouter). Burr allows to add condition directly via the `.with_transitions()` method by specifying in the tuple `(from_action, to_action, condition)`." ] }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "import burr.integrations.haystack\n", - "\n", - "%reload_ext autoreload\n", - "%autoreload 2\n", - "%aimport burr.integrations.haystack" - ] - }, { "cell_type": "markdown", "metadata": {}, From dc421d0ea92177e6da6b12cc32d50142e5593164 Mon Sep 17 00:00:00 2001 From: zilto Date: Fri, 18 Oct 2024 16:27:06 -0400 Subject: [PATCH 5/8] added tests and docs; applied reviews --- burr/integrations/haystack.py | 245 ++++++++--- docs/reference/integrations/haystack.rst | 9 + examples/haystack-integration/__init__.py | 0 examples/haystack-integration/application.py | 77 ++++ examples/haystack-integration/notebook.ipynb | 424 +++++++++---------- tests/integrations/test_burr_haystack.py | 253 +++++++++++ 6 files changed, 721 insertions(+), 287 deletions(-) create mode 100644 docs/reference/integrations/haystack.rst create mode 100644 examples/haystack-integration/__init__.py create mode 100644 examples/haystack-integration/application.py create mode 100644 tests/integrations/test_burr_haystack.py diff --git a/burr/integrations/haystack.py b/burr/integrations/haystack.py index 88b5a84f..162092f5 100644 --- a/burr/integrations/haystack.py +++ b/burr/integrations/haystack.py @@ -1,4 +1,6 @@ -from typing import Any, Optional, Union +import inspect +from collections.abc import Mapping +from typing import Any, Optional, Sequence, Union from haystack import Pipeline from haystack.core.component import Component @@ -9,8 +11,16 @@ from burr.core.state import State +# TODO show OpenTelemetry integration class HaystackAction(Action): - """Create a Burr `Action` from a Haystack `Component`.""" + """Burr ``Action`` wrapping a Haystack ``Component``. + + Haystack ``Component`` is the basic block of a Haystack ``Pipeline``. + A ``Component`` is instantiated, then it receives inputs for its ``.run()`` method + and returns output values. + + Learn more about components here: https://docs.haystack.deepset.ai/docs/custom-components + """ def __init__( self, @@ -20,46 +30,110 @@ def __init__( name: Optional[str] = None, bound_params: Optional[dict] = None, ): - """ - Notes - - need to figure out how to use bind - - you can use `action.bind()` to set values of `Component.run()`. + """Create a Burr ``Action`` from a Haystack ``Component``. + + :param component: Haystack ``Component`` to wrap + :param reads: State fields read and passed to ``Component.run()`` + :param writes: State fields where results of ``Component.run()`` are written + :param name: Name of the action. Can be set later via ``.with_name()`` or in the + ``ApplicationBuilder``. + :param bound_params: Parameters to bind to the `Component.run()` method. + + Basic example: + + .. code-block:: python + + from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever + from haystack.document_stores.in_memory import InMemoryDocumentStore + from burr.core import ApplicationBuilder + from burr.integrations.haystack import HaystackAction + + retrieve_documents = HaystackAction( + component=InMemoryEmbeddingRetriever(InMemoryDocumentStore()), + name="retrieve_documents", + reads=["query_embedding"], + writes=["documents"], + ) + + app = ( + ApplicationBuilder() + .with_actions(retrieve_documents) + .with_transitions("retrieve_documents", "retrieve_documents") + .with_entrypoint("retrieve_documents") + .build() + ) """ self._component = component self._name = name - self._reads = list(reads.keys()) if isinstance(reads, dict) else reads - self._writes = list(writes.values()) if isinstance(writes, dict) else writes self._bound_params = bound_params if bound_params is not None else {} - self._socket_mapping = {} - if isinstance(reads, dict): - for state_field, socket_name in reads.items(): - self._socket_mapping[socket_name] = state_field + # NOTE input and output socket mappings are kept separately to avoid naming conflicts. + if isinstance(reads, Mapping): + self._input_socket_mapping = reads + self._reads = list(set(reads.values())) + elif isinstance(reads, Sequence): + self._input_socket_mapping = {socket_name: socket_name for socket_name in reads} + self._reads = reads + else: + raise TypeError(f"`reads` must be a sequence or mapping. Received: {type(reads)}") + + self._validate_input_sockets() + + if isinstance(writes, Mapping): + self._output_socket_mapping = writes + self._writes = list(writes.keys()) + elif isinstance(writes, Sequence): + self._output_socket_mapping = {socket_name: socket_name for socket_name in writes} + self._writes = writes + else: + raise TypeError(f"`writes` must be a sequence or mapping. Received: {type(writes)}") + + self._validate_output_sockets() + + def _validate_input_sockets(self) -> None: + component_inputs = self._component.__haystack_input__._sockets_dict.keys() + for socket_name in self._input_socket_mapping.keys(): + if socket_name not in component_inputs: + raise ValueError( + f"Socket `{socket_name}` not found in `Component` inputs: {component_inputs}" + ) + + def _validate_output_sockets(self) -> None: + component_outputs = self._component.__haystack_output__._sockets_dict.keys() + for socket_name in self._output_socket_mapping.values(): + if socket_name not in component_outputs: + raise ValueError( + f"Socket `{socket_name}` not found in `Component` outputs: {component_outputs}" + ) - if isinstance(writes, dict): - for socket_name, state_field in writes.items(): - self._socket_mapping[socket_name] = state_field + @property + def component(self) -> Component: + """Haystack `Component` used by this action.""" + return self._component @property def reads(self) -> list[str]: + """State fields read and passed to `Component.run()`""" return self._reads @property def writes(self) -> list[str]: + """State fields where results of `Component.run()` are written.""" return self._writes @property def inputs(self) -> tuple[dict[str, str], dict[str, str]]: - """Return dictionaries of required and optional inputs.""" + """Return dictionaries of required and optional inputs for `Component.run()`""" required_inputs, optional_inputs = {}, {} for socket_name, input_socket in self._component.__haystack_input__._sockets_dict.items(): - state_field_name = self._socket_mapping.get(socket_name, socket_name) + state_field_name = self._input_socket_mapping.get(socket_name, socket_name) - if state_field_name in self.reads: - continue - elif state_field_name in self._bound_params: + # if we expect the value to come from state (previous actions) or it's a + # bound parameter, then this socket isn't a user-provided input + if state_field_name in self.reads or state_field_name in self._bound_params: continue + # determine if input is required or optional based on the socket's default value if input_socket.default_value == haystack_empty: required_inputs[state_field_name] = input_socket.type else: @@ -68,47 +142,68 @@ def inputs(self) -> tuple[dict[str, str], dict[str, str]]: return required_inputs, optional_inputs def run(self, state: State, **run_kwargs) -> dict[str, Any]: - """Call the Haystack `Component.run()` method. It returns a dictionary - of results with mapping {socket_name: value}. + """Call the Haystack `Component.run()` method. - Values come from 3 sources: - - bound parameters (from HaystackAction instantiation, or by using `.bind()`) + :param state: State object of the application. It contains some input values + for ``Component.run()``. + :param run_kwargs: User-provided inputs for ``Component.run()``. + :return: Dictionary of results with mapping ``{socket_name: value}``. + + Note, values come from 3 sources: - state (from previous actions) - - run_kwargs (inputs from `Application.run()`) + - run_kwargs (inputs from ``Application.run()``) + - bound parameters (from ``HaystackAction`` instantiation) """ values = {} # here, precedence matters. Alternatively, we could unpack all dictionaries at once # which would throw an error for key collisions - for param, value in self._bound_params.items(): - values[param] = value + for input_socket_name, value in self._bound_params.items(): + values[input_socket_name] = value - for param in self.reads: - values[param] = state[param] + for input_socket_name, state_field_name in self._input_socket_mapping.items(): + try: + values[input_socket_name] = state[state_field_name] + except KeyError as e: + raise ValueError(f"No value found in state for field: {state_field_name}") from e - for param, value in run_kwargs.items(): - values[param] = value + for input_socket_name, value in run_kwargs.items(): + values[input_socket_name] = value return self._component.run(**values) def update(self, result: dict, state: State) -> State: - """Update the state using the results of `Component.run()`.""" + """Update the state using the results of ``Component.run()``. + The output socket name is mapped to the Burr state field name. + + Values returned by ``Component.run()`` that aren't in ``writes`` are ignored. + """ + # TODO we could want to handle ``.update()`` and ``.append()`` differently state_update = {} - for socket_name, value in result.items(): - state_field_name = self._socket_mapping.get(socket_name, socket_name) - if state_field_name in self.writes: - state_update[state_field_name] = value + for state_field_name, output_socket_name in self._output_socket_mapping.items(): + if state_field_name in self.writes: + try: + state_update[state_field_name] = result[output_socket_name] + except KeyError as e: + raise ValueError( + f"Socket `{output_socket_name}` missing from output of `Component.run()`" + ) from e + print(state_update) return state.update(**state_update) - def bind(self, **kwargs): - """Bind a parameter for the `Component.run()` call.""" - self._bound_params.update(**kwargs) - return self + def get_source(self) -> str: + """Return the source code of the Haystack ``Component``. + + NOTE. This doesn't include the initialization parameters of the ``Component``. + This can be obtained using``HaystackAction().component.to_dict()``, but this + method might is not implemented for all components. + """ + return inspect.getsource(self._component.__class__) -def _socket_name_mapping(pipeline) -> dict[str, str]: - """Map socket names to a single state field name. +def _socket_name_mapping(sockets_connections: list[tuple[str, str]]) -> dict[str, str]: + """Map socket names to a single socket name. In Haystack, components communicate via sockets. A socket called "embedding" in one component can be renamed to "query_embedding" when @@ -119,27 +214,22 @@ def _socket_name_mapping(pipeline) -> dict[str, str]: creates a mapping {socket_name: state_field} to rename sockets when creating the Burr `Graph`. """ - sockets_connections = [ - (edge_data["from_socket"].name, edge_data["to_socket"].name) - for _, _, edge_data in pipeline.graph.edges.data() - ] - mapping = {} - + all_connections: dict[str, set[str]] = {} for from_, to in sockets_connections: - if from_ not in mapping: - mapping[from_] = {from_} - mapping[from_].add(to) + if from_ not in all_connections: + all_connections[from_] = {from_} + all_connections[from_].add(to) - if to not in mapping: - mapping[to] = {to} - mapping[to].add(from_) + if to not in all_connections: + all_connections[to] = {to} + all_connections[to].add(from_) - result = {} - for key, values in mapping.items(): + reduced_mapping: dict[str, str] = {} + for key, values in all_connections.items(): unique_name = min(values) - result[key] = unique_name + reduced_mapping[key] = unique_name - return result + return reduced_mapping def _connected_inputs(pipeline) -> dict[str, list[str]]: @@ -167,30 +257,47 @@ def _connected_outputs(pipeline) -> dict[str, list[str]]: def haystack_pipeline_to_burr_graph(pipeline: Pipeline) -> Graph: """Convert a Haystack `Pipeline` to a Burr `Graph`. + NOTE. This currently doesn't support Haystack pipelines with + parallel branches. Learn more https://docs.haystack.deepset.ai/docs/pipelines#branching + From the Haystack `Pipeline`, we can easily retrieve transitions. For actions, we need to create `HaystackAction` from components and map their sockets to Burr state fields + + EXPERIMENTAL: This feature is experimental and may change in the future. + Changes to Haystack or Burr could impact this function. Please let us know if + you encounter any issues. """ - socket_mapping = _socket_name_mapping(pipeline) - connected_inputs = _connected_inputs(pipeline) - connected_outputs = _connected_outputs(pipeline) + + # get all socket connections in the pipeline + sockets_connections = [ + (edge_data["from_socket"].name, edge_data["to_socket"].name) + for _, _, edge_data in pipeline.graph.edges.data() + ] + socket_mapping = _socket_name_mapping(sockets_connections) transitions = [(from_, to) for from_, to, _ in pipeline.graph.edges] + # get all input and output sockets that are connected to other components + connected_inputs = _connected_inputs(pipeline) + connected_outputs = _connected_outputs(pipeline) + actions = [] for component_name, component in pipeline.walk(): - inputs_from_state = [ - socket_mapping[socket_name] for socket_name in connected_inputs[component_name] - ] - outputs_to_state = [ - socket_mapping[socket_name] for socket_name in connected_outputs[component_name] - ] + inputs_mapping = { + socket_name: socket_mapping[socket_name] + for socket_name in connected_inputs[component_name] + } + outputs_mapping = { + socket_mapping[socket_name]: socket_name + for socket_name in connected_outputs[component_name] + } haystack_action = HaystackAction( name=component_name, component=component, - reads=inputs_from_state, - writes=outputs_to_state, + reads=inputs_mapping, + writes=outputs_mapping, ) actions.append(haystack_action) diff --git a/docs/reference/integrations/haystack.rst b/docs/reference/integrations/haystack.rst new file mode 100644 index 00000000..045a099b --- /dev/null +++ b/docs/reference/integrations/haystack.rst @@ -0,0 +1,9 @@ +======== +Haystack +======== + +The Haystack integration allows you to use ``Component`` as Burr ``Action`` using the ``HaystackAction`` construct. You can visit the examples in ``burr/examples/haystack-integration`` for a notebook tutorial. + +.. autoclass:: burr.integrations.haystack.HaystackAction + +.. autofunction:: burr.integrations.haystack.haystack_pipeline_to_burr_graph diff --git a/examples/haystack-integration/__init__.py b/examples/haystack-integration/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/examples/haystack-integration/application.py b/examples/haystack-integration/application.py new file mode 100644 index 00000000..584ad93f --- /dev/null +++ b/examples/haystack-integration/application.py @@ -0,0 +1,77 @@ +import os + +from haystack.components.builders import PromptBuilder +from haystack.components.embedders import SentenceTransformersTextEmbedder +from haystack.components.generators import OpenAIGenerator +from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever +from haystack.document_stores.in_memory import InMemoryDocumentStore + +from burr.core import ApplicationBuilder, State, action +from burr.integrations.haystack import HaystackAction + +# dummy OpenAI key to avoid raising an error +os.environ["OPENAI_API_KEY"] = "sk-..." + + +embed_text = HaystackAction( + component=SentenceTransformersTextEmbedder(model="sentence-transformers/all-MiniLM-L6-v2"), + name="embed_text", + reads=[], + writes={"embedding": "query_embedding"}, +) + + +retrieve_documents = HaystackAction( + component=InMemoryEmbeddingRetriever(InMemoryDocumentStore()), + name="retrieve_documents", + reads=["query_embedding"], + writes=["documents"], +) + + +build_prompt = HaystackAction( + component=PromptBuilder(template="Document: {{documents}} Question: {{question}}"), + name="build_prompt", + reads=["documents"], + writes={"prompt": "question_prompt"}, +) + + +generate_answer = HaystackAction( + component=OpenAIGenerator(model="gpt-4o-mini"), + name="generate_answer", + reads={"question_prompt": "prompt"}, + writes={"text": "answer"}, +) + + +@action(reads=["answer"], writes=[]) +def display_answer(state: State) -> State: + print(state["answer"]) + return state + + +def build_application(): + return ( + ApplicationBuilder() + .with_actions( + embed_text, + retrieve_documents, + build_prompt, + generate_answer, + display_answer, + ) + .with_transitions( + ("embed_text", "retrieve_documents"), + ("retrieve_documents", "build_prompt"), + ("build_prompt", "generate_answer"), + ("generate_answer", "display_answer"), + ) + .with_entrypoint("embed_text") + .build() + ) + + +if __name__ == "__main__": + app = build_application() + app.visualize(include_state=True) diff --git a/examples/haystack-integration/notebook.ipynb b/examples/haystack-integration/notebook.ipynb index 4578d1ac..2bbed2a4 100644 --- a/examples/haystack-integration/notebook.ipynb +++ b/examples/haystack-integration/notebook.ipynb @@ -21,7 +21,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": {}, "outputs": [ { @@ -91,7 +91,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": {}, "outputs": [ { @@ -172,10 +172,10 @@ "\n" ], "text/plain": [ - "" + "" ] }, - "execution_count": 3, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -267,7 +267,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -301,13 +301,13 @@ "Note that some for some `HaystackAction`, `reads` and `writes` are dictionaries instead of the usual lists. This helps map the values from the Burr `State` to the Haystack `Component.run()` parameters and outputs. \n", "\n", "For example, in `generate_answer`:\n", - " - `reads={\"question_prompt\": \"prompt\"}` maps the state to the run method `Component.run(prompt=state[\"question_prompt\"])`\n", - " - `writes={\"text\": \"answer\"}` maps the results of `.run()` to the state update `state.update(answer=Component.run(...)[\"text\"])`" + " - `reads={\"prompt\": \"question_prompt\"}` takes the value `State[\"question_prompt\"]` and assigns it to `Component.run(prompt=...)`\n", + " - `writes={\"answer\": \"replies\"}` takes the value `Component.run(...)[\"replies\"]` and assigns it to `state.update(answer=...)`" ] }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -319,193 +319,193 @@ "\n", "\n", - "\n", + "\n", "\n", "%3\n", - "\n", + "\n", "\n", "\n", "embed_text\n", - "\n", - "embed_text(): query_embedding\n", + "\n", + "embed_text(): query_embedding\n", "\n", "\n", "\n", "retrieve_documents\n", - "\n", - "retrieve_documents(query_embedding): documents\n", + "\n", + "retrieve_documents(query_embedding): documents\n", "\n", "\n", "\n", "embed_text->retrieve_documents\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "input__text\n", - "\n", - "input: text\n", + "\n", + "input: text\n", "\n", "\n", "\n", "input__text->embed_text\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "build_prompt\n", - "\n", - "build_prompt(documents): question_prompt\n", + "\n", + "build_prompt(documents): question_prompt\n", "\n", "\n", "\n", "retrieve_documents->build_prompt\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "input__top_k\n", - "\n", - "input: top_k\n", + "input__return_embedding\n", + "\n", + "input: return_embedding\n", "\n", - "\n", + "\n", "\n", - "input__top_k->retrieve_documents\n", - "\n", - "\n", + "input__return_embedding->retrieve_documents\n", + "\n", + "\n", "\n", "\n", "\n", "input__scale_score\n", - "\n", - "input: scale_score\n", + "\n", + "input: scale_score\n", "\n", "\n", "\n", "input__scale_score->retrieve_documents\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "input__return_embedding\n", - "\n", - "input: return_embedding\n", + "input__filters\n", + "\n", + "input: filters\n", "\n", - "\n", + "\n", "\n", - "input__return_embedding->retrieve_documents\n", - "\n", - "\n", + "input__filters->retrieve_documents\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "input__filters\n", - "\n", - "input: filters\n", + "input__top_k\n", + "\n", + "input: top_k\n", "\n", - "\n", + "\n", "\n", - "input__filters->retrieve_documents\n", - "\n", - "\n", + "input__top_k->retrieve_documents\n", + "\n", + "\n", "\n", "\n", "\n", "generate_answer\n", - "\n", - "generate_answer(question_prompt): answer\n", + "\n", + "generate_answer(question_prompt): answer\n", "\n", "\n", "\n", "build_prompt->generate_answer\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "input__template\n", - "\n", - "input: template\n", - "\n", - "\n", - "\n", - "input__template->build_prompt\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "input__template_variables\n", - "\n", - "input: template_variables\n", + "\n", + "input: template_variables\n", "\n", "\n", - "\n", + "\n", "input__template_variables->build_prompt\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "input__question\n", - "\n", - "input: question\n", + "\n", + "input: question\n", "\n", "\n", - "\n", + "\n", "input__question->build_prompt\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__template\n", + "\n", + "input: template\n", + "\n", + "\n", + "\n", + "input__template->build_prompt\n", + "\n", + "\n", "\n", "\n", "\n", "display_answer\n", - "\n", - "display_answer(answer): \n", + "\n", + "display_answer(answer): \n", "\n", "\n", "\n", "generate_answer->display_answer\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "input__generation_kwargs\n", - "\n", - "input: generation_kwargs\n", + "input__streaming_callback\n", + "\n", + "input: streaming_callback\n", "\n", - "\n", + "\n", "\n", - "input__generation_kwargs->generate_answer\n", - "\n", - "\n", + "input__streaming_callback->generate_answer\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", - "input__streaming_callback\n", - "\n", - "input: streaming_callback\n", + "input__generation_kwargs\n", + "\n", + "input: generation_kwargs\n", "\n", - "\n", + "\n", "\n", - "input__streaming_callback->generate_answer\n", - "\n", - "\n", + "input__generation_kwargs->generate_answer\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, - "execution_count": 6, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -517,7 +517,7 @@ " component=SentenceTransformersTextEmbedder(model=\"sentence-transformers/all-MiniLM-L6-v2\"),\n", " name=\"embed_text\",\n", " reads=[],\n", - " writes={\"embedding\": \"query_embedding\"},\n", + " writes={\"query_embedding\": \"embedding\"},\n", ")\n", "\n", "retrieve_documents = HaystackAction(\n", @@ -531,14 +531,14 @@ " component=PromptBuilder(template=\"Document: {{documents}} Question: {{question}}\"),\n", " name=\"build_prompt\",\n", " reads=[\"documents\"],\n", - " writes={\"prompt\": \"question_prompt\"},\n", + " writes={\"question_prompt\": \"prompt\"},\n", ")\n", "\n", "generate_answer = HaystackAction(\n", " component=OpenAIGenerator(model=\"gpt-4o-mini\"),\n", " name=\"generate_answer\",\n", - " reads={\"question_prompt\": \"prompt\"},\n", - " writes={\"text\": \"answer\"}\n", + " reads={\"prompt\": \"question_prompt\"},\n", + " writes={\"answer\": \"replies\"}\n", ")\n", "\n", "@action(reads=[\"answer\"], writes=[])\n", @@ -583,7 +583,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -595,193 +595,181 @@ "\n", "\n", - "\n", + "\n", "\n", "%3\n", - "\n", + "\n", "\n", "\n", "text_embedder\n", - "\n", - "text_embedder(): embedding\n", + "\n", + "text_embedder(): embedding\n", "\n", "\n", "\n", "retriever\n", - "\n", - "retriever(embedding): documents\n", + "\n", + "retriever(embedding): documents\n", "\n", "\n", - "\n", + "\n", "text_embedder->retriever\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", "\n", "input__text\n", - "\n", - "input: text\n", + "\n", + "input: text\n", "\n", "\n", "\n", "input__text->text_embedder\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "prompt_builder\n", - "\n", - "prompt_builder(documents): prompt\n", + "\n", + "prompt_builder(documents): prompt\n", "\n", "\n", - "\n", + "\n", "retriever->prompt_builder\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", + "\n", "\n", + "input__return_embedding\n", + "\n", + "input: return_embedding\n", + "\n", + "\n", + "\n", + "input__return_embedding->retriever\n", + "\n", + "\n", + "\n", + "\n", + "\n", "input__scale_score\n", - "\n", - "input: scale_score\n", + "\n", + "input: scale_score\n", "\n", "\n", - "\n", + "\n", "input__scale_score->retriever\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "input__filters\n", - "\n", - "input: filters\n", + "\n", + "input: filters\n", "\n", "\n", - "\n", + "\n", "input__filters->retriever\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "input__top_k\n", - "\n", - "input: top_k\n", + "\n", + "input: top_k\n", "\n", "\n", - "\n", - "input__top_k->retriever\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "input__return_embedding\n", - "\n", - "input: return_embedding\n", - "\n", - "\n", "\n", - "input__return_embedding->retriever\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "input__query_embedding\n", - "\n", - "input: query_embedding\n", - "\n", - "\n", - "\n", - "input__query_embedding->retriever\n", - "\n", - "\n", + "input__top_k->retriever\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "llm\n", - "\n", - "llm(prompt): \n", + "\n", + "llm(prompt): \n", "\n", "\n", - "\n", + "\n", "prompt_builder->llm\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "input__template\n", - "\n", - "input: template\n", - "\n", - "\n", - "\n", - "input__template->prompt_builder\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "input__template_variables\n", - "\n", - "input: template_variables\n", + "\n", + "input: template_variables\n", "\n", "\n", - "\n", + "\n", "input__template_variables->prompt_builder\n", - "\n", - "\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "input__question\n", - "\n", - "input: question\n", + "\n", + "input: question\n", "\n", "\n", - "\n", + "\n", "input__question->prompt_builder\n", - "\n", - "\n", + "\n", + "\n", "\n", - "\n", - "\n", - "input__generation_kwargs\n", - "\n", - "input: generation_kwargs\n", + "\n", + "\n", + "input__template\n", + "\n", + "input: template\n", "\n", - "\n", - "\n", - "input__generation_kwargs->llm\n", - "\n", - "\n", + "\n", + "\n", + "input__template->prompt_builder\n", + "\n", + "\n", "\n", "\n", - "\n", + "\n", "input__streaming_callback\n", - "\n", - "input: streaming_callback\n", + "\n", + "input: streaming_callback\n", "\n", "\n", - "\n", + "\n", "input__streaming_callback->llm\n", - "\n", - "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "input__generation_kwargs\n", + "\n", + "input: generation_kwargs\n", + "\n", + "\n", + "\n", + "input__generation_kwargs->llm\n", + "\n", + "\n", "\n", "\n", "\n" ], "text/plain": [ - "" + "" ] }, - "execution_count": 7, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } diff --git a/tests/integrations/test_burr_haystack.py b/tests/integrations/test_burr_haystack.py new file mode 100644 index 00000000..3ddb124b --- /dev/null +++ b/tests/integrations/test_burr_haystack.py @@ -0,0 +1,253 @@ +from haystack import Pipeline, component +from haystack.components.embedders import SentenceTransformersTextEmbedder +from haystack.components.retrievers.in_memory import InMemoryEmbeddingRetriever +from haystack.document_stores.in_memory import InMemoryDocumentStore + +from burr.core import State, action +from burr.core.graph import GraphBuilder +from burr.integrations.haystack import HaystackAction, haystack_pipeline_to_burr_graph + + +@component +class MockComponent: + def __init__(self, required_init: str, optional_init: str = "default"): + self.required_init = required_init + self.optional_init = optional_init + + @component.output_types(output_1=str, output_2=str) + def run(self, required_input: str, optional_input: str = "default") -> dict: + return { + "output_1": required_input, + "output_2": optional_input, + } + + +@action(reads=["query_embedding"], writes=["documents"]) +def retrieve_documents(state: State) -> State: + query_embedding = state["query_embedding"] + + document_store = InMemoryDocumentStore() + retriever = InMemoryEmbeddingRetriever(document_store) + + results = retriever.run(query_embedding=query_embedding) + return state.update(documents=results["documents"]) + + +haystack_retrieve_documents = HaystackAction( + component=InMemoryEmbeddingRetriever(InMemoryDocumentStore()), + name="retrieve_documents", + reads=["query_embedding"], + writes=["documents"], +) + + +def test_input_socket_mapping(): + # {input_socket_name: state_field} + reads = {"required_input": "foo"} + + haction = HaystackAction( + component=MockComponent(required_init="init"), name="mock", reads=reads, writes=[] + ) + + assert haction.reads == list(set(reads.values())) == ["foo"] + + +def test_input_socket_sequence(): + # {input_socket_name: input_socket_name} + reads = ["required_input"] + + haction = HaystackAction( + component=MockComponent(required_init="init"), name="mock", reads=reads, writes=[] + ) + + assert haction.reads == list(reads) == ["required_input"] + + +def test_output_socket_mapping(): + # {state_field: output_socket_name} + writes = {"bar": "output_1"} + + haction = HaystackAction( + component=MockComponent(required_init="init"), name="mock", reads=[], writes=writes + ) + + assert haction.writes == list(writes.keys()) == ["bar"] + + +def test_output_socket_sequence(): + # {output_socket_name: output_socket_name} + writes = ["output_1"] + + haction = HaystackAction( + component=MockComponent(required_init="init"), name="mock", reads=[], writes=writes + ) + + assert haction.writes == writes == ["output_1"] + + +def test_get_component_source(): + haction = HaystackAction( + component=MockComponent(required_init="init"), name="mock", reads=[], writes=[] + ) + + expected_source = """\ +@component +class MockComponent: + def __init__(self, required_init: str, optional_init: str = "default"): + self.required_init = required_init + self.optional_init = optional_init + + @component.output_types(output_1=str, output_2=str) + def run(self, required_input: str, optional_input: str = "default") -> dict: + return { + "output_1": required_input, + "output_2": optional_input, + } +""" + + assert haction.get_source() == expected_source + + +def test_run_with_external_inputs(): + state = State(initial_values={}) + haction = HaystackAction( + component=MockComponent(required_init="init"), name="mock", reads=[], writes=[] + ) + + results = haction.run(state=state, required_input="as_input") + + assert results == {"output_1": "as_input", "output_2": "default"} + + +def test_run_with_state_inputs(): + state = State(initial_values={"foo": "bar"}) + haction = HaystackAction( + component=MockComponent(required_init="init"), + name="mock", + reads={"required_input": "foo"}, + writes=[], + ) + + results = haction.run(state=state) + + assert results == {"output_1": "bar", "output_2": "default"} + + +def test_run_with_bound_params(): + state = State(initial_values={}) + haction = HaystackAction( + component=MockComponent(required_init="init"), + name="mock", + reads=[], + writes=[], + bound_params={"required_input": "baz"}, + ) + + results = haction.run(state=state) + + assert results == {"output_1": "baz", "output_2": "default"} + + +def test_run_mixed_params(): + state = State(initial_values={"foo": "bar"}) + haction = HaystackAction( + component=MockComponent(required_init="init"), + name="mock", + reads={"required_input": "foo"}, + writes=[], + bound_params={"optional_input": "baz"}, + ) + + results = haction.run(state=state) + + assert results == {"output_1": "bar", "output_2": "baz"} + + +def test_run_with_sequence(): + state = State(initial_values={"required_input": "bar"}) + haction = HaystackAction( + component=MockComponent(required_init="init"), + name="mock", + reads=["required_input"], + writes=[], + ) + + results = haction.run(state=state) + + assert results == {"output_1": "bar", "output_2": "default"} + + +def test_update_with_writes_mapping(): + state = State(initial_values={}) + results = {"output_1": 1, "output_2": 2} + haction = HaystackAction( + component=MockComponent(required_init="init"), + name="mock", + reads=[], + writes={"foo": "output_1"}, + ) + + new_state = haction.update(result=results, state=state) + + assert new_state["foo"] == 1 + + +def test_update_with_writes_sequence(): + state = State(initial_values={}) + results = {"output_1": 1, "output_2": 2} + haction = HaystackAction( + component=MockComponent(required_init="init"), + name="mock", + reads=[], + writes=["output_1"], + ) + + new_state = haction.update(result=results, state=state) + + assert new_state["output_1"] == 1 + + +def test_pipeline_converter(): + # create haystack Pipeline + retriever = InMemoryEmbeddingRetriever(InMemoryDocumentStore()) + text_embedder = SentenceTransformersTextEmbedder(model="sentence-transformers/all-MiniLM-L6-v2") + + basic_rag_pipeline = Pipeline() + basic_rag_pipeline.add_component("text_embedder", text_embedder) + basic_rag_pipeline.add_component("retriever", retriever) + basic_rag_pipeline.connect("text_embedder.embedding", "retriever.query_embedding") + + # create Burr application + embed_text = HaystackAction( + component=text_embedder, + name="text_embedder", + reads=[], + writes={"query_embedding": "embedding"}, + ) + + retrieve_documents = HaystackAction( + component=retriever, + name="retriever", + reads=["query_embedding"], + writes=["documents"], + ) + + burr_graph = ( + GraphBuilder() + .with_actions(embed_text, retrieve_documents) + .with_transitions(("text_embedder", "retriever")) + .build() + ) + + # convert the Haystack Pipeline to a Burr graph + haystack_graph = haystack_pipeline_to_burr_graph(basic_rag_pipeline) + + converted_action_names = [action.name for action in haystack_graph.actions] + for graph_action in burr_graph.actions: + assert graph_action.name in converted_action_names + + for burr_t in burr_graph.transitions: + assert any( + burr_t.from_.name == haystack_t.from_.name and burr_t.to.name == haystack_t.to.name + for haystack_t in haystack_graph.transitions + ) From f2bc1228009538f04193b2a82e82c6f8a820c37a Mon Sep 17 00:00:00 2001 From: zilto Date: Fri, 18 Oct 2024 16:34:17 -0400 Subject: [PATCH 6/8] added haystack optional dep --- pyproject.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 8bbc631d..17f73294 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -62,6 +62,7 @@ tests = [ "pyarrow", "redis", "burr[opentelemetry]" + "burr[haystack]" ] documentation = [ @@ -113,6 +114,10 @@ pydantic = [ "pydantic" ] +haystack = [ + "haystack" +] + cli = [ "loguru", "click", From 82ee637dcac33a75660af87123a6deb30b8a6670 Mon Sep 17 00:00:00 2001 From: zilto Date: Fri, 18 Oct 2024 16:35:02 -0400 Subject: [PATCH 7/8] fixed typo --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 17f73294..d3e8d2cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,7 +61,7 @@ tests = [ "pydantic[email]", "pyarrow", "redis", - "burr[opentelemetry]" + "burr[opentelemetry]", "burr[haystack]" ] From f9e171b787bb6f4a6640cb61a4b808fca25ab870 Mon Sep 17 00:00:00 2001 From: zilto Date: Fri, 18 Oct 2024 16:37:02 -0400 Subject: [PATCH 8/8] fixed dependency to haystack-ai; removed print() --- burr/integrations/haystack.py | 1 - pyproject.toml | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/burr/integrations/haystack.py b/burr/integrations/haystack.py index 162092f5..508862f5 100644 --- a/burr/integrations/haystack.py +++ b/burr/integrations/haystack.py @@ -189,7 +189,6 @@ def update(self, result: dict, state: State) -> State: raise ValueError( f"Socket `{output_socket_name}` missing from output of `Component.run()`" ) from e - print(state_update) return state.update(**state_update) def get_source(self) -> str: diff --git a/pyproject.toml b/pyproject.toml index d3e8d2cb..f32c279d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -115,7 +115,7 @@ pydantic = [ ] haystack = [ - "haystack" + "haystack-ai" ] cli = [