LangChain Deep Agents Python Integration

Use the Oracle integration for LangChain Deep Agents to build a planning and research agent that searches Oracle data and can persist its state in Oracle AI Database.

Contents

Before You Begin

Prepare the following resources:

The ADB datastore expects a table that is compatible with the OracleVS schema. The full companion notebook shows how to create the table, insert documents, and add the Oracle Text index before creating the agent.

Install the Packages

Install the Deep Agents extra for langchain-oci.

python -m pip install --upgrade "langchain-oci[deepagents]"

The extra installs the upstream deepagents harness and the Oracle datastore and persistence integrations. Install the LangChain package for another model or embedding provider separately if you plan to pass prebuilt model objects.

Configure the OCI compartment, region, authentication, and Oracle connection. The default OCI authentication type is API key authentication with the DEFAULT profile in ~/.oci/config. The examples read the authentication values below and pass them to both the model factory and the separately created embedding client.

export OCI_COMPARTMENT_ID="ocid1.compartment..."
export OCI_REGION="us-chicago-1"
export OCI_AUTH_TYPE="API_KEY"
export OCI_AUTH_PROFILE="DEFAULT"
export OCI_AUTH_FILE_LOCATION="$HOME/.oci/config"

export ADB_DSN="mydb_low"
export ADB_USER="ADMIN"
export ADB_PASSWORD="<database-password>"
export ADB_TABLE_NAME="VECTOR_DOCUMENTS"

# Set these values for an Autonomous AI Database mTLS connection.
export ADB_WALLET_LOCATION="/path/to/wallet"
export ADB_WALLET_PASSWORD="<wallet-password>"

Do not store production passwords, private keys, or wallet files in source control.

Prepare an Oracle Datastore

Create the embedding model and register the prepared vector table as an ADB datastore.

import os

from langchain_oci import OCIGenAIEmbeddings
from langchain_oci.datastores import ADB

compartment_id = os.environ["OCI_COMPARTMENT_ID"]
region = os.getenv("OCI_REGION", "us-chicago-1")
service_endpoint = os.getenv(
    "OCI_SERVICE_ENDPOINT",
    f"https://inference.generativeai.{region}.oci.oraclecloud.com",
)
auth_type = os.getenv("OCI_AUTH_TYPE", "API_KEY")
auth_profile = os.getenv("OCI_AUTH_PROFILE", "DEFAULT")
auth_file_location = os.getenv(
    "OCI_AUTH_FILE_LOCATION",
    "~/.oci/config",
)

# Use the same model and dimensions that were used to index the table.
embeddings = OCIGenAIEmbeddings(
    model_id="cohere.embed-v4.0",
    compartment_id=compartment_id,
    service_endpoint=service_endpoint,
    auth_type=auth_type,
    auth_profile=auth_profile,
    auth_file_location=auth_file_location,
)

knowledge = ADB(
    dsn=os.environ["ADB_DSN"],
    user=os.environ["ADB_USER"],
    password=os.environ["ADB_PASSWORD"],
    wallet_location=os.getenv("ADB_WALLET_LOCATION"),
    wallet_password=os.getenv("ADB_WALLET_PASSWORD"),
    table_name=os.getenv("ADB_TABLE_NAME", "VECTOR_DOCUMENTS"),
    datastore_description=(
        "product documentation, operating procedures, and support runbooks"
    ),
)

Keep datastore_description short and specific to the datastore content. When you register multiple datastores, the factory embeds these descriptions and uses them to select the datastore that best matches a query.

Create and Invoke a Deep Agent

Pass the datastore and its embedding model to create_deepagents_agent().

from langchain_oci import create_deepagents_agent

agent = create_deepagents_agent(
    datastores={"knowledge": knowledge},
    default_datastore="knowledge",
    embedding_model=embeddings,
    model_id="google.gemini-2.5-pro",
    compartment_id=compartment_id,
    service_endpoint=service_endpoint,
    auth_type=auth_type,
    auth_profile=auth_profile,
    auth_file_location=auth_file_location,
    top_k=5,
    system_prompt=(
        "You are a research agent. Search Oracle before making factual "
        "claims, cite document IDs, and save useful intermediate results."
    ),
    name="oracle-research-agent",
)

result = agent.invoke(
    {
        "messages": [
            {
                "role": "user",
                "content": "Research the connection pool recovery procedure.",
            }
        ]
    }
)
print(result["messages"][-1].content)

# Close the datastore after the application finishes using the agent.
knowledge.close()

The factory adds three tools for the registered datastores:

Tool Purpose
stats Inspect datastore sizes and metadata.
search Search relevant chunks by semantic similarity and Oracle Text keyword matches.
get_document Retrieve a complete document by its identifier.

The default factory path uses the full upstream Deep Agents harness. Do not pass middleware=[] when you want the planning, file system, and subagent features. An explicit empty middleware list selects a lighter LangChain ReAct path when no other Deep Agents-only option is set.

For explicit model-client lifecycle control, create a ChatOCIGenAI instance, pass it through model=, and call await model.aclose() during application shutdown. Closing the model client is especially important for long-running asynchronous applications.

Use Non-OCI Models and Embeddings

Pass prebuilt LangChain objects through model= and embedding_model= to use non-OCI providers for both reasoning and query embeddings. The Oracle datastore, generated tools, and persistence configuration remain unchanged.

Install only the provider packages that your application uses.

python -m pip install --upgrade langchain-anthropic langchain-huggingface sentence-transformers
python -m pip install --upgrade langchain-openai

The Oracle vector table must be indexed with the same embedding model, dimensions, and embedding settings that you pass to embedding_model=. For example, a table indexed with sentence-transformers/all-MiniLM-L6-v2 and normalized embeddings must be searched with that same HuggingFace embedding configuration.

Use an ADB datastore that points to a table indexed for the embedding model in the example. Do not point the HuggingFace or OpenAI examples at a table that was indexed with OCI embeddings.

Anthropic Chat Model and HuggingFace Embeddings

Use this pattern when the agent should reason with Claude and use local HuggingFace embeddings for Oracle datastore search.

Set ANTHROPIC_API_KEY and ANTHROPIC_MODEL before running the example.

import os

from langchain_anthropic import ChatAnthropic
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_oci import create_deepagents_agent

embedding_model = HuggingFaceEmbeddings(
    model_name="sentence-transformers/all-MiniLM-L6-v2",
    model_kwargs={"device": "cpu"},
    encode_kwargs={"normalize_embeddings": True},
)

model = ChatAnthropic(
    model=os.environ["ANTHROPIC_MODEL"],
    max_tokens=2048,
)

agent = create_deepagents_agent(
    model=model,
    datastores={"knowledge": knowledge},
    default_datastore="knowledge",
    embedding_model=embedding_model,
    system_prompt="Search Oracle, plan the research, and cite document IDs.",
)

This example does not require OCI model or embedding credentials. It still requires Oracle AI Database credentials for the ADB datastore and any Oracle-backed persistence components.

OpenAI Chat Model and OpenAI Embeddings

Use this pattern when the agent should use OpenAI for both reasoning and query embeddings.

import os

from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_oci import create_deepagents_agent

embedding_model = OpenAIEmbeddings(
    model=os.environ["OPENAI_EMBEDDING_MODEL"],
)

model = ChatOpenAI(
    model=os.environ["OPENAI_CHAT_MODEL"],
)

agent = create_deepagents_agent(
    model=model,
    datastores={"knowledge": knowledge},
    default_datastore="knowledge",
    embedding_model=embedding_model,
    system_prompt="Search Oracle, plan the research, and cite document IDs.",
)

Set OPENAI_API_KEY, OPENAI_CHAT_MODEL, and OPENAI_EMBEDDING_MODEL before running the example. The Oracle vector table must use vectors generated by the same OpenAI embedding model and dimensions.

Persist Agent State

Pass an OracleSaver to the factory when an agent must preserve per-thread graph state. Create the saver before you create the agent, then invoke the agent with a stable thread_id.

import oracledb
from langgraph_oracledb.checkpoint.oracle import OracleSaver

pool = oracledb.create_pool(
    user=os.environ["ADB_USER"],
    password=os.environ["ADB_PASSWORD"],
    dsn=os.environ["ADB_DSN"],
    config_dir=os.getenv("ADB_WALLET_LOCATION"),
    wallet_location=os.getenv("ADB_WALLET_LOCATION"),
    wallet_password=os.getenv("ADB_WALLET_PASSWORD"),
    min=1,
    max=6,
    increment=1,
)

checkpointer = OracleSaver(pool, json_size_threshold_mb=0.0)
checkpointer.setup()

durable_agent = create_deepagents_agent(
    datastores={"knowledge": knowledge},
    default_datastore="knowledge",
    embedding_model=embeddings,
    model_id="google.gemini-2.5-pro",
    compartment_id=compartment_id,
    service_endpoint=service_endpoint,
    auth_type=auth_type,
    auth_profile=auth_profile,
    auth_file_location=auth_file_location,
    checkpointer=checkpointer,
    system_prompt="Search Oracle, plan the research, and cite document IDs.",
)

config = {"configurable": {"thread_id": "research-thread-001"}}
result = durable_agent.invoke(
    {
        "messages": [
            {"role": "user", "content": "Research the recovery procedure."}
        ]
    },
    config=config,
)

Invoke the agent again with the same thread_id to continue from its stored graph state. Use OracleStore for application-managed, vector-searchable values that span threads. Passing a store does not automatically expose its semantic search to the model. Add a tool or middleware when the agent must recall those values autonomously. To persist the agent’s virtual files, create a Deep Agents StoreBackend over OracleStore and pass both store= and backend= to the factory.

Close the datastore and connection pool when the application finishes using them.

Continue with the Companion Notebook

As the next step, work through Build a Deep Research Agent over a Private Knowledge Base — Oracle AI Database + Claude.

The notebook provides an executable end-to-end workflow that does the following:

  1. Starts Oracle AI Database Free for local development.
  2. Loads a small incident-research corpus into an ADB datastore.
  3. Adds an Oracle Text index for hybrid vector and keyword search.
  4. Creates the agent with a prebuilt Claude chat model.
  5. Runs a research request and inspects the tool calls.

The notebook uses Claude and HuggingFace embeddings as one non-OCI model-provider example. create_deepagents_agent() accepts compatible prebuilt LangChain chat and embedding models, so the Oracle integration is not tied to Anthropic, HuggingFace, or OCI models.

Caution: Use an Oracle AI Database Free image that includes Oracle Text when you run the notebook locally. Images with a -slim tag omit the Oracle Text component required by the notebook’s search index.

Troubleshoot Common Issues

Use this table to identify common configuration problems.

Symptom Corrective Action
The deepagents package cannot be imported. Use Python 3.11 through 3.13 and install langchain-oci[deepagents].
The factory reports that compartment_id is missing. Pass compartment_id= or set OCI_COMPARTMENT_ID.
Search returns irrelevant results or reports a vector dimension error. Use the same embedding model and dimensions for document indexing and query-time search.
A non-OCI model provider reports an authentication error. Set the provider’s API key and model environment variables before creating the LangChain model object.
Exact identifiers are not found. Verify that the Oracle Text search index exists and that the datastore keyword retriever can use it.
The agent does not have the expected planning, file, or subagent capabilities. Remove middleware=[] so the factory uses the full Deep Agents path.
An Autonomous AI Database connection fails. Verify the DSN, user, password, wallet path, wallet password, and network access.

Review Reference Links