Metadata-Version: 2.4
Name: unitycatalog-langchain
Version: 0.3.0
Summary: Support for Unity Catalog functions as LangChain tools
Author-email: Serena Ruan <serena.ruan@databricks.com>
License: Apache-2.0
Requires-Python: >=3.10
Requires-Dist: langchain-community>=0.4.0
Requires-Dist: langchain>=1.0.0
Requires-Dist: unitycatalog-ai
Provides-Extra: databricks
Requires-Dist: unitycatalog-ai[databricks]; extra == 'databricks'
Provides-Extra: databricks-dev
Requires-Dist: databricks-langchain; extra == 'databricks-dev'
Requires-Dist: langgraph; extra == 'databricks-dev'
Requires-Dist: unitycatalog-ai[databricks-dev]; extra == 'databricks-dev'
Provides-Extra: dev
Requires-Dist: databricks-langchain; extra == 'dev'
Requires-Dist: langgraph; extra == 'dev'
Requires-Dist: unitycatalog-ai[dev]; extra == 'dev'
Description-Content-Type: text/markdown

# 🦜🔗 Using Unity Catalog AI with Langchain

Integrate the Unity Catalog AI package with `Langchain` to allow seamless usage of UC functions as tools in agentic applications.

## Installation

### Client Library

To install the Unity Catalog function client SDK and the `LangChain` (and `LangGraph`) integration, simply install from PyPI:

```sh
pip install unitycatalog-langchain
```

If you are working with **Databricks Unity Catalog**, you can install the optional package:

```sh
pip install unitycatalog-langchain[databricks]
```

## Getting started

### Creating a Unity Catalog Client

To interact with your Unity Catalog server, initialize the `UnitycatalogFunctionClient` as shown below:

```python
import asyncio
from unitycatalog.ai.core.client import UnitycatalogFunctionClient
from unitycatalog.client import ApiClient, Configuration

# Configure the Unity Catalog API client
config = Configuration(
    host="http://localhost:8080/api/2.1/unity-catalog"  # Replace with your UC server URL
)

# Initialize the asynchronous ApiClient
api_client = ApiClient(configuration=config)

# Instantiate the UnitycatalogFunctionClient
uc_client = UnitycatalogFunctionClient(api_client=api_client)

# Example catalog and schema names
CATALOG = "my_catalog"
SCHEMA = "my_schema"
```

### Creating a Unity Catalog Function

You can create a UC function either by providing a Python callable or by submitting a `FunctionInfo` object. Below is an example (recommended) of using the `create_python_function` API that accepts a Python callable (function) as input.

To create a UC function from a Python function, define your function with appropriate type hints and a Google-style docstring:

```python
def add_numbers(a: float, b: float) -> float:
    """
    Adds two numbers and returns the result.

    Args:
        a (float): First number.
        b (float): Second number.

    Returns:
        float: The sum of the two numbers.
    """
    return a + b

# Create the function within the Unity Catalog catalog and schema specified
function_info = uc_client.create_python_function(
    func=add_numbers,
    catalog=CATALOG,
    schema=SCHEMA,
    replace=False,  # Set to True to overwrite if the function already exists
)

print(function_info)
```

### Databricks-managed Unity Catalog

To use Databricks-managed Unity Catalog with this package, follow the [instructions](https://docs.databricks.com/en/dev-tools/cli/authentication.html#authentication-for-the-databricks-cli) to authenticate to your workspace and ensure that your access token has workspace-level privilege for managing UC functions.

#### Client setup

Initialize a client for managing UC functions in a Databricks workspace, and set it as the global client.

```python
from unitycatalog.ai.core.base import set_uc_function_client
from unitycatalog.ai.core.databricks import DatabricksFunctionClient

client = DatabricksFunctionClient()

# sets the default uc function client
set_uc_function_client(client)
```

#### Create a function in UC

Create a python UDF in Unity Catalog with the client

```python
# replace with your own catalog and schema
CATALOG = "catalog"
SCHEMA = "schema"

func_name = f"{CATALOG}.{SCHEMA}.python_exec"
# define the function body in SQL
sql_body = f"""CREATE OR REPLACE FUNCTION {func_name}(code STRING COMMENT 'Python code to execute. Remember to print the final result to stdout.')
RETURNS STRING
LANGUAGE PYTHON
COMMENT 'Executes Python code and returns its stdout.'
AS $$
    import sys
    from io import StringIO
    stdout = StringIO()
    sys.stdout = stdout
    exec(code)
    return stdout.getvalue()
$$
"""

client.create_function(sql_function_body=sql_body)
```

Now the function is created and stored in the corresponding catalog and schema.

## Using the Function as a GenAI Tool

### Create a UCFunctionToolkit instance

[Langchain tools](https://python.langchain.com/v0.2/docs/concepts/#tools) are utilities designed to be called by a model, and UCFunctionToolkit provides the ability to use UC functions as tools that are recognized natively by LangChain.

```python
from unitycatalog.ai.langchain.toolkit import UCFunctionToolkit

# create a UCFunctionToolkit that includes the above UC function
toolkit = UCFunctionToolkit(function_names=[f"{CATALOG}.{SCHEMA}.python_exec"])

# Printing the tool definition will display the configured metadata for the instance.
print(python_exec_tool)

# Execute the tool directly
result = client.execute_function(function_name=f"{CATALOG}.{SCHEMA}.python_exec", parameters={"code": "print(1 + 1)"})
print(result.value)  # Outputs: 2
```

### Use the tools in a Langchain Agent

Now we create an agent and use the tools.

```python
from langchain_community.chat_models.databricks import ChatDatabricks
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate

# Use Databricks foundation models
llm = ChatDatabricks(endpoint="databricks-meta-llama-3-1-70b-instruct")
prompt = ChatPromptTemplate.from_messages(
    [
        (
            "system",
            "You are a helpful assistant. Make sure to use tool for information.",
        ),
        ("placeholder", "{chat_history}"),
        ("human", "{input}"),
        ("placeholder", "{agent_scratchpad}"),
    ]
)
agent = create_tool_calling_agent(llm, tools, prompt)

# Create the agent executor
agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
agent_executor.invoke({"input": "36939 * 8922.4"})
```

### Configurations for Databricks managed UC functions execution

We provide configurations for databricks client to control the function execution behaviors, check [function execution arguments section](../../README.md#function-execution-arguments-configuration).
