[KongchangAI]
· 2 min read· 1,088 words

How to Intercept LangChain Tool Calls by Argument Without Touching Agent Code

How to Intercept LangChain Tool Calls by Argument Without Touching Agent Code

Insert a policy gateway via base_url to intercept LangGraph tool calls by argument with zero agent code changes.

This article introduces a lightweight approach to intercepting tool calls in LangChain/LangGraph: replace ChatOpenAI's base_url with a third-party policy gateway to define argument-based blocking rules (e.g., "block refunds over 1000") without modifying agent code. The gateway intervenes between the model's tool call response and actual execution, logging intercepted calls in the trace. Key limitations include streaming mode only supporting after-the-fact flagging rather than true blocking, and a fail open design that passes requests through when the gateway is unavailable — making it unsuitable as the sole security boundary. The author recommends combining it with in-tool validation or interrupt()-based human approval as part of a defense-in-depth strategy.

When building LangChain / LangGraph agents, a common security challenge is: how do you prevent an agent from executing dangerous or unauthorized tool calls? For example, automatically blocking issue_refund when the refund amount exceeds a threshold. Traditional approaches either embed validation logic inside the tool itself or use interrupt() to introduce human approval — but both require modifying the agent code.

Recently, a developer on Reddit (founder of axonpush.xyz) shared a lighter-weight approach: inserting a "policy gateway" layer before tool execution, enabling zero-code-change call interception. This article breaks down that approach and analyzes its tradeoffs.

Core Idea: Insert a Policy Layer Between Model Response and Tool Execution

The key to this approach is changing the base URL to route requests through a gateway service instead of connecting directly to the model provider. With ChatOpenAI, you only need to swap out base_url and add an auth header at initialization:

llm = ChatOpenAI(
    model="gpt-4o",
    base_url="https://gateway.axonpush.xyz/v1",
    default_headers={"x-axonpush-key": AXONPUSH_KEY},
)

Once configured, you can define rules like block issue_refund when amount > 1000. The gateway reads the tool calls returned by the model and intercepts them before the agent's graph actually executes the tool. Intercepted calls appear in the trace log, annotated next to the step where execution was attempted.

reddit source: Block a LangChain/LangGraph tool call by its arguments without touching the agent code

The elegance of this design lies in separation of concerns: the agent's graph structure, tool definitions, and memory mechanisms all remain untouched. Security policies are externalized into an independently configurable layer. For scenarios where business rules change frequently, this means updating rules without touching code or redeploying the agent.

Three Key Limitations to Be Aware Of

The author honestly lists several boundary conditions for this approach — worth evaluating carefully before adoption:

No True Interception Under Streaming

Interception only works in non-streaming mode. When streaming=True, tool calls are detected and flagged, but this happens after the content has already been delivered. In other words, streaming mode only allows after-the-fact auditing (flagging), not pre-execution blocking. This is a significant constraint for production environments that rely heavily on streaming for real-time user experience.

Fail Open Behavior

The gateway uses a fail open policy: if the gateway service is unavailable, requests are passed directly to the model provider and calls execute as normal. This design preserves availability — a gateway outage won't take down the entire agent — but at the cost of a security compromise. In high-security scenarios, fail open could mean that an attacker who manages to disable the gateway bypasses all policies. This requires a conscious tradeoff between "availability first" and "security first" depending on your use case.

Depends on the Model's Tool Call Structure

The entire mechanism relies on parsing tool calls from the model's response. This makes it a natural fit for standard function calling flows, but compatibility with non-standard tool call formats or custom parsing logic remains unverified.


Fail Open vs. Fail Closed are two fundamental strategies in security system design. Fail Open means the system defaults to allowing all requests when a component fails, prioritizing availability. Fail Closed does the opposite — denying all requests on failure to prioritize security. Traditional security infrastructure like firewalls and WAFs typically use Fail Closed, since they're designed as the sole security boundary. This approach chooses Fail Open, suggesting it's positioned more as an "observability + convenient control layer" than a hard security boundary. For high-risk operations like payments or permission changes, relying on a single Fail Open gateway is essentially betting on the gateway's high availability — which generally doesn't align with Defense in Depth principles.


Comparison with Existing Approaches

In the LangGraph ecosystem, there are three main paths to controlling tool calls, each with its own tradeoffs:

Option 1: In-tool validation. Write check logic inside each tool function. Precise and controllable, but policies are coupled to business code, scattered across multiple places, and hard to manage or audit centrally.

Option 2: interrupt() for human approval. LangGraph's native interrupt mechanism, suitable for high-risk operations requiring human-in-the-loop. It can truly block execution and wait for a human decision, but introduces human latency and requires explicit interrupt nodes to be designed into the graph.

Option 3: External gateway (this approach). Policies are fully decoupled from code — changing rules doesn't require touching the agent. Well-suited for scenarios where rules change frequently or multiple agents share the same policy set. However, the streaming limitation and fail open behavior mean it's better suited as one layer of defense in depth rather than the sole security boundary.

The author actively invited feedback in the post: "Would love to hear from people who've solved this differently — e.g., using interrupt() for human approval or doing checks inside the tool." This openness suggests the approach is still in an exploratory phase.


Human-in-the-loop is an important concept in AI system safety, referring to the introduction of human decision-making at critical points in an automated process to prevent irreversible consequences from model errors or unauthorized actions. LangGraph's interrupt() mechanism is native support for this pattern: when an agent reaches an interrupt node, the graph's execution state is persisted and waits for external input (such as human approval) before continuing. This is similar to "approval nodes" in traditional RPA or workflow engines, but LangGraph's implementation allows the full conversation context and tool call arguments to be presented to the approver, enabling more informed human decisions. The tradeoff is introducing asynchronous waiting, making it unsuitable for millisecond-latency scenarios.


Practical Recommendations

For teams evaluating this type of approach, consider the following angles:

  • If your agent relies heavily on streaming output, the gateway's pre-execution blocking capability is significantly weakened — additional fallback measures are needed;
  • Fail open means the gateway cannot serve as the sole security boundary. For critical operations (e.g., financial transactions), it's recommended to layer in-tool validation or human approval on top;
  • The greatest value of an external policy layer lies in centralized management and observability — the trace clearly shows which calls were intercepted, which is valuable for compliance auditing.

Overall, intercepting tool calls by argument through a gateway is an architectural idea worth watching. It shifts agent security from "hardcoded in the application" to "configurable policy." But before going to production, be sure to test behavior in streaming scenarios and clearly understand the security boundaries created by fail open. As a disclosure, this approach is provided by axonpush.xyz — readers should evaluate it critically based on their own context.

#LangChain tool call interception#LangGraph policy gateway#agent security#tool call blocking#human-in-the-loop#fail open#LangGraph interrupt#ChatOpenAI base_url#AI agent safety#function calling security
Share:

Related articles