# OpenAI API client isnide creat\_agent insted of ChatOpenAI

**URL:** <https://forum.langchain.com/t/openai-api-client-isnide-creat-agent-insted-of-chatopenai/2891>\
**Category:** Forum Feedback\
**Created:** [February 5, 2026, 10:34am UTC](https://forum.langchain.com/t/openai-api-client-isnide-creat-agent-insted-of-chatopenai/2891 "2026-02-05T10:34:36Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![Petar](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.langchain.com/petar/32/60_2.png) [@Petar](https://forum.langchain.com/u/Petar)\
**Post date:** [February 5, 2026, 10:34am UTC](https://forum.langchain.com/t/openai-api-client-isnide-creat-agent-insted-of-chatopenai/2891/1 "2026-02-05T10:34:36Z")

</div>

Is it possible to use the OpenAI API directly without using the LangChain wrapper for `create_agent` in LangGraph, and also trace this OpenAI client in LangSmith traces (usage, metadata, etc.)?

Insted of using this:

return create\_agent(  
model=ChatOpenAI(),  
tools=CHAT\_TOOLS,  
system\_prompt=None,  
middleware=self.\_get\_middleware\_stack(),  
state\_schema=State,  
context\_schema=AgentContext,  
)

However, for architectural and reliability reasons, we’d prefer to:

- call the **OpenAI client directly** (e.g. openai.responses.create),

- have **full control over request construction** (model selection, reasoning mode, tool schema, retries, fallbacks),

- **avoid LangChain abstractions** for the core LLM call,

- while still keeping **LangGraph orchestration** and **LangSmith observability**.

---

<div class="post-metadata">

**Author:** ![pawel-twardziak](https://yyz1.discourse-cdn.com/flex007/user_avatar/forum.langchain.com/pawel-twardziak/32/960_2.png) [@pawel-twardziak](https://forum.langchain.com/u/pawel-twardziak)\
**Post date:** [February 5, 2026, 4:23pm UTC](https://forum.langchain.com/t/openai-api-client-isnide-creat-agent-insted-of-chatopenai/2891/2 "2026-02-05T16:23:51Z")

</div>

hi @Petar

I think you can call the OpenAI SDK directly and still get LangGraph orchestration + LangSmith traces - but with one important constraint.  
You can’t pass a raw OpenAI client as the `model=` argument to `create_agent`. `create_agent` expects either a model string (e.g. `"openai:gpt-4o"`) or a LangChain `BaseChatModel` instance, and its internal loop assumes it can call `.invoke()` / `.ainvoke()` on that model.

If you truly want to avoid LangChain for the core LLM call, you typically choose one of the following patterns:

### A: Build a small LangGraph agent loop yourself, call OpenAI directly, trace with LangSmith

This is the cleanest approach if you want full control over the OpenAI request shape (Responses API, reasoning mode, retries, fallbacks, custom tool schema, etc.).

- LangGraph orchestration: you implement a node that calls OpenAI and a node that executes tools (or call tools inline).
- LangSmith tracing: wrap the OpenAI client with `wrap_openai`, and decorate your own nodes/tools with `@traceable`.

LangSmith docs show exactly this idea (LangGraph workflow that calls OpenAI via a wrapped client, and traces tools via `@traceable`) in their “Trace with LangGraph” guide:

> **[Trace with LangGraph - Docs by LangChain](https://docs.langchain.com/langsmith/trace-with-langgraph)**

LangSmith also documents wrapping the OpenAI client for automatic tracing:

> **[Trace with OpenAI - Docs by LangChain](https://docs.langchain.com/langsmith/trace-openai)**

And LangGraph docs show how to selectively enable tracing + add tags/metadata for a run via `tracing_context`:

> **[LangSmith Observability - Docs by LangChain](https://docs.langchain.com/oss/python/langgraph/observability)**

OpenAI’s Python SDK documents the Responses API client call:

> <https://github.com/openai/openai-python/blob/main/README.md>

and endpoint details in:

> <https://github.com/openai/openai-python/blob/main/api.md>

**Sketch (Responses API + tracing):**

```python
from openai import OpenAI
import langsmith as ls
from langsmith import traceable
from langsmith.wrappers import wrap_openai
from langgraph.graph import StateGraph

# 1) Wrap OpenAI client so LLM calls are traced in LangSmith
oai = wrap_openai(OpenAI())

@traceable(run_type="tool", name="MyTool")
def my_tool(x: str) -> str:
    return x.upper()

def call_model(state: dict):
    # 2) Call OpenAI directly (you control: model, reasoning params, retries, fallbacks, tools schema, etc.)
    resp = oai.responses.create(
        model="gpt-4o",
        input=state["messages"],
        # tools=[...], tool_choice="auto", reasoning={...}, etc.
    )
    # 3) Convert resp into your graph state shape (messages + tool calls if any)
    return {"messages": state["messages"] + [{"role": "assistant", "content": resp.output_text}]}

workflow = StateGraph(dict)
workflow.add_node("model", call_model)
workflow.add_edge(" __start__", "model")
app = workflow.compile()

# 4) Add tags/metadata to LangSmith traces for this invocation
with ls.tracing_context(
    enabled=True,
    project_name="my-agent",
    tags=["prod", "responses-api"],
    metadata={"user_id": "123", "request_id": "abc"},
):
    out = app.invoke({"messages": [{"role": "user", "content": "hello"}]})

```

Notes:

- If you want tool calling, you’ll need to (a) pass OpenAI tool schemas to `responses.create`, (b) parse tool calls from the Responses output structure, (c) execute tools, (d) append tool results back into `state["messages"]`, then loop. LangSmith’s "Trace with LangGraph” guide demonstrates the same loop shape using `chat.completions` tool calls; the exact extraction differs for Responses but the tracing/orchestration pattern is identical. (`wrap_openai` + `@traceable` + a LangGraph loop.)

### B: Keep `create_agent`, but intercept the model call with middleware (advanced)

If you strongly want the `create_agent` scaffolding (middleware hooks, ToolNode integration, structured output wiring), you can implement an `AgentMiddleware.wrap_model_call` / `awrap_model_call` that does not call the provided handler, and instead calls OpenAI directly and returns an `AIMessage`/`ModelResponse`.

This can work because `create_agent` explicitly supports `wrap_model_call` middleware and the middleware return type can be an `AIMessage` (or `ModelResponse`). But it’s more complex because:

- You must translate OpenAI Responses output into a LangChain `AIMessage` that `create_agent` can route (including correctly-shaped `tool_calls` if you want tools).
- You must ensure your tool-call IDs and tool-result messages align with the agent loop expectations.
- You must decide how to derive or pass tool schemas (the agent normally uses `model.bind_tools(...)` + `ToolNode` tool definitions).  
Tracing is still straightforward: wrap the OpenAI client with `wrap_openai` and/or wrap the middleware method with `@traceable`.
