diff --git a/content/integrations/other/exa.mdx b/content/integrations/other/exa.mdx index 9022e96502..20aa203abd 100644 --- a/content/integrations/other/exa.mdx +++ b/content/integrations/other/exa.mdx @@ -54,7 +54,7 @@ exa = Exa(api_key= os.environ["EXA_API_KEY"]) langfuse = get_client() ``` -## Example 1: Trace Exa `search_and_contents` +## Example 1: Trace Exa `search` To monitor your Exa search operations, we use the [Langfuse `@observe()` decorator](https://langfuse.com/docs/sdk/python/decorators). In this example, the `@observe()` decorator captures the inputs, outputs, and execution time of the `search_with_exa()` function. For more control over the data you are sending to Langfuse, you can use the [Context Manager or create manual observations](https://langfuse.com/docs/observability/sdk/python/instrumentation#custom-instrumentation) using the Python SDK. @@ -64,10 +64,9 @@ from langfuse import observe @observe(as_type="retriever") def search_with_exa(query: str, num_results: int = 5): """Search the web using Exa AI and return results.""" - results = exa.search_and_contents( + results = exa.search( query, - num_results=num_results, - text=True + num_results=num_results ) return results @@ -78,7 +77,7 @@ search_results = search_with_exa("What is Langfuse and how does it help with LLM for result in search_results.results: print(f"Title: {result.title}") print(f"URL: {result.url}") - print(f"Text: {result.text[:200]}...\n") + print() ``` ## Example 2: Exa Search together with OpenAI @@ -92,21 +91,23 @@ from langfuse.openai import OpenAI @observe() def search_and_summarize(query: str): - # 1. Exa search + # 1. Exa search with highlights @observe(as_type="retriever") def search_with_exa(query: str, num_results: int = 5): - """Search the web using Exa AI and return results.""" + """Search the web using Exa AI and return results with highlights.""" results = exa.search_and_contents( query, num_results=num_results, - text=True + highlights=True ) return results results = search_with_exa(query) - # 2. Build a short context - context = "\n".join([f"{r.title} ({r.url}): {r.text}" for r in results.results]) + # 2. Build context from search results + context = "\n".join([ + f"{r.title}: {' '.join(r.highlights)}" for r in results.results + ]) # 3. Summarize with OpenAI client = OpenAI() diff --git a/cookbook/integration_exa.ipynb b/cookbook/integration_exa.ipynb index ed79f43884..142ca466a8 100644 --- a/cookbook/integration_exa.ipynb +++ b/cookbook/integration_exa.ipynb @@ -1,215 +1,144 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "\n", - "\n", - "# Exa Integration\n", - "\n", - "In this guide, we'll show you how to integrate [Langfuse](https://langfuse.com) with [Exa](https://exa.ai/) to trace your AI search operations. By leveraging Langfuse's tracing capabilities, you can automatically capture details such as inputs, outputs, and execution times of your Exa search functions.\n", - "\n", - "> **What is Exa?** [Exa](https://exa.ai/) is an AI-powered search API built for LLMs and AI applications. Unlike traditional search engines, Exa is designed to understand semantic meaning and retrieve high-quality, relevant results that are perfect for AI use cases like RAG (Retrieval-Augmented Generation), research, and content discovery.\n", - "\n", - "> **What is Langfuse?** [Langfuse](https://langfuse.com) is an open source LLM engineering platform that helps teams trace API calls, monitor performance, and debug issues in their AI applications.\n", - "\n", - "\n", - "## Install Dependencies\n", - "\n", - "First, install the necessary Python packages:" - ] + "cells": [ + { + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "# Exa Integration\n", + "\n", + "In this guide, we'll show you how to integrate [Langfuse](https://langfuse.com) with [Exa](https://exa.ai/) to trace your AI search operations. By leveraging Langfuse's tracing capabilities, you can automatically capture details such as inputs, outputs, and execution times of your Exa search functions.\n", + "\n", + "> **What is Exa?** [Exa](https://exa.ai/) is an AI-powered search API built for LLMs and AI applications. Unlike traditional search engines, Exa is designed to understand semantic meaning and retrieve high-quality, relevant results that are perfect for AI use cases like RAG (Retrieval-Augmented Generation), research, and content discovery.\n", + "\n", + "> **What is Langfuse?** [Langfuse](https://langfuse.com) is an open source LLM engineering platform that helps teams trace API calls, monitor performance, and debug issues in their AI applications.\n", + "\n", + "\n", + "## Install Dependencies\n", + "\n", + "First, install the necessary Python packages:" + ], + "metadata": {} + }, + { + "cell_type": "code", + "source": [ + "%pip install langfuse exa-py" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "### Set Up Environment Variables\n", + "\n", + "Get your Langfuse API keys by signing up for [Langfuse Cloud](https://cloud.langfuse.com) or [self-hosting Langfuse](https://langfuse.com/self-hosting). You'll also need your Exa and OpenAI API key." + ], + "metadata": {} + }, + { + "cell_type": "code", + "source": [ + "import os\n", + "\n", + "# Get keys for your project from the project settings page: https://cloud.langfuse.com\n", + "os.environ[\"LANGFUSE_PUBLIC_KEY\"] = \"pk-lf-...\" \n", + "os.environ[\"LANGFUSE_SECRET_KEY\"] = \"sk-lf-...\" \n", + "os.environ[\"LANGFUSE_HOST\"] = \"https://cloud.langfuse.com\" # πŸ‡ͺπŸ‡Ί EU region\n", + "# Other Langfuse data regions include πŸ‡ΊπŸ‡Έ US: https://us.cloud.langfuse.com, πŸ‡―πŸ‡΅ Japan: https://jp.cloud.langfuse.com and βš•οΈ HIPAA: https://hipaa.cloud.langfuse.com\n", + "\n", + "# Your Exa API key\n", + "os.environ[\"EXA_API_KEY\"] = \"...\"\n", + "\n", + "# Your openai key\n", + "os.environ[\"OPENAI_API_KEY\"] = \"sk-...\"" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "With the environment variables set, we can now initialize the Exa and the Langfuse client." + ], + "metadata": {} + }, + { + "cell_type": "code", + "source": [ + "from exa_py import Exa\n", + "from langfuse import get_client\n", + "\n", + "exa = Exa(api_key= os.environ[\"EXA_API_KEY\"])\n", + "langfuse = get_client()" + ], + "metadata": {} + }, + { + "cell_type": "markdown", + "source": "## Example 1: Trace Exa `search` \n\nTo monitor your Exa search operations, we use the [Langfuse `@observe()` decorator](https://langfuse.com/docs/sdk/python/decorators). In this example, the `@observe()` decorator captures the inputs, outputs, and execution time of the `search_with_exa()` function. For more control over the data you are sending to Langfuse, you can use the [Context Manager or create manual observations](https://langfuse.com/docs/observability/sdk/python/instrumentation#custom-instrumentation) using the Python SDK.", + "metadata": {} + }, + { + "cell_type": "code", + "source": "from langfuse import observe\n\n@observe(as_type=\"retriever\")\ndef search_with_exa(query: str, num_results: int = 5):\n \"\"\"Search the web using Exa AI and return results.\"\"\"\n results = exa.search(\n query,\n num_results=num_results\n )\n return results\n\n# Example: Search for information about Langfuse\nsearch_results = search_with_exa(\"What is Langfuse and how does it help with LLM observability?\")\n\n# Display the results\nfor result in search_results.results:\n print(f\"Title: {result.title}\")\n print(f\"URL: {result.url}\")\n print()", + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## Example 2: Exa Search together with OpenAI\n", + "\n", + "You can also trace more complex workflows that involve summarizing the search results with OpenAI. Here we use the [Langfuse `@observe()` decorator](https://langfuse.com/docs/sdk/python/decorators) to group both the Exa search and the OpenAI generation into one trace. " + ], + "metadata": {} + }, + { + "cell_type": "code", + "source": "import os\nfrom langfuse.openai import OpenAI\n\n@observe()\ndef search_and_summarize(query: str):\n\n # 1. Exa search with highlights\n @observe(as_type=\"retriever\")\n def search_with_exa(query: str, num_results: int = 5):\n \"\"\"Search the web using Exa AI and return results with highlights.\"\"\"\n results = exa.search_and_contents(\n query,\n num_results=num_results,\n highlights=True\n )\n return results\n\n results = search_with_exa(query)\n\n # 2. Build context from search results\n context = \"\\n\".join([\n f\"{r.title}: {' '.join(r.highlights)}\" for r in results.results\n ])\n\n # 3. Summarize with OpenAI\n client = OpenAI()\n resp = client.chat.completions.create(\n model=\"gpt-5-mini\",\n messages=[\n {\"role\": \"system\", \"content\": \"Summarize the following search results clearly and concisely.\"},\n {\"role\": \"user\", \"content\": context}\n ]\n )\n\n print(\"Summary:\\n\", resp.choices[0].message.content)\n\nsearch_and_summarize(\"What is Langfuse and how does it help with LLM observability?\")", + "metadata": {} + }, + { + "cell_type": "markdown", + "source": [ + "## See Traces in Langfuse\n", + "\n", + "After executing the traced functions, log in to your [Langfuse Dashboard](https://cloud.langfuse.com) to view detailed trace logs. You'll be able to see:\n", + "\n", + "- Search queries and their parameters\n", + "- Response times for each API call\n", + "- Nested traces showing the relationship between search and similarity operations\n", + "- Full input and output data for debugging\n", + "\n", + "![Example trace in the Langfuse UI](https://langfuse.com/images/cookbook/integration_exa/exa-search-example-trace.png)\n", + "\n", + "[Example trace in Langfuse](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/27c03a05a881ae454f6612a99cc54a92?observation=5af197a22620dc4a×tamp=2025-10-28T10:20:13.672Z)\n", + "\n", + "\n", + "\n", + "" + ], + "metadata": {} + } + ], + "metadata": { + "language_info": { + "name": "python", + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "nbconvert_exporter": "python", + "file_extension": ".py", + "pygments_lexer": "ipython3", + "mimetype": "text/x-python", + "version": "3.13.2" + }, + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + } }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%pip install langfuse exa-py" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Set Up Environment Variables\n", - "\n", - "Get your Langfuse API keys by signing up for [Langfuse Cloud](https://cloud.langfuse.com) or [self-hosting Langfuse](https://langfuse.com/self-hosting). You'll also need your Exa and OpenAI API key." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "\n", - "# Get keys for your project from the project settings page: https://cloud.langfuse.com\n", - "os.environ[\"LANGFUSE_PUBLIC_KEY\"] = \"pk-lf-...\" \n", - "os.environ[\"LANGFUSE_SECRET_KEY\"] = \"sk-lf-...\" \n", - "os.environ[\"LANGFUSE_HOST\"] = \"https://cloud.langfuse.com\" # πŸ‡ͺπŸ‡Ί EU region\n", - "# Other Langfuse data regions include πŸ‡ΊπŸ‡Έ US: https://us.cloud.langfuse.com, πŸ‡―πŸ‡΅ Japan: https://jp.cloud.langfuse.com and βš•οΈ HIPAA: https://hipaa.cloud.langfuse.com\n", - "\n", - "# Your Exa API key\n", - "os.environ[\"EXA_API_KEY\"] = \"...\"\n", - "\n", - "# Your openai key\n", - "os.environ[\"OPENAI_API_KEY\"] = \"sk-...\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the environment variables set, we can now initialize the Exa and the Langfuse client." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from exa_py import Exa\n", - "from langfuse import get_client\n", - "\n", - "exa = Exa(api_key= os.environ[\"EXA_API_KEY\"])\n", - "langfuse = get_client()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Example 1: Trace Exa `search_and_contents` \n", - "\n", - "To monitor your Exa search operations, we use the [Langfuse `@observe()` decorator](https://langfuse.com/docs/sdk/python/decorators). In this example, the `@observe()` decorator captures the inputs, outputs, and execution time of the `search_with_exa()` function. For more control over the data you are sending to Langfuse, you can use the [Context Manager or create manual observations](https://langfuse.com/docs/observability/sdk/python/instrumentation#custom-instrumentation) using the Python SDK." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from langfuse import observe\n", - "\n", - "@observe(as_type=\"retriever\")\n", - "def search_with_exa(query: str, num_results: int = 5):\n", - " \"\"\"Search the web using Exa AI and return results.\"\"\"\n", - " results = exa.search_and_contents(\n", - " query,\n", - " num_results=num_results,\n", - " text=True\n", - " )\n", - " return results\n", - "\n", - "# Example: Search for information about Langfuse\n", - "search_results = search_with_exa(\"What is Langfuse and how does it help with LLM observability?\")\n", - "\n", - "# Display the results\n", - "for result in search_results.results:\n", - " print(f\"Title: {result.title}\")\n", - " print(f\"URL: {result.url}\")\n", - " print(f\"Text: {result.text[:200]}...\\n\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Example 2: Exa Search together with OpenAI\n", - "\n", - "You can also trace more complex workflows that involve summarizing the search results with OpenAI. Here we use the [Langfuse `@observe()` decorator](https://langfuse.com/docs/sdk/python/decorators) to group both the Exa search and the OpenAI generation into one trace. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import os\n", - "from langfuse.openai import OpenAI\n", - "\n", - "@observe()\n", - "def search_and_summarize(query: str):\n", - "\n", - " # 1. Exa search\n", - " @observe(as_type=\"retriever\")\n", - " def search_with_exa(query: str, num_results: int = 5):\n", - " \"\"\"Search the web using Exa AI and return results.\"\"\"\n", - " results = exa.search_and_contents(\n", - " query,\n", - " num_results=num_results,\n", - " text=True\n", - " )\n", - " return results\n", - "\n", - " results = search_with_exa(query)\n", - "\n", - " # 2. Build a short context\n", - " context = \"\\n\".join([f\"{r.title} ({r.url}): {r.text}\" for r in results.results])\n", - "\n", - " # 3. Summarize with OpenAI\n", - " client = OpenAI()\n", - " resp = client.chat.completions.create(\n", - " model=\"gpt-5-mini\",\n", - " messages=[\n", - " {\"role\": \"system\", \"content\": \"Summarize the following search results clearly and concisely.\"},\n", - " {\"role\": \"user\", \"content\": context}\n", - " ]\n", - " )\n", - "\n", - " print(\"Summary:\\n\", resp.choices[0].message.content)\n", - "\n", - "search_and_summarize(\"What is Langfuse and how does it help with LLM observability?\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## See Traces in Langfuse\n", - "\n", - "After executing the traced functions, log in to your [Langfuse Dashboard](https://cloud.langfuse.com) to view detailed trace logs. You'll be able to see:\n", - "\n", - "- Search queries and their parameters\n", - "- Response times for each API call\n", - "- Nested traces showing the relationship between search and similarity operations\n", - "- Full input and output data for debugging\n", - "\n", - "![Example trace in the Langfuse UI](https://langfuse.com/images/cookbook/integration_exa/exa-search-example-trace.png)\n", - "\n", - "[Example trace in Langfuse](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/27c03a05a881ae454f6612a99cc54a92?observation=5af197a22620dc4a×tamp=2025-10-28T10:20:13.672Z)\n", - "\n", - "\n", - "\n", - "" - ] - } - ], - "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.13.2" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file