Back to Blog

DeepSeek Responses API: Fix Context and Tool-Call Errors

Tutorials and Guides2452
DeepSeek Responses API: Fix Context and Tool-Call Errors

Your first DeepSeek Responses API request succeeds. The second request forgets information from the first. A tool runs correctly, but the model behaves as though it never received the result.

These failures often appear to be model-quality problems. In practice, they can come from how the application manages conversation history and tool results.

DeepSeek’s current Responses API is stateless. Your client is responsible for supplying the conversation needed for each request. Sending a previous response identifier does not provide the same continuation behavior as a service that stores and retrieves conversation state.

This tutorial shows how to build a small multi-turn flow, preserve the required items and validate an API gateway route before adding a larger agent workflow.

*Documentation checked: October 29, 2026.*

1. Understand the stateless Responses API contract

The DeepSeek Responses API reference states that responses and conversations are not stored on the server for continuation. Multi-turn clients must send conversation history in the next request.

The compatibility guide also identifies unsupported state-related parameters, including previous_response_id and conversation.

This distinction matters because an SDK may expose parameters that a particular provider does not implement.

A request can therefore look familiar while behaving differently.

The application should treat its own conversation record as the source of truth. That record needs enough information to reconstruct the next request without assuming the upstream service remembers earlier turns.

This applies whether you connect directly or through an API gateway, unless the gateway explicitly documents an additional state-management layer.

2. Confirm the endpoint and model before debugging memory

Start with three configuration values:

SettingWhat to verify
Base URLIt belongs to the service receiving the request
API keyIt was issued for that service and account
Model IDIt is available on the selected Responses route

DeepSeek’s direct documentation uses https://api.deepseek.com as its base URL and shows deepseek-flash in its example.

A gateway may use a different base URL and model alias. Copy those values from its current documentation or account console.

Do not automatically append /v1 to every provider’s address. Likewise, do not place /responses inside an SDK base URL if the SDK will add the endpoint itself.

For a gateway integration, verify Responses support specifically. A working Chat Completions request is not enough.

The API gateway integration checklist explains why protocol and feature support should be evaluated separately.

3. Run a two-turn memory test

Before adding tools, run a small conversation in which the second answer depends on the first message.

Install the SDK:

bash
python -m pip install openai

Set these variables in the server environment:

Then use this local test:

python
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["LLM_API_KEY"],
    base_url=os.environ["LLM_BASE_URL"],
    timeout=60.0,
    max_retries=0,
)

model_id = os.environ["LLM_MODEL"]
instructions = (
    "Answer briefly using the conversation supplied in this request. "
    "Do not invent missing information."
)

history = [
    {
        "role": "user",
        "content": (
            "For this synthetic test, my demo order ID is ORDER-1042. "
            "Acknowledge the ID."
        ),
    }
]

def create_response(items):
    response = client.responses.create(
        model=model_id,
        instructions=instructions,
        input=items,
    )

    if response.status != "completed":
        raise RuntimeError(
            f"Response did not complete: {response.status}"
        )

    if not response.output_text.strip():
        raise RuntimeError("The response contained no final text.")

    return response

first = create_response(history)
print("First reply:", first.output_text)

history.extend(
    item.model_dump(exclude_none=True)
    for item in first.output
)

history.append(
    {
        "role": "user",
        "content": "Which demo order ID did I give you?",
    }
)

second = create_response(history)
print("Second reply:", second.output_text)

The second request includes the earlier user message and the first response’s output items. It does not rely on server-side memory.

This is a teaching template for a compatible route, not a claim that a paid request has already been tested on your account.

4. Check the request history, not only the final answer

If the second answer is wrong, inspect the request construction before changing models.

Confirm that:

  1. The original user message remains in the history.
  2. The first response was added after that message.
  3. The follow-up question appears last.
  4. The second request uses the intended model and endpoint.
  5. No middleware replaced the history with only the latest message.

Keep diagnostic logs focused on structure: item types, item counts, status and request identifiers. Avoid dumping secrets or unnecessary personal information.

For this synthetic example, you can inspect the complete history because it contains no real customer data. Use stricter logging rules when connecting production records.

The test is deliberately simple. If it fails, adding a database tool or a larger prompt will make the problem harder to isolate.

5. Treat tool calls as a paired exchange

A tool-enabled interaction introduces another requirement: the tool result must be associated with the model’s actual call.

The basic flow is:

  1. Send the user request and tool definition.
  2. Receive the model’s tool-call item.
  3. Validate the tool name and arguments.
  4. Execute an allowed application function.
  5. Add the tool call and its matching result to the history.
  6. Request the next model response.

For Responses-format function tools, the result uses the call’s call_id.

An illustrative result item looks like this:

json
{
  "type": "function_call_output",
  "call_id": "COPY_THE_ACTUAL_CALL_ID",
  "output": "{\"status\":\"processing\",\"source\":\"demo_fixture\"}"
}

The identifier above is a placeholder. In a running application, copy the value from the actual function-call item. Do not generate an unrelated ID for the result.

Also preserve the corresponding call item. A result without its call, or a call without its result, does not represent a complete exchange.

6. Validate arguments before running application code

A model-generated tool call is a request to your application. Your application still decides whether the request is valid.

For a read-only order-status tool, validate:

Do not use a user-supplied order number as sufficient authorization.

Return a clear tool result when the record is unavailable. That result might distinguish “not found” from “not authorized,” according to your application’s information-disclosure policy.

The model can then explain the outcome using the supplied result. It should not fill a failed lookup with a plausible shipping status.

For an initial integration test, use synthetic records and read-only tools. This makes the request sequence easier to verify.

7. Handle multiple calls with explicit limits

Do not assume a response will contain only one function call.

Inspect the output items and handle supported calls deliberately. Keep the association between each call and its result.

Your application should enforce its own limits on execution rounds and tool activity. An API parameter that is ignored by a provider cannot serve as your application’s budget control.

For example, you might allow:

These are application policies. They should be implemented in code rather than expressed only in the prompt.

If the workflow reaches a limit, return a clear partial outcome and explain what remains unresolved.

8. Recognize the correct streaming completion signal

Streaming introduces a different kind of state: a response may have started without finishing successfully.

DeepSeek’s Responses guide documents typed events. Terminal outcomes include response.completed, response.incomplete and response.failed; the stream does not end with the Chat Completions-style data: [DONE] marker.

Your application should distinguish visible text from successful completion.

A user may have seen several text fragments before the connection stopped. That does not prove the final answer was completed, nor that every intended tool exchange finished.

Buffer partial tool arguments until the relevant argument item is complete. Do not execute a function from an unfinished JSON fragment.

For debugging, begin with non-streaming requests. Add streaming after the conversation and tool-result flow works.

9. Avoid retrying the entire business operation blindly

A network timeout leaves an important question: which parts of the operation actually completed?

A model request may have failed before a tool was selected. Alternatively, the tool may have completed, and the connection may have failed before the final explanation reached the user.

Those situations require different recovery behavior.

For read-only tools, repeating a lookup may be acceptable. For actions that create records, send notifications or modify data, use application-level operation identifiers and completion records.

Before replaying an interrupted action, check whether it already completed.

The SDK in the example uses max_retries=0 so that the initial diagnostic test has explicit retry behavior. Production retry rules should distinguish temporary transport failures from invalid requests, exhausted quota and completed business operations.

If the underlying issue is repeated rate limiting, use the existing Codex 429 troubleshooting guide to investigate the account and route involved.

10. Keep history useful without breaking its structure

Stateless conversation handling does not mean every future request should grow without limits.

Separate the durable task record from the context selected for the next model call.

A durable record can retain the full audit trail. The next request should contain the instructions, relevant facts and complete tool exchanges required for the current task.

When reducing context:

Do not remove random items merely to fit a token target. That can leave the model with an answer but no supporting tool result, or a tool result whose purpose is unclear.

11. Validate a gateway with a small compatibility suite

Before moving a larger workflow, test the selected route with:

TestExpected evidence
Plain text requestA completed response
Two-turn conversationCorrect use of client-supplied history
Read-only tool callValid arguments and a matched result
Missing recordNo invented result
Streaming requestA recognized terminal event
Interrupted workflowA controlled recovery path

Use 4SAPI’s model catalog and pricing page to identify the available DeepSeek route, then confirm its current Responses support and model identifier.

A route should pass the operations your application uses. Passing the first row alone is not enough to validate an agent workflow.

Frequently asked questions

Why does DeepSeek forget the previous message?

Check whether the next request contains the conversation history. The direct Responses API is stateless.

Can I use previous_response_id instead of sending history?

Do not depend on that behavior for DeepSeek’s documented direct API. A gateway would need to document its own state-management capability separately.

Why did the tool run but the model ignore its result?

Inspect the history for the original tool call, the matching call_id and the result item. Also check whether the next request actually included them.

Does an HTTP 200 response prove full compatibility?

No. Check the returned structure, completion status and the behavior of the feature you requested.

Does stateless mean the provider never logs anything?

No. Conversation continuation behavior and data-retention policy are separate questions. Read the provider’s applicable terms and documentation.

Build the conversation before expanding the agent

Start with a two-turn memory test. Then add one read-only tool, validate the call-result pairing and test interruption handling.

Create a 4SAPI account, confirm a compatible DeepSeek Responses route, and use this small test sequence to verify the integration before connecting a larger workflow.

Tags:DeepSeekResponses APITool CallingConversation StateAPI Integration

Recommended reading

Explore more frontier insights and industry know-how.