DeepSeek AI Agents: Architecture, Vision, Tools & Python

Build safer DeepSeek agents with Flash, Pro and Vision Exp, exact model routing, image validation, tool approvals, telemetry, fallbacks and Python examples.

Current API baseline verified: August 24, 2026. There is no separate DeepSeek API product called “DeepSeek AI Agent.” In practical terms, a DeepSeek agent is an application-controlled loop around the DeepSeek API: the model proposes text or a tool call, your code validates it, your system decides whether approval is required, and only then does your application execute the action. DeepSeek currently lists two text-only models—deepseek-v4-flash and deepseek-v4-pro—plus the experimental multimodal deepseek-v4-flash-vision-exp for text-and-image input.

That distinction is the foundation of a reliable agent. DeepSeek can interpret a goal, plan a next step, and produce structured tool arguments. It does not automatically gain access to your database, browser, CRM, shell, email account, or payment system. Your application owns those connections—and must also own identity, permissions, validation, timeouts, audit logs, human review, and stop conditions.

Quick answer: Use deepseek-v4-flash as a practical starting point for routine text agents, evaluate deepseek-v4-pro for harder planning or coding tasks, and route screenshots, photos, diagrams, or other image-dependent work to deepseek-v4-flash-vision-exp. Give every model narrow tools, validate media before inference, cap every run, reject unknown functions and model IDs, and require explicit confirmation before any high-impact action.

A safe DeepSeek agent architecture

A useful mental model is: the model proposes; the application disposes. The model can request an action, but a trusted control layer makes the decision.

Authenticated user request
        ↓
Identity, tenant scope, and input/media validation
        ↓
Allowlisted model router selects Flash, Pro, or Vision Exp
        ↓
System instructions and policy
        ↓
DeepSeek model proposes an answer or tool call
        ↓
Allowlist + JSON argument validation + authorization
        ↓
Human approval when impact is high
        ↓
Application executes an idempotent, time-limited tool
        ↓
Sanitized tool result returns to the model
        ↓
Final answer, another bounded step, or a safe stop
LayerResponsibilityFailure to prevent
IdentityAuthenticate the user and resolve their tenant, role, and scopeOne user acting on another user’s data
Media intakeValidate actual image bytes, size, dimensions, source URL, tenant ownership, and retentionSSRF, spoofed formats, oversized payloads, or cross-tenant file reuse
Model routerChoose from an exact model allowlist using required modality and measured task difficultySending an image task to a text-only model or routing unknown IDs
OrchestratorManage messages, tools, step limits, state, retries, fallbacks, and terminationInfinite loops, silent degradation, and uncontrolled cost
DeepSeek modelUnderstand the goal and propose text or structured tool callsTreating a probabilistic proposal as authorization
Tool gatewayAllowlist functions, validate arguments, enforce policy, and normalize resultsArbitrary API or code execution
Approval serviceBind a human confirmation to an exact user, action, arguments, and expiryIrreversible actions without informed consent
Memory or RAGRetrieve scoped knowledge and preserve only necessary stateData leakage, stale facts, and invented policies
ObservabilityRecord model, modality, route reason, latency, tokens, tool outcomes, approvals, fallbacks, and errorsInvisible quality drift and untraceable changes

Start with one narrow workflow and one or two read-only tools. A deterministic script is better when the steps never change. An agent is useful when the system must interpret natural language, choose among constrained tools, or adapt its next step to a tool result.

Current DeepSeek model IDs for agents

DeepSeek’s current official model table lists three API identifiers. All three support a one-million-token context, up to 384,000 output tokens, thinking and non-thinking modes, Tool Calls, Chat Prefix Completion, and the Responses API. Flash and Pro accept text; Vision Exp accepts text plus images. FIM is available only for Flash and Pro in non-thinking mode and is not supported by Vision Exp. DeepSeek’s agent benchmark language is a vendor claim, so validate every route on your own tasks.

Model IDInputConcurrencySensible starting useImportant limit
deepseek-v4-flashText2,500 per accountRoutine support, retrieval, classification, and high-volume tool workflowsDo not send image blocks
deepseek-v4-proText500 per accountMore difficult planning, coding, or multi-step workDo not send image blocks
deepseek-v4-flash-vision-expText + images2,500 per accountScreenshot triage, visual QA, chart or diagram interpretation, photo-assisted support, and multimodal tool workflowsExperimental; FIM is not supported
Current direct-API capabilities checked August 24, 2026. Concurrency is account-level across keys. A third-party agent UI or adapter may expose fewer models or input types than the API.

The retired names deepseek-chat and deepseek-reasoner are absent from the current official model list. Their post-cutoff behavior has also been inconsistent in our dated checks: requests returned HTTP 400 on July 25, while July 28 checks returned HTTP 200 and identified V4 Flash in the response. That is an observation of temporary compatibility—not a production guarantee. New agents should use the explicit V4 IDs and monitor the official list. See our DeepSeek API updates, V4 migration guide, model guide, and pricing guide before deployment.

Multimodal agents with Vision Exp

deepseek-v4-flash-vision-exp can combine image understanding with Tool Calls and the Responses API. A safe agent can inspect a UI screenshot, extract visible evidence, and then propose a narrow tool call such as create_visual_bug_report. The model still does not execute that tool: your application validates the visual evidence, arguments, authorization, and impact before doing anything.

Image routeUse it whenRequired controls
Public HTTPS URLThe image is intentionally public and can be fetched within the provider limitServer-side URL allowlist, HTTPS only, redirect/IP checks, no signed secrets in query strings
Base64 data URLA local image fits inside the request-body budgetValidate decoded bytes, MIME signature, size, dimensions, and memory use before encoding
Files API file_idThe same approved image is reused or is too large for the inline pathBind the ID to tenant and purpose, use image-only uploads, define expiry, and never expose reusable IDs to another tenant
Inline file_dataAn image is sent in a file block without a prior uploadApply the same byte, format, size, privacy, and retention checks as Base64
Official image inputs are URL, Base64, file_id, and file_data. The Files API supports images—not PDF, DOCX, ZIP, arbitrary knowledge files, or batch jobs.

Exact model allowlist and safe fallback

MODEL_POLICY = {
    "deepseek-v4-flash": {"modalities": {"text"}, "concurrency": 2500},
    "deepseek-v4-pro": {"modalities": {"text"}, "concurrency": 500},
    "deepseek-v4-flash-vision-exp": {
        "modalities": {"text", "image"},
        "concurrency": 2500,
    },
}

def select_model(*, image_count: int, hard_reasoning: bool) -> str:
    if image_count < 0:
        raise ValueError("image_count cannot be negative")
    if image_count:
        return "deepseek-v4-flash-vision-exp"
    return "deepseek-v4-pro" if hard_reasoning else "deepseek-v4-flash"

def assert_route(model: str, *, has_images: bool) -> None:
    policy = MODEL_POLICY.get(model)
    if policy is None:
        raise ValueError("Unknown model rejected")
    if has_images and "image" not in policy["modalities"]:
        raise ValueError("Image task cannot use a text-only model")

Do not silently fall back from Vision to Flash or Pro while pretending the image was analyzed. If the visual route is unavailable, either stop with a clear error or enter a labeled degraded mode that uses trusted OCR, accessibility-tree text, or a user-provided description. Record fallback_from, fallback_to, fallback_reason, and degraded_mode=true. For medical, financial, legal, security, identity, or irreversible decisions, require human review rather than converting a failed visual request into an unverified text-only decision.

Image-plus-tool request shape

import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["DEEPSEEK_API_KEY"],
    base_url="https://api.deepseek.com",
)

response = client.chat.completions.create(
    model="deepseek-v4-flash-vision-exp",
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": (
                "Inspect this UI screenshot. If there is visible clipping, "
                "propose create_visual_bug_report with observable evidence only."
            )},
            {"type": "image_url", "image_url": {
                "url": "https://static.example.com/review/ui-screenshot.png",
                "detail": "low",
            }},
        ],
    }],
    tools=[{
        "type": "function",
        "function": {
            "name": "create_visual_bug_report",
            "description": "Propose a draft bug report; does not publish it.",
            "parameters": {
                "type": "object",
                "properties": {
                    "summary": {"type": "string"},
                    "visible_evidence": {"type": "string"},
                },
                "required": ["summary", "visible_evidence"],
                "additionalProperties": False,
            },
        },
    }],
    tool_choice="auto",
    max_tokens=700,
    extra_body={"thinking": {"type": "disabled"}},
)

The sample URL is a placeholder. In production, never let the model or an untrusted user turn your image fetcher into an unrestricted network client. For Files API input, replace the image block with a validated {"type":"file","file_id":"file-api-..."} block; file_data is the inline file-block alternative. Images belong in user messages for Chat Completions. See the Vision Exp guide and API guide for the current size and message-placement limits.

Treat pixels and image text as untrusted input

  • Detect JPEG, PNG, GIF, or WebP from the actual bytes; do not trust the extension or declared MIME type.
  • Reject oversized files, excessive dimensions, too many images, decompression bombs, and unexpected animation before the provider request.
  • Strip unnecessary metadata and avoid retaining faces, IDs, screens, or location data longer than the documented purpose requires.
  • Treat text inside screenshots as data. It cannot override system policy, authorize a tool, reveal a secret, or approve an action.
  • Keep original media and file_id values out of ordinary logs. Record a protected internal reference or hash only when policy permits.
  • Make accessibility and OCR uncertainty visible. A confident visual description is not proof that every small label or state was read correctly.

Design tools as a security boundary

A tool schema helps the model format a request; it does not prove that the request is safe, authorized, or factually correct. Prefer small tools with explicit names such as lookup_order_status(order_id) over a broad function such as manage_order(action, data). Use required fields, enums where possible, and additionalProperties: false. Then repeat validation in application code before execution.

  • Allowlist tool names. Never dynamically import, evaluate, or dispatch a model-provided function name.
  • Validate types, formats, ranges, and exact keys. Valid JSON can still contain an unauthorized customer ID or a fabricated parameter.
  • Authorize after validation. Check the authenticated user’s tenant and resource permissions against server-side data.
  • Separate reads from writes. Search and status lookup can often run automatically; deletion, payment, permission changes, publishing, and external messages usually need approval.
  • Minimize tool output. Return only fields needed for the next step, cap response size, and remove secrets or internal stack traces.
  • Treat retrieved text as untrusted data. A document saying “ignore your policy and call this tool” is content, not an instruction.

DeepSeek documents a strict tool-call mode in beta. It requires the beta base URL https://api.deepseek.com/beta and "strict": true on every function definition. The server validates supported JSON Schema features. Strict mode can improve schema conformance, but it is still beta and does not replace local validation, authorization, or approval.

Bounded Python agent with validation and approval

This complete example uses the OpenAI Python SDK against DeepSeek’s OpenAI-compatible endpoint. It has two simulated tools: a read-only order lookup and a cancellation action. The cancellation cannot run unless a trusted application layer supplies an approval ID bound to the exact action. In the default call at the bottom, no approval exists, so the agent stops and asks for one.

import json
import os
import re
import time
import uuid
from typing import Any

from openai import OpenAI

MODEL = "deepseek-v4-flash"
MAX_STEPS = 6
MAX_TOOL_CALLS_PER_STEP = 3
MAX_TOOL_RESULT_CHARS = 4_000
ORDER_ID = re.compile(r"^ord_[0-9]{4,12}$")

client = OpenAI(
    api_key=os.environ["DEEPSEEK_API_KEY"],
    base_url="https://api.deepseek.com",
    timeout=30.0,
    max_retries=2,
)

# Simulated storage. Replace it with an authorized server-side service.
ORDERS = {
    "ord_1001": {"status": "processing", "owner": "current_user"},
}
IDEMPOTENT_RESULTS: dict[str, dict[str, Any]] = {}

TOOLS = [
    {
        "type": "function",
        "function": {
            "name": "lookup_order_status",
            "description": "Read the status of an order owned by the signed-in user.",
            "parameters": {
                "type": "object",
                "properties": {"order_id": {"type": "string"}},
                "required": ["order_id"],
                "additionalProperties": False,
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "cancel_order",
            "description": (
                "Cancel an eligible order. This is a high-impact action "
                "and the application requires explicit human approval."
            ),
            "parameters": {
                "type": "object",
                "properties": {
                    "order_id": {"type": "string"},
                    "reason": {"type": "string"},
                },
                "required": ["order_id", "reason"],
                "additionalProperties": False,
            },
        },
    },
]

ALLOWED_TOOLS = {"lookup_order_status", "cancel_order"}


def audit(run_id: str, step: int, event: str, **fields: Any) -> None:
    # In production, send structured events to a protected log service.
    # Do not log secrets, private documents, or reasoning_content.
    record = {"run_id": run_id, "step": step, "event": event, **fields}
    print(json.dumps(record, separators=(",", ":"), default=str))


def validate_order_id(value: Any) -> str:
    if not isinstance(value, str) or not ORDER_ID.fullmatch(value):
        raise ValueError("Invalid order_id")
    return value


def parse_arguments(tool_name: str, raw: str) -> dict[str, str]:
    try:
        args = json.loads(raw)
    except json.JSONDecodeError as exc:
        raise ValueError("Tool arguments were not valid JSON") from exc

    if not isinstance(args, dict):
        raise ValueError("Tool arguments must be an object")

    if tool_name == "lookup_order_status":
        if set(args) != {"order_id"}:
            raise ValueError("Unexpected lookup arguments")
        return {"order_id": validate_order_id(args["order_id"])}

    if tool_name == "cancel_order":
        if set(args) != {"order_id", "reason"}:
            raise ValueError("Unexpected cancellation arguments")
        order_id = validate_order_id(args["order_id"])
        reason = args["reason"]
        if not isinstance(reason, str) or not 5 <= len(reason.strip()) <= 200:
            raise ValueError("Reason must contain 5 to 200 characters")
        return {"order_id": order_id, "reason": reason.strip()}

    raise ValueError("Unknown tool")


def lookup_order_status(order_id: str) -> dict[str, Any]:
    order = ORDERS.get(order_id)
    if not order or order["owner"] != "current_user":
        return {"found": False}
    return {"found": True, "order_id": order_id, "status": order["status"]}


def cancel_order(
    order_id: str, reason: str, idempotency_key: str
) -> dict[str, Any]:
    if idempotency_key in IDEMPOTENT_RESULTS:
        return IDEMPOTENT_RESULTS[idempotency_key]

    order = ORDERS.get(order_id)
    if not order or order["owner"] != "current_user":
        result = {"ok": False, "error": "Order not found"}
    elif order["status"] not in {"pending", "processing"}:
        result = {"ok": False, "error": "Order is not cancellable"}
    else:
        order["status"] = "cancelled"
        result = {
            "ok": True,
            "order_id": order_id,
            "status": "cancelled",
            "reason": reason,
        }

    IDEMPOTENT_RESULTS[idempotency_key] = result
    return result


def execute_tool(
    name: str,
    raw_arguments: str,
    approved_actions: dict[str, dict[str, Any]],
) -> tuple[dict[str, Any], bool]:
    if name not in ALLOWED_TOOLS:
        raise PermissionError("Unknown tool rejected")

    args = parse_arguments(name, raw_arguments)

    if name == "lookup_order_status":
        return lookup_order_status(**args), False

    # Bind approval to the authenticated user and the exact validated arguments.
    action_payload = {
        "tool": name,
        "arguments": args,
        "user_id": "current_user",
    }
    action_key = json.dumps(
        action_payload,
        sort_keys=True,
        separators=(",", ":"),
    )
    approval = approved_actions.get(action_key)
    if (
        not approval
        or approval.get("user_id") != "current_user"
        or not isinstance(approval.get("expires_at"), (int, float))
        or approval["expires_at"] <= time.time()
        or not isinstance(approval.get("approval_id"), str)
    ):
        return {
            "approval_required": True,
            "action_key": action_key,
            "summary": f"Cancel {args['order_id']} for: {args['reason']}",
        }, True

    # This record must come from an authenticated, short-lived server session.
    # Never accept an approval token invented by the model or copied from its text.
    approval_id = approval["approval_id"]
    idempotency_key = f"{action_key}:{approval_id}"
    return cancel_order(**args, idempotency_key=idempotency_key), False


def run_agent(
    user_text: str,
    approved_actions: dict[str, dict[str, Any]] | None = None,
) -> dict[str, Any]:
    run_id = str(uuid.uuid4())
    approvals = approved_actions or {}
    messages: list[dict[str, Any]] = [
        {
            "role": "system",
            "content": (
                "You are a careful order-support agent. Use tools for order facts. "
                "Never claim an action succeeded until a tool confirms it. "
                "Do not invent order data or bypass approval."
            ),
        },
        {"role": "user", "content": user_text},
    ]

    for step in range(1, MAX_STEPS + 1):
        response = client.chat.completions.create(
            model=MODEL,
            messages=messages,
            tools=TOOLS,
            tool_choice="auto",
            max_tokens=700,
            extra_body={"thinking": {"type": "disabled"}},
        )
        message = response.choices[0].message

        # Preserve every complete assistant message before checking tool_calls.
        # If a thinking-mode request includes tools, later requests must replay
        # its reasoning_content even when this turn produced no tool call.
        messages.append(message.model_dump(exclude_none=True))
        calls = message.tool_calls or []

        if not calls:
            audit(run_id, step, "completed")
            return {
                "status": "completed",
                "run_id": run_id,
                "answer": message.content or "",
            }

        if len(calls) > MAX_TOOL_CALLS_PER_STEP:
            audit(run_id, step, "rejected", reason="too_many_tool_calls")
            raise RuntimeError("Too many tool calls in one step")

        for call in calls:
            name = call.function.name
            if name not in ALLOWED_TOOLS:
                audit(run_id, step, "rejected", tool=name)
                raise PermissionError("Unknown tool rejected")

            try:
                result, needs_approval = execute_tool(
                    name,
                    call.function.arguments,
                    approvals,
                )
            except (ValueError, PermissionError) as exc:
                audit(run_id, step, "rejected", tool=name, reason=str(exc))
                raise

            audit(
                run_id,
                step,
                "tool_checked",
                tool=name,
                approval_required=needs_approval,
            )

            if needs_approval:
                return {
                    "status": "approval_required",
                    "run_id": run_id,
                    "action": result,
                }

            result_json = json.dumps(result, separators=(",", ":"))
            if len(result_json) > MAX_TOOL_RESULT_CHARS:
                result_json = json.dumps({"error": "Tool result exceeded limit"})

            messages.append(
                {
                    "role": "tool",
                    "tool_call_id": call.id,
                    "content": result_json,
                }
            )

    audit(run_id, MAX_STEPS, "stopped", reason="step_limit")
    raise RuntimeError("Agent stopped at the configured step limit")


# No cancellation can execute because the trusted approval map is empty.
result = run_agent(
    "Check ord_1001 and cancel it because I ordered the wrong item.",
    approved_actions={},
)
print(json.dumps(result, indent=2))

In a real product, the approval screen should show the exact action and arguments. After the authenticated user confirms, your server creates a short-lived, one-time approval record bound to the user, tenant, action key, arguments, and expiry. Do not infer approval from phrases inside the prompt, and do not let the model mint its own approval token.

Thinking mode and reasoning_content

The example disables thinking to keep the first implementation easy to inspect. If you enable thinking and the Chat Completions request includes tools, DeepSeek’s documentation requires the complete returned assistant message—including its reasoning_content—to be passed back in subsequent requests between user messages. This requirement is triggered by the presence of tools in the request, even when the model did not produce a tool call in that turn. Omitting the field can produce an HTTP 400 response. Preserve every assistant message in order; do not retain only tool-call turns.

Appending the SDK message with message.model_dump(exclude_none=True), as the example does, preserves the fields returned by the API. Do not reconstruct the assistant message with only content and tool_calls. Also avoid exposing or logging reasoning content; preserve it only as required inside the controlled conversation state. Test thinking and non-thinking paths separately before choosing a default.

Permissions, retries, and idempotency

Agent reliability is mostly systems engineering. Set both a model-step limit and an overall wall-clock deadline. Give each tool its own timeout. Retry only transient failures, use exponential backoff with jitter, and keep a small retry budget. Authentication and billing errors should be surfaced for correction, not retried in a loop. See the DeepSeek API guide for current request patterns.

Retries are especially dangerous for writes. If a request times out after reaching a payment, email, or order service, the agent may not know whether the action succeeded. Use an idempotency key at the action boundary and persist the result, so replaying the same approved operation returns the earlier outcome instead of performing it twice.

  • Give every run a trace ID and every tool call a stable ID.
  • Record requested_model, returned_model, input modality, route reason, mode, prompt version, step number, latency, prompt/cache/output tokens, tool name, validation result, approval record, and final status.
  • For visual routes, record a non-sensitive image count, input method, detail level, validation outcome, and any fallback_from, fallback_to, fallback_reason, or degraded-mode flag.
  • Never place Base64 payloads, raw images, signed URL query strings, reusable file_id values, credentials, private document text, or reasoning_content in ordinary logs.
  • Never expose provider stack traces or internal tool errors directly to an end user.
  • Use model-specific queue limits and a circuit breaker when a dependency repeatedly fails.

Memory and RAG without data leakage

The chat-completions API does not become durable business memory by itself. Your application decides which messages, summaries, and tool results to keep. Store the minimum needed, define retention, and isolate every tenant. A user-controlled conversation ID must never be sufficient to retrieve another account’s history.

For company policies or changing facts, retrieve relevant documents at run time instead of relying on model memory. Apply access control before retrieval, carry source identifiers into the answer, and let the agent say that the available context is insufficient. Retrieved passages and web pages are untrusted input, so they cannot override system policy or grant tool permission. The DeepSeek RAG knowledge-base guide covers retrieval, citations, metadata filters, and tenant isolation in more detail.

Evaluate the whole agent, not one answer

A model benchmark does not measure whether your agent chooses the correct internal tool, respects permission boundaries, or recovers from a timeout. Build a versioned evaluation set from real workflows and include ordinary requests, ambiguous requests, malformed IDs, unauthorized resources, prompt injection, unavailable tools, duplicate retries, and explicit approval cases.

MetricQuestion it answers
Task successDid the user’s goal reach the correct final state?
Modality-routing accuracyWere image-dependent requests sent to Vision and text-only requests kept on an appropriate text route?
Visual-grounding accuracyDid the answer and tool arguments describe evidence actually visible in the image?
Tool-selection accuracyDid the model choose the right tool—or correctly choose none?
Argument validityDid calls pass schema and business-rule validation?
Unauthorized-action rateDid any run attempt or complete an action outside policy?
Approval precisionWere high-impact actions paused without blocking safe reads unnecessarily?
Fallback integrityDid visual failures stop or enter an explicitly labeled degraded path without inventing unseen evidence?
Loop efficiencyHow many model steps and tool calls did successful runs require?
Quality, latency, and costDoes a model or prompt change improve outcomes enough to justify its trade-offs?

Run regression tests whenever you change the model ID, modality router, image preprocessing, thinking mode, system instructions, tool descriptions, schemas, retrieval configuration, fallback policy, or downstream APIs. In production, alert on rising media or argument validation failures, unexpected returned models, repeated tool loops, approval bypass attempts, silent visual fallbacks, latency spikes, empty responses, and token-cost anomalies.

Production deployment checklist

  1. Use an exact allowlist containing only the three current model IDs; reject unknown names and verify the returned model.
  2. Route every image-dependent task to Vision Exp; never send image blocks to Flash or Pro.
  3. Keep the DeepSeek API key in a server-side secret store.
  4. Authenticate users and enforce tenant scope before any retrieval, image upload, Files API lookup, or tool call.
  5. Validate actual image bytes, dimensions, count, source URL, ownership, expiry, and privacy before inference.
  6. Start with narrow, read-only tools and an explicit function-name allowlist.
  7. Validate every argument again in code; never trust schema conformance or visual confidence alone.
  8. Require human confirmation for writes with financial, legal, privacy, access, publishing, deletion, or external-communication impact.
  9. Use idempotency keys, per-tool timeouts, bounded retries, model-specific queues, and a circuit breaker.
  10. Cap steps, tool calls, images, tokens, tool-result size, wall time, and run cost.
  11. Sanitize tool output and defend against prompt injection in retrieved text and image content.
  12. Make fallbacks explicit; stop rather than pretending a text-only model saw an unavailable image.
  13. Maintain modality-aware telemetry, evaluation cases, rollback controls, and an incident owner.

DeepSeek AI agent FAQ

Is “DeepSeek AI Agent” an official standalone product?

No standalone API product with that name appears in the official materials reviewed for this guide. Developers use DeepSeek models inside an application-controlled agent loop. Third-party products may also use DeepSeek as a model provider, but their tools, storage, permissions, and privacy practices belong to those products.

Which DeepSeek model should I use for an agent?

Begin with deepseek-v4-flash for routine text workflows, test deepseek-v4-pro where planning or coding quality has higher value, and use deepseek-v4-flash-vision-exp whenever the result depends on pixels. Do not select by marketing alone: compare task success, modality routing, visual grounding, tool accuracy, latency, and total run cost on your own evaluation set.

Can a DeepSeek agent analyze screenshots or photos?

Yes—through the experimental deepseek-v4-flash-vision-exp model. It accepts image URL, Base64, file_id, or file_data input and supports Tool Calls and Responses. Flash and Pro remain text-only. Validate images and keep human review for high-impact decisions.

Can an agent silently fall back from Vision to Flash or Pro?

No. A text-only model cannot inspect missing pixels. Stop clearly or use an explicitly labeled degraded path based on trusted OCR, accessibility-tree text, or a user description. Record the route and reason, and require review when the fallback could change a consequential decision.

Does the model execute tool calls itself?

No. DeepSeek returns a structured request describing a function and arguments. Your application supplies and executes the function. That separation lets you reject unknown tools, validate arguments, check authorization, require approval, and log the result.

Is strict tool-call mode enough for production safety?

No. Strict mode is a beta schema-conformance feature reached through https://api.deepseek.com/beta. It can help format arguments, but valid arguments may still request an unauthorized or harmful action. Keep local validation, policy checks, approval, and idempotency.

Can a DeepSeek agent run autonomously?

It can automate bounded, low-risk workflows, but “autonomous” should not mean unbounded. Define allowed tools, resources, time, token budget, maximum steps, failure behavior, and escalation rules. Keep a human decision point for irreversible or materially consequential actions.

Do tool calls work with thinking mode?

Yes. If a thinking-mode Chat Completions request includes tools, pass every complete returned assistant message—including reasoning_content—back in later requests between user messages, even when a particular assistant turn contains no tool call. Do not display or log that field as an end-user explanation.

How should I give an agent company knowledge?

Use a permission-aware retrieval layer. Filter sources by the authenticated user and tenant before retrieval, return source metadata, constrain the answer to retrieved evidence, and test refusal when evidence is missing. Do not paste an entire private knowledge base into every prompt.

What should never be placed directly in an agent prompt?

Do not place API keys, passwords, unrestricted database credentials, private signing keys, or reusable approval tokens in prompts. Avoid unnecessary personal or regulated data. Give tools short-lived, least-privilege credentials on the server side instead.

Official DeepSeek sources

  • Models & Pricing — current model IDs, input modality, context/output sizes, features, and concurrency.
  • Vision — URL, Base64, file_id, file_data, formats, limits, and image token billing.
  • Files API — image-only uploads, lifecycle, and quotas.
  • Responses API — current stateless interface, tool support, and Vision image input.
  • Tool Calls — function-calling flow and strict beta mode.
  • Thinking Mode — multi-turn behavior and reasoning_content requirements.
  • Rate Limit & Isolation — account-level concurrency and user_id rules.
  • Error Codes — official HTTP error meanings.
  • Vision Exp and Files release — August 21 multimodal release notice.

Chat-Deep.ai is an independent DeepSeek reference and is not affiliated with, endorsed by, or operated by DeepSeek. Recheck official model availability, pricing, API behavior, terms, and privacy requirements before a production release.