DeepClaude – Claude Code agent loop with DeepSeek V4 Pro
DeepClaude – Claude Code agent loop with DeepSeek V4 Pro
A coding agent can burn through 200,000 input tokens without generating 200,000 tokens of visible conversation. Ask it to fix one failing test and the loop may read package.json, inspect 12 source files, search the repository, run the test suite twice, and resend much of that accumulated context on every model call.
That is why swapping the model behind Claude Code is more than a compatibility trick. A setup I’ll call DeepClaude keeps the Claude Code agent loop—the repository navigation, tool execution, permission flow, and iterative planning—but routes model inference to DeepSeek V4 Pro through an API adapter.
The useful mental model is simple:
Claude Code
↓ Anthropic Messages API
compatibility gateway
↓ provider-specific request
DeepSeek V4 Pro
↓ provider-specific response
compatibility gateway
↓ Anthropic content blocks
Claude Code executes tools and continues the loop
This can reduce inference cost or give you a different reasoning profile without rebuilding the entire coding harness. It also exposes a hard truth: API compatibility does not guarantee equivalent agent behavior.
What the Claude Code agent loop actually does
Claude Code is not merely a chat client attached to a shell. The harness repeatedly coordinates four jobs:
- Builds a prompt containing instructions, conversation state, and tool definitions.
- Sends that state to a model.
- Interprets text or structured tool requests from the response.
- Executes approved tools and returns their results to the model.
A simplified loop looks like this:
messages = [{"role": "user", "content": "Fix the failing parser tests"}]
while True:
response = model.create_message(
system=project_instructions,
messages=messages,
tools=available_tools,
max_tokens=4096,
)
messages.append({
"role": "assistant",
"content": response.content,
})
tool_calls = extract_tool_calls(response.content)
if not tool_calls:
print(extract_text(response.content))
break
results = []
for call in tool_calls:
result = execute_with_permissions(call)
results.append({
"type": "tool_result",
"tool_use_id": call["id"],
"content": result,
})
messages.append({
"role": "user",
"content": results,
})
The model proposes actions; the harness performs them. This distinction matters because DeepSeek V4 Pro does not need to implement file editing or shell execution itself. It needs to reliably select tools, produce valid arguments, interpret results, and know when to stop.
“DeepSeek V4 Pro” may also be a provider-specific deployment name rather than a universal API contract. Before relying on it, verify the exact model identifier, context limit, tool-calling format, pricing, and availability exposed by your endpoint.
Connecting Claude Code through a compatibility gateway
If your gateway exposes an Anthropic-compatible Messages API, the client-side configuration can be small:
export ANTHROPIC_BASE_URL="http://127.0.0.1:8787"
export ANTHROPIC_AUTH_TOKEN="local-gateway-token"
claude
Environment variable support can vary by Claude Code release and provider setup, so confirm the effective configuration locally. Do not assume that setting a base URL means every Anthropic feature is supported.
The gateway must accept a request shaped roughly like this:
{
"model": "deepseek-v4-pro",
"max_tokens": 4096,
"system": "You are working in a TypeScript repository.",
"messages": [
{
"role": "user",
"content": "Find and fix the failing parser test."
}
],
"tools": [
{
"name": "read_file",
"description": "Read a UTF-8 text file",
"input_schema": {
"type": "object",
"properties": {
"path": {"type": "string"}
},
"required": ["path"]
}
}
]
}
The adapter then translates that request into the target provider’s schema. A minimal FastAPI sketch illustrates where the important work belongs:
import os
import uuid
import httpx
from fastapi import FastAPI, Header, HTTPException, Request
app = FastAPI()
UPSTREAM_URL = os.environ["UPSTREAM_URL"]
UPSTREAM_KEY = os.environ["UPSTREAM_KEY"]
GATEWAY_TOKEN = os.environ["GATEWAY_TOKEN"]
@app.post("/v1/messages")
async def messages(
request: Request,
x_api_key: str | None = Header(default=None),
):
if x_api_key != GATEWAY_TOKEN:
raise HTTPException(status_code=401, detail="Invalid gateway token")
body = await request.json()
upstream_request = {
"model": "deepseek-v4-pro",
"messages": normalize_messages(
body.get("system"),
body["messages"],
),
"tools": convert_tools(body.get("tools", [])),
"max_tokens": body.get("max_tokens", 4096),
"stream": False,
}
async with httpx.AsyncClient(timeout=180) as client:
result = await client.post(
UPSTREAM_URL,
headers={"Authorization": f"Bearer {UPSTREAM_KEY}"},
json=upstream_request,
)
result.raise_for_status()
payload = result.json()
return to_anthropic_response(payload, uuid.uuid4().hex)
The omitted conversion functions are the real engineering task. In practice, most integration failures occur there—not in the HTTP request itself.
Preserve tool-call identity
Claude-style responses represent tool use as typed content blocks:
{
"content": [
{
"type": "tool_use",
"id": "toolu_01",
"name": "read_file",
"input": {"path": "src/parser.ts"}
}
],
"stop_reason": "tool_use"
}
If the upstream API returns tool_calls, map every call to a stable tool_use ID. When Claude Code sends the result back, that ID must still identify the original call. Generating a different ID during each conversion causes orphaned results and repeated tool requests.
You also need explicit mappings for:
- system prompts;
- mixed text and tool blocks;
- tool errors;
- parallel tool calls;
- stop reasons;
- token usage;
- streaming deltas;
- empty or malformed arguments.
A common gotcha is returning valid JSON with the wrong stop reason. Claude Code may see text plus a tool block, receive an “end turn” signal, and terminate instead of executing the tool.
Start without streaming, then add it deliberately
Streaming improves perceived latency, but it multiplies adapter complexity. Tool arguments may arrive as fragments:
{"path":
"src/par"
"ser.ts"}
Your gateway must buffer those fragments, associate them with the correct tool call, and emit valid Anthropic-style events in order. For an initial implementation, use a non-streaming upstream request and return one complete response. Once tool execution is stable, add streaming with tests for fragmented JSON and multiple simultaneous calls.
This is less flashy, but it shortens debugging dramatically.
Model interchangeability has limits
Claude Code’s prompts and tool descriptions are tuned around Claude-family behavior. A compatible model can read the same schema while making different operational choices.
| Area | Claude-family model | DeepSeek V4 Pro through an adapter | Practical implication |
|---|---|---|---|
| API shape | Native Messages semantics | Translated semantics | Test every content-block type |
| Tool selection | Aligned with Claude Code’s harness | Model- and provider-dependent | Expect different call order and frequency |
| Streaming | Native event format | Requires event conversion | Begin with non-streaming |
| Context handling | Known to the selected Claude deployment | Depends on the exposed deployment | Enforce a gateway-side budget |
| Errors and usage | Native fields | Must be normalized | Preserve raw upstream diagnostics privately |
| Prompt behavior | Harness and model evolved together | Same prompt, different interpretation | Evaluate on real repositories |
This does not mean the alternative model is inherently worse. I have found that agent quality is task-shaped: one model may navigate a repository efficiently but over-edit files, while another reasons carefully and spends too many turns inspecting context. The only meaningful evaluation uses your own tasks.
Create a small repeatable suite:
- fix a test with a one-line implementation defect;
- add a feature spanning three files;
- diagnose a build failure without editing;
- perform a constrained refactor;
- reject a malicious instruction embedded in a repository file.
Record completion, changed files, tool calls, retries, input tokens, output tokens, and wall-clock time. “The final test passed” is insufficient if the agent rewrote unrelated modules or needed 40 shell calls.
Cost depends on the loop, not one prompt
Suppose an endpoint charges a hypothetical $0.50 per million input tokens and $2.00 per million output tokens. A task consuming 180,000 input tokens and 12,000 output tokens costs:
input = 180,000 / 1,000,000 × $0.50 = $0.090
output = 12,000 / 1,000,000 × $2.00 = $0.024
total $0.114
Those rates are an example, not a claim about current DeepSeek V4 Pro pricing. Substitute the prices shown by your provider.
The subtle cost is repeated context. Ten calls averaging 30,000 input tokens create 300,000 billed input tokens even if the repository contains only 30,000 relevant tokens. Cache discounts, if offered, also depend on provider-specific rules and must be verified rather than assumed.
A multi-model gateway can help compare this path with Claude, GPT-5.5, or Gemini 3 without changing application code repeatedly. AI Prime Tech is one option for cheaper multi-model API access, but normalize usage and error reporting before comparing invoices.
Guardrails I would keep in production
A model swap must not weaken the execution boundary. Keep permissions in the harness or gateway, never in the model prompt alone.
- Require confirmation for destructive shell commands.
- Restrict file access to the repository root.
- Redact API keys from prompts, tool output, and logs.
- Cap turns, cumulative tokens, and wall-clock duration.
- Validate tool arguments against JSON Schema.
- Limit command output before returning it to context.
- Log model ID, request ID, tool calls, usage, and termination reason.
- Fall back to a known model after repeated malformed tool calls, not after every difficult answer.
Treat repository content as untrusted. A checked-in file can contain instructions telling the agent to upload secrets or ignore its task. The model may read that text, but the executor must still deny the action.
Practical takeaways
- DeepClaude is best understood as Claude Code’s agent harness plus a DeepSeek V4 Pro inference backend, joined by a compatibility layer.
- Prove non-streaming message and tool conversion before implementing streamed events.
- Preserve tool IDs, content-block ordering, stop reasons, and usage data exactly.
- Verify the deployment’s real model name, limits, pricing, and tool support; provider labels are not universal specifications.
- Compare models on repository-level tasks, including changed-file scope and tool-call count—not only whether tests pass.
- Budget for cumulative loop tokens, because repeated context usually dominates agent cost.
- Keep shell, filesystem, secret, and network controls outside the model.
- Maintain an escape hatch to Claude, GPT, or Gemini when a task exposes compatibility or reasoning weaknesses.
One API key for Claude Opus 4.8, Sonnet 4.6, Haiku 4.5, Fable 5, plus GPT & Gemini — up to 80% off official pricing, pay-as-you-go.
Get Your API Key →